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