1// Copyright (C) 2023 basysKom GmbH, opensource@basyskom.com
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "recursivedescentparser.h"
5
6#include <QtCore/qcommandlineoption.h>
7#include <QtCore/qcommandlineparser.h>
8#include <QtCore/qdebug.h>
9#include <QtCore/qfile.h>
10#include <QtCore/qregularexpression.h>
11#include <QtCore/qstring.h>
12#include <QtCore/qstringlist.h>
13#include <QtCore/qtextstream.h>
14#include <QtCore/qxmlstream.h>
15
16#include <cstdlib>
17
18bool readBsdFile(RecursiveDescentParser &recursiveDescentParser,
19 const QString &fileName,
20 bool dependencyInput)
21{
22 switch (recursiveDescentParser.parseFile(fileName, dependencyTypeDictionary: dependencyInput)) {
23 case RecursiveDescentParser::NoError:
24 return true;
25 case RecursiveDescentParser::InvalidFileName:
26 qCritical() << "Error: File does not exist:" << fileName;
27 return false;
28 case RecursiveDescentParser::InvalidTypeDictionaryEntry:
29 qCritical() << "Error: Invalid TypeDictionary entry in" << fileName;
30 return false;
31 case RecursiveDescentParser::InvalidStructuredTypeEntry:
32 qCritical() << "Error: Invalid StructuredType entry in" << fileName;
33 return false;
34 case RecursiveDescentParser::InvalidEnumeratedTypeEntry:
35 qCritical() << "Error: Invalid EnumeratedType entry in" << fileName;
36 return false;
37 case RecursiveDescentParser::InvalidImportEntry:
38 qCritical() << "Error: Invalid Import entry in" << fileName;
39 return false;
40 case RecursiveDescentParser::InvalidFieldEntry:
41 qCritical() << "Error: Invalid Field entry in" << fileName;
42 return false;
43 case RecursiveDescentParser::InvalidEnumeratedValueEntry:
44 qCritical() << "Error: Invalid EnumeratedValue entry in" << fileName;
45 return false;
46 case RecursiveDescentParser::CannotFullyGenerateNamespaceZero:
47 qCritical() << "Error: Full generation of namespace 0 is currently not "
48 "supported";
49 return false;
50 case RecursiveDescentParser::MissingDependency:
51 qCritical() << "Error: Missing dependency Type found in" << fileName;
52 return false;
53 default:
54 qCritical() << "Error: Unknown parsing error occurred";
55 return false;
56 }
57}
58
59bool generateBsdFiles(RecursiveDescentParser &recursiveDescentParser,
60 const QString &outputPath,
61 const QString &dataPrefix,
62 const QString &outputFileHeader)
63{
64 switch (recursiveDescentParser.generateInputFiles(path: outputPath,
65 prefix: dataPrefix,
66 header: outputFileHeader)) {
67 case RecursiveDescentParser::NoError:
68 return true;
69 case RecursiveDescentParser::UnableToWriteFile:
70 qCritical() << "Error: Unable to write files at specified path.";
71 return false;
72 case RecursiveDescentParser::MissingDependency:
73 qCritical() << "Error: Unresolved dependent type occurred.";
74 return false;
75 case RecursiveDescentParser::UnableToResolveDependency:
76 qCritical() << "Error: Unresolvable mapping occurred.";
77 return false;
78 default:
79 qCritical() << "Error: Unknown file generating error occurred.";
80 return false;
81 }
82}
83
84int main(int argc, char *argv[])
85{
86 QCoreApplication a(argc, argv);
87
88 const QString appName = QStringLiteral("qopcuaxmldatatypes2cpp");
89 const QString appVersion = QStringLiteral("1.0");
90
91 auto arguments = a.arguments();
92 arguments.replace(i: 0, t: appName);
93
94 const auto outputFileHeader = QStringLiteral("/*\n"
95 " * This file was generated by %1 version %2\n"
96 " * Command line used: %3\n"
97 " */")
98 .arg(args: appName,
99 args: appVersion,
100 args: arguments.join(sep: QLatin1Char(' ')));
101
102 QCoreApplication::setApplicationName(appName);
103 QCoreApplication::setApplicationVersion(appVersion);
104 QCommandLineParser parser;
105 parser.setApplicationDescription(
106 "Code generator for custom data models.\n"
107 "Converts OPC UA .bsd files into enums and C++ data classes and generates a class "
108 "to decode and encode the values from/to a QOpcUaExtensionObject with binary body or a QByteArray.");
109 parser.addHelpOption();
110 parser.addVersionOption();
111
112 const QCommandLineOption inputFileOption(QStringList() << "i"
113 << "input",
114 "A primary input file. Will generate code for all contained types and "
115 "check for missing dependencies",
116 "file");
117 parser.addOption(commandLineOption: inputFileOption);
118 const QCommandLineOption inputDependencyFileOption(
119 QStringList() << "d"
120 << "dependencyinput",
121 "A dependency input file. Only types required by primary input files will be generated",
122 "file");
123 parser.addOption(commandLineOption: inputDependencyFileOption);
124 const QCommandLineOption outputDirectoryPathOption(QStringList() << "o"
125 << "output",
126 "output directory for the generated C++ files.",
127 "path");
128 parser.addOption(commandLineOption: outputDirectoryPathOption);
129 const QCommandLineOption
130 outputPrefixOption(QStringList() << "p"
131 << "prefix",
132 "prefix for the generated files, default is GeneratedOpcUa",
133 "prefix",
134 "GeneratedOpcUa");
135 parser.addOption(commandLineOption: outputPrefixOption);
136
137 parser.process(app: a);
138
139 if (!parser.isSet(option: inputFileOption)) {
140 qCritical() << "Error: At least one input file must be specified";
141 parser.showHelp(exitCode: 1);
142 return EXIT_FAILURE;
143 }
144
145 if (!parser.isSet(option: outputDirectoryPathOption)) {
146 qCritical() << "Error: The output path must be specified.";
147 parser.showHelp(exitCode: 1);
148 return EXIT_FAILURE;
149 }
150
151 if (parser.values(option: outputPrefixOption).size() > 1)
152 qInfo() << "Info: The first output prefix will be used";
153 if (!parser.values(option: outputPrefixOption)
154 .at(i: 0)
155 .contains(re: QRegularExpression("^[A-Za-z]+[A-Za-z0-9]*$"))) {
156 qCritical() << "Error: The prefix contains illegal characters";
157 qInfo() << "Info: The prefix must consist of letters and numbers and start with a letter";
158 return EXIT_FAILURE;
159 }
160
161 const auto dataPrefix = parser.value(option: outputPrefixOption);
162
163 auto success = true;
164 RecursiveDescentParser recursiveDescentParser;
165 const QStringList inputFileNames = parser.values(option: inputFileOption);
166 for (const auto &fileName : inputFileNames)
167 success &= readBsdFile(recursiveDescentParser, fileName, dependencyInput: false);
168 const QStringList dependencyInputFileNames = parser.values(option: inputDependencyFileOption);
169 for (const auto &fileName : dependencyInputFileNames)
170 success &= readBsdFile(recursiveDescentParser, fileName, dependencyInput: true);
171 if (success) {
172 const auto outputPath = parser.value(option: outputDirectoryPathOption);
173 if (generateBsdFiles(recursiveDescentParser,
174 outputPath,
175 dataPrefix,
176 outputFileHeader)) {
177 qInfo() << "Info: All types were successfully generated";
178 return EXIT_SUCCESS;
179 }
180 }
181 return EXIT_FAILURE;
182}
183

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtopcua/tools/datatypecodegenerator/main.cpp