Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / i18npool / source / localedata / LocaleNode.cxx
blob690bfebf204f9b37b91282f27f3e6db0c938cdb3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <algorithm>
24 #include <iostream>
25 #include <set>
26 #include <vector>
28 #include <rtl/ustrbuf.hxx>
29 #include <sal/macros.h>
31 #include "LocaleNode.hxx"
32 #include <com/sun/star/i18n/NumberFormatIndex.hpp>
34 // NOTE: MUST match the Locale versionDTD attribute defined in data/locale.dtd
35 #define LOCALE_VERSION_DTD "2.0.3"
37 typedef ::std::set< OUString > NameSet;
38 typedef ::std::set< sal_Int16 > ValueSet;
40 namespace cssi = ::com::sun::star::i18n;
42 LocaleNode::LocaleNode (const OUString& name, const Reference< XAttributeList > & attr)
43 : aName(name)
44 , aAttribs(attr)
45 , parent(nullptr)
46 , children(nullptr)
47 , nChildren(0)
48 , childArrSize(0)
49 , nError(0)
53 int LocaleNode::getError() const
55 int err = nError;
56 for (sal_Int32 i=0;i<nChildren;i++)
57 err += children[i]->getError();
58 return err;
61 void LocaleNode::print () const {
62 printf ("<");
63 OUString str (aName);
64 for(sal_Int32 i = 0; i < str.getLength(); i++)
65 printf( "%c", str[i]);
66 printf (">\n");
69 void LocaleNode::printR () const {
70 print();
71 for (sal_Int32 i=0;i<nChildren;i++)
72 children[i]->printR();
73 printf ("\t");
74 print();
77 void LocaleNode::addChild ( LocaleNode * node) {
78 if (childArrSize <= nChildren) {
79 LocaleNode ** arrN = new LocaleNode*[childArrSize+10];
80 for (sal_Int32 i = 0; i<childArrSize; ++i)
81 arrN[i] = children[i];
82 delete [] children;
83 childArrSize += 10;
84 children = arrN;
86 children[nChildren++] = node;
87 node->setParent (this);
90 void LocaleNode::setParent ( LocaleNode * node) {
91 parent = node;
94 const LocaleNode* LocaleNode::getRoot() const
96 const LocaleNode* pRoot = nullptr;
97 const LocaleNode* pParent = this;
98 while ( (pParent = pParent->getParent()) != nullptr )
99 pRoot = pParent;
100 return pRoot;
103 const LocaleNode * LocaleNode::findNode ( const sal_Char *name) const {
104 if (aName.equalsAscii(name))
105 return this;
106 for (sal_Int32 i = 0; i< nChildren; i++) {
107 const LocaleNode *n=children[i]->findNode(name);
108 if (n)
109 return n;
111 return nullptr;
114 LocaleNode::~LocaleNode()
116 for (sal_Int32 i=0; i < nChildren; ++i)
117 delete children[i];
118 delete [] children;
121 LocaleNode* LocaleNode::createNode (const OUString& name, const Reference< XAttributeList > & attr)
123 if ( name == "LC_INFO" )
124 return new LCInfoNode (name,attr);
125 if ( name == "LC_CTYPE" )
126 return new LCCTYPENode (name,attr);
127 if ( name == "LC_FORMAT" )
128 return new LCFormatNode (name,attr);
129 if ( name == "LC_FORMAT_1" )
130 return new LCFormatNode (name,attr);
131 if ( name == "LC_CALENDAR" )
132 return new LCCalendarNode (name,attr);
133 if ( name == "LC_CURRENCY" )
134 return new LCCurrencyNode (name,attr);
135 if ( name == "LC_TRANSLITERATION" )
136 return new LCTransliterationNode (name,attr);
137 if ( name == "LC_COLLATION" )
138 return new LCCollationNode (name,attr);
139 if ( name == "LC_INDEX" )
140 return new LCIndexNode (name,attr);
141 if ( name == "LC_SEARCH" )
142 return new LCSearchNode (name,attr);
143 if ( name == "LC_MISC" )
144 return new LCMiscNode (name,attr);
145 if ( name == "LC_NumberingLevel" )
146 return new LCNumberingLevelNode (name, attr);
147 if ( name == "LC_OutLineNumberingLevel" )
148 return new LCOutlineNumberingLevelNode (name, attr);
150 return new LocaleNode(name,attr);
154 // printf(" name: '%s'\n", p->getName().pData->buffer );
155 // printf("value: '%s'\n", p->getValue().pData->buffer );
157 #define OSTR(s) (OUStringToOString( (s), RTL_TEXTENCODING_UTF8).getStr())
159 void print_OUString( const OUString& s )
161 printf( "%s", OSTR(s));
164 bool is_empty_string( const OUString& s )
166 return s.isEmpty() || s == "\n";
169 void print_indent( int depth )
171 for( int i=0; i<depth; i++ ) printf(" ");
174 void print_color( int color )
176 printf("\033[%dm", color);
179 void print_node( const LocaleNode* p, int depth=0 )
181 if( !p ) return;
183 print_indent( depth );
184 printf("<");
185 print_color(36);
186 print_OUString( p->getName() );
187 print_color(0);
188 const Attr& q = p->getAttr();
189 for( sal_Int32 j = 0; j < q.getLength(); ++j )
191 printf(" ");
192 print_color(33);
193 print_OUString( q.getTypeByIndex(j) );
194 print_color(0);
195 printf("=");
196 print_color(31);
197 printf("'");
198 print_OUString( q.getValueByIndex(j) );
199 printf("'");
200 print_color(0);
202 printf(">");
203 printf("\n");
204 if( !is_empty_string( p->getValue() ) )
206 print_indent( depth+1 );
207 printf("value: ");
208 print_color(31);
209 printf("'");
210 print_OUString( p->getValue() );
211 printf("'");
212 print_color(0);
213 printf("\n");
215 for( sal_Int32 i=0; i<p->getNumberOfChildren(); i++ )
217 print_node( p->getChildAt(i), depth+1 );
219 print_indent( depth );
220 printf("</");
221 print_OUString( p->getName() );
222 printf(">");
223 printf("\n");
226 void LocaleNode::generateCode (const OFileWriter &of) const
228 OUString aDTD = getAttr().getValueByName("versionDTD");
229 if ( aDTD != LOCALE_VERSION_DTD )
231 ++nError;
232 fprintf( stderr, "Error: Locale versionDTD is not %s, see comment in locale.dtd\n", LOCALE_VERSION_DTD);
234 for (sal_Int32 i=0; i<nChildren;i++)
235 children[i]->generateCode (of);
236 // print_node( this );
240 OUString LocaleNode::writeParameterCheckLen( const OFileWriter &of,
241 const char* pParameterName, const LocaleNode* pNode,
242 sal_Int32 nMinLen, sal_Int32 nMaxLen ) const
244 OUString aVal;
245 if (pNode)
246 aVal = pNode->getValue();
247 else
249 ++nError;
250 fprintf( stderr, "Error: node NULL pointer for parameter %s.\n",
251 pParameterName);
253 // write empty data if error
254 of.writeParameter( pParameterName, aVal);
255 sal_Int32 nLen = aVal.getLength();
256 if (nLen < nMinLen)
258 ++nError;
259 fprintf( stderr, "Error: less than %ld character%s (%ld) in %s '%s'.\n",
260 sal::static_int_cast< long >(nMinLen), (nMinLen > 1 ? "s" : ""),
261 sal::static_int_cast< long >(nLen),
262 (pNode ? OSTR( pNode->getName()) : ""),
263 OSTR( aVal));
265 else if (nLen > nMaxLen && nMaxLen >= 0)
266 fprintf( stderr,
267 "Warning: more than %ld character%s (%ld) in %s %s not supported by application.\n",
268 sal::static_int_cast< long >(nMaxLen), (nMaxLen > 1 ? "s" : ""),
269 sal::static_int_cast< long >(nLen),
270 (pNode ? OSTR( pNode->getName()) : ""),
271 OSTR( aVal));
272 return aVal;
276 OUString LocaleNode::writeParameterCheckLen( const OFileWriter &of,
277 const char* pNodeName, const char* pParameterName,
278 sal_Int32 nMinLen, sal_Int32 nMaxLen ) const
280 OUString aVal;
281 const LocaleNode * pNode = findNode( pNodeName);
282 if (pNode)
283 aVal = writeParameterCheckLen( of, pParameterName, pNode, nMinLen, nMaxLen);
284 else
286 ++nError;
287 fprintf( stderr, "Error: node %s not found.\n", pNodeName);
288 // write empty data if error
289 of.writeParameter( pParameterName, aVal);
291 return aVal;
294 void LocaleNode::incError( const char* pStr ) const
296 ++nError;
297 fprintf( stderr, "Error: %s\n", pStr);
300 void LocaleNode::incError( const OUString& rStr ) const
302 incError( OSTR( rStr));
305 void LocaleNode::incErrorInt( const char* pStr, int nVal ) const
307 ++nError;
308 fprintf( stderr, pStr, nVal);
311 void LocaleNode::incErrorStr( const char* pStr, const OUString& rVal ) const
313 ++nError;
314 fprintf( stderr, pStr, OSTR( rVal));
317 void LocaleNode::incErrorStrStr( const char* pStr, const OUString& rVal1, const OUString& rVal2 ) const
319 ++nError;
320 fprintf(stderr, pStr, OSTR(rVal1), OSTR(rVal2));
323 void LCInfoNode::generateCode (const OFileWriter &of) const
326 const LocaleNode * languageNode = findNode("Language");
327 const LocaleNode * countryNode = findNode("Country");
328 const LocaleNode * variantNode = findNode("Variant");
330 OUString aLanguage;
332 if (languageNode)
334 aLanguage = languageNode->getChildAt(0)->getValue();
335 if (!(aLanguage.getLength() == 2 || aLanguage.getLength() == 3))
336 incErrorStr( "Error: langID '%s' not 2-3 characters\n", aLanguage);
337 of.writeParameter("langID", aLanguage);
338 of.writeParameter("langDefaultName", languageNode->getChildAt(1)->getValue());
340 else
341 incError( "No Language node.");
342 if (countryNode)
344 OUString aCountry( countryNode->getChildAt(0)->getValue());
345 if (!(aCountry.isEmpty() || aCountry.getLength() == 2))
346 incErrorStr( "Error: countryID '%s' not empty or more than 2 characters\n", aCountry);
347 of.writeParameter("countryID", aCountry);
348 of.writeParameter("countryDefaultName", countryNode->getChildAt(1)->getValue());
350 else
351 incError( "No Country node.");
352 if (variantNode)
354 // If given Variant must be at least ll-Ssss and language must be 'qlt'
355 OUString aVariant( variantNode->getValue());
356 if (!(aVariant.isEmpty() || (aVariant.getLength() >= 7 && aVariant.indexOf('-') >= 2)))
357 incErrorStr( "Error: invalid Variant '%s'\n", aVariant);
358 if (!(aVariant.isEmpty() || aLanguage == "qlt"))
359 incErrorStrStr( "Error: Variant '%s' given but Language '%s' is not 'qlt'\n", aVariant, aLanguage);
360 of.writeParameter("Variant", aVariant);
362 else
363 of.writeParameter("Variant", OUString());
364 of.writeAsciiString("\nstatic const sal_Unicode* LCInfoArray[] = {\n");
365 of.writeAsciiString("\tlangID,\n");
366 of.writeAsciiString("\tlangDefaultName,\n");
367 of.writeAsciiString("\tcountryID,\n");
368 of.writeAsciiString("\tcountryDefaultName,\n");
369 of.writeAsciiString("\tVariant\n");
370 of.writeAsciiString("};\n\n");
371 of.writeFunction("getLCInfo_", "0", "LCInfoArray");
375 static OUString aDateSep;
376 static OUString aDecSep;
378 void LCCTYPENode::generateCode (const OFileWriter &of) const
380 const LocaleNode * sepNode = nullptr;
381 OUString useLocale = getAttr().getValueByName("ref");
382 if (!useLocale.isEmpty()) {
383 useLocale = useLocale.replace( '-', '_');
384 of.writeRefFunction("getLocaleItem_", useLocale);
385 return;
387 OUString str = getAttr().getValueByName("unoid");
388 of.writeAsciiString("\n\n");
389 of.writeParameter("LC_CTYPE_Unoid", str);
391 aDateSep =
392 writeParameterCheckLen( of, "DateSeparator", "dateSeparator", 1, 1);
393 OUString aThoSep =
394 writeParameterCheckLen( of, "ThousandSeparator", "thousandSeparator", 1, 1);
395 aDecSep =
396 writeParameterCheckLen( of, "DecimalSeparator", "decimalSeparator", 1, 1);
397 OUString aTimeSep =
398 writeParameterCheckLen( of, "TimeSeparator", "timeSeparator", 1, 1);
399 OUString aTime100Sep =
400 writeParameterCheckLen( of, "Time100SecSeparator", "time100SecSeparator", 1, 1);
401 OUString aListSep =
402 writeParameterCheckLen( of, "ListSeparator", "listSeparator", 1, 1);
404 OUString aLDS;
406 sepNode = findNode("LongDateDayOfWeekSeparator");
407 aLDS = sepNode->getValue();
408 of.writeParameter("LongDateDayOfWeekSeparator", aLDS);
409 if (aLDS == ",")
410 fprintf( stderr, "Warning: %s\n",
411 "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\".");
413 sepNode = findNode("LongDateDaySeparator");
414 aLDS = sepNode->getValue();
415 of.writeParameter("LongDateDaySeparator", aLDS);
416 if (aLDS == "," || aLDS == ".")
417 fprintf( stderr, "Warning: %s\n",
418 "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\".");
420 sepNode = findNode("LongDateMonthSeparator");
421 aLDS = sepNode->getValue();
422 of.writeParameter("LongDateMonthSeparator", aLDS);
423 if (aLDS.isEmpty())
424 fprintf( stderr, "Warning: %s\n",
425 "LongDateMonthSeparator is empty. Usually this is not the case and may lead to concatenated display names like \"Wednesday, May9, 2007\".");
427 sepNode = findNode("LongDateYearSeparator");
428 aLDS = sepNode->getValue();
429 of.writeParameter("LongDateYearSeparator", aLDS);
430 if (aLDS.isEmpty())
431 fprintf( stderr, "Warning: %s\n",
432 "LongDateYearSeparator is empty. Usually this is not the case and may lead to concatenated display names like \"Wednesday, 2007May 9\".");
435 int nSavErr = nError;
436 int nWarn = 0;
437 if (aDateSep == aTimeSep)
438 incError( "DateSeparator equals TimeSeparator.");
439 if (aDecSep == aThoSep)
440 incError( "DecimalSeparator equals ThousandSeparator.");
441 if ( aThoSep == " " )
442 incError( "ThousandSeparator is an ' ' ordinary space, this should be a non-breaking space U+00A0 instead.");
443 if (aListSep == aDecSep)
444 fprintf( stderr, "Warning: %s\n",
445 "ListSeparator equals DecimalSeparator.");
446 if (aListSep == aThoSep)
447 fprintf( stderr, "Warning: %s\n",
448 "ListSeparator equals ThousandSeparator.");
449 if (aListSep.getLength() != 1 || aListSep[0] != ';')
451 incError( "ListSeparator not ';' semicolon. Strongly recommended. Currently required.");
452 ++nSavErr; // format codes not affected
454 if (aTimeSep == aTime100Sep)
456 ++nWarn;
457 fprintf( stderr, "Warning: %s\n",
458 "Time100SecSeparator equals TimeSeparator, this is probably an error.");
460 if (aDecSep != aTime100Sep)
462 ++nWarn;
463 fprintf( stderr, "Warning: %s\n",
464 "Time100SecSeparator is different from DecimalSeparator, this may be correct or not. Intended?");
466 if (nSavErr != nError || nWarn)
467 fprintf( stderr, "Warning: %s\n",
468 "Don't forget to adapt corresponding FormatCode elements when changing separators.");
470 OUString aQuoteStart =
471 writeParameterCheckLen( of, "QuotationStart", "quotationStart", 1, 1);
472 OUString aQuoteEnd =
473 writeParameterCheckLen( of, "QuotationEnd", "quotationEnd", 1, 1);
474 OUString aDoubleQuoteStart =
475 writeParameterCheckLen( of, "DoubleQuotationStart", "doubleQuotationStart", 1, 1);
476 OUString aDoubleQuoteEnd =
477 writeParameterCheckLen( of, "DoubleQuotationEnd", "doubleQuotationEnd", 1, 1);
479 if (aQuoteStart.toChar() <= 127 && aQuoteEnd.toChar() > 127)
480 fprintf( stderr, "Warning: %s\n",
481 "QuotationStart is an ASCII character but QuotationEnd is not.");
482 if (aQuoteEnd.toChar() <= 127 && aQuoteStart.toChar() > 127)
483 fprintf( stderr, "Warning: %s\n",
484 "QuotationEnd is an ASCII character but QuotationStart is not.");
485 if (aDoubleQuoteStart.toChar() <= 127 && aDoubleQuoteEnd.toChar() > 127)
486 fprintf( stderr, "Warning: %s\n",
487 "DoubleQuotationStart is an ASCII character but DoubleQuotationEnd is not.");
488 if (aDoubleQuoteEnd.toChar() <= 127 && aDoubleQuoteStart.toChar() > 127)
489 fprintf( stderr, "Warning: %s\n",
490 "DoubleQuotationEnd is an ASCII character but DoubleQuotationStart is not.");
491 if (aQuoteStart.toChar() <= 127 && aQuoteEnd.toChar() <= 127)
492 fprintf( stderr, "Warning: %s\n",
493 "QuotationStart and QuotationEnd are both ASCII characters. Not necessarily an issue, but unusual.");
494 if (aDoubleQuoteStart.toChar() <= 127 && aDoubleQuoteEnd.toChar() <= 127)
495 fprintf( stderr, "Warning: %s\n",
496 "DoubleQuotationStart and DoubleQuotationEnd are both ASCII characters. Not necessarily an issue, but unusual.");
497 if (aQuoteStart == aQuoteEnd)
498 fprintf( stderr, "Warning: %s\n",
499 "QuotationStart equals QuotationEnd. Not necessarily an issue, but unusual.");
500 if (aDoubleQuoteStart == aDoubleQuoteEnd)
501 fprintf( stderr, "Warning: %s\n",
502 "DoubleQuotationStart equals DoubleQuotationEnd. Not necessarily an issue, but unusual.");
503 /* TODO: should equalness of single and double quotes be an error? Would
504 * need to adapt quite some locales' data. */
505 if (aQuoteStart == aDoubleQuoteStart)
506 fprintf( stderr, "Warning: %s\n",
507 "QuotationStart equals DoubleQuotationStart. Not necessarily an issue, but unusual.");
508 if (aQuoteEnd == aDoubleQuoteEnd)
509 fprintf( stderr, "Warning: %s\n",
510 "QuotationEnd equals DoubleQuotationEnd. Not necessarily an issue, but unusual.");
511 // Known good values, exclude ASCII single (U+0027, ') and double (U+0022, ") quotes.
512 switch (int ic = aQuoteStart.toChar())
514 case 0x2018: // LEFT SINGLE QUOTATION MARK
515 case 0x201a: // SINGLE LOW-9 QUOTATION MARK
516 case 0x201b: // SINGLE HIGH-REVERSED-9 QUOTATION MARK
517 case 0x2039: // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
518 case 0x203a: // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
519 case 0x300c: // LEFT CORNER BRACKET (Chinese)
521 break;
522 default:
523 fprintf( stderr, "Warning: %s U+%04X %s\n",
524 "QuotationStart may be wrong:", ic, OSTR( aQuoteStart));
526 switch (int ic = aQuoteEnd.toChar())
528 case 0x2019: // RIGHT SINGLE QUOTATION MARK
529 case 0x201a: // SINGLE LOW-9 QUOTATION MARK
530 case 0x201b: // SINGLE HIGH-REVERSED-9 QUOTATION MARK
531 case 0x2039: // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
532 case 0x203a: // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
533 case 0x300d: // RIGHT CORNER BRACKET (Chinese)
535 break;
536 default:
537 fprintf( stderr, "Warning: %s U+%04X %s\n",
538 "QuotationEnd may be wrong:", ic, OSTR( aQuoteEnd));
540 switch (int ic = aDoubleQuoteStart.toChar())
542 case 0x00ab: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
543 case 0x00bb: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
544 case 0x201c: // LEFT DOUBLE QUOTATION MARK
545 case 0x201e: // DOUBLE LOW-9 QUOTATION MARK
546 case 0x201f: // DOUBLE HIGH-REVERSED-9 QUOTATION MARK
547 case 0x300e: // LEFT WHITE CORNER BRACKET (Chinese)
549 break;
550 default:
551 fprintf( stderr, "Warning: %s U+%04X %s\n",
552 "DoubleQuotationStart may be wrong:", ic, OSTR( aDoubleQuoteStart));
554 switch (int ic = aDoubleQuoteEnd.toChar())
556 case 0x00ab: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
557 case 0x00bb: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
558 case 0x201d: // RIGHT DOUBLE QUOTATION MARK
559 case 0x201e: // DOUBLE LOW-9 QUOTATION MARK
560 case 0x201f: // DOUBLE HIGH-REVERSED-9 QUOTATION MARK
561 case 0x300f: // RIGHT WHITE CORNER BRACKET (Chinese)
563 break;
564 default:
565 fprintf( stderr, "Warning: %s U+%04X %s\n",
566 "DoubleQuotationEnd may be wrong:", ic, OSTR( aDoubleQuoteEnd));
569 writeParameterCheckLen( of, "TimeAM", "timeAM", 1, -1);
570 writeParameterCheckLen( of, "TimePM", "timePM", 1, -1);
571 sepNode = findNode("MeasurementSystem");
572 of.writeParameter("measurementSystem", sepNode->getValue());
574 of.writeAsciiString("\nstatic const sal_Unicode* LCType[] = {\n");
575 of.writeAsciiString("\tLC_CTYPE_Unoid,\n");
576 of.writeAsciiString("\tdateSeparator,\n");
577 of.writeAsciiString("\tthousandSeparator,\n");
578 of.writeAsciiString("\tdecimalSeparator,\n");
579 of.writeAsciiString("\ttimeSeparator,\n");
580 of.writeAsciiString("\ttime100SecSeparator,\n");
581 of.writeAsciiString("\tlistSeparator,\n");
582 of.writeAsciiString("\tquotationStart,\n");
583 of.writeAsciiString("\tquotationEnd,\n");
584 of.writeAsciiString("\tdoubleQuotationStart,\n");
585 of.writeAsciiString("\tdoubleQuotationEnd,\n");
586 of.writeAsciiString("\ttimeAM,\n");
587 of.writeAsciiString("\ttimePM,\n");
588 of.writeAsciiString("\tmeasurementSystem,\n");
589 of.writeAsciiString("\tLongDateDayOfWeekSeparator,\n");
590 of.writeAsciiString("\tLongDateDaySeparator,\n");
591 of.writeAsciiString("\tLongDateMonthSeparator,\n");
592 of.writeAsciiString("\tLongDateYearSeparator\n");
593 of.writeAsciiString("};\n\n");
594 of.writeFunction("getLocaleItem_", "0", "LCType");
598 static OUString sTheCurrencyReplaceTo;
599 static OUString sTheCompatibleCurrency;
600 static OUString sTheDateEditFormat;
602 sal_Int16 LCFormatNode::mnSection = 0;
603 sal_Int16 LCFormatNode::mnFormats = 0;
605 void LCFormatNode::generateCode (const OFileWriter &of) const
607 if (mnSection >= 2)
608 incError("more than 2 LC_FORMAT sections");
610 ::std::vector< OUString > theDateAcceptancePatterns;
612 OUString useLocale(getAttr().getValueByName("ref"));
614 OUString str;
615 OUString strFrom( getAttr().getValueByName("replaceFrom"));
616 if (useLocale.isEmpty())
618 of.writeParameter("replaceFrom", strFrom, mnSection);
620 str = getAttr().getValueByName("replaceTo");
621 if (!strFrom.isEmpty() && str.isEmpty())
622 incErrorStr("replaceFrom=\"%s\" replaceTo=\"\" is empty replacement.\n", strFrom);
623 // Locale data generator inserts FFFF for LangID, we need to adapt that.
624 if (str.endsWithIgnoreAsciiCase( "-FFFF]"))
625 incErrorStr("replaceTo=\"%s\" needs FFFF to be adapted to the real LangID value.\n", str);
626 of.writeParameter("replaceTo", str, mnSection);
627 // Remember the replaceTo value for "[CURRENCY]" to check format codes.
628 if ( strFrom == "[CURRENCY]" )
629 sTheCurrencyReplaceTo = str;
630 // Remember the currency symbol if present.
631 if (str.startsWith( "[$" ))
633 sal_Int32 nHyphen = str.indexOf( '-');
634 if (nHyphen >= 3)
636 sTheCompatibleCurrency = str.copy( 2, nHyphen - 2);
640 if (!useLocale.isEmpty())
642 if (!strFrom.isEmpty() && strFrom != "[CURRENCY]") //???
644 incErrorStrStr(
645 "Error: non-empty replaceFrom=\"%s\" with non-empty ref=\"%s\".",
646 strFrom, useLocale);
648 useLocale = useLocale.replace( '-', '_');
649 switch (mnSection)
651 case 0:
652 of.writeRefFunction("getAllFormats0_", useLocale, "replaceTo0");
653 break;
654 case 1:
655 of.writeRefFunction("getAllFormats1_", useLocale, "replaceTo1");
656 break;
658 of.writeRefFunction("getDateAcceptancePatterns_", useLocale);
659 return;
662 sal_Int16 formatCount = mnFormats;
663 NameSet aMsgIdSet;
664 ValueSet aFormatIndexSet;
665 NameSet aDefaultsSet;
666 bool bCtypeIsRef = false;
667 bool bHaveEngineering = false;
669 for (sal_Int32 i = 0; i< getNumberOfChildren() ; i++, formatCount++)
671 LocaleNode * currNode = getChildAt (i);
672 if ( currNode->getName() == "DateAcceptancePattern" )
674 if (mnSection > 0)
675 incError( "DateAcceptancePattern only handled in LC_FORMAT, not LC_FORMAT_1");
676 else
677 theDateAcceptancePatterns.push_back( currNode->getValue());
678 --formatCount;
679 continue; // for
681 if ( currNode->getName() != "FormatElement" )
683 incErrorStr( "Error: Undefined element '%s' in LC_FORMAT\n", currNode->getName());
684 --formatCount;
685 continue; // for
688 OUString aUsage;
689 OUString aType;
690 OUString aFormatIndex;
691 // currNode -> print();
692 const Attr &currNodeAttr = currNode->getAttr();
693 //printf ("getLen() = %d\n", currNode->getAttr().getLength());
695 str = currNodeAttr.getValueByName("msgid");
696 if (!aMsgIdSet.insert( str).second)
697 incErrorStr( "Error: Duplicated msgid=\"%s\" in FormatElement.\n", str);
698 of.writeParameter("FormatKey", str, formatCount);
700 str = currNodeAttr.getValueByName("default");
701 bool bDefault = str == "true";
702 of.writeDefaultParameter("FormatElement", str, formatCount);
704 aType = currNodeAttr.getValueByName("type");
705 of.writeParameter("FormatType", aType, formatCount);
707 aUsage = currNodeAttr.getValueByName("usage");
708 of.writeParameter("FormatUsage", aUsage, formatCount);
710 aFormatIndex = currNodeAttr.getValueByName("formatindex");
711 sal_Int16 formatindex = (sal_Int16)aFormatIndex.toInt32();
712 // Ensure the new reserved range is not used anymore, free usage start
713 // was up'ed from 50 to 60.
714 if (50 <= formatindex && formatindex < 60)
715 incErrorInt( "Error: Reserved formatindex=\"%d\" in FormatElement, free usage starts at 60.\n", formatindex);
716 if (!aFormatIndexSet.insert( formatindex).second)
717 incErrorInt( "Error: Duplicated formatindex=\"%d\" in FormatElement.\n", formatindex);
718 of.writeIntParameter("Formatindex", formatCount, formatindex);
720 // Ensure only one default per usage and type.
721 if (bDefault)
723 OUString aKey( aUsage + "," + aType);
724 if (!aDefaultsSet.insert( aKey).second)
726 OUString aStr( "Duplicated default for usage=\"");
727 aStr += aUsage;
728 aStr += "\" type=\"";
729 aStr += aType;
730 aStr += "\": formatindex=\"";
731 aStr += aFormatIndex;
732 aStr += "\".";
733 incError( aStr);
737 const LocaleNode * n = currNode -> findNode("FormatCode");
738 if (n)
740 of.writeParameter("FormatCode", n->getValue(), formatCount);
741 // Check separator usage for some FormatCode elements.
742 const LocaleNode* pCtype = nullptr;
743 switch (formatindex)
745 case cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY :
746 sTheDateEditFormat = n->getValue();
747 break;
748 case cssi::NumberFormatIndex::NUMBER_1000DEC2 : // #,##0.00
749 case cssi::NumberFormatIndex::TIME_MMSS00 : // MM:SS.00
750 case cssi::NumberFormatIndex::TIME_HH_MMSS00 : // [HH]:MM:SS.00
752 const LocaleNode* pRoot = getRoot();
753 if (!pRoot)
754 incError( "No root for FormatCode.");
755 else
757 pCtype = pRoot->findNode( "LC_CTYPE");
758 if (!pCtype)
759 incError( "No LC_CTYPE found for FormatCode.");
760 else
762 OUString aRef( pCtype->getAttr().getValueByName("ref"));
763 if (!aRef.isEmpty())
765 aRef = aRef.replace( '-', '_');
766 if (!bCtypeIsRef)
767 fprintf( stderr,
768 "Warning: Can't check separators used in FormatCode due to LC_CTYPE ref=\"%s\".\n"
769 "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",
770 OSTR( aRef));
771 bCtypeIsRef = true;
772 pCtype = nullptr;
777 break;
778 case cssi::NumberFormatIndex::CURRENCY_1000DEC2 :
779 // Remember the currency symbol if present.
781 sal_Int32 nStart;
782 if (sTheCompatibleCurrency.isEmpty() &&
783 ((nStart = n->getValue().indexOf("[$")) >= 0))
785 OUString aCode( n->getValue());
786 sal_Int32 nHyphen = aCode.indexOf( '-', nStart);
787 if (nHyphen >= nStart + 3)
788 sTheCompatibleCurrency = aCode.copy( nStart + 2, nHyphen - nStart - 2);
791 SAL_FALLTHROUGH;
792 case cssi::NumberFormatIndex::CURRENCY_1000INT :
793 case cssi::NumberFormatIndex::CURRENCY_1000INT_RED :
794 case cssi::NumberFormatIndex::CURRENCY_1000DEC2_RED :
795 case cssi::NumberFormatIndex::CURRENCY_1000DEC2_CCC :
796 case cssi::NumberFormatIndex::CURRENCY_1000DEC2_DASHED :
797 // Currency formats should be something like [C]###0;-[C]###0
798 // and not parenthesized [C]###0;([C]###0) if not en_US.
799 if (strcmp( of.getLocale(), "en_US") != 0)
801 OUString aCode( n->getValue());
802 OUString aPar1( "0)");
803 OUString aPar2( "-)" );
804 OUString aPar3( " )" );
805 OUString aPar4( "])" );
806 if (aCode.indexOf( aPar1 ) > 0 || aCode.indexOf( aPar2 ) > 0 ||
807 aCode.indexOf( aPar3 ) > 0 || aCode.indexOf( aPar4 ) > 0)
808 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);
810 // Check if we have replaceTo for "[CURRENCY]" placeholder.
811 if (sTheCurrencyReplaceTo.isEmpty())
813 OUString aCode( n->getValue());
814 if (aCode.indexOf( "[CURRENCY]" ) >= 0)
815 incErrorInt( "Error: [CURRENCY] replaceTo not found for formatindex=\"%d\".\n", formatindex);
817 break;
818 default:
819 if (aUsage == "SCIENTIFIC_NUMBER")
821 // Check for presence of ##0.00E+00
822 OUString aCode( n->getValue());
823 // Simple check without decimal separator (assumed to
824 // be one UTF-16 character). May be prefixed with
825 // [NatNum1] or other tags.
826 sal_Int32 nInt = aCode.indexOf("##0");
827 sal_Int32 nDec = (nInt < 0 ? -1 : aCode.indexOf("00E+00", nInt));
828 if (nInt >= 0 && nDec == nInt+4)
829 bHaveEngineering = true;
831 break;
833 if (pCtype)
835 int nSavErr = nError;
836 OUString aCode( n->getValue());
837 if (formatindex == cssi::NumberFormatIndex::NUMBER_1000DEC2)
839 sal_Int32 nDec = -1;
840 sal_Int32 nGrp = -1;
841 const LocaleNode* pSep = pCtype->findNode( "DecimalSeparator");
842 if (!pSep)
843 incError( "No DecimalSeparator found for FormatCode.");
844 else
846 nDec = aCode.indexOf( pSep->getValue());
847 if (nDec < 0)
848 incErrorInt( "Error: DecimalSeparator not present in FormatCode formatindex=\"%d\".\n",
849 formatindex);
851 pSep = pCtype->findNode( "ThousandSeparator");
852 if (!pSep)
853 incError( "No ThousandSeparator found for FormatCode.");
854 else
856 nGrp = aCode.indexOf( pSep->getValue());
857 if (nGrp < 0)
858 incErrorInt( "Error: ThousandSeparator not present in FormatCode formatindex=\"%d\".\n",
859 formatindex);
861 if (nDec >= 0 && nGrp >= 0 && nDec <= nGrp)
862 incErrorInt( "Error: Ordering of ThousandSeparator and DecimalSeparator not correct in formatindex=\"%d\".\n",
863 formatindex);
865 if (formatindex == cssi::NumberFormatIndex::TIME_MMSS00 ||
866 formatindex == cssi::NumberFormatIndex::TIME_HH_MMSS00)
868 sal_Int32 nTime = -1;
869 sal_Int32 n100s = -1;
870 const LocaleNode* pSep = pCtype->findNode( "TimeSeparator");
871 if (!pSep)
872 incError( "No TimeSeparator found for FormatCode.");
873 else
875 nTime = aCode.indexOf( pSep->getValue());
876 if (nTime < 0)
877 incErrorInt( "Error: TimeSeparator not present in FormatCode formatindex=\"%d\".\n",
878 formatindex);
880 pSep = pCtype->findNode( "Time100SecSeparator");
881 if (!pSep)
882 incError( "No Time100SecSeparator found for FormatCode.");
883 else
885 n100s = aCode.indexOf( pSep->getValue());
886 if (n100s < 0)
887 incErrorInt( "Error: Time100SecSeparator not present in FormatCode formatindex=\"%d\".\n",
888 formatindex);
889 OUStringBuffer a100s( pSep->getValue());
890 a100s.append( "00");
891 n100s = aCode.indexOf( a100s.makeStringAndClear());
892 if (n100s < 0)
893 incErrorInt( "Error: Time100SecSeparator+00 not present in FormatCode formatindex=\"%d\".\n",
894 formatindex);
896 if (n100s >= 0 && nTime >= 0 && n100s <= nTime)
897 incErrorInt( "Error: Ordering of Time100SecSeparator and TimeSeparator not correct in formatindex=\"%d\".\n",
898 formatindex);
900 if (nSavErr != nError)
901 fprintf( stderr,
902 "Warning: formatindex=\"%d\",\"%d\",\"%d\" are the only FormatCode elements checked for separator usage, there may be others that have errors.\n",
903 int(cssi::NumberFormatIndex::NUMBER_1000DEC2),
904 int(cssi::NumberFormatIndex::TIME_MMSS00),
905 int(cssi::NumberFormatIndex::TIME_HH_MMSS00));
909 else
910 incError( "No FormatCode in FormatElement.");
911 n = currNode -> findNode("DefaultName");
912 if (n)
913 of.writeParameter("FormatDefaultName", n->getValue(), formatCount);
914 else
915 of.writeParameter("FormatDefaultName", OUString(), formatCount);
919 // Check presence of all required format codes only in first section
920 // LC_FORMAT, not in optional LC_FORMAT_1
921 if (mnSection == 0)
923 // At least one abbreviated date acceptance pattern must be present.
924 if (theDateAcceptancePatterns.empty())
925 incError( "No DateAcceptancePattern present.\n");
926 else
928 bool bHaveAbbr = false;
929 for (::std::vector< OUString >::const_iterator it( theDateAcceptancePatterns.begin());
930 !bHaveAbbr && it != theDateAcceptancePatterns.end(); ++it)
932 if ((*it).indexOf('D') > -1 && (*it).indexOf('M') > -1 && (*it).indexOf('Y') <= -1)
933 bHaveAbbr = true;
935 if (!bHaveAbbr)
936 incError( "No abbreviated DateAcceptancePattern present. For example M/D or D.M.\n");
939 // 0..47 MUST be present, 48,49 MUST NOT be present
940 ValueSet::const_iterator aIter( aFormatIndexSet.begin());
941 for (sal_Int16 nNext = cssi::NumberFormatIndex::NUMBER_START;
942 nNext < cssi::NumberFormatIndex::INDEX_TABLE_ENTRIES; ++nNext)
944 sal_Int16 nHere = ::std::min( ((aIter != aFormatIndexSet.end() ? *aIter :
945 cssi::NumberFormatIndex::INDEX_TABLE_ENTRIES)),
946 cssi::NumberFormatIndex::INDEX_TABLE_ENTRIES);
947 if (aIter != aFormatIndexSet.end()) ++aIter;
948 for ( ; nNext < nHere; ++nNext)
950 switch (nNext)
952 case cssi::NumberFormatIndex::FRACTION_1 :
953 case cssi::NumberFormatIndex::FRACTION_2 :
954 case cssi::NumberFormatIndex::BOOLEAN :
955 case cssi::NumberFormatIndex::TEXT :
956 // generated internally
957 break;
958 default:
959 incErrorInt( "Error: FormatElement formatindex=\"%d\" not present.\n", nNext);
962 switch (nHere)
964 case cssi::NumberFormatIndex::BOOLEAN :
965 incErrorInt( "Error: FormatElement formatindex=\"%d\" reserved for internal ``BOOLEAN''.\n", nNext);
966 break;
967 case cssi::NumberFormatIndex::TEXT :
968 incErrorInt( "Error: FormatElement formatindex=\"%d\" reserved for internal ``@'' (TEXT).\n", nNext);
969 break;
970 default:
971 ; // nothing
975 if (!bHaveEngineering)
976 incError("Engineering notation format not present, e.g. ##0.00E+00 or ##0,00E+00 for usage=\"SCIENTIFIC_NUMBER\"\n");
979 of.writeAsciiString("\nstatic const sal_Int16 ");
980 of.writeAsciiString("FormatElementsCount");
981 of.writeInt(mnSection);
982 of.writeAsciiString(" = ");
983 of.writeInt( formatCount - mnFormats);
984 of.writeAsciiString(";\n");
985 of.writeAsciiString("static const sal_Unicode* ");
986 of.writeAsciiString("FormatElementsArray");
987 of.writeInt(mnSection);
988 of.writeAsciiString("[] = {\n");
989 for(sal_Int16 i = mnFormats; i < formatCount; i++) {
991 of.writeAsciiString("\t");
992 of.writeAsciiString("FormatCode");
993 of.writeInt(i);
994 of.writeAsciiString(",\n");
996 of.writeAsciiString("\t");
997 of.writeAsciiString("FormatDefaultName");
998 of.writeInt(i);
999 of.writeAsciiString(",\n");
1001 of.writeAsciiString("\t");
1002 of.writeAsciiString("FormatKey");
1003 of.writeInt(i);
1004 of.writeAsciiString(",\n");
1006 of.writeAsciiString("\t");
1007 of.writeAsciiString("FormatType");
1008 of.writeInt(i);
1009 of.writeAsciiString(",\n");
1011 of.writeAsciiString("\t");
1012 of.writeAsciiString("FormatUsage");
1013 of.writeInt(i);
1014 of.writeAsciiString(",\n");
1016 of.writeAsciiString("\t");
1017 of.writeAsciiString("Formatindex");
1018 of.writeInt(i);
1019 of.writeAsciiString(",\n");
1022 of.writeAsciiString("\tdefaultFormatElement");
1023 of.writeInt(i);
1024 of.writeAsciiString(",\n");
1026 of.writeAsciiString("};\n\n");
1028 switch (mnSection)
1030 case 0:
1031 of.writeFunction("getAllFormats0_", "FormatElementsCount0", "FormatElementsArray0", "replaceFrom0", "replaceTo0");
1032 break;
1033 case 1:
1034 of.writeFunction("getAllFormats1_", "FormatElementsCount1", "FormatElementsArray1", "replaceFrom1", "replaceTo1");
1035 break;
1038 mnFormats = mnFormats + formatCount;
1040 if (mnSection == 0)
1042 // Extract and add date acceptance pattern for full date, so we provide
1043 // at least one valid pattern, even if the number parser doesn't need
1044 // that one.
1045 /* XXX NOTE: only simple [...] modifier and "..." quotes detected and
1046 * ignored, not nested, no fancy stuff. */
1047 sal_Int32 nIndex = 0;
1048 // aDateSep can be empty if LC_CTYPE was a ref=..., determine from
1049 // FormatCode then.
1050 sal_uInt32 cDateSep = (aDateSep.isEmpty() ? 0 : aDateSep.iterateCodePoints( &nIndex));
1051 sal_uInt32 cDateSep2 = cDateSep;
1052 nIndex = 0;
1053 OUStringBuffer aPatternBuf(5);
1054 OUStringBuffer aPatternBuf2(5);
1055 sal_uInt8 nDetected = 0; // bits Y,M,D
1056 bool bInModifier = false;
1057 bool bQuoted = false;
1058 while (nIndex < sTheDateEditFormat.getLength() && nDetected < 7)
1060 sal_uInt32 cChar = sTheDateEditFormat.iterateCodePoints( &nIndex);
1061 if (bInModifier)
1063 if (cChar == ']')
1064 bInModifier = false;
1065 continue; // while
1067 if (bQuoted)
1069 if (cChar == '"')
1070 bQuoted = false;
1071 continue; // while
1073 switch (cChar)
1075 case 'Y':
1076 case 'y':
1077 if (!(nDetected & 4))
1079 aPatternBuf.append( 'Y');
1080 if (!aPatternBuf2.isEmpty())
1081 aPatternBuf2.append( 'Y');
1082 nDetected |= 4;
1084 break;
1085 case 'M':
1086 case 'm':
1087 if (!(nDetected & 2))
1089 aPatternBuf.append( 'M');
1090 if (!aPatternBuf2.isEmpty())
1091 aPatternBuf2.append( 'M');
1092 nDetected |= 2;
1094 break;
1095 case 'D':
1096 case 'd':
1097 if (!(nDetected & 1))
1099 aPatternBuf.append( 'D');
1100 if (!aPatternBuf2.isEmpty())
1101 aPatternBuf2.append( 'D');
1102 nDetected |= 1;
1104 break;
1105 case '[':
1106 bInModifier = true;
1107 break;
1108 case '"':
1109 bQuoted = true;
1110 break;
1111 case '\\':
1112 cChar = sTheDateEditFormat.iterateCodePoints( &nIndex);
1113 goto handleDefault;
1114 case '-':
1115 case '.':
1116 case '/':
1117 // There are locales that use an ISO 8601 edit format
1118 // regardless of what the date separator or other formats
1119 // say, for example hu-HU. Generalize this for all cases
1120 // where the used separator differs and is one of the known
1121 // separators and generate a second pattern with the
1122 // format's separator at the current position.
1123 cDateSep2 = cChar;
1124 SAL_FALLTHROUGH;
1125 default:
1126 handleDefault:
1127 if (!cDateSep)
1128 cDateSep = cChar;
1129 if (!cDateSep2)
1130 cDateSep2 = cChar;
1131 if (cDateSep != cDateSep2 && aPatternBuf2.isEmpty())
1132 aPatternBuf2 = aPatternBuf;
1133 if (cChar == cDateSep || cChar == cDateSep2)
1134 aPatternBuf.append( OUString( &cDateSep, 1)); // always the defined separator
1135 if (cChar == cDateSep2 && !aPatternBuf2.isEmpty())
1136 aPatternBuf2.append( OUString( &cDateSep2, 1)); // always the format's separator
1137 break;
1138 // The localized legacy:
1139 case 'A':
1140 if (((nDetected & 7) == 3) || ((nDetected & 7) == 0))
1142 // es DD/MM/AAAA
1143 // fr JJ.MM.AAAA
1144 // it GG/MM/AAAA
1145 // fr_CA AAAA-MM-JJ
1146 aPatternBuf.append( 'Y');
1147 if (!aPatternBuf2.isEmpty())
1148 aPatternBuf2.append( 'Y');
1149 nDetected |= 4;
1151 break;
1152 case 'J':
1153 if (((nDetected & 7) == 0) || ((nDetected & 7) == 6))
1155 // fr JJ.MM.AAAA
1156 // fr_CA AAAA-MM-JJ
1157 aPatternBuf.append( 'D');
1158 if (!aPatternBuf2.isEmpty())
1159 aPatternBuf2.append( 'D');
1160 nDetected |= 1;
1162 else if ((nDetected & 7) == 3)
1164 // nl DD-MM-JJJJ
1165 // de TT.MM.JJJJ
1166 aPatternBuf.append( 'Y');
1167 if (!aPatternBuf2.isEmpty())
1168 aPatternBuf2.append( 'Y');
1169 nDetected |= 4;
1171 break;
1172 case 'T':
1173 if ((nDetected & 7) == 0)
1175 // de TT.MM.JJJJ
1176 aPatternBuf.append( 'D');
1177 if (!aPatternBuf2.isEmpty())
1178 aPatternBuf2.append( 'D');
1179 nDetected |= 1;
1181 break;
1182 case 'G':
1183 if ((nDetected & 7) == 0)
1185 // it GG/MM/AAAA
1186 aPatternBuf.append( 'D');
1187 if (!aPatternBuf2.isEmpty())
1188 aPatternBuf2.append( 'D');
1189 nDetected |= 1;
1191 break;
1192 case 'P':
1193 if ((nDetected & 7) == 0)
1195 // fi PP.KK.VVVV
1196 aPatternBuf.append( 'D');
1197 if (!aPatternBuf2.isEmpty())
1198 aPatternBuf2.append( 'D');
1199 nDetected |= 1;
1201 break;
1202 case 'K':
1203 if ((nDetected & 7) == 1)
1205 // fi PP.KK.VVVV
1206 aPatternBuf.append( 'M');
1207 if (!aPatternBuf2.isEmpty())
1208 aPatternBuf2.append( 'M');
1209 nDetected |= 2;
1211 break;
1212 case 'V':
1213 if ((nDetected & 7) == 3)
1215 // fi PP.KK.VVVV
1216 aPatternBuf.append( 'Y');
1217 if (!aPatternBuf2.isEmpty())
1218 aPatternBuf2.append( 'Y');
1219 nDetected |= 4;
1221 break;
1224 OUString aPattern( aPatternBuf.makeStringAndClear());
1225 if (((nDetected & 7) != 7) || aPattern.getLength() < 5)
1227 incErrorStr( "Error: failed to extract full date acceptance pattern: %s\n", aPattern);
1228 fprintf( stderr, " with DateSeparator '%s' from FormatCode '%s' (formatindex=\"%d\")\n",
1229 OSTR( OUString(&cDateSep, 1)), OSTR( sTheDateEditFormat),
1230 (int)cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY);
1232 else
1234 fprintf( stderr, "Generated date acceptance pattern: '%s' from '%s' (formatindex=\"%d\" and defined DateSeparator '%s')\n",
1235 OSTR( aPattern), OSTR( sTheDateEditFormat),
1236 (int)cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY,
1237 OSTR( OUString(&cDateSep, 1)));
1238 // Insert at front so full date pattern is first in checks.
1239 theDateAcceptancePatterns.insert( theDateAcceptancePatterns.begin(), aPattern);
1241 if (!aPatternBuf2.isEmpty())
1243 OUString aPattern2( aPatternBuf2.makeStringAndClear());
1244 if (aPattern2.getLength() < 5)
1246 incErrorStr( "Error: failed to extract 2nd date acceptance pattern: %s\n", aPattern2);
1247 fprintf( stderr, " with DateSeparator '%s' from FormatCode '%s' (formatindex=\"%d\")\n",
1248 OSTR( OUString(&cDateSep2, 1)), OSTR( sTheDateEditFormat),
1249 (int)cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY);
1251 else
1253 fprintf( stderr, "Generated 2nd acceptance pattern: '%s' from '%s' (formatindex=\"%d\")\n",
1254 OSTR( aPattern2), OSTR( sTheDateEditFormat),
1255 (int)cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY);
1256 theDateAcceptancePatterns.insert( theDateAcceptancePatterns.begin(), aPattern2);
1260 // Rudimentary check if a pattern interferes with decimal number.
1261 // But only if not inherited in which case we don't have aDecSep here.
1262 if (!aDecSep.isEmpty())
1264 nIndex = 0;
1265 sal_uInt32 cDecSep = aDecSep.iterateCodePoints( &nIndex);
1266 for (vector<OUString>::const_iterator aIt = theDateAcceptancePatterns.begin();
1267 aIt != theDateAcceptancePatterns.end(); ++aIt)
1269 if ((*aIt).getLength() == (cDecSep <= 0xffff ? 3 : 4))
1271 nIndex = 1;
1272 if ((*aIt).iterateCodePoints( &nIndex) == cDecSep)
1274 ++nError;
1275 fprintf( stderr, "Error: Date acceptance pattern '%s' matches decimal number '#%s#'\n",
1276 OSTR( *aIt), OSTR( aDecSep));
1282 // Check for duplicates.
1283 for (vector<OUString>::const_iterator aIt = theDateAcceptancePatterns.begin();
1284 aIt != theDateAcceptancePatterns.end(); ++aIt)
1286 for (vector<OUString>::iterator aComp = theDateAcceptancePatterns.begin();
1287 aComp != theDateAcceptancePatterns.end(); /*nop*/)
1289 if (aIt != aComp && *aIt == *aComp)
1291 incErrorStr( "Error: Duplicated DateAcceptancePattern: %s\n", *aComp);
1292 aComp = theDateAcceptancePatterns.erase( aComp);
1294 else
1295 ++aComp;
1299 sal_Int16 nbOfDateAcceptancePatterns = static_cast<sal_Int16>(theDateAcceptancePatterns.size());
1301 for (sal_Int16 i = 0; i < nbOfDateAcceptancePatterns; ++i)
1303 of.writeParameter("DateAcceptancePattern", theDateAcceptancePatterns[i], i);
1306 of.writeAsciiString("static const sal_Int16 DateAcceptancePatternsCount = ");
1307 of.writeInt( nbOfDateAcceptancePatterns);
1308 of.writeAsciiString(";\n");
1310 of.writeAsciiString("static const sal_Unicode* DateAcceptancePatternsArray[] = {\n");
1311 for (sal_Int16 i = 0; i < nbOfDateAcceptancePatterns; ++i)
1313 of.writeAsciiString("\t");
1314 of.writeAsciiString("DateAcceptancePattern");
1315 of.writeInt(i);
1316 of.writeAsciiString(",\n");
1318 of.writeAsciiString("};\n\n");
1320 of.writeFunction("getDateAcceptancePatterns_", "DateAcceptancePatternsCount", "DateAcceptancePatternsArray");
1323 ++mnSection;
1326 void LCCollationNode::generateCode (const OFileWriter &of) const
1328 OUString useLocale = getAttr().getValueByName("ref");
1329 if (!useLocale.isEmpty()) {
1330 useLocale = useLocale.replace( '-', '_');
1331 of.writeRefFunction("getCollatorImplementation_", useLocale);
1332 of.writeRefFunction("getCollationOptions_", useLocale);
1333 return;
1335 sal_Int16 nbOfCollations = 0;
1336 sal_Int16 nbOfCollationOptions = 0;
1337 sal_Int16 j;
1339 for ( j = 0; j < getNumberOfChildren(); j++ ) {
1340 LocaleNode * currNode = getChildAt (j);
1341 if( currNode->getName() == "Collator" )
1343 OUString str;
1344 str = currNode->getAttr().getValueByName("unoid");
1345 of.writeParameter("CollatorID", str, j);
1346 str = currNode->getValue();
1347 of.writeParameter("CollatorRule", str, j);
1348 str = currNode -> getAttr().getValueByName("default");
1349 of.writeDefaultParameter("Collator", str, j);
1350 of.writeAsciiString("\n");
1352 nbOfCollations++;
1354 if( currNode->getName() == "CollationOptions" )
1356 LocaleNode* pCollationOptions = currNode;
1357 nbOfCollationOptions = sal::static_int_cast<sal_Int16>( pCollationOptions->getNumberOfChildren() );
1358 for( sal_Int16 i=0; i<nbOfCollationOptions; i++ )
1360 of.writeParameter("collationOption", pCollationOptions->getChildAt( i )->getValue(), i );
1363 of.writeAsciiString("static const sal_Int16 nbOfCollationOptions = ");
1364 of.writeInt( nbOfCollationOptions );
1365 of.writeAsciiString(";\n\n");
1368 of.writeAsciiString("static const sal_Int16 nbOfCollations = ");
1369 of.writeInt(nbOfCollations);
1370 of.writeAsciiString(";\n\n");
1372 of.writeAsciiString("\nstatic const sal_Unicode* LCCollatorArray[] = {\n");
1373 for(j = 0; j < nbOfCollations; j++) {
1374 of.writeAsciiString("\tCollatorID");
1375 of.writeInt(j);
1376 of.writeAsciiString(",\n");
1378 of.writeAsciiString("\tdefaultCollator");
1379 of.writeInt(j);
1380 of.writeAsciiString(",\n");
1382 of.writeAsciiString("\tCollatorRule");
1383 of.writeInt(j);
1384 of.writeAsciiString(",\n");
1386 of.writeAsciiString("};\n\n");
1388 of.writeAsciiString("static const sal_Unicode* collationOptions[] = {");
1389 for( j=0; j<nbOfCollationOptions; j++ )
1391 of.writeAsciiString( "collationOption" );
1392 of.writeInt( j );
1393 of.writeAsciiString( ", " );
1395 of.writeAsciiString("NULL };\n");
1396 of.writeFunction("getCollatorImplementation_", "nbOfCollations", "LCCollatorArray");
1397 of.writeFunction("getCollationOptions_", "nbOfCollationOptions", "collationOptions");
1400 void LCSearchNode::generateCode (const OFileWriter &of) const
1402 OUString useLocale = getAttr().getValueByName("ref");
1403 if (!useLocale.isEmpty()) {
1404 useLocale = useLocale.replace( '-', '_');
1405 of.writeRefFunction("getSearchOptions_", useLocale);
1406 return;
1409 if( getNumberOfChildren() != 1 )
1411 ++nError;
1412 fprintf(
1413 stderr, "Error: LC_SEARCH: more than 1 child: %ld\n",
1414 sal::static_int_cast< long >(getNumberOfChildren()));
1416 sal_Int32 i;
1417 LocaleNode* pSearchOptions = getChildAt( 0 );
1418 sal_Int32 nSearchOptions = pSearchOptions->getNumberOfChildren();
1419 for( i=0; i<nSearchOptions; i++ )
1421 of.writeParameter("searchOption", pSearchOptions->getChildAt( i )->getValue(), sal::static_int_cast<sal_Int16>(i) );
1424 of.writeAsciiString("static const sal_Int16 nbOfSearchOptions = ");
1425 of.writeInt( sal::static_int_cast<sal_Int16>( nSearchOptions ) );
1426 of.writeAsciiString(";\n\n");
1428 of.writeAsciiString("static const sal_Unicode* searchOptions[] = {");
1429 for( i=0; i<nSearchOptions; i++ )
1431 of.writeAsciiString( "searchOption" );
1432 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
1433 of.writeAsciiString( ", " );
1435 of.writeAsciiString("NULL };\n");
1436 of.writeFunction("getSearchOptions_", "nbOfSearchOptions", "searchOptions");
1439 void LCIndexNode::generateCode (const OFileWriter &of) const
1441 OUString useLocale = getAttr().getValueByName("ref");
1442 if (!useLocale.isEmpty()) {
1443 useLocale = useLocale.replace( '-', '_');
1444 of.writeRefFunction("getIndexAlgorithm_", useLocale);
1445 of.writeRefFunction("getUnicodeScripts_", useLocale);
1446 of.writeRefFunction("getFollowPageWords_", useLocale);
1447 return;
1449 sal_Int16 nbOfIndexs = 0;
1450 sal_Int16 nbOfUnicodeScripts = 0;
1451 sal_Int16 nbOfPageWords = 0;
1452 sal_Int16 i;
1453 for (i = 0; i< getNumberOfChildren();i++) {
1454 LocaleNode * currNode = getChildAt (i);
1455 if( currNode->getName() == "IndexKey" )
1457 OUString str;
1458 str = currNode->getAttr().getValueByName("unoid");
1459 of.writeParameter("IndexID", str, nbOfIndexs);
1460 str = currNode->getAttr().getValueByName("module");
1461 of.writeParameter("IndexModule", str, nbOfIndexs);
1462 str = currNode->getValue();
1463 of.writeParameter("IndexKey", str, nbOfIndexs);
1464 str = currNode -> getAttr().getValueByName("default");
1465 of.writeDefaultParameter("Index", str, nbOfIndexs);
1466 str = currNode -> getAttr().getValueByName("phonetic");
1467 of.writeDefaultParameter("Phonetic", str, nbOfIndexs);
1468 of.writeAsciiString("\n");
1470 nbOfIndexs++;
1472 if( currNode->getName() == "UnicodeScript" )
1474 of.writeParameter("unicodeScript", currNode->getValue(), nbOfUnicodeScripts );
1475 nbOfUnicodeScripts++;
1478 if( currNode->getName() == "FollowPageWord" )
1480 of.writeParameter("followPageWord", currNode->getValue(), nbOfPageWords);
1481 nbOfPageWords++;
1484 of.writeAsciiString("static const sal_Int16 nbOfIndexs = ");
1485 of.writeInt(nbOfIndexs);
1486 of.writeAsciiString(";\n\n");
1488 of.writeAsciiString("\nstatic const sal_Unicode* IndexArray[] = {\n");
1489 for(i = 0; i < nbOfIndexs; i++) {
1490 of.writeAsciiString("\tIndexID");
1491 of.writeInt(i);
1492 of.writeAsciiString(",\n");
1494 of.writeAsciiString("\tIndexModule");
1495 of.writeInt(i);
1496 of.writeAsciiString(",\n");
1498 of.writeAsciiString("\tIndexKey");
1499 of.writeInt(i);
1500 of.writeAsciiString(",\n");
1502 of.writeAsciiString("\tdefaultIndex");
1503 of.writeInt(i);
1504 of.writeAsciiString(",\n");
1506 of.writeAsciiString("\tdefaultPhonetic");
1507 of.writeInt(i);
1508 of.writeAsciiString(",\n");
1510 of.writeAsciiString("};\n\n");
1512 of.writeAsciiString("static const sal_Int16 nbOfUnicodeScripts = ");
1513 of.writeInt( nbOfUnicodeScripts );
1514 of.writeAsciiString(";\n\n");
1516 of.writeAsciiString("static const sal_Unicode* UnicodeScriptArray[] = {");
1517 for( i=0; i<nbOfUnicodeScripts; i++ )
1519 of.writeAsciiString( "unicodeScript" );
1520 of.writeInt( i );
1521 of.writeAsciiString( ", " );
1523 of.writeAsciiString("NULL };\n\n");
1525 of.writeAsciiString("static const sal_Int16 nbOfPageWords = ");
1526 of.writeInt(nbOfPageWords);
1527 of.writeAsciiString(";\n\n");
1529 of.writeAsciiString("static const sal_Unicode* FollowPageWordArray[] = {\n");
1530 for(i = 0; i < nbOfPageWords; i++) {
1531 of.writeAsciiString("\tfollowPageWord");
1532 of.writeInt(i);
1533 of.writeAsciiString(",\n");
1535 of.writeAsciiString("\tNULL\n};\n\n");
1537 of.writeFunction("getIndexAlgorithm_", "nbOfIndexs", "IndexArray");
1538 of.writeFunction("getUnicodeScripts_", "nbOfUnicodeScripts", "UnicodeScriptArray");
1539 of.writeFunction("getFollowPageWords_", "nbOfPageWords", "FollowPageWordArray");
1543 static void lcl_writeAbbrFullNarrNames( const OFileWriter & of, const LocaleNode* currNode,
1544 const sal_Char* elementTag, sal_Int16 i, sal_Int16 j )
1546 OUString aAbbrName = currNode->getChildAt(1)->getValue();
1547 OUString aFullName = currNode->getChildAt(2)->getValue();
1548 OUString aNarrName;
1549 LocaleNode* p = (currNode->getNumberOfChildren() > 3 ? currNode->getChildAt(3) : nullptr);
1550 if ( p && p->getName() == "DefaultNarrowName" )
1551 aNarrName = p->getValue();
1552 else
1554 sal_Int32 nIndex = 0;
1555 sal_uInt32 nChar = aFullName.iterateCodePoints( &nIndex);
1556 aNarrName = OUString( &nChar, 1);
1558 of.writeParameter( elementTag, "DefaultAbbrvName", aAbbrName, i, j);
1559 of.writeParameter( elementTag, "DefaultFullName", aFullName, i, j);
1560 of.writeParameter( elementTag, "DefaultNarrowName", aNarrName, i, j);
1563 static void lcl_writeTabTagString( const OFileWriter & of, const sal_Char* pTag, const sal_Char* pStr )
1565 of.writeAsciiString("\t");
1566 of.writeAsciiString( pTag);
1567 of.writeAsciiString( pStr);
1570 static void lcl_writeTabTagStringNums( const OFileWriter & of,
1571 const sal_Char* pTag, const sal_Char* pStr, sal_Int16 i, sal_Int16 j )
1573 lcl_writeTabTagString( of, pTag, pStr);
1574 of.writeInt(i); of.writeInt(j); of.writeAsciiString(",\n");
1577 static void lcl_writeAbbrFullNarrArrays( const OFileWriter & of, sal_Int16 nCount,
1578 const sal_Char* elementTag, sal_Int16 i, bool bNarrow )
1580 if (nCount == 0)
1582 lcl_writeTabTagString( of, elementTag, "Ref");
1583 of.writeInt(i); of.writeAsciiString(",\n");
1584 lcl_writeTabTagString( of, elementTag, "RefName");
1585 of.writeInt(i); of.writeAsciiString(",\n");
1587 else
1589 for (sal_Int16 j = 0; j < nCount; j++)
1591 lcl_writeTabTagStringNums( of, elementTag, "ID", i, j);
1592 lcl_writeTabTagStringNums( of, elementTag, "DefaultAbbrvName", i, j);
1593 lcl_writeTabTagStringNums( of, elementTag, "DefaultFullName", i, j);
1594 if (bNarrow)
1595 lcl_writeTabTagStringNums( of, elementTag, "DefaultNarrowName", i, j);
1600 void LCCalendarNode::generateCode (const OFileWriter &of) const
1602 OUString useLocale = getAttr().getValueByName("ref");
1603 if (!useLocale.isEmpty()) {
1604 useLocale = useLocale.replace( '-', '_');
1605 of.writeRefFunction("getAllCalendars_", useLocale);
1606 return;
1608 sal_Int16 nbOfCalendars = sal::static_int_cast<sal_Int16>( getNumberOfChildren() );
1609 OUString str;
1610 sal_Int16 * nbOfDays = new sal_Int16[nbOfCalendars];
1611 sal_Int16 * nbOfMonths = new sal_Int16[nbOfCalendars];
1612 sal_Int16 * nbOfGenitiveMonths = new sal_Int16[nbOfCalendars];
1613 sal_Int16 * nbOfPartitiveMonths = new sal_Int16[nbOfCalendars];
1614 sal_Int16 * nbOfEras = new sal_Int16[nbOfCalendars];
1615 sal_Int16 j;
1616 sal_Int16 i;
1617 bool bHasGregorian = false;
1620 for ( i = 0; i < nbOfCalendars; i++) {
1621 LocaleNode * calNode = getChildAt (i);
1622 OUString calendarID = calNode -> getAttr().getValueByName("unoid");
1623 of.writeParameter( "calendarID", calendarID, i);
1624 bool bGregorian = calendarID == "gregorian";
1625 if (!bHasGregorian)
1626 bHasGregorian = bGregorian;
1627 str = calNode -> getAttr().getValueByName("default");
1628 of.writeDefaultParameter("Calendar", str, i);
1630 sal_Int16 nChild = 0;
1632 // Generate Days of Week
1633 const sal_Char *elementTag;
1634 LocaleNode * daysNode = nullptr;
1635 OUString ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
1636 ref_name = ref_name.replace( '-', '_');
1637 if (!ref_name.isEmpty() && i > 0) {
1638 for (j = 0; j < i; j++) {
1639 str = getChildAt(j)->getAttr().getValueByName("unoid");
1640 if (str.equals(ref_name))
1641 daysNode = getChildAt(j)->getChildAt(0);
1644 if (!ref_name.isEmpty() && daysNode == nullptr) {
1645 of.writeParameter("dayRef", "ref", i);
1646 of.writeParameter("dayRefName", ref_name, i);
1647 nbOfDays[i] = 0;
1648 } else {
1649 if (daysNode == nullptr)
1650 daysNode = calNode -> getChildAt(nChild);
1651 nbOfDays[i] = sal::static_int_cast<sal_Int16>( daysNode->getNumberOfChildren() );
1652 if (bGregorian && nbOfDays[i] != 7)
1653 incErrorInt( "Error: A Gregorian calendar must have 7 days per week, this one has %d\n", nbOfDays[i]);
1654 elementTag = "day";
1655 for (j = 0; j < nbOfDays[i]; j++) {
1656 LocaleNode *currNode = daysNode -> getChildAt(j);
1657 OUString dayID( currNode->getChildAt(0)->getValue());
1658 of.writeParameter("dayID", dayID, i, j);
1659 if ( j == 0 && bGregorian && dayID != "sun" )
1660 incError( "First day of a week of a Gregorian calendar must be <DayID>sun</DayID>");
1661 lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
1664 ++nChild;
1666 // Generate Months of Year
1667 LocaleNode * monthsNode = nullptr;
1668 ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
1669 ref_name = ref_name.replace( '-', '_');
1670 if (!ref_name.isEmpty() && i > 0) {
1671 for (j = 0; j < i; j++) {
1672 str = getChildAt(j)->getAttr().getValueByName("unoid");
1673 if (str.equals(ref_name))
1674 monthsNode = getChildAt(j)->getChildAt(1);
1677 if (!ref_name.isEmpty() && monthsNode == nullptr) {
1678 of.writeParameter("monthRef", "ref", i);
1679 of.writeParameter("monthRefName", ref_name, i);
1680 nbOfMonths[i] = 0;
1681 } else {
1682 if (monthsNode == nullptr)
1683 monthsNode = calNode -> getChildAt(nChild);
1684 nbOfMonths[i] = sal::static_int_cast<sal_Int16>( monthsNode->getNumberOfChildren() );
1685 if (bGregorian && nbOfMonths[i] != 12)
1686 incErrorInt( "Error: A Gregorian calendar must have 12 months, this one has %d\n", nbOfMonths[i]);
1687 elementTag = "month";
1688 for (j = 0; j < nbOfMonths[i]; j++) {
1689 LocaleNode *currNode = monthsNode -> getChildAt(j);
1690 OUString monthID( currNode->getChildAt(0)->getValue());
1691 of.writeParameter("monthID", monthID, i, j);
1692 if ( j == 0 && bGregorian && monthID != "jan" )
1693 incError( "First month of a year of a Gregorian calendar must be <MonthID>jan</MonthID>");
1694 lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
1697 ++nChild;
1699 // Generate genitive Months of Year
1700 // Optional, if not present fall back to month nouns.
1701 if ( calNode->getChildAt(nChild)->getName() != "GenitiveMonths" )
1702 --nChild;
1703 LocaleNode * genitiveMonthsNode = nullptr;
1704 ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
1705 ref_name = ref_name.replace( '-', '_');
1706 if (!ref_name.isEmpty() && i > 0) {
1707 for (j = 0; j < i; j++) {
1708 str = getChildAt(j)->getAttr().getValueByName("unoid");
1709 if (str.equals(ref_name))
1710 genitiveMonthsNode = getChildAt(j)->getChildAt(1);
1713 if (!ref_name.isEmpty() && genitiveMonthsNode == nullptr) {
1714 of.writeParameter("genitiveMonthRef", "ref", i);
1715 of.writeParameter("genitiveMonthRefName", ref_name, i);
1716 nbOfGenitiveMonths[i] = 0;
1717 } else {
1718 if (genitiveMonthsNode == nullptr)
1719 genitiveMonthsNode = calNode -> getChildAt(nChild);
1720 nbOfGenitiveMonths[i] = sal::static_int_cast<sal_Int16>( genitiveMonthsNode->getNumberOfChildren() );
1721 if (bGregorian && nbOfGenitiveMonths[i] != 12)
1722 incErrorInt( "Error: A Gregorian calendar must have 12 genitive months, this one has %d\n", nbOfGenitiveMonths[i]);
1723 elementTag = "genitiveMonth";
1724 for (j = 0; j < nbOfGenitiveMonths[i]; j++) {
1725 LocaleNode *currNode = genitiveMonthsNode -> getChildAt(j);
1726 OUString genitiveMonthID( currNode->getChildAt(0)->getValue());
1727 of.writeParameter("genitiveMonthID", genitiveMonthID, i, j);
1728 if ( j == 0 && bGregorian && genitiveMonthID != "jan" )
1729 incError( "First genitive month of a year of a Gregorian calendar must be <MonthID>jan</MonthID>");
1730 lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
1733 ++nChild;
1735 // Generate partitive Months of Year
1736 // Optional, if not present fall back to genitive months, or nominative
1737 // months (nouns) if that isn't present either.
1738 if ( calNode->getChildAt(nChild)->getName() != "PartitiveMonths" )
1739 --nChild;
1740 LocaleNode * partitiveMonthsNode = nullptr;
1741 ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
1742 ref_name = ref_name.replace( '-', '_');
1743 if (!ref_name.isEmpty() && i > 0) {
1744 for (j = 0; j < i; j++) {
1745 str = getChildAt(j)->getAttr().getValueByName("unoid");
1746 if (str.equals(ref_name))
1747 partitiveMonthsNode = getChildAt(j)->getChildAt(1);
1750 if (!ref_name.isEmpty() && partitiveMonthsNode == nullptr) {
1751 of.writeParameter("partitiveMonthRef", "ref", i);
1752 of.writeParameter("partitiveMonthRefName", ref_name, i);
1753 nbOfPartitiveMonths[i] = 0;
1754 } else {
1755 if (partitiveMonthsNode == nullptr)
1756 partitiveMonthsNode = calNode -> getChildAt(nChild);
1757 nbOfPartitiveMonths[i] = sal::static_int_cast<sal_Int16>( partitiveMonthsNode->getNumberOfChildren() );
1758 if (bGregorian && nbOfPartitiveMonths[i] != 12)
1759 incErrorInt( "Error: A Gregorian calendar must have 12 partitive months, this one has %d\n", nbOfPartitiveMonths[i]);
1760 elementTag = "partitiveMonth";
1761 for (j = 0; j < nbOfPartitiveMonths[i]; j++) {
1762 LocaleNode *currNode = partitiveMonthsNode -> getChildAt(j);
1763 OUString partitiveMonthID( currNode->getChildAt(0)->getValue());
1764 of.writeParameter("partitiveMonthID", partitiveMonthID, i, j);
1765 if ( j == 0 && bGregorian && partitiveMonthID != "jan" )
1766 incError( "First partitive month of a year of a Gregorian calendar must be <MonthID>jan</MonthID>");
1767 lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
1770 ++nChild;
1772 // Generate Era name
1773 LocaleNode * erasNode = nullptr;
1774 ref_name = calNode -> getChildAt(nChild) ->getAttr().getValueByName("ref");
1775 ref_name = ref_name.replace( '-', '_');
1776 if (!ref_name.isEmpty() && i > 0) {
1777 for (j = 0; j < i; j++) {
1778 str = getChildAt(j)->getAttr().getValueByName("unoid");
1779 if (str.equals(ref_name))
1780 erasNode = getChildAt(j)->getChildAt(2);
1783 if (!ref_name.isEmpty() && erasNode == nullptr) {
1784 of.writeParameter("eraRef", "ref", i);
1785 of.writeParameter("eraRefName", ref_name, i);
1786 nbOfEras[i] = 0;
1787 } else {
1788 if (erasNode == nullptr)
1789 erasNode = calNode -> getChildAt(nChild);
1790 nbOfEras[i] = sal::static_int_cast<sal_Int16>( erasNode->getNumberOfChildren() );
1791 if (bGregorian && nbOfEras[i] != 2)
1792 incErrorInt( "Error: A Gregorian calendar must have 2 eras, this one has %d\n", nbOfEras[i]);
1793 elementTag = "era";
1794 for (j = 0; j < nbOfEras[i]; j++) {
1795 LocaleNode *currNode = erasNode -> getChildAt(j);
1796 OUString eraID( currNode->getChildAt(0)->getValue());
1797 of.writeParameter("eraID", eraID, i, j);
1798 if ( j == 0 && bGregorian && eraID != "bc" )
1799 incError( "First era of a Gregorian calendar must be <EraID>bc</EraID>");
1800 if ( j == 1 && bGregorian && eraID != "ad" )
1801 incError( "Second era of a Gregorian calendar must be <EraID>ad</EraID>");
1802 of.writeAsciiString("\n");
1803 of.writeParameter(elementTag, "DefaultAbbrvName",currNode->getChildAt(1)->getValue() ,i, j);
1804 of.writeParameter(elementTag, "DefaultFullName",currNode->getChildAt(2)->getValue() , i, j);
1807 ++nChild;
1809 str = calNode->getChildAt(nChild)->getChildAt(0)->getValue();
1810 if (nbOfDays[i])
1812 for (j = 0; j < nbOfDays[i]; j++)
1814 LocaleNode *currNode = daysNode->getChildAt(j);
1815 OUString dayID( currNode->getChildAt(0)->getValue());
1816 if (str == dayID)
1817 break; // for
1819 if (j >= nbOfDays[i])
1820 incErrorStr( "Error: <StartDayOfWeek> <DayID> must be one of the <DaysOfWeek>, but is: %s\n", str);
1822 of.writeParameter("startDayOfWeek", str, i);
1823 ++nChild;
1825 str = calNode ->getChildAt(nChild)-> getValue();
1826 sal_Int16 nDays = sal::static_int_cast<sal_Int16>( str.toInt32() );
1827 if (nDays < 1 || (0 < nbOfDays[i] && nbOfDays[i] < nDays))
1828 incErrorInt( "Error: Bad value of MinimalDaysInFirstWeek: %d, must be 1 <= value <= days_in_week\n", nDays);
1829 of.writeIntParameter("minimalDaysInFirstWeek", i, nDays);
1831 if (!bHasGregorian)
1832 fprintf( stderr, "Warning: %s\n", "No Gregorian calendar defined, are you sure?");
1834 of.writeAsciiString("static const sal_Int16 calendarsCount = ");
1835 of.writeInt(nbOfCalendars);
1836 of.writeAsciiString(";\n\n");
1838 of.writeAsciiString("static const sal_Unicode nbOfDays[] = {");
1839 for(i = 0; i < nbOfCalendars - 1; i++) {
1840 of.writeInt(nbOfDays[i]);
1841 of.writeAsciiString(", ");
1843 of.writeInt(nbOfDays[i]);
1844 of.writeAsciiString("};\n");
1846 of.writeAsciiString("static const sal_Unicode nbOfMonths[] = {");
1847 for(i = 0; i < nbOfCalendars - 1; i++) {
1848 of.writeInt(nbOfMonths[i]);
1849 of.writeAsciiString(", ");
1851 of.writeInt(nbOfMonths[i]);
1852 of.writeAsciiString("};\n");
1854 of.writeAsciiString("static const sal_Unicode nbOfGenitiveMonths[] = {");
1855 for(i = 0; i < nbOfCalendars - 1; i++) {
1856 of.writeInt(nbOfGenitiveMonths[i]);
1857 of.writeAsciiString(", ");
1859 of.writeInt(nbOfGenitiveMonths[i]);
1860 of.writeAsciiString("};\n");
1862 of.writeAsciiString("static const sal_Unicode nbOfPartitiveMonths[] = {");
1863 for(i = 0; i < nbOfCalendars - 1; i++) {
1864 of.writeInt(nbOfPartitiveMonths[i]);
1865 of.writeAsciiString(", ");
1867 of.writeInt(nbOfPartitiveMonths[i]);
1868 of.writeAsciiString("};\n");
1870 of.writeAsciiString("static const sal_Unicode nbOfEras[] = {");
1871 for(i = 0; i < nbOfCalendars - 1; i++) {
1872 of.writeInt(nbOfEras[i]);
1873 of.writeAsciiString(", ");
1875 of.writeInt(nbOfEras[i]);
1876 of.writeAsciiString("};\n");
1879 of.writeAsciiString("static const sal_Unicode* calendars[] = {\n");
1880 of.writeAsciiString("\tnbOfDays,\n");
1881 of.writeAsciiString("\tnbOfMonths,\n");
1882 of.writeAsciiString("\tnbOfGenitiveMonths,\n");
1883 of.writeAsciiString("\tnbOfPartitiveMonths,\n");
1884 of.writeAsciiString("\tnbOfEras,\n");
1885 for(i = 0; i < nbOfCalendars; i++) {
1886 of.writeAsciiString("\tcalendarID");
1887 of.writeInt(i);
1888 of.writeAsciiString(",\n");
1889 of.writeAsciiString("\tdefaultCalendar");
1890 of.writeInt(i);
1891 of.writeAsciiString(",\n");
1892 lcl_writeAbbrFullNarrArrays( of, nbOfDays[i], "day", i, true);
1893 lcl_writeAbbrFullNarrArrays( of, nbOfMonths[i], "month", i, true);
1894 lcl_writeAbbrFullNarrArrays( of, nbOfGenitiveMonths[i], "genitiveMonth", i, true);
1895 lcl_writeAbbrFullNarrArrays( of, nbOfPartitiveMonths[i], "partitiveMonth", i, true);
1896 lcl_writeAbbrFullNarrArrays( of, nbOfEras[i], "era", i, false /*noNarrow*/);
1897 of.writeAsciiString("\tstartDayOfWeek");of.writeInt(i); of.writeAsciiString(",\n");
1898 of.writeAsciiString("\tminimalDaysInFirstWeek");of.writeInt(i); of.writeAsciiString(",\n");
1901 of.writeAsciiString("};\n\n");
1902 of.writeFunction("getAllCalendars_", "calendarsCount", "calendars");
1904 delete []nbOfDays;
1905 delete []nbOfMonths;
1906 delete []nbOfGenitiveMonths;
1907 delete []nbOfPartitiveMonths;
1908 delete []nbOfEras;
1911 bool isIso4217( const OUString& rStr )
1913 const sal_Unicode* p = rStr.getStr();
1914 return rStr.getLength() == 3
1915 && 'A' <= p[0] && p[0] <= 'Z'
1916 && 'A' <= p[1] && p[1] <= 'Z'
1917 && 'A' <= p[2] && p[2] <= 'Z'
1921 void LCCurrencyNode::generateCode (const OFileWriter &of) const
1923 OUString useLocale = getAttr().getValueByName("ref");
1924 if (!useLocale.isEmpty()) {
1925 useLocale = useLocale.replace( '-', '_');
1926 of.writeRefFunction("getAllCurrencies_", useLocale);
1927 return;
1929 sal_Int16 nbOfCurrencies = 0;
1930 OUString str;
1931 sal_Int16 i;
1933 bool bTheDefault= false;
1934 bool bTheCompatible = false;
1935 for ( i = 0; i < getNumberOfChildren(); i++,nbOfCurrencies++) {
1936 LocaleNode * currencyNode = getChildAt (i);
1937 str = currencyNode->getAttr().getValueByName("default");
1938 bool bDefault = of.writeDefaultParameter("Currency", str, nbOfCurrencies);
1939 str = currencyNode->getAttr().getValueByName("usedInCompatibleFormatCodes");
1940 bool bCompatible = of.writeDefaultParameter("CurrencyUsedInCompatibleFormatCodes", str, nbOfCurrencies);
1941 str = currencyNode->getAttr().getValueByName("legacyOnly");
1942 bool bLegacy = of.writeDefaultParameter("CurrencyLegacyOnly", str, nbOfCurrencies);
1943 if (bLegacy && (bDefault || bCompatible))
1944 incError( "Currency: if legacyOnly==true, both 'default' and 'usedInCompatibleFormatCodes' must be false.");
1945 if (bDefault)
1947 if (bTheDefault)
1948 incError( "Currency: more than one default currency.");
1949 bTheDefault = true;
1951 if (bCompatible)
1953 if (bTheCompatible)
1954 incError( "Currency: more than one currency flagged as usedInCompatibleFormatCodes.");
1955 bTheCompatible = true;
1957 str = currencyNode -> findNode ("CurrencyID") -> getValue();
1958 of.writeParameter("currencyID", str, nbOfCurrencies);
1959 // CurrencyID MUST be ISO 4217.
1960 if (!bLegacy && !isIso4217(str))
1961 incError( "CurrencyID is not ISO 4217");
1962 str = currencyNode -> findNode ("CurrencySymbol") -> getValue();
1963 of.writeParameter("currencySymbol", str, nbOfCurrencies);
1964 // Check if this currency really is the one used in number format
1965 // codes. In case of ref=... mechanisms it may be that TheCurrency
1966 // couldn't had been determined from the current locale (i.e. is
1967 // empty), silently assume the referred locale has things right.
1968 if (bCompatible && !sTheCompatibleCurrency.isEmpty() && sTheCompatibleCurrency != str)
1969 incErrorStrStr( "Error: CurrencySymbol \"%s\" flagged as usedInCompatibleFormatCodes doesn't match \"%s\" determined from format codes.\n", str, sTheCompatibleCurrency);
1970 str = currencyNode -> findNode ("BankSymbol") -> getValue();
1971 of.writeParameter("bankSymbol", str, nbOfCurrencies);
1972 // BankSymbol currently must be ISO 4217. May change later if
1973 // application always uses CurrencyID instead of BankSymbol.
1974 if (!bLegacy && !isIso4217(str))
1975 incError( "BankSymbol is not ISO 4217");
1976 str = currencyNode -> findNode ("CurrencyName") -> getValue();
1977 of.writeParameter("currencyName", str, nbOfCurrencies);
1978 str = currencyNode -> findNode ("DecimalPlaces") -> getValue();
1979 sal_Int16 nDecimalPlaces = (sal_Int16)str.toInt32();
1980 of.writeIntParameter("currencyDecimalPlaces", nbOfCurrencies, nDecimalPlaces);
1981 of.writeAsciiString("\n");
1984 if (!bTheDefault)
1985 incError( "Currency: no default currency.");
1986 if (!bTheCompatible)
1987 incError( "Currency: no currency flagged as usedInCompatibleFormatCodes.");
1989 of.writeAsciiString("static const sal_Int16 currencyCount = ");
1990 of.writeInt(nbOfCurrencies);
1991 of.writeAsciiString(";\n\n");
1992 of.writeAsciiString("static const sal_Unicode* currencies[] = {\n");
1993 for(i = 0; i < nbOfCurrencies; i++) {
1994 of.writeAsciiString("\tcurrencyID");
1995 of.writeInt(i);
1996 of.writeAsciiString(",\n");
1997 of.writeAsciiString("\tcurrencySymbol");
1998 of.writeInt(i);
1999 of.writeAsciiString(",\n");
2000 of.writeAsciiString("\tbankSymbol");
2001 of.writeInt(i);
2002 of.writeAsciiString(",\n");
2003 of.writeAsciiString("\tcurrencyName");
2004 of.writeInt(i);
2005 of.writeAsciiString(",\n");
2006 of.writeAsciiString("\tdefaultCurrency");
2007 of.writeInt(i);
2008 of.writeAsciiString(",\n");
2009 of.writeAsciiString("\tdefaultCurrencyUsedInCompatibleFormatCodes");
2010 of.writeInt(i);
2011 of.writeAsciiString(",\n");
2012 of.writeAsciiString("\tcurrencyDecimalPlaces");
2013 of.writeInt(i);
2014 of.writeAsciiString(",\n");
2015 of.writeAsciiString("\tdefaultCurrencyLegacyOnly");
2016 of.writeInt(i);
2017 of.writeAsciiString(",\n");
2019 of.writeAsciiString("};\n\n");
2020 of.writeFunction("getAllCurrencies_", "currencyCount", "currencies");
2023 void LCTransliterationNode::generateCode (const OFileWriter &of) const
2025 OUString useLocale = getAttr().getValueByName("ref");
2026 if (!useLocale.isEmpty()) {
2027 useLocale = useLocale.replace( '-', '_');
2028 of.writeRefFunction("getTransliterations_", useLocale);
2029 return;
2031 sal_Int16 nbOfModules = 0;
2032 OUString str;
2033 sal_Int16 i;
2035 for ( i = 0; i < getNumberOfChildren(); i++,nbOfModules++) {
2036 LocaleNode * transNode = getChildAt (i);
2037 str = transNode->getAttr().getValueByIndex(0);
2038 of.writeParameter("Transliteration", str, nbOfModules);
2040 of.writeAsciiString("static const sal_Int16 nbOfTransliterations = ");
2041 of.writeInt(nbOfModules);
2042 of.writeAsciiString(";\n\n");
2044 of.writeAsciiString("\nstatic const sal_Unicode* LCTransliterationsArray[] = {\n");
2045 for( i = 0; i < nbOfModules; i++) {
2046 of.writeAsciiString("\tTransliteration");
2047 of.writeInt(i);
2048 of.writeAsciiString(",\n");
2050 of.writeAsciiString("};\n\n");
2051 of.writeFunction("getTransliterations_", "nbOfTransliterations", "LCTransliterationsArray");
2054 struct NameValuePair {
2055 const sal_Char *name;
2056 const sal_Char *value;
2058 static const NameValuePair ReserveWord[] = {
2059 { "trueWord", "true" },
2060 { "falseWord", "false" },
2061 { "quarter1Word", "1st quarter" },
2062 { "quarter2Word", "2nd quarter" },
2063 { "quarter3Word", "3rd quarter" },
2064 { "quarter4Word", "4th quarter" },
2065 { "aboveWord", "above" },
2066 { "belowWord", "below" },
2067 { "quarter1Abbreviation", "Q1" },
2068 { "quarter2Abbreviation", "Q2" },
2069 { "quarter3Abbreviation", "Q3" },
2070 { "quarter4Abbreviation", "Q4" }
2073 void LCMiscNode::generateCode (const OFileWriter &of) const
2075 OUString useLocale = getAttr().getValueByName("ref");
2076 if (!useLocale.isEmpty()) {
2077 useLocale = useLocale.replace( '-', '_');
2078 of.writeRefFunction("getForbiddenCharacters_", useLocale);
2079 of.writeRefFunction("getBreakIteratorRules_", useLocale);
2080 of.writeRefFunction("getReservedWords_", useLocale);
2081 return;
2083 const LocaleNode * reserveNode = findNode("ReservedWords");
2084 if (!reserveNode)
2085 incError( "No ReservedWords element."); // should not happen if validated..
2086 const LocaleNode * forbidNode = findNode("ForbiddenCharacters");
2087 const LocaleNode * breakNode = findNode("BreakIteratorRules");
2089 bool bEnglishLocale = (strncmp( of.getLocale(), "en_", 3) == 0);
2091 sal_Int16 nbOfWords = 0;
2092 OUString str;
2093 sal_Int16 i;
2095 for ( i = 0; i < sal_Int16(SAL_N_ELEMENTS(ReserveWord)); i++,nbOfWords++) {
2096 const LocaleNode * curNode = (reserveNode ? reserveNode->findNode(
2097 ReserveWord[i].name) : nullptr);
2098 if (!curNode)
2099 fprintf( stderr,
2100 "Warning: No %s in ReservedWords, using en_US default: \"%s\".\n",
2101 ReserveWord[i].name, ReserveWord[i].value);
2102 str = curNode ? curNode -> getValue() : OUString::createFromAscii(ReserveWord[i].value);
2103 if (str.isEmpty())
2105 ++nError;
2106 fprintf( stderr, "Error: No content for ReservedWords %s.\n", ReserveWord[i].name);
2108 of.writeParameter("ReservedWord", str, nbOfWords);
2109 // "true", ..., "below" trigger untranslated warning.
2110 if (!bEnglishLocale && curNode && (0 <= i && i <= 7) &&
2111 str.equalsIgnoreAsciiCaseAscii( ReserveWord[i].value))
2113 fprintf( stderr,
2114 "Warning: ReservedWord %s seems to be untranslated \"%s\".\n",
2115 ReserveWord[i].name, ReserveWord[i].value);
2118 of.writeAsciiString("static const sal_Int16 nbOfReservedWords = ");
2119 of.writeInt(nbOfWords);
2120 of.writeAsciiString(";\n\n");
2121 of.writeAsciiString("\nstatic const sal_Unicode* LCReservedWordsArray[] = {\n");
2122 for( i = 0; i < nbOfWords; i++) {
2123 of.writeAsciiString("\tReservedWord");
2124 of.writeInt(i);
2125 of.writeAsciiString(",\n");
2127 of.writeAsciiString("};\n\n");
2128 of.writeFunction("getReservedWords_", "nbOfReservedWords", "LCReservedWordsArray");
2130 if (forbidNode) {
2131 of.writeParameter( "forbiddenBegin", forbidNode -> getChildAt(0)->getValue());
2132 of.writeParameter( "forbiddenEnd", forbidNode -> getChildAt(1)->getValue());
2133 of.writeParameter( "hangingChars", forbidNode -> getChildAt(2)->getValue());
2134 } else {
2135 of.writeParameter( "forbiddenBegin", OUString());
2136 of.writeParameter( "forbiddenEnd", OUString());
2137 of.writeParameter( "hangingChars", OUString());
2139 of.writeAsciiString("\nstatic const sal_Unicode* LCForbiddenCharactersArray[] = {\n");
2140 of.writeAsciiString("\tforbiddenBegin,\n");
2141 of.writeAsciiString("\tforbiddenEnd,\n");
2142 of.writeAsciiString("\thangingChars\n");
2143 of.writeAsciiString("};\n\n");
2144 of.writeFunction("getForbiddenCharacters_", "3", "LCForbiddenCharactersArray");
2146 if (breakNode) {
2147 of.writeParameter( "EditMode", breakNode -> getChildAt(0)->getValue());
2148 of.writeParameter( "DictionaryMode", breakNode -> getChildAt(1)->getValue());
2149 of.writeParameter( "WordCountMode", breakNode -> getChildAt(2)->getValue());
2150 of.writeParameter( "CharacterMode", breakNode -> getChildAt(3)->getValue());
2151 of.writeParameter( "LineMode", breakNode -> getChildAt(4)->getValue());
2152 } else {
2153 of.writeParameter( "EditMode", OUString());
2154 of.writeParameter( "DictionaryMode", OUString());
2155 of.writeParameter( "WordCountMode", OUString());
2156 of.writeParameter( "CharacterMode", OUString());
2157 of.writeParameter( "LineMode", OUString());
2159 of.writeAsciiString("\nstatic const sal_Unicode* LCBreakIteratorRulesArray[] = {\n");
2160 of.writeAsciiString("\tEditMode,\n");
2161 of.writeAsciiString("\tDictionaryMode,\n");
2162 of.writeAsciiString("\tWordCountMode,\n");
2163 of.writeAsciiString("\tCharacterMode,\n");
2164 of.writeAsciiString("\tLineMode\n");
2165 of.writeAsciiString("};\n\n");
2166 of.writeFunction("getBreakIteratorRules_", "5", "LCBreakIteratorRulesArray");
2170 void LCNumberingLevelNode::generateCode (const OFileWriter &of) const
2172 of.writeAsciiString("// ---> ContinuousNumbering\n");
2173 OUString useLocale = getAttr().getValueByName("ref");
2174 if (!useLocale.isEmpty()) {
2175 useLocale = useLocale.replace( '-', '_');
2176 of.writeRefFunction2("getContinuousNumberingLevels_", useLocale);
2177 return;
2180 // hard code number of attributes per style.
2181 const int nAttributes = 5;
2182 const char* attr[ nAttributes ] = { "Prefix", "NumType", "Suffix", "Transliteration", "NatNum" };
2184 // record each attribute of each style in a static C++ variable.
2185 // determine number of styles on the fly.
2186 sal_Int32 nStyles = getNumberOfChildren();
2187 sal_Int32 i;
2189 for( i = 0; i < nStyles; ++i )
2191 const Attr &q = getChildAt( i )->getAttr();
2192 for( sal_Int32 j=0; j<nAttributes; ++j )
2194 const char* name = attr[j];
2195 OUString value = q.getValueByName( name );
2196 of.writeParameter("continuous", name, value, sal::static_int_cast<sal_Int16>(i) );
2200 // record number of styles and attributes.
2201 of.writeAsciiString("static const sal_Int16 continuousNbOfStyles = ");
2202 of.writeInt( sal::static_int_cast<sal_Int16>( nStyles ) );
2203 of.writeAsciiString(";\n\n");
2204 of.writeAsciiString("static const sal_Int16 continuousNbOfAttributesPerStyle = ");
2205 of.writeInt( nAttributes );
2206 of.writeAsciiString(";\n\n");
2208 // generate code. (intermediate arrays)
2209 for( i=0; i<nStyles; i++ )
2211 of.writeAsciiString("\nstatic const sal_Unicode* continuousStyle" );
2212 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2213 of.writeAsciiString("[] = {\n");
2214 for( sal_Int32 j=0; j<nAttributes; j++)
2216 of.writeAsciiString("\t");
2217 of.writeAsciiString( "continuous" );
2218 of.writeAsciiString( attr[j] );
2219 of.writeInt(sal::static_int_cast<sal_Int16>(i));
2220 of.writeAsciiString(",\n");
2222 of.writeAsciiString("\t0\n};\n\n");
2225 // generate code. (top-level array)
2226 of.writeAsciiString("\n");
2227 of.writeAsciiString("static const sal_Unicode** LCContinuousNumberingLevelsArray[] = {\n" );
2228 for( i=0; i<nStyles; i++ )
2230 of.writeAsciiString( "\t" );
2231 of.writeAsciiString( "continuousStyle" );
2232 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2233 of.writeAsciiString( ",\n");
2235 of.writeAsciiString("\t0\n};\n\n");
2236 of.writeFunction2("getContinuousNumberingLevels_", "continuousNbOfStyles",
2237 "continuousNbOfAttributesPerStyle", "LCContinuousNumberingLevelsArray");
2241 void LCOutlineNumberingLevelNode::generateCode (const OFileWriter &of) const
2243 of.writeAsciiString("// ---> OutlineNumbering\n");
2244 OUString useLocale = getAttr().getValueByName("ref");
2245 if (!useLocale.isEmpty()) {
2246 useLocale = useLocale.replace( '-', '_');
2247 of.writeRefFunction3("getOutlineNumberingLevels_", useLocale);
2248 return;
2251 // hardcode number of attributes per level
2252 const int nAttributes = 11;
2253 const char* attr[ nAttributes ] =
2255 "Prefix",
2256 "NumType",
2257 "Suffix",
2258 "BulletChar",
2259 "BulletFontName",
2260 "ParentNumbering",
2261 "LeftMargin",
2262 "SymbolTextDistance",
2263 "FirstLineOffset",
2264 "Transliteration",
2265 "NatNum",
2268 // record each attribute of each level of each style in a static C++ variable.
2269 // determine number of styles and number of levels per style on the fly.
2270 sal_Int32 nStyles = getNumberOfChildren();
2271 vector<sal_Int32> nLevels; // may be different for each style?
2272 for( sal_Int32 i = 0; i < nStyles; i++ )
2274 LocaleNode* p = getChildAt( i );
2275 nLevels.push_back( p->getNumberOfChildren() );
2276 for( sal_Int32 j=0; j<nLevels.back(); j++ )
2278 const Attr& q = p->getChildAt( j )->getAttr();
2279 for( sal_Int32 k=0; k<nAttributes; ++k )
2281 const char* name = attr[k];
2282 OUString value = q.getValueByName( name );
2283 of.writeParameter("outline", name, value,
2284 sal::static_int_cast<sal_Int16>(i),
2285 sal::static_int_cast<sal_Int16>(j) );
2290 // verify that each style has the same number of levels.
2291 for( size_t i=0; i<nLevels.size(); i++ )
2293 if( nLevels[0] != nLevels[i] )
2295 incError( "Numbering levels don't match.");
2299 // record number of attributes, levels, and styles.
2300 of.writeAsciiString("static const sal_Int16 outlineNbOfStyles = ");
2301 of.writeInt( sal::static_int_cast<sal_Int16>( nStyles ) );
2302 of.writeAsciiString(";\n\n");
2303 of.writeAsciiString("static const sal_Int16 outlineNbOfLevelsPerStyle = ");
2304 of.writeInt( sal::static_int_cast<sal_Int16>( nLevels.back() ) );
2305 of.writeAsciiString(";\n\n");
2306 of.writeAsciiString("static const sal_Int16 outlineNbOfAttributesPerLevel = ");
2307 of.writeInt( nAttributes );
2308 of.writeAsciiString(";\n\n");
2310 // too complicated for now...
2311 // of.writeAsciiString("static const sal_Int16 nbOfOutlineNumberingLevels[] = { ");
2312 // for( sal_Int32 j=0; j<nStyles; j++ )
2313 // {
2314 // of.writeInt( nLevels[j] );
2315 // of.writeAsciiString(", ");
2316 // }
2317 // of.writeAsciiString("};\n\n");
2320 for( sal_Int32 i=0; i<nStyles; i++ )
2322 for( sal_Int32 j=0; j<nLevels.back(); j++ )
2324 of.writeAsciiString("static const sal_Unicode* outline");
2325 of.writeAsciiString("Style");
2326 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2327 of.writeAsciiString("Level");
2328 of.writeInt( sal::static_int_cast<sal_Int16>(j) );
2329 of.writeAsciiString("[] = { ");
2331 for( sal_Int32 k=0; k<nAttributes; k++ )
2333 of.writeAsciiString( "outline" );
2334 of.writeAsciiString( attr[k] );
2335 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2336 of.writeInt( sal::static_int_cast<sal_Int16>(j) );
2337 of.writeAsciiString(", ");
2339 of.writeAsciiString("NULL };\n");
2343 of.writeAsciiString("\n");
2346 for( sal_Int32 i=0; i<nStyles; i++ )
2348 of.writeAsciiString("static const sal_Unicode** outline");
2349 of.writeAsciiString( "Style" );
2350 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2351 of.writeAsciiString("[] = { ");
2353 for( sal_Int32 j=0; j<nLevels.back(); j++ )
2355 of.writeAsciiString("outlineStyle");
2356 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2357 of.writeAsciiString("Level");
2358 of.writeInt( sal::static_int_cast<sal_Int16>(j) );
2359 of.writeAsciiString(", ");
2361 of.writeAsciiString("NULL };\n");
2363 of.writeAsciiString("\n");
2365 of.writeAsciiString("static const sal_Unicode*** LCOutlineNumberingLevelsArray[] = {\n" );
2366 for( sal_Int32 i=0; i<nStyles; i++ )
2368 of.writeAsciiString( "\t" );
2369 of.writeAsciiString( "outlineStyle" );
2370 of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2371 of.writeAsciiString(",\n");
2373 of.writeAsciiString("\tNULL\n};\n\n");
2374 of.writeFunction3("getOutlineNumberingLevels_", "outlineNbOfStyles", "outlineNbOfLevelsPerStyle",
2375 "outlineNbOfAttributesPerLevel", "LCOutlineNumberingLevelsArray");
2378 Attr::Attr (const Reference< XAttributeList > & attr) {
2379 sal_Int16 len = attr->getLength();
2380 name.realloc (len);
2381 value.realloc (len);
2382 for (sal_Int16 i =0; i< len;i++) {
2383 name[i] = attr->getNameByIndex(i);
2384 value[i] = attr -> getValueByIndex(i);
2388 const OUString& Attr::getValueByName (const sal_Char *str) const {
2389 static OUString empty;
2390 sal_Int32 len = name.getLength();
2391 for (sal_Int32 i = 0;i<len;i++)
2392 if (name[i].equalsAscii(str))
2393 return value[i];
2394 return empty;
2397 sal_Int32 Attr::getLength() const{
2398 return name.getLength();
2401 const OUString& Attr::getTypeByIndex (sal_Int32 idx) const {
2402 return name[idx];
2405 const OUString& Attr::getValueByIndex (sal_Int32 idx) const
2407 return value[idx];
2410 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */