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