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