File indexing completed on 2024-04-21 14:56:19

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2010 Luigi Toscano <luigi.toscano@tiscali.it>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 
0008 #include "loggingcategory.h"
0009 
0010 #include <QCoreApplication>
0011 #include <QDir>
0012 #include <QFile>
0013 #include <QIODevice>
0014 #include <QList>
0015 #include <QPair>
0016 #include <QRegularExpression>
0017 #include <QStringList>
0018 #include <QTextStream>
0019 
0020 class LangListType : public QList<QPair<QString, QString>>
0021 {
0022 public:
0023     int searchLang(const QString &el)
0024     {
0025         for (int i = 0; i < size(); ++i) {
0026             if (at(i).first == el) {
0027                 return i;
0028             }
0029         }
0030         return -1;
0031     }
0032 };
0033 
0034 int writeLangFile(const QString &fname, const QString &dtdPath, const LangListType &langMap)
0035 {
0036     QFile outFile(fname);
0037     if (!outFile.open(QIODevice::WriteOnly)) {
0038         qCCritical(KDocToolsLog) << QStringLiteral("Could not write %1").arg(outFile.fileName());
0039         return (1);
0040     }
0041 
0042     QTextStream outStream(&outFile);
0043     outStream << "<?xml version='1.0'?>\n";
0044     outStream << QStringLiteral("<!DOCTYPE l:i18n SYSTEM \"%1\" [").arg(dtdPath) << QLatin1Char('\n');
0045 
0046     LangListType::const_iterator i = langMap.constBegin();
0047     while (i != langMap.constEnd()) {
0048         // qCDebug(KDocToolsLog) << (*i).first << ": " << (*i).second;
0049         outStream << QStringLiteral("<!ENTITY %1 SYSTEM \"%2\">").arg((*i).first).arg((*i).second) << QLatin1Char('\n');
0050         ++i;
0051     }
0052     outStream << "]>\n";
0053 
0054     if (!langMap.isEmpty()) {
0055         outStream << "<l:i18n xmlns:l=\"http://docbook.sourceforge.net/xmlns/l10n/1.0\">\n";
0056         i = langMap.constBegin();
0057         while (i != langMap.constEnd()) {
0058             outStream << QStringLiteral("&%1;").arg((*i).first) << QLatin1Char('\n');
0059             ++i;
0060         }
0061         outStream << "</l:i18n>\n";
0062     }
0063 
0064     outFile.close();
0065 
0066     return (0);
0067 }
0068 
0069 int writeLangFileNew(const QString &fname, const QString &dtdPath, const LangListType &langMap)
0070 {
0071     QFile outFile(fname);
0072     if (!outFile.open(QIODevice::WriteOnly)) {
0073         qCCritical(KDocToolsLog) << QStringLiteral("Could not write %1").arg(outFile.fileName());
0074         return (1);
0075     }
0076 
0077     QTextStream outStream(&outFile);
0078     outStream << "<?xml version='1.0'?>\n";
0079     outStream << QStringLiteral("<!DOCTYPE l:i18n SYSTEM \"%1\">").arg(dtdPath) << QLatin1Char('\n');
0080 
0081     if (!langMap.isEmpty()) {
0082         outStream << "<l:i18n xmlns:l=\"http://docbook.sourceforge.net/xmlns/l10n/1.0\">" << QLatin1Char('\n');
0083         LangListType::const_iterator i = langMap.constBegin();
0084         while (i != langMap.constEnd()) {
0085             outStream << QStringLiteral("<l:l10n language=\"%1\" href=\"%2\"/>").arg((*i).first).arg((*i).second) << QLatin1Char('\n');
0086             ++i;
0087         }
0088         outStream << "</l:i18n>\n";
0089     }
0090 
0091     outFile.close();
0092 
0093     return (0);
0094 }
0095 
0096 inline const QString addTrailingSlash(const QString &p)
0097 {
0098     return p.endsWith(QStringLiteral("/")) ? p : p + QStringLiteral("/");
0099 }
0100 
0101 int main(int argc, char **argv)
0102 {
0103     QCoreApplication app(argc, argv);
0104 
0105     const QStringList arguments = app.arguments();
0106     if (arguments.count() != 4) {
0107         qCCritical(KDocToolsLog) << "wrong argument count";
0108         return (1);
0109     }
0110 
0111     const QString l10nDir = addTrailingSlash(arguments[1]);
0112     const QString l10nCustomDir = addTrailingSlash(arguments[2]);
0113     const QString destDir = addTrailingSlash(arguments[3]);
0114 
0115     QFile i18nFile(l10nDir + QStringLiteral("common/l10n.xml"));
0116 
0117     if (!i18nFile.open(QIODevice::ReadOnly)) {
0118         qCCritical(KDocToolsLog) << i18nFile.fileName() << " not found";
0119         return (1);
0120     }
0121 
0122     const QString all10nFName = destDir + QStringLiteral("all-l10n.xml");
0123     const QString customl10nFName = destDir + QStringLiteral("kde-custom-l10n.xml");
0124 
0125     /*
0126      * for each language defined in the original l10n.xml, copy
0127      * it into all-l10n.xml and store it in a list;
0128      **/
0129     const QRegularExpression rxDocType(QStringLiteral("^\\s*<!DOCTYPE\\s+l:i18n\\s+SYSTEM\\s+\"l10n\\.dtd\"\\s+\\[\\s*$"));
0130     const QRegularExpression rxDocType2(QStringLiteral("^\\s*<!DOCTYPE\\s+l:i18n\\s+SYSTEM\\s+\"l10n\\.dtd\"\\s*>$"));
0131     const QRegularExpression rxEntity(QStringLiteral("^\\s*<!ENTITY\\s+([^\\s]+)\\s+SYSTEM\\s+\"([^\\s]+)\">\\s*$"));
0132     const QRegularExpression rxEntity2(QStringLiteral("^\\s*<l:l10n language=\"([^\\s]+)\"\\s+href=\"([^\\s]+)\"/>\\s*$"));
0133     QTextStream inStream(&i18nFile);
0134     int parsingState = 0;
0135 
0136     LangListType allLangs;
0137     LangListType customLangs;
0138 
0139     bool foundRxEntity = false;
0140     bool foundRxEntity2 = false;
0141     while (!inStream.atEnd()) {
0142         QString line = inStream.readLine();
0143 
0144         switch (parsingState) {
0145         case 0:
0146             if (rxDocType.match(line).hasMatch()) {
0147                 parsingState = 1;
0148                 // qCDebug(KDocToolsLog) << "DTD found";
0149             } else if (rxDocType2.match(line).hasMatch()) {
0150                 parsingState = 1;
0151                 // qCDebug(KDocToolsLog) << "DTD found";
0152             }
0153             break;
0154         case 1:
0155             QString langCode, langFile;
0156             QRegularExpressionMatch match = rxEntity.match(line);
0157             if (match.hasMatch() && !foundRxEntity2) {
0158                 foundRxEntity = true;
0159                 langCode = match.captured(1);
0160                 langFile = l10nDir + QStringLiteral("common/") + match.captured(2);
0161                 allLangs += qMakePair(langCode, langFile);
0162                 // qCDebug(KDocToolsLog) << langCode << " - " << langFile;
0163             } else if (!foundRxEntity) {
0164                 match = rxEntity2.match(line);
0165                 if (match.hasMatch()) {
0166                     foundRxEntity2 = true;
0167                     langCode = match.captured(1);
0168                     langFile = l10nDir + QStringLiteral("common/") + match.captured(2);
0169                     allLangs += qMakePair(langCode, langFile);
0170                     // qCDebug(KDocToolsLog) << langCode << " - " << langFile;
0171                 }
0172             }
0173             break;
0174         }
0175     }
0176     i18nFile.close();
0177 
0178     /* read the list of locally-available custom languages */
0179     QDir outDir(l10nCustomDir);
0180 
0181     QStringList dirFileFilters;
0182     dirFileFilters << QStringLiteral("*.xml");
0183     QStringList customLangFiles = outDir.entryList(dirFileFilters, QDir::Files, QDir::Name);
0184     /* the following two calls to removeOne should not be needed, as
0185      * the customization directory from the sources should not contain
0186      * those files
0187      */
0188     customLangFiles.removeOne(QStringLiteral("all-l10n.xml"));
0189     customLangFiles.removeOne(QStringLiteral("kde-custom-l10n.xml"));
0190     // qCDebug(KDocToolsLog) << "customLangFiles:" << customLangFiles;
0191 
0192     /*
0193      * for each custom language (from directory listing), if it is not
0194      * in the list of upstream languages, add it to all-l10n.xml,
0195      * otherwise add it to kde-custom-l10n.xml
0196      */
0197     QStringList::const_iterator i = customLangFiles.constBegin();
0198     while (i != customLangFiles.constEnd()) {
0199         QString langFile = (*i);
0200         /* remove trailing .xml */
0201         QString langCode = langFile.left(langFile.length() - 4);
0202 
0203         QPair<QString, QString> cl = qMakePair(langCode, langFile);
0204         if ((allLangs.searchLang(langCode)) > 0) {
0205             /* custom language found in upstream list */
0206             customLangs += cl;
0207         } else {
0208             /* custom language not found in upstream list */
0209             allLangs += cl;
0210         }
0211         ++i;
0212     }
0213 
0214     int res = 0;
0215 
0216     if (foundRxEntity) {
0217         /* old style (docbook-xsl<=1.75) */
0218         res = writeLangFile(all10nFName, l10nDir + QStringLiteral("common/l10n.dtd"), allLangs);
0219     } else {
0220         res = writeLangFileNew(all10nFName, l10nDir + QStringLiteral("common/l10n.dtd"), allLangs);
0221     }
0222 
0223     return (res);
0224 }