KContacts

main.cpp
1 /*
2  SPDX-FileCopyrightText: 2018 Sune Vuorela <[email protected]>
3  SPDX-FileCopyrightText: 2018 Volker Krause <[email protected]>
4 
5  SPDX-License-Identifier: MIT
6 */
7 
8 #include "translatedcountrylist.h"
9 #include "../countrytoisomap_p.h"
10 
11 #include <QCoreApplication>
12 #include <QCommandLineParser>
13 #include <QDebug>
14 #include <QDir>
15 #include <QFile>
16 
17 int main(int argc, char **argv)
18 {
19  QCoreApplication app(argc, argv);
20  app.setApplicationName(QStringLiteral("generate country name map"));
21  app.setApplicationVersion(QStringLiteral("0.1"));
22 
24  QCommandLineOption sourceDir({QStringLiteral("sourceDir"), QStringLiteral("s")}, QStringLiteral("Location of CLDR data"), QStringLiteral("cldrdata"), QStringLiteral("/usr/share/unicode/cldr/common/main/"));
25  p.addOption(sourceDir);
26  QCommandLineOption outputFile({QStringLiteral("outputFile"), QStringLiteral("o")}, QStringLiteral("Output file"), QStringLiteral("output file"), QStringLiteral("countrytransl.map"));
27  p.addOption(outputFile);
28  p.addHelpOption();
29  p.addVersionOption();
30 
31  p.process(app);
32 
33  if (!p.isSet(sourceDir)) {
34  p.showHelp(0);
35  }
36  if (!p.isSet(outputFile)) {
37  p.showHelp(0);
38  }
39 
40 
41  QString sourceDirPath = p.value(sourceDir);
42  if (!QDir().exists(sourceDirPath)) {
43  qCritical("Specified CLDR source dir does not exist.");
44  return 1;
45  }
46  QString outputFilePath = p.value(outputFile);
47 
48  QFile f(outputFilePath);
49  bool success = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
50  if (!success) {
51  qCritical("failed to open file: %s", qPrintable(f.errorString()));
52  return 1;
53  }
54 
55  f.write(R"(
56 /*
57  * Generated file based on CLDR data. Do not edit!
58  * See src/generator/ for how to re-generate this.
59  *
60  * SPDX-FileCopyrightText: 1991-2018 Unicode Inc. All rights reserved.
61  * SPDX-License-Identifier: Unicode-DFS-2016
62  */
63 
64 #include "countrytoisomap_p.h"
65 
66 using namespace KContacts;
67 
68 static const char country_name_stringtable[] = {
69 )");
70 
71  const auto parsedList = TranslatedCountries::parseFilesRecursive(sourceDirPath);
72 
73  struct Elem {
75  QString isoCode;
76  QString language;
77  int offset;
78  };
79  std::vector<Elem> processedList;
80  processedList.reserve(parsedList.size());
81  for(const auto &country : parsedList) {
82  const auto name = KContacts::normalizeCountryName(country.name);
83  if (name.isEmpty()) {
84  qWarning() << "Skipping empty normalized country name:" << country.name << country.isoCode << country.language;
85  continue;
86  }
87  processedList.push_back(Elem{name, country.isoCode, country.language, 0});
88  }
89  // we must sort exactly as we do this for lookup
90  std::sort(processedList.begin(), processedList.end(), [](const Elem &lhs, const Elem &rhs) {
91  const auto c = strcmp(lhs.name.constData(), rhs.name.constData());
92  if (c == 0) {
93  return lhs.isoCode < rhs.isoCode;
94  }
95  return c < 0;
96  });
97 
98  // remove all duplicates referring to the same ISO code
99  const auto it = std::unique(processedList.begin(), processedList.end(), [](const Elem &lhs, const Elem &rhs) {
100  return strcmp(lhs.name.constData(), rhs.name.constData()) == 0 && lhs.isoCode == rhs.isoCode;
101  });
102  processedList.erase(it, processedList.end());
103 
104  // find duplicates that refer to different ISO codes, and remove those entirely
105  for (auto it = processedList.begin() + 1; it != processedList.end();) {
106  auto prevIt = it - 1;
107  if (strcmp((*it).name.constData(), (*prevIt).name.constData()) != 0) {
108  ++it;
109  continue;
110  }
111  qDebug() << "Removing ambigious string:" << QString::fromUtf8((*it).name)
112  << (*prevIt).isoCode.toUpper() << (*prevIt).language
113  << (*it).isoCode.toUpper() << (*it).language;
114  it = processedList.erase(prevIt);
115  it = processedList.erase(it);
116  }
117 
118  int offset = 0;
119  for(auto& elem : processedList) {
120  f.write(" ");
121  bool encodedChar = false;
122  // MSVC has a limit on strings of 65535 bytes, however arrays can be longer
123  // so we have to encode this ~500k string as an char array manually...
124  for (const char c : elem.name) {
125  f.write("'");
126  if (c >= 32 && c < 127) {
127  f.write(&c, 1);
128  } else {
129  f.write("\\x");
130  f.write(QByteArray::number(c, 16).right(2));
131  encodedChar = true;
132  }
133  f.write("',");
134  }
135  f.write("0, // ");
136  if (encodedChar) {
137  f.write(elem.name);
138  f.write(" ");
139  }
140  f.write(elem.isoCode.toUtf8());
141  f.write("\n");
142 
143  elem.offset = offset;
144  offset += elem.name.size() + 1; // +1 for the terminating \0
145  }
146  f.write(R"(
147 };
148 
149 static const CountryToIsoIndex country_to_iso_index[] = {
150 )");
151 
152  for (const auto &elem: processedList) {
153  f.write(" CountryToIsoIndex{");
154  f.write(QByteArray::number(elem.offset));
155  f.write(", \"");
156  f.write(elem.isoCode.toUtf8());
157  f.write("\"},\n");
158  }
159  f.write("};\n");
160 
161  f.close();
162  return 0;
163 }
QString toUpper() const const
QString name(const QVariant &location)
int size() const const
QTextStream & right(QTextStream &stream)
QCommandLineOption addVersionOption()
QString fromUtf8(const char *str, int size)
bool isEmpty() const const
QByteArray number(int n, int base)
QCommandLineOption addHelpOption()
bool isSet(const QString &name) const const
void process(const QStringList &arguments)
void showHelp(int exitCode)
void reserve(int size)
bool addOption(const QCommandLineOption &option)
QString value(const QString &optionName) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Tue Aug 4 2020 22:53:59 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.