1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include <ctype.h>
20 #ifndef _WIN32
21 #include <sys/time.h>
22 #endif
23 #include <iostream>
24 #include <fstream>
25 #include <map>
26 #include <set>
27
28 #include <boost/algorithm/string.hpp>
29 #include <boost/lexical_cast.hpp>
30 #include <boost/program_options.hpp>
31
32 #include <boost/random/mersenne_twister.hpp>
33 #include <boost/random/uniform_int.hpp>
34 #include <boost/random/variate_generator.hpp>
35
36 #include "Compiler.hh"
37 #include "ValidSchema.hh"
38 #include "NodeImpl.hh"
39
40 using std::ostream;
41 using std::ifstream;
42 using std::ofstream;
43 using std::map;
44 using std::set;
45 using std::string;
46 using std::vector;
47 using internal_avro::NodePtr;
48 using internal_avro::resolveSymbol;
49
50 using boost::lexical_cast;
51
52 using internal_avro::ValidSchema;
53 using internal_avro::compileJsonSchema;
54
55 struct PendingSetterGetter {
56 string structName;
57 string type;
58 string name;
59 size_t idx;
60
PendingSetterGetterPendingSetterGetter61 PendingSetterGetter(const string& sn, const string& t, const string& n,
62 size_t i)
63 : structName(sn), type(t), name(n), idx(i) {}
64 };
65
66 struct PendingConstructor {
67 string structName;
68 string memberName;
69 bool initMember;
PendingConstructorPendingConstructor70 PendingConstructor(const string& sn, const string& n, bool im)
71 : structName(sn), memberName(n), initMember(im) {}
72 };
73
74 class CodeGen {
75 size_t unionNumber_;
76 std::ostream& os_;
77 bool inNamespace_;
78 const std::string ns_;
79 const std::string schemaFile_;
80 const std::string headerFile_;
81 const std::string includePrefix_;
82 const bool noUnion_;
83 const std::string guardString_;
84 boost::mt19937 random_;
85
86 vector<PendingSetterGetter> pendingGettersAndSetters;
87 vector<PendingConstructor> pendingConstructors;
88
89 map<NodePtr, string> done;
90 set<NodePtr> doing;
91
92 std::string guard();
93 std::string fullname(const string& name) const;
94 std::string generateEnumType(const NodePtr& n);
95 std::string cppTypeOf(const NodePtr& n);
96 std::string generateRecordType(const NodePtr& n);
97 std::string unionName();
98 std::string generateUnionType(const NodePtr& n);
99 std::string generateType(const NodePtr& n);
100 std::string generateDeclaration(const NodePtr& n);
101 std::string doGenerateType(const NodePtr& n);
102 void generateEnumTraits(const NodePtr& n);
103 void generateTraits(const NodePtr& n);
104 void generateRecordTraits(const NodePtr& n);
105 void generateUnionTraits(const NodePtr& n);
106 void emitCopyright();
107
108 public:
CodeGen(std::ostream & os,const std::string & ns,const std::string & schemaFile,const std::string & headerFile,const std::string & guardString,const std::string & includePrefix,bool noUnion)109 CodeGen(std::ostream& os, const std::string& ns,
110 const std::string& schemaFile, const std::string& headerFile,
111 const std::string& guardString, const std::string& includePrefix,
112 bool noUnion)
113 : unionNumber_(0),
114 os_(os),
115 inNamespace_(false),
116 ns_(ns),
117 schemaFile_(schemaFile),
118 headerFile_(headerFile),
119 includePrefix_(includePrefix),
120 noUnion_(noUnion),
121 guardString_(guardString),
122 random_(static_cast<uint32_t>(::time(0))) {}
123 void generate(const ValidSchema& schema);
124 };
125
decorate(const internal_avro::Name & name)126 static string decorate(const internal_avro::Name& name) {
127 return name.simpleName();
128 }
129
fullname(const string & name) const130 string CodeGen::fullname(const string& name) const {
131 return ns_.empty() ? name : (ns_ + "::" + name);
132 }
133
generateEnumType(const NodePtr & n)134 string CodeGen::generateEnumType(const NodePtr& n) {
135 string s = decorate(n->name());
136 os_ << "enum " << s << " {\n";
137 size_t c = n->names();
138 for (size_t i = 0; i < c; ++i) {
139 os_ << " " << n->nameAt(i) << ",\n";
140 }
141 os_ << "};\n\n";
142 return s;
143 }
144
cppTypeOf(const NodePtr & n)145 string CodeGen::cppTypeOf(const NodePtr& n) {
146 switch (n->type()) {
147 case internal_avro::AVRO_STRING:
148 return "std::string";
149 case internal_avro::AVRO_BYTES:
150 return "std::vector<uint8_t>";
151 case internal_avro::AVRO_INT:
152 return "int32_t";
153 case internal_avro::AVRO_LONG:
154 return "int64_t";
155 case internal_avro::AVRO_FLOAT:
156 return "float";
157 case internal_avro::AVRO_DOUBLE:
158 return "double";
159 case internal_avro::AVRO_BOOL:
160 return "bool";
161 case internal_avro::AVRO_RECORD:
162 case internal_avro::AVRO_ENUM: {
163 string nm = decorate(n->name());
164 return inNamespace_ ? nm : fullname(nm);
165 }
166 case internal_avro::AVRO_ARRAY:
167 return "std::vector<" + cppTypeOf(n->leafAt(0)) + " >";
168 case internal_avro::AVRO_MAP:
169 return "std::map<std::string, " + cppTypeOf(n->leafAt(1)) + " >";
170 case internal_avro::AVRO_FIXED:
171 return "boost::array<uint8_t, " + lexical_cast<string>(n->fixedSize()) +
172 ">";
173 case internal_avro::AVRO_SYMBOLIC:
174 return cppTypeOf(resolveSymbol(n));
175 case internal_avro::AVRO_UNION:
176 return fullname(done[n]);
177 default:
178 return "$Undefined$";
179 }
180 }
181
cppNameOf(const NodePtr & n)182 static string cppNameOf(const NodePtr& n) {
183 switch (n->type()) {
184 case internal_avro::AVRO_NULL:
185 return "null";
186 case internal_avro::AVRO_STRING:
187 return "string";
188 case internal_avro::AVRO_BYTES:
189 return "bytes";
190 case internal_avro::AVRO_INT:
191 return "int";
192 case internal_avro::AVRO_LONG:
193 return "long";
194 case internal_avro::AVRO_FLOAT:
195 return "float";
196 case internal_avro::AVRO_DOUBLE:
197 return "double";
198 case internal_avro::AVRO_BOOL:
199 return "bool";
200 case internal_avro::AVRO_RECORD:
201 case internal_avro::AVRO_ENUM:
202 case internal_avro::AVRO_FIXED:
203 return decorate(n->name());
204 case internal_avro::AVRO_ARRAY:
205 return "array";
206 case internal_avro::AVRO_MAP:
207 return "map";
208 case internal_avro::AVRO_SYMBOLIC:
209 return cppNameOf(resolveSymbol(n));
210 default:
211 return "$Undefined$";
212 }
213 }
214
generateRecordType(const NodePtr & n)215 string CodeGen::generateRecordType(const NodePtr& n) {
216 size_t c = n->leaves();
217 vector<string> types;
218 for (size_t i = 0; i < c; ++i) {
219 types.push_back(generateType(n->leafAt(i)));
220 }
221
222 map<NodePtr, string>::const_iterator it = done.find(n);
223 if (it != done.end()) {
224 return it->second;
225 }
226
227 os_ << "struct " << decorate(n->name()) << " {\n";
228 if (!noUnion_) {
229 for (size_t i = 0; i < c; ++i) {
230 if (n->leafAt(i)->type() == internal_avro::AVRO_UNION) {
231 os_ << " typedef " << types[i] << ' ' << n->nameAt(i) << "_t;\n";
232 }
233 }
234 }
235 for (size_t i = 0; i < c; ++i) {
236 if (!noUnion_ && n->leafAt(i)->type() == internal_avro::AVRO_UNION) {
237 os_ << " " << n->nameAt(i) << "_t";
238 } else {
239 os_ << " " << types[i];
240 }
241 os_ << ' ' << n->nameAt(i) << ";\n";
242 }
243 os_ << "};\n\n";
244 return decorate(n->name());
245 }
246
makeCanonical(string & s,bool foldCase)247 void makeCanonical(string& s, bool foldCase) {
248 for (string::iterator it = s.begin(); it != s.end(); ++it) {
249 if (isalpha(*it)) {
250 if (foldCase) {
251 *it = toupper(*it);
252 }
253 } else if (!isdigit(*it)) {
254 *it = '_';
255 }
256 }
257 }
258
unionName()259 string CodeGen::unionName() {
260 string s = schemaFile_;
261 string::size_type n = s.find_last_of("/\\");
262 if (n != string::npos) {
263 s = s.substr(n);
264 }
265 makeCanonical(s, false);
266
267 return s + "_Union__" + boost::lexical_cast<string>(unionNumber_++) + "__";
268 }
269
generateGetterAndSetter(ostream & os,const string & structName,const string & type,const string & name,size_t idx)270 static void generateGetterAndSetter(ostream& os, const string& structName,
271 const string& type, const string& name,
272 size_t idx) {
273 string sn = " " + structName + "::";
274
275 os << "inline\n";
276
277 os << type << sn << "get_" << name << "() const {\n"
278 << " if (idx_ != " << idx << ") {\n"
279 << " throw internal_avro::Exception(\"Invalid type for "
280 << "union\");\n"
281 << " }\n"
282 << " return boost::any_cast<" << type << " >(value_);\n"
283 << "}\n\n";
284
285 os << "inline\n"
286 << "void" << sn << "set_" << name << "(const " << type << "& v) {\n"
287 << " idx_ = " << idx << ";\n"
288 << " value_ = v;\n"
289 << "}\n\n";
290 }
291
generateConstructor(ostream & os,const string & structName,bool initMember,const string & type)292 static void generateConstructor(ostream& os, const string& structName,
293 bool initMember, const string& type) {
294 os << "inline " << structName << "::" << structName << "() : idx_(0)";
295 if (initMember) {
296 os << ", value_(" << type << "())";
297 }
298 os << " { }\n";
299 }
300
301 /**
302 * Generates a type for union and emits the code.
303 * Since unions can encounter names that are not fully defined yet,
304 * such names must be declared and the inline functions deferred until all
305 * types are fully defined.
306 */
generateUnionType(const NodePtr & n)307 string CodeGen::generateUnionType(const NodePtr& n) {
308 size_t c = n->leaves();
309 vector<string> types;
310 vector<string> names;
311
312 set<NodePtr>::const_iterator it = doing.find(n);
313 if (it != doing.end()) {
314 for (size_t i = 0; i < c; ++i) {
315 const NodePtr& nn = n->leafAt(i);
316 types.push_back(generateDeclaration(nn));
317 names.push_back(cppNameOf(nn));
318 }
319 } else {
320 doing.insert(n);
321 for (size_t i = 0; i < c; ++i) {
322 const NodePtr& nn = n->leafAt(i);
323 types.push_back(generateType(nn));
324 names.push_back(cppNameOf(nn));
325 }
326 doing.erase(n);
327 }
328 if (done.find(n) != done.end()) {
329 return done[n];
330 }
331
332 const string result = unionName();
333
334 os_ << "struct " << result << " {\n"
335 << "private:\n"
336 << " size_t idx_;\n"
337 << " boost::any value_;\n"
338 << "public:\n"
339 << " size_t idx() const { return idx_; }\n";
340
341 for (size_t i = 0; i < c; ++i) {
342 const NodePtr& nn = n->leafAt(i);
343 if (nn->type() == internal_avro::AVRO_NULL) {
344 os_ << " bool is_null() const {\n"
345 << " return (idx_ == " << i << ");\n"
346 << " }\n"
347 << " void set_null() {\n"
348 << " idx_ = " << i << ";\n"
349 << " value_ = boost::any();\n"
350 << " }\n";
351 } else {
352 const string& type = types[i];
353 const string& name = names[i];
354 os_ << " " << type << " get_" << name << "() const;\n"
355 " void set_" << name
356 << "(const " << type << "& v);\n";
357 pendingGettersAndSetters.push_back(
358 PendingSetterGetter(result, type, name, i));
359 }
360 }
361
362 os_ << " " << result << "();\n";
363 pendingConstructors.push_back(PendingConstructor(
364 result, types[0], n->leafAt(0)->type() != internal_avro::AVRO_NULL));
365 os_ << "};\n\n";
366
367 return result;
368 }
369
370 /**
371 * Returns the type for the given schema node and emits code to os.
372 */
generateType(const NodePtr & n)373 string CodeGen::generateType(const NodePtr& n) {
374 NodePtr nn =
375 (n->type() == internal_avro::AVRO_SYMBOLIC) ? resolveSymbol(n) : n;
376
377 map<NodePtr, string>::const_iterator it = done.find(nn);
378 if (it != done.end()) {
379 return it->second;
380 }
381 string result = doGenerateType(nn);
382 done[nn] = result;
383 return result;
384 }
385
doGenerateType(const NodePtr & n)386 string CodeGen::doGenerateType(const NodePtr& n) {
387 switch (n->type()) {
388 case internal_avro::AVRO_STRING:
389 case internal_avro::AVRO_BYTES:
390 case internal_avro::AVRO_INT:
391 case internal_avro::AVRO_LONG:
392 case internal_avro::AVRO_FLOAT:
393 case internal_avro::AVRO_DOUBLE:
394 case internal_avro::AVRO_BOOL:
395 case internal_avro::AVRO_NULL:
396 case internal_avro::AVRO_FIXED:
397 return cppTypeOf(n);
398 case internal_avro::AVRO_ARRAY:
399 return "std::vector<" + generateType(n->leafAt(0)) + " >";
400 case internal_avro::AVRO_MAP:
401 return "std::map<std::string, " + generateType(n->leafAt(1)) + " >";
402 case internal_avro::AVRO_RECORD:
403 return generateRecordType(n);
404 case internal_avro::AVRO_ENUM:
405 return generateEnumType(n);
406 case internal_avro::AVRO_UNION:
407 return generateUnionType(n);
408 default:
409 break;
410 }
411 return "$Undefuned$";
412 }
413
generateDeclaration(const NodePtr & n)414 string CodeGen::generateDeclaration(const NodePtr& n) {
415 NodePtr nn =
416 (n->type() == internal_avro::AVRO_SYMBOLIC) ? resolveSymbol(n) : n;
417 switch (nn->type()) {
418 case internal_avro::AVRO_STRING:
419 case internal_avro::AVRO_BYTES:
420 case internal_avro::AVRO_INT:
421 case internal_avro::AVRO_LONG:
422 case internal_avro::AVRO_FLOAT:
423 case internal_avro::AVRO_DOUBLE:
424 case internal_avro::AVRO_BOOL:
425 case internal_avro::AVRO_NULL:
426 case internal_avro::AVRO_FIXED:
427 return cppTypeOf(nn);
428 case internal_avro::AVRO_ARRAY:
429 return "std::vector<" + generateDeclaration(nn->leafAt(0)) + " >";
430 case internal_avro::AVRO_MAP:
431 return "std::map<std::string, " + generateDeclaration(nn->leafAt(1)) +
432 " >";
433 case internal_avro::AVRO_RECORD:
434 os_ << "struct " << cppTypeOf(nn) << ";\n";
435 return cppTypeOf(nn);
436 case internal_avro::AVRO_ENUM:
437 return generateEnumType(nn);
438 case internal_avro::AVRO_UNION:
439 // FIXME: When can this happen?
440 return generateUnionType(nn);
441 default:
442 break;
443 }
444 return "$Undefuned$";
445 }
446
generateEnumTraits(const NodePtr & n)447 void CodeGen::generateEnumTraits(const NodePtr& n) {
448 string fn = fullname(decorate(n->name()));
449 os_ << "template<> struct codec_traits<" << fn << "> {\n"
450 << " static void encode(Encoder& e, " << fn << " v) {\n"
451 << " e.encodeEnum(v);\n"
452 << " }\n"
453 << " static void decode(Decoder& d, " << fn << "& v) {\n"
454 << " v = static_cast<" << fn << ">(d.decodeEnum());\n"
455 << " }\n"
456 << "};\n\n";
457 }
458
generateRecordTraits(const NodePtr & n)459 void CodeGen::generateRecordTraits(const NodePtr& n) {
460 size_t c = n->leaves();
461 for (size_t i = 0; i < c; ++i) {
462 generateTraits(n->leafAt(i));
463 }
464
465 string fn = fullname(decorate(n->name()));
466 os_ << "template<> struct codec_traits<" << fn << "> {\n"
467 << " static void encode(Encoder& e, const " << fn << "& v) {\n";
468
469 for (size_t i = 0; i < c; ++i) {
470 os_ << " internal_avro::encode(e, v." << n->nameAt(i) << ");\n";
471 }
472
473 os_ << " }\n"
474 << " static void decode(Decoder& d, " << fn << "& v) {\n";
475
476 for (size_t i = 0; i < c; ++i) {
477 os_ << " internal_avro::decode(d, v." << n->nameAt(i) << ");\n";
478 }
479
480 os_ << " }\n"
481 << "};\n\n";
482 }
483
generateUnionTraits(const NodePtr & n)484 void CodeGen::generateUnionTraits(const NodePtr& n) {
485 size_t c = n->leaves();
486
487 for (size_t i = 0; i < c; ++i) {
488 const NodePtr& nn = n->leafAt(i);
489 generateTraits(nn);
490 }
491
492 string name = done[n];
493 string fn = fullname(name);
494
495 os_ << "template<> struct codec_traits<" << fn << "> {\n"
496 << " static void encode(Encoder& e, " << fn << " v) {\n"
497 << " e.encodeUnionIndex(v.idx());\n"
498 << " switch (v.idx()) {\n";
499
500 for (size_t i = 0; i < c; ++i) {
501 const NodePtr& nn = n->leafAt(i);
502 os_ << " case " << i << ":\n";
503 if (nn->type() == internal_avro::AVRO_NULL) {
504 os_ << " e.encodeNull();\n";
505 } else {
506 os_ << " internal_avro::encode(e, v.get_" << cppNameOf(nn)
507 << "());\n";
508 }
509 os_ << " break;\n";
510 }
511
512 os_ << " }\n"
513 << " }\n"
514 << " static void decode(Decoder& d, " << fn << "& v) {\n"
515 << " size_t n = d.decodeUnionIndex();\n"
516 << " if (n >= " << c << ") { throw internal_avro::Exception(\""
517 "Union index too big\"); }\n"
518 << " switch (n) {\n";
519
520 for (size_t i = 0; i < c; ++i) {
521 const NodePtr& nn = n->leafAt(i);
522 os_ << " case " << i << ":\n";
523 if (nn->type() == internal_avro::AVRO_NULL) {
524 os_ << " d.decodeNull();\n"
525 << " v.set_null();\n";
526 } else {
527 os_ << " {\n"
528 << " " << cppTypeOf(nn) << " vv;\n"
529 << " internal_avro::decode(d, vv);\n"
530 << " v.set_" << cppNameOf(nn) << "(vv);\n"
531 << " }\n";
532 }
533 os_ << " break;\n";
534 }
535 os_ << " }\n"
536 << " }\n"
537 << "};\n\n";
538 }
539
generateTraits(const NodePtr & n)540 void CodeGen::generateTraits(const NodePtr& n) {
541 switch (n->type()) {
542 case internal_avro::AVRO_STRING:
543 case internal_avro::AVRO_BYTES:
544 case internal_avro::AVRO_INT:
545 case internal_avro::AVRO_LONG:
546 case internal_avro::AVRO_FLOAT:
547 case internal_avro::AVRO_DOUBLE:
548 case internal_avro::AVRO_BOOL:
549 case internal_avro::AVRO_NULL:
550 break;
551 case internal_avro::AVRO_RECORD:
552 generateRecordTraits(n);
553 break;
554 case internal_avro::AVRO_ENUM:
555 generateEnumTraits(n);
556 break;
557 case internal_avro::AVRO_ARRAY:
558 case internal_avro::AVRO_MAP:
559 generateTraits(n->leafAt(n->type() == internal_avro::AVRO_ARRAY ? 0 : 1));
560 break;
561 case internal_avro::AVRO_UNION:
562 generateUnionTraits(n);
563 break;
564 case internal_avro::AVRO_FIXED:
565 break;
566 default:
567 break;
568 }
569 }
570
emitCopyright()571 void CodeGen::emitCopyright() {
572 os_ << "/**\n"
573 " * Licensed to the Apache Software Foundation (ASF) under one\n"
574 " * or more contributor license agreements. See the NOTICE file\n"
575 " * distributed with this work for additional information\n"
576 " * regarding copyright ownership. The ASF licenses this file\n"
577 " * to you under the Apache License, Version 2.0 (the\n"
578 " * \"License\"); you may not use this file except in compliance\n"
579 " * with the License. You may obtain a copy of the License at\n"
580 " *\n"
581 " * http://www.apache.org/licenses/LICENSE-2.0\n"
582 " *\n"
583 " * Unless required by applicable law or agreed to in writing, "
584 "software\n"
585 " * distributed under the License is distributed on an "
586 "\"AS IS\" BASIS,\n"
587 " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express "
588 "or implied.\n"
589 " * See the License for the specific language governing "
590 "permissions and\n"
591 " * limitations under the License.\n"
592 " */\n\n\n";
593 }
594
guard()595 string CodeGen::guard() {
596 string h = headerFile_;
597 makeCanonical(h, true);
598 return h + "_" + lexical_cast<string>(random_()) + "__H_";
599 }
600
generate(const ValidSchema & schema)601 void CodeGen::generate(const ValidSchema& schema) {
602 emitCopyright();
603
604 string h = guardString_.empty() ? guard() : guardString_;
605
606 os_ << "#ifndef " << h << "\n";
607 os_ << "#define " << h << "\n\n\n";
608
609 os_ << "#include \"boost/any.hpp\"\n"
610 << "#include \"" << includePrefix_ << "Specific.hh\"\n"
611 << "#include \"" << includePrefix_ << "Encoder.hh\"\n"
612 << "#include \"" << includePrefix_ << "Decoder.hh\"\n"
613 << "\n";
614
615 if (!ns_.empty()) {
616 os_ << "namespace " << ns_ << " {\n";
617 inNamespace_ = true;
618 }
619
620 const NodePtr& root = schema.root();
621 generateType(root);
622
623 for (vector<PendingSetterGetter>::const_iterator it =
624 pendingGettersAndSetters.begin();
625 it != pendingGettersAndSetters.end(); ++it) {
626 generateGetterAndSetter(os_, it->structName, it->type, it->name, it->idx);
627 }
628
629 for (vector<PendingConstructor>::const_iterator it =
630 pendingConstructors.begin();
631 it != pendingConstructors.end(); ++it) {
632 generateConstructor(os_, it->structName, it->initMember, it->memberName);
633 }
634
635 if (!ns_.empty()) {
636 inNamespace_ = false;
637 os_ << "}\n";
638 }
639
640 os_ << "namespace internal_avro {\n";
641
642 unionNumber_ = 0;
643
644 generateTraits(root);
645
646 os_ << "}\n";
647
648 os_ << "#endif\n";
649 os_.flush();
650 }
651
652 namespace po = boost::program_options;
653
654 static const string NS("namespace");
655 static const string OUT("output");
656 static const string IN("input");
657 static const string INCLUDE_PREFIX("include-prefix");
658 static const string NO_UNION_TYPEDEF("no-union-typedef");
659
readGuard(const string & filename)660 static string readGuard(const string& filename) {
661 std::ifstream ifs(filename.c_str());
662 string buf;
663 string candidate;
664 while (std::getline(ifs, buf)) {
665 boost::algorithm::trim(buf);
666 if (candidate.empty()) {
667 if (boost::algorithm::starts_with(buf, "#ifndef ")) {
668 candidate = buf.substr(8);
669 }
670 } else if (boost::algorithm::starts_with(buf, "#define ")) {
671 if (candidate == buf.substr(8)) {
672 break;
673 }
674 } else {
675 candidate.erase();
676 }
677 }
678 return candidate;
679 }
680
main(int argc,char ** argv)681 int main(int argc, char** argv) {
682 po::options_description desc("Allowed options");
683 desc.add_options()("help,h", "produce help message")(
684 "include-prefix,p", po::value<string>()->default_value("internal_avro"),
685 "prefix for include headers, - for none, default: internal_avro")(
686 "no-union-typedef,U", "do not generate typedefs for unions in records")(
687 "namespace,n", po::value<string>(), "set namespace for generated code")(
688 "input,i", po::value<string>(), "input file")(
689 "output,o", po::value<string>(), "output file to generate");
690
691 po::variables_map vm;
692 po::store(po::parse_command_line(argc, argv, desc), vm);
693 po::notify(vm);
694
695 if (vm.count("help") || vm.count(IN) == 0 || vm.count(OUT) == 0) {
696 std::cout << desc << std::endl;
697 return 1;
698 }
699
700 string ns = vm.count(NS) > 0 ? vm[NS].as<string>() : string();
701 string outf = vm.count(OUT) > 0 ? vm[OUT].as<string>() : string();
702 string inf = vm.count(IN) > 0 ? vm[IN].as<string>() : string();
703 string incPrefix = vm[INCLUDE_PREFIX].as<string>();
704 bool noUnion = vm.count(NO_UNION_TYPEDEF) != 0;
705 if (incPrefix == "-") {
706 incPrefix.clear();
707 } else if (*incPrefix.rbegin() != '/') {
708 incPrefix += "/";
709 }
710
711 try {
712 ValidSchema schema;
713
714 if (!inf.empty()) {
715 ifstream in(inf.c_str());
716 compileJsonSchema(in, schema);
717 } else {
718 compileJsonSchema(std::cin, schema);
719 }
720
721 if (!outf.empty()) {
722 string g = readGuard(outf);
723 ofstream out(outf.c_str());
724 CodeGen(out, ns, inf, outf, g, incPrefix, noUnion).generate(schema);
725 } else {
726 CodeGen(std::cout, ns, inf, outf, "", incPrefix, noUnion)
727 .generate(schema);
728 }
729 return 0;
730 }
731 catch (std::exception& e) {
732 std::cerr << "Failed to parse or compile schema: " << e.what() << std::endl;
733 return 1;
734 }
735 }
736