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