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