1 /**
2 * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
3 * (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
4 *
5 * @file xml2cpp.cpp
6 *
7 * Created on: Feb 1, 2017
8 * Project: sdbus-c++
9 * Description: High-level D-Bus IPC C++ library based on sd-bus
10 *
11 * This file is part of sdbus-c++.
12 *
13 * sdbus-c++ is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU Lesser General Public License as published by
15 * the Free Software Foundation, either version 2.1 of the License, or
16 * (at your option) any later version.
17 *
18 * sdbus-c++ is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
25 */
26
27 // Own
28 #include "xml.h"
29 #include "AdaptorGenerator.h"
30 #include "ProxyGenerator.h"
31
32 // STL
33 #include <cstdlib>
34 #include <cstring>
35 #include <string>
36 #include <map>
37 #include <iostream>
38 #include <fstream>
39 #include <sstream>
40
41 using std::endl;
42 using namespace sdbuscpp;
43
usage(std::ostream & output,const char * programName)44 void usage(std::ostream& output, const char* programName)
45 {
46 output << "Usage: " << programName << " [OPTION]... [FILE]" << endl <<
47 "Creates C++ stubs for DBus API for adaptor and/or client" << endl <<
48 endl <<
49 "Available options:" << endl <<
50 " --proxy=FILE Generate header file FILE with proxy class (client)" << endl <<
51 " --adaptor=FILE Generate header file FILE with stub class (server)" << endl <<
52 " -h, --help " << endl <<
53 " --verbose Explain what is being done" << endl <<
54 endl <<
55 "The stub generator takes an XML file describing DBus interface and creates" << endl <<
56 "C++ header files to be used by C++ code wanting to cumminicate through that" << endl <<
57 "interface. Clients of the interface (those making the calls) need header" << endl <<
58 "created with the --proxy option as this header forwards the calls via DBus" << endl <<
59 "to provider of the service and the returns the result to the caller. Server" << endl <<
60 "implementing the service should derive from interface classes in header" << endl <<
61 "generated for --adaptor option and implement their methods." << endl <<
62 endl <<
63 "When FILE is not specified, standard input is read. Exit status is 0 when" << endl <<
64 "no error was encountered and all requested headers were sucessfully generated." << endl <<
65 "Otherwise 1 is returned." << endl;
66 }
67
68
main(int argc,char ** argv)69 int main(int argc, char **argv)
70 {
71 const char* programName = argv[0];
72 argv++;
73 argc--;
74
75 const char* proxy = nullptr;
76 const char* adaptor = nullptr;
77 const char* xmlFile = nullptr;
78 bool verbose = false;
79
80 while (argc > 0)
81 {
82 if (!strncmp(*argv, "--proxy=", 8))
83 {
84 if (proxy != nullptr)
85 {
86 std::cerr << "Multiple occurrencies of --proxy is not allowed" << endl;
87 usage(std::cerr, programName);
88 return 1;
89 }
90 proxy = *argv + 8;
91 }
92 else if (!strncmp(*argv, "--adaptor=", 10) || !strncmp(*argv, "--adapter=", 10))
93 {
94 if (adaptor != nullptr)
95 {
96 std::cerr << "Multiple occurrencies of --adaptor is not allowed" << endl;
97 usage(std::cerr, programName);
98 return 1;
99 }
100 adaptor = *argv + 10;
101 }
102 else if (!strcmp(*argv, "--help") || !strcmp(*argv, "-h"))
103 {
104 usage(std::cout, programName);
105 return 0;
106 }
107 else if (!strcmp(*argv, "--verbose"))
108 {
109 verbose = true;
110 }
111 else if (**argv == '-')
112 {
113 std::cerr << "Unknown option " << *argv << endl;
114 usage(std::cerr, programName);
115 return 1;
116 }
117 else
118 {
119 if (xmlFile != nullptr)
120 {
121 std::cerr << "More than one input file specified: " << *argv << endl;
122 usage(std::cerr, programName);
123 return 1;
124 }
125 xmlFile = *argv;
126 }
127
128 argc--;
129 argv++;
130 }
131
132 if (!proxy && !adaptor)
133 {
134 std::cerr << "Either --proxy or --adapter need to be specified" << endl;
135 usage(std::cerr, programName);
136 return 1;
137 }
138
139 xml::Document doc;
140
141 try
142 {
143 if (xmlFile != nullptr)
144 {
145 if (verbose)
146 {
147 std::cerr << "Reading DBus interface from " << xmlFile << endl;
148 }
149
150 std::ifstream input(xmlFile);
151
152 if (input.fail())
153 {
154 std::cerr << "Unable to open file " << xmlFile << endl;
155 return 1;
156 }
157
158 input >> doc;
159 }
160 else
161 {
162 if (verbose)
163 {
164 std::cerr << "Reading DBus interface from standard input" << endl;
165 }
166
167 std::cin >> doc;
168 }
169 }
170 catch (const xml::Error& e)
171 {
172 std::cerr << "Parsing error: " << e.what() << endl;
173 return 1;
174 }
175
176 if (!doc.root)
177 {
178 std::cerr << "Empty document" << endl;
179 return 1;
180 }
181
182 if (proxy)
183 {
184 if (verbose)
185 {
186 std::cerr << "Generating proxy header " << proxy << endl;
187 }
188 ProxyGenerator pg;
189 pg.transformXmlToFile(doc, proxy);
190 }
191
192 if (adaptor)
193 {
194 if (verbose)
195 {
196 std::cerr << "Generating adaptor header " << adaptor << endl;
197 }
198 AdaptorGenerator ag;
199 ag.transformXmlToFile(doc, adaptor);
200 }
201
202 return 0;
203 }
204