LibreOffice Module i18npool (master) 1
LocaleNode.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <stdio.h>
21#include <string.h>
22#include <algorithm>
23#include <memory>
24#include <utility>
25#include <vector>
26#include <map>
28#include <o3tl/temporary.hxx>
29#include <rtl/ustrbuf.hxx>
30#include <sal/macros.h>
31#include <sal/types.h>
32
33#include "LocaleNode.hxx"
35#include <com/sun/star/i18n/NumberFormatIndex.hpp>
36#include <com/sun/star/xml/sax/XAttributeList.hpp>
37
38// NOTE: MUST match the Locale versionDTD attribute defined in data/locale.dtd
39#define LOCALE_VERSION_DTD "2.0.3"
40
41typedef ::o3tl::sorted_vector< OUString > NameSet;
42typedef ::o3tl::sorted_vector< sal_Int16 > ValueSet;
43
44namespace cssi = ::com::sun::star::i18n;
45
46LocaleNode::LocaleNode (OUString name, const Reference< XAttributeList > & attr)
47 : aName(std::move(name))
48 , aAttribs(attr)
49 , parent(nullptr)
50 , nError(0)
51{
52}
53
55{
56 int err = nError;
57 for (size_t i=0;i<children.size();i++)
58 err += children[i]->getError();
59 return err;
60}
61
63 children.emplace_back(node);
64 node->parent = this;
65}
66
68{
69 const LocaleNode* pRoot = nullptr;
70 const LocaleNode* pParent = this;
71 while ( (pParent = pParent->parent) != nullptr )
72 pRoot = pParent;
73 return pRoot;
74}
75
76const LocaleNode * LocaleNode::findNode ( const char *name) const {
77 if (aName.equalsAscii(name))
78 return this;
79 for (size_t i = 0; i< children.size(); i++)
80 {
81 const LocaleNode *n=children[i]->findNode(name);
82 if (n)
83 return n;
84 }
85 return nullptr;
86}
87
89{
90}
91
92LocaleNode* LocaleNode::createNode (const OUString& name, const Reference< XAttributeList > & attr)
93{
94 if ( name == "LC_INFO" )
95 return new LCInfoNode (name,attr);
96 if ( name == "LC_CTYPE" )
97 return new LCCTYPENode (name,attr);
98 if ( name == "LC_FORMAT" )
99 return new LCFormatNode (name,attr);
100 if ( name == "LC_FORMAT_1" )
101 return new LCFormatNode (name,attr);
102 if ( name == "LC_CALENDAR" )
103 return new LCCalendarNode (name,attr);
104 if ( name == "LC_CURRENCY" )
105 return new LCCurrencyNode (name,attr);
106 if ( name == "LC_TRANSLITERATION" )
107 return new LCTransliterationNode (name,attr);
108 if ( name == "LC_COLLATION" )
109 return new LCCollationNode (name,attr);
110 if ( name == "LC_INDEX" )
111 return new LCIndexNode (name,attr);
112 if ( name == "LC_SEARCH" )
113 return new LCSearchNode (name,attr);
114 if ( name == "LC_MISC" )
115 return new LCMiscNode (name,attr);
116 if ( name == "LC_NumberingLevel" )
117 return new LCNumberingLevelNode (name, attr);
118 if ( name == "LC_OutLineNumberingLevel" )
119 return new LCOutlineNumberingLevelNode (name, attr);
120
121 return new LocaleNode(name,attr);
122}
123
124
125// printf(" name: '%s'\n", p->getName().pData->buffer );
126// printf("value: '%s'\n", p->getValue().pData->buffer );
127
128#define OSTR(s) (OUStringToOString( (s), RTL_TEXTENCODING_UTF8).getStr())
129
131{
132 OUString aDTD = getAttr().getValueByName("versionDTD");
133 if ( aDTD != LOCALE_VERSION_DTD )
134 {
135 ++nError;
136 fprintf( stderr, "Error: Locale versionDTD is not %s, see comment in locale.dtd\n", LOCALE_VERSION_DTD);
137 }
138 for (size_t i=0; i<children.size(); i++)
139 children[i]->generateCode (of);
140// print_node( this );
141}
142
143
145 const char* pParameterName, const LocaleNode* pNode,
146 sal_Int32 nMinLen, sal_Int32 nMaxLen ) const
147{
148 OUString aVal;
149 if (pNode)
150 aVal = pNode->getValue();
151 else if (nMinLen >= 0) // -1: optional => empty, 0: must be present, empty
152 {
153 ++nError;
154 fprintf( stderr, "Error: node NULL pointer for parameter %s.\n",
155 pParameterName);
156 }
157 // write empty data if error
158 of.writeParameter( pParameterName, aVal);
159 sal_Int32 nLen = aVal.getLength();
160 if (nLen < nMinLen)
161 {
162 ++nError;
163 fprintf( stderr, "Error: less than %" SAL_PRIdINT32 " character%s (%" SAL_PRIdINT32 ") in %s '%s'.\n",
164 nMinLen, (nMinLen > 1 ? "s" : ""),
165 nLen,
166 (pNode ? OSTR( pNode->getName()) : ""),
167 OSTR( aVal));
168 }
169 else if (nLen > nMaxLen && nMaxLen >= 0)
170 {
171 ++nError;
172 fprintf( stderr,
173 "Error: more than %" SAL_PRIdINT32 " character%s (%" SAL_PRIdINT32 ") in %s '%s' not supported by application.\n",
174 nMaxLen, (nMaxLen > 1 ? "s" : ""),
175 nLen,
176 (pNode ? OSTR( pNode->getName()) : ""),
177 OSTR( aVal));
178 }
179 return aVal;
180}
181
182
184 const char* pNodeName, const char* pParameterName,
185 sal_Int32 nMinLen, sal_Int32 nMaxLen ) const
186{
187 OUString aVal;
188 const LocaleNode * pNode = findNode( pNodeName);
189 if (pNode || nMinLen < 0)
190 aVal = writeParameterCheckLen( of, pParameterName, pNode, nMinLen, nMaxLen);
191 else
192 {
193 ++nError;
194 fprintf( stderr, "Error: node %s not found.\n", pNodeName);
195 // write empty data if error
196 of.writeParameter( pParameterName, aVal);
197 }
198 return aVal;
199}
200
201void LocaleNode::incError( const char* pStr ) const
202{
203 ++nError;
204 fprintf( stderr, "Error: %s\n", pStr);
205}
206
207void LocaleNode::incError( std::u16string_view rStr ) const
208{
209 incError( OSTR( rStr));
210}
211
212void LocaleNode::incErrorInt( const char* pStr, int nVal ) const
213{
214 ++nError;
215 fprintf( stderr, pStr, nVal);
216}
217
218void LocaleNode::incErrorStr( const char* pStr, std::u16string_view rVal ) const
219{
220 ++nError;
221 fprintf( stderr, pStr, OSTR( rVal));
222}
223
224void LocaleNode::incErrorStrStr( const char* pStr, std::u16string_view rVal1, std::u16string_view rVal2 ) const
225{
226 ++nError;
227 fprintf(stderr, pStr, OSTR(rVal1), OSTR(rVal2));
228}
229
231{
232
233 const LocaleNode * languageNode = findNode("Language");
234 const LocaleNode * countryNode = findNode("Country");
235 const LocaleNode * variantNode = findNode("Variant");
236
237 OUString aLanguage;
238
239 if (languageNode)
240 {
241 aLanguage = languageNode->getChildAt(0)->getValue();
242 if (aLanguage.getLength() != 2 && aLanguage.getLength() != 3)
243 incErrorStr( "Error: langID '%s' not 2-3 characters\n", aLanguage);
244 of.writeParameter("langID", aLanguage);
245 of.writeParameter("langDefaultName", languageNode->getChildAt(1)->getValue());
246 }
247 else
248 incError( "No Language node.");
249 if (countryNode)
250 {
251 OUString aCountry( countryNode->getChildAt(0)->getValue());
252 if (!(aCountry.isEmpty() || aCountry.getLength() == 2))
253 incErrorStr( "Error: countryID '%s' not empty or more than 2 characters\n", aCountry);
254 of.writeParameter("countryID", aCountry);
255 of.writeParameter("countryDefaultName", countryNode->getChildAt(1)->getValue());
256 }
257 else
258 incError( "No Country node.");
259 if (variantNode)
260 {
261 // If given Variant must be at least ll-Ssss and language must be 'qlt'
262 const OUString& aVariant( variantNode->getValue());
263 if (!(aVariant.isEmpty() || (aVariant.getLength() >= 7 && aVariant.indexOf('-') >= 2)))
264 incErrorStr( "Error: invalid Variant '%s'\n", aVariant);
265 if (!(aVariant.isEmpty() || aLanguage == "qlt"))
266 incErrorStrStr( "Error: Variant '%s' given but Language '%s' is not 'qlt'\n", aVariant, aLanguage);
267 of.writeParameter("Variant", aVariant);
268 }
269 else
270 of.writeParameter("Variant", std::u16string_view());
271 of.writeAsciiString("\nstatic const sal_Unicode* LCInfoArray[] = {\n");
272 of.writeAsciiString("\tlangID,\n");
273 of.writeAsciiString("\tlangDefaultName,\n");
274 of.writeAsciiString("\tcountryID,\n");
275 of.writeAsciiString("\tcountryDefaultName,\n");
276 of.writeAsciiString("\tVariant\n");
277 of.writeAsciiString("};\n\n");
278 of.writeFunction("getLCInfo_", "SAL_N_ELEMENTS(LCInfoArray)", "LCInfoArray");
279}
280
281
282static OUString aDateSep;
283static OUString aDecSep;
284
286{
287 const LocaleNode * sepNode = nullptr;
288 OUString useLocale = getAttr().getValueByName("ref");
289 if (!useLocale.isEmpty()) {
290 useLocale = useLocale.replace( '-', '_');
291 of.writeRefFunction("getLocaleItem_", useLocale);
292 return;
293 }
294 OUString str = getAttr().getValueByName("unoid");
295 of.writeAsciiString("\n\n");
296 of.writeParameter("LC_CTYPE_Unoid", str);
297
298 aDateSep =
299 writeParameterCheckLen( of, "DateSeparator", "dateSeparator", 1, 1);
300 OUString aThoSep =
301 writeParameterCheckLen( of, "ThousandSeparator", "thousandSeparator", 1, 1);
302 aDecSep =
303 writeParameterCheckLen( of, "DecimalSeparator", "decimalSeparator", 1, 1);
304 OUString aDecSepAlt =
305 writeParameterCheckLen( of, "DecimalSeparatorAlternative", "decimalSeparatorAlternative", -1, 1);
306 OUString aTimeSep =
307 writeParameterCheckLen( of, "TimeSeparator", "timeSeparator", 1, 1);
308 OUString aTime100Sep =
309 writeParameterCheckLen( of, "Time100SecSeparator", "time100SecSeparator", 1, 1);
310 OUString aListSep =
311 writeParameterCheckLen( of, "ListSeparator", "listSeparator", 1, 1);
312
313 OUString aLDS;
314
315 sepNode = findNode("LongDateDayOfWeekSeparator");
316 aLDS = sepNode->getValue();
317 of.writeParameter("LongDateDayOfWeekSeparator", aLDS);
318 if (aLDS == ",")
319 fprintf( stderr, "Warning: %s\n",
320 "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\".");
321
322 sepNode = findNode("LongDateDaySeparator");
323 aLDS = sepNode->getValue();
324 of.writeParameter("LongDateDaySeparator", aLDS);
325 if (aLDS == "," || aLDS == ".")
326 fprintf( stderr, "Warning: %s\n",
327 "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\".");
328
329 sepNode = findNode("LongDateMonthSeparator");
330 aLDS = sepNode->getValue();
331 of.writeParameter("LongDateMonthSeparator", aLDS);
332 if (aLDS.isEmpty())
333 fprintf( stderr, "Warning: %s\n",
334 "LongDateMonthSeparator is empty. Usually this is not the case and may lead to concatenated display names like \"Wednesday, May9, 2007\".");
335
336 sepNode = findNode("LongDateYearSeparator");
337 aLDS = sepNode->getValue();
338 of.writeParameter("LongDateYearSeparator", aLDS);
339 if (aLDS.isEmpty())
340 fprintf( stderr, "Warning: %s\n",
341 "LongDateYearSeparator is empty. Usually this is not the case and may lead to concatenated display names like \"Wednesday, 2007May 9\".");
342
343 int nSavErr = nError;
344 int nWarn = 0;
345 if (aDateSep == aTimeSep)
346 incError( "DateSeparator equals TimeSeparator.");
347 if (aDecSep == aThoSep)
348 incError( "DecimalSeparator equals ThousandSeparator.");
349 if (aDecSepAlt == aThoSep)
350 incError( "DecimalSeparatorAlternative equals ThousandSeparator.");
351 if (aDecSepAlt == aDecSep)
352 incError( "DecimalSeparatorAlternative equals DecimalSeparator, it must not be specified then.");
353 if ( aThoSep == " " )
354 incError( "ThousandSeparator is an ' ' ordinary space, this should be a non-breaking space U+00A0 instead.");
355 if (aListSep == aDecSep)
356 fprintf( stderr, "Warning: %s\n",
357 "ListSeparator equals DecimalSeparator.");
358 if (aListSep == aThoSep)
359 fprintf( stderr, "Warning: %s\n",
360 "ListSeparator equals ThousandSeparator.");
361 if (aListSep.getLength() != 1 || aListSep[0] != ';')
362 {
363 incError( "ListSeparator not ';' semicolon. Strongly recommended. Currently required.");
364 ++nSavErr; // format codes not affected
365 }
366 if (aTimeSep == aTime100Sep)
367 {
368 ++nWarn;
369 fprintf( stderr, "Warning: %s\n",
370 "Time100SecSeparator equals TimeSeparator, this is probably an error.");
371 }
372 if (aDecSep != aTime100Sep)
373 {
374 ++nWarn;
375 fprintf( stderr, "Warning: %s\n",
376 "Time100SecSeparator is different from DecimalSeparator, this may be correct or not. Intended?");
377 }
378 if (nSavErr != nError || nWarn)
379 fprintf( stderr, "Warning: %s\n",
380 "Don't forget to adapt corresponding FormatCode elements when changing separators.");
381
382 OUString aQuoteStart =
383 writeParameterCheckLen( of, "QuotationStart", "quotationStart", 1, 1);
384 OUString aQuoteEnd =
385 writeParameterCheckLen( of, "QuotationEnd", "quotationEnd", 1, 1);
386 OUString aDoubleQuoteStart =
387 writeParameterCheckLen( of, "DoubleQuotationStart", "doubleQuotationStart", 1, 1);
388 OUString aDoubleQuoteEnd =
389 writeParameterCheckLen( of, "DoubleQuotationEnd", "doubleQuotationEnd", 1, 1);
390
391 if (aQuoteStart.toChar() <= 127 && aQuoteEnd.toChar() > 127)
392 fprintf( stderr, "Warning: %s\n",
393 "QuotationStart is an ASCII character but QuotationEnd is not.");
394 if (aQuoteEnd.toChar() <= 127 && aQuoteStart.toChar() > 127)
395 fprintf( stderr, "Warning: %s\n",
396 "QuotationEnd is an ASCII character but QuotationStart is not.");
397 if (aDoubleQuoteStart.toChar() <= 127 && aDoubleQuoteEnd.toChar() > 127)
398 fprintf( stderr, "Warning: %s\n",
399 "DoubleQuotationStart is an ASCII character but DoubleQuotationEnd is not.");
400 if (aDoubleQuoteEnd.toChar() <= 127 && aDoubleQuoteStart.toChar() > 127)
401 fprintf( stderr, "Warning: %s\n",
402 "DoubleQuotationEnd is an ASCII character but DoubleQuotationStart is not.");
403 if (aQuoteStart.toChar() <= 127 && aQuoteEnd.toChar() <= 127)
404 fprintf( stderr, "Warning: %s\n",
405 "QuotationStart and QuotationEnd are both ASCII characters. Not necessarily an issue, but unusual.");
406 if (aDoubleQuoteStart.toChar() <= 127 && aDoubleQuoteEnd.toChar() <= 127)
407 fprintf( stderr, "Warning: %s\n",
408 "DoubleQuotationStart and DoubleQuotationEnd are both ASCII characters. Not necessarily an issue, but unusual.");
409 if (aQuoteStart == aQuoteEnd)
410 fprintf( stderr, "Warning: %s\n",
411 "QuotationStart equals QuotationEnd. Not necessarily an issue, but unusual.");
412 if (aDoubleQuoteStart == aDoubleQuoteEnd)
413 fprintf( stderr, "Warning: %s\n",
414 "DoubleQuotationStart equals DoubleQuotationEnd. Not necessarily an issue, but unusual.");
415 /* TODO: should equalness of single and double quotes be an error? Would
416 * need to adapt quite some locales' data. */
417 if (aQuoteStart == aDoubleQuoteStart)
418 fprintf( stderr, "Warning: %s\n",
419 "QuotationStart equals DoubleQuotationStart. Not necessarily an issue, but unusual.");
420 if (aQuoteEnd == aDoubleQuoteEnd)
421 fprintf( stderr, "Warning: %s\n",
422 "QuotationEnd equals DoubleQuotationEnd. Not necessarily an issue, but unusual.");
423 // Known good values, exclude ASCII single (U+0027, ') and double (U+0022, ") quotes.
424 switch (int ic = aQuoteStart.toChar())
425 {
426 case 0x2018: // LEFT SINGLE QUOTATION MARK
427 case 0x201a: // SINGLE LOW-9 QUOTATION MARK
428 case 0x201b: // SINGLE HIGH-REVERSED-9 QUOTATION MARK
429 case 0x2039: // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
430 case 0x203a: // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
431 case 0x300c: // LEFT CORNER BRACKET (Chinese)
432 ;
433 break;
434 default:
435 fprintf( stderr, "Warning: %s U+%04X %s\n",
436 "QuotationStart may be wrong:", ic, OSTR( aQuoteStart));
437 }
438 switch (int ic = aQuoteEnd.toChar())
439 {
440 case 0x2019: // RIGHT SINGLE QUOTATION MARK
441 case 0x201a: // SINGLE LOW-9 QUOTATION MARK
442 case 0x201b: // SINGLE HIGH-REVERSED-9 QUOTATION MARK
443 case 0x2039: // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
444 case 0x203a: // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
445 case 0x300d: // RIGHT CORNER BRACKET (Chinese)
446 ;
447 break;
448 default:
449 fprintf( stderr, "Warning: %s U+%04X %s\n",
450 "QuotationEnd may be wrong:", ic, OSTR( aQuoteEnd));
451 }
452 switch (int ic = aDoubleQuoteStart.toChar())
453 {
454 case 0x00ab: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
455 case 0x00bb: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
456 case 0x201c: // LEFT DOUBLE QUOTATION MARK
457 case 0x201e: // DOUBLE LOW-9 QUOTATION MARK
458 case 0x201f: // DOUBLE HIGH-REVERSED-9 QUOTATION MARK
459 case 0x300e: // LEFT WHITE CORNER BRACKET (Chinese)
460 ;
461 break;
462 default:
463 fprintf( stderr, "Warning: %s U+%04X %s\n",
464 "DoubleQuotationStart may be wrong:", ic, OSTR( aDoubleQuoteStart));
465 }
466 switch (int ic = aDoubleQuoteEnd.toChar())
467 {
468 case 0x00ab: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
469 case 0x00bb: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
470 case 0x201d: // RIGHT DOUBLE QUOTATION MARK
471 case 0x201e: // DOUBLE LOW-9 QUOTATION MARK
472 case 0x201f: // DOUBLE HIGH-REVERSED-9 QUOTATION MARK
473 case 0x300f: // RIGHT WHITE CORNER BRACKET (Chinese)
474 ;
475 break;
476 default:
477 fprintf( stderr, "Warning: %s U+%04X %s\n",
478 "DoubleQuotationEnd may be wrong:", ic, OSTR( aDoubleQuoteEnd));
479 }
480
481 writeParameterCheckLen( of, "TimeAM", "timeAM", 1, -1);
482 writeParameterCheckLen( of, "TimePM", "timePM", 1, -1);
483 sepNode = findNode("MeasurementSystem");
484 of.writeParameter("measurementSystem", sepNode->getValue());
485
486 of.writeAsciiString("\nstatic const sal_Unicode* LCType[] = {\n");
487 of.writeAsciiString("\tLC_CTYPE_Unoid,\n");
488 of.writeAsciiString("\tdateSeparator,\n");
489 of.writeAsciiString("\tthousandSeparator,\n");
490 of.writeAsciiString("\tdecimalSeparator,\n");
491 of.writeAsciiString("\ttimeSeparator,\n");
492 of.writeAsciiString("\ttime100SecSeparator,\n");
493 of.writeAsciiString("\tlistSeparator,\n");
494 of.writeAsciiString("\tquotationStart,\n");
495 of.writeAsciiString("\tquotationEnd,\n");
496 of.writeAsciiString("\tdoubleQuotationStart,\n");
497 of.writeAsciiString("\tdoubleQuotationEnd,\n");
498 of.writeAsciiString("\ttimeAM,\n");
499 of.writeAsciiString("\ttimePM,\n");
500 of.writeAsciiString("\tmeasurementSystem,\n");
501 of.writeAsciiString("\tLongDateDayOfWeekSeparator,\n");
502 of.writeAsciiString("\tLongDateDaySeparator,\n");
503 of.writeAsciiString("\tLongDateMonthSeparator,\n");
504 of.writeAsciiString("\tLongDateYearSeparator,\n");
505 of.writeAsciiString("\tdecimalSeparatorAlternative\n");
506 of.writeAsciiString("};\n\n");
507 of.writeFunction("getLocaleItem_", "SAL_N_ELEMENTS(LCType)", "LCType");
508}
509
510
511static OUString sTheCurrencyReplaceTo;
513static OUString sTheDateEditFormat;
514
515sal_Int16 LCFormatNode::mnSection = 0;
516sal_Int16 LCFormatNode::mnFormats = 0;
517
519{
520 if (mnSection >= 2)
521 incError("more than 2 LC_FORMAT sections");
522
523 ::std::vector< OUString > theDateAcceptancePatterns;
524
525 OUString useLocale(getAttr().getValueByName("ref"));
526
527 OUString str;
528 OUString strFrom( getAttr().getValueByName("replaceFrom"));
529 if (useLocale.isEmpty())
530 {
531 of.writeParameter("replaceFrom", strFrom, mnSection);
532 }
533 str = getAttr().getValueByName("replaceTo");
534 if (!strFrom.isEmpty() && str.isEmpty())
535 incErrorStr("replaceFrom=\"%s\" replaceTo=\"\" is empty replacement.\n", strFrom);
536 // Locale data generator inserts FFFF for LangID, we need to adapt that.
537 if (str.endsWithIgnoreAsciiCase( "-FFFF]"))
538 incErrorStr("replaceTo=\"%s\" needs FFFF to be adapted to the real LangID value.\n", str);
539 of.writeParameter("replaceTo", str, mnSection);
540 // Remember the replaceTo value for "[CURRENCY]" to check format codes.
541 if ( strFrom == "[CURRENCY]" )
543 // Remember the currency symbol if present.
544 if (str.startsWith( "[$" ))
545 {
546 sal_Int32 nHyphen = str.indexOf( '-');
547 if (nHyphen >= 3)
548 {
549 sTheCompatibleCurrency = str.copy( 2, nHyphen - 2);
550 }
551 }
552
553 if (!useLocale.isEmpty())
554 {
555 if (!strFrom.isEmpty() && strFrom != "[CURRENCY]") //???
556 {
558 "Error: non-empty replaceFrom=\"%s\" with non-empty ref=\"%s\".",
559 strFrom, useLocale);
560 }
561 useLocale = useLocale.replace( '-', '_');
562 switch (mnSection)
563 {
564 case 0:
565 of.writeRefFunction("getAllFormats0_", useLocale, "replaceTo0");
566 of.writeRefFunction("getDateAcceptancePatterns_", useLocale);
567 break;
568 case 1:
569 of.writeRefFunction("getAllFormats1_", useLocale, "replaceTo1");
570 break;
571 }
572 ++mnSection;
573 return;
574 }
575
576 sal_Int16 formatCount = mnFormats;
577 NameSet aMsgIdSet;
578 ValueSet aFormatIndexSet;
579 NameSet aDefaultsSet;
580 bool bCtypeIsRef = false;
581 bool bHaveEngineering = false;
582 bool bShowNextFreeFormatIndex = false;
583
584 for (sal_Int32 i = 0; i< getNumberOfChildren() ; i++, formatCount++)
585 {
586 LocaleNode * currNode = getChildAt (i);
587 if ( currNode->getName() == "DateAcceptancePattern" )
588 {
589 if (mnSection > 0)
590 incError( "DateAcceptancePattern only handled in LC_FORMAT, not LC_FORMAT_1");
591 else
592 theDateAcceptancePatterns.push_back( currNode->getValue());
593 --formatCount;
594 continue; // for
595 }
596 if ( currNode->getName() != "FormatElement" )
597 {
598 incErrorStr( "Error: Undefined element '%s' in LC_FORMAT\n", currNode->getName());
599 --formatCount;
600 continue; // for
601 }
602
603 OUString aUsage;
604 OUString aType;
605 OUString aFormatIndex;
606 // currNode -> print();
607 const Attr &currNodeAttr = currNode->getAttr();
608 //printf ("getLen() = %d\n", currNode->getAttr().getLength());
609
610 str = currNodeAttr.getValueByName("msgid");
611 if (!aMsgIdSet.insert( str).second)
612 incErrorStr( "Error: Duplicated msgid=\"%s\" in FormatElement.\n", str);
613 of.writeParameter("FormatKey", str, formatCount);
614
615 str = currNodeAttr.getValueByName("default");
616 bool bDefault = str == "true";
617 of.writeDefaultParameter("FormatElement", str, formatCount);
618
619 aType = currNodeAttr.getValueByName("type");
620 of.writeParameter("FormatType", aType, formatCount);
621
622 aUsage = currNodeAttr.getValueByName("usage");
623 of.writeParameter("FormatUsage", aUsage, formatCount);
624
625 aFormatIndex = currNodeAttr.getValueByName("formatindex");
626 sal_Int16 formatindex = static_cast<sal_Int16>(aFormatIndex.toInt32());
627 // Ensure the new reserved range is not used anymore, free usage start
628 // was up'ed from 50 to 60 (and more later).
630 {
631 incErrorInt( "Error: Reserved formatindex=\"%d\" in FormatElement.\n", formatindex);
632 bShowNextFreeFormatIndex = true;
633 }
634 if (!aFormatIndexSet.insert( formatindex).second)
635 {
636 incErrorInt( "Error: Duplicated formatindex=\"%d\" in FormatElement.\n", formatindex);
637 bShowNextFreeFormatIndex = true;
638 }
639 of.writeIntParameter("Formatindex", formatCount, formatindex);
640
641 // Ensure only one default per usage and type.
642 if (bDefault)
643 {
644 OUString aKey( aUsage + "," + aType);
645 if (!aDefaultsSet.insert( aKey).second)
646 {
647 OUString aStr = "Duplicated default for usage=\"" + aUsage + "\" type=\"" + aType + "\": formatindex=\"" + aFormatIndex + "\".";
648 incError( aStr);
649 }
650 }
651
652 const LocaleNode * n = currNode -> findNode("FormatCode");
653 if (n)
654 {
655 of.writeParameter("FormatCode", n->getValue(), formatCount);
656 // Check separator usage for some FormatCode elements.
657 const LocaleNode* pCtype = nullptr;
658 switch (formatindex)
659 {
660 case cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY :
661 sTheDateEditFormat = n->getValue();
662 break;
663 case cssi::NumberFormatIndex::NUMBER_1000DEC2 : // #,##0.00
664 case cssi::NumberFormatIndex::TIME_MMSS00 : // MM:SS.00
665 case cssi::NumberFormatIndex::TIME_HH_MMSS00 : // [HH]:MM:SS.00
666 {
667 const LocaleNode* pRoot = getRoot();
668 if (!pRoot)
669 incError( "No root for FormatCode.");
670 else
671 {
672 pCtype = pRoot->findNode( "LC_CTYPE");
673 if (!pCtype)
674 incError( "No LC_CTYPE found for FormatCode.");
675 else
676 {
677 OUString aRef( pCtype->getAttr().getValueByName("ref"));
678 if (!aRef.isEmpty())
679 {
680 aRef = aRef.replace( '-', '_');
681 if (!bCtypeIsRef)
682 fprintf( stderr,
683 "Warning: Can't check separators used in FormatCode due to LC_CTYPE ref=\"%s\".\n"
684 "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",
685 OSTR( aRef));
686 bCtypeIsRef = true;
687 pCtype = nullptr;
688 }
689 }
690 }
691 }
692 break;
693 case cssi::NumberFormatIndex::CURRENCY_1000DEC2 :
694 // Remember the currency symbol if present.
695 {
696 if (sTheCompatibleCurrency.isEmpty())
697 {
698 sal_Int32 nStart = n->getValue().indexOf("[$");
699 if (nStart >= 0)
700 {
701 const OUString& aCode( n->getValue());
702 sal_Int32 nHyphen = aCode.indexOf( '-', nStart);
703 if (nHyphen >= nStart + 3)
704 sTheCompatibleCurrency = aCode.copy( nStart + 2, nHyphen - nStart - 2);
705 }
706 }
707 }
708 [[fallthrough]];
709 case cssi::NumberFormatIndex::CURRENCY_1000INT :
710 case cssi::NumberFormatIndex::CURRENCY_1000INT_RED :
711 case cssi::NumberFormatIndex::CURRENCY_1000DEC2_RED :
712 case cssi::NumberFormatIndex::CURRENCY_1000DEC2_CCC :
713 case cssi::NumberFormatIndex::CURRENCY_1000DEC2_DASHED :
714 // Currency formats should be something like [C]###0;-[C]###0
715 // and not parenthesized [C]###0;([C]###0) if not en_US.
716 if (strcmp( of.getLocale(), "en_US") != 0)
717 {
718 const OUString& aCode( n->getValue());
719 if (aCode.indexOf( "0)" ) > 0 || aCode.indexOf( "-)" ) > 0 ||
720 aCode.indexOf( " )" ) > 0 || aCode.indexOf( "])" ) > 0)
721 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);
722 }
723 // Check if we have replaceTo for "[CURRENCY]" placeholder.
724 if (sTheCurrencyReplaceTo.isEmpty())
725 {
726 const OUString& aCode( n->getValue());
727 if (aCode.indexOf( "[CURRENCY]" ) >= 0)
728 incErrorInt( "Error: [CURRENCY] replaceTo not found for formatindex=\"%d\".\n", formatindex);
729 }
730 break;
731 default:
732 if (aUsage == "SCIENTIFIC_NUMBER")
733 {
734 // Check for presence of ##0.00E+00
735 const OUString& aCode( n->getValue());
736 // Simple check without decimal separator (assumed to
737 // be one UTF-16 character). May be prefixed with
738 // [NatNum1] or other tags.
739 sal_Int32 nInt = aCode.indexOf("##0");
740 sal_Int32 nDec = (nInt < 0 ? -1 : aCode.indexOf("00E+00", nInt));
741 if (nInt >= 0 && nDec == nInt+4)
742 bHaveEngineering = true;
743 }
744 break;
745 }
746 if (pCtype)
747 {
748 int nSavErr = nError;
749 const OUString& aCode( n->getValue());
750 if (formatindex == cssi::NumberFormatIndex::NUMBER_1000DEC2)
751 {
752 sal_Int32 nDec = -1;
753 sal_Int32 nGrp = -1;
754 const LocaleNode* pSep = pCtype->findNode( "DecimalSeparator");
755 if (!pSep)
756 incError( "No DecimalSeparator found for FormatCode.");
757 else
758 {
759 nDec = aCode.indexOf( pSep->getValue());
760 if (nDec < 0)
761 incErrorInt( "Error: DecimalSeparator not present in FormatCode formatindex=\"%d\".\n",
762 formatindex);
763 }
764 pSep = pCtype->findNode( "ThousandSeparator");
765 if (!pSep)
766 incError( "No ThousandSeparator found for FormatCode.");
767 else
768 {
769 nGrp = aCode.indexOf( pSep->getValue());
770 if (nGrp < 0)
771 incErrorInt( "Error: ThousandSeparator not present in FormatCode formatindex=\"%d\".\n",
772 formatindex);
773 }
774 if (nDec >= 0 && nGrp >= 0 && nDec <= nGrp)
775 incErrorInt( "Error: Ordering of ThousandSeparator and DecimalSeparator not correct in formatindex=\"%d\".\n",
776 formatindex);
777 }
778 if (formatindex == cssi::NumberFormatIndex::TIME_MMSS00 ||
779 formatindex == cssi::NumberFormatIndex::TIME_HH_MMSS00)
780 {
781 sal_Int32 nTime = -1;
782 sal_Int32 n100s = -1;
783 const LocaleNode* pSep = pCtype->findNode( "TimeSeparator");
784 if (!pSep)
785 incError( "No TimeSeparator found for FormatCode.");
786 else
787 {
788 nTime = aCode.indexOf( pSep->getValue());
789 if (nTime < 0)
790 incErrorInt( "Error: TimeSeparator not present in FormatCode formatindex=\"%d\".\n",
791 formatindex);
792 }
793 pSep = pCtype->findNode( "Time100SecSeparator");
794 if (!pSep)
795 incError( "No Time100SecSeparator found for FormatCode.");
796 else
797 {
798 n100s = aCode.indexOf( pSep->getValue());
799 if (n100s < 0)
800 incErrorInt( "Error: Time100SecSeparator not present in FormatCode formatindex=\"%d\".\n",
801 formatindex);
802 n100s = aCode.indexOf( OUStringConcatenation(pSep->getValue() + "00"));
803 if (n100s < 0)
804 incErrorInt( "Error: Time100SecSeparator+00 not present in FormatCode formatindex=\"%d\".\n",
805 formatindex);
806 }
807 if (n100s >= 0 && nTime >= 0 && n100s <= nTime)
808 incErrorInt( "Error: Ordering of Time100SecSeparator and TimeSeparator not correct in formatindex=\"%d\".\n",
809 formatindex);
810 }
811 if (nSavErr != nError)
812 fprintf( stderr,
813 "Warning: formatindex=\"%d\",\"%d\",\"%d\" are the only FormatCode elements checked for separator usage, there may be others that have errors.\n",
814 int(cssi::NumberFormatIndex::NUMBER_1000DEC2),
815 int(cssi::NumberFormatIndex::TIME_MMSS00),
816 int(cssi::NumberFormatIndex::TIME_HH_MMSS00));
817
818 }
819 }
820 else
821 incError( "No FormatCode in FormatElement.");
822 n = currNode -> findNode("DefaultName");
823 if (n)
824 of.writeParameter("FormatDefaultName", n->getValue(), formatCount);
825 else
826 of.writeParameter("FormatDefaultName", std::u16string_view(), formatCount);
827
828 }
829
830 if (bShowNextFreeFormatIndex)
831 {
832 sal_Int16 nNext = i18npool::nFirstFreeFormatIndex;
833 auto it = aFormatIndexSet.find( nNext);
834 if (it != aFormatIndexSet.end())
835 {
836 // nFirstFreeFormatIndex already used, find next free including gaps.
837 do
838 {
839 ++nNext;
840 }
841 while (++it != aFormatIndexSet.end() && *it == nNext);
842 }
843 fprintf( stderr, "Hint: Next free formatindex is %d.\n", static_cast<int>(nNext));
844 }
845
846 // Check presence of all required format codes only in first section
847 // LC_FORMAT, not in optional LC_FORMAT_1
848 if (mnSection == 0)
849 {
850 // At least one abbreviated date acceptance pattern must be present.
851 if (theDateAcceptancePatterns.empty())
852 incError( "No DateAcceptancePattern present.\n");
853 else
854 {
855 bool bHaveAbbr = false;
856 for (auto const& elem : theDateAcceptancePatterns)
857 {
858 if (elem.indexOf('D') > -1 && elem.indexOf('M') > -1 && elem.indexOf('Y') <= -1)
859 {
860 bHaveAbbr = true;
861 break;
862 }
863 }
864 if (!bHaveAbbr)
865 incError( "No abbreviated DateAcceptancePattern present. For example M/D or D.M.\n");
866 }
867
868 // 0..9 MUST be present, 10,11 MUST NOT be present, 12..47 MUST be
869 // present, 48,49 MUST NOT be present, 50 MUST be present.
870 ValueSet::const_iterator aIter( aFormatIndexSet.begin());
871 for (sal_Int16 nNext = cssi::NumberFormatIndex::NUMBER_START;
873 {
874 sal_Int16 nHere = ::std::min( (aIter != aFormatIndexSet.end() ? *aIter :
877 if (aIter != aFormatIndexSet.end()) ++aIter;
878 for ( ; nNext < nHere; ++nNext)
879 {
880 switch (nNext)
881 {
882 case cssi::NumberFormatIndex::FRACTION_1 :
883 case cssi::NumberFormatIndex::FRACTION_2 :
884 case cssi::NumberFormatIndex::BOOLEAN :
885 case cssi::NumberFormatIndex::TEXT :
886 // generated internally
887 break;
888 default:
889 incErrorInt( "Error: FormatElement formatindex=\"%d\" not present.\n", nNext);
890 }
891 }
892 switch (nHere)
893 {
894 case cssi::NumberFormatIndex::FRACTION_1 :
895 incErrorInt( "Error: FormatElement formatindex=\"%d\" reserved for internal ``# ?/?''.\n", nNext);
896 break;
897 case cssi::NumberFormatIndex::FRACTION_2 :
898 incErrorInt( "Error: FormatElement formatindex=\"%d\" reserved for internal ``# ?\?/?\?''.\n", nNext);
899 break;
900 case cssi::NumberFormatIndex::BOOLEAN :
901 incErrorInt( "Error: FormatElement formatindex=\"%d\" reserved for internal ``BOOLEAN''.\n", nNext);
902 break;
903 case cssi::NumberFormatIndex::TEXT :
904 incErrorInt( "Error: FormatElement formatindex=\"%d\" reserved for internal ``@'' (TEXT).\n", nNext);
905 break;
906 default:
907 ; // nothing
908 }
909 }
910
911 if (!bHaveEngineering)
912 incError("Engineering notation format not present, e.g. ##0.00E+00 or ##0,00E+00 for usage=\"SCIENTIFIC_NUMBER\"\n");
913 }
914
915 of.writeAsciiString("\nstatic const sal_Int16 ");
916 of.writeAsciiString("FormatElementsCount");
918 of.writeAsciiString(" = ");
919 of.writeInt( formatCount - mnFormats);
920 of.writeAsciiString(";\n");
921 of.writeAsciiString("static const sal_Unicode* ");
922 of.writeAsciiString("FormatElementsArray");
924 of.writeAsciiString("[] = {\n");
925 for(sal_Int16 i = mnFormats; i < formatCount; i++) {
926
927 of.writeAsciiString("\t");
928 of.writeAsciiString("FormatCode");
929 of.writeInt(i);
930 of.writeAsciiString(",\n");
931
932 of.writeAsciiString("\t");
933 of.writeAsciiString("FormatDefaultName");
934 of.writeInt(i);
935 of.writeAsciiString(",\n");
936
937 of.writeAsciiString("\t");
938 of.writeAsciiString("FormatKey");
939 of.writeInt(i);
940 of.writeAsciiString(",\n");
941
942 of.writeAsciiString("\t");
943 of.writeAsciiString("FormatType");
944 of.writeInt(i);
945 of.writeAsciiString(",\n");
946
947 of.writeAsciiString("\t");
948 of.writeAsciiString("FormatUsage");
949 of.writeInt(i);
950 of.writeAsciiString(",\n");
951
952 of.writeAsciiString("\t");
953 of.writeAsciiString("Formatindex");
954 of.writeInt(i);
955 of.writeAsciiString(",\n");
956
957
958 of.writeAsciiString("\tdefaultFormatElement");
959 of.writeInt(i);
960 of.writeAsciiString(",\n");
961 }
962 of.writeAsciiString("};\n\n");
963
964 switch (mnSection)
965 {
966 case 0:
967 of.writeFunction("getAllFormats0_", "FormatElementsCount0", "FormatElementsArray0", "replaceFrom0", "replaceTo0");
968 break;
969 case 1:
970 of.writeFunction("getAllFormats1_", "FormatElementsCount1", "FormatElementsArray1", "replaceFrom1", "replaceTo1");
971 break;
972 }
973
974 mnFormats = mnFormats + formatCount;
975
976 if (mnSection == 0)
977 {
978 // Extract and add date acceptance pattern for full date, so we provide
979 // at least one valid pattern, even if the number parser doesn't need
980 // that one.
981 /* XXX NOTE: only simple [...] modifier and "..." quotes detected and
982 * ignored, not nested, no fancy stuff. */
983 // aDateSep can be empty if LC_CTYPE was a ref=..., determine from
984 // FormatCode then.
985 sal_uInt32 cDateSep = (aDateSep.isEmpty()
986 ? 0 : aDateSep.iterateCodePoints( &o3tl::temporary(sal_Int32(0))));
987 sal_uInt32 cDateSep2 = cDateSep;
988 sal_Int32 nIndex = 0;
989 OUStringBuffer aPatternBuf(5);
990 OUStringBuffer aPatternBuf2(5);
991 sal_uInt8 nDetected = 0; // bits Y,M,D
992 bool bInModifier = false;
993 bool bQuoted = false;
994 while (nIndex < sTheDateEditFormat.getLength() && nDetected < 7)
995 {
996 sal_uInt32 cChar = sTheDateEditFormat.iterateCodePoints( &nIndex);
997 if (bInModifier)
998 {
999 if (cChar == ']')
1000 bInModifier = false;
1001 continue; // while
1002 }
1003 if (bQuoted)
1004 {
1005 if (cChar == '"')
1006 bQuoted = false;
1007 continue; // while
1008 }
1009 switch (cChar)
1010 {
1011 case 'Y':
1012 case 'y':
1013 if (!(nDetected & 4))
1014 {
1015 aPatternBuf.append( 'Y');
1016 if (!aPatternBuf2.isEmpty())
1017 aPatternBuf2.append( 'Y');
1018 nDetected |= 4;
1019 }
1020 break;
1021 case 'M':
1022 case 'm':
1023 if (!(nDetected & 2))
1024 {
1025 aPatternBuf.append( 'M');
1026 if (!aPatternBuf2.isEmpty())
1027 aPatternBuf2.append( 'M');
1028 nDetected |= 2;
1029 }
1030 break;
1031 case 'D':
1032 case 'd':
1033 if (!(nDetected & 1))
1034 {
1035 aPatternBuf.append( 'D');
1036 if (!aPatternBuf2.isEmpty())
1037 aPatternBuf2.append( 'D');
1038 nDetected |= 1;
1039 }
1040 break;
1041 case '[':
1042 bInModifier = true;
1043 break;
1044 case '"':
1045 bQuoted = true;
1046 break;
1047 case '\\':
1048 cChar = sTheDateEditFormat.iterateCodePoints( &nIndex);
1049 goto handleDefault;
1050 case '-':
1051 case '.':
1052 case '/':
1053 // There are locales that use an ISO 8601 edit format
1054 // regardless of what the date separator or other formats
1055 // say, for example hu-HU. Generalize this for all cases
1056 // where the used separator differs and is one of the known
1057 // separators and generate a second pattern with the
1058 // format's separator at the current position.
1059 cDateSep2 = cChar;
1060 [[fallthrough]];
1061 default:
1062 handleDefault:
1063 if (!cDateSep)
1064 cDateSep = cChar;
1065 if (!cDateSep2)
1066 cDateSep2 = cChar;
1067 if (cDateSep != cDateSep2 && aPatternBuf2.isEmpty())
1068 aPatternBuf2 = aPatternBuf;
1069 if (cChar == cDateSep || cChar == cDateSep2)
1070 aPatternBuf.append( OUString( &cDateSep, 1)); // always the defined separator
1071 if (cChar == cDateSep2 && !aPatternBuf2.isEmpty())
1072 aPatternBuf2.append( OUString( &cDateSep2, 1)); // always the format's separator
1073 break;
1074 // The localized legacy:
1075 case 'A':
1076 if (((nDetected & 7) == 3) || ((nDetected & 7) == 0))
1077 {
1078 // es DD/MM/AAAA
1079 // fr JJ.MM.AAAA
1080 // it GG/MM/AAAA
1081 // fr_CA AAAA-MM-JJ
1082 aPatternBuf.append( 'Y');
1083 if (!aPatternBuf2.isEmpty())
1084 aPatternBuf2.append( 'Y');
1085 nDetected |= 4;
1086 }
1087 break;
1088 case 'J':
1089 if (((nDetected & 7) == 0) || ((nDetected & 7) == 6))
1090 {
1091 // fr JJ.MM.AAAA
1092 // fr_CA AAAA-MM-JJ
1093 aPatternBuf.append( 'D');
1094 if (!aPatternBuf2.isEmpty())
1095 aPatternBuf2.append( 'D');
1096 nDetected |= 1;
1097 }
1098 else if ((nDetected & 7) == 3)
1099 {
1100 // nl DD-MM-JJJJ
1101 // de TT.MM.JJJJ
1102 aPatternBuf.append( 'Y');
1103 if (!aPatternBuf2.isEmpty())
1104 aPatternBuf2.append( 'Y');
1105 nDetected |= 4;
1106 }
1107 break;
1108 case 'T':
1109 if ((nDetected & 7) == 0)
1110 {
1111 // de TT.MM.JJJJ
1112 aPatternBuf.append( 'D');
1113 if (!aPatternBuf2.isEmpty())
1114 aPatternBuf2.append( 'D');
1115 nDetected |= 1;
1116 }
1117 break;
1118 case 'G':
1119 if ((nDetected & 7) == 0)
1120 {
1121 // it GG/MM/AAAA
1122 aPatternBuf.append( 'D');
1123 if (!aPatternBuf2.isEmpty())
1124 aPatternBuf2.append( 'D');
1125 nDetected |= 1;
1126 }
1127 break;
1128 case 'P':
1129 if ((nDetected & 7) == 0)
1130 {
1131 // fi PP.KK.VVVV
1132 aPatternBuf.append( 'D');
1133 if (!aPatternBuf2.isEmpty())
1134 aPatternBuf2.append( 'D');
1135 nDetected |= 1;
1136 }
1137 break;
1138 case 'K':
1139 if ((nDetected & 7) == 1)
1140 {
1141 // fi PP.KK.VVVV
1142 aPatternBuf.append( 'M');
1143 if (!aPatternBuf2.isEmpty())
1144 aPatternBuf2.append( 'M');
1145 nDetected |= 2;
1146 }
1147 break;
1148 case 'V':
1149 if ((nDetected & 7) == 3)
1150 {
1151 // fi PP.KK.VVVV
1152 aPatternBuf.append( 'Y');
1153 if (!aPatternBuf2.isEmpty())
1154 aPatternBuf2.append( 'Y');
1155 nDetected |= 4;
1156 }
1157 break;
1158 }
1159 }
1160 OUString aPattern( aPatternBuf.makeStringAndClear());
1161 if (((nDetected & 7) != 7) || aPattern.getLength() < 5)
1162 {
1163 incErrorStr( "Error: failed to extract full date acceptance pattern: %s\n", aPattern);
1164 fprintf( stderr, " with DateSeparator '%s' from FormatCode '%s' (formatindex=\"%d\")\n",
1165 OSTR( OUString(&cDateSep, 1)), OSTR( sTheDateEditFormat),
1166 int(cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY));
1167 }
1168 else
1169 {
1170 fprintf( stderr, "Generated date acceptance pattern: '%s' from '%s' (formatindex=\"%d\" and defined DateSeparator '%s')\n",
1171 OSTR( aPattern), OSTR( sTheDateEditFormat),
1172 int(cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY),
1173 OSTR( OUString(&cDateSep, 1)));
1174 // Insert at front so full date pattern is first in checks.
1175 theDateAcceptancePatterns.insert( theDateAcceptancePatterns.begin(), aPattern);
1176 }
1177 if (!aPatternBuf2.isEmpty())
1178 {
1179 OUString aPattern2( aPatternBuf2.makeStringAndClear());
1180 if (aPattern2.getLength() < 5)
1181 {
1182 incErrorStr( "Error: failed to extract 2nd date acceptance pattern: %s\n", aPattern2);
1183 fprintf( stderr, " with DateSeparator '%s' from FormatCode '%s' (formatindex=\"%d\")\n",
1184 OSTR( OUString(&cDateSep2, 1)), OSTR( sTheDateEditFormat),
1185 int(cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY));
1186 }
1187 else
1188 {
1189 fprintf( stderr, "Generated 2nd acceptance pattern: '%s' from '%s' (formatindex=\"%d\")\n",
1190 OSTR( aPattern2), OSTR( sTheDateEditFormat),
1191 int(cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY));
1192 theDateAcceptancePatterns.insert( theDateAcceptancePatterns.begin(), aPattern2);
1193 }
1194 }
1195
1196 // Rudimentary check if a pattern interferes with decimal number.
1197 // But only if not inherited in which case we don't have aDecSep here.
1198 if (!aDecSep.isEmpty())
1199 {
1200 sal_uInt32 cDecSep = aDecSep.iterateCodePoints( &o3tl::temporary(sal_Int32(0)));
1201 for (auto const& elem : theDateAcceptancePatterns)
1202 {
1203 if (elem.getLength() == (cDecSep <= 0xffff ? 3 : 4))
1204 {
1205 if (elem.iterateCodePoints( &o3tl::temporary(sal_Int32(1))) == cDecSep)
1206 {
1207 ++nError;
1208 fprintf( stderr, "Error: Date acceptance pattern '%s' matches decimal number '#%s#'\n",
1209 OSTR(elem), OSTR( aDecSep));
1210 }
1211 }
1212 }
1213 }
1214
1215 // Check for duplicates.
1216 for (std::vector<OUString>::const_iterator aIt = theDateAcceptancePatterns.begin();
1217 aIt != theDateAcceptancePatterns.end(); ++aIt)
1218 {
1219 for (std::vector<OUString>::iterator aComp = theDateAcceptancePatterns.begin();
1220 aComp != theDateAcceptancePatterns.end(); /*nop*/)
1221 {
1222 if (aIt != aComp && *aIt == *aComp)
1223 {
1224 incErrorStr( "Error: Duplicated DateAcceptancePattern: %s\n", *aComp);
1225 aComp = theDateAcceptancePatterns.erase( aComp);
1226 }
1227 else
1228 ++aComp;
1229 }
1230 }
1231
1232 sal_Int16 nbOfDateAcceptancePatterns = static_cast<sal_Int16>(theDateAcceptancePatterns.size());
1233
1234 for (sal_Int16 i = 0; i < nbOfDateAcceptancePatterns; ++i)
1235 {
1236 of.writeParameter("DateAcceptancePattern", theDateAcceptancePatterns[i], i);
1237 }
1238
1239 of.writeAsciiString("static const sal_Int16 DateAcceptancePatternsCount = ");
1240 of.writeInt( nbOfDateAcceptancePatterns);
1241 of.writeAsciiString(";\n");
1242
1243 of.writeAsciiString("static const sal_Unicode* DateAcceptancePatternsArray[] = {\n");
1244 for (sal_Int16 i = 0; i < nbOfDateAcceptancePatterns; ++i)
1245 {
1246 of.writeAsciiString("\t");
1247 of.writeAsciiString("DateAcceptancePattern");
1248 of.writeInt(i);
1249 of.writeAsciiString(",\n");
1250 }
1251 of.writeAsciiString("};\n\n");
1252
1253 of.writeFunction("getDateAcceptancePatterns_", "DateAcceptancePatternsCount", "DateAcceptancePatternsArray");
1254 }
1255
1256 ++mnSection;
1257}
1258
1260{
1261 OUString useLocale = getAttr().getValueByName("ref");
1262 if (!useLocale.isEmpty()) {
1263 useLocale = useLocale.replace( '-', '_');
1264 of.writeRefFunction("getCollatorImplementation_", useLocale);
1265 of.writeRefFunction("getCollationOptions_", useLocale);
1266 return;
1267 }
1268 sal_Int16 nbOfCollations = 0;
1269 sal_Int16 nbOfCollationOptions = 0;
1270
1271 for ( sal_Int32 j = 0; j < getNumberOfChildren(); j++ ) {
1272 LocaleNode * currNode = getChildAt (j);
1273 if( currNode->getName() == "Collator" )
1274 {
1275 OUString str;
1276 str = currNode->getAttr().getValueByName("unoid");
1277 of.writeParameter("CollatorID", str, j);
1278 str = currNode->getValue();
1279 of.writeParameter("CollatorRule", str, j);
1280 str = currNode -> getAttr().getValueByName("default");
1281 of.writeDefaultParameter("Collator", str, j);
1282 of.writeAsciiString("\n");
1283
1284 nbOfCollations++;
1285 }
1286 if( currNode->getName() == "CollationOptions" )
1287 {
1288 LocaleNode* pCollationOptions = currNode;
1289 nbOfCollationOptions = sal::static_int_cast<sal_Int16>( pCollationOptions->getNumberOfChildren() );
1290 for( sal_Int16 i=0; i<nbOfCollationOptions; i++ )
1291 {
1292 of.writeParameter("collationOption", pCollationOptions->getChildAt( i )->getValue(), i );
1293 }
1294
1295 of.writeAsciiString("static const sal_Int16 nbOfCollationOptions = ");
1296 of.writeInt( nbOfCollationOptions );
1297 of.writeAsciiString(";\n\n");
1298 }
1299 }
1300 of.writeAsciiString("static const sal_Int16 nbOfCollations = ");
1301 of.writeInt(nbOfCollations);
1302 of.writeAsciiString(";\n\n");
1303
1304 of.writeAsciiString("\nstatic const sal_Unicode* LCCollatorArray[] = {\n");
1305 for(sal_Int16 j = 0; j < nbOfCollations; j++) {
1306 of.writeAsciiString("\tCollatorID");
1307 of.writeInt(j);
1308 of.writeAsciiString(",\n");
1309
1310 of.writeAsciiString("\tdefaultCollator");
1311 of.writeInt(j);
1312 of.writeAsciiString(",\n");
1313
1314 of.writeAsciiString("\tCollatorRule");
1315 of.writeInt(j);
1316 of.writeAsciiString(",\n");
1317 }
1318 of.writeAsciiString("};\n\n");
1319
1320 of.writeAsciiString("static const sal_Unicode* collationOptions[] = {");
1321 for( sal_Int16 j=0; j<nbOfCollationOptions; j++ )
1322 {
1323 of.writeAsciiString( "collationOption" );
1324 of.writeInt( j );
1325 of.writeAsciiString( ", " );
1326 }
1327 of.writeAsciiString("NULL };\n");
1328 of.writeFunction("getCollatorImplementation_", "nbOfCollations", "LCCollatorArray");
1329 of.writeFunction("getCollationOptions_", "nbOfCollationOptions", "collationOptions");
1330}
1331
1333{
1334 OUString useLocale = getAttr().getValueByName("ref");
1335 if (!useLocale.isEmpty()) {
1336 useLocale = useLocale.replace( '-', '_');
1337 of.writeRefFunction("getSearchOptions_", useLocale);
1338 return;
1339 }
1340
1341 if( getNumberOfChildren() != 1 )
1342 {
1343 ++nError;
1344 fprintf(
1345 stderr, "Error: LC_SEARCH: more than 1 child: %" SAL_PRIdINT32 "\n",
1347 }
1348 sal_Int32 i;
1349 LocaleNode* pSearchOptions = getChildAt( 0 );
1350 sal_Int32 nSearchOptions = pSearchOptions->getNumberOfChildren();
1351 for( i=0; i<nSearchOptions; i++ )
1352 {
1353 of.writeParameter("searchOption", pSearchOptions->getChildAt( i )->getValue(), sal::static_int_cast<sal_Int16>(i) );
1354 }
1355
1356 of.writeAsciiString("static const sal_Int16 nbOfSearchOptions = ");
1357 of.writeInt( sal::static_int_cast<sal_Int16>( nSearchOptions ) );
1358 of.writeAsciiString(";\n\n");
1359
1360 of.writeAsciiString("static const sal_Unicode* searchOptions[] = {");
1361 for( i=0; i<nSearchOptions; i++ )
1362 {
1363 of.writeAsciiString( "searchOption" );
1364 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
1365 of.writeAsciiString( ", " );
1366 }
1367 of.writeAsciiString("NULL };\n");
1368 of.writeFunction("getSearchOptions_", "nbOfSearchOptions", "searchOptions");
1369}
1370
1372{
1373 OUString useLocale = getAttr().getValueByName("ref");
1374 if (!useLocale.isEmpty()) {
1375 useLocale = useLocale.replace( '-', '_');
1376 of.writeRefFunction("getIndexAlgorithm_", useLocale);
1377 of.writeRefFunction("getUnicodeScripts_", useLocale);
1378 of.writeRefFunction("getFollowPageWords_", useLocale);
1379 return;
1380 }
1381 sal_Int16 nbOfIndexs = 0;
1382 sal_Int16 nbOfUnicodeScripts = 0;
1383 sal_Int16 nbOfPageWords = 0;
1384 for (sal_Int32 i = 0; i< getNumberOfChildren();i++) {
1385 LocaleNode * currNode = getChildAt (i);
1386 if( currNode->getName() == "IndexKey" )
1387 {
1388 OUString str;
1389 str = currNode->getAttr().getValueByName("unoid");
1390 of.writeParameter("IndexID", str, nbOfIndexs);
1391 str = currNode->getAttr().getValueByName("module");
1392 of.writeParameter("IndexModule", str, nbOfIndexs);
1393 str = currNode->getValue();
1394 of.writeParameter("IndexKey", str, nbOfIndexs);
1395 str = currNode -> getAttr().getValueByName("default");
1396 of.writeDefaultParameter("Index", str, nbOfIndexs);
1397 str = currNode -> getAttr().getValueByName("phonetic");
1398 of.writeDefaultParameter("Phonetic", str, nbOfIndexs);
1399 of.writeAsciiString("\n");
1400
1401 nbOfIndexs++;
1402 }
1403 if( currNode->getName() == "UnicodeScript" )
1404 {
1405 of.writeParameter("unicodeScript", currNode->getValue(), nbOfUnicodeScripts );
1406 nbOfUnicodeScripts++;
1407
1408 }
1409 if( currNode->getName() == "FollowPageWord" )
1410 {
1411 of.writeParameter("followPageWord", currNode->getValue(), nbOfPageWords);
1412 nbOfPageWords++;
1413 }
1414 }
1415 of.writeAsciiString("static const sal_Int16 nbOfIndexs = ");
1416 of.writeInt(nbOfIndexs);
1417 of.writeAsciiString(";\n\n");
1418
1419 of.writeAsciiString("\nstatic const sal_Unicode* IndexArray[] = {\n");
1420 for(sal_Int16 i = 0; i < nbOfIndexs; i++) {
1421 of.writeAsciiString("\tIndexID");
1422 of.writeInt(i);
1423 of.writeAsciiString(",\n");
1424
1425 of.writeAsciiString("\tIndexModule");
1426 of.writeInt(i);
1427 of.writeAsciiString(",\n");
1428
1429 of.writeAsciiString("\tIndexKey");
1430 of.writeInt(i);
1431 of.writeAsciiString(",\n");
1432
1433 of.writeAsciiString("\tdefaultIndex");
1434 of.writeInt(i);
1435 of.writeAsciiString(",\n");
1436
1437 of.writeAsciiString("\tdefaultPhonetic");
1438 of.writeInt(i);
1439 of.writeAsciiString(",\n");
1440 }
1441 of.writeAsciiString("};\n\n");
1442
1443 of.writeAsciiString("static const sal_Int16 nbOfUnicodeScripts = ");
1444 of.writeInt( nbOfUnicodeScripts );
1445 of.writeAsciiString(";\n\n");
1446
1447 of.writeAsciiString("static const sal_Unicode* UnicodeScriptArray[] = {");
1448 for( sal_Int16 i=0; i<nbOfUnicodeScripts; i++ )
1449 {
1450 of.writeAsciiString( "unicodeScript" );
1451 of.writeInt( i );
1452 of.writeAsciiString( ", " );
1453 }
1454 of.writeAsciiString("NULL };\n\n");
1455
1456 of.writeAsciiString("static const sal_Int16 nbOfPageWords = ");
1457 of.writeInt(nbOfPageWords);
1458 of.writeAsciiString(";\n\n");
1459
1460 of.writeAsciiString("static const sal_Unicode* FollowPageWordArray[] = {\n");
1461 for(sal_Int16 i = 0; i < nbOfPageWords; i++) {
1462 of.writeAsciiString("\tfollowPageWord");
1463 of.writeInt(i);
1464 of.writeAsciiString(",\n");
1465 }
1466 of.writeAsciiString("\tNULL\n};\n\n");
1467
1468 of.writeFunction("getIndexAlgorithm_", "nbOfIndexs", "IndexArray");
1469 of.writeFunction("getUnicodeScripts_", "nbOfUnicodeScripts", "UnicodeScriptArray");
1470 of.writeFunction("getFollowPageWords_", "nbOfPageWords", "FollowPageWordArray");
1471}
1472
1473
1474static void lcl_writeAbbrFullNarrNames( const OFileWriter & of, const LocaleNode* currNode,
1475 const char* elementTag, sal_Int16 i, sal_Int16 j )
1476{
1477 OUString aAbbrName = currNode->getChildAt(1)->getValue();
1478 OUString aFullName = currNode->getChildAt(2)->getValue();
1479 OUString aNarrName;
1480 LocaleNode* p = (currNode->getNumberOfChildren() > 3 ? currNode->getChildAt(3) : nullptr);
1481 if ( p && p->getName() == "DefaultNarrowName" )
1482 aNarrName = p->getValue();
1483 else
1484 {
1485 sal_uInt32 nChar = aFullName.iterateCodePoints( &o3tl::temporary(sal_Int32(0)));
1486 aNarrName = OUString( &nChar, 1);
1487 }
1488 of.writeParameter( elementTag, "DefaultAbbrvName", aAbbrName, i, j);
1489 of.writeParameter( elementTag, "DefaultFullName", aFullName, i, j);
1490 of.writeParameter( elementTag, "DefaultNarrowName", aNarrName, i, j);
1491}
1492
1493static void lcl_writeTabTagString( const OFileWriter & of, const char* pTag, const char* pStr )
1494{
1495 of.writeAsciiString("\t");
1496 of.writeAsciiString( pTag);
1497 of.writeAsciiString( pStr);
1498}
1499
1501 const char* pTag, const char* pStr, sal_Int16 i, sal_Int16 j )
1502{
1503 lcl_writeTabTagString( of, pTag, pStr);
1504 of.writeInt(i); of.writeInt(j); of.writeAsciiString(",\n");
1505}
1506
1507static void lcl_writeAbbrFullNarrArrays( const OFileWriter & of, sal_Int16 nCount,
1508 const char* elementTag, sal_Int16 i, bool bNarrow )
1509{
1510 if (nCount == 0)
1511 {
1512 lcl_writeTabTagString( of, elementTag, "Ref");
1513 of.writeInt(i); of.writeAsciiString(",\n");
1514 lcl_writeTabTagString( of, elementTag, "RefName");
1515 of.writeInt(i); of.writeAsciiString(",\n");
1516 }
1517 else
1518 {
1519 for (sal_Int16 j = 0; j < nCount; j++)
1520 {
1521 lcl_writeTabTagStringNums( of, elementTag, "ID", i, j);
1522 lcl_writeTabTagStringNums( of, elementTag, "DefaultAbbrvName", i, j);
1523 lcl_writeTabTagStringNums( of, elementTag, "DefaultFullName", i, j);
1524 if (bNarrow)
1525 lcl_writeTabTagStringNums( of, elementTag, "DefaultNarrowName", i, j);
1526 }
1527 }
1528}
1529
1530bool LCCalendarNode::expectedCalendarElement( std::u16string_view rName,
1531 const LocaleNode* pNode, sal_Int16 nChild, std::u16string_view rCalendarID ) const
1532{
1533 bool bFound = true;
1534 if (nChild >= 0)
1535 {
1536 if (nChild >= pNode->getNumberOfChildren())
1537 bFound = false;
1538 else
1539 pNode = pNode->getChildAt(nChild);
1540 }
1541 if (bFound && (!pNode || pNode->getName() != rName))
1542 bFound = false;
1543 if (!bFound)
1544 incErrorStrStr( "Error: <%s> element expected in calendar '%s'\n", rName, rCalendarID);
1545 return bFound;
1546}
1547
1549{
1550 OUString useLocale = getAttr().getValueByName("ref");
1551 if (!useLocale.isEmpty()) {
1552 useLocale = useLocale.replace( '-', '_');
1553 of.writeRefFunction("getAllCalendars_", useLocale);
1554 return;
1555 }
1556 sal_Int16 nbOfCalendars = sal::static_int_cast<sal_Int16>( getNumberOfChildren() );
1557 OUString str;
1558 std::unique_ptr<sal_Int16[]> nbOfDays( new sal_Int16[nbOfCalendars] );
1559 std::unique_ptr<sal_Int16[]> nbOfMonths( new sal_Int16[nbOfCalendars] );
1560 std::unique_ptr<sal_Int16[]> nbOfGenitiveMonths( new sal_Int16[nbOfCalendars] );
1561 std::unique_ptr<sal_Int16[]> nbOfPartitiveMonths( new sal_Int16[nbOfCalendars] );
1562 std::unique_ptr<sal_Int16[]> nbOfEras( new sal_Int16[nbOfCalendars] );
1563
1564 // Known allowed calendar identifiers (unoid) and whether used or not.
1565 // Of course there must be an implementation for new to be added
1566 // identifiers.. see data/locale.dtd
1567 std::map< OUString, bool > aCalendars;
1568 aCalendars["buddhist"] = false;
1569 aCalendars["gengou"] = false;
1570 aCalendars["gregorian"] = false;
1571 aCalendars["hanja"] = false;
1572 aCalendars["hanja_yoil"] = false;
1573 aCalendars["hijri"] = false;
1574 aCalendars["jewish"] = false;
1575 aCalendars["ROC"] = false;
1576 // Not in ODF:
1577 aCalendars["dangi"] = false;
1578 aCalendars["persian"] = false;
1579
1580 sal_Int16 j;
1581 sal_Int16 i;
1582 bool bHasGregorian = false;
1583
1584
1585 for ( i = 0; i < nbOfCalendars; i++) {
1586 LocaleNode * calNode = getChildAt (i);
1587 OUString calendarID = calNode -> getAttr().getValueByName("unoid");
1588 of.writeParameter( "calendarID", calendarID, i);
1589 bool bGregorian = calendarID == "gregorian";
1590 if (!bHasGregorian)
1591 bHasGregorian = bGregorian;
1592 auto calIt = aCalendars.find(calendarID);
1593 if (calIt == aCalendars.end())
1594 incErrorStr( "Error: unknown Calendar unoid: %s\n", calendarID);
1595 else if (calIt->second)
1596 incErrorStr( "Error: duplicate Calendar unoid: %s\n", calendarID);
1597 else
1598 calIt->second = true;
1599 str = calNode -> getAttr().getValueByName("default");
1600 of.writeDefaultParameter("Calendar", str, i);
1601
1602 sal_Int16 nChild = 0;
1603
1604 // Generate Days of Week
1605 const char *elementTag;
1606 LocaleNode * daysNode = nullptr;
1607 OUString ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
1608 ref_name = ref_name.replace( '-', '_');
1609 if (!ref_name.isEmpty() && i > 0) {
1610 for (j = 0; j < i; j++) {
1611 str = getChildAt(j)->getAttr().getValueByName("unoid");
1612 if (str == ref_name)
1613 daysNode = getChildAt(j)->getChildAt(0);
1614 }
1615 }
1616 if (!ref_name.isEmpty() && daysNode == nullptr) {
1617 of.writeParameter("dayRef", u"ref", i);
1618 of.writeParameter("dayRefName", ref_name, i);
1619 nbOfDays[i] = 0;
1620 } else {
1621 if (daysNode == nullptr)
1622 daysNode = calNode -> getChildAt(nChild);
1623 nbOfDays[i] = sal::static_int_cast<sal_Int16>( daysNode->getNumberOfChildren() );
1624 if (bGregorian && nbOfDays[i] != 7)
1625 incErrorInt( "Error: A Gregorian calendar must have 7 days per week, this one has %d\n", nbOfDays[i]);
1626 elementTag = "day";
1627 for (j = 0; j < nbOfDays[i]; j++) {
1628 LocaleNode *currNode = daysNode -> getChildAt(j);
1629 OUString dayID( currNode->getChildAt(0)->getValue());
1630 of.writeParameter("dayID", dayID, i, j);
1631 if ( j == 0 && bGregorian && dayID != "sun" )
1632 incError( "First day of a week of a Gregorian calendar must be <DayID>sun</DayID>");
1633 lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
1634 }
1635 }
1636 ++nChild;
1637
1638 // Generate Months of Year
1639 LocaleNode * monthsNode = nullptr;
1640 ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
1641 ref_name = ref_name.replace( '-', '_');
1642 if (!ref_name.isEmpty() && i > 0) {
1643 for (j = 0; j < i; j++) {
1644 str = getChildAt(j)->getAttr().getValueByName("unoid");
1645 if (str == ref_name)
1646 monthsNode = getChildAt(j)->getChildAt(1);
1647 }
1648 }
1649 if (!ref_name.isEmpty() && monthsNode == nullptr) {
1650 of.writeParameter("monthRef", u"ref", i);
1651 of.writeParameter("monthRefName", ref_name, i);
1652 nbOfMonths[i] = 0;
1653 } else {
1654 if (monthsNode == nullptr)
1655 monthsNode = calNode -> getChildAt(nChild);
1656 nbOfMonths[i] = sal::static_int_cast<sal_Int16>( monthsNode->getNumberOfChildren() );
1657 if (bGregorian && nbOfMonths[i] != 12)
1658 incErrorInt( "Error: A Gregorian calendar must have 12 months, this one has %d\n", nbOfMonths[i]);
1659 elementTag = "month";
1660 for (j = 0; j < nbOfMonths[i]; j++) {
1661 LocaleNode *currNode = monthsNode -> getChildAt(j);
1662 OUString monthID( currNode->getChildAt(0)->getValue());
1663 of.writeParameter("monthID", monthID, i, j);
1664 if ( j == 0 && bGregorian && monthID != "jan" )
1665 incError( "First month of a year of a Gregorian calendar must be <MonthID>jan</MonthID>");
1666 lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
1667 }
1668 }
1669 ++nChild;
1670
1671 // Generate genitive Months of Year
1672 // Optional, if not present fall back to month nouns.
1673 if ( calNode->getChildAt(nChild)->getName() != "GenitiveMonths" )
1674 --nChild;
1675 LocaleNode * genitiveMonthsNode = nullptr;
1676 ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
1677 ref_name = ref_name.replace( '-', '_');
1678 if (!ref_name.isEmpty() && i > 0) {
1679 for (j = 0; j < i; j++) {
1680 str = getChildAt(j)->getAttr().getValueByName("unoid");
1681 if (str == ref_name)
1682 genitiveMonthsNode = getChildAt(j)->getChildAt(1);
1683 }
1684 }
1685 if (!ref_name.isEmpty() && genitiveMonthsNode == nullptr) {
1686 of.writeParameter("genitiveMonthRef", u"ref", i);
1687 of.writeParameter("genitiveMonthRefName", ref_name, i);
1688 nbOfGenitiveMonths[i] = 0;
1689 } else {
1690 if (genitiveMonthsNode == nullptr)
1691 genitiveMonthsNode = calNode -> getChildAt(nChild);
1692 nbOfGenitiveMonths[i] = sal::static_int_cast<sal_Int16>( genitiveMonthsNode->getNumberOfChildren() );
1693 if (bGregorian && nbOfGenitiveMonths[i] != 12)
1694 incErrorInt( "Error: A Gregorian calendar must have 12 genitive months, this one has %d\n", nbOfGenitiveMonths[i]);
1695 elementTag = "genitiveMonth";
1696 for (j = 0; j < nbOfGenitiveMonths[i]; j++) {
1697 LocaleNode *currNode = genitiveMonthsNode -> getChildAt(j);
1698 OUString genitiveMonthID( currNode->getChildAt(0)->getValue());
1699 of.writeParameter("genitiveMonthID", genitiveMonthID, i, j);
1700 if ( j == 0 && bGregorian && genitiveMonthID != "jan" )
1701 incError( "First genitive month of a year of a Gregorian calendar must be <MonthID>jan</MonthID>");
1702 lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
1703 }
1704 }
1705 ++nChild;
1706
1707 // Generate partitive Months of Year
1708 // Optional, if not present fall back to genitive months, or nominative
1709 // months (nouns) if that isn't present either.
1710 if ( calNode->getChildAt(nChild)->getName() != "PartitiveMonths" )
1711 --nChild;
1712 LocaleNode * partitiveMonthsNode = nullptr;
1713 ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
1714 ref_name = ref_name.replace( '-', '_');
1715 if (!ref_name.isEmpty() && i > 0) {
1716 for (j = 0; j < i; j++) {
1717 str = getChildAt(j)->getAttr().getValueByName("unoid");
1718 if (str == ref_name)
1719 partitiveMonthsNode = getChildAt(j)->getChildAt(1);
1720 }
1721 }
1722 if (!ref_name.isEmpty() && partitiveMonthsNode == nullptr) {
1723 of.writeParameter("partitiveMonthRef", u"ref", i);
1724 of.writeParameter("partitiveMonthRefName", ref_name, i);
1725 nbOfPartitiveMonths[i] = 0;
1726 } else {
1727 if (partitiveMonthsNode == nullptr)
1728 partitiveMonthsNode = calNode -> getChildAt(nChild);
1729 nbOfPartitiveMonths[i] = sal::static_int_cast<sal_Int16>( partitiveMonthsNode->getNumberOfChildren() );
1730 if (bGregorian && nbOfPartitiveMonths[i] != 12)
1731 incErrorInt( "Error: A Gregorian calendar must have 12 partitive months, this one has %d\n", nbOfPartitiveMonths[i]);
1732 elementTag = "partitiveMonth";
1733 for (j = 0; j < nbOfPartitiveMonths[i]; j++) {
1734 LocaleNode *currNode = partitiveMonthsNode -> getChildAt(j);
1735 OUString partitiveMonthID( currNode->getChildAt(0)->getValue());
1736 of.writeParameter("partitiveMonthID", partitiveMonthID, i, j);
1737 if ( j == 0 && bGregorian && partitiveMonthID != "jan" )
1738 incError( "First partitive month of a year of a Gregorian calendar must be <MonthID>jan</MonthID>");
1739 lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
1740 }
1741 }
1742 ++nChild;
1743
1744 // Generate Era name
1745 LocaleNode * erasNode = nullptr;
1746 ref_name = calNode -> getChildAt(nChild) ->getAttr().getValueByName("ref");
1747 ref_name = ref_name.replace( '-', '_');
1748 if (!ref_name.isEmpty() && i > 0) {
1749 for (j = 0; j < i; j++) {
1750 str = getChildAt(j)->getAttr().getValueByName("unoid");
1751 if (str == ref_name)
1752 erasNode = getChildAt(j)->getChildAt(2);
1753 }
1754 }
1755 if (!ref_name.isEmpty() && erasNode == nullptr) {
1756 of.writeParameter("eraRef", u"ref", i);
1757 of.writeParameter("eraRefName", ref_name, i);
1758 nbOfEras[i] = 0;
1759 } else {
1760 if (erasNode == nullptr)
1761 erasNode = calNode -> getChildAt(nChild);
1762 if (!expectedCalendarElement(u"Eras", erasNode, -1, calendarID))
1763 {
1764 --nChild;
1765 }
1766 else
1767 {
1768 nbOfEras[i] = sal::static_int_cast<sal_Int16>( erasNode->getNumberOfChildren() );
1769 if (bGregorian && nbOfEras[i] != 2)
1770 incErrorInt( "Error: A Gregorian calendar must have 2 eras, this one has %d\n", nbOfEras[i]);
1771 elementTag = "era";
1772 for (j = 0; j < nbOfEras[i]; j++) {
1773 LocaleNode *currNode = erasNode -> getChildAt(j);
1774 if (!expectedCalendarElement(u"Era", currNode, -1, calendarID))
1775 {
1776 continue; // for
1777 }
1778 OUString eraID( currNode->getChildAt(0)->getValue());
1779 of.writeParameter("eraID", eraID, i, j);
1780 if ( j == 0 && bGregorian && eraID != "bc" )
1781 incError( "First era of a Gregorian calendar must be <EraID>bc</EraID>");
1782 if ( j == 1 && bGregorian && eraID != "ad" )
1783 incError( "Second era of a Gregorian calendar must be <EraID>ad</EraID>");
1784 of.writeAsciiString("\n");
1785 of.writeParameter(elementTag, "DefaultAbbrvName",currNode->getChildAt(1)->getValue() ,i, j);
1786 of.writeParameter(elementTag, "DefaultFullName",currNode->getChildAt(2)->getValue() , i, j);
1787 }
1788 }
1789 }
1790 ++nChild;
1791
1792 if (expectedCalendarElement(u"StartDayOfWeek", calNode, nChild, calendarID))
1793 {
1794 str = calNode->getChildAt(nChild)->getChildAt(0)->getValue();
1795 if (nbOfDays[i])
1796 {
1797 for (j = 0; j < nbOfDays[i]; j++)
1798 {
1799 LocaleNode *currNode = daysNode->getChildAt(j);
1800 OUString dayID( currNode->getChildAt(0)->getValue());
1801 if (str == dayID)
1802 break; // for
1803 }
1804 if (j >= nbOfDays[i])
1805 incErrorStr( "Error: <StartDayOfWeek> <DayID> must be one of the <DaysOfWeek>, but is: %s\n", str);
1806 }
1807 of.writeParameter("startDayOfWeek", str, i);
1808 ++nChild;
1809 }
1810
1811 if (expectedCalendarElement(u"MinimalDaysInFirstWeek", calNode, nChild, calendarID))
1812 {
1813 str = calNode ->getChildAt(nChild)-> getValue();
1814 sal_Int16 nDays = sal::static_int_cast<sal_Int16>( str.toInt32() );
1815 if (nDays < 1 || (0 < nbOfDays[i] && nbOfDays[i] < nDays))
1816 incErrorInt( "Error: Bad value of MinimalDaysInFirstWeek: %d, must be 1 <= value <= days_in_week\n",
1817 nDays);
1818 of.writeIntParameter("minimalDaysInFirstWeek", i, nDays);
1819 }
1820 }
1821 if (!bHasGregorian)
1822 fprintf( stderr, "Warning: %s\n", "No Gregorian calendar defined, are you sure?");
1823
1824 of.writeAsciiString("static const sal_Int16 calendarsCount = ");
1825 of.writeInt(nbOfCalendars);
1826 of.writeAsciiString(";\n\n");
1827
1828 of.writeAsciiString("static const sal_Unicode nbOfDays[] = {");
1829 for(i = 0; i < nbOfCalendars - 1; i++) {
1830 of.writeInt(nbOfDays[i]);
1831 of.writeAsciiString(", ");
1832 }
1833 of.writeInt(nbOfDays[i]);
1834 of.writeAsciiString("};\n");
1835
1836 of.writeAsciiString("static const sal_Unicode nbOfMonths[] = {");
1837 for(i = 0; i < nbOfCalendars - 1; i++) {
1838 of.writeInt(nbOfMonths[i]);
1839 of.writeAsciiString(", ");
1840 }
1841 of.writeInt(nbOfMonths[i]);
1842 of.writeAsciiString("};\n");
1843
1844 of.writeAsciiString("static const sal_Unicode nbOfGenitiveMonths[] = {");
1845 for(i = 0; i < nbOfCalendars - 1; i++) {
1846 of.writeInt(nbOfGenitiveMonths[i]);
1847 of.writeAsciiString(", ");
1848 }
1849 of.writeInt(nbOfGenitiveMonths[i]);
1850 of.writeAsciiString("};\n");
1851
1852 of.writeAsciiString("static const sal_Unicode nbOfPartitiveMonths[] = {");
1853 for(i = 0; i < nbOfCalendars - 1; i++) {
1854 of.writeInt(nbOfPartitiveMonths[i]);
1855 of.writeAsciiString(", ");
1856 }
1857 of.writeInt(nbOfPartitiveMonths[i]);
1858 of.writeAsciiString("};\n");
1859
1860 of.writeAsciiString("static const sal_Unicode nbOfEras[] = {");
1861 for(i = 0; i < nbOfCalendars - 1; i++) {
1862 of.writeInt(nbOfEras[i]);
1863 of.writeAsciiString(", ");
1864 }
1865 of.writeInt(nbOfEras[i]);
1866 of.writeAsciiString("};\n");
1867
1868
1869 of.writeAsciiString("static const sal_Unicode* calendars[] = {\n");
1870 of.writeAsciiString("\tnbOfDays,\n");
1871 of.writeAsciiString("\tnbOfMonths,\n");
1872 of.writeAsciiString("\tnbOfGenitiveMonths,\n");
1873 of.writeAsciiString("\tnbOfPartitiveMonths,\n");
1874 of.writeAsciiString("\tnbOfEras,\n");
1875 for(i = 0; i < nbOfCalendars; i++) {
1876 of.writeAsciiString("\tcalendarID");
1877 of.writeInt(i);
1878 of.writeAsciiString(",\n");
1879 of.writeAsciiString("\tdefaultCalendar");
1880 of.writeInt(i);
1881 of.writeAsciiString(",\n");
1882 lcl_writeAbbrFullNarrArrays( of, nbOfDays[i], "day", i, true);
1883 lcl_writeAbbrFullNarrArrays( of, nbOfMonths[i], "month", i, true);
1884 lcl_writeAbbrFullNarrArrays( of, nbOfGenitiveMonths[i], "genitiveMonth", i, true);
1885 lcl_writeAbbrFullNarrArrays( of, nbOfPartitiveMonths[i], "partitiveMonth", i, true);
1886 lcl_writeAbbrFullNarrArrays( of, nbOfEras[i], "era", i, false /*noNarrow*/);
1887 of.writeAsciiString("\tstartDayOfWeek");of.writeInt(i); of.writeAsciiString(",\n");
1888 of.writeAsciiString("\tminimalDaysInFirstWeek");of.writeInt(i); of.writeAsciiString(",\n");
1889 }
1890
1891 of.writeAsciiString("};\n\n");
1892 of.writeFunction("getAllCalendars_", "calendarsCount", "calendars");
1893}
1894
1895static bool isIso4217( const OUString& rStr )
1896{
1897 const sal_Unicode* p = rStr.getStr();
1898 return rStr.getLength() == 3
1899 && 'A' <= p[0] && p[0] <= 'Z'
1900 && 'A' <= p[1] && p[1] <= 'Z'
1901 && 'A' <= p[2] && p[2] <= 'Z'
1902 ;
1903}
1904
1906{
1907 OUString useLocale = getAttr().getValueByName("ref");
1908 if (!useLocale.isEmpty()) {
1909 useLocale = useLocale.replace( '-', '_');
1910 of.writeRefFunction("getAllCurrencies_", useLocale);
1911 return;
1912 }
1913 sal_Int16 nbOfCurrencies = 0;
1914 OUString str;
1915
1916 bool bTheDefault= false;
1917 bool bTheCompatible = false;
1918 for ( sal_Int32 i = 0; i < getNumberOfChildren(); i++,nbOfCurrencies++) {
1919 LocaleNode * currencyNode = getChildAt (i);
1920 str = currencyNode->getAttr().getValueByName("default");
1921 bool bDefault = of.writeDefaultParameter("Currency", str, nbOfCurrencies);
1922 str = currencyNode->getAttr().getValueByName("usedInCompatibleFormatCodes");
1923 bool bCompatible = of.writeDefaultParameter("CurrencyUsedInCompatibleFormatCodes", str, nbOfCurrencies);
1924 str = currencyNode->getAttr().getValueByName("legacyOnly");
1925 bool bLegacy = of.writeDefaultParameter("CurrencyLegacyOnly", str, nbOfCurrencies);
1926 if (bLegacy && (bDefault || bCompatible))
1927 incError( "Currency: if legacyOnly==true, both 'default' and 'usedInCompatibleFormatCodes' must be false.");
1928 if (bDefault)
1929 {
1930 if (bTheDefault)
1931 incError( "Currency: more than one default currency.");
1932 bTheDefault = true;
1933 }
1934 if (bCompatible)
1935 {
1936 if (bTheCompatible)
1937 incError( "Currency: more than one currency flagged as usedInCompatibleFormatCodes.");
1938 bTheCompatible = true;
1939 }
1940 str = currencyNode -> findNode ("CurrencyID") -> getValue();
1941 of.writeParameter("currencyID", str, nbOfCurrencies);
1942 // CurrencyID MUST be ISO 4217.
1943 if (!bLegacy && !isIso4217(str))
1944 incError( "CurrencyID is not ISO 4217");
1945 str = currencyNode -> findNode ("CurrencySymbol") -> getValue();
1946 of.writeParameter("currencySymbol", str, nbOfCurrencies);
1947 // Check if this currency really is the one used in number format
1948 // codes. In case of ref=... mechanisms it may be that TheCurrency
1949 // couldn't had been determined from the current locale (i.e. is
1950 // empty), silently assume the referred locale has things right.
1951 if (bCompatible && !sTheCompatibleCurrency.isEmpty() && sTheCompatibleCurrency != str)
1952 incErrorStrStr( "Error: CurrencySymbol \"%s\" flagged as usedInCompatibleFormatCodes doesn't match \"%s\" determined from format codes.\n", str, sTheCompatibleCurrency);
1953 str = currencyNode -> findNode ("BankSymbol") -> getValue();
1954 of.writeParameter("bankSymbol", str, nbOfCurrencies);
1955 // BankSymbol currently must be ISO 4217. May change later if
1956 // application always uses CurrencyID instead of BankSymbol.
1957 if (!bLegacy && !isIso4217(str))
1958 incError( "BankSymbol is not ISO 4217");
1959 str = currencyNode -> findNode ("CurrencyName") -> getValue();
1960 of.writeParameter("currencyName", str, nbOfCurrencies);
1961 str = currencyNode -> findNode ("DecimalPlaces") -> getValue();
1962 sal_Int16 nDecimalPlaces = static_cast<sal_Int16>(str.toInt32());
1963 of.writeIntParameter("currencyDecimalPlaces", nbOfCurrencies, nDecimalPlaces);
1964 of.writeAsciiString("\n");
1965 };
1966
1967 if (!bTheDefault)
1968 incError( "Currency: no default currency.");
1969 if (!bTheCompatible)
1970 incError( "Currency: no currency flagged as usedInCompatibleFormatCodes.");
1971
1972 of.writeAsciiString("static const sal_Int16 currencyCount = ");
1973 of.writeInt(nbOfCurrencies);
1974 of.writeAsciiString(";\n\n");
1975 of.writeAsciiString("static const sal_Unicode* currencies[] = {\n");
1976 for(sal_Int16 i = 0; i < nbOfCurrencies; i++) {
1977 of.writeAsciiString("\tcurrencyID");
1978 of.writeInt(i);
1979 of.writeAsciiString(",\n");
1980 of.writeAsciiString("\tcurrencySymbol");
1981 of.writeInt(i);
1982 of.writeAsciiString(",\n");
1983 of.writeAsciiString("\tbankSymbol");
1984 of.writeInt(i);
1985 of.writeAsciiString(",\n");
1986 of.writeAsciiString("\tcurrencyName");
1987 of.writeInt(i);
1988 of.writeAsciiString(",\n");
1989 of.writeAsciiString("\tdefaultCurrency");
1990 of.writeInt(i);
1991 of.writeAsciiString(",\n");
1992 of.writeAsciiString("\tdefaultCurrencyUsedInCompatibleFormatCodes");
1993 of.writeInt(i);
1994 of.writeAsciiString(",\n");
1995 of.writeAsciiString("\tcurrencyDecimalPlaces");
1996 of.writeInt(i);
1997 of.writeAsciiString(",\n");
1998 of.writeAsciiString("\tdefaultCurrencyLegacyOnly");
1999 of.writeInt(i);
2000 of.writeAsciiString(",\n");
2001 }
2002 of.writeAsciiString("};\n\n");
2003 of.writeFunction("getAllCurrencies_", "currencyCount", "currencies");
2004}
2005
2007{
2008 OUString useLocale = getAttr().getValueByName("ref");
2009 if (!useLocale.isEmpty()) {
2010 useLocale = useLocale.replace( '-', '_');
2011 of.writeRefFunction("getTransliterations_", useLocale);
2012 return;
2013 }
2014 sal_Int16 nbOfModules = 0;
2015 OUString str;
2016
2017 for ( sal_Int32 i = 0; i < getNumberOfChildren(); i++,nbOfModules++) {
2018 LocaleNode * transNode = getChildAt (i);
2019 str = transNode->getAttr().getValueByIndex(0);
2020 of.writeParameter("Transliteration", str, nbOfModules);
2021 }
2022 of.writeAsciiString("static const sal_Int16 nbOfTransliterations = ");
2023 of.writeInt(nbOfModules);
2024 of.writeAsciiString(";\n\n");
2025
2026 of.writeAsciiString("\nstatic const sal_Unicode* LCTransliterationsArray[] = {\n");
2027 for( sal_Int16 i = 0; i < nbOfModules; i++) {
2028 of.writeAsciiString("\tTransliteration");
2029 of.writeInt(i);
2030 of.writeAsciiString(",\n");
2031 }
2032 of.writeAsciiString("};\n\n");
2033 of.writeFunction("getTransliterations_", "nbOfTransliterations", "LCTransliterationsArray");
2034}
2035
2036namespace {
2037
2038struct NameValuePair {
2039 const char *name;
2040 const char *value;
2041};
2042
2043}
2044
2045const NameValuePair ReserveWord[] = {
2046 { "trueWord", "true" },
2047 { "falseWord", "false" },
2048 { "quarter1Word", "1st quarter" },
2049 { "quarter2Word", "2nd quarter" },
2050 { "quarter3Word", "3rd quarter" },
2051 { "quarter4Word", "4th quarter" },
2052 { "aboveWord", "above" },
2053 { "belowWord", "below" },
2054 { "quarter1Abbreviation", "Q1" },
2055 { "quarter2Abbreviation", "Q2" },
2056 { "quarter3Abbreviation", "Q3" },
2057 { "quarter4Abbreviation", "Q4" }
2058};
2059
2061{
2062 OUString useLocale = getAttr().getValueByName("ref");
2063 if (!useLocale.isEmpty()) {
2064 useLocale = useLocale.replace( '-', '_');
2065 of.writeRefFunction("getForbiddenCharacters_", useLocale);
2066 of.writeRefFunction("getBreakIteratorRules_", useLocale);
2067 of.writeRefFunction("getReservedWords_", useLocale);
2068 return;
2069 }
2070 const LocaleNode * reserveNode = findNode("ReservedWords");
2071 if (!reserveNode)
2072 incError( "No ReservedWords element."); // should not happen if validated...
2073 const LocaleNode * forbidNode = findNode("ForbiddenCharacters");
2074 const LocaleNode * breakNode = findNode("BreakIteratorRules");
2075
2076 bool bEnglishLocale = (strncmp( of.getLocale(), "en_", 3) == 0);
2077
2078 sal_Int16 nbOfWords = 0;
2079 OUString str;
2080 sal_Int16 i;
2081
2082 for ( i = 0; i < sal_Int16(SAL_N_ELEMENTS(ReserveWord)); i++,nbOfWords++) {
2083 const LocaleNode * curNode = (reserveNode ? reserveNode->findNode(
2084 ReserveWord[i].name) : nullptr);
2085 if (!curNode)
2086 fprintf( stderr,
2087 "Warning: No %s in ReservedWords, using en_US default: \"%s\".\n",
2089 str = curNode ? curNode -> getValue() : OUString::createFromAscii(ReserveWord[i].value);
2090 if (str.isEmpty())
2091 {
2092 ++nError;
2093 fprintf( stderr, "Error: No content for ReservedWords %s.\n", ReserveWord[i].name);
2094 }
2095 of.writeParameter("ReservedWord", str, nbOfWords);
2096 // "true", ..., "below" trigger untranslated warning.
2097 if (!bEnglishLocale && curNode && i <= 7 &&
2098 str.equalsIgnoreAsciiCaseAscii( ReserveWord[i].value))
2099 {
2100 fprintf( stderr,
2101 "Warning: ReservedWord %s seems to be untranslated \"%s\".\n",
2103 }
2104 }
2105 of.writeAsciiString("static const sal_Int16 nbOfReservedWords = ");
2106 of.writeInt(nbOfWords);
2107 of.writeAsciiString(";\n\n");
2108 of.writeAsciiString("\nstatic const sal_Unicode* LCReservedWordsArray[] = {\n");
2109 for( i = 0; i < nbOfWords; i++) {
2110 of.writeAsciiString("\tReservedWord");
2111 of.writeInt(i);
2112 of.writeAsciiString(",\n");
2113 }
2114 of.writeAsciiString("};\n\n");
2115 of.writeFunction("getReservedWords_", "nbOfReservedWords", "LCReservedWordsArray");
2116
2117 if (forbidNode) {
2118 of.writeParameter( "forbiddenBegin", forbidNode -> getChildAt(0)->getValue());
2119 of.writeParameter( "forbiddenEnd", forbidNode -> getChildAt(1)->getValue());
2120 of.writeParameter( "hangingChars", forbidNode -> getChildAt(2)->getValue());
2121 } else {
2122 of.writeParameter( "forbiddenBegin", std::u16string_view());
2123 of.writeParameter( "forbiddenEnd", std::u16string_view());
2124 of.writeParameter( "hangingChars", std::u16string_view());
2125 }
2126 of.writeAsciiString("\nstatic const sal_Unicode* LCForbiddenCharactersArray[] = {\n");
2127 of.writeAsciiString("\tforbiddenBegin,\n");
2128 of.writeAsciiString("\tforbiddenEnd,\n");
2129 of.writeAsciiString("\thangingChars\n");
2130 of.writeAsciiString("};\n\n");
2131 of.writeFunction("getForbiddenCharacters_", "3", "LCForbiddenCharactersArray");
2132
2133 if (breakNode) {
2134 of.writeParameter( "EditMode", breakNode -> getChildAt(0)->getValue());
2135 of.writeParameter( "DictionaryMode", breakNode -> getChildAt(1)->getValue());
2136 of.writeParameter( "WordCountMode", breakNode -> getChildAt(2)->getValue());
2137 of.writeParameter( "CharacterMode", breakNode -> getChildAt(3)->getValue());
2138 of.writeParameter( "LineMode", breakNode -> getChildAt(4)->getValue());
2139 } else {
2140 of.writeParameter( "EditMode", std::u16string_view());
2141 of.writeParameter( "DictionaryMode", std::u16string_view());
2142 of.writeParameter( "WordCountMode", std::u16string_view());
2143 of.writeParameter( "CharacterMode", std::u16string_view());
2144 of.writeParameter( "LineMode", std::u16string_view());
2145 }
2146 of.writeAsciiString("\nstatic const sal_Unicode* LCBreakIteratorRulesArray[] = {\n");
2147 of.writeAsciiString("\tEditMode,\n");
2148 of.writeAsciiString("\tDictionaryMode,\n");
2149 of.writeAsciiString("\tWordCountMode,\n");
2150 of.writeAsciiString("\tCharacterMode,\n");
2151 of.writeAsciiString("\tLineMode\n");
2152 of.writeAsciiString("};\n\n");
2153 of.writeFunction("getBreakIteratorRules_", "5", "LCBreakIteratorRulesArray");
2154
2155}
2156
2158{
2159 of.writeAsciiString("// ---> ContinuousNumbering\n");
2160 OUString useLocale = getAttr().getValueByName("ref");
2161 if (!useLocale.isEmpty()) {
2162 useLocale = useLocale.replace( '-', '_');
2163 of.writeRefFunction2("getContinuousNumberingLevels_", useLocale);
2164 return;
2165 }
2166
2167 // hard code number of attributes per style.
2168 const int nAttributes = 5;
2169 const char* attr[ nAttributes ] = { "Prefix", "NumType", "Suffix", "Transliteration", "NatNum" };
2170
2171 // record each attribute of each style in a static C++ variable.
2172 // determine number of styles on the fly.
2173 sal_Int32 nStyles = getNumberOfChildren();
2174 sal_Int32 i;
2175
2176 for( i = 0; i < nStyles; ++i )
2177 {
2178 const Attr &q = getChildAt( i )->getAttr();
2179 for( sal_Int32 j=0; j<nAttributes; ++j )
2180 {
2181 const char* name = attr[j];
2182 OUString value = q.getValueByName( name );
2183 of.writeParameter("continuous", name, value, sal::static_int_cast<sal_Int16>(i) );
2184 }
2185 }
2186
2187 // record number of styles and attributes.
2188 of.writeAsciiString("static const sal_Int16 continuousNbOfStyles = ");
2189 of.writeInt( sal::static_int_cast<sal_Int16>( nStyles ) );
2190 of.writeAsciiString(";\n\n");
2191 of.writeAsciiString("static const sal_Int16 continuousNbOfAttributesPerStyle = ");
2192 of.writeInt( nAttributes );
2193 of.writeAsciiString(";\n\n");
2194
2195 // generate code. (intermediate arrays)
2196 for( i=0; i<nStyles; i++ )
2197 {
2198 of.writeAsciiString("\nstatic const sal_Unicode* continuousStyle" );
2199 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2200 of.writeAsciiString("[] = {\n");
2201 for( sal_Int32 j=0; j<nAttributes; j++)
2202 {
2203 of.writeAsciiString("\t");
2204 of.writeAsciiString( "continuous" );
2205 of.writeAsciiString( attr[j] );
2206 of.writeInt(sal::static_int_cast<sal_Int16>(i));
2207 of.writeAsciiString(",\n");
2208 }
2209 of.writeAsciiString("\t0\n};\n\n");
2210 }
2211
2212 // generate code. (top-level array)
2213 of.writeAsciiString("\n");
2214 of.writeAsciiString("static const sal_Unicode** LCContinuousNumberingLevelsArray[] = {\n" );
2215 for( i=0; i<nStyles; i++ )
2216 {
2217 of.writeAsciiString( "\t" );
2218 of.writeAsciiString( "continuousStyle" );
2219 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2220 of.writeAsciiString( ",\n");
2221 }
2222 of.writeAsciiString("\t0\n};\n\n");
2223 of.writeFunction2("getContinuousNumberingLevels_", "continuousNbOfStyles",
2224 "continuousNbOfAttributesPerStyle", "LCContinuousNumberingLevelsArray");
2225}
2226
2227
2229{
2230 of.writeAsciiString("// ---> OutlineNumbering\n");
2231 OUString useLocale = getAttr().getValueByName("ref");
2232 if (!useLocale.isEmpty()) {
2233 useLocale = useLocale.replace( '-', '_');
2234 of.writeRefFunction3("getOutlineNumberingLevels_", useLocale);
2235 return;
2236 }
2237
2238 // hardcode number of attributes per level
2239 const int nAttributes = 11;
2240 const char* attr[ nAttributes ] =
2241 {
2242 "Prefix",
2243 "NumType",
2244 "Suffix",
2245 "BulletChar",
2246 "BulletFontName",
2247 "ParentNumbering",
2248 "LeftMargin",
2249 "SymbolTextDistance",
2250 "FirstLineOffset",
2251 "Transliteration",
2252 "NatNum",
2253 };
2254
2255 // record each attribute of each level of each style in a static C++ variable.
2256 // determine number of styles and number of levels per style on the fly.
2257 sal_Int32 nStyles = getNumberOfChildren();
2258 std::vector<sal_Int32> nLevels; // may be different for each style?
2259 for( sal_Int32 i = 0; i < nStyles; i++ )
2260 {
2261 LocaleNode* p = getChildAt( i );
2262 nLevels.push_back( p->getNumberOfChildren() );
2263 for( sal_Int32 j=0; j<nLevels.back(); j++ )
2264 {
2265 const Attr& q = p->getChildAt( j )->getAttr();
2266 for( sal_Int32 k=0; k<nAttributes; ++k )
2267 {
2268 const char* name = attr[k];
2269 OUString value = q.getValueByName( name );
2270 of.writeParameter("outline", name, value,
2271 sal::static_int_cast<sal_Int16>(i),
2272 sal::static_int_cast<sal_Int16>(j) );
2273 }
2274 }
2275 }
2276
2277 // verify that each style has the same number of levels.
2278 for( size_t i=0; i<nLevels.size(); i++ )
2279 {
2280 if( nLevels[0] != nLevels[i] )
2281 {
2282 incError( "Numbering levels don't match.");
2283 }
2284 }
2285
2286 // record number of attributes, levels, and styles.
2287 of.writeAsciiString("static const sal_Int16 outlineNbOfStyles = ");
2288 of.writeInt( sal::static_int_cast<sal_Int16>( nStyles ) );
2289 of.writeAsciiString(";\n\n");
2290 of.writeAsciiString("static const sal_Int16 outlineNbOfLevelsPerStyle = ");
2291 of.writeInt( sal::static_int_cast<sal_Int16>( nLevels.back() ) );
2292 of.writeAsciiString(";\n\n");
2293 of.writeAsciiString("static const sal_Int16 outlineNbOfAttributesPerLevel = ");
2294 of.writeInt( nAttributes );
2295 of.writeAsciiString(";\n\n");
2296
2297 // too complicated for now...
2298 // of.writeAsciiString("static const sal_Int16 nbOfOutlineNumberingLevels[] = { ");
2299 // for( sal_Int32 j=0; j<nStyles; j++ )
2300 // {
2301 // of.writeInt( nLevels[j] );
2302 // of.writeAsciiString(", ");
2303 // }
2304 // of.writeAsciiString("};\n\n");
2305
2306
2307 for( sal_Int32 i=0; i<nStyles; i++ )
2308 {
2309 for( sal_Int32 j=0; j<nLevels.back(); j++ )
2310 {
2311 of.writeAsciiString("static const sal_Unicode* outline");
2312 of.writeAsciiString("Style");
2313 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2314 of.writeAsciiString("Level");
2315 of.writeInt( sal::static_int_cast<sal_Int16>(j) );
2316 of.writeAsciiString("[] = { ");
2317
2318 for( sal_Int32 k=0; k<nAttributes; k++ )
2319 {
2320 of.writeAsciiString( "outline" );
2321 of.writeAsciiString( attr[k] );
2322 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2323 of.writeInt( sal::static_int_cast<sal_Int16>(j) );
2324 of.writeAsciiString(", ");
2325 }
2326 of.writeAsciiString("NULL };\n");
2327 }
2328 }
2329
2330 of.writeAsciiString("\n");
2331
2332
2333 for( sal_Int32 i=0; i<nStyles; i++ )
2334 {
2335 of.writeAsciiString("static const sal_Unicode** outline");
2336 of.writeAsciiString( "Style" );
2337 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2338 of.writeAsciiString("[] = { ");
2339
2340 for( sal_Int32 j=0; j<nLevels.back(); j++ )
2341 {
2342 of.writeAsciiString("outlineStyle");
2343 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2344 of.writeAsciiString("Level");
2345 of.writeInt( sal::static_int_cast<sal_Int16>(j) );
2346 of.writeAsciiString(", ");
2347 }
2348 of.writeAsciiString("NULL };\n");
2349 }
2350 of.writeAsciiString("\n");
2351
2352 of.writeAsciiString("static const sal_Unicode*** LCOutlineNumberingLevelsArray[] = {\n" );
2353 for( sal_Int32 i=0; i<nStyles; i++ )
2354 {
2355 of.writeAsciiString( "\t" );
2356 of.writeAsciiString( "outlineStyle" );
2357 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2358 of.writeAsciiString(",\n");
2359 }
2360 of.writeAsciiString("\tNULL\n};\n\n");
2361 of.writeFunction3("getOutlineNumberingLevels_", "outlineNbOfStyles", "outlineNbOfLevelsPerStyle",
2362 "outlineNbOfAttributesPerLevel", "LCOutlineNumberingLevelsArray");
2363}
2364
2365Attr::Attr (const Reference< XAttributeList > & attr) {
2366 sal_Int16 len = attr->getLength();
2367 name.realloc (len);
2368 auto pName = name.getArray();
2369 value.realloc (len);
2370 auto pValue = value.getArray();
2371 for (sal_Int16 i =0; i< len;i++) {
2372 pName[i] = attr->getNameByIndex(i);
2373 pValue[i] = attr -> getValueByIndex(i);
2374 }
2375}
2376
2377OUString Attr::getValueByName (const char *str) const {
2378 auto pName = std::find_if(std::cbegin(name), std::cend(name),
2379 [&str](const OUString& rName) { return rName.equalsAscii(str); });
2380 if (pName != std::cend(name))
2381 {
2382 auto i = static_cast<sal_Int32>(std::distance(std::cbegin(name), pName));
2383 return value[i];
2384 }
2385 return OUString();
2386}
2387
2388const OUString& Attr::getValueByIndex (sal_Int32 idx) const
2389{
2390 return value[idx];
2391}
2392
2393/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static OUString aDateSep
Definition: LocaleNode.cxx:282
static bool isIso4217(const OUString &rStr)
::o3tl::sorted_vector< sal_Int16 > ValueSet
Definition: LocaleNode.cxx:42
static OUString sTheCurrencyReplaceTo
Definition: LocaleNode.cxx:511
const NameValuePair ReserveWord[]
static OUString sTheDateEditFormat
Definition: LocaleNode.cxx:513
static void lcl_writeAbbrFullNarrArrays(const OFileWriter &of, sal_Int16 nCount, const char *elementTag, sal_Int16 i, bool bNarrow)
#define OSTR(s)
Definition: LocaleNode.cxx:128
static void lcl_writeAbbrFullNarrNames(const OFileWriter &of, const LocaleNode *currNode, const char *elementTag, sal_Int16 i, sal_Int16 j)
#define LOCALE_VERSION_DTD
Definition: LocaleNode.cxx:39
::o3tl::sorted_vector< OUString > NameSet
Definition: LocaleNode.cxx:41
static void lcl_writeTabTagString(const OFileWriter &of, const char *pTag, const char *pStr)
static OUString sTheCompatibleCurrency
Definition: LocaleNode.cxx:512
static void lcl_writeTabTagStringNums(const OFileWriter &of, const char *pTag, const char *pStr, sal_Int16 i, sal_Int16 j)
static OUString aDecSep
Definition: LocaleNode.cxx:283
const char * pName
Sequence< OUString > name
Definition: LocaleNode.hxx:67
const OUString & getValueByIndex(sal_Int32 idx) const
OUString getValueByName(const char *str) const
Sequence< OUString > value
Definition: LocaleNode.hxx:68
Attr(const Reference< XAttributeList > &attr)
virtual void generateCode(const OFileWriter &of) const override
Definition: LocaleNode.cxx:285
bool expectedCalendarElement(std::u16string_view rName, const LocaleNode *pNode, sal_Int16 nChild, std::u16string_view rCalendarID) const
virtual void generateCode(const OFileWriter &of) const override
virtual void generateCode(const OFileWriter &of) const override
virtual void generateCode(const OFileWriter &of) const override
virtual void generateCode(const OFileWriter &of) const override
Definition: LocaleNode.cxx:518
static sal_Int16 mnFormats
Definition: LocaleNode.hxx:141
static sal_Int16 mnSection
Definition: LocaleNode.hxx:140
virtual void generateCode(const OFileWriter &of) const override
virtual void generateCode(const OFileWriter &of) const override
Definition: LocaleNode.cxx:230
virtual void generateCode(const OFileWriter &of) const override
virtual void generateCode(const OFileWriter &of) const override
virtual void generateCode(const OFileWriter &of) const override
virtual void generateCode(const OFileWriter &of) const override
virtual void generateCode(const OFileWriter &of) const override
void incErrorStrStr(const char *pStr, std::u16string_view rVal1, std::u16string_view rVal2) const
Definition: LocaleNode.cxx:224
void addChild(LocaleNode *node)
Definition: LocaleNode.cxx:62
const OUString & getName() const
Definition: LocaleNode.hxx:90
void incErrorInt(const char *pStr, int nVal) const
Definition: LocaleNode.cxx:212
const OUString & getValue() const
Definition: LocaleNode.hxx:91
sal_Int32 getNumberOfChildren() const
Definition: LocaleNode.hxx:93
const LocaleNode * getRoot() const
Definition: LocaleNode.cxx:67
static LocaleNode * createNode(const OUString &name, const Reference< XAttributeList > &attr)
Definition: LocaleNode.cxx:92
int getError() const
Definition: LocaleNode.cxx:54
const Attr & getAttr() const
Definition: LocaleNode.hxx:92
virtual ~LocaleNode()
Definition: LocaleNode.cxx:88
const LocaleNode * findNode(const char *name) const
Definition: LocaleNode.cxx:76
OUString aName
Definition: LocaleNode.hxx:78
LocaleNode * getChildAt(sal_Int32 idx) const
Definition: LocaleNode.hxx:94
LocaleNode * parent
Definition: LocaleNode.hxx:81
void incError(const char *pStr) const
Definition: LocaleNode.cxx:201
LocaleNode(OUString name, const Reference< XAttributeList > &attr)
Definition: LocaleNode.cxx:46
virtual void generateCode(const OFileWriter &of) const
Definition: LocaleNode.cxx:130
std::vector< std::unique_ptr< LocaleNode > > children
Definition: LocaleNode.hxx:82
OUString writeParameterCheckLen(const OFileWriter &of, const char *pParameterName, const LocaleNode *pNode, sal_Int32 nMinLen, sal_Int32 nMaxLen) const
Definition: LocaleNode.cxx:144
void incErrorStr(const char *pStr, std::u16string_view rVal) const
Definition: LocaleNode.cxx:218
const char * getLocale() const
Return the locale string, something like en_US or de_DE.
Definition: LocaleNode.hxx:60
void writeAsciiString(const char *str) const
Definition: filewriter.cxx:42
void writeInt(sal_Int16 nb) const
Definition: filewriter.cxx:37
void writeFunction2(const char *func, const char *style, const char *attr, const char *array) const
Definition: filewriter.cxx:89
void writeParameter(const char *pAsciiStr, std::u16string_view aChars) const
Definition: filewriter.cxx:136
void writeRefFunction2(const char *func, std::u16string_view useLocale) const
Definition: filewriter.cxx:97
void writeRefFunction3(const char *func, std::u16string_view useLocale) const
Definition: filewriter.cxx:115
void writeFunction3(const char *func, const char *style, const char *levels, const char *attr, const char *array) const
Definition: filewriter.cxx:106
bool writeDefaultParameter(const char *pAsciiStr, std::u16string_view str, sal_Int16 count) const
Definition: filewriter.cxx:129
void writeFunction(const char *func, const char *count, const char *array) const
Definition: filewriter.cxx:53
void writeIntParameter(const char *pAsciiStr, const sal_Int16 count, sal_Int16 val) const
Definition: filewriter.cxx:124
void writeRefFunction(const char *func, std::u16string_view useLocale) const
Definition: filewriter.cxx:60
std::vector< Value >::const_iterator const_iterator
std::pair< const_iterator, bool > insert(Value &&x)
int nCount
float u
const char * name
const sal_uInt16 idx[]
sal_Int32 nIndex
OUString aName
void * p
sal_Int64 n
#define SAL_N_ELEMENTS(arr)
aStr
err
int i
constexpr sal_Int16 nFirstFreeFormatIndex
The number of reserved (with defined meaning) built-in format code indices, additional locale data fo...
constexpr sal_Int16 nStopPredefinedFormatIndex
The number of predefined format code indices that must be defined by locale data, except BOOLEAN and ...
constexpr T & temporary(T &&x)
sal_Int16 value
sal_Int16 nAttributes
unsigned char sal_uInt8
sal_uInt16 sal_Unicode