Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / i18npool / source / localedata / LocaleNode.cxx
blob273d40698a8f1f4d317c1884ce971400ff463f1c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <stdio.h>
21 #include <string.h>
22 #include <algorithm>
23 #include <memory>
24 #include <set>
25 #include <vector>
27 #include <rtl/ustrbuf.hxx>
28 #include <sal/macros.h>
30 #include "LocaleNode.hxx"
31 #include <i18npool/reservedconstants.hxx>
32 #include <com/sun/star/i18n/NumberFormatIndex.hpp>
33 #include <com/sun/star/xml/sax/XAttributeList.hpp>
35 // NOTE: MUST match the Locale versionDTD attribute defined in data/locale.dtd
36 #define LOCALE_VERSION_DTD "2.0.3"
38 typedef ::std::set< OUString > NameSet;
39 typedef ::std::set< sal_Int16 > ValueSet;
41 namespace cssi = ::com::sun::star::i18n;
43 LocaleNode::LocaleNode (const OUString& name, const Reference< XAttributeList > & attr)
44 : aName(name)
45 , aAttribs(attr)
46 , parent(nullptr)
47 , nError(0)
51 int LocaleNode::getError() const
53 int err = nError;
54 for (size_t i=0;i<children.size();i++)
55 err += children[i]->getError();
56 return err;
59 void LocaleNode::addChild ( LocaleNode * node) {
60 children.emplace_back(node);
61 node->parent = this;
64 const LocaleNode* LocaleNode::getRoot() const
66 const LocaleNode* pRoot = nullptr;
67 const LocaleNode* pParent = this;
68 while ( (pParent = pParent->parent) != nullptr )
69 pRoot = pParent;
70 return pRoot;
73 const LocaleNode * LocaleNode::findNode ( const sal_Char *name) const {
74 if (aName.equalsAscii(name))
75 return this;
76 for (size_t i = 0; i< children.size(); i++) {
77 const LocaleNode *n=children[i]->findNode(name);
78 if (n)
79 return n;
81 return nullptr;
84 LocaleNode::~LocaleNode()
88 LocaleNode* LocaleNode::createNode (const OUString& name, const Reference< XAttributeList > & attr)
90 if ( name == "LC_INFO" )
91 return new LCInfoNode (name,attr);
92 if ( name == "LC_CTYPE" )
93 return new LCCTYPENode (name,attr);
94 if ( name == "LC_FORMAT" )
95 return new LCFormatNode (name,attr);
96 if ( name == "LC_FORMAT_1" )
97 return new LCFormatNode (name,attr);
98 if ( name == "LC_CALENDAR" )
99 return new LCCalendarNode (name,attr);
100 if ( name == "LC_CURRENCY" )
101 return new LCCurrencyNode (name,attr);
102 if ( name == "LC_TRANSLITERATION" )
103 return new LCTransliterationNode (name,attr);
104 if ( name == "LC_COLLATION" )
105 return new LCCollationNode (name,attr);
106 if ( name == "LC_INDEX" )
107 return new LCIndexNode (name,attr);
108 if ( name == "LC_SEARCH" )
109 return new LCSearchNode (name,attr);
110 if ( name == "LC_MISC" )
111 return new LCMiscNode (name,attr);
112 if ( name == "LC_NumberingLevel" )
113 return new LCNumberingLevelNode (name, attr);
114 if ( name == "LC_OutLineNumberingLevel" )
115 return new LCOutlineNumberingLevelNode (name, attr);
117 return new LocaleNode(name,attr);
121 // printf(" name: '%s'\n", p->getName().pData->buffer );
122 // printf("value: '%s'\n", p->getValue().pData->buffer );
124 #define OSTR(s) (OUStringToOString( (s), RTL_TEXTENCODING_UTF8).getStr())
126 void LocaleNode::generateCode (const OFileWriter &of) const
128 OUString aDTD = getAttr().getValueByName("versionDTD");
129 if ( aDTD != LOCALE_VERSION_DTD )
131 ++nError;
132 fprintf( stderr, "Error: Locale versionDTD is not %s, see comment in locale.dtd\n", LOCALE_VERSION_DTD);
134 for (size_t i=0; i<children.size(); i++)
135 children[i]->generateCode (of);
136 // print_node( this );
140 OUString LocaleNode::writeParameterCheckLen( const OFileWriter &of,
141 const char* pParameterName, const LocaleNode* pNode,
142 sal_Int32 nMinLen, sal_Int32 nMaxLen ) const
144 OUString aVal;
145 if (pNode)
146 aVal = pNode->getValue();
147 else if (nMinLen >= 0) // -1: optional => empty, 0: must be present, empty
149 ++nError;
150 fprintf( stderr, "Error: node NULL pointer for parameter %s.\n",
151 pParameterName);
153 // write empty data if error
154 of.writeParameter( pParameterName, aVal);
155 sal_Int32 nLen = aVal.getLength();
156 if (nLen < nMinLen)
158 ++nError;
159 fprintf( stderr, "Error: less than %ld character%s (%ld) in %s '%s'.\n",
160 sal::static_int_cast< long >(nMinLen), (nMinLen > 1 ? "s" : ""),
161 sal::static_int_cast< long >(nLen),
162 (pNode ? OSTR( pNode->getName()) : ""),
163 OSTR( aVal));
165 else if (nLen > nMaxLen && nMaxLen >= 0)
167 ++nError;
168 fprintf( stderr,
169 "Error: more than %ld character%s (%ld) in %s '%s' not supported by application.\n",
170 sal::static_int_cast< long >(nMaxLen), (nMaxLen > 1 ? "s" : ""),
171 sal::static_int_cast< long >(nLen),
172 (pNode ? OSTR( pNode->getName()) : ""),
173 OSTR( aVal));
175 return aVal;
179 OUString LocaleNode::writeParameterCheckLen( const OFileWriter &of,
180 const char* pNodeName, const char* pParameterName,
181 sal_Int32 nMinLen, sal_Int32 nMaxLen ) const
183 OUString aVal;
184 const LocaleNode * pNode = findNode( pNodeName);
185 if (pNode || nMinLen < 0)
186 aVal = writeParameterCheckLen( of, pParameterName, pNode, nMinLen, nMaxLen);
187 else
189 ++nError;
190 fprintf( stderr, "Error: node %s not found.\n", pNodeName);
191 // write empty data if error
192 of.writeParameter( pParameterName, aVal);
194 return aVal;
197 void LocaleNode::incError( const char* pStr ) const
199 ++nError;
200 fprintf( stderr, "Error: %s\n", pStr);
203 void LocaleNode::incError( const OUString& rStr ) const
205 incError( OSTR( rStr));
208 void LocaleNode::incErrorInt( const char* pStr, int nVal ) const
210 ++nError;
211 fprintf( stderr, pStr, nVal);
214 void LocaleNode::incErrorStr( const char* pStr, const OUString& rVal ) const
216 ++nError;
217 fprintf( stderr, pStr, OSTR( rVal));
220 void LocaleNode::incErrorStrStr( const char* pStr, const OUString& rVal1, const OUString& rVal2 ) const
222 ++nError;
223 fprintf(stderr, pStr, OSTR(rVal1), OSTR(rVal2));
226 void LCInfoNode::generateCode (const OFileWriter &of) const
229 const LocaleNode * languageNode = findNode("Language");
230 const LocaleNode * countryNode = findNode("Country");
231 const LocaleNode * variantNode = findNode("Variant");
233 OUString aLanguage;
235 if (languageNode)
237 aLanguage = languageNode->getChildAt(0)->getValue();
238 if (!(aLanguage.getLength() == 2 || aLanguage.getLength() == 3))
239 incErrorStr( "Error: langID '%s' not 2-3 characters\n", aLanguage);
240 of.writeParameter("langID", aLanguage);
241 of.writeParameter("langDefaultName", languageNode->getChildAt(1)->getValue());
243 else
244 incError( "No Language node.");
245 if (countryNode)
247 OUString aCountry( countryNode->getChildAt(0)->getValue());
248 if (!(aCountry.isEmpty() || aCountry.getLength() == 2))
249 incErrorStr( "Error: countryID '%s' not empty or more than 2 characters\n", aCountry);
250 of.writeParameter("countryID", aCountry);
251 of.writeParameter("countryDefaultName", countryNode->getChildAt(1)->getValue());
253 else
254 incError( "No Country node.");
255 if (variantNode)
257 // If given Variant must be at least ll-Ssss and language must be 'qlt'
258 const OUString& aVariant( variantNode->getValue());
259 if (!(aVariant.isEmpty() || (aVariant.getLength() >= 7 && aVariant.indexOf('-') >= 2)))
260 incErrorStr( "Error: invalid Variant '%s'\n", aVariant);
261 if (!(aVariant.isEmpty() || aLanguage == "qlt"))
262 incErrorStrStr( "Error: Variant '%s' given but Language '%s' is not 'qlt'\n", aVariant, aLanguage);
263 of.writeParameter("Variant", aVariant);
265 else
266 of.writeParameter("Variant", OUString());
267 of.writeAsciiString("\nstatic const sal_Unicode* LCInfoArray[] = {\n");
268 of.writeAsciiString("\tlangID,\n");
269 of.writeAsciiString("\tlangDefaultName,\n");
270 of.writeAsciiString("\tcountryID,\n");
271 of.writeAsciiString("\tcountryDefaultName,\n");
272 of.writeAsciiString("\tVariant\n");
273 of.writeAsciiString("};\n\n");
274 of.writeFunction("getLCInfo_", "SAL_N_ELEMENTS(LCInfoArray)", "LCInfoArray");
278 static OUString aDateSep;
279 static OUString aDecSep;
281 void LCCTYPENode::generateCode (const OFileWriter &of) const
283 const LocaleNode * sepNode = nullptr;
284 OUString useLocale = getAttr().getValueByName("ref");
285 if (!useLocale.isEmpty()) {
286 useLocale = useLocale.replace( '-', '_');
287 of.writeRefFunction("getLocaleItem_", useLocale);
288 return;
290 OUString str = getAttr().getValueByName("unoid");
291 of.writeAsciiString("\n\n");
292 of.writeParameter("LC_CTYPE_Unoid", str);
294 aDateSep =
295 writeParameterCheckLen( of, "DateSeparator", "dateSeparator", 1, 1);
296 OUString aThoSep =
297 writeParameterCheckLen( of, "ThousandSeparator", "thousandSeparator", 1, 1);
298 aDecSep =
299 writeParameterCheckLen( of, "DecimalSeparator", "decimalSeparator", 1, 1);
300 OUString aDecSepAlt =
301 writeParameterCheckLen( of, "DecimalSeparatorAlternative", "decimalSeparatorAlternative", -1, 1);
302 OUString aTimeSep =
303 writeParameterCheckLen( of, "TimeSeparator", "timeSeparator", 1, 1);
304 OUString aTime100Sep =
305 writeParameterCheckLen( of, "Time100SecSeparator", "time100SecSeparator", 1, 1);
306 OUString aListSep =
307 writeParameterCheckLen( of, "ListSeparator", "listSeparator", 1, 1);
309 OUString aLDS;
311 sepNode = findNode("LongDateDayOfWeekSeparator");
312 aLDS = sepNode->getValue();
313 of.writeParameter("LongDateDayOfWeekSeparator", aLDS);
314 if (aLDS == ",")
315 fprintf( stderr, "Warning: %s\n",
316 "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\".");
318 sepNode = findNode("LongDateDaySeparator");
319 aLDS = sepNode->getValue();
320 of.writeParameter("LongDateDaySeparator", aLDS);
321 if (aLDS == "," || aLDS == ".")
322 fprintf( stderr, "Warning: %s\n",
323 "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\".");
325 sepNode = findNode("LongDateMonthSeparator");
326 aLDS = sepNode->getValue();
327 of.writeParameter("LongDateMonthSeparator", aLDS);
328 if (aLDS.isEmpty())
329 fprintf( stderr, "Warning: %s\n",
330 "LongDateMonthSeparator is empty. Usually this is not the case and may lead to concatenated display names like \"Wednesday, May9, 2007\".");
332 sepNode = findNode("LongDateYearSeparator");
333 aLDS = sepNode->getValue();
334 of.writeParameter("LongDateYearSeparator", aLDS);
335 if (aLDS.isEmpty())
336 fprintf( stderr, "Warning: %s\n",
337 "LongDateYearSeparator is empty. Usually this is not the case and may lead to concatenated display names like \"Wednesday, 2007May 9\".");
339 int nSavErr = nError;
340 int nWarn = 0;
341 if (aDateSep == aTimeSep)
342 incError( "DateSeparator equals TimeSeparator.");
343 if (aDecSep == aThoSep)
344 incError( "DecimalSeparator equals ThousandSeparator.");
345 if (aDecSepAlt == aThoSep)
346 incError( "DecimalSeparatorAlternative equals ThousandSeparator.");
347 if (aDecSepAlt == aDecSep)
348 incError( "DecimalSeparatorAlternative equals DecimalSeparator, it must not be specified then.");
349 if ( aThoSep == " " )
350 incError( "ThousandSeparator is an ' ' ordinary space, this should be a non-breaking space U+00A0 instead.");
351 if (aListSep == aDecSep)
352 fprintf( stderr, "Warning: %s\n",
353 "ListSeparator equals DecimalSeparator.");
354 if (aListSep == aThoSep)
355 fprintf( stderr, "Warning: %s\n",
356 "ListSeparator equals ThousandSeparator.");
357 if (aListSep.getLength() != 1 || aListSep[0] != ';')
359 incError( "ListSeparator not ';' semicolon. Strongly recommended. Currently required.");
360 ++nSavErr; // format codes not affected
362 if (aTimeSep == aTime100Sep)
364 ++nWarn;
365 fprintf( stderr, "Warning: %s\n",
366 "Time100SecSeparator equals TimeSeparator, this is probably an error.");
368 if (aDecSep != aTime100Sep)
370 ++nWarn;
371 fprintf( stderr, "Warning: %s\n",
372 "Time100SecSeparator is different from DecimalSeparator, this may be correct or not. Intended?");
374 if (nSavErr != nError || nWarn)
375 fprintf( stderr, "Warning: %s\n",
376 "Don't forget to adapt corresponding FormatCode elements when changing separators.");
378 OUString aQuoteStart =
379 writeParameterCheckLen( of, "QuotationStart", "quotationStart", 1, 1);
380 OUString aQuoteEnd =
381 writeParameterCheckLen( of, "QuotationEnd", "quotationEnd", 1, 1);
382 OUString aDoubleQuoteStart =
383 writeParameterCheckLen( of, "DoubleQuotationStart", "doubleQuotationStart", 1, 1);
384 OUString aDoubleQuoteEnd =
385 writeParameterCheckLen( of, "DoubleQuotationEnd", "doubleQuotationEnd", 1, 1);
387 if (aQuoteStart.toChar() <= 127 && aQuoteEnd.toChar() > 127)
388 fprintf( stderr, "Warning: %s\n",
389 "QuotationStart is an ASCII character but QuotationEnd is not.");
390 if (aQuoteEnd.toChar() <= 127 && aQuoteStart.toChar() > 127)
391 fprintf( stderr, "Warning: %s\n",
392 "QuotationEnd is an ASCII character but QuotationStart is not.");
393 if (aDoubleQuoteStart.toChar() <= 127 && aDoubleQuoteEnd.toChar() > 127)
394 fprintf( stderr, "Warning: %s\n",
395 "DoubleQuotationStart is an ASCII character but DoubleQuotationEnd is not.");
396 if (aDoubleQuoteEnd.toChar() <= 127 && aDoubleQuoteStart.toChar() > 127)
397 fprintf( stderr, "Warning: %s\n",
398 "DoubleQuotationEnd is an ASCII character but DoubleQuotationStart is not.");
399 if (aQuoteStart.toChar() <= 127 && aQuoteEnd.toChar() <= 127)
400 fprintf( stderr, "Warning: %s\n",
401 "QuotationStart and QuotationEnd are both ASCII characters. Not necessarily an issue, but unusual.");
402 if (aDoubleQuoteStart.toChar() <= 127 && aDoubleQuoteEnd.toChar() <= 127)
403 fprintf( stderr, "Warning: %s\n",
404 "DoubleQuotationStart and DoubleQuotationEnd are both ASCII characters. Not necessarily an issue, but unusual.");
405 if (aQuoteStart == aQuoteEnd)
406 fprintf( stderr, "Warning: %s\n",
407 "QuotationStart equals QuotationEnd. Not necessarily an issue, but unusual.");
408 if (aDoubleQuoteStart == aDoubleQuoteEnd)
409 fprintf( stderr, "Warning: %s\n",
410 "DoubleQuotationStart equals DoubleQuotationEnd. Not necessarily an issue, but unusual.");
411 /* TODO: should equalness of single and double quotes be an error? Would
412 * need to adapt quite some locales' data. */
413 if (aQuoteStart == aDoubleQuoteStart)
414 fprintf( stderr, "Warning: %s\n",
415 "QuotationStart equals DoubleQuotationStart. Not necessarily an issue, but unusual.");
416 if (aQuoteEnd == aDoubleQuoteEnd)
417 fprintf( stderr, "Warning: %s\n",
418 "QuotationEnd equals DoubleQuotationEnd. Not necessarily an issue, but unusual.");
419 // Known good values, exclude ASCII single (U+0027, ') and double (U+0022, ") quotes.
420 switch (int ic = aQuoteStart.toChar())
422 case 0x2018: // LEFT SINGLE QUOTATION MARK
423 case 0x201a: // SINGLE LOW-9 QUOTATION MARK
424 case 0x201b: // SINGLE HIGH-REVERSED-9 QUOTATION MARK
425 case 0x2039: // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
426 case 0x203a: // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
427 case 0x300c: // LEFT CORNER BRACKET (Chinese)
429 break;
430 default:
431 fprintf( stderr, "Warning: %s U+%04X %s\n",
432 "QuotationStart may be wrong:", ic, OSTR( aQuoteStart));
434 switch (int ic = aQuoteEnd.toChar())
436 case 0x2019: // RIGHT SINGLE QUOTATION MARK
437 case 0x201a: // SINGLE LOW-9 QUOTATION MARK
438 case 0x201b: // SINGLE HIGH-REVERSED-9 QUOTATION MARK
439 case 0x2039: // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
440 case 0x203a: // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
441 case 0x300d: // RIGHT CORNER BRACKET (Chinese)
443 break;
444 default:
445 fprintf( stderr, "Warning: %s U+%04X %s\n",
446 "QuotationEnd may be wrong:", ic, OSTR( aQuoteEnd));
448 switch (int ic = aDoubleQuoteStart.toChar())
450 case 0x00ab: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
451 case 0x00bb: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
452 case 0x201c: // LEFT DOUBLE QUOTATION MARK
453 case 0x201e: // DOUBLE LOW-9 QUOTATION MARK
454 case 0x201f: // DOUBLE HIGH-REVERSED-9 QUOTATION MARK
455 case 0x300e: // LEFT WHITE CORNER BRACKET (Chinese)
457 break;
458 default:
459 fprintf( stderr, "Warning: %s U+%04X %s\n",
460 "DoubleQuotationStart may be wrong:", ic, OSTR( aDoubleQuoteStart));
462 switch (int ic = aDoubleQuoteEnd.toChar())
464 case 0x00ab: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
465 case 0x00bb: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
466 case 0x201d: // RIGHT DOUBLE QUOTATION MARK
467 case 0x201e: // DOUBLE LOW-9 QUOTATION MARK
468 case 0x201f: // DOUBLE HIGH-REVERSED-9 QUOTATION MARK
469 case 0x300f: // RIGHT WHITE CORNER BRACKET (Chinese)
471 break;
472 default:
473 fprintf( stderr, "Warning: %s U+%04X %s\n",
474 "DoubleQuotationEnd may be wrong:", ic, OSTR( aDoubleQuoteEnd));
477 writeParameterCheckLen( of, "TimeAM", "timeAM", 1, -1);
478 writeParameterCheckLen( of, "TimePM", "timePM", 1, -1);
479 sepNode = findNode("MeasurementSystem");
480 of.writeParameter("measurementSystem", sepNode->getValue());
482 of.writeAsciiString("\nstatic const sal_Unicode* LCType[] = {\n");
483 of.writeAsciiString("\tLC_CTYPE_Unoid,\n");
484 of.writeAsciiString("\tdateSeparator,\n");
485 of.writeAsciiString("\tthousandSeparator,\n");
486 of.writeAsciiString("\tdecimalSeparator,\n");
487 of.writeAsciiString("\ttimeSeparator,\n");
488 of.writeAsciiString("\ttime100SecSeparator,\n");
489 of.writeAsciiString("\tlistSeparator,\n");
490 of.writeAsciiString("\tquotationStart,\n");
491 of.writeAsciiString("\tquotationEnd,\n");
492 of.writeAsciiString("\tdoubleQuotationStart,\n");
493 of.writeAsciiString("\tdoubleQuotationEnd,\n");
494 of.writeAsciiString("\ttimeAM,\n");
495 of.writeAsciiString("\ttimePM,\n");
496 of.writeAsciiString("\tmeasurementSystem,\n");
497 of.writeAsciiString("\tLongDateDayOfWeekSeparator,\n");
498 of.writeAsciiString("\tLongDateDaySeparator,\n");
499 of.writeAsciiString("\tLongDateMonthSeparator,\n");
500 of.writeAsciiString("\tLongDateYearSeparator,\n");
501 of.writeAsciiString("\tdecimalSeparatorAlternative\n");
502 of.writeAsciiString("};\n\n");
503 of.writeFunction("getLocaleItem_", "SAL_N_ELEMENTS(LCType)", "LCType");
507 static OUString sTheCurrencyReplaceTo;
508 static OUString sTheCompatibleCurrency;
509 static OUString sTheDateEditFormat;
511 sal_Int16 LCFormatNode::mnSection = 0;
512 sal_Int16 LCFormatNode::mnFormats = 0;
514 void LCFormatNode::generateCode (const OFileWriter &of) const
516 if (mnSection >= 2)
517 incError("more than 2 LC_FORMAT sections");
519 ::std::vector< OUString > theDateAcceptancePatterns;
521 OUString useLocale(getAttr().getValueByName("ref"));
523 OUString str;
524 OUString strFrom( getAttr().getValueByName("replaceFrom"));
525 if (useLocale.isEmpty())
527 of.writeParameter("replaceFrom", strFrom, mnSection);
529 str = getAttr().getValueByName("replaceTo");
530 if (!strFrom.isEmpty() && str.isEmpty())
531 incErrorStr("replaceFrom=\"%s\" replaceTo=\"\" is empty replacement.\n", strFrom);
532 // Locale data generator inserts FFFF for LangID, we need to adapt that.
533 if (str.endsWithIgnoreAsciiCase( "-FFFF]"))
534 incErrorStr("replaceTo=\"%s\" needs FFFF to be adapted to the real LangID value.\n", str);
535 of.writeParameter("replaceTo", str, mnSection);
536 // Remember the replaceTo value for "[CURRENCY]" to check format codes.
537 if ( strFrom == "[CURRENCY]" )
538 sTheCurrencyReplaceTo = str;
539 // Remember the currency symbol if present.
540 if (str.startsWith( "[$" ))
542 sal_Int32 nHyphen = str.indexOf( '-');
543 if (nHyphen >= 3)
545 sTheCompatibleCurrency = str.copy( 2, nHyphen - 2);
549 if (!useLocale.isEmpty())
551 if (!strFrom.isEmpty() && strFrom != "[CURRENCY]") //???
553 incErrorStrStr(
554 "Error: non-empty replaceFrom=\"%s\" with non-empty ref=\"%s\".",
555 strFrom, useLocale);
557 useLocale = useLocale.replace( '-', '_');
558 switch (mnSection)
560 case 0:
561 of.writeRefFunction("getAllFormats0_", useLocale, "replaceTo0");
562 break;
563 case 1:
564 of.writeRefFunction("getAllFormats1_", useLocale, "replaceTo1");
565 break;
567 of.writeRefFunction("getDateAcceptancePatterns_", useLocale);
568 return;
571 sal_Int16 formatCount = mnFormats;
572 NameSet aMsgIdSet;
573 ValueSet aFormatIndexSet;
574 NameSet aDefaultsSet;
575 bool bCtypeIsRef = false;
576 bool bHaveEngineering = false;
577 bool bShowNextFreeFormatIndex = false;
579 for (sal_Int32 i = 0; i< getNumberOfChildren() ; i++, formatCount++)
581 LocaleNode * currNode = getChildAt (i);
582 if ( currNode->getName() == "DateAcceptancePattern" )
584 if (mnSection > 0)
585 incError( "DateAcceptancePattern only handled in LC_FORMAT, not LC_FORMAT_1");
586 else
587 theDateAcceptancePatterns.push_back( currNode->getValue());
588 --formatCount;
589 continue; // for
591 if ( currNode->getName() != "FormatElement" )
593 incErrorStr( "Error: Undefined element '%s' in LC_FORMAT\n", currNode->getName());
594 --formatCount;
595 continue; // for
598 OUString aUsage;
599 OUString aType;
600 OUString aFormatIndex;
601 // currNode -> print();
602 const Attr &currNodeAttr = currNode->getAttr();
603 //printf ("getLen() = %d\n", currNode->getAttr().getLength());
605 str = currNodeAttr.getValueByName("msgid");
606 if (!aMsgIdSet.insert( str).second)
607 incErrorStr( "Error: Duplicated msgid=\"%s\" in FormatElement.\n", str);
608 of.writeParameter("FormatKey", str, formatCount);
610 str = currNodeAttr.getValueByName("default");
611 bool bDefault = str == "true";
612 of.writeDefaultParameter("FormatElement", str, formatCount);
614 aType = currNodeAttr.getValueByName("type");
615 of.writeParameter("FormatType", aType, formatCount);
617 aUsage = currNodeAttr.getValueByName("usage");
618 of.writeParameter("FormatUsage", aUsage, formatCount);
620 aFormatIndex = currNodeAttr.getValueByName("formatindex");
621 sal_Int16 formatindex = static_cast<sal_Int16>(aFormatIndex.toInt32());
622 // Ensure the new reserved range is not used anymore, free usage start
623 // was up'ed from 50 to 60.
624 if (50 <= formatindex && formatindex < i18npool::nFirstFreeFormatIndex)
626 incErrorInt( "Error: Reserved formatindex=\"%d\" in FormatElement.\n", formatindex);
627 bShowNextFreeFormatIndex = true;
629 if (!aFormatIndexSet.insert( formatindex).second)
631 incErrorInt( "Error: Duplicated formatindex=\"%d\" in FormatElement.\n", formatindex);
632 bShowNextFreeFormatIndex = true;
634 of.writeIntParameter("Formatindex", formatCount, formatindex);
636 // Ensure only one default per usage and type.
637 if (bDefault)
639 OUString aKey( aUsage + "," + aType);
640 if (!aDefaultsSet.insert( aKey).second)
642 OUString aStr = "Duplicated default for usage=\"" + aUsage + "\" type=\"" + aType + "\": formatindex=\"" + aFormatIndex + "\".";
643 incError( aStr);
647 const LocaleNode * n = currNode -> findNode("FormatCode");
648 if (n)
650 of.writeParameter("FormatCode", n->getValue(), formatCount);
651 // Check separator usage for some FormatCode elements.
652 const LocaleNode* pCtype = nullptr;
653 switch (formatindex)
655 case cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY :
656 sTheDateEditFormat = n->getValue();
657 break;
658 case cssi::NumberFormatIndex::NUMBER_1000DEC2 : // #,##0.00
659 case cssi::NumberFormatIndex::TIME_MMSS00 : // MM:SS.00
660 case cssi::NumberFormatIndex::TIME_HH_MMSS00 : // [HH]:MM:SS.00
662 const LocaleNode* pRoot = getRoot();
663 if (!pRoot)
664 incError( "No root for FormatCode.");
665 else
667 pCtype = pRoot->findNode( "LC_CTYPE");
668 if (!pCtype)
669 incError( "No LC_CTYPE found for FormatCode.");
670 else
672 OUString aRef( pCtype->getAttr().getValueByName("ref"));
673 if (!aRef.isEmpty())
675 aRef = aRef.replace( '-', '_');
676 if (!bCtypeIsRef)
677 fprintf( stderr,
678 "Warning: Can't check separators used in FormatCode due to LC_CTYPE ref=\"%s\".\n"
679 "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",
680 OSTR( aRef));
681 bCtypeIsRef = true;
682 pCtype = nullptr;
687 break;
688 case cssi::NumberFormatIndex::CURRENCY_1000DEC2 :
689 // Remember the currency symbol if present.
691 sal_Int32 nStart;
692 if (sTheCompatibleCurrency.isEmpty() &&
693 ((nStart = n->getValue().indexOf("[$")) >= 0))
695 const OUString& aCode( n->getValue());
696 sal_Int32 nHyphen = aCode.indexOf( '-', nStart);
697 if (nHyphen >= nStart + 3)
698 sTheCompatibleCurrency = aCode.copy( nStart + 2, nHyphen - nStart - 2);
701 [[fallthrough]];
702 case cssi::NumberFormatIndex::CURRENCY_1000INT :
703 case cssi::NumberFormatIndex::CURRENCY_1000INT_RED :
704 case cssi::NumberFormatIndex::CURRENCY_1000DEC2_RED :
705 case cssi::NumberFormatIndex::CURRENCY_1000DEC2_CCC :
706 case cssi::NumberFormatIndex::CURRENCY_1000DEC2_DASHED :
707 // Currency formats should be something like [C]###0;-[C]###0
708 // and not parenthesized [C]###0;([C]###0) if not en_US.
709 if (strcmp( of.getLocale(), "en_US") != 0)
711 const OUString& aCode( n->getValue());
712 OUString const aPar1( "0)");
713 OUString const aPar2( "-)" );
714 OUString const aPar3( " )" );
715 OUString const aPar4( "])" );
716 if (aCode.indexOf( aPar1 ) > 0 || aCode.indexOf( aPar2 ) > 0 ||
717 aCode.indexOf( aPar3 ) > 0 || aCode.indexOf( aPar4 ) > 0)
718 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);
720 // Check if we have replaceTo for "[CURRENCY]" placeholder.
721 if (sTheCurrencyReplaceTo.isEmpty())
723 const OUString& aCode( n->getValue());
724 if (aCode.indexOf( "[CURRENCY]" ) >= 0)
725 incErrorInt( "Error: [CURRENCY] replaceTo not found for formatindex=\"%d\".\n", formatindex);
727 break;
728 default:
729 if (aUsage == "SCIENTIFIC_NUMBER")
731 // Check for presence of ##0.00E+00
732 const OUString& aCode( n->getValue());
733 // Simple check without decimal separator (assumed to
734 // be one UTF-16 character). May be prefixed with
735 // [NatNum1] or other tags.
736 sal_Int32 nInt = aCode.indexOf("##0");
737 sal_Int32 nDec = (nInt < 0 ? -1 : aCode.indexOf("00E+00", nInt));
738 if (nInt >= 0 && nDec == nInt+4)
739 bHaveEngineering = true;
741 break;
743 if (pCtype)
745 int nSavErr = nError;
746 const OUString& aCode( n->getValue());
747 if (formatindex == cssi::NumberFormatIndex::NUMBER_1000DEC2)
749 sal_Int32 nDec = -1;
750 sal_Int32 nGrp = -1;
751 const LocaleNode* pSep = pCtype->findNode( "DecimalSeparator");
752 if (!pSep)
753 incError( "No DecimalSeparator found for FormatCode.");
754 else
756 nDec = aCode.indexOf( pSep->getValue());
757 if (nDec < 0)
758 incErrorInt( "Error: DecimalSeparator not present in FormatCode formatindex=\"%d\".\n",
759 formatindex);
761 pSep = pCtype->findNode( "ThousandSeparator");
762 if (!pSep)
763 incError( "No ThousandSeparator found for FormatCode.");
764 else
766 nGrp = aCode.indexOf( pSep->getValue());
767 if (nGrp < 0)
768 incErrorInt( "Error: ThousandSeparator not present in FormatCode formatindex=\"%d\".\n",
769 formatindex);
771 if (nDec >= 0 && nGrp >= 0 && nDec <= nGrp)
772 incErrorInt( "Error: Ordering of ThousandSeparator and DecimalSeparator not correct in formatindex=\"%d\".\n",
773 formatindex);
775 if (formatindex == cssi::NumberFormatIndex::TIME_MMSS00 ||
776 formatindex == cssi::NumberFormatIndex::TIME_HH_MMSS00)
778 sal_Int32 nTime = -1;
779 sal_Int32 n100s = -1;
780 const LocaleNode* pSep = pCtype->findNode( "TimeSeparator");
781 if (!pSep)
782 incError( "No TimeSeparator found for FormatCode.");
783 else
785 nTime = aCode.indexOf( pSep->getValue());
786 if (nTime < 0)
787 incErrorInt( "Error: TimeSeparator not present in FormatCode formatindex=\"%d\".\n",
788 formatindex);
790 pSep = pCtype->findNode( "Time100SecSeparator");
791 if (!pSep)
792 incError( "No Time100SecSeparator found for FormatCode.");
793 else
795 n100s = aCode.indexOf( pSep->getValue());
796 if (n100s < 0)
797 incErrorInt( "Error: Time100SecSeparator not present in FormatCode formatindex=\"%d\".\n",
798 formatindex);
799 n100s = aCode.indexOf( pSep->getValue() + "00");
800 if (n100s < 0)
801 incErrorInt( "Error: Time100SecSeparator+00 not present in FormatCode formatindex=\"%d\".\n",
802 formatindex);
804 if (n100s >= 0 && nTime >= 0 && n100s <= nTime)
805 incErrorInt( "Error: Ordering of Time100SecSeparator and TimeSeparator not correct in formatindex=\"%d\".\n",
806 formatindex);
808 if (nSavErr != nError)
809 fprintf( stderr,
810 "Warning: formatindex=\"%d\",\"%d\",\"%d\" are the only FormatCode elements checked for separator usage, there may be others that have errors.\n",
811 int(cssi::NumberFormatIndex::NUMBER_1000DEC2),
812 int(cssi::NumberFormatIndex::TIME_MMSS00),
813 int(cssi::NumberFormatIndex::TIME_HH_MMSS00));
817 else
818 incError( "No FormatCode in FormatElement.");
819 n = currNode -> findNode("DefaultName");
820 if (n)
821 of.writeParameter("FormatDefaultName", n->getValue(), formatCount);
822 else
823 of.writeParameter("FormatDefaultName", OUString(), formatCount);
827 if (bShowNextFreeFormatIndex)
829 sal_Int16 nNext = i18npool::nFirstFreeFormatIndex;
830 std::set<sal_Int16>::const_iterator it( aFormatIndexSet.find( nNext));
831 if (it != aFormatIndexSet.end())
833 // nFirstFreeFormatIndex already used, find next free including gaps.
836 ++nNext;
838 while (++it != aFormatIndexSet.end() && *it == nNext);
840 fprintf( stderr, "Hint: Next free formatindex is %d.\n", static_cast<int>(nNext));
843 // Check presence of all required format codes only in first section
844 // LC_FORMAT, not in optional LC_FORMAT_1
845 if (mnSection == 0)
847 // At least one abbreviated date acceptance pattern must be present.
848 if (theDateAcceptancePatterns.empty())
849 incError( "No DateAcceptancePattern present.\n");
850 else
852 bool bHaveAbbr = false;
853 for (auto const& elem : theDateAcceptancePatterns)
855 if (elem.indexOf('D') > -1 && elem.indexOf('M') > -1 && elem.indexOf('Y') <= -1)
857 bHaveAbbr = true;
858 break;
861 if (!bHaveAbbr)
862 incError( "No abbreviated DateAcceptancePattern present. For example M/D or D.M.\n");
865 // 0..47 MUST be present, 48,49 MUST NOT be present
866 ValueSet::const_iterator aIter( aFormatIndexSet.begin());
867 for (sal_Int16 nNext = cssi::NumberFormatIndex::NUMBER_START;
868 nNext < cssi::NumberFormatIndex::INDEX_TABLE_ENTRIES; ++nNext)
870 sal_Int16 nHere = ::std::min( (aIter != aFormatIndexSet.end() ? *aIter :
871 cssi::NumberFormatIndex::INDEX_TABLE_ENTRIES),
872 cssi::NumberFormatIndex::INDEX_TABLE_ENTRIES);
873 if (aIter != aFormatIndexSet.end()) ++aIter;
874 for ( ; nNext < nHere; ++nNext)
876 switch (nNext)
878 case cssi::NumberFormatIndex::FRACTION_1 :
879 case cssi::NumberFormatIndex::FRACTION_2 :
880 case cssi::NumberFormatIndex::BOOLEAN :
881 case cssi::NumberFormatIndex::TEXT :
882 // generated internally
883 break;
884 default:
885 incErrorInt( "Error: FormatElement formatindex=\"%d\" not present.\n", nNext);
888 switch (nHere)
890 case cssi::NumberFormatIndex::BOOLEAN :
891 incErrorInt( "Error: FormatElement formatindex=\"%d\" reserved for internal ``BOOLEAN''.\n", nNext);
892 break;
893 case cssi::NumberFormatIndex::TEXT :
894 incErrorInt( "Error: FormatElement formatindex=\"%d\" reserved for internal ``@'' (TEXT).\n", nNext);
895 break;
896 default:
897 ; // nothing
901 if (!bHaveEngineering)
902 incError("Engineering notation format not present, e.g. ##0.00E+00 or ##0,00E+00 for usage=\"SCIENTIFIC_NUMBER\"\n");
905 of.writeAsciiString("\nstatic const sal_Int16 ");
906 of.writeAsciiString("FormatElementsCount");
907 of.writeInt(mnSection);
908 of.writeAsciiString(" = ");
909 of.writeInt( formatCount - mnFormats);
910 of.writeAsciiString(";\n");
911 of.writeAsciiString("static const sal_Unicode* ");
912 of.writeAsciiString("FormatElementsArray");
913 of.writeInt(mnSection);
914 of.writeAsciiString("[] = {\n");
915 for(sal_Int16 i = mnFormats; i < formatCount; i++) {
917 of.writeAsciiString("\t");
918 of.writeAsciiString("FormatCode");
919 of.writeInt(i);
920 of.writeAsciiString(",\n");
922 of.writeAsciiString("\t");
923 of.writeAsciiString("FormatDefaultName");
924 of.writeInt(i);
925 of.writeAsciiString(",\n");
927 of.writeAsciiString("\t");
928 of.writeAsciiString("FormatKey");
929 of.writeInt(i);
930 of.writeAsciiString(",\n");
932 of.writeAsciiString("\t");
933 of.writeAsciiString("FormatType");
934 of.writeInt(i);
935 of.writeAsciiString(",\n");
937 of.writeAsciiString("\t");
938 of.writeAsciiString("FormatUsage");
939 of.writeInt(i);
940 of.writeAsciiString(",\n");
942 of.writeAsciiString("\t");
943 of.writeAsciiString("Formatindex");
944 of.writeInt(i);
945 of.writeAsciiString(",\n");
948 of.writeAsciiString("\tdefaultFormatElement");
949 of.writeInt(i);
950 of.writeAsciiString(",\n");
952 of.writeAsciiString("};\n\n");
954 switch (mnSection)
956 case 0:
957 of.writeFunction("getAllFormats0_", "FormatElementsCount0", "FormatElementsArray0", "replaceFrom0", "replaceTo0");
958 break;
959 case 1:
960 of.writeFunction("getAllFormats1_", "FormatElementsCount1", "FormatElementsArray1", "replaceFrom1", "replaceTo1");
961 break;
964 mnFormats = mnFormats + formatCount;
966 if (mnSection == 0)
968 // Extract and add date acceptance pattern for full date, so we provide
969 // at least one valid pattern, even if the number parser doesn't need
970 // that one.
971 /* XXX NOTE: only simple [...] modifier and "..." quotes detected and
972 * ignored, not nested, no fancy stuff. */
973 sal_Int32 nIndex = 0;
974 // aDateSep can be empty if LC_CTYPE was a ref=..., determine from
975 // FormatCode then.
976 sal_uInt32 cDateSep = (aDateSep.isEmpty() ? 0 : aDateSep.iterateCodePoints( &nIndex));
977 sal_uInt32 cDateSep2 = cDateSep;
978 nIndex = 0;
979 OUStringBuffer aPatternBuf(5);
980 OUStringBuffer aPatternBuf2(5);
981 sal_uInt8 nDetected = 0; // bits Y,M,D
982 bool bInModifier = false;
983 bool bQuoted = false;
984 while (nIndex < sTheDateEditFormat.getLength() && nDetected < 7)
986 sal_uInt32 cChar = sTheDateEditFormat.iterateCodePoints( &nIndex);
987 if (bInModifier)
989 if (cChar == ']')
990 bInModifier = false;
991 continue; // while
993 if (bQuoted)
995 if (cChar == '"')
996 bQuoted = false;
997 continue; // while
999 switch (cChar)
1001 case 'Y':
1002 case 'y':
1003 if (!(nDetected & 4))
1005 aPatternBuf.append( 'Y');
1006 if (!aPatternBuf2.isEmpty())
1007 aPatternBuf2.append( 'Y');
1008 nDetected |= 4;
1010 break;
1011 case 'M':
1012 case 'm':
1013 if (!(nDetected & 2))
1015 aPatternBuf.append( 'M');
1016 if (!aPatternBuf2.isEmpty())
1017 aPatternBuf2.append( 'M');
1018 nDetected |= 2;
1020 break;
1021 case 'D':
1022 case 'd':
1023 if (!(nDetected & 1))
1025 aPatternBuf.append( 'D');
1026 if (!aPatternBuf2.isEmpty())
1027 aPatternBuf2.append( 'D');
1028 nDetected |= 1;
1030 break;
1031 case '[':
1032 bInModifier = true;
1033 break;
1034 case '"':
1035 bQuoted = true;
1036 break;
1037 case '\\':
1038 cChar = sTheDateEditFormat.iterateCodePoints( &nIndex);
1039 goto handleDefault;
1040 case '-':
1041 case '.':
1042 case '/':
1043 // There are locales that use an ISO 8601 edit format
1044 // regardless of what the date separator or other formats
1045 // say, for example hu-HU. Generalize this for all cases
1046 // where the used separator differs and is one of the known
1047 // separators and generate a second pattern with the
1048 // format's separator at the current position.
1049 cDateSep2 = cChar;
1050 [[fallthrough]];
1051 default:
1052 handleDefault:
1053 if (!cDateSep)
1054 cDateSep = cChar;
1055 if (!cDateSep2)
1056 cDateSep2 = cChar;
1057 if (cDateSep != cDateSep2 && aPatternBuf2.isEmpty())
1058 aPatternBuf2 = aPatternBuf;
1059 if (cChar == cDateSep || cChar == cDateSep2)
1060 aPatternBuf.append( OUString( &cDateSep, 1)); // always the defined separator
1061 if (cChar == cDateSep2 && !aPatternBuf2.isEmpty())
1062 aPatternBuf2.append( OUString( &cDateSep2, 1)); // always the format's separator
1063 break;
1064 // The localized legacy:
1065 case 'A':
1066 if (((nDetected & 7) == 3) || ((nDetected & 7) == 0))
1068 // es DD/MM/AAAA
1069 // fr JJ.MM.AAAA
1070 // it GG/MM/AAAA
1071 // fr_CA AAAA-MM-JJ
1072 aPatternBuf.append( 'Y');
1073 if (!aPatternBuf2.isEmpty())
1074 aPatternBuf2.append( 'Y');
1075 nDetected |= 4;
1077 break;
1078 case 'J':
1079 if (((nDetected & 7) == 0) || ((nDetected & 7) == 6))
1081 // fr JJ.MM.AAAA
1082 // fr_CA AAAA-MM-JJ
1083 aPatternBuf.append( 'D');
1084 if (!aPatternBuf2.isEmpty())
1085 aPatternBuf2.append( 'D');
1086 nDetected |= 1;
1088 else if ((nDetected & 7) == 3)
1090 // nl DD-MM-JJJJ
1091 // de TT.MM.JJJJ
1092 aPatternBuf.append( 'Y');
1093 if (!aPatternBuf2.isEmpty())
1094 aPatternBuf2.append( 'Y');
1095 nDetected |= 4;
1097 break;
1098 case 'T':
1099 if ((nDetected & 7) == 0)
1101 // de TT.MM.JJJJ
1102 aPatternBuf.append( 'D');
1103 if (!aPatternBuf2.isEmpty())
1104 aPatternBuf2.append( 'D');
1105 nDetected |= 1;
1107 break;
1108 case 'G':
1109 if ((nDetected & 7) == 0)
1111 // it GG/MM/AAAA
1112 aPatternBuf.append( 'D');
1113 if (!aPatternBuf2.isEmpty())
1114 aPatternBuf2.append( 'D');
1115 nDetected |= 1;
1117 break;
1118 case 'P':
1119 if ((nDetected & 7) == 0)
1121 // fi PP.KK.VVVV
1122 aPatternBuf.append( 'D');
1123 if (!aPatternBuf2.isEmpty())
1124 aPatternBuf2.append( 'D');
1125 nDetected |= 1;
1127 break;
1128 case 'K':
1129 if ((nDetected & 7) == 1)
1131 // fi PP.KK.VVVV
1132 aPatternBuf.append( 'M');
1133 if (!aPatternBuf2.isEmpty())
1134 aPatternBuf2.append( 'M');
1135 nDetected |= 2;
1137 break;
1138 case 'V':
1139 if ((nDetected & 7) == 3)
1141 // fi PP.KK.VVVV
1142 aPatternBuf.append( 'Y');
1143 if (!aPatternBuf2.isEmpty())
1144 aPatternBuf2.append( 'Y');
1145 nDetected |= 4;
1147 break;
1150 OUString aPattern( aPatternBuf.makeStringAndClear());
1151 if (((nDetected & 7) != 7) || aPattern.getLength() < 5)
1153 incErrorStr( "Error: failed to extract full date acceptance pattern: %s\n", aPattern);
1154 fprintf( stderr, " with DateSeparator '%s' from FormatCode '%s' (formatindex=\"%d\")\n",
1155 OSTR( OUString(&cDateSep, 1)), OSTR( sTheDateEditFormat),
1156 int(cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY));
1158 else
1160 fprintf( stderr, "Generated date acceptance pattern: '%s' from '%s' (formatindex=\"%d\" and defined DateSeparator '%s')\n",
1161 OSTR( aPattern), OSTR( sTheDateEditFormat),
1162 int(cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY),
1163 OSTR( OUString(&cDateSep, 1)));
1164 // Insert at front so full date pattern is first in checks.
1165 theDateAcceptancePatterns.insert( theDateAcceptancePatterns.begin(), aPattern);
1167 if (!aPatternBuf2.isEmpty())
1169 OUString aPattern2( aPatternBuf2.makeStringAndClear());
1170 if (aPattern2.getLength() < 5)
1172 incErrorStr( "Error: failed to extract 2nd date acceptance pattern: %s\n", aPattern2);
1173 fprintf( stderr, " with DateSeparator '%s' from FormatCode '%s' (formatindex=\"%d\")\n",
1174 OSTR( OUString(&cDateSep2, 1)), OSTR( sTheDateEditFormat),
1175 int(cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY));
1177 else
1179 fprintf( stderr, "Generated 2nd acceptance pattern: '%s' from '%s' (formatindex=\"%d\")\n",
1180 OSTR( aPattern2), OSTR( sTheDateEditFormat),
1181 int(cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY));
1182 theDateAcceptancePatterns.insert( theDateAcceptancePatterns.begin(), aPattern2);
1186 // Rudimentary check if a pattern interferes with decimal number.
1187 // But only if not inherited in which case we don't have aDecSep here.
1188 if (!aDecSep.isEmpty())
1190 nIndex = 0;
1191 sal_uInt32 cDecSep = aDecSep.iterateCodePoints( &nIndex);
1192 for (auto const& elem : theDateAcceptancePatterns)
1194 if (elem.getLength() == (cDecSep <= 0xffff ? 3 : 4))
1196 nIndex = 1;
1197 if (elem.iterateCodePoints( &nIndex) == cDecSep)
1199 ++nError;
1200 fprintf( stderr, "Error: Date acceptance pattern '%s' matches decimal number '#%s#'\n",
1201 OSTR(elem), OSTR( aDecSep));
1207 // Check for duplicates.
1208 for (vector<OUString>::const_iterator aIt = theDateAcceptancePatterns.begin();
1209 aIt != theDateAcceptancePatterns.end(); ++aIt)
1211 for (vector<OUString>::iterator aComp = theDateAcceptancePatterns.begin();
1212 aComp != theDateAcceptancePatterns.end(); /*nop*/)
1214 if (aIt != aComp && *aIt == *aComp)
1216 incErrorStr( "Error: Duplicated DateAcceptancePattern: %s\n", *aComp);
1217 aComp = theDateAcceptancePatterns.erase( aComp);
1219 else
1220 ++aComp;
1224 sal_Int16 nbOfDateAcceptancePatterns = static_cast<sal_Int16>(theDateAcceptancePatterns.size());
1226 for (sal_Int16 i = 0; i < nbOfDateAcceptancePatterns; ++i)
1228 of.writeParameter("DateAcceptancePattern", theDateAcceptancePatterns[i], i);
1231 of.writeAsciiString("static const sal_Int16 DateAcceptancePatternsCount = ");
1232 of.writeInt( nbOfDateAcceptancePatterns);
1233 of.writeAsciiString(";\n");
1235 of.writeAsciiString("static const sal_Unicode* DateAcceptancePatternsArray[] = {\n");
1236 for (sal_Int16 i = 0; i < nbOfDateAcceptancePatterns; ++i)
1238 of.writeAsciiString("\t");
1239 of.writeAsciiString("DateAcceptancePattern");
1240 of.writeInt(i);
1241 of.writeAsciiString(",\n");
1243 of.writeAsciiString("};\n\n");
1245 of.writeFunction("getDateAcceptancePatterns_", "DateAcceptancePatternsCount", "DateAcceptancePatternsArray");
1248 ++mnSection;
1251 void LCCollationNode::generateCode (const OFileWriter &of) const
1253 OUString useLocale = getAttr().getValueByName("ref");
1254 if (!useLocale.isEmpty()) {
1255 useLocale = useLocale.replace( '-', '_');
1256 of.writeRefFunction("getCollatorImplementation_", useLocale);
1257 of.writeRefFunction("getCollationOptions_", useLocale);
1258 return;
1260 sal_Int16 nbOfCollations = 0;
1261 sal_Int16 nbOfCollationOptions = 0;
1263 for ( sal_Int32 j = 0; j < getNumberOfChildren(); j++ ) {
1264 LocaleNode * currNode = getChildAt (j);
1265 if( currNode->getName() == "Collator" )
1267 OUString str;
1268 str = currNode->getAttr().getValueByName("unoid");
1269 of.writeParameter("CollatorID", str, j);
1270 str = currNode->getValue();
1271 of.writeParameter("CollatorRule", str, j);
1272 str = currNode -> getAttr().getValueByName("default");
1273 of.writeDefaultParameter("Collator", str, j);
1274 of.writeAsciiString("\n");
1276 nbOfCollations++;
1278 if( currNode->getName() == "CollationOptions" )
1280 LocaleNode* pCollationOptions = currNode;
1281 nbOfCollationOptions = sal::static_int_cast<sal_Int16>( pCollationOptions->getNumberOfChildren() );
1282 for( sal_Int16 i=0; i<nbOfCollationOptions; i++ )
1284 of.writeParameter("collationOption", pCollationOptions->getChildAt( i )->getValue(), i );
1287 of.writeAsciiString("static const sal_Int16 nbOfCollationOptions = ");
1288 of.writeInt( nbOfCollationOptions );
1289 of.writeAsciiString(";\n\n");
1292 of.writeAsciiString("static const sal_Int16 nbOfCollations = ");
1293 of.writeInt(nbOfCollations);
1294 of.writeAsciiString(";\n\n");
1296 of.writeAsciiString("\nstatic const sal_Unicode* LCCollatorArray[] = {\n");
1297 for(sal_Int16 j = 0; j < nbOfCollations; j++) {
1298 of.writeAsciiString("\tCollatorID");
1299 of.writeInt(j);
1300 of.writeAsciiString(",\n");
1302 of.writeAsciiString("\tdefaultCollator");
1303 of.writeInt(j);
1304 of.writeAsciiString(",\n");
1306 of.writeAsciiString("\tCollatorRule");
1307 of.writeInt(j);
1308 of.writeAsciiString(",\n");
1310 of.writeAsciiString("};\n\n");
1312 of.writeAsciiString("static const sal_Unicode* collationOptions[] = {");
1313 for( sal_Int16 j=0; j<nbOfCollationOptions; j++ )
1315 of.writeAsciiString( "collationOption" );
1316 of.writeInt( j );
1317 of.writeAsciiString( ", " );
1319 of.writeAsciiString("NULL };\n");
1320 of.writeFunction("getCollatorImplementation_", "nbOfCollations", "LCCollatorArray");
1321 of.writeFunction("getCollationOptions_", "nbOfCollationOptions", "collationOptions");
1324 void LCSearchNode::generateCode (const OFileWriter &of) const
1326 OUString useLocale = getAttr().getValueByName("ref");
1327 if (!useLocale.isEmpty()) {
1328 useLocale = useLocale.replace( '-', '_');
1329 of.writeRefFunction("getSearchOptions_", useLocale);
1330 return;
1333 if( getNumberOfChildren() != 1 )
1335 ++nError;
1336 fprintf(
1337 stderr, "Error: LC_SEARCH: more than 1 child: %ld\n",
1338 sal::static_int_cast< long >(getNumberOfChildren()));
1340 sal_Int32 i;
1341 LocaleNode* pSearchOptions = getChildAt( 0 );
1342 sal_Int32 nSearchOptions = pSearchOptions->getNumberOfChildren();
1343 for( i=0; i<nSearchOptions; i++ )
1345 of.writeParameter("searchOption", pSearchOptions->getChildAt( i )->getValue(), sal::static_int_cast<sal_Int16>(i) );
1348 of.writeAsciiString("static const sal_Int16 nbOfSearchOptions = ");
1349 of.writeInt( sal::static_int_cast<sal_Int16>( nSearchOptions ) );
1350 of.writeAsciiString(";\n\n");
1352 of.writeAsciiString("static const sal_Unicode* searchOptions[] = {");
1353 for( i=0; i<nSearchOptions; i++ )
1355 of.writeAsciiString( "searchOption" );
1356 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
1357 of.writeAsciiString( ", " );
1359 of.writeAsciiString("NULL };\n");
1360 of.writeFunction("getSearchOptions_", "nbOfSearchOptions", "searchOptions");
1363 void LCIndexNode::generateCode (const OFileWriter &of) const
1365 OUString useLocale = getAttr().getValueByName("ref");
1366 if (!useLocale.isEmpty()) {
1367 useLocale = useLocale.replace( '-', '_');
1368 of.writeRefFunction("getIndexAlgorithm_", useLocale);
1369 of.writeRefFunction("getUnicodeScripts_", useLocale);
1370 of.writeRefFunction("getFollowPageWords_", useLocale);
1371 return;
1373 sal_Int16 nbOfIndexs = 0;
1374 sal_Int16 nbOfUnicodeScripts = 0;
1375 sal_Int16 nbOfPageWords = 0;
1376 for (sal_Int32 i = 0; i< getNumberOfChildren();i++) {
1377 LocaleNode * currNode = getChildAt (i);
1378 if( currNode->getName() == "IndexKey" )
1380 OUString str;
1381 str = currNode->getAttr().getValueByName("unoid");
1382 of.writeParameter("IndexID", str, nbOfIndexs);
1383 str = currNode->getAttr().getValueByName("module");
1384 of.writeParameter("IndexModule", str, nbOfIndexs);
1385 str = currNode->getValue();
1386 of.writeParameter("IndexKey", str, nbOfIndexs);
1387 str = currNode -> getAttr().getValueByName("default");
1388 of.writeDefaultParameter("Index", str, nbOfIndexs);
1389 str = currNode -> getAttr().getValueByName("phonetic");
1390 of.writeDefaultParameter("Phonetic", str, nbOfIndexs);
1391 of.writeAsciiString("\n");
1393 nbOfIndexs++;
1395 if( currNode->getName() == "UnicodeScript" )
1397 of.writeParameter("unicodeScript", currNode->getValue(), nbOfUnicodeScripts );
1398 nbOfUnicodeScripts++;
1401 if( currNode->getName() == "FollowPageWord" )
1403 of.writeParameter("followPageWord", currNode->getValue(), nbOfPageWords);
1404 nbOfPageWords++;
1407 of.writeAsciiString("static const sal_Int16 nbOfIndexs = ");
1408 of.writeInt(nbOfIndexs);
1409 of.writeAsciiString(";\n\n");
1411 of.writeAsciiString("\nstatic const sal_Unicode* IndexArray[] = {\n");
1412 for(sal_Int16 i = 0; i < nbOfIndexs; i++) {
1413 of.writeAsciiString("\tIndexID");
1414 of.writeInt(i);
1415 of.writeAsciiString(",\n");
1417 of.writeAsciiString("\tIndexModule");
1418 of.writeInt(i);
1419 of.writeAsciiString(",\n");
1421 of.writeAsciiString("\tIndexKey");
1422 of.writeInt(i);
1423 of.writeAsciiString(",\n");
1425 of.writeAsciiString("\tdefaultIndex");
1426 of.writeInt(i);
1427 of.writeAsciiString(",\n");
1429 of.writeAsciiString("\tdefaultPhonetic");
1430 of.writeInt(i);
1431 of.writeAsciiString(",\n");
1433 of.writeAsciiString("};\n\n");
1435 of.writeAsciiString("static const sal_Int16 nbOfUnicodeScripts = ");
1436 of.writeInt( nbOfUnicodeScripts );
1437 of.writeAsciiString(";\n\n");
1439 of.writeAsciiString("static const sal_Unicode* UnicodeScriptArray[] = {");
1440 for( sal_Int16 i=0; i<nbOfUnicodeScripts; i++ )
1442 of.writeAsciiString( "unicodeScript" );
1443 of.writeInt( i );
1444 of.writeAsciiString( ", " );
1446 of.writeAsciiString("NULL };\n\n");
1448 of.writeAsciiString("static const sal_Int16 nbOfPageWords = ");
1449 of.writeInt(nbOfPageWords);
1450 of.writeAsciiString(";\n\n");
1452 of.writeAsciiString("static const sal_Unicode* FollowPageWordArray[] = {\n");
1453 for(sal_Int16 i = 0; i < nbOfPageWords; i++) {
1454 of.writeAsciiString("\tfollowPageWord");
1455 of.writeInt(i);
1456 of.writeAsciiString(",\n");
1458 of.writeAsciiString("\tNULL\n};\n\n");
1460 of.writeFunction("getIndexAlgorithm_", "nbOfIndexs", "IndexArray");
1461 of.writeFunction("getUnicodeScripts_", "nbOfUnicodeScripts", "UnicodeScriptArray");
1462 of.writeFunction("getFollowPageWords_", "nbOfPageWords", "FollowPageWordArray");
1466 static void lcl_writeAbbrFullNarrNames( const OFileWriter & of, const LocaleNode* currNode,
1467 const sal_Char* elementTag, sal_Int16 i, sal_Int16 j )
1469 OUString aAbbrName = currNode->getChildAt(1)->getValue();
1470 OUString aFullName = currNode->getChildAt(2)->getValue();
1471 OUString aNarrName;
1472 LocaleNode* p = (currNode->getNumberOfChildren() > 3 ? currNode->getChildAt(3) : nullptr);
1473 if ( p && p->getName() == "DefaultNarrowName" )
1474 aNarrName = p->getValue();
1475 else
1477 sal_Int32 nIndex = 0;
1478 sal_uInt32 nChar = aFullName.iterateCodePoints( &nIndex);
1479 aNarrName = OUString( &nChar, 1);
1481 of.writeParameter( elementTag, "DefaultAbbrvName", aAbbrName, i, j);
1482 of.writeParameter( elementTag, "DefaultFullName", aFullName, i, j);
1483 of.writeParameter( elementTag, "DefaultNarrowName", aNarrName, i, j);
1486 static void lcl_writeTabTagString( const OFileWriter & of, const sal_Char* pTag, const sal_Char* pStr )
1488 of.writeAsciiString("\t");
1489 of.writeAsciiString( pTag);
1490 of.writeAsciiString( pStr);
1493 static void lcl_writeTabTagStringNums( const OFileWriter & of,
1494 const sal_Char* pTag, const sal_Char* pStr, sal_Int16 i, sal_Int16 j )
1496 lcl_writeTabTagString( of, pTag, pStr);
1497 of.writeInt(i); of.writeInt(j); of.writeAsciiString(",\n");
1500 static void lcl_writeAbbrFullNarrArrays( const OFileWriter & of, sal_Int16 nCount,
1501 const sal_Char* elementTag, sal_Int16 i, bool bNarrow )
1503 if (nCount == 0)
1505 lcl_writeTabTagString( of, elementTag, "Ref");
1506 of.writeInt(i); of.writeAsciiString(",\n");
1507 lcl_writeTabTagString( of, elementTag, "RefName");
1508 of.writeInt(i); of.writeAsciiString(",\n");
1510 else
1512 for (sal_Int16 j = 0; j < nCount; j++)
1514 lcl_writeTabTagStringNums( of, elementTag, "ID", i, j);
1515 lcl_writeTabTagStringNums( of, elementTag, "DefaultAbbrvName", i, j);
1516 lcl_writeTabTagStringNums( of, elementTag, "DefaultFullName", i, j);
1517 if (bNarrow)
1518 lcl_writeTabTagStringNums( of, elementTag, "DefaultNarrowName", i, j);
1523 void LCCalendarNode::generateCode (const OFileWriter &of) const
1525 OUString useLocale = getAttr().getValueByName("ref");
1526 if (!useLocale.isEmpty()) {
1527 useLocale = useLocale.replace( '-', '_');
1528 of.writeRefFunction("getAllCalendars_", useLocale);
1529 return;
1531 sal_Int16 nbOfCalendars = sal::static_int_cast<sal_Int16>( getNumberOfChildren() );
1532 OUString str;
1533 std::unique_ptr<sal_Int16[]> nbOfDays( new sal_Int16[nbOfCalendars] );
1534 std::unique_ptr<sal_Int16[]> nbOfMonths( new sal_Int16[nbOfCalendars] );
1535 std::unique_ptr<sal_Int16[]> nbOfGenitiveMonths( new sal_Int16[nbOfCalendars] );
1536 std::unique_ptr<sal_Int16[]> nbOfPartitiveMonths( new sal_Int16[nbOfCalendars] );
1537 std::unique_ptr<sal_Int16[]> nbOfEras( new sal_Int16[nbOfCalendars] );
1538 sal_Int16 j;
1539 sal_Int16 i;
1540 bool bHasGregorian = false;
1543 for ( i = 0; i < nbOfCalendars; i++) {
1544 LocaleNode * calNode = getChildAt (i);
1545 OUString calendarID = calNode -> getAttr().getValueByName("unoid");
1546 of.writeParameter( "calendarID", calendarID, i);
1547 bool bGregorian = calendarID == "gregorian";
1548 if (!bHasGregorian)
1549 bHasGregorian = bGregorian;
1550 str = calNode -> getAttr().getValueByName("default");
1551 of.writeDefaultParameter("Calendar", str, i);
1553 sal_Int16 nChild = 0;
1555 // Generate Days of Week
1556 const sal_Char *elementTag;
1557 LocaleNode * daysNode = nullptr;
1558 OUString ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
1559 ref_name = ref_name.replace( '-', '_');
1560 if (!ref_name.isEmpty() && i > 0) {
1561 for (j = 0; j < i; j++) {
1562 str = getChildAt(j)->getAttr().getValueByName("unoid");
1563 if (str == ref_name)
1564 daysNode = getChildAt(j)->getChildAt(0);
1567 if (!ref_name.isEmpty() && daysNode == nullptr) {
1568 of.writeParameter("dayRef", "ref", i);
1569 of.writeParameter("dayRefName", ref_name, i);
1570 nbOfDays[i] = 0;
1571 } else {
1572 if (daysNode == nullptr)
1573 daysNode = calNode -> getChildAt(nChild);
1574 nbOfDays[i] = sal::static_int_cast<sal_Int16>( daysNode->getNumberOfChildren() );
1575 if (bGregorian && nbOfDays[i] != 7)
1576 incErrorInt( "Error: A Gregorian calendar must have 7 days per week, this one has %d\n", nbOfDays[i]);
1577 elementTag = "day";
1578 for (j = 0; j < nbOfDays[i]; j++) {
1579 LocaleNode *currNode = daysNode -> getChildAt(j);
1580 OUString dayID( currNode->getChildAt(0)->getValue());
1581 of.writeParameter("dayID", dayID, i, j);
1582 if ( j == 0 && bGregorian && dayID != "sun" )
1583 incError( "First day of a week of a Gregorian calendar must be <DayID>sun</DayID>");
1584 lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
1587 ++nChild;
1589 // Generate Months of Year
1590 LocaleNode * monthsNode = nullptr;
1591 ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
1592 ref_name = ref_name.replace( '-', '_');
1593 if (!ref_name.isEmpty() && i > 0) {
1594 for (j = 0; j < i; j++) {
1595 str = getChildAt(j)->getAttr().getValueByName("unoid");
1596 if (str == ref_name)
1597 monthsNode = getChildAt(j)->getChildAt(1);
1600 if (!ref_name.isEmpty() && monthsNode == nullptr) {
1601 of.writeParameter("monthRef", "ref", i);
1602 of.writeParameter("monthRefName", ref_name, i);
1603 nbOfMonths[i] = 0;
1604 } else {
1605 if (monthsNode == nullptr)
1606 monthsNode = calNode -> getChildAt(nChild);
1607 nbOfMonths[i] = sal::static_int_cast<sal_Int16>( monthsNode->getNumberOfChildren() );
1608 if (bGregorian && nbOfMonths[i] != 12)
1609 incErrorInt( "Error: A Gregorian calendar must have 12 months, this one has %d\n", nbOfMonths[i]);
1610 elementTag = "month";
1611 for (j = 0; j < nbOfMonths[i]; j++) {
1612 LocaleNode *currNode = monthsNode -> getChildAt(j);
1613 OUString monthID( currNode->getChildAt(0)->getValue());
1614 of.writeParameter("monthID", monthID, i, j);
1615 if ( j == 0 && bGregorian && monthID != "jan" )
1616 incError( "First month of a year of a Gregorian calendar must be <MonthID>jan</MonthID>");
1617 lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
1620 ++nChild;
1622 // Generate genitive Months of Year
1623 // Optional, if not present fall back to month nouns.
1624 if ( calNode->getChildAt(nChild)->getName() != "GenitiveMonths" )
1625 --nChild;
1626 LocaleNode * genitiveMonthsNode = nullptr;
1627 ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
1628 ref_name = ref_name.replace( '-', '_');
1629 if (!ref_name.isEmpty() && i > 0) {
1630 for (j = 0; j < i; j++) {
1631 str = getChildAt(j)->getAttr().getValueByName("unoid");
1632 if (str == ref_name)
1633 genitiveMonthsNode = getChildAt(j)->getChildAt(1);
1636 if (!ref_name.isEmpty() && genitiveMonthsNode == nullptr) {
1637 of.writeParameter("genitiveMonthRef", "ref", i);
1638 of.writeParameter("genitiveMonthRefName", ref_name, i);
1639 nbOfGenitiveMonths[i] = 0;
1640 } else {
1641 if (genitiveMonthsNode == nullptr)
1642 genitiveMonthsNode = calNode -> getChildAt(nChild);
1643 nbOfGenitiveMonths[i] = sal::static_int_cast<sal_Int16>( genitiveMonthsNode->getNumberOfChildren() );
1644 if (bGregorian && nbOfGenitiveMonths[i] != 12)
1645 incErrorInt( "Error: A Gregorian calendar must have 12 genitive months, this one has %d\n", nbOfGenitiveMonths[i]);
1646 elementTag = "genitiveMonth";
1647 for (j = 0; j < nbOfGenitiveMonths[i]; j++) {
1648 LocaleNode *currNode = genitiveMonthsNode -> getChildAt(j);
1649 OUString genitiveMonthID( currNode->getChildAt(0)->getValue());
1650 of.writeParameter("genitiveMonthID", genitiveMonthID, i, j);
1651 if ( j == 0 && bGregorian && genitiveMonthID != "jan" )
1652 incError( "First genitive month of a year of a Gregorian calendar must be <MonthID>jan</MonthID>");
1653 lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
1656 ++nChild;
1658 // Generate partitive Months of Year
1659 // Optional, if not present fall back to genitive months, or nominative
1660 // months (nouns) if that isn't present either.
1661 if ( calNode->getChildAt(nChild)->getName() != "PartitiveMonths" )
1662 --nChild;
1663 LocaleNode * partitiveMonthsNode = nullptr;
1664 ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
1665 ref_name = ref_name.replace( '-', '_');
1666 if (!ref_name.isEmpty() && i > 0) {
1667 for (j = 0; j < i; j++) {
1668 str = getChildAt(j)->getAttr().getValueByName("unoid");
1669 if (str == ref_name)
1670 partitiveMonthsNode = getChildAt(j)->getChildAt(1);
1673 if (!ref_name.isEmpty() && partitiveMonthsNode == nullptr) {
1674 of.writeParameter("partitiveMonthRef", "ref", i);
1675 of.writeParameter("partitiveMonthRefName", ref_name, i);
1676 nbOfPartitiveMonths[i] = 0;
1677 } else {
1678 if (partitiveMonthsNode == nullptr)
1679 partitiveMonthsNode = calNode -> getChildAt(nChild);
1680 nbOfPartitiveMonths[i] = sal::static_int_cast<sal_Int16>( partitiveMonthsNode->getNumberOfChildren() );
1681 if (bGregorian && nbOfPartitiveMonths[i] != 12)
1682 incErrorInt( "Error: A Gregorian calendar must have 12 partitive months, this one has %d\n", nbOfPartitiveMonths[i]);
1683 elementTag = "partitiveMonth";
1684 for (j = 0; j < nbOfPartitiveMonths[i]; j++) {
1685 LocaleNode *currNode = partitiveMonthsNode -> getChildAt(j);
1686 OUString partitiveMonthID( currNode->getChildAt(0)->getValue());
1687 of.writeParameter("partitiveMonthID", partitiveMonthID, i, j);
1688 if ( j == 0 && bGregorian && partitiveMonthID != "jan" )
1689 incError( "First partitive month of a year of a Gregorian calendar must be <MonthID>jan</MonthID>");
1690 lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
1693 ++nChild;
1695 // Generate Era name
1696 LocaleNode * erasNode = nullptr;
1697 ref_name = calNode -> getChildAt(nChild) ->getAttr().getValueByName("ref");
1698 ref_name = ref_name.replace( '-', '_');
1699 if (!ref_name.isEmpty() && i > 0) {
1700 for (j = 0; j < i; j++) {
1701 str = getChildAt(j)->getAttr().getValueByName("unoid");
1702 if (str == ref_name)
1703 erasNode = getChildAt(j)->getChildAt(2);
1706 if (!ref_name.isEmpty() && erasNode == nullptr) {
1707 of.writeParameter("eraRef", "ref", i);
1708 of.writeParameter("eraRefName", ref_name, i);
1709 nbOfEras[i] = 0;
1710 } else {
1711 if (erasNode == nullptr)
1712 erasNode = calNode -> getChildAt(nChild);
1713 nbOfEras[i] = sal::static_int_cast<sal_Int16>( erasNode->getNumberOfChildren() );
1714 if (bGregorian && nbOfEras[i] != 2)
1715 incErrorInt( "Error: A Gregorian calendar must have 2 eras, this one has %d\n", nbOfEras[i]);
1716 elementTag = "era";
1717 for (j = 0; j < nbOfEras[i]; j++) {
1718 LocaleNode *currNode = erasNode -> getChildAt(j);
1719 OUString eraID( currNode->getChildAt(0)->getValue());
1720 of.writeParameter("eraID", eraID, i, j);
1721 if ( j == 0 && bGregorian && eraID != "bc" )
1722 incError( "First era of a Gregorian calendar must be <EraID>bc</EraID>");
1723 if ( j == 1 && bGregorian && eraID != "ad" )
1724 incError( "Second era of a Gregorian calendar must be <EraID>ad</EraID>");
1725 of.writeAsciiString("\n");
1726 of.writeParameter(elementTag, "DefaultAbbrvName",currNode->getChildAt(1)->getValue() ,i, j);
1727 of.writeParameter(elementTag, "DefaultFullName",currNode->getChildAt(2)->getValue() , i, j);
1730 ++nChild;
1732 str = calNode->getChildAt(nChild)->getChildAt(0)->getValue();
1733 if (nbOfDays[i])
1735 for (j = 0; j < nbOfDays[i]; j++)
1737 LocaleNode *currNode = daysNode->getChildAt(j);
1738 OUString dayID( currNode->getChildAt(0)->getValue());
1739 if (str == dayID)
1740 break; // for
1742 if (j >= nbOfDays[i])
1743 incErrorStr( "Error: <StartDayOfWeek> <DayID> must be one of the <DaysOfWeek>, but is: %s\n", str);
1745 of.writeParameter("startDayOfWeek", str, i);
1746 ++nChild;
1748 str = calNode ->getChildAt(nChild)-> getValue();
1749 sal_Int16 nDays = sal::static_int_cast<sal_Int16>( str.toInt32() );
1750 if (nDays < 1 || (0 < nbOfDays[i] && nbOfDays[i] < nDays))
1751 incErrorInt( "Error: Bad value of MinimalDaysInFirstWeek: %d, must be 1 <= value <= days_in_week\n", nDays);
1752 of.writeIntParameter("minimalDaysInFirstWeek", i, nDays);
1754 if (!bHasGregorian)
1755 fprintf( stderr, "Warning: %s\n", "No Gregorian calendar defined, are you sure?");
1757 of.writeAsciiString("static const sal_Int16 calendarsCount = ");
1758 of.writeInt(nbOfCalendars);
1759 of.writeAsciiString(";\n\n");
1761 of.writeAsciiString("static const sal_Unicode nbOfDays[] = {");
1762 for(i = 0; i < nbOfCalendars - 1; i++) {
1763 of.writeInt(nbOfDays[i]);
1764 of.writeAsciiString(", ");
1766 of.writeInt(nbOfDays[i]);
1767 of.writeAsciiString("};\n");
1769 of.writeAsciiString("static const sal_Unicode nbOfMonths[] = {");
1770 for(i = 0; i < nbOfCalendars - 1; i++) {
1771 of.writeInt(nbOfMonths[i]);
1772 of.writeAsciiString(", ");
1774 of.writeInt(nbOfMonths[i]);
1775 of.writeAsciiString("};\n");
1777 of.writeAsciiString("static const sal_Unicode nbOfGenitiveMonths[] = {");
1778 for(i = 0; i < nbOfCalendars - 1; i++) {
1779 of.writeInt(nbOfGenitiveMonths[i]);
1780 of.writeAsciiString(", ");
1782 of.writeInt(nbOfGenitiveMonths[i]);
1783 of.writeAsciiString("};\n");
1785 of.writeAsciiString("static const sal_Unicode nbOfPartitiveMonths[] = {");
1786 for(i = 0; i < nbOfCalendars - 1; i++) {
1787 of.writeInt(nbOfPartitiveMonths[i]);
1788 of.writeAsciiString(", ");
1790 of.writeInt(nbOfPartitiveMonths[i]);
1791 of.writeAsciiString("};\n");
1793 of.writeAsciiString("static const sal_Unicode nbOfEras[] = {");
1794 for(i = 0; i < nbOfCalendars - 1; i++) {
1795 of.writeInt(nbOfEras[i]);
1796 of.writeAsciiString(", ");
1798 of.writeInt(nbOfEras[i]);
1799 of.writeAsciiString("};\n");
1802 of.writeAsciiString("static const sal_Unicode* calendars[] = {\n");
1803 of.writeAsciiString("\tnbOfDays,\n");
1804 of.writeAsciiString("\tnbOfMonths,\n");
1805 of.writeAsciiString("\tnbOfGenitiveMonths,\n");
1806 of.writeAsciiString("\tnbOfPartitiveMonths,\n");
1807 of.writeAsciiString("\tnbOfEras,\n");
1808 for(i = 0; i < nbOfCalendars; i++) {
1809 of.writeAsciiString("\tcalendarID");
1810 of.writeInt(i);
1811 of.writeAsciiString(",\n");
1812 of.writeAsciiString("\tdefaultCalendar");
1813 of.writeInt(i);
1814 of.writeAsciiString(",\n");
1815 lcl_writeAbbrFullNarrArrays( of, nbOfDays[i], "day", i, true);
1816 lcl_writeAbbrFullNarrArrays( of, nbOfMonths[i], "month", i, true);
1817 lcl_writeAbbrFullNarrArrays( of, nbOfGenitiveMonths[i], "genitiveMonth", i, true);
1818 lcl_writeAbbrFullNarrArrays( of, nbOfPartitiveMonths[i], "partitiveMonth", i, true);
1819 lcl_writeAbbrFullNarrArrays( of, nbOfEras[i], "era", i, false /*noNarrow*/);
1820 of.writeAsciiString("\tstartDayOfWeek");of.writeInt(i); of.writeAsciiString(",\n");
1821 of.writeAsciiString("\tminimalDaysInFirstWeek");of.writeInt(i); of.writeAsciiString(",\n");
1824 of.writeAsciiString("};\n\n");
1825 of.writeFunction("getAllCalendars_", "calendarsCount", "calendars");
1828 static bool isIso4217( const OUString& rStr )
1830 const sal_Unicode* p = rStr.getStr();
1831 return rStr.getLength() == 3
1832 && 'A' <= p[0] && p[0] <= 'Z'
1833 && 'A' <= p[1] && p[1] <= 'Z'
1834 && 'A' <= p[2] && p[2] <= 'Z'
1838 void LCCurrencyNode::generateCode (const OFileWriter &of) const
1840 OUString useLocale = getAttr().getValueByName("ref");
1841 if (!useLocale.isEmpty()) {
1842 useLocale = useLocale.replace( '-', '_');
1843 of.writeRefFunction("getAllCurrencies_", useLocale);
1844 return;
1846 sal_Int16 nbOfCurrencies = 0;
1847 OUString str;
1849 bool bTheDefault= false;
1850 bool bTheCompatible = false;
1851 for ( sal_Int32 i = 0; i < getNumberOfChildren(); i++,nbOfCurrencies++) {
1852 LocaleNode * currencyNode = getChildAt (i);
1853 str = currencyNode->getAttr().getValueByName("default");
1854 bool bDefault = of.writeDefaultParameter("Currency", str, nbOfCurrencies);
1855 str = currencyNode->getAttr().getValueByName("usedInCompatibleFormatCodes");
1856 bool bCompatible = of.writeDefaultParameter("CurrencyUsedInCompatibleFormatCodes", str, nbOfCurrencies);
1857 str = currencyNode->getAttr().getValueByName("legacyOnly");
1858 bool bLegacy = of.writeDefaultParameter("CurrencyLegacyOnly", str, nbOfCurrencies);
1859 if (bLegacy && (bDefault || bCompatible))
1860 incError( "Currency: if legacyOnly==true, both 'default' and 'usedInCompatibleFormatCodes' must be false.");
1861 if (bDefault)
1863 if (bTheDefault)
1864 incError( "Currency: more than one default currency.");
1865 bTheDefault = true;
1867 if (bCompatible)
1869 if (bTheCompatible)
1870 incError( "Currency: more than one currency flagged as usedInCompatibleFormatCodes.");
1871 bTheCompatible = true;
1873 str = currencyNode -> findNode ("CurrencyID") -> getValue();
1874 of.writeParameter("currencyID", str, nbOfCurrencies);
1875 // CurrencyID MUST be ISO 4217.
1876 if (!bLegacy && !isIso4217(str))
1877 incError( "CurrencyID is not ISO 4217");
1878 str = currencyNode -> findNode ("CurrencySymbol") -> getValue();
1879 of.writeParameter("currencySymbol", str, nbOfCurrencies);
1880 // Check if this currency really is the one used in number format
1881 // codes. In case of ref=... mechanisms it may be that TheCurrency
1882 // couldn't had been determined from the current locale (i.e. is
1883 // empty), silently assume the referred locale has things right.
1884 if (bCompatible && !sTheCompatibleCurrency.isEmpty() && sTheCompatibleCurrency != str)
1885 incErrorStrStr( "Error: CurrencySymbol \"%s\" flagged as usedInCompatibleFormatCodes doesn't match \"%s\" determined from format codes.\n", str, sTheCompatibleCurrency);
1886 str = currencyNode -> findNode ("BankSymbol") -> getValue();
1887 of.writeParameter("bankSymbol", str, nbOfCurrencies);
1888 // BankSymbol currently must be ISO 4217. May change later if
1889 // application always uses CurrencyID instead of BankSymbol.
1890 if (!bLegacy && !isIso4217(str))
1891 incError( "BankSymbol is not ISO 4217");
1892 str = currencyNode -> findNode ("CurrencyName") -> getValue();
1893 of.writeParameter("currencyName", str, nbOfCurrencies);
1894 str = currencyNode -> findNode ("DecimalPlaces") -> getValue();
1895 sal_Int16 nDecimalPlaces = static_cast<sal_Int16>(str.toInt32());
1896 of.writeIntParameter("currencyDecimalPlaces", nbOfCurrencies, nDecimalPlaces);
1897 of.writeAsciiString("\n");
1900 if (!bTheDefault)
1901 incError( "Currency: no default currency.");
1902 if (!bTheCompatible)
1903 incError( "Currency: no currency flagged as usedInCompatibleFormatCodes.");
1905 of.writeAsciiString("static const sal_Int16 currencyCount = ");
1906 of.writeInt(nbOfCurrencies);
1907 of.writeAsciiString(";\n\n");
1908 of.writeAsciiString("static const sal_Unicode* currencies[] = {\n");
1909 for(sal_Int16 i = 0; i < nbOfCurrencies; i++) {
1910 of.writeAsciiString("\tcurrencyID");
1911 of.writeInt(i);
1912 of.writeAsciiString(",\n");
1913 of.writeAsciiString("\tcurrencySymbol");
1914 of.writeInt(i);
1915 of.writeAsciiString(",\n");
1916 of.writeAsciiString("\tbankSymbol");
1917 of.writeInt(i);
1918 of.writeAsciiString(",\n");
1919 of.writeAsciiString("\tcurrencyName");
1920 of.writeInt(i);
1921 of.writeAsciiString(",\n");
1922 of.writeAsciiString("\tdefaultCurrency");
1923 of.writeInt(i);
1924 of.writeAsciiString(",\n");
1925 of.writeAsciiString("\tdefaultCurrencyUsedInCompatibleFormatCodes");
1926 of.writeInt(i);
1927 of.writeAsciiString(",\n");
1928 of.writeAsciiString("\tcurrencyDecimalPlaces");
1929 of.writeInt(i);
1930 of.writeAsciiString(",\n");
1931 of.writeAsciiString("\tdefaultCurrencyLegacyOnly");
1932 of.writeInt(i);
1933 of.writeAsciiString(",\n");
1935 of.writeAsciiString("};\n\n");
1936 of.writeFunction("getAllCurrencies_", "currencyCount", "currencies");
1939 void LCTransliterationNode::generateCode (const OFileWriter &of) const
1941 OUString useLocale = getAttr().getValueByName("ref");
1942 if (!useLocale.isEmpty()) {
1943 useLocale = useLocale.replace( '-', '_');
1944 of.writeRefFunction("getTransliterations_", useLocale);
1945 return;
1947 sal_Int16 nbOfModules = 0;
1948 OUString str;
1950 for ( sal_Int32 i = 0; i < getNumberOfChildren(); i++,nbOfModules++) {
1951 LocaleNode * transNode = getChildAt (i);
1952 str = transNode->getAttr().getValueByIndex(0);
1953 of.writeParameter("Transliteration", str, nbOfModules);
1955 of.writeAsciiString("static const sal_Int16 nbOfTransliterations = ");
1956 of.writeInt(nbOfModules);
1957 of.writeAsciiString(";\n\n");
1959 of.writeAsciiString("\nstatic const sal_Unicode* LCTransliterationsArray[] = {\n");
1960 for( sal_Int16 i = 0; i < nbOfModules; i++) {
1961 of.writeAsciiString("\tTransliteration");
1962 of.writeInt(i);
1963 of.writeAsciiString(",\n");
1965 of.writeAsciiString("};\n\n");
1966 of.writeFunction("getTransliterations_", "nbOfTransliterations", "LCTransliterationsArray");
1969 struct NameValuePair {
1970 const sal_Char *name;
1971 const sal_Char *value;
1973 static const NameValuePair ReserveWord[] = {
1974 { "trueWord", "true" },
1975 { "falseWord", "false" },
1976 { "quarter1Word", "1st quarter" },
1977 { "quarter2Word", "2nd quarter" },
1978 { "quarter3Word", "3rd quarter" },
1979 { "quarter4Word", "4th quarter" },
1980 { "aboveWord", "above" },
1981 { "belowWord", "below" },
1982 { "quarter1Abbreviation", "Q1" },
1983 { "quarter2Abbreviation", "Q2" },
1984 { "quarter3Abbreviation", "Q3" },
1985 { "quarter4Abbreviation", "Q4" }
1988 void LCMiscNode::generateCode (const OFileWriter &of) const
1990 OUString useLocale = getAttr().getValueByName("ref");
1991 if (!useLocale.isEmpty()) {
1992 useLocale = useLocale.replace( '-', '_');
1993 of.writeRefFunction("getForbiddenCharacters_", useLocale);
1994 of.writeRefFunction("getBreakIteratorRules_", useLocale);
1995 of.writeRefFunction("getReservedWords_", useLocale);
1996 return;
1998 const LocaleNode * reserveNode = findNode("ReservedWords");
1999 if (!reserveNode)
2000 incError( "No ReservedWords element."); // should not happen if validated...
2001 const LocaleNode * forbidNode = findNode("ForbiddenCharacters");
2002 const LocaleNode * breakNode = findNode("BreakIteratorRules");
2004 bool bEnglishLocale = (strncmp( of.getLocale(), "en_", 3) == 0);
2006 sal_Int16 nbOfWords = 0;
2007 OUString str;
2008 sal_Int16 i;
2010 for ( i = 0; i < sal_Int16(SAL_N_ELEMENTS(ReserveWord)); i++,nbOfWords++) {
2011 const LocaleNode * curNode = (reserveNode ? reserveNode->findNode(
2012 ReserveWord[i].name) : nullptr);
2013 if (!curNode)
2014 fprintf( stderr,
2015 "Warning: No %s in ReservedWords, using en_US default: \"%s\".\n",
2016 ReserveWord[i].name, ReserveWord[i].value);
2017 str = curNode ? curNode -> getValue() : OUString::createFromAscii(ReserveWord[i].value);
2018 if (str.isEmpty())
2020 ++nError;
2021 fprintf( stderr, "Error: No content for ReservedWords %s.\n", ReserveWord[i].name);
2023 of.writeParameter("ReservedWord", str, nbOfWords);
2024 // "true", ..., "below" trigger untranslated warning.
2025 if (!bEnglishLocale && curNode && i <= 7 &&
2026 str.equalsIgnoreAsciiCaseAscii( ReserveWord[i].value))
2028 fprintf( stderr,
2029 "Warning: ReservedWord %s seems to be untranslated \"%s\".\n",
2030 ReserveWord[i].name, ReserveWord[i].value);
2033 of.writeAsciiString("static const sal_Int16 nbOfReservedWords = ");
2034 of.writeInt(nbOfWords);
2035 of.writeAsciiString(";\n\n");
2036 of.writeAsciiString("\nstatic const sal_Unicode* LCReservedWordsArray[] = {\n");
2037 for( i = 0; i < nbOfWords; i++) {
2038 of.writeAsciiString("\tReservedWord");
2039 of.writeInt(i);
2040 of.writeAsciiString(",\n");
2042 of.writeAsciiString("};\n\n");
2043 of.writeFunction("getReservedWords_", "nbOfReservedWords", "LCReservedWordsArray");
2045 if (forbidNode) {
2046 of.writeParameter( "forbiddenBegin", forbidNode -> getChildAt(0)->getValue());
2047 of.writeParameter( "forbiddenEnd", forbidNode -> getChildAt(1)->getValue());
2048 of.writeParameter( "hangingChars", forbidNode -> getChildAt(2)->getValue());
2049 } else {
2050 of.writeParameter( "forbiddenBegin", OUString());
2051 of.writeParameter( "forbiddenEnd", OUString());
2052 of.writeParameter( "hangingChars", OUString());
2054 of.writeAsciiString("\nstatic const sal_Unicode* LCForbiddenCharactersArray[] = {\n");
2055 of.writeAsciiString("\tforbiddenBegin,\n");
2056 of.writeAsciiString("\tforbiddenEnd,\n");
2057 of.writeAsciiString("\thangingChars\n");
2058 of.writeAsciiString("};\n\n");
2059 of.writeFunction("getForbiddenCharacters_", "3", "LCForbiddenCharactersArray");
2061 if (breakNode) {
2062 of.writeParameter( "EditMode", breakNode -> getChildAt(0)->getValue());
2063 of.writeParameter( "DictionaryMode", breakNode -> getChildAt(1)->getValue());
2064 of.writeParameter( "WordCountMode", breakNode -> getChildAt(2)->getValue());
2065 of.writeParameter( "CharacterMode", breakNode -> getChildAt(3)->getValue());
2066 of.writeParameter( "LineMode", breakNode -> getChildAt(4)->getValue());
2067 } else {
2068 of.writeParameter( "EditMode", OUString());
2069 of.writeParameter( "DictionaryMode", OUString());
2070 of.writeParameter( "WordCountMode", OUString());
2071 of.writeParameter( "CharacterMode", OUString());
2072 of.writeParameter( "LineMode", OUString());
2074 of.writeAsciiString("\nstatic const sal_Unicode* LCBreakIteratorRulesArray[] = {\n");
2075 of.writeAsciiString("\tEditMode,\n");
2076 of.writeAsciiString("\tDictionaryMode,\n");
2077 of.writeAsciiString("\tWordCountMode,\n");
2078 of.writeAsciiString("\tCharacterMode,\n");
2079 of.writeAsciiString("\tLineMode\n");
2080 of.writeAsciiString("};\n\n");
2081 of.writeFunction("getBreakIteratorRules_", "5", "LCBreakIteratorRulesArray");
2085 void LCNumberingLevelNode::generateCode (const OFileWriter &of) const
2087 of.writeAsciiString("// ---> ContinuousNumbering\n");
2088 OUString useLocale = getAttr().getValueByName("ref");
2089 if (!useLocale.isEmpty()) {
2090 useLocale = useLocale.replace( '-', '_');
2091 of.writeRefFunction2("getContinuousNumberingLevels_", useLocale);
2092 return;
2095 // hard code number of attributes per style.
2096 const int nAttributes = 5;
2097 const char* attr[ nAttributes ] = { "Prefix", "NumType", "Suffix", "Transliteration", "NatNum" };
2099 // record each attribute of each style in a static C++ variable.
2100 // determine number of styles on the fly.
2101 sal_Int32 nStyles = getNumberOfChildren();
2102 sal_Int32 i;
2104 for( i = 0; i < nStyles; ++i )
2106 const Attr &q = getChildAt( i )->getAttr();
2107 for( sal_Int32 j=0; j<nAttributes; ++j )
2109 const char* name = attr[j];
2110 OUString value = q.getValueByName( name );
2111 of.writeParameter("continuous", name, value, sal::static_int_cast<sal_Int16>(i) );
2115 // record number of styles and attributes.
2116 of.writeAsciiString("static const sal_Int16 continuousNbOfStyles = ");
2117 of.writeInt( sal::static_int_cast<sal_Int16>( nStyles ) );
2118 of.writeAsciiString(";\n\n");
2119 of.writeAsciiString("static const sal_Int16 continuousNbOfAttributesPerStyle = ");
2120 of.writeInt( nAttributes );
2121 of.writeAsciiString(";\n\n");
2123 // generate code. (intermediate arrays)
2124 for( i=0; i<nStyles; i++ )
2126 of.writeAsciiString("\nstatic const sal_Unicode* continuousStyle" );
2127 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2128 of.writeAsciiString("[] = {\n");
2129 for( sal_Int32 j=0; j<nAttributes; j++)
2131 of.writeAsciiString("\t");
2132 of.writeAsciiString( "continuous" );
2133 of.writeAsciiString( attr[j] );
2134 of.writeInt(sal::static_int_cast<sal_Int16>(i));
2135 of.writeAsciiString(",\n");
2137 of.writeAsciiString("\t0\n};\n\n");
2140 // generate code. (top-level array)
2141 of.writeAsciiString("\n");
2142 of.writeAsciiString("static const sal_Unicode** LCContinuousNumberingLevelsArray[] = {\n" );
2143 for( i=0; i<nStyles; i++ )
2145 of.writeAsciiString( "\t" );
2146 of.writeAsciiString( "continuousStyle" );
2147 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2148 of.writeAsciiString( ",\n");
2150 of.writeAsciiString("\t0\n};\n\n");
2151 of.writeFunction2("getContinuousNumberingLevels_", "continuousNbOfStyles",
2152 "continuousNbOfAttributesPerStyle", "LCContinuousNumberingLevelsArray");
2156 void LCOutlineNumberingLevelNode::generateCode (const OFileWriter &of) const
2158 of.writeAsciiString("// ---> OutlineNumbering\n");
2159 OUString useLocale = getAttr().getValueByName("ref");
2160 if (!useLocale.isEmpty()) {
2161 useLocale = useLocale.replace( '-', '_');
2162 of.writeRefFunction3("getOutlineNumberingLevels_", useLocale);
2163 return;
2166 // hardcode number of attributes per level
2167 const int nAttributes = 11;
2168 const char* attr[ nAttributes ] =
2170 "Prefix",
2171 "NumType",
2172 "Suffix",
2173 "BulletChar",
2174 "BulletFontName",
2175 "ParentNumbering",
2176 "LeftMargin",
2177 "SymbolTextDistance",
2178 "FirstLineOffset",
2179 "Transliteration",
2180 "NatNum",
2183 // record each attribute of each level of each style in a static C++ variable.
2184 // determine number of styles and number of levels per style on the fly.
2185 sal_Int32 nStyles = getNumberOfChildren();
2186 vector<sal_Int32> nLevels; // may be different for each style?
2187 for( sal_Int32 i = 0; i < nStyles; i++ )
2189 LocaleNode* p = getChildAt( i );
2190 nLevels.push_back( p->getNumberOfChildren() );
2191 for( sal_Int32 j=0; j<nLevels.back(); j++ )
2193 const Attr& q = p->getChildAt( j )->getAttr();
2194 for( sal_Int32 k=0; k<nAttributes; ++k )
2196 const char* name = attr[k];
2197 OUString value = q.getValueByName( name );
2198 of.writeParameter("outline", name, value,
2199 sal::static_int_cast<sal_Int16>(i),
2200 sal::static_int_cast<sal_Int16>(j) );
2205 // verify that each style has the same number of levels.
2206 for( size_t i=0; i<nLevels.size(); i++ )
2208 if( nLevels[0] != nLevels[i] )
2210 incError( "Numbering levels don't match.");
2214 // record number of attributes, levels, and styles.
2215 of.writeAsciiString("static const sal_Int16 outlineNbOfStyles = ");
2216 of.writeInt( sal::static_int_cast<sal_Int16>( nStyles ) );
2217 of.writeAsciiString(";\n\n");
2218 of.writeAsciiString("static const sal_Int16 outlineNbOfLevelsPerStyle = ");
2219 of.writeInt( sal::static_int_cast<sal_Int16>( nLevels.back() ) );
2220 of.writeAsciiString(";\n\n");
2221 of.writeAsciiString("static const sal_Int16 outlineNbOfAttributesPerLevel = ");
2222 of.writeInt( nAttributes );
2223 of.writeAsciiString(";\n\n");
2225 // too complicated for now...
2226 // of.writeAsciiString("static const sal_Int16 nbOfOutlineNumberingLevels[] = { ");
2227 // for( sal_Int32 j=0; j<nStyles; j++ )
2228 // {
2229 // of.writeInt( nLevels[j] );
2230 // of.writeAsciiString(", ");
2231 // }
2232 // of.writeAsciiString("};\n\n");
2235 for( sal_Int32 i=0; i<nStyles; i++ )
2237 for( sal_Int32 j=0; j<nLevels.back(); j++ )
2239 of.writeAsciiString("static const sal_Unicode* outline");
2240 of.writeAsciiString("Style");
2241 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2242 of.writeAsciiString("Level");
2243 of.writeInt( sal::static_int_cast<sal_Int16>(j) );
2244 of.writeAsciiString("[] = { ");
2246 for( sal_Int32 k=0; k<nAttributes; k++ )
2248 of.writeAsciiString( "outline" );
2249 of.writeAsciiString( attr[k] );
2250 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2251 of.writeInt( sal::static_int_cast<sal_Int16>(j) );
2252 of.writeAsciiString(", ");
2254 of.writeAsciiString("NULL };\n");
2258 of.writeAsciiString("\n");
2261 for( sal_Int32 i=0; i<nStyles; i++ )
2263 of.writeAsciiString("static const sal_Unicode** outline");
2264 of.writeAsciiString( "Style" );
2265 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2266 of.writeAsciiString("[] = { ");
2268 for( sal_Int32 j=0; j<nLevels.back(); j++ )
2270 of.writeAsciiString("outlineStyle");
2271 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2272 of.writeAsciiString("Level");
2273 of.writeInt( sal::static_int_cast<sal_Int16>(j) );
2274 of.writeAsciiString(", ");
2276 of.writeAsciiString("NULL };\n");
2278 of.writeAsciiString("\n");
2280 of.writeAsciiString("static const sal_Unicode*** LCOutlineNumberingLevelsArray[] = {\n" );
2281 for( sal_Int32 i=0; i<nStyles; i++ )
2283 of.writeAsciiString( "\t" );
2284 of.writeAsciiString( "outlineStyle" );
2285 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2286 of.writeAsciiString(",\n");
2288 of.writeAsciiString("\tNULL\n};\n\n");
2289 of.writeFunction3("getOutlineNumberingLevels_", "outlineNbOfStyles", "outlineNbOfLevelsPerStyle",
2290 "outlineNbOfAttributesPerLevel", "LCOutlineNumberingLevelsArray");
2293 Attr::Attr (const Reference< XAttributeList > & attr) {
2294 sal_Int16 len = attr->getLength();
2295 name.realloc (len);
2296 value.realloc (len);
2297 for (sal_Int16 i =0; i< len;i++) {
2298 name[i] = attr->getNameByIndex(i);
2299 value[i] = attr -> getValueByIndex(i);
2303 OUString Attr::getValueByName (const sal_Char *str) const {
2304 auto pName = std::find_if(std::cbegin(name), std::cend(name),
2305 [&str](const OUString& rName) { return rName.equalsAscii(str); });
2306 if (pName != std::cend(name))
2308 auto i = static_cast<sal_Int32>(std::distance(std::cbegin(name), pName));
2309 return value[i];
2311 return OUString();
2314 const OUString& Attr::getValueByIndex (sal_Int32 idx) const
2316 return value[idx];
2319 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */