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

KDE's Doxygen guidelines are available online.