/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
if (languageNode)
{
aLanguage = languageNode->getChildAt(0)->getValue(); if (aLanguage.getLength() != 2 && aLanguage.getLength() != 3)
incErrorStr( "Error: langID '%s' not 2-3 characters\n", aLanguage);
of.writeOUStringLiteralParameter("langID", aLanguage);
of.writeOUStringLiteralParameter("langDefaultName", languageNode->getChildAt(1)->getValue());
} else
incError( "No Language node."); if (countryNode)
{
OUString aCountry( countryNode->getChildAt(0)->getValue()); if (!(aCountry.isEmpty() || aCountry.getLength() == 2))
incErrorStr( "Error: countryID '%s' not empty or more than 2 characters\n", aCountry);
of.writeOUStringLiteralParameter("countryID", aCountry);
of.writeOUStringLiteralParameter("countryDefaultName", countryNode->getChildAt(1)->getValue());
} else
incError( "No Country node."); if (variantNode)
{ // If given Variant must be at least ll-Ssss and language must be 'qlt' const OUString& aVariant( variantNode->getValue()); if (!(aVariant.isEmpty() || (aVariant.getLength() >= 7 && aVariant.indexOf('-') >= 2)))
incErrorStr( "Error: invalid Variant '%s'\n", aVariant); if (!(aVariant.isEmpty() || aLanguage == "qlt"))
incErrorStrStr( "Error: Variant '%s' given but Language '%s' is not 'qlt'\n", aVariant, aLanguage);
of.writeOUStringLiteralParameter("Variant", aVariant);
} else
of.writeOUStringLiteralParameter("Variant", std::u16string_view());
of.writeAsciiString("\nstatic constexpr OUString LCInfoArray[] = {\n");
of.writeAsciiString("\tlangID,\n");
of.writeAsciiString("\tlangDefaultName,\n");
of.writeAsciiString("\tcountryID,\n");
of.writeAsciiString("\tcountryDefaultName,\n");
of.writeAsciiString("\tVariant\n");
of.writeAsciiString("};\n\n");
of.writeOUStringFunction("getLCInfo_", "std::size(LCInfoArray)", "LCInfoArray");
}
sepNode = findNode("LongDateDayOfWeekSeparator");
aLDS = sepNode->getValue();
of.writeOUStringLiteralParameter("LongDateDayOfWeekSeparator", aLDS); if (aLDS == ",")
fprintf( stderr, "Warning: %s\n", "LongDateDayOfWeekSeparator is only a comma not followed by a space. Usually this is not the case and may lead to concatenated display names like \"Wednesday,May 9, 2007\".");
sepNode = findNode("LongDateDaySeparator");
aLDS = sepNode->getValue();
of.writeOUStringLiteralParameter("LongDateDaySeparator", aLDS); if (aLDS == "," || aLDS == ".")
fprintf( stderr, "Warning: %s\n", "LongDateDaySeparator is only a comma or dot not followed by a space. Usually this is not the case and may lead to concatenated display names like \"Wednesday, May 9,2007\".");
sepNode = findNode("LongDateMonthSeparator");
aLDS = sepNode->getValue();
of.writeOUStringLiteralParameter("LongDateMonthSeparator", aLDS); if (aLDS.isEmpty())
fprintf( stderr, "Warning: %s\n", "LongDateMonthSeparator is empty. Usually this is not the case and may lead to concatenated display names like \"Wednesday, May9, 2007\".");
sepNode = findNode("LongDateYearSeparator");
aLDS = sepNode->getValue();
of.writeOUStringLiteralParameter("LongDateYearSeparator", aLDS); if (aLDS.isEmpty())
fprintf( stderr, "Warning: %s\n", "LongDateYearSeparator is empty. Usually this is not the case and may lead to concatenated display names like \"Wednesday, 2007May 9\".");
int nSavErr = nError; int nWarn = 0; if (aDateSep == aTimeSep)
incError( "DateSeparator equals TimeSeparator."); if (aDecSep == aThoSep)
incError( "DecimalSeparator equals ThousandSeparator."); if (aDecSepAlt == aThoSep)
incError( "DecimalSeparatorAlternative equals ThousandSeparator."); if (aDecSepAlt == aDecSep)
incError( "DecimalSeparatorAlternative equals DecimalSeparator, it must not be specified then."); if ( aThoSep == " " )
incError( "ThousandSeparator is an ' ' ordinary space, this should be a non-breaking space U+00A0 instead."); if (aListSep == aDecSep)
fprintf( stderr, "Warning: %s\n", "ListSeparator equals DecimalSeparator."); if (aListSep == aThoSep)
fprintf( stderr, "Warning: %s\n", "ListSeparator equals ThousandSeparator."); if (aListSep.getLength() != 1 || aListSep[0] != ';')
{
incError( "ListSeparator not ';' semicolon. Strongly recommended. Currently required.");
++nSavErr; // format codes not affected
} if (aTimeSep == aTime100Sep)
{
++nWarn;
fprintf( stderr, "Warning: %s\n", "Time100SecSeparator equals TimeSeparator, this is probably an error.");
} if (aDecSep != aTime100Sep)
{
++nWarn;
fprintf( stderr, "Warning: %s\n", "Time100SecSeparator is different from DecimalSeparator, this may be correct or not. Intended?");
} if (nSavErr != nError || nWarn)
fprintf( stderr, "Warning: %s\n", "Don't forget to adapt corresponding FormatCode elements when changing separators.");
if (aQuoteStart.toChar() <= 127 && aQuoteEnd.toChar() > 127)
fprintf( stderr, "Warning: %s\n", "QuotationStart is an ASCII character but QuotationEnd is not."); if (aQuoteEnd.toChar() <= 127 && aQuoteStart.toChar() > 127)
fprintf( stderr, "Warning: %s\n", "QuotationEnd is an ASCII character but QuotationStart is not."); if (aDoubleQuoteStart.toChar() <= 127 && aDoubleQuoteEnd.toChar() > 127)
fprintf( stderr, "Warning: %s\n", "DoubleQuotationStart is an ASCII character but DoubleQuotationEnd is not."); if (aDoubleQuoteEnd.toChar() <= 127 && aDoubleQuoteStart.toChar() > 127)
fprintf( stderr, "Warning: %s\n", "DoubleQuotationEnd is an ASCII character but DoubleQuotationStart is not."); if (aQuoteStart.toChar() <= 127 && aQuoteEnd.toChar() <= 127)
fprintf( stderr, "Warning: %s\n", "QuotationStart and QuotationEnd are both ASCII characters. Not necessarily an issue, but unusual."); if (aDoubleQuoteStart.toChar() <= 127 && aDoubleQuoteEnd.toChar() <= 127)
fprintf( stderr, "Warning: %s\n", "DoubleQuotationStart and DoubleQuotationEnd are both ASCII characters. Not necessarily an issue, but unusual."); if (aQuoteStart == aQuoteEnd)
fprintf( stderr, "Warning: %s\n", "QuotationStart equals QuotationEnd. Not necessarily an issue, but unusual."); if (aDoubleQuoteStart == aDoubleQuoteEnd)
fprintf( stderr, "Warning: %s\n", "DoubleQuotationStart equals DoubleQuotationEnd. Not necessarily an issue, but unusual."); /* TODO: should equalness of single and double quotes be an error? Would
* need to adapt quite some locales' data. */ if (aQuoteStart == aDoubleQuoteStart)
fprintf( stderr, "Warning: %s\n", "QuotationStart equals DoubleQuotationStart. Not necessarily an issue, but unusual."); if (aQuoteEnd == aDoubleQuoteEnd)
fprintf( stderr, "Warning: %s\n", "QuotationEnd equals DoubleQuotationEnd. Not necessarily an issue, but unusual."); // Known good values, exclude ASCII single (U+0027, ') and double (U+0022, ") quotes. switch (int ic = aQuoteStart.toChar())
{ case 0x2018: // LEFT SINGLE QUOTATION MARK case 0x201a: // SINGLE LOW-9 QUOTATION MARK case 0x201b: // SINGLE HIGH-REVERSED-9 QUOTATION MARK case 0x2039: // SINGLE LEFT-POINTING ANGLE QUOTATION MARK case 0x203a: // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK case 0x300c: // LEFT CORNER BRACKET (Chinese)
; break; default:
fprintf( stderr, "Warning: %s U+%04X %s\n", "QuotationStart may be wrong:", ic, OSTR( aQuoteStart));
} switch (int ic = aQuoteEnd.toChar())
{ case 0x2019: // RIGHT SINGLE QUOTATION MARK case 0x201a: // SINGLE LOW-9 QUOTATION MARK case 0x201b: // SINGLE HIGH-REVERSED-9 QUOTATION MARK case 0x2039: // SINGLE LEFT-POINTING ANGLE QUOTATION MARK case 0x203a: // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK case 0x300d: // RIGHT CORNER BRACKET (Chinese)
; break; default:
fprintf( stderr, "Warning: %s U+%04X %s\n", "QuotationEnd may be wrong:", ic, OSTR( aQuoteEnd));
} switch (int ic = aDoubleQuoteStart.toChar())
{ case 0x00ab: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK case 0x00bb: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK case 0x201c: // LEFT DOUBLE QUOTATION MARK case 0x201e: // DOUBLE LOW-9 QUOTATION MARK case 0x201f: // DOUBLE HIGH-REVERSED-9 QUOTATION MARK case 0x300e: // LEFT WHITE CORNER BRACKET (Chinese)
; break; default:
fprintf( stderr, "Warning: %s U+%04X %s\n", "DoubleQuotationStart may be wrong:", ic, OSTR( aDoubleQuoteStart));
} switch (int ic = aDoubleQuoteEnd.toChar())
{ case 0x00ab: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK case 0x00bb: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK case 0x201d: // RIGHT DOUBLE QUOTATION MARK case 0x201e: // DOUBLE LOW-9 QUOTATION MARK case 0x201f: // DOUBLE HIGH-REVERSED-9 QUOTATION MARK case 0x300f: // RIGHT WHITE CORNER BRACKET (Chinese)
; break; default:
fprintf( stderr, "Warning: %s U+%04X %s\n", "DoubleQuotationEnd may be wrong:", ic, OSTR( aDoubleQuoteEnd));
}
OUString str;
OUString strFrom( getAttr().getValueByName("replaceFrom")); if (useLocale.isEmpty())
{
of.writeParameter("replaceFrom", strFrom, mnSection);
}
str = getAttr().getValueByName("replaceTo"); if (!strFrom.isEmpty() && str.isEmpty())
incErrorStr("replaceFrom=\"%s\" replaceTo=\"\" is empty replacement.\n", strFrom); // Locale data generator inserts FFFF for LangID, we need to adapt that. if (str.endsWithIgnoreAsciiCase( "-FFFF]"))
incErrorStr("replaceTo=\"%s\" needs FFFF to be adapted to the real LangID value.\n", str);
of.writeParameter("replaceTo", str, mnSection); // Remember the replaceTo value for "[CURRENCY]" to check format codes. if ( strFrom == "[CURRENCY]" )
sTheCurrencyReplaceTo = str; // Remember the currency symbol if present. if (str.startsWith( "[$" ))
{
sal_Int32 nHyphen = str.indexOf( '-'); if (nHyphen >= 3)
{
sTheCompatibleCurrency = str.copy( 2, nHyphen - 2);
}
}
if (!useLocale.isEmpty())
{ if (!strFrom.isEmpty() && strFrom != "[CURRENCY]") //???
{
incErrorStrStr( "Error: non-empty replaceFrom=\"%s\" with non-empty ref=\"%s\".",
strFrom, useLocale);
}
useLocale = useLocale.replace( '-', '_'); switch (mnSection)
{ case 0:
of.writeOUStringRefFunction("getAllFormats0_", useLocale, "replaceTo0");
of.writeOUStringRefFunction("getDateAcceptancePatterns_", useLocale); break; case 1:
of.writeOUStringRefFunction("getAllFormats1_", useLocale, "replaceTo1"); break;
}
++mnSection; return;
}
aFormatIndex = currNodeAttr.getValueByName("formatindex");
sal_Int16 formatindex = static_cast<sal_Int16>(aFormatIndex.toInt32()); // Ensure the new reserved range is not used anymore, free usage start // was up'ed from 50 to 60 (and more later). if (i18npool::nStopPredefinedFormatIndex <= formatindex && formatindex < i18npool::nFirstFreeFormatIndex)
{
incErrorInt( "Error: Reserved formatindex=\"%d\" in FormatElement.\n", formatindex);
bShowNextFreeFormatIndex = true;
} if (!aFormatIndexSet.insert( formatindex).second)
{
incErrorInt( "Error: Duplicated formatindex=\"%d\" in FormatElement.\n", formatindex);
bShowNextFreeFormatIndex = true;
}
of.writeOUStringLiteralIntParameter("Formatindex", formatCount, formatindex);
// Ensure only one default per usage and type. if (bDefault)
{
OUString aKey( aUsage + "," + aType); if (!aDefaultsSet.insert( aKey).second)
{
OUString aStr = "Duplicated default for usage=\"" + aUsage + "\" type=\"" + aType + "\": formatindex=\"" + aFormatIndex + "\".";
incError( aStr);
}
}
const LocaleNode * n = currNode -> findNode("FormatCode"); if (n)
{
of.writeOUStringLiteralParameter("FormatCode", n->getValue(), formatCount); // Check separator usage for some FormatCode elements. const LocaleNode* pCtype = nullptr; switch (formatindex)
{ case cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY :
sTheDateEditFormat = n->getValue(); break; case cssi::NumberFormatIndex::NUMBER_1000DEC2 : // #,##0.00 case cssi::NumberFormatIndex::TIME_MMSS00 : // MM:SS.00 case cssi::NumberFormatIndex::TIME_HH_MMSS00 : // [HH]:MM:SS.00
{ const LocaleNode* pRoot = getRoot(); if (!pRoot)
incError( "No root for FormatCode."); else
{
pCtype = pRoot->findNode( "LC_CTYPE"); if (!pCtype)
incError( "No LC_CTYPE found for FormatCode."); else
{
OUString aRef( pCtype->getAttr().getValueByName("ref")); if (!aRef.isEmpty())
{
aRef = aRef.replace( '-', '_'); if (!bCtypeIsRef)
fprintf( stderr, "Warning: Can't check separators used in FormatCode due to LC_CTYPE ref=\"%s\".\n" "If these two locales use identical format codes, you should consider to use the ref= mechanism also for the LC_FORMAT element, together with replaceFrom= and replaceTo= for the currency.\n",
OSTR( aRef));
bCtypeIsRef = true;
pCtype = nullptr;
}
}
}
} break; case cssi::NumberFormatIndex::CURRENCY_1000DEC2 : // Remember the currency symbol if present.
{ if (sTheCompatibleCurrency.isEmpty())
{
sal_Int32 nStart = n->getValue().indexOf("[$"); if (nStart >= 0)
{ const OUString& aCode( n->getValue());
sal_Int32 nHyphen = aCode.indexOf( '-', nStart); if (nHyphen >= nStart + 3)
sTheCompatibleCurrency = aCode.copy( nStart + 2, nHyphen - nStart - 2);
}
}
}
[[fallthrough]]; case cssi::NumberFormatIndex::CURRENCY_1000INT : case cssi::NumberFormatIndex::CURRENCY_1000INT_RED : case cssi::NumberFormatIndex::CURRENCY_1000DEC2_RED : case cssi::NumberFormatIndex::CURRENCY_1000DEC2_CCC : case cssi::NumberFormatIndex::CURRENCY_1000DEC2_DASHED : // Currency formats should be something like [C]###0;-[C]###0 // and not parenthesized [C]###0;([C]###0) if not en_US. if (strcmp( of.getLocale(), "en_US") != 0)
{ const OUString& aCode( n->getValue()); if (aCode.indexOf( "0)" ) > 0 || aCode.indexOf( "-)" ) > 0 ||
aCode.indexOf( " )" ) > 0 || aCode.indexOf( "])" ) > 0)
fprintf( stderr, "Warning: FormatCode formatindex=\"%d\" for currency uses parentheses for negative amounts, which probably is not correct for locales not based on en_US.\n", formatindex);
} // Check if we have replaceTo for "[CURRENCY]" placeholder. if (sTheCurrencyReplaceTo.isEmpty())
{ const OUString& aCode( n->getValue()); if (aCode.indexOf( "[CURRENCY]" ) >= 0)
incErrorInt( "Error: [CURRENCY] replaceTo not found for formatindex=\"%d\".\n", formatindex);
} break; default: if (aUsage == "SCIENTIFIC_NUMBER")
{ // Check for presence of ##0.00E+00 const OUString& aCode( n->getValue()); // Simple check without decimal separator (assumed to // be one UTF-16 character). May be prefixed with // [NatNum1] or other tags.
sal_Int32 nInt = aCode.indexOf("##0");
sal_Int32 nDec = (nInt < 0 ? -1 : aCode.indexOf("00E+00", nInt)); if (nInt >= 0 && nDec == nInt+4)
bHaveEngineering = true;
} break;
} if (pCtype)
{ int nSavErr = nError; const OUString& aCode( n->getValue()); if (formatindex == cssi::NumberFormatIndex::NUMBER_1000DEC2)
{
sal_Int32 nDec = -1;
sal_Int32 nGrp = -1; const LocaleNode* pSep = pCtype->findNode( "DecimalSeparator"); if (!pSep)
incError( "No DecimalSeparator found for FormatCode."); else
{
nDec = aCode.indexOf( pSep->getValue()); if (nDec < 0)
incErrorInt( "Error: DecimalSeparator not present in FormatCode formatindex=\"%d\".\n",
formatindex);
}
pSep = pCtype->findNode( "ThousandSeparator"); if (!pSep)
incError( "No ThousandSeparator found for FormatCode."); else
{
nGrp = aCode.indexOf( pSep->getValue()); if (nGrp < 0)
incErrorInt( "Error: ThousandSeparator not present in FormatCode formatindex=\"%d\".\n",
formatindex);
} if (nDec >= 0 && nGrp >= 0 && nDec <= nGrp)
incErrorInt( "Error: Ordering of ThousandSeparator and DecimalSeparator not correct in formatindex=\"%d\".\n",
formatindex);
} if (formatindex == cssi::NumberFormatIndex::TIME_MMSS00 ||
formatindex == cssi::NumberFormatIndex::TIME_HH_MMSS00)
{
sal_Int32 nTime = -1;
sal_Int32 n100s = -1; const LocaleNode* pSep = pCtype->findNode( "TimeSeparator"); if (!pSep)
incError( "No TimeSeparator found for FormatCode."); else
{
nTime = aCode.indexOf( pSep->getValue()); if (nTime < 0)
incErrorInt( "Error: TimeSeparator not present in FormatCode formatindex=\"%d\".\n",
formatindex);
}
pSep = pCtype->findNode( "Time100SecSeparator"); if (!pSep)
incError( "No Time100SecSeparator found for FormatCode."); else
{
n100s = aCode.indexOf( pSep->getValue()); if (n100s < 0)
incErrorInt( "Error: Time100SecSeparator not present in FormatCode formatindex=\"%d\".\n",
formatindex);
n100s = aCode.indexOf( Concat2View(pSep->getValue() + "00")); if (n100s < 0)
incErrorInt( "Error: Time100SecSeparator+00 not present in FormatCode formatindex=\"%d\".\n",
formatindex);
} if (n100s >= 0 && nTime >= 0 && n100s <= nTime)
incErrorInt( "Error: Ordering of Time100SecSeparator and TimeSeparator not correct in formatindex=\"%d\".\n",
formatindex);
} if (nSavErr != nError)
fprintf( stderr, "Warning: formatindex=\"%d\",\"%d\",\"%d\" are the only FormatCode elements checked for separator usage, there may be others that have errors.\n", int(cssi::NumberFormatIndex::NUMBER_1000DEC2), int(cssi::NumberFormatIndex::TIME_MMSS00), int(cssi::NumberFormatIndex::TIME_HH_MMSS00));
}
} else
incError( "No FormatCode in FormatElement.");
n = currNode -> findNode("DefaultName"); if (n)
of.writeOUStringLiteralParameter("FormatDefaultName", n->getValue(), formatCount); else
of.writeOUStringLiteralParameter("FormatDefaultName", std::u16string_view(), formatCount);
}
if (bShowNextFreeFormatIndex)
{
sal_Int16 nNext = i18npool::nFirstFreeFormatIndex; auto it = aFormatIndexSet.find( nNext); if (it != aFormatIndexSet.end())
{ // nFirstFreeFormatIndex already used, find next free including gaps. do
{
++nNext;
} while (++it != aFormatIndexSet.end() && *it == nNext);
}
fprintf( stderr, "Hint: Next free formatindex is %d.\n", static_cast<int>(nNext));
}
// Check presence of all required format codes only in first section // LC_FORMAT, not in optional LC_FORMAT_1 if (mnSection == 0)
{ // At least one abbreviated date acceptance pattern must be present. if (theDateAcceptancePatterns.empty())
incError( "No DateAcceptancePattern present.\n"); else
{ bool bHaveAbbr = false; for (autoconst& elem : theDateAcceptancePatterns)
{ if (elem.indexOf('D') > -1 && elem.indexOf('M') > -1 && elem.indexOf('Y') <= -1)
{
bHaveAbbr = true; break;
}
} if (!bHaveAbbr)
incError( "No abbreviated DateAcceptancePattern present. For example M/D or D.M.\n");
}
// 0..9 MUST be present, 10,11 MUST NOT be present, 12..47 MUST be // present, 48,49 MUST NOT be present, 50 MUST be present.
ValueSet::const_iterator aIter( aFormatIndexSet.begin()); for (sal_Int16 nNext = cssi::NumberFormatIndex::NUMBER_START;
nNext < i18npool::nStopPredefinedFormatIndex; ++nNext)
{
sal_Int16 nHere = ::std::min( (aIter != aFormatIndexSet.end() ? *aIter :
i18npool::nStopPredefinedFormatIndex),
i18npool::nStopPredefinedFormatIndex); if (aIter != aFormatIndexSet.end()) ++aIter; for ( ; nNext < nHere; ++nNext)
{ switch (nNext)
{ case cssi::NumberFormatIndex::FRACTION_1 : case cssi::NumberFormatIndex::FRACTION_2 : case cssi::NumberFormatIndex::BOOLEAN : case cssi::NumberFormatIndex::TEXT : // generated internally break; default:
incErrorInt( "Error: FormatElement formatindex=\"%d\" not present.\n", nNext);
}
} switch (nHere)
{ case cssi::NumberFormatIndex::FRACTION_1 :
incErrorInt( "Error: FormatElement formatindex=\"%d\" reserved for internal ``# ?/?''.\n", nNext); break; case cssi::NumberFormatIndex::FRACTION_2 :
incErrorInt( "Error: FormatElement formatindex=\"%d\" reserved for internal ``# ?\?/?\?''.\n", nNext); break; case cssi::NumberFormatIndex::BOOLEAN :
incErrorInt( "Error: FormatElement formatindex=\"%d\" reserved for internal ``BOOLEAN''.\n", nNext); break; case cssi::NumberFormatIndex::TEXT :
incErrorInt( "Error: FormatElement formatindex=\"%d\" reserved for internal ``@'' (TEXT).\n", nNext); break; default:
; // nothing
}
}
if (!bHaveEngineering)
incError("Engineering notation format not present, e.g. ##0.00E+00 or ##0,00E+00 for usage=\"SCIENTIFIC_NUMBER\"\n");
}
// Rudimentary check if a pattern interferes with decimal number. // But only if not inherited in which case we don't have aDecSep here. if (!aDecSep.isEmpty())
{
sal_uInt32 cDecSep = aDecSep.iterateCodePoints( &o3tl::temporary(sal_Int32(0))); for (autoconst& elem : theDateAcceptancePatterns)
{ if (elem.getLength() == (cDecSep <= 0xffff ? 3 : 4))
{ if (elem.iterateCodePoints( &o3tl::temporary(sal_Int32(1))) == cDecSep)
{
++nError;
fprintf( stderr, "Error: Date acceptance pattern '%s' matches decimal number '#%s#'\n",
OSTR(elem), OSTR( aDecSep));
}
}
}
}
for (sal_Int16 i = 0; i < nbOfDateAcceptancePatterns; ++i)
{
of.writeOUStringLiteralParameter("DateAcceptancePattern", theDateAcceptancePatterns[i], i);
}
void LCCalendarNode::generateCode (const OFileWriter &of) const
{
OUString useLocale = getAttr().getValueByName("ref"); if (!useLocale.isEmpty()) {
useLocale = useLocale.replace( '-', '_');
of.writeOUStringRefFunction("getAllCalendars_", useLocale); return;
}
sal_Int16 nbOfCalendars = sal::static_int_cast<sal_Int16>( getNumberOfChildren() );
OUString str;
std::unique_ptr<sal_Int16[]> nbOfDays( new sal_Int16[nbOfCalendars] );
std::unique_ptr<sal_Int16[]> nbOfMonths( new sal_Int16[nbOfCalendars] );
std::unique_ptr<sal_Int16[]> nbOfGenitiveMonths( new sal_Int16[nbOfCalendars] );
std::unique_ptr<sal_Int16[]> nbOfPartitiveMonths( new sal_Int16[nbOfCalendars] );
std::unique_ptr<sal_Int16[]> nbOfEras( new sal_Int16[nbOfCalendars] );
// Known allowed calendar identifiers (unoid) and whether used or not. // Of course there must be an implementation for new to be added // identifiers.. see data/locale.dtd
std::map< OUString, bool > aCalendars;
aCalendars[u"buddhist"_ustr] = false;
aCalendars[u"gengou"_ustr] = false;
aCalendars[u"gregorian"_ustr] = false;
aCalendars[u"hanja"_ustr] = false;
aCalendars[u"hanja_yoil"_ustr] = false;
aCalendars[u"hijri"_ustr] = false;
aCalendars[u"jewish"_ustr] = false;
aCalendars[u"ROC"_ustr] = false; // Not in ODF:
aCalendars[u"dangi"_ustr] = false;
aCalendars[u"persian"_ustr] = false;
// Generate Days of Week constchar *elementTag;
LocaleNode * daysNode = nullptr;
OUString ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
ref_name = ref_name.replace( '-', '_'); if (!ref_name.isEmpty() && i > 0) { for (j = 0; j < i; j++) {
str = getChildAt(j)->getAttr().getValueByName("unoid"); if (str == ref_name)
daysNode = getChildAt(j)->getChildAt(0);
}
} if (!ref_name.isEmpty() && daysNode == nullptr) {
of.writeOUStringLiteralParameter("dayRef", u"ref", i);
of.writeOUStringLiteralParameter("dayRefName", ref_name, i);
nbOfDays[i] = 0;
} else { if (daysNode == nullptr)
daysNode = calNode -> getChildAt(nChild);
nbOfDays[i] = sal::static_int_cast<sal_Int16>( daysNode->getNumberOfChildren() ); if (bGregorian && nbOfDays[i] != 7)
incErrorInt( "Error: A Gregorian calendar must have 7 days per week, this one has %d\n", nbOfDays[i]);
elementTag = "day"; for (j = 0; j < nbOfDays[i]; j++) {
LocaleNode *currNode = daysNode -> getChildAt(j);
OUString dayID( currNode->getChildAt(0)->getValue());
of.writeOUStringLiteralParameter("dayID", dayID, i, j); if ( j == 0 && bGregorian && dayID != "sun" )
incError( "First day of a week of a Gregorian calendar must be <DayID>sun</DayID>");
lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
}
}
++nChild;
// Generate Months of Year
LocaleNode * monthsNode = nullptr;
ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
ref_name = ref_name.replace( '-', '_'); if (!ref_name.isEmpty() && i > 0) { for (j = 0; j < i; j++) {
str = getChildAt(j)->getAttr().getValueByName("unoid"); if (str == ref_name)
monthsNode = getChildAt(j)->getChildAt(1);
}
} if (!ref_name.isEmpty() && monthsNode == nullptr) {
of.writeOUStringLiteralParameter("monthRef", u"ref", i);
of.writeOUStringLiteralParameter("monthRefName", ref_name, i);
nbOfMonths[i] = 0;
} else { if (monthsNode == nullptr)
monthsNode = calNode -> getChildAt(nChild);
nbOfMonths[i] = sal::static_int_cast<sal_Int16>( monthsNode->getNumberOfChildren() ); if (bGregorian && nbOfMonths[i] != 12)
incErrorInt( "Error: A Gregorian calendar must have 12 months, this one has %d\n", nbOfMonths[i]);
elementTag = "month"; for (j = 0; j < nbOfMonths[i]; j++) {
LocaleNode *currNode = monthsNode -> getChildAt(j);
OUString monthID( currNode->getChildAt(0)->getValue());
of.writeOUStringLiteralParameter("monthID", monthID, i, j); if ( j == 0 && bGregorian && monthID != "jan" )
incError( "First month of a year of a Gregorian calendar must be <MonthID>jan</MonthID>");
lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
}
}
++nChild;
// Generate genitive Months of Year // Optional, if not present fall back to month nouns. if ( calNode->getChildAt(nChild)->getName() != "GenitiveMonths" )
--nChild;
LocaleNode * genitiveMonthsNode = nullptr;
ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
ref_name = ref_name.replace( '-', '_'); if (!ref_name.isEmpty() && i > 0) { for (j = 0; j < i; j++) {
str = getChildAt(j)->getAttr().getValueByName("unoid"); if (str == ref_name)
genitiveMonthsNode = getChildAt(j)->getChildAt(1);
}
} if (!ref_name.isEmpty() && genitiveMonthsNode == nullptr) {
of.writeOUStringLiteralParameter("genitiveMonthRef", u"ref", i);
of.writeOUStringLiteralParameter("genitiveMonthRefName", ref_name, i);
nbOfGenitiveMonths[i] = 0;
} else { if (genitiveMonthsNode == nullptr)
genitiveMonthsNode = calNode -> getChildAt(nChild);
nbOfGenitiveMonths[i] = sal::static_int_cast<sal_Int16>( genitiveMonthsNode->getNumberOfChildren() ); if (bGregorian && nbOfGenitiveMonths[i] != 12)
incErrorInt( "Error: A Gregorian calendar must have 12 genitive months, this one has %d\n", nbOfGenitiveMonths[i]);
elementTag = "genitiveMonth"; for (j = 0; j < nbOfGenitiveMonths[i]; j++) {
LocaleNode *currNode = genitiveMonthsNode -> getChildAt(j);
OUString genitiveMonthID( currNode->getChildAt(0)->getValue());
of.writeOUStringLiteralParameter("genitiveMonthID", genitiveMonthID, i, j); if ( j == 0 && bGregorian && genitiveMonthID != "jan" )
incError( "First genitive month of a year of a Gregorian calendar must be <MonthID>jan</MonthID>");
lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
}
}
++nChild;
// Generate partitive Months of Year // Optional, if not present fall back to genitive months, or nominative // months (nouns) if that isn't present either. if ( calNode->getChildAt(nChild)->getName() != "PartitiveMonths" )
--nChild;
LocaleNode * partitiveMonthsNode = nullptr;
ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
ref_name = ref_name.replace( '-', '_'); if (!ref_name.isEmpty() && i > 0) { for (j = 0; j < i; j++) {
str = getChildAt(j)->getAttr().getValueByName("unoid"); if (str == ref_name)
partitiveMonthsNode = getChildAt(j)->getChildAt(1);
}
} if (!ref_name.isEmpty() && partitiveMonthsNode == nullptr) {
of.writeOUStringLiteralParameter("partitiveMonthRef", u"ref", i);
of.writeOUStringLiteralParameter("partitiveMonthRefName", ref_name, i);
nbOfPartitiveMonths[i] = 0;
} else { if (partitiveMonthsNode == nullptr)
partitiveMonthsNode = calNode -> getChildAt(nChild);
nbOfPartitiveMonths[i] = sal::static_int_cast<sal_Int16>( partitiveMonthsNode->getNumberOfChildren() ); if (bGregorian && nbOfPartitiveMonths[i] != 12)
incErrorInt( "Error: A Gregorian calendar must have 12 partitive months, this one has %d\n", nbOfPartitiveMonths[i]);
elementTag = "partitiveMonth"; for (j = 0; j < nbOfPartitiveMonths[i]; j++) {
LocaleNode *currNode = partitiveMonthsNode -> getChildAt(j);
OUString partitiveMonthID( currNode->getChildAt(0)->getValue());
of.writeOUStringLiteralParameter("partitiveMonthID", partitiveMonthID, i, j); if ( j == 0 && bGregorian && partitiveMonthID != "jan" )
incError( "First partitive month of a year of a Gregorian calendar must be <MonthID>jan</MonthID>");
lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
}
}
++nChild;
// Generate Era name
LocaleNode * erasNode = nullptr;
ref_name = calNode -> getChildAt(nChild) ->getAttr().getValueByName("ref");
ref_name = ref_name.replace( '-', '_'); if (!ref_name.isEmpty() && i > 0) { for (j = 0; j < i; j++) {
str = getChildAt(j)->getAttr().getValueByName("unoid"); if (str == ref_name)
erasNode = getChildAt(j)->getChildAt(2);
}
} if (!ref_name.isEmpty() && erasNode == nullptr) {
of.writeOUStringLiteralParameter("eraRef", u"ref", i);
of.writeOUStringLiteralParameter("eraRefName", ref_name, i);
nbOfEras[i] = 0;
} else { if (erasNode == nullptr)
erasNode = calNode -> getChildAt(nChild); if (!expectedCalendarElement(u"Eras", erasNode, -1, calendarID))
{
--nChild;
} else
{
nbOfEras[i] = sal::static_int_cast<sal_Int16>( erasNode->getNumberOfChildren() ); if (bGregorian && nbOfEras[i] != 2)
incErrorInt( "Error: A Gregorian calendar must have 2 eras, this one has %d\n", nbOfEras[i]);
elementTag = "era"; for (j = 0; j < nbOfEras[i]; j++) {
LocaleNode *currNode = erasNode -> getChildAt(j); if (!expectedCalendarElement(u"Era", currNode, -1, calendarID))
{ continue; // for
}
OUString eraID( currNode->getChildAt(0)->getValue());
of.writeOUStringLiteralParameter("eraID", eraID, i, j); if ( j == 0 && bGregorian && eraID != "bc" )
incError( "First era of a Gregorian calendar must be <EraID>bc</EraID>"); if ( j == 1 && bGregorian && eraID != "ad" )
incError( "Second era of a Gregorian calendar must be <EraID>ad</EraID>");
of.writeAsciiString("\n");
of.writeOUStringLiteralParameter(elementTag, "DefaultAbbrvName",currNode->getChildAt(1)->getValue() ,i, j);
of.writeOUStringLiteralParameter(elementTag, "DefaultFullName",currNode->getChildAt(2)->getValue() , i, j);
}
}
}
++nChild;
if (expectedCalendarElement(u"StartDayOfWeek", calNode, nChild, calendarID))
{
str = calNode->getChildAt(nChild)->getChildAt(0)->getValue(); if (nbOfDays[i])
{ for (j = 0; j < nbOfDays[i]; j++)
{
LocaleNode *currNode = daysNode->getChildAt(j);
OUString dayID( currNode->getChildAt(0)->getValue()); if (str == dayID) break; // for
} if (j >= nbOfDays[i])
incErrorStr( "Error: <StartDayOfWeek> <DayID> must be one of the <DaysOfWeek>, but is: %s\n", str);
}
of.writeOUStringLiteralParameter("startDayOfWeek", str, i);
++nChild;
}
if (expectedCalendarElement(u"MinimalDaysInFirstWeek", calNode, nChild, calendarID))
{
str = calNode ->getChildAt(nChild)-> getValue();
sal_Int16 nDays = sal::static_int_cast<sal_Int16>( str.toInt32() ); if (nDays < 1 || (0 < nbOfDays[i] && nbOfDays[i] < nDays))
incErrorInt( "Error: Bad value of MinimalDaysInFirstWeek: %d, must be 1 <= value <= days_in_week\n",
nDays);
of.writeOUStringLiteralIntParameter("minimalDaysInFirstWeek", i, nDays);
}
} if (!bHasGregorian)
fprintf( stderr, "Warning: %s\n", "No Gregorian calendar defined, are you sure?");
bool bTheDefault= false; bool bTheCompatible = false; for ( sal_Int32 i = 0; i < getNumberOfChildren(); i++,nbOfCurrencies++) {
LocaleNode * currencyNode = getChildAt (i);
str = currencyNode->getAttr().getValueByName("default"); bool bDefault = of.writeOUStringLiteralDefaultParameter("Currency", str, nbOfCurrencies);
str = currencyNode->getAttr().getValueByName("usedInCompatibleFormatCodes"); bool bCompatible = of.writeOUStringLiteralDefaultParameter("CurrencyUsedInCompatibleFormatCodes", str, nbOfCurrencies);
str = currencyNode->getAttr().getValueByName("legacyOnly"); bool bLegacy = of.writeOUStringLiteralDefaultParameter("CurrencyLegacyOnly", str, nbOfCurrencies); if (bLegacy && (bDefault || bCompatible))
incError( "Currency: if legacyOnly==true, both 'default' and 'usedInCompatibleFormatCodes' must be false."); if (bDefault)
{ if (bTheDefault)
incError( "Currency: more than one default currency.");
bTheDefault = true;
} if (bCompatible)
{ if (bTheCompatible)
incError( "Currency: more than one currency flagged as usedInCompatibleFormatCodes.");
bTheCompatible = true;
}
str = currencyNode -> findNode ("CurrencyID") -> getValue();
of.writeOUStringLiteralParameter("currencyID", str, nbOfCurrencies); // CurrencyID MUST be ISO 4217. if (!bLegacy && !isIso4217(str))
incError( "CurrencyID is not ISO 4217");
str = currencyNode -> findNode ("CurrencySymbol") -> getValue();
of.writeOUStringLiteralParameter("currencySymbol", str, nbOfCurrencies); // Check if this currency really is the one used in number format // codes. In case of ref=... mechanisms it may be that TheCurrency // couldn't had been determined from the current locale (i.e. is // empty), silently assume the referred locale has things right. if (bCompatible && !sTheCompatibleCurrency.isEmpty() && sTheCompatibleCurrency != str)
incErrorStrStr( "Error: CurrencySymbol \"%s\" flagged as usedInCompatibleFormatCodes doesn't match \"%s\" determined from format codes.\n", str, sTheCompatibleCurrency);
str = currencyNode -> findNode ("BankSymbol") -> getValue();
of.writeOUStringLiteralParameter("bankSymbol", str, nbOfCurrencies); // BankSymbol currently must be ISO 4217. May change later if // application always uses CurrencyID instead of BankSymbol. if (!bLegacy && !isIso4217(str))
incError( "BankSymbol is not ISO 4217");
str = currencyNode -> findNode ("CurrencyName") -> getValue();
of.writeOUStringLiteralParameter("currencyName", str, nbOfCurrencies);
str = currencyNode -> findNode ("DecimalPlaces") -> getValue();
sal_Int16 nDecimalPlaces = static_cast<sal_Int16>(str.toInt32());
of.writeOUStringLiteralIntParameter("currencyDecimalPlaces", nbOfCurrencies, nDecimalPlaces);
of.writeAsciiString("\n");
};
if (!bTheDefault)
incError( "Currency: no default currency."); if (!bTheCompatible)
incError( "Currency: no currency flagged as usedInCompatibleFormatCodes.");
// hard code number of attributes per style. constint nAttributes = 5; constchar* attr[ nAttributes ] = { "Prefix", "NumType", "Suffix", "Transliteration", "NatNum" };
// record each attribute of each style in a static C++ variable. // determine number of styles on the fly.
sal_Int32 nStyles = getNumberOfChildren();
sal_Int32 i;
for( i = 0; i < nStyles; ++i )
{ const Attr &q = getChildAt( i )->getAttr(); for( sal_Int32 j=0; j<nAttributes; ++j )
{ constchar* name = attr[j];
OUString value = q.getValueByName( name );
of.writeOUStringLiteralParameter("continuous", name, value, sal::static_int_cast<sal_Int16>(i) );
}
}
// record number of styles and attributes.
of.writeAsciiString("static const sal_Int16 continuousNbOfStyles = ");
of.writeInt( sal::static_int_cast<sal_Int16>( nStyles ) );
of.writeAsciiString(";\n\n");
of.writeAsciiString("static const sal_Int16 continuousNbOfAttributesPerStyle = ");
of.writeInt( nAttributes );
of.writeAsciiString(";\n\n");
// hardcode number of attributes per level constint nAttributes = 12; constchar* attr[ nAttributes ] =
{ "Prefix", "NumType", "Suffix", "BulletChar", "BulletFontName", "ParentNumbering", "LeftMargin", "SymbolTextDistance", "FirstLineOffset", "Adjust", "Transliteration", "NatNum",
};
// record each attribute of each level of each style in a static C++ variable. // determine number of styles and number of levels per style on the fly.
sal_Int32 nStyles = getNumberOfChildren();
std::vector<sal_Int32> nLevels; // may be different for each style? for( sal_Int32 i = 0; i < nStyles; i++ )
{
LocaleNode* p = getChildAt( i );
nLevels.push_back( p->getNumberOfChildren() ); for( sal_Int32 j=0; j<nLevels.back(); j++ )
{ const Attr& q = p->getChildAt( j )->getAttr(); for( sal_Int32 k=0; k<nAttributes; ++k )
{ constchar* name = attr[k];
OUString value = q.getValueByName( name );
of.writeOUStringLiteralParameter("outline", name, value,
sal::static_int_cast<sal_Int16>(i),
sal::static_int_cast<sal_Int16>(j) );
}
}
}
// verify that each style has the same number of levels. for( size_t i=0; i<nLevels.size(); i++ )
{ if( nLevels[0] != nLevels[i] )
{
incError( "Numbering levels don't match.");
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.