Line data Source code
1 : /***************************************************************************\
2 : * Name : spb-protoc *
3 : * Description : proto file compiler *
4 : * Author : antonin.kriz@gmail.com *
5 : * ------------------------------------------------------------------------- *
6 : * This is free software; you can redistribute it and/or modify it under the *
7 : * terms of the MIT license. A copy of the license can be found in the file *
8 : * "LICENSE" at the root of this distribution. *
9 : \***************************************************************************/
10 :
11 : #include "dumper/dumper.h"
12 : #include "parser/parser.h"
13 : #include <cstdio>
14 : #include <cstring>
15 : #include <exception>
16 : #include <filesystem>
17 : #include <fstream>
18 : #include <iostream>
19 : #include <vector>
20 :
21 : namespace
22 : {
23 : using namespace std::literals;
24 : namespace fs = std::filesystem;
25 :
26 : constexpr auto opt_version = "--version"sv;
27 : constexpr auto opt_v = "-v"sv;
28 :
29 : constexpr auto opt_help = "--help"sv;
30 : constexpr auto opt_h = "-h"sv;
31 :
32 : constexpr auto opt_cpp_out = "--cpp_out="sv;
33 :
34 : constexpr auto opt_proto_path = "--proto_path="sv;
35 : constexpr auto opt_ipath = "-IPATH="sv;
36 :
37 0 : void print_usage( )
38 : {
39 : std::cout
40 : << "Usage: spb-protoc [OPTION] PROTO_FILES\n"
41 : << "Parse PROTO_FILES and generate C++ source files.\n"
42 : << " -IPATH=, --proto_path=PATH Specify the directory in which to search for imports.\n"
43 : << "May be specified multiple times. directories will be searched in order.\n"
44 : << " -v, --version Show version info and exit.\n"
45 : << " -h, --help Show this text and exit.\n"
46 0 : << " --cpp_out=OUT_DIR Generate C++ header and source.\n\n";
47 0 : }
48 :
49 12 : void process_file( const fs::path & input_file, std::span< const fs::path > import_paths,
50 : const fs::path & output_dir )
51 : {
52 12 : const auto parsed_file = parse_proto_file( input_file, import_paths );
53 12 : const auto output_cpp_header = cpp_file_name_from_proto( input_file, ".pb.h" );
54 12 : const auto output_cpp = cpp_file_name_from_proto( input_file, ".pb.cc" );
55 :
56 12 : auto cpp_header_stream = std::ofstream( output_dir / output_cpp_header );
57 12 : dump_cpp_header( parsed_file, cpp_header_stream );
58 :
59 12 : auto cpp_stream = std::ofstream( output_dir / output_cpp );
60 12 : dump_cpp( parsed_file, output_cpp_header, cpp_stream );
61 12 : }
62 :
63 : }// namespace
64 :
65 12 : auto main( int argc, char * argv[] ) -> int
66 : {
67 12 : if( argc < 2 )
68 : {
69 0 : print_usage( );
70 0 : return 1;
71 : }
72 :
73 12 : auto output_dir = fs::path( );
74 36 : auto import_paths = std::vector< fs::path >{ fs::current_path( ) };
75 :
76 24 : for( ; argc > 1 && argv[ 1 ][ 0 ] == '-'; argc--, argv++ )
77 : {
78 12 : if( opt_help == argv[ 1 ] || opt_h == argv[ 1 ] )
79 : {
80 0 : print_usage( );
81 0 : return 0;
82 : }
83 :
84 12 : if( opt_version == argv[ 1 ] || opt_v == argv[ 1 ] )
85 : {
86 0 : std::cout << "spb-protoc version 0.1.0\n";
87 0 : return 0;
88 : }
89 :
90 12 : if( std::string_view( argv[ 1 ] ).starts_with( opt_proto_path ) )
91 : {
92 0 : import_paths.emplace_back( argv[ 1 ] + opt_proto_path.size( ) );
93 : }
94 12 : else if( std::string_view( argv[ 1 ] ).starts_with( opt_ipath ) )
95 : {
96 0 : import_paths.emplace_back( argv[ 1 ] + opt_ipath.size( ) );
97 : }
98 12 : else if( std::string_view( argv[ 1 ] ).starts_with( opt_cpp_out ) )
99 : {
100 12 : output_dir = argv[ 1 ] + opt_cpp_out.size( );
101 : }
102 : else
103 : {
104 0 : std::cerr << "Unknown option: " << argv[ 1 ] << ", use -h or --help\n";
105 0 : return 1;
106 : }
107 : }
108 :
109 12 : auto input_files = std::vector< fs::path >( );
110 24 : for( auto i = 1; i < argc; i++ )
111 : {
112 12 : input_files.emplace_back( argv[ i ] );
113 12 : import_paths.emplace_back( input_files.back( ).parent_path( ) );
114 : }
115 :
116 12 : if( output_dir.empty( ) )
117 : {
118 0 : std::cerr << "Missing output directory, use --cpp_out=OUT_DIR:\n";
119 0 : return 1;
120 : }
121 :
122 12 : if( input_files.empty( ) )
123 : {
124 0 : std::cerr << "Missing input files, use PROTO_FILES:\n";
125 0 : return 1;
126 : }
127 :
128 : try
129 : {
130 24 : for( const auto & input_file : input_files )
131 : {
132 12 : process_file( input_file, import_paths, output_dir );
133 : }
134 : }
135 0 : catch( const std::exception & e )
136 : {
137 0 : std::cerr << e.what( ) << '\n';
138 0 : return 1;
139 0 : }
140 :
141 12 : return 0;
142 24 : }
|