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 0 : LocaleNode::LocaleNode (const OUString& name, const Reference< XAttributeList > & attr)
42 : : aName(name)
43 : , aAttribs(attr)
44 : , parent(0)
45 : , children(0)
46 : , nChildren(0)
47 : , childArrSize(0)
48 0 : , nError(0)
49 : {
50 0 : }
51 :
52 0 : int LocaleNode::getError() const
53 : {
54 0 : int err = nError;
55 0 : for (sal_Int32 i=0;i<nChildren;i++)
56 0 : err += children[i]->getError();
57 0 : return err;
58 : }
59 :
60 0 : void LocaleNode::print () const {
61 0 : printf ("<");
62 0 : ::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 0 : void LocaleNode::addChild ( LocaleNode * node) {
77 0 : if (childArrSize <= nChildren) {
78 0 : LocaleNode ** arrN = new LocaleNode*[childArrSize+10];
79 0 : for (sal_Int32 i = 0; i<childArrSize; ++i)
80 0 : arrN[i] = children[i];
81 0 : delete [] children;
82 0 : childArrSize += 10;
83 0 : children = arrN;
84 : }
85 0 : children[nChildren++] = node;
86 0 : node->setParent (this);
87 0 : }
88 :
89 0 : void LocaleNode::setParent ( LocaleNode * node) {
90 0 : parent = node;
91 0 : }
92 :
93 0 : const LocaleNode* LocaleNode::getRoot() const
94 : {
95 0 : const LocaleNode* pRoot = 0;
96 0 : const LocaleNode* pParent = this;
97 0 : while ( (pParent = pParent->getParent()) != 0 )
98 0 : pRoot = pParent;
99 0 : return pRoot;
100 : }
101 :
102 0 : const LocaleNode * LocaleNode::findNode ( const sal_Char *name) const {
103 0 : if (aName.equalsAscii(name))
104 0 : return this;
105 0 : for (sal_Int32 i = 0; i< nChildren; i++) {
106 0 : const LocaleNode *n=children[i]->findNode(name);
107 0 : if (n)
108 0 : return n;
109 : }
110 0 : return 0;
111 : }
112 :
113 0 : LocaleNode::~LocaleNode()
114 : {
115 0 : for (sal_Int32 i=0; i < nChildren; ++i)
116 0 : delete children[i];
117 0 : delete [] children;
118 0 : }
119 :
120 0 : LocaleNode* LocaleNode::createNode (const OUString& name, const Reference< XAttributeList > & attr)
121 : {
122 0 : if ( name == "LC_INFO" )
123 0 : return new LCInfoNode (name,attr);
124 0 : if ( name == "LC_CTYPE" )
125 0 : return new LCCTYPENode (name,attr);
126 0 : if ( name == "LC_FORMAT" )
127 0 : return new LCFormatNode (name,attr);
128 0 : if ( name == "LC_FORMAT_1" )
129 0 : return new LCFormatNode (name,attr);
130 0 : if ( name == "LC_CALENDAR" )
131 0 : return new LCCalendarNode (name,attr);
132 0 : if ( name == "LC_CURRENCY" )
133 0 : return new LCCurrencyNode (name,attr);
134 0 : if ( name == "LC_TRANSLITERATION" )
135 0 : return new LCTransliterationNode (name,attr);
136 0 : if ( name == "LC_COLLATION" )
137 0 : return new LCCollationNode (name,attr);
138 0 : if ( name == "LC_INDEX" )
139 0 : return new LCIndexNode (name,attr);
140 0 : if ( name == "LC_SEARCH" )
141 0 : return new LCSearchNode (name,attr);
142 0 : if ( name == "LC_MISC" )
143 0 : return new LCMiscNode (name,attr);
144 0 : if ( name == "LC_NumberingLevel" )
145 0 : return new LCNumberingLevelNode (name, attr);
146 0 : if ( name == "LC_OutLineNumberingLevel" )
147 0 : return new LCOutlineNumberingLevelNode (name, attr);
148 :
149 0 : return new LocaleNode(name,attr);
150 : }
151 :
152 :
153 : // printf(" name: '%s'\n", p->getName().pData->buffer );
154 : // printf("value: '%s'\n", p->getValue().pData->buffer );
155 :
156 : #define OSTR(s) (OUStringToOString( (s), RTL_TEXTENCODING_UTF8).getStr())
157 :
158 0 : void print_OUString( const OUString& s )
159 : {
160 0 : printf( "%s", OSTR(s));
161 0 : }
162 :
163 0 : bool is_empty_string( const OUString& s )
164 : {
165 0 : return s.isEmpty() || (s.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 0 : void LocaleNode :: generateCode (const OFileWriter &of) const
226 : {
227 0 : ::rtl::OUString aDTD = getAttr().getValueByName("versionDTD");
228 0 : if ( aDTD != LOCALE_VERSION_DTD )
229 : {
230 0 : ++nError;
231 0 : fprintf( stderr, "Error: Locale versionDTD is not %s, see comment in locale.dtd\n", LOCALE_VERSION_DTD);
232 : }
233 0 : for (sal_Int32 i=0; i<nChildren;i++)
234 0 : children[i]->generateCode (of);
235 : // print_node( this );
236 0 : }
237 :
238 :
239 0 : ::rtl::OUString LocaleNode::writeParameterCheckLen( const OFileWriter &of,
240 : const char* pParameterName, const LocaleNode* pNode,
241 : sal_Int32 nMinLen, sal_Int32 nMaxLen ) const
242 : {
243 0 : OUString aVal;
244 0 : if (pNode)
245 0 : aVal = pNode->getValue();
246 : else
247 : {
248 0 : ++nError;
249 : fprintf( stderr, "Error: node NULL pointer for parameter %s.\n",
250 0 : pParameterName);
251 : }
252 : // write empty data if error
253 0 : of.writeParameter( pParameterName, aVal);
254 0 : sal_Int32 nLen = aVal.getLength();
255 0 : if (nLen < nMinLen)
256 : {
257 0 : ++nError;
258 : fprintf( stderr, "Error: less than %ld character%s (%ld) in %s '%s'.\n",
259 : sal::static_int_cast< long >(nMinLen), (nMinLen > 1 ? "s" : ""),
260 : sal::static_int_cast< long >(nLen),
261 0 : (pNode ? OSTR( pNode->getName()) : ""),
262 0 : OSTR( aVal));
263 : }
264 0 : else if (nLen > nMaxLen && nMaxLen >= 0)
265 : fprintf( stderr,
266 : "Warning: more than %ld character%s (%ld) in %s %s not supported by application.\n",
267 : sal::static_int_cast< long >(nMaxLen), (nMaxLen > 1 ? "s" : ""),
268 : sal::static_int_cast< long >(nLen),
269 0 : (pNode ? OSTR( pNode->getName()) : ""),
270 0 : OSTR( aVal));
271 0 : return aVal;
272 : }
273 :
274 :
275 0 : ::rtl::OUString LocaleNode::writeParameterCheckLen( const OFileWriter &of,
276 : const char* pNodeName, const char* pParameterName,
277 : sal_Int32 nMinLen, sal_Int32 nMaxLen ) const
278 : {
279 0 : OUString aVal;
280 0 : const LocaleNode * pNode = findNode( pNodeName);
281 0 : if (pNode)
282 0 : aVal = writeParameterCheckLen( of, pParameterName, pNode, nMinLen, nMaxLen);
283 : else
284 : {
285 0 : ++nError;
286 0 : fprintf( stderr, "Error: node %s not found.\n", pNodeName);
287 : // write empty data if error
288 0 : of.writeParameter( pParameterName, aVal);
289 : }
290 0 : return aVal;
291 : }
292 :
293 0 : void LocaleNode::incError( const char* pStr ) const
294 : {
295 0 : ++nError;
296 0 : fprintf( stderr, "Error: %s\n", pStr);
297 0 : }
298 :
299 0 : void LocaleNode::incError( const ::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 0 : void LCInfoNode::generateCode (const OFileWriter &of) const
337 : {
338 :
339 0 : const LocaleNode * languageNode = findNode("Language");
340 0 : const LocaleNode * countryNode = findNode("Country");
341 0 : const LocaleNode * variantNode = findNode("Variant");
342 :
343 0 : if (languageNode)
344 : {
345 0 : writeParameterCheckLen( of, "langID", languageNode->getChildAt(0), 2, -1);
346 0 : of.writeParameter("langDefaultName", languageNode->getChildAt(1)->getValue());
347 : }
348 : else
349 0 : incError( "No Language node.");
350 0 : if (countryNode)
351 : {
352 0 : of.writeParameter("countryID", countryNode->getChildAt(0)->getValue());
353 0 : of.writeParameter("countryDefaultName", countryNode->getChildAt(1)->getValue());
354 : }
355 : else
356 0 : incError( "No Country node.");
357 0 : 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 0 : of.writeParameter("Variant", ::rtl::OUString());
365 0 : of.writeAsciiString("\nstatic const sal_Unicode* LCInfoArray[] = {\n");
366 0 : of.writeAsciiString("\tlangID,\n");
367 0 : of.writeAsciiString("\tlangDefaultName,\n");
368 0 : of.writeAsciiString("\tcountryID,\n");
369 0 : of.writeAsciiString("\tcountryDefaultName,\n");
370 0 : of.writeAsciiString("\tVariant\n");
371 0 : of.writeAsciiString("};\n\n");
372 0 : of.writeFunction("getLCInfo_", "0", "LCInfoArray");
373 0 : }
374 :
375 :
376 0 : static OUString aDateSep;
377 0 : static OUString aDecSep;
378 :
379 0 : void LCCTYPENode::generateCode (const OFileWriter &of) const
380 : {
381 0 : const LocaleNode * sepNode = 0;
382 0 : ::rtl::OUString useLocale = getAttr().getValueByName("ref");
383 0 : if (!useLocale.isEmpty()) {
384 0 : of.writeRefFunction("getLocaleItem_", useLocale);
385 0 : return;
386 : }
387 0 : ::rtl::OUString str = getAttr().getValueByName("unoid");
388 0 : of.writeAsciiString("\n\n");
389 0 : of.writeParameter("LC_CTYPE_Unoid", str);;
390 :
391 : aDateSep =
392 0 : writeParameterCheckLen( of, "DateSeparator", "dateSeparator", 1, 1);
393 : OUString aThoSep =
394 0 : writeParameterCheckLen( of, "ThousandSeparator", "thousandSeparator", 1, 1);
395 : aDecSep =
396 0 : writeParameterCheckLen( of, "DecimalSeparator", "decimalSeparator", 1, 1);
397 : OUString aTimeSep =
398 0 : writeParameterCheckLen( of, "TimeSeparator", "timeSeparator", 1, 1);
399 : OUString aTime100Sep =
400 0 : writeParameterCheckLen( of, "Time100SecSeparator", "time100SecSeparator", 1, 1);
401 : OUString aListSep =
402 0 : writeParameterCheckLen( of, "ListSeparator", "listSeparator", 1, 1);
403 :
404 0 : OUString aLDS;
405 :
406 0 : sepNode = findNode("LongDateDayOfWeekSeparator");
407 0 : aLDS = sepNode->getValue();
408 0 : of.writeParameter("LongDateDayOfWeekSeparator", aLDS);
409 0 : 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 0 : sepNode = findNode("LongDateDaySeparator");
414 0 : aLDS = sepNode->getValue();
415 0 : of.writeParameter("LongDateDaySeparator", aLDS);
416 0 : if (aLDS.getLength() == 1 && (aLDS.getStr()[0] == ',' || aLDS.getStr()[0] == '.'))
417 : fprintf( stderr, "Warning: %s\n",
418 0 : "LongDateDaySeparator is only a comma or dot not followed by a space. Usually this is not the case and may lead to concatenated display names like \"Wednesday, May 9,2007\".");
419 :
420 0 : sepNode = findNode("LongDateMonthSeparator");
421 0 : aLDS = sepNode->getValue();
422 0 : of.writeParameter("LongDateMonthSeparator", aLDS);
423 0 : 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 0 : sepNode = findNode("LongDateYearSeparator");
428 0 : aLDS = sepNode->getValue();
429 0 : of.writeParameter("LongDateYearSeparator", aLDS);
430 0 : if (aLDS.isEmpty())
431 : fprintf( stderr, "Warning: %s\n",
432 0 : "LongDateYearSeparator is empty. Usually this is not the case and may lead to concatenated display names like \"Wednesday, 2007May 9\".");
433 :
434 :
435 0 : int nSavErr = nError;
436 0 : int nWarn = 0;
437 0 : if (aDateSep == aTimeSep)
438 0 : incError( "DateSeparator equals TimeSeparator.");
439 0 : if (aDecSep == aThoSep)
440 0 : incError( "DecimalSeparator equals ThousandSeparator.");
441 0 : if ( aThoSep == " " )
442 0 : incError( "ThousandSeparator is an ' ' ordinary space, this should be a non-breaking space U+00A0 instead.");
443 0 : if (aListSep == aDecSep)
444 : fprintf( stderr, "Warning: %s\n",
445 0 : "ListSeparator equals DecimalSeparator.");
446 0 : if (aListSep == aThoSep)
447 : fprintf( stderr, "Warning: %s\n",
448 0 : "ListSeparator equals ThousandSeparator.");
449 0 : 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 0 : if (aTimeSep == aTime100Sep)
455 : ++nWarn, fprintf( stderr, "Warning: %s\n",
456 0 : "Time100SecSeparator equals TimeSeparator, this is probably an error.");
457 0 : if (aDecSep != aTime100Sep)
458 : ++nWarn, fprintf( stderr, "Warning: %s\n",
459 0 : "Time100SecSeparator is different from DecimalSeparator, this may be correct or not. Intended?");
460 0 : if (nSavErr != nError || nWarn)
461 : fprintf( stderr, "Warning: %s\n",
462 0 : "Don't forget to adapt corresponding FormatCode elements when changing separators.");
463 :
464 : OUString aQuoteStart =
465 0 : writeParameterCheckLen( of, "QuotationStart", "quotationStart", 1, 1);
466 : OUString aQuoteEnd =
467 0 : writeParameterCheckLen( of, "QuotationEnd", "quotationEnd", 1, 1);
468 : OUString aDoubleQuoteStart =
469 0 : writeParameterCheckLen( of, "DoubleQuotationStart", "doubleQuotationStart", 1, 1);
470 : OUString aDoubleQuoteEnd =
471 0 : writeParameterCheckLen( of, "DoubleQuotationEnd", "doubleQuotationEnd", 1, 1);
472 :
473 0 : 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 0 : 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 0 : if (aDoubleQuoteStart.toChar() <= 127 && aDoubleQuoteEnd.toChar() > 127)
480 : fprintf( stderr, "Warning: %s\n",
481 0 : "DoubleQuotationStart is an ASCII character but DoubleQuotationEnd is not.");
482 0 : 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 0 : if (aQuoteStart.toChar() <= 127 && aQuoteEnd.toChar() <= 127)
486 : fprintf( stderr, "Warning: %s\n",
487 0 : "QuotationStart and QuotationEnd are both ASCII characters. Not necessarily an issue, but unusual.");
488 0 : if (aDoubleQuoteStart.toChar() <= 127 && aDoubleQuoteEnd.toChar() <= 127)
489 : fprintf( stderr, "Warning: %s\n",
490 0 : "DoubleQuotationStart and DoubleQuotationEnd are both ASCII characters. Not necessarily an issue, but unusual.");
491 0 : if (aQuoteStart == aQuoteEnd)
492 : fprintf( stderr, "Warning: %s\n",
493 0 : "QuotationStart equals QuotationEnd. Not necessarily an issue, but unusual.");
494 0 : if (aDoubleQuoteStart == aDoubleQuoteEnd)
495 : fprintf( stderr, "Warning: %s\n",
496 0 : "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 0 : if (aQuoteStart == aDoubleQuoteStart)
500 : fprintf( stderr, "Warning: %s\n",
501 0 : "QuotationStart equals DoubleQuotationStart. Not necessarily an isue, but unusual.");
502 0 : if (aQuoteEnd == aDoubleQuoteEnd)
503 : fprintf( stderr, "Warning: %s\n",
504 0 : "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 0 : 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 0 : break;
517 : default:
518 : fprintf( stderr, "Warning: %s U+%04X %s\n",
519 0 : "QuotationStart may be wrong:", ic, OSTR( aQuoteStart));
520 : }
521 0 : 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 0 : break;
531 : default:
532 : fprintf( stderr, "Warning: %s U+%04X %s\n",
533 0 : "QuotationEnd may be wrong:", ic, OSTR( aQuoteEnd));
534 : }
535 0 : 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 0 : break;
545 : default:
546 : fprintf( stderr, "Warning: %s U+%04X %s\n",
547 0 : "DoubleQuotationStart may be wrong:", ic, OSTR( aDoubleQuoteStart));
548 : }
549 0 : 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 0 : break;
559 : default:
560 : fprintf( stderr, "Warning: %s U+%04X %s\n",
561 0 : "DoubleQuotationEnd may be wrong:", ic, OSTR( aDoubleQuoteEnd));
562 : }
563 :
564 0 : writeParameterCheckLen( of, "TimeAM", "timeAM", 1, -1);
565 0 : writeParameterCheckLen( of, "TimePM", "timePM", 1, -1);
566 0 : sepNode = findNode("MeasurementSystem");
567 0 : of.writeParameter("measurementSystem", sepNode->getValue());
568 :
569 0 : of.writeAsciiString("\nstatic const sal_Unicode* LCType[] = {\n");
570 0 : of.writeAsciiString("\tLC_CTYPE_Unoid,\n");
571 0 : of.writeAsciiString("\tdateSeparator,\n");
572 0 : of.writeAsciiString("\tthousandSeparator,\n");
573 0 : of.writeAsciiString("\tdecimalSeparator,\n");
574 0 : of.writeAsciiString("\ttimeSeparator,\n");
575 0 : of.writeAsciiString("\ttime100SecSeparator,\n");
576 0 : of.writeAsciiString("\tlistSeparator,\n");
577 0 : of.writeAsciiString("\tquotationStart,\n");
578 0 : of.writeAsciiString("\tquotationEnd,\n");
579 0 : of.writeAsciiString("\tdoubleQuotationStart,\n");
580 0 : of.writeAsciiString("\tdoubleQuotationEnd,\n");
581 0 : of.writeAsciiString("\ttimeAM,\n");
582 0 : of.writeAsciiString("\ttimePM,\n");
583 0 : of.writeAsciiString("\tmeasurementSystem,\n");
584 0 : of.writeAsciiString("\tLongDateDayOfWeekSeparator,\n");
585 0 : of.writeAsciiString("\tLongDateDaySeparator,\n");
586 0 : of.writeAsciiString("\tLongDateMonthSeparator,\n");
587 0 : of.writeAsciiString("\tLongDateYearSeparator\n");
588 0 : of.writeAsciiString("};\n\n");
589 0 : of.writeFunction("getLocaleItem_", "0", "LCType");
590 : }
591 :
592 :
593 0 : static OUString sTheCurrencyReplaceTo;
594 0 : static OUString sTheCompatibleCurrency;
595 0 : static OUString sTheDateEditFormat;
596 :
597 : sal_Int16 LCFormatNode::mnSection = 0;
598 : sal_Int16 LCFormatNode::mnFormats = 0;
599 :
600 0 : void LCFormatNode::generateCode (const OFileWriter &of) const
601 : {
602 0 : if (mnSection >= 2)
603 0 : incError("more than 2 LC_FORMAT sections");
604 :
605 0 : ::std::vector< OUString > theDateAcceptancePatterns;
606 :
607 0 : OUString str;
608 0 : OUString strFrom( getAttr().getValueByName("replaceFrom"));
609 0 : of.writeParameter("replaceFrom", strFrom, mnSection);
610 0 : str = getAttr().getValueByName("replaceTo");
611 0 : 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 0 : if (str.endsWithIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "-FFFF]")))
615 0 : incErrorStr("replaceTo=\"%s\" needs FFFF to be adapted to the real LangID value.", str);
616 0 : of.writeParameter("replaceTo", str, mnSection);
617 : // Remember the replaceTo value for "[CURRENCY]" to check format codes.
618 0 : if ( strFrom == "[CURRENCY]" )
619 0 : sTheCurrencyReplaceTo = str;
620 : // Remember the currency symbol if present.
621 0 : if (str.indexOfAsciiL( "[$", 2) == 0)
622 : {
623 0 : sal_Int32 nHyphen = str.indexOf( '-');
624 0 : if (nHyphen >= 3)
625 : {
626 0 : sTheCompatibleCurrency = str.copy( 2, nHyphen - 2);
627 : }
628 : }
629 :
630 0 : ::rtl::OUString useLocale = getAttr().getValueByName("ref");
631 0 : if (!useLocale.isEmpty())
632 : {
633 0 : switch (mnSection)
634 : {
635 : case 0:
636 0 : of.writeRefFunction("getAllFormats0_", useLocale, "replaceTo0");
637 0 : break;
638 : case 1:
639 0 : of.writeRefFunction("getAllFormats1_", useLocale, "replaceTo1");
640 0 : break;
641 : }
642 0 : of.writeRefFunction("getDateAcceptancePatterns_", useLocale);
643 0 : return;
644 : }
645 :
646 0 : sal_Int16 formatCount = mnFormats;
647 0 : NameSet aMsgIdSet;
648 0 : ValueSet aFormatIndexSet;
649 0 : NameSet aDefaultsSet;
650 0 : bool bCtypeIsRef = false;
651 :
652 0 : for (sal_Int16 i = 0; i< getNumberOfChildren() ; i++, formatCount++)
653 : {
654 0 : LocaleNode * currNode = getChildAt (i);
655 0 : if ( currNode->getName() == "DateAcceptancePattern" )
656 : {
657 0 : if (mnSection > 0)
658 0 : incError( "DateAcceptancePattern only handled in LC_FORMAT, not LC_FORMAT_1");
659 : else
660 0 : theDateAcceptancePatterns.push_back( currNode->getValue());
661 0 : --formatCount;
662 0 : continue; // for
663 : }
664 0 : 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 0 : OUString aUsage;
672 0 : OUString aType;
673 0 : OUString aFormatIndex;
674 : // currNode -> print();
675 0 : const Attr &currNodeAttr = currNode->getAttr();
676 : //printf ("getLen() = %d\n", currNode->getAttr().getLength());
677 :
678 0 : str = currNodeAttr.getValueByName("msgid");
679 0 : if (!aMsgIdSet.insert( str).second)
680 0 : incErrorStr( "Duplicated msgid=\"%s\" in FormatElement.", str);
681 0 : of.writeParameter("FormatKey", str, formatCount);
682 :
683 0 : str = currNodeAttr.getValueByName("default");
684 0 : bool bDefault = str == "true";
685 0 : of.writeDefaultParameter("FormatElement", str, formatCount);
686 :
687 0 : aType = currNodeAttr.getValueByName("type");
688 0 : of.writeParameter("FormatType", aType, formatCount);
689 :
690 0 : aUsage = currNodeAttr.getValueByName("usage");
691 0 : of.writeParameter("FormatUsage", aUsage, formatCount);
692 :
693 0 : aFormatIndex = currNodeAttr.getValueByName("formatindex");
694 0 : sal_Int16 formatindex = (sal_Int16)aFormatIndex.toInt32();
695 0 : if (!aFormatIndexSet.insert( formatindex).second)
696 0 : incErrorInt( "Duplicated formatindex=\"%d\" in FormatElement.", formatindex);
697 0 : of.writeIntParameter("Formatindex", formatCount, formatindex);
698 :
699 : // Ensure only one default per usage and type.
700 0 : if (bDefault)
701 : {
702 0 : OUString aKey( aUsage + OUString( sal_Unicode(',')) + aType);
703 0 : 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 0 : }
714 : }
715 :
716 0 : const LocaleNode * n = currNode -> findNode("FormatCode");
717 0 : if (n)
718 : {
719 0 : of.writeParameter("FormatCode", n->getValue(), formatCount);
720 : // Check separator usage for some FormatCode elements.
721 0 : const LocaleNode* pCtype = 0;
722 0 : switch (formatindex)
723 : {
724 : case cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY :
725 0 : sTheDateEditFormat = n->getValue();
726 0 : 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 0 : const LocaleNode* pRoot = getRoot();
732 0 : if (!pRoot)
733 0 : incError( "No root for FormatCode.");
734 : else
735 : {
736 0 : pCtype = pRoot->findNode( "LC_CTYPE");
737 0 : if (!pCtype)
738 0 : incError( "No LC_CTYPE found for FormatCode.");
739 : else
740 : {
741 0 : OUString aRef( pCtype->getAttr().getValueByName("ref"));
742 0 : if (!aRef.isEmpty())
743 : {
744 0 : 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 0 : OSTR( aRef));
749 0 : bCtypeIsRef = true;
750 0 : pCtype = 0;
751 0 : }
752 : }
753 : }
754 : }
755 0 : break;
756 : case cssi::NumberFormatIndex::CURRENCY_1000DEC2 :
757 : // Remember the currency symbol if present.
758 : {
759 : sal_Int32 nStart;
760 0 : if (sTheCompatibleCurrency.isEmpty() &&
761 0 : ((nStart = n->getValue().indexOfAsciiL( "[$", 2)) >= 0))
762 : {
763 0 : OUString aCode( n->getValue());
764 0 : sal_Int32 nHyphen = aCode.indexOf( '-', nStart);
765 0 : if (nHyphen >= nStart + 3)
766 0 : 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 0 : if (strcmp( of.getLocale(), "en_US") != 0)
778 : {
779 0 : OUString aCode( n->getValue());
780 0 : OUString aPar1( "0)");
781 0 : OUString aPar2( "-)" );
782 0 : OUString aPar3( " )" );
783 0 : OUString aPar4( "])" );
784 0 : if (aCode.indexOf( aPar1 ) > 0 || aCode.indexOf( aPar2 ) > 0 ||
785 0 : aCode.indexOf( aPar3 ) > 0 || aCode.indexOf( aPar4 ) > 0)
786 0 : fprintf( stderr, "Warning: FormatCode formatindex=\"%d\" for currency uses parentheses for negative amounts, which probably is not correct for locales not based on en_US.\n", formatindex);
787 : }
788 : // Check if we have replaceTo for "[CURRENCY]" placeholder.
789 0 : if (sTheCurrencyReplaceTo.isEmpty())
790 : {
791 0 : OUString aCode( n->getValue());
792 0 : if (aCode.indexOfAsciiL( RTL_CONSTASCII_STRINGPARAM( "[CURRENCY]")) >= 0)
793 0 : incErrorInt( "[CURRENCY] replaceTo not found for formatindex=\"%d\".", formatindex);
794 : }
795 0 : break;
796 : }
797 0 : if (pCtype)
798 : {
799 0 : int nSavErr = nError;
800 0 : OUString aCode( n->getValue());
801 0 : if (formatindex == cssi::NumberFormatIndex::NUMBER_1000DEC2)
802 : {
803 0 : sal_Int32 nDec = -1;
804 0 : sal_Int32 nGrp = -1;
805 0 : const LocaleNode* pSep = pCtype->findNode( "DecimalSeparator");
806 0 : if (!pSep)
807 0 : incError( "No DecimalSeparator found for FormatCode.");
808 : else
809 : {
810 0 : nDec = aCode.indexOf( pSep->getValue());
811 0 : if (nDec < 0)
812 : incErrorInt( "DecimalSeparator not present in FormatCode formatindex=\"%d\".",
813 0 : formatindex);
814 : }
815 0 : pSep = pCtype->findNode( "ThousandSeparator");
816 0 : if (!pSep)
817 0 : incError( "No ThousandSeparator found for FormatCode.");
818 : else
819 : {
820 0 : nGrp = aCode.indexOf( pSep->getValue());
821 0 : if (nGrp < 0)
822 : incErrorInt( "ThousandSeparator not present in FormatCode formatindex=\"%d\".",
823 0 : formatindex);
824 : }
825 0 : if (nDec >= 0 && nGrp >= 0 && nDec <= nGrp)
826 : incErrorInt( "Ordering of ThousandSeparator and DecimalSeparator not correct in formatindex=\"%d\".",
827 0 : formatindex);
828 : }
829 0 : if (formatindex == cssi::NumberFormatIndex::TIME_MMSS00 ||
830 : formatindex == cssi::NumberFormatIndex::TIME_HH_MMSS00)
831 : {
832 0 : sal_Int32 nTime = -1;
833 0 : sal_Int32 n100s = -1;
834 0 : const LocaleNode* pSep = pCtype->findNode( "TimeSeparator");
835 0 : if (!pSep)
836 0 : incError( "No TimeSeparator found for FormatCode.");
837 : else
838 : {
839 0 : nTime = aCode.indexOf( pSep->getValue());
840 0 : if (nTime < 0)
841 : incErrorInt( "TimeSeparator not present in FormatCode formatindex=\"%d\".",
842 0 : formatindex);
843 : }
844 0 : pSep = pCtype->findNode( "Time100SecSeparator");
845 0 : if (!pSep)
846 0 : incError( "No Time100SecSeparator found for FormatCode.");
847 : else
848 : {
849 0 : n100s = aCode.indexOf( pSep->getValue());
850 0 : if (n100s < 0)
851 : incErrorInt( "Time100SecSeparator not present in FormatCode formatindex=\"%d\".",
852 0 : formatindex);
853 0 : OUStringBuffer a100s( pSep->getValue());
854 0 : a100s.appendAscii( "00");
855 0 : n100s = aCode.indexOf( a100s.makeStringAndClear());
856 0 : if (n100s < 0)
857 : incErrorInt( "Time100SecSeparator+00 not present in FormatCode formatindex=\"%d\".",
858 0 : formatindex);
859 : }
860 0 : if (n100s >= 0 && nTime >= 0 && n100s <= nTime)
861 : incErrorInt( "Ordering of Time100SecSeparator and TimeSeparator not correct in formatindex=\"%d\".",
862 0 : formatindex);
863 : }
864 0 : 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 0 : n = currNode -> findNode("DefaultName");
876 0 : if (n)
877 0 : of.writeParameter("FormatDefaultName", n->getValue(), formatCount);
878 : else
879 0 : of.writeParameter("FormatDefaultName", ::rtl::OUString(), formatCount);
880 :
881 0 : }
882 :
883 : // Check presence of all required format codes only in first section
884 : // LC_FORMAT, not in optional LC_FORMAT_1
885 0 : if (mnSection == 0)
886 : {
887 : // 0..47 MUST be present, 48,49 MUST NOT be present
888 0 : ValueSet::const_iterator aIter( aFormatIndexSet.begin());
889 0 : for (sal_Int16 nNext = cssi::NumberFormatIndex::NUMBER_START;
890 : nNext < cssi::NumberFormatIndex::INDEX_TABLE_ENTRIES; ++nNext)
891 : {
892 0 : sal_Int16 nHere = ::std::min( ((aIter != aFormatIndexSet.end() ? *aIter :
893 : cssi::NumberFormatIndex::INDEX_TABLE_ENTRIES)),
894 0 : cssi::NumberFormatIndex::INDEX_TABLE_ENTRIES);
895 0 : if (aIter != aFormatIndexSet.end()) ++aIter;
896 0 : for ( ; nNext < nHere; ++nNext)
897 : {
898 0 : 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 0 : break;
906 : default:
907 0 : incErrorInt( "FormatElement formatindex=\"%d\" not present.", nNext);
908 : }
909 : }
910 0 : 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 0 : of.writeAsciiString("\nstatic const sal_Int16 ");
925 0 : of.writeAsciiString("FormatElementsCount");
926 0 : of.writeInt(mnSection);
927 0 : of.writeAsciiString(" = ");
928 0 : of.writeInt( formatCount - mnFormats);
929 0 : of.writeAsciiString(";\n");
930 0 : of.writeAsciiString("static const sal_Unicode* ");
931 0 : of.writeAsciiString("FormatElementsArray");
932 0 : of.writeInt(mnSection);
933 0 : of.writeAsciiString("[] = {\n");
934 0 : for(sal_Int16 i = mnFormats; i < formatCount; i++) {
935 :
936 0 : of.writeAsciiString("\t");
937 0 : of.writeAsciiString("FormatCode");
938 0 : of.writeInt(i);
939 0 : of.writeAsciiString(",\n");
940 :
941 0 : of.writeAsciiString("\t");
942 0 : of.writeAsciiString("FormatDefaultName");
943 0 : of.writeInt(i);
944 0 : of.writeAsciiString(",\n");
945 :
946 0 : of.writeAsciiString("\t");
947 0 : of.writeAsciiString("FormatKey");
948 0 : of.writeInt(i);
949 0 : of.writeAsciiString(",\n");
950 :
951 0 : of.writeAsciiString("\t");
952 0 : of.writeAsciiString("FormatType");
953 0 : of.writeInt(i);
954 0 : of.writeAsciiString(",\n");
955 :
956 0 : of.writeAsciiString("\t");
957 0 : of.writeAsciiString("FormatUsage");
958 0 : of.writeInt(i);
959 0 : of.writeAsciiString(",\n");
960 :
961 0 : of.writeAsciiString("\t");
962 0 : of.writeAsciiString("Formatindex");
963 0 : of.writeInt(i);
964 0 : of.writeAsciiString(",\n");
965 :
966 :
967 0 : of.writeAsciiString("\tdefaultFormatElement");
968 0 : of.writeInt(i);
969 0 : of.writeAsciiString(",\n");
970 : }
971 0 : of.writeAsciiString("};\n\n");
972 :
973 0 : switch (mnSection)
974 : {
975 : case 0:
976 0 : of.writeFunction("getAllFormats0_", "FormatElementsCount0", "FormatElementsArray0", "replaceFrom0", "replaceTo0");
977 0 : break;
978 : case 1:
979 0 : of.writeFunction("getAllFormats1_", "FormatElementsCount1", "FormatElementsArray1", "replaceFrom1", "replaceTo1");
980 0 : break;
981 : }
982 :
983 0 : mnFormats = mnFormats + formatCount;
984 :
985 0 : 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 0 : sal_Int32 nIndex = 0;
993 : // aDateSep can be empty if LC_CTYPE was a ref=..., determine from
994 : // FormatCode then.
995 0 : sal_uInt32 cDateSep = (aDateSep.isEmpty() ? 0 : aDateSep.iterateCodePoints( &nIndex));
996 0 : sal_uInt32 cDateSep2 = cDateSep;
997 0 : nIndex = 0;
998 0 : OUStringBuffer aPatternBuf(5);
999 0 : OUStringBuffer aPatternBuf2(5);
1000 0 : sal_uInt8 nDetected = 0; // bits Y,M,D
1001 0 : bool bInModifier = false;
1002 0 : bool bQuoted = false;
1003 0 : while (nIndex < sTheDateEditFormat.getLength() && nDetected < 7)
1004 : {
1005 0 : sal_uInt32 cChar = sTheDateEditFormat.iterateCodePoints( &nIndex);
1006 0 : if (bInModifier)
1007 : {
1008 0 : if (cChar == ']')
1009 0 : bInModifier = false;
1010 0 : continue; // while
1011 : }
1012 0 : if (bQuoted)
1013 : {
1014 0 : if (cChar == '"')
1015 0 : bQuoted = false;
1016 0 : continue; // while
1017 : }
1018 0 : switch (cChar)
1019 : {
1020 : case 'Y':
1021 : case 'y':
1022 0 : if (!(nDetected & 4))
1023 : {
1024 0 : aPatternBuf.append( 'Y');
1025 0 : if (aPatternBuf2.getLength() > 0)
1026 0 : aPatternBuf2.append( 'Y');
1027 0 : nDetected |= 4;
1028 : }
1029 0 : break;
1030 : case 'M':
1031 : case 'm':
1032 0 : if (!(nDetected & 2))
1033 : {
1034 0 : aPatternBuf.append( 'M');
1035 0 : if (aPatternBuf2.getLength() > 0)
1036 0 : aPatternBuf2.append( 'M');
1037 0 : nDetected |= 2;
1038 : }
1039 0 : break;
1040 : case 'D':
1041 : case 'd':
1042 0 : if (!(nDetected & 1))
1043 : {
1044 0 : aPatternBuf.append( 'D');
1045 0 : if (aPatternBuf2.getLength() > 0)
1046 0 : aPatternBuf2.append( 'D');
1047 0 : nDetected |= 1;
1048 : }
1049 0 : break;
1050 : case '[':
1051 0 : bInModifier = true;
1052 0 : 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 0 : cDateSep2 = cChar;
1069 : // fallthru
1070 : default:
1071 0 : if (!cDateSep)
1072 0 : cDateSep = cChar;
1073 0 : if (!cDateSep2)
1074 0 : cDateSep2 = cChar;
1075 0 : if (cDateSep != cDateSep2 && aPatternBuf2.getLength() == 0)
1076 0 : aPatternBuf2 = aPatternBuf;
1077 0 : if (cChar == cDateSep || cChar == cDateSep2)
1078 0 : aPatternBuf.append( OUString( &cDateSep, 1)); // always the defined separator
1079 0 : if (cChar == cDateSep2 && aPatternBuf2.getLength() > 0)
1080 0 : aPatternBuf2.append( OUString( &cDateSep2, 1)); // always the format's separator
1081 0 : break;
1082 : // The localized legacy:
1083 : case 'A':
1084 0 : 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 0 : aPatternBuf.append( 'Y');
1091 0 : if (aPatternBuf2.getLength() > 0)
1092 0 : aPatternBuf2.append( 'Y');
1093 0 : nDetected |= 4;
1094 : }
1095 0 : break;
1096 : case 'J':
1097 0 : if (((nDetected & 7) == 0) || ((nDetected & 7) == 6))
1098 : {
1099 : // fr JJ.MM.AAAA
1100 : // fr_CA AAAA-MM-JJ
1101 0 : aPatternBuf.append( 'D');
1102 0 : if (aPatternBuf2.getLength() > 0)
1103 0 : aPatternBuf2.append( 'D');
1104 0 : nDetected |= 1;
1105 : }
1106 0 : else if ((nDetected & 7) == 3)
1107 : {
1108 : // nl DD-MM-JJJJ
1109 : // de TT.MM.JJJJ
1110 0 : aPatternBuf.append( 'Y');
1111 0 : if (aPatternBuf2.getLength() > 0)
1112 0 : aPatternBuf2.append( 'Y');
1113 0 : nDetected |= 4;
1114 : }
1115 0 : break;
1116 : case 'T':
1117 0 : if ((nDetected & 7) == 0)
1118 : {
1119 : // de TT.MM.JJJJ
1120 0 : aPatternBuf.append( 'D');
1121 0 : if (aPatternBuf2.getLength() > 0)
1122 0 : aPatternBuf2.append( 'D');
1123 0 : nDetected |= 1;
1124 : }
1125 0 : break;
1126 : case 'G':
1127 0 : if ((nDetected & 7) == 0)
1128 : {
1129 : // it GG/MM/AAAA
1130 0 : aPatternBuf.append( 'D');
1131 0 : if (aPatternBuf2.getLength() > 0)
1132 0 : aPatternBuf2.append( 'D');
1133 0 : nDetected |= 1;
1134 : }
1135 0 : break;
1136 : case 'P':
1137 0 : if ((nDetected & 7) == 0)
1138 : {
1139 : // fi PP.KK.VVVV
1140 0 : aPatternBuf.append( 'D');
1141 0 : if (aPatternBuf2.getLength() > 0)
1142 0 : aPatternBuf2.append( 'D');
1143 0 : nDetected |= 1;
1144 : }
1145 0 : break;
1146 : case 'K':
1147 0 : if ((nDetected & 7) == 1)
1148 : {
1149 : // fi PP.KK.VVVV
1150 0 : aPatternBuf.append( 'M');
1151 0 : if (aPatternBuf2.getLength() > 0)
1152 0 : aPatternBuf2.append( 'M');
1153 0 : nDetected |= 2;
1154 : }
1155 0 : break;
1156 : case 'V':
1157 0 : if ((nDetected & 7) == 3)
1158 : {
1159 : // fi PP.KK.VVVV
1160 0 : aPatternBuf.append( 'Y');
1161 0 : if (aPatternBuf2.getLength() > 0)
1162 0 : aPatternBuf2.append( 'Y');
1163 0 : nDetected |= 4;
1164 : }
1165 0 : break;
1166 : }
1167 : }
1168 0 : OUString aPattern( aPatternBuf.makeStringAndClear());
1169 0 : 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 0 : OSTR( OUString( cDateSep)));
1182 : // Insert at front so full date pattern is first in checks.
1183 0 : theDateAcceptancePatterns.insert( theDateAcceptancePatterns.begin(), aPattern);
1184 : }
1185 0 : if (aPatternBuf2.getLength() > 0)
1186 : {
1187 0 : OUString aPattern2( aPatternBuf2.makeStringAndClear());
1188 0 : 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 0 : (int)cssi::NumberFormatIndex::DATE_SYS_DDMMYYYY);
1200 0 : theDateAcceptancePatterns.insert( theDateAcceptancePatterns.begin(), aPattern2);
1201 0 : }
1202 : }
1203 :
1204 : // Rudimentary check if a pattern interferes with decimal number.
1205 0 : nIndex = 0;
1206 0 : sal_uInt32 cDecSep = aDecSep.iterateCodePoints( &nIndex);
1207 0 : for (vector<OUString>::const_iterator aIt = theDateAcceptancePatterns.begin();
1208 0 : aIt != theDateAcceptancePatterns.end(); ++aIt)
1209 : {
1210 0 : if ((*aIt).getLength() == (cDecSep <= 0xffff ? 3 : 4))
1211 : {
1212 0 : nIndex = 1;
1213 0 : 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 0 : for (vector<OUString>::const_iterator aIt = theDateAcceptancePatterns.begin();
1224 0 : aIt != theDateAcceptancePatterns.end(); ++aIt)
1225 : {
1226 0 : for (vector<OUString>::iterator aComp = theDateAcceptancePatterns.begin();
1227 0 : aComp != theDateAcceptancePatterns.end(); /*nop*/)
1228 : {
1229 0 : if (aIt != aComp && *aIt == *aComp)
1230 : {
1231 0 : incErrorStr( "Duplicated DateAcceptancePattern", *aComp);
1232 0 : aComp = theDateAcceptancePatterns.erase( aComp);
1233 : }
1234 : else
1235 0 : ++aComp;
1236 : }
1237 : }
1238 :
1239 0 : sal_Int16 nbOfDateAcceptancePatterns = static_cast<sal_Int16>(theDateAcceptancePatterns.size());
1240 :
1241 0 : for (sal_Int16 i = 0; i < nbOfDateAcceptancePatterns; ++i)
1242 : {
1243 0 : of.writeParameter("DateAcceptancePattern", theDateAcceptancePatterns[i], i);
1244 : }
1245 :
1246 0 : of.writeAsciiString("static const sal_Int16 DateAcceptancePatternsCount = ");
1247 0 : of.writeInt( nbOfDateAcceptancePatterns);
1248 0 : of.writeAsciiString(";\n");
1249 :
1250 0 : of.writeAsciiString("static const sal_Unicode* DateAcceptancePatternsArray[] = {\n");
1251 0 : for (sal_Int16 i = 0; i < nbOfDateAcceptancePatterns; ++i)
1252 : {
1253 0 : of.writeAsciiString("\t");
1254 0 : of.writeAsciiString("DateAcceptancePattern");
1255 0 : of.writeInt(i);
1256 0 : of.writeAsciiString(",\n");
1257 : }
1258 0 : of.writeAsciiString("};\n\n");
1259 :
1260 0 : of.writeFunction("getDateAcceptancePatterns_", "DateAcceptancePatternsCount", "DateAcceptancePatternsArray");
1261 : }
1262 :
1263 0 : ++mnSection;
1264 : }
1265 :
1266 0 : void LCCollationNode::generateCode (const OFileWriter &of) const
1267 : {
1268 0 : ::rtl::OUString useLocale = getAttr().getValueByName("ref");
1269 0 : if (!useLocale.isEmpty()) {
1270 0 : of.writeRefFunction("getCollatorImplementation_", useLocale);
1271 0 : of.writeRefFunction("getCollationOptions_", useLocale);
1272 0 : return;
1273 : }
1274 0 : sal_Int16 nbOfCollations = 0;
1275 0 : sal_Int16 nbOfCollationOptions = 0;
1276 : sal_Int16 j;
1277 :
1278 0 : for ( j = 0; j < getNumberOfChildren(); j++ ) {
1279 0 : LocaleNode * currNode = getChildAt (j);
1280 0 : if( currNode->getName().compareToAscii("Collator") == 0 )
1281 : {
1282 0 : ::rtl::OUString str;
1283 0 : str = currNode->getAttr().getValueByName("unoid");
1284 0 : of.writeParameter("CollatorID", str, j);
1285 0 : str = currNode->getValue();
1286 0 : of.writeParameter("CollatorRule", str, j);
1287 0 : str = currNode -> getAttr().getValueByName("default");
1288 0 : of.writeDefaultParameter("Collator", str, j);
1289 0 : of.writeAsciiString("\n");
1290 :
1291 0 : nbOfCollations++;
1292 : }
1293 0 : if( currNode->getName().compareToAscii("CollationOptions") == 0 )
1294 : {
1295 0 : LocaleNode* pCollationOptions = currNode;
1296 0 : nbOfCollationOptions = sal::static_int_cast<sal_Int16>( pCollationOptions->getNumberOfChildren() );
1297 0 : for( sal_Int16 i=0; i<nbOfCollationOptions; i++ )
1298 : {
1299 0 : of.writeParameter("collationOption", pCollationOptions->getChildAt( i )->getValue(), i );
1300 : }
1301 :
1302 0 : of.writeAsciiString("static const sal_Int16 nbOfCollationOptions = ");
1303 0 : of.writeInt( nbOfCollationOptions );
1304 0 : of.writeAsciiString(";\n\n");
1305 : }
1306 : }
1307 0 : of.writeAsciiString("static const sal_Int16 nbOfCollations = ");
1308 0 : of.writeInt(nbOfCollations);
1309 0 : of.writeAsciiString(";\n\n");
1310 :
1311 0 : of.writeAsciiString("\nstatic const sal_Unicode* LCCollatorArray[] = {\n");
1312 0 : for(j = 0; j < nbOfCollations; j++) {
1313 0 : of.writeAsciiString("\tCollatorID");
1314 0 : of.writeInt(j);
1315 0 : of.writeAsciiString(",\n");
1316 :
1317 0 : of.writeAsciiString("\tdefaultCollator");
1318 0 : of.writeInt(j);
1319 0 : of.writeAsciiString(",\n");
1320 :
1321 0 : of.writeAsciiString("\tCollatorRule");
1322 0 : of.writeInt(j);
1323 0 : of.writeAsciiString(",\n");
1324 : }
1325 0 : of.writeAsciiString("};\n\n");
1326 :
1327 0 : of.writeAsciiString("static const sal_Unicode* collationOptions[] = {");
1328 0 : for( j=0; j<nbOfCollationOptions; j++ )
1329 : {
1330 0 : of.writeAsciiString( "collationOption" );
1331 0 : of.writeInt( j );
1332 0 : of.writeAsciiString( ", " );
1333 : }
1334 0 : of.writeAsciiString("NULL };\n");
1335 0 : of.writeFunction("getCollatorImplementation_", "nbOfCollations", "LCCollatorArray");
1336 0 : of.writeFunction("getCollationOptions_", "nbOfCollationOptions", "collationOptions");
1337 : }
1338 :
1339 0 : void LCSearchNode::generateCode (const OFileWriter &of) const
1340 : {
1341 0 : ::rtl::OUString useLocale = getAttr().getValueByName("ref");
1342 0 : if (!useLocale.isEmpty()) {
1343 0 : of.writeRefFunction("getSearchOptions_", useLocale);
1344 0 : return;
1345 : }
1346 :
1347 0 : 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 0 : LocaleNode* pSearchOptions = getChildAt( 0 );
1356 0 : sal_Int32 nSearchOptions = pSearchOptions->getNumberOfChildren();
1357 0 : for( i=0; i<nSearchOptions; i++ )
1358 : {
1359 0 : of.writeParameter("searchOption", pSearchOptions->getChildAt( i )->getValue(), sal::static_int_cast<sal_Int16>(i) );
1360 : }
1361 :
1362 0 : of.writeAsciiString("static const sal_Int16 nbOfSearchOptions = ");
1363 0 : of.writeInt( sal::static_int_cast<sal_Int16>( nSearchOptions ) );
1364 0 : of.writeAsciiString(";\n\n");
1365 :
1366 0 : of.writeAsciiString("static const sal_Unicode* searchOptions[] = {");
1367 0 : for( i=0; i<nSearchOptions; i++ )
1368 : {
1369 0 : of.writeAsciiString( "searchOption" );
1370 0 : of.writeInt( sal::static_int_cast<sal_Int16>(i) );
1371 0 : of.writeAsciiString( ", " );
1372 : }
1373 0 : of.writeAsciiString("NULL };\n");
1374 0 : of.writeFunction("getSearchOptions_", "nbOfSearchOptions", "searchOptions");
1375 : }
1376 :
1377 0 : void LCIndexNode::generateCode (const OFileWriter &of) const
1378 : {
1379 0 : ::rtl::OUString useLocale = getAttr().getValueByName("ref");
1380 0 : if (!useLocale.isEmpty()) {
1381 0 : of.writeRefFunction("getIndexAlgorithm_", useLocale);
1382 0 : of.writeRefFunction("getUnicodeScripts_", useLocale);
1383 0 : of.writeRefFunction("getFollowPageWords_", useLocale);
1384 0 : return;
1385 : }
1386 0 : sal_Int16 nbOfIndexs = 0;
1387 0 : sal_Int16 nbOfUnicodeScripts = 0;
1388 0 : sal_Int16 nbOfPageWords = 0;
1389 : sal_Int16 i;
1390 0 : for (i = 0; i< getNumberOfChildren();i++) {
1391 0 : LocaleNode * currNode = getChildAt (i);
1392 0 : if( currNode->getName().compareToAscii("IndexKey") == 0 )
1393 : {
1394 0 : ::rtl::OUString str;
1395 0 : str = currNode->getAttr().getValueByName("unoid");
1396 0 : of.writeParameter("IndexID", str, nbOfIndexs);
1397 0 : str = currNode->getAttr().getValueByName("module");
1398 0 : of.writeParameter("IndexModule", str, nbOfIndexs);
1399 0 : str = currNode->getValue();
1400 0 : of.writeParameter("IndexKey", str, nbOfIndexs);
1401 0 : str = currNode -> getAttr().getValueByName("default");
1402 0 : of.writeDefaultParameter("Index", str, nbOfIndexs);
1403 0 : str = currNode -> getAttr().getValueByName("phonetic");
1404 0 : of.writeDefaultParameter("Phonetic", str, nbOfIndexs);
1405 0 : of.writeAsciiString("\n");
1406 :
1407 0 : nbOfIndexs++;
1408 : }
1409 0 : if( currNode->getName().compareToAscii("UnicodeScript") == 0 )
1410 : {
1411 0 : of.writeParameter("unicodeScript", currNode->getValue(), nbOfUnicodeScripts );
1412 0 : nbOfUnicodeScripts++;
1413 :
1414 : }
1415 0 : if( currNode->getName().compareToAscii("FollowPageWord") == 0 )
1416 : {
1417 0 : of.writeParameter("followPageWord", currNode->getValue(), nbOfPageWords);
1418 0 : nbOfPageWords++;
1419 : }
1420 : }
1421 0 : of.writeAsciiString("static const sal_Int16 nbOfIndexs = ");
1422 0 : of.writeInt(nbOfIndexs);
1423 0 : of.writeAsciiString(";\n\n");
1424 :
1425 0 : of.writeAsciiString("\nstatic const sal_Unicode* IndexArray[] = {\n");
1426 0 : for(i = 0; i < nbOfIndexs; i++) {
1427 0 : of.writeAsciiString("\tIndexID");
1428 0 : of.writeInt(i);
1429 0 : of.writeAsciiString(",\n");
1430 :
1431 0 : of.writeAsciiString("\tIndexModule");
1432 0 : of.writeInt(i);
1433 0 : of.writeAsciiString(",\n");
1434 :
1435 0 : of.writeAsciiString("\tIndexKey");
1436 0 : of.writeInt(i);
1437 0 : of.writeAsciiString(",\n");
1438 :
1439 0 : of.writeAsciiString("\tdefaultIndex");
1440 0 : of.writeInt(i);
1441 0 : of.writeAsciiString(",\n");
1442 :
1443 0 : of.writeAsciiString("\tdefaultPhonetic");
1444 0 : of.writeInt(i);
1445 0 : of.writeAsciiString(",\n");
1446 : }
1447 0 : of.writeAsciiString("};\n\n");
1448 :
1449 0 : of.writeAsciiString("static const sal_Int16 nbOfUnicodeScripts = ");
1450 0 : of.writeInt( nbOfUnicodeScripts );
1451 0 : of.writeAsciiString(";\n\n");
1452 :
1453 0 : of.writeAsciiString("static const sal_Unicode* UnicodeScriptArray[] = {");
1454 0 : for( i=0; i<nbOfUnicodeScripts; i++ )
1455 : {
1456 0 : of.writeAsciiString( "unicodeScript" );
1457 0 : of.writeInt( i );
1458 0 : of.writeAsciiString( ", " );
1459 : }
1460 0 : of.writeAsciiString("NULL };\n\n");
1461 :
1462 0 : of.writeAsciiString("static const sal_Int16 nbOfPageWords = ");
1463 0 : of.writeInt(nbOfPageWords);
1464 0 : of.writeAsciiString(";\n\n");
1465 :
1466 0 : of.writeAsciiString("static const sal_Unicode* FollowPageWordArray[] = {\n");
1467 0 : for(i = 0; i < nbOfPageWords; i++) {
1468 0 : of.writeAsciiString("\tfollowPageWord");
1469 0 : of.writeInt(i);
1470 0 : of.writeAsciiString(",\n");
1471 : }
1472 0 : of.writeAsciiString("\tNULL\n};\n\n");
1473 :
1474 0 : of.writeFunction("getIndexAlgorithm_", "nbOfIndexs", "IndexArray");
1475 0 : of.writeFunction("getUnicodeScripts_", "nbOfUnicodeScripts", "UnicodeScriptArray");
1476 0 : of.writeFunction("getFollowPageWords_", "nbOfPageWords", "FollowPageWordArray");
1477 : }
1478 :
1479 :
1480 0 : static void lcl_writeAbbrFullNarrNames( const OFileWriter & of, const LocaleNode* currNode,
1481 : const sal_Char* elementTag, sal_Int16 i, sal_Int16 j )
1482 : {
1483 0 : OUString aAbbrName = currNode->getChildAt(1)->getValue();
1484 0 : OUString aFullName = currNode->getChildAt(2)->getValue();
1485 0 : OUString aNarrName;
1486 0 : LocaleNode* p = (currNode->getNumberOfChildren() > 3 ? currNode->getChildAt(3) : 0);
1487 0 : if ( p && p->getName() == "DefaultNarrowName" )
1488 0 : aNarrName = p->getValue();
1489 : else
1490 : {
1491 0 : sal_Int32 nIndex = 0;
1492 0 : sal_uInt32 nChar = aFullName.iterateCodePoints( &nIndex);
1493 0 : aNarrName = OUString( &nChar, 1);
1494 : }
1495 0 : of.writeParameter( elementTag, "DefaultAbbrvName", aAbbrName, i, j);
1496 0 : of.writeParameter( elementTag, "DefaultFullName", aFullName, i, j);
1497 0 : of.writeParameter( elementTag, "DefaultNarrowName", aNarrName, i, j);
1498 0 : }
1499 :
1500 0 : static void lcl_writeTabTagString( const OFileWriter & of, const sal_Char* pTag, const sal_Char* pStr )
1501 : {
1502 0 : of.writeAsciiString("\t");
1503 0 : of.writeAsciiString( pTag);
1504 0 : of.writeAsciiString( pStr);
1505 0 : }
1506 :
1507 0 : static void lcl_writeTabTagStringNums( const OFileWriter & of,
1508 : const sal_Char* pTag, const sal_Char* pStr, sal_Int16 i, sal_Int16 j )
1509 : {
1510 0 : lcl_writeTabTagString( of, pTag, pStr);
1511 0 : of.writeInt(i); of.writeInt(j); of.writeAsciiString(",\n");
1512 0 : }
1513 :
1514 0 : static void lcl_writeAbbrFullNarrArrays( const OFileWriter & of, sal_Int16 nCount,
1515 : const sal_Char* elementTag, sal_Int16 i, bool bNarrow )
1516 : {
1517 0 : if (nCount == 0)
1518 : {
1519 0 : lcl_writeTabTagString( of, elementTag, "Ref");
1520 0 : of.writeInt(i); of.writeAsciiString(",\n");
1521 0 : lcl_writeTabTagString( of, elementTag, "RefName");
1522 0 : of.writeInt(i); of.writeAsciiString(",\n");
1523 : }
1524 : else
1525 : {
1526 0 : for (sal_Int16 j = 0; j < nCount; j++)
1527 : {
1528 0 : lcl_writeTabTagStringNums( of, elementTag, "ID", i, j);
1529 0 : lcl_writeTabTagStringNums( of, elementTag, "DefaultAbbrvName", i, j);
1530 0 : lcl_writeTabTagStringNums( of, elementTag, "DefaultFullName", i, j);
1531 0 : if (bNarrow)
1532 0 : lcl_writeTabTagStringNums( of, elementTag, "DefaultNarrowName", i, j);
1533 : }
1534 : }
1535 0 : }
1536 :
1537 0 : void LCCalendarNode::generateCode (const OFileWriter &of) const
1538 : {
1539 0 : ::rtl::OUString useLocale = getAttr().getValueByName("ref");
1540 0 : if (!useLocale.isEmpty()) {
1541 0 : of.writeRefFunction("getAllCalendars_", useLocale);
1542 0 : return;
1543 : }
1544 0 : sal_Int16 nbOfCalendars = sal::static_int_cast<sal_Int16>( getNumberOfChildren() );
1545 0 : ::rtl::OUString str;
1546 0 : sal_Int16 * nbOfDays = new sal_Int16[nbOfCalendars];
1547 0 : sal_Int16 * nbOfMonths = new sal_Int16[nbOfCalendars];
1548 0 : sal_Int16 * nbOfGenitiveMonths = new sal_Int16[nbOfCalendars];
1549 0 : sal_Int16 * nbOfPartitiveMonths = new sal_Int16[nbOfCalendars];
1550 0 : sal_Int16 * nbOfEras = new sal_Int16[nbOfCalendars];
1551 : sal_Int16 j;
1552 : sal_Int16 i;
1553 0 : bool bHasGregorian = false;
1554 :
1555 :
1556 0 : for ( i = 0; i < nbOfCalendars; i++) {
1557 0 : LocaleNode * calNode = getChildAt (i);
1558 0 : OUString calendarID = calNode -> getAttr().getValueByName("unoid");
1559 0 : of.writeParameter( "calendarID", calendarID, i);
1560 0 : bool bGregorian = calendarID == "gregorian";
1561 0 : if (!bHasGregorian)
1562 0 : bHasGregorian = bGregorian;
1563 0 : str = calNode -> getAttr().getValueByName("default");
1564 0 : of.writeDefaultParameter("Calendar", str, i);
1565 :
1566 0 : sal_Int16 nChild = 0;
1567 :
1568 : // Generate Days of Week
1569 : const sal_Char *elementTag;
1570 0 : LocaleNode * daysNode = NULL;
1571 0 : ::rtl::OUString ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
1572 0 : if (!ref_name.isEmpty() && i > 0) {
1573 0 : for (j = 0; j < i; j++) {
1574 0 : str = getChildAt(j)->getAttr().getValueByName("unoid");
1575 0 : if (str.equals(ref_name))
1576 0 : daysNode = getChildAt(j)->getChildAt(0);
1577 : }
1578 : }
1579 0 : if (!ref_name.isEmpty() && daysNode == NULL) {
1580 0 : of.writeParameter("dayRef", OUString("ref"), i);
1581 0 : of.writeParameter("dayRefName", ref_name, i);
1582 0 : nbOfDays[i] = 0;
1583 : } else {
1584 0 : if (daysNode == NULL)
1585 0 : daysNode = calNode -> getChildAt(nChild);
1586 0 : nbOfDays[i] = sal::static_int_cast<sal_Int16>( daysNode->getNumberOfChildren() );
1587 0 : if (bGregorian && nbOfDays[i] != 7)
1588 0 : incErrorInt( "A Gregorian calendar must have 7 days per week, this one has %d", nbOfDays[i]);
1589 0 : elementTag = "day";
1590 0 : for (j = 0; j < nbOfDays[i]; j++) {
1591 0 : LocaleNode *currNode = daysNode -> getChildAt(j);
1592 0 : OUString dayID( currNode->getChildAt(0)->getValue());
1593 0 : of.writeParameter("dayID", dayID, i, j);
1594 0 : if ( j == 0 && bGregorian && dayID != "sun" )
1595 0 : incError( "First day of a week of a Gregorian calendar must be <DayID>sun</DayID>");
1596 0 : lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
1597 0 : }
1598 : }
1599 0 : ++nChild;
1600 :
1601 : // Generate Months of Year
1602 0 : LocaleNode * monthsNode = NULL;
1603 0 : ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
1604 0 : if (!ref_name.isEmpty() && i > 0) {
1605 0 : for (j = 0; j < i; j++) {
1606 0 : str = getChildAt(j)->getAttr().getValueByName("unoid");
1607 0 : if (str.equals(ref_name))
1608 0 : monthsNode = getChildAt(j)->getChildAt(1);
1609 : }
1610 : }
1611 0 : if (!ref_name.isEmpty() && monthsNode == NULL) {
1612 0 : of.writeParameter("monthRef", OUString("ref"), i);
1613 0 : of.writeParameter("monthRefName", ref_name, i);
1614 0 : nbOfMonths[i] = 0;
1615 : } else {
1616 0 : if (monthsNode == NULL)
1617 0 : monthsNode = calNode -> getChildAt(nChild);
1618 0 : nbOfMonths[i] = sal::static_int_cast<sal_Int16>( monthsNode->getNumberOfChildren() );
1619 0 : if (bGregorian && nbOfMonths[i] != 12)
1620 0 : incErrorInt( "A Gregorian calendar must have 12 months, this one has %d", nbOfMonths[i]);
1621 0 : elementTag = "month";
1622 0 : for (j = 0; j < nbOfMonths[i]; j++) {
1623 0 : LocaleNode *currNode = monthsNode -> getChildAt(j);
1624 0 : OUString monthID( currNode->getChildAt(0)->getValue());
1625 0 : of.writeParameter("monthID", monthID, i, j);
1626 0 : if ( j == 0 && bGregorian && monthID != "jan" )
1627 0 : incError( "First month of a year of a Gregorian calendar must be <MonthID>jan</MonthID>");
1628 0 : lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
1629 0 : }
1630 : }
1631 0 : ++nChild;
1632 :
1633 : // Generate genitive Months of Year
1634 : // Optional, if not present fall back to month nouns.
1635 0 : if ( calNode->getChildAt(nChild)->getName() != "GenitiveMonths" )
1636 0 : --nChild;
1637 0 : LocaleNode * genitiveMonthsNode = NULL;
1638 0 : ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
1639 0 : if (!ref_name.isEmpty() && i > 0) {
1640 0 : for (j = 0; j < i; j++) {
1641 0 : str = getChildAt(j)->getAttr().getValueByName("unoid");
1642 0 : if (str.equals(ref_name))
1643 0 : genitiveMonthsNode = getChildAt(j)->getChildAt(1);
1644 : }
1645 : }
1646 0 : if (!ref_name.isEmpty() && genitiveMonthsNode == NULL) {
1647 0 : of.writeParameter("genitiveMonthRef", OUString("ref"), i);
1648 0 : of.writeParameter("genitiveMonthRefName", ref_name, i);
1649 0 : nbOfGenitiveMonths[i] = 0;
1650 : } else {
1651 0 : if (genitiveMonthsNode == NULL)
1652 0 : genitiveMonthsNode = calNode -> getChildAt(nChild);
1653 0 : nbOfGenitiveMonths[i] = sal::static_int_cast<sal_Int16>( genitiveMonthsNode->getNumberOfChildren() );
1654 0 : if (bGregorian && nbOfGenitiveMonths[i] != 12)
1655 0 : incErrorInt( "A Gregorian calendar must have 12 genitive months, this one has %d", nbOfGenitiveMonths[i]);
1656 0 : elementTag = "genitiveMonth";
1657 0 : for (j = 0; j < nbOfGenitiveMonths[i]; j++) {
1658 0 : LocaleNode *currNode = genitiveMonthsNode -> getChildAt(j);
1659 0 : OUString genitiveMonthID( currNode->getChildAt(0)->getValue());
1660 0 : of.writeParameter("genitiveMonthID", genitiveMonthID, i, j);
1661 0 : 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 0 : lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
1664 0 : }
1665 : }
1666 0 : ++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 0 : if ( calNode->getChildAt(nChild)->getName() != "PartitiveMonths" )
1672 0 : --nChild;
1673 0 : LocaleNode * partitiveMonthsNode = NULL;
1674 0 : ref_name = calNode->getChildAt(nChild)->getAttr().getValueByName("ref");
1675 0 : if (!ref_name.isEmpty() && i > 0) {
1676 0 : for (j = 0; j < i; j++) {
1677 0 : str = getChildAt(j)->getAttr().getValueByName("unoid");
1678 0 : if (str.equals(ref_name))
1679 0 : partitiveMonthsNode = getChildAt(j)->getChildAt(1);
1680 : }
1681 : }
1682 0 : if (!ref_name.isEmpty() && partitiveMonthsNode == NULL) {
1683 0 : of.writeParameter("partitiveMonthRef", OUString("ref"), i);
1684 0 : of.writeParameter("partitiveMonthRefName", ref_name, i);
1685 0 : nbOfPartitiveMonths[i] = 0;
1686 : } else {
1687 0 : if (partitiveMonthsNode == NULL)
1688 0 : partitiveMonthsNode = calNode -> getChildAt(nChild);
1689 0 : nbOfPartitiveMonths[i] = sal::static_int_cast<sal_Int16>( partitiveMonthsNode->getNumberOfChildren() );
1690 0 : if (bGregorian && nbOfPartitiveMonths[i] != 12)
1691 0 : incErrorInt( "A Gregorian calendar must have 12 partitive months, this one has %d", nbOfPartitiveMonths[i]);
1692 0 : elementTag = "partitiveMonth";
1693 0 : for (j = 0; j < nbOfPartitiveMonths[i]; j++) {
1694 0 : LocaleNode *currNode = partitiveMonthsNode -> getChildAt(j);
1695 0 : OUString partitiveMonthID( currNode->getChildAt(0)->getValue());
1696 0 : of.writeParameter("partitiveMonthID", partitiveMonthID, i, j);
1697 0 : 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 0 : lcl_writeAbbrFullNarrNames( of, currNode, elementTag, i, j);
1700 0 : }
1701 : }
1702 0 : ++nChild;
1703 :
1704 : // Generate Era name
1705 0 : LocaleNode * erasNode = NULL;
1706 0 : ref_name = calNode -> getChildAt(nChild) ->getAttr().getValueByName("ref");
1707 0 : 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 0 : if (!ref_name.isEmpty() && erasNode == NULL) {
1715 0 : of.writeParameter("eraRef", OUString("ref"), i);
1716 0 : of.writeParameter("eraRefName", ref_name, i);
1717 0 : nbOfEras[i] = 0;
1718 : } else {
1719 0 : if (erasNode == NULL)
1720 0 : erasNode = calNode -> getChildAt(nChild);
1721 0 : nbOfEras[i] = sal::static_int_cast<sal_Int16>( erasNode->getNumberOfChildren() );
1722 0 : if (bGregorian && nbOfEras[i] != 2)
1723 0 : incErrorInt( "A Gregorian calendar must have 2 eras, this one has %d", nbOfEras[i]);
1724 0 : elementTag = "era";
1725 0 : for (j = 0; j < nbOfEras[i]; j++) {
1726 0 : LocaleNode *currNode = erasNode -> getChildAt(j);
1727 0 : OUString eraID( currNode->getChildAt(0)->getValue());
1728 0 : of.writeParameter("eraID", eraID, i, j);
1729 0 : if ( j == 0 && bGregorian && eraID != "bc" )
1730 0 : incError( "First era of a Gregorian calendar must be <EraID>bc</EraID>");
1731 0 : if ( j == 1 && bGregorian && eraID != "ad" )
1732 0 : incError( "Second era of a Gregorian calendar must be <EraID>ad</EraID>");
1733 0 : of.writeAsciiString("\n");
1734 0 : of.writeParameter(elementTag, "DefaultAbbrvName",currNode->getChildAt(1)->getValue() ,i, j);
1735 0 : of.writeParameter(elementTag, "DefaultFullName",currNode->getChildAt(2)->getValue() , i, j);
1736 0 : }
1737 : }
1738 0 : ++nChild;
1739 :
1740 0 : str = calNode->getChildAt(nChild)->getChildAt(0)->getValue();
1741 0 : if (nbOfDays[i])
1742 : {
1743 0 : for (j = 0; j < nbOfDays[i]; j++)
1744 : {
1745 0 : LocaleNode *currNode = daysNode->getChildAt(j);
1746 0 : OUString dayID( currNode->getChildAt(0)->getValue());
1747 0 : if (str == dayID)
1748 : break; // for
1749 0 : }
1750 0 : if (j >= nbOfDays[i])
1751 0 : incErrorStr( "<StartDayOfWeek> <DayID> must be one of the <DaysOfWeek>, but is", str);
1752 : }
1753 0 : of.writeParameter("startDayOfWeek", str, i);
1754 0 : ++nChild;
1755 :
1756 0 : str = calNode ->getChildAt(nChild)-> getValue();
1757 0 : sal_Int16 nDays = sal::static_int_cast<sal_Int16>( str.toInt32() );
1758 0 : 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 0 : of.writeIntParameter("minimalDaysInFirstWeek", i, nDays);
1761 0 : }
1762 0 : if (!bHasGregorian)
1763 0 : fprintf( stderr, "Warning: %s\n", "No Gregorian calendar defined, are you sure?");
1764 :
1765 0 : of.writeAsciiString("static const sal_Int16 calendarsCount = ");
1766 0 : of.writeInt(nbOfCalendars);
1767 0 : of.writeAsciiString(";\n\n");
1768 :
1769 0 : of.writeAsciiString("static const sal_Unicode nbOfDays[] = {");
1770 0 : for(i = 0; i < nbOfCalendars - 1; i++) {
1771 0 : of.writeInt(nbOfDays[i]);
1772 0 : of.writeAsciiString(", ");
1773 : };
1774 0 : of.writeInt(nbOfDays[i]);
1775 0 : of.writeAsciiString("};\n");
1776 :
1777 0 : of.writeAsciiString("static const sal_Unicode nbOfMonths[] = {");
1778 0 : for(i = 0; i < nbOfCalendars - 1; i++) {
1779 0 : of.writeInt(nbOfMonths[i]);
1780 0 : of.writeAsciiString(", ");
1781 : };
1782 0 : of.writeInt(nbOfMonths[i]);
1783 0 : of.writeAsciiString("};\n");
1784 :
1785 0 : of.writeAsciiString("static const sal_Unicode nbOfGenitiveMonths[] = {");
1786 0 : for(i = 0; i < nbOfCalendars - 1; i++) {
1787 0 : of.writeInt(nbOfGenitiveMonths[i]);
1788 0 : of.writeAsciiString(", ");
1789 : };
1790 0 : of.writeInt(nbOfGenitiveMonths[i]);
1791 0 : of.writeAsciiString("};\n");
1792 :
1793 0 : of.writeAsciiString("static const sal_Unicode nbOfPartitiveMonths[] = {");
1794 0 : for(i = 0; i < nbOfCalendars - 1; i++) {
1795 0 : of.writeInt(nbOfPartitiveMonths[i]);
1796 0 : of.writeAsciiString(", ");
1797 : };
1798 0 : of.writeInt(nbOfPartitiveMonths[i]);
1799 0 : of.writeAsciiString("};\n");
1800 :
1801 0 : of.writeAsciiString("static const sal_Unicode nbOfEras[] = {");
1802 0 : for(i = 0; i < nbOfCalendars - 1; i++) {
1803 0 : of.writeInt(nbOfEras[i]);
1804 0 : of.writeAsciiString(", ");
1805 : };
1806 0 : of.writeInt(nbOfEras[i]);
1807 0 : of.writeAsciiString("};\n");
1808 :
1809 :
1810 0 : of.writeAsciiString("static const sal_Unicode* calendars[] = {\n");
1811 0 : of.writeAsciiString("\tnbOfDays,\n");
1812 0 : of.writeAsciiString("\tnbOfMonths,\n");
1813 0 : of.writeAsciiString("\tnbOfGenitiveMonths,\n");
1814 0 : of.writeAsciiString("\tnbOfPartitiveMonths,\n");
1815 0 : of.writeAsciiString("\tnbOfEras,\n");
1816 0 : for(i = 0; i < nbOfCalendars; i++) {
1817 0 : of.writeAsciiString("\tcalendarID");
1818 0 : of.writeInt(i);
1819 0 : of.writeAsciiString(",\n");
1820 0 : of.writeAsciiString("\tdefaultCalendar");
1821 0 : of.writeInt(i);
1822 0 : of.writeAsciiString(",\n");
1823 0 : lcl_writeAbbrFullNarrArrays( of, nbOfDays[i], "day", i, true);
1824 0 : lcl_writeAbbrFullNarrArrays( of, nbOfMonths[i], "month", i, true);
1825 0 : lcl_writeAbbrFullNarrArrays( of, nbOfGenitiveMonths[i], "genitiveMonth", i, true);
1826 0 : lcl_writeAbbrFullNarrArrays( of, nbOfPartitiveMonths[i], "partitiveMonth", i, true);
1827 0 : lcl_writeAbbrFullNarrArrays( of, nbOfEras[i], "era", i, false /*noNarrow*/);
1828 0 : of.writeAsciiString("\tstartDayOfWeek");of.writeInt(i); of.writeAsciiString(",\n");
1829 0 : of.writeAsciiString("\tminimalDaysInFirstWeek");of.writeInt(i); of.writeAsciiString(",\n");
1830 : }
1831 :
1832 0 : of.writeAsciiString("};\n\n");
1833 0 : of.writeFunction("getAllCalendars_", "calendarsCount", "calendars");
1834 :
1835 0 : delete []nbOfDays;
1836 0 : delete []nbOfMonths;
1837 0 : delete []nbOfGenitiveMonths;
1838 0 : delete []nbOfPartitiveMonths;
1839 0 : delete []nbOfEras;
1840 : }
1841 :
1842 0 : bool isIso4217( const OUString& rStr )
1843 : {
1844 0 : const sal_Unicode* p = rStr.getStr();
1845 0 : return rStr.getLength() == 3
1846 0 : && 'A' <= p[0] && p[0] <= 'Z'
1847 0 : && 'A' <= p[1] && p[1] <= 'Z'
1848 0 : && 'A' <= p[2] && p[2] <= 'Z'
1849 : ;
1850 : }
1851 :
1852 0 : void LCCurrencyNode :: generateCode (const OFileWriter &of) const
1853 : {
1854 0 : ::rtl::OUString useLocale = getAttr().getValueByName("ref");
1855 0 : if (!useLocale.isEmpty()) {
1856 0 : of.writeRefFunction("getAllCurrencies_", useLocale);
1857 0 : return;
1858 : }
1859 0 : sal_Int16 nbOfCurrencies = 0;
1860 0 : ::rtl::OUString str;
1861 : sal_Int16 i;
1862 :
1863 0 : bool bTheDefault= false;
1864 0 : bool bTheCompatible = false;
1865 0 : for ( i = 0; i < getNumberOfChildren(); i++,nbOfCurrencies++) {
1866 0 : LocaleNode * currencyNode = getChildAt (i);
1867 0 : str = currencyNode->getAttr().getValueByName("default");
1868 0 : bool bDefault = of.writeDefaultParameter("Currency", str, nbOfCurrencies);
1869 0 : str = currencyNode->getAttr().getValueByName("usedInCompatibleFormatCodes");
1870 0 : bool bCompatible = of.writeDefaultParameter("CurrencyUsedInCompatibleFormatCodes", str, nbOfCurrencies);
1871 0 : str = currencyNode->getAttr().getValueByName("legacyOnly");
1872 0 : bool bLegacy = of.writeDefaultParameter("CurrencyLegacyOnly", str, nbOfCurrencies);
1873 0 : if (bLegacy && (bDefault || bCompatible))
1874 0 : incError( "Currency: if legacyOnly==true, both 'default' and 'usedInCompatibleFormatCodes' must be false.");
1875 0 : if (bDefault)
1876 : {
1877 0 : if (bTheDefault)
1878 0 : incError( "Currency: more than one default currency.");
1879 0 : bTheDefault = true;
1880 : }
1881 0 : if (bCompatible)
1882 : {
1883 0 : if (bTheCompatible)
1884 0 : incError( "Currency: more than one currency flagged as usedInCompatibleFormatCodes.");
1885 0 : bTheCompatible = true;
1886 : }
1887 0 : str = currencyNode -> findNode ("CurrencyID") -> getValue();
1888 0 : of.writeParameter("currencyID", str, nbOfCurrencies);
1889 : // CurrencyID MUST be ISO 4217.
1890 0 : if (!bLegacy && !isIso4217(str))
1891 0 : incError( "CurrencyID is not ISO 4217");
1892 0 : str = currencyNode -> findNode ("CurrencySymbol") -> getValue();
1893 0 : 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 0 : 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 0 : str = currencyNode -> findNode ("BankSymbol") -> getValue();
1901 0 : 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 0 : if (!bLegacy && !isIso4217(str))
1905 0 : incError( "BankSymbol is not ISO 4217");
1906 0 : str = currencyNode -> findNode ("CurrencyName") -> getValue();
1907 0 : of.writeParameter("currencyName", str, nbOfCurrencies);
1908 0 : str = currencyNode -> findNode ("DecimalPlaces") -> getValue();
1909 0 : sal_Int16 nDecimalPlaces = (sal_Int16)str.toInt32();
1910 0 : of.writeIntParameter("currencyDecimalPlaces", nbOfCurrencies, nDecimalPlaces);
1911 0 : of.writeAsciiString("\n");
1912 : };
1913 :
1914 0 : if (!bTheDefault)
1915 0 : incError( "Currency: no default currency.");
1916 0 : if (!bTheCompatible)
1917 0 : incError( "Currency: no currency flagged as usedInCompatibleFormatCodes.");
1918 :
1919 0 : of.writeAsciiString("static const sal_Int16 currencyCount = ");
1920 0 : of.writeInt(nbOfCurrencies);
1921 0 : of.writeAsciiString(";\n\n");
1922 0 : of.writeAsciiString("static const sal_Unicode* currencies[] = {\n");
1923 0 : for(i = 0; i < nbOfCurrencies; i++) {
1924 0 : of.writeAsciiString("\tcurrencyID");
1925 0 : of.writeInt(i);
1926 0 : of.writeAsciiString(",\n");
1927 0 : of.writeAsciiString("\tcurrencySymbol");
1928 0 : of.writeInt(i);
1929 0 : of.writeAsciiString(",\n");
1930 0 : of.writeAsciiString("\tbankSymbol");
1931 0 : of.writeInt(i);
1932 0 : of.writeAsciiString(",\n");
1933 0 : of.writeAsciiString("\tcurrencyName");
1934 0 : of.writeInt(i);
1935 0 : of.writeAsciiString(",\n");
1936 0 : of.writeAsciiString("\tdefaultCurrency");
1937 0 : of.writeInt(i);
1938 0 : of.writeAsciiString(",\n");
1939 0 : of.writeAsciiString("\tdefaultCurrencyUsedInCompatibleFormatCodes");
1940 0 : of.writeInt(i);
1941 0 : of.writeAsciiString(",\n");
1942 0 : of.writeAsciiString("\tcurrencyDecimalPlaces");
1943 0 : of.writeInt(i);
1944 0 : of.writeAsciiString(",\n");
1945 0 : of.writeAsciiString("\tdefaultCurrencyLegacyOnly");
1946 0 : of.writeInt(i);
1947 0 : of.writeAsciiString(",\n");
1948 : }
1949 0 : of.writeAsciiString("};\n\n");
1950 0 : of.writeFunction("getAllCurrencies_", "currencyCount", "currencies");
1951 : }
1952 :
1953 0 : void LCTransliterationNode::generateCode (const OFileWriter &of) const
1954 : {
1955 0 : ::rtl::OUString useLocale = getAttr().getValueByName("ref");
1956 0 : if (!useLocale.isEmpty()) {
1957 0 : of.writeRefFunction("getTransliterations_", useLocale);
1958 0 : return;
1959 : }
1960 0 : sal_Int16 nbOfModules = 0;
1961 0 : ::rtl::OUString str;
1962 : sal_Int16 i;
1963 :
1964 0 : for ( i = 0; i < getNumberOfChildren(); i++,nbOfModules++) {
1965 0 : LocaleNode * transNode = getChildAt (i);
1966 0 : str = transNode->getAttr().getValueByIndex(0);
1967 0 : of.writeParameter("Transliteration", str, nbOfModules);
1968 : }
1969 0 : of.writeAsciiString("static const sal_Int16 nbOfTransliterations = ");
1970 0 : of.writeInt(nbOfModules);
1971 0 : of.writeAsciiString(";\n\n");
1972 :
1973 0 : of.writeAsciiString("\nstatic const sal_Unicode* LCTransliterationsArray[] = {\n");
1974 0 : for( i = 0; i < nbOfModules; i++) {
1975 0 : of.writeAsciiString("\tTransliteration");
1976 0 : of.writeInt(i);
1977 0 : of.writeAsciiString(",\n");
1978 : }
1979 0 : of.writeAsciiString("};\n\n");
1980 0 : 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 0 : void LCMiscNode::generateCode (const OFileWriter &of) const
2003 : {
2004 0 : ::rtl::OUString useLocale = getAttr().getValueByName("ref");
2005 0 : if (!useLocale.isEmpty()) {
2006 0 : of.writeRefFunction("getForbiddenCharacters_", useLocale);
2007 0 : of.writeRefFunction("getBreakIteratorRules_", useLocale);
2008 0 : of.writeRefFunction("getReservedWords_", useLocale);
2009 0 : return;
2010 : }
2011 0 : const LocaleNode * reserveNode = findNode("ReservedWords");
2012 0 : if (!reserveNode)
2013 0 : incError( "No ReservedWords element."); // should not happen if validated..
2014 0 : const LocaleNode * forbidNode = findNode("ForbiddenCharacters");
2015 0 : const LocaleNode * breakNode = findNode("BreakIteratorRules");
2016 :
2017 0 : bool bEnglishLocale = (strncmp( of.getLocale(), "en_", 3) == 0);
2018 :
2019 0 : sal_Int16 nbOfWords = 0;
2020 0 : ::rtl::OUString str;
2021 : sal_Int16 i;
2022 :
2023 0 : for ( i = 0; i < sal_Int16(SAL_N_ELEMENTS(ReserveWord)); i++,nbOfWords++) {
2024 : const LocaleNode * curNode = (reserveNode ? reserveNode->findNode(
2025 0 : ReserveWord[i].name) : 0);
2026 0 : 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 0 : str = curNode ? curNode -> getValue() : OUString::createFromAscii(ReserveWord[i].value);
2031 0 : if (str.isEmpty())
2032 : {
2033 0 : ++nError;
2034 0 : fprintf( stderr, "Error: No content for ReservedWords %s.\n", ReserveWord[i].name);
2035 : }
2036 0 : of.writeParameter("ReservedWord", str, nbOfWords);
2037 : // "true", ..., "below" trigger untranslated warning.
2038 0 : if (!bEnglishLocale && curNode && (0 <= i && i <= 7) &&
2039 0 : str.equalsIgnoreAsciiCaseAscii( ReserveWord[i].value))
2040 : {
2041 : fprintf( stderr,
2042 : "Warning: ReservedWord %s seems to be untranslated \"%s\".\n",
2043 0 : ReserveWord[i].name, ReserveWord[i].value);
2044 : }
2045 : }
2046 0 : of.writeAsciiString("static const sal_Int16 nbOfReservedWords = ");
2047 0 : of.writeInt(nbOfWords);
2048 0 : of.writeAsciiString(";\n\n");
2049 0 : of.writeAsciiString("\nstatic const sal_Unicode* LCReservedWordsArray[] = {\n");
2050 0 : for( i = 0; i < nbOfWords; i++) {
2051 0 : of.writeAsciiString("\tReservedWord");
2052 0 : of.writeInt(i);
2053 0 : of.writeAsciiString(",\n");
2054 : }
2055 0 : of.writeAsciiString("};\n\n");
2056 0 : of.writeFunction("getReservedWords_", "nbOfReservedWords", "LCReservedWordsArray");
2057 :
2058 0 : if (forbidNode) {
2059 0 : of.writeParameter( "forbiddenBegin", forbidNode -> getChildAt(0)->getValue());
2060 0 : of.writeParameter( "forbiddenEnd", forbidNode -> getChildAt(1)->getValue());
2061 0 : of.writeParameter( "hangingChars", forbidNode -> getChildAt(2)->getValue());
2062 : } else {
2063 0 : of.writeParameter( "forbiddenBegin", ::rtl::OUString());
2064 0 : of.writeParameter( "forbiddenEnd", ::rtl::OUString());
2065 0 : of.writeParameter( "hangingChars", ::rtl::OUString());
2066 : }
2067 0 : of.writeAsciiString("\nstatic const sal_Unicode* LCForbiddenCharactersArray[] = {\n");
2068 0 : of.writeAsciiString("\tforbiddenBegin,\n");
2069 0 : of.writeAsciiString("\tforbiddenEnd,\n");
2070 0 : of.writeAsciiString("\thangingChars\n");
2071 0 : of.writeAsciiString("};\n\n");
2072 0 : of.writeFunction("getForbiddenCharacters_", "3", "LCForbiddenCharactersArray");
2073 :
2074 0 : if (breakNode) {
2075 0 : of.writeParameter( "EditMode", breakNode -> getChildAt(0)->getValue());
2076 0 : of.writeParameter( "DictionaryMode", breakNode -> getChildAt(1)->getValue());
2077 0 : of.writeParameter( "WordCountMode", breakNode -> getChildAt(2)->getValue());
2078 0 : of.writeParameter( "CharacterMode", breakNode -> getChildAt(3)->getValue());
2079 0 : of.writeParameter( "LineMode", breakNode -> getChildAt(4)->getValue());
2080 : } else {
2081 0 : of.writeParameter( "EditMode", ::rtl::OUString());
2082 0 : of.writeParameter( "DictionaryMode", ::rtl::OUString());
2083 0 : of.writeParameter( "WordCountMode", ::rtl::OUString());
2084 0 : of.writeParameter( "CharacterMode", ::rtl::OUString());
2085 0 : of.writeParameter( "LineMode", ::rtl::OUString());
2086 : }
2087 0 : of.writeAsciiString("\nstatic const sal_Unicode* LCBreakIteratorRulesArray[] = {\n");
2088 0 : of.writeAsciiString("\tEditMode,\n");
2089 0 : of.writeAsciiString("\tDictionaryMode,\n");
2090 0 : of.writeAsciiString("\tWordCountMode,\n");
2091 0 : of.writeAsciiString("\tCharacterMode,\n");
2092 0 : of.writeAsciiString("\tLineMode\n");
2093 0 : of.writeAsciiString("};\n\n");
2094 0 : of.writeFunction("getBreakIteratorRules_", "5", "LCBreakIteratorRulesArray");
2095 :
2096 : }
2097 :
2098 0 : void LCNumberingLevelNode::generateCode (const OFileWriter &of) const
2099 : {
2100 0 : of.writeAsciiString("// ---> ContinuousNumbering\n");
2101 0 : ::rtl::OUString useLocale = getAttr().getValueByName("ref");
2102 0 : if (!useLocale.isEmpty()) {
2103 0 : of.writeRefFunction2("getContinuousNumberingLevels_", useLocale);
2104 0 : return;
2105 : }
2106 :
2107 : // hard code number of attributes per style.
2108 0 : const int nAttributes = 5;
2109 0 : 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 0 : sal_Int32 nStyles = getNumberOfChildren();
2114 : sal_Int32 i;
2115 :
2116 0 : for( i = 0; i < nStyles; ++i )
2117 : {
2118 0 : const Attr &q = getChildAt( i )->getAttr();
2119 0 : for( sal_Int32 j=0; j<nAttributes; ++j )
2120 : {
2121 0 : const char* name = attr[j];
2122 0 : OUString value = q.getValueByName( name );
2123 0 : of.writeParameter("continuous", name, value, sal::static_int_cast<sal_Int16>(i) );
2124 0 : }
2125 : }
2126 :
2127 : // record number of styles and attributes.
2128 0 : of.writeAsciiString("static const sal_Int16 continuousNbOfStyles = ");
2129 0 : of.writeInt( sal::static_int_cast<sal_Int16>( nStyles ) );
2130 0 : of.writeAsciiString(";\n\n");
2131 0 : of.writeAsciiString("static const sal_Int16 continuousNbOfAttributesPerStyle = ");
2132 0 : of.writeInt( nAttributes );
2133 0 : of.writeAsciiString(";\n\n");
2134 :
2135 : // generate code. (intermediate arrays)
2136 0 : for( i=0; i<nStyles; i++ )
2137 : {
2138 0 : of.writeAsciiString("\nstatic const sal_Unicode* continuousStyle" );
2139 0 : of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2140 0 : of.writeAsciiString("[] = {\n");
2141 0 : for( sal_Int32 j=0; j<nAttributes; j++)
2142 : {
2143 0 : of.writeAsciiString("\t");
2144 0 : of.writeAsciiString( "continuous" );
2145 0 : of.writeAsciiString( attr[j] );
2146 0 : of.writeInt(sal::static_int_cast<sal_Int16>(i));
2147 0 : of.writeAsciiString(",\n");
2148 : }
2149 0 : of.writeAsciiString("\t0\n};\n\n");
2150 : }
2151 :
2152 : // generate code. (top-level array)
2153 0 : of.writeAsciiString("\n");
2154 0 : of.writeAsciiString("static const sal_Unicode** LCContinuousNumberingLevelsArray[] = {\n" );
2155 0 : for( i=0; i<nStyles; i++ )
2156 : {
2157 0 : of.writeAsciiString( "\t" );
2158 0 : of.writeAsciiString( "continuousStyle" );
2159 0 : of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2160 0 : of.writeAsciiString( ",\n");
2161 : }
2162 0 : of.writeAsciiString("\t0\n};\n\n");
2163 : of.writeFunction2("getContinuousNumberingLevels_", "continuousNbOfStyles",
2164 0 : "continuousNbOfAttributesPerStyle", "LCContinuousNumberingLevelsArray");
2165 : }
2166 :
2167 :
2168 0 : void LCOutlineNumberingLevelNode::generateCode (const OFileWriter &of) const
2169 : {
2170 0 : of.writeAsciiString("// ---> OutlineNumbering\n");
2171 0 : ::rtl::OUString useLocale = getAttr().getValueByName("ref");
2172 0 : if (!useLocale.isEmpty()) {
2173 0 : of.writeRefFunction3("getOutlineNumberingLevels_", useLocale);
2174 0 : return;
2175 : }
2176 :
2177 : // hardcode number of attributes per level
2178 0 : 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 0 : };
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 0 : sal_Int32 nStyles = getNumberOfChildren();
2197 0 : vector<sal_Int32> nLevels; // may be different for each style?
2198 0 : for( sal_Int32 i = 0; i < nStyles; i++ )
2199 : {
2200 0 : LocaleNode* p = getChildAt( i );
2201 0 : nLevels.push_back( p->getNumberOfChildren() );
2202 0 : for( sal_Int32 j=0; j<nLevels.back(); j++ )
2203 : {
2204 0 : const Attr& q = p->getChildAt( j )->getAttr();
2205 0 : for( sal_Int32 k=0; k<nAttributes; ++k )
2206 : {
2207 0 : const char* name = attr[k];
2208 0 : OUString value = q.getValueByName( name );
2209 : of.writeParameter("outline", name, value,
2210 0 : sal::static_int_cast<sal_Int16>(i),
2211 0 : sal::static_int_cast<sal_Int16>(j) );
2212 0 : }
2213 : }
2214 : }
2215 :
2216 : // verify that each style has the same number of levels.
2217 0 : for( size_t i=0; i<nLevels.size(); i++ )
2218 : {
2219 0 : 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 0 : of.writeAsciiString("static const sal_Int16 outlineNbOfStyles = ");
2227 0 : of.writeInt( sal::static_int_cast<sal_Int16>( nStyles ) );
2228 0 : of.writeAsciiString(";\n\n");
2229 0 : of.writeAsciiString("static const sal_Int16 outlineNbOfLevelsPerStyle = ");
2230 0 : of.writeInt( sal::static_int_cast<sal_Int16>( nLevels.back() ) );
2231 0 : of.writeAsciiString(";\n\n");
2232 0 : of.writeAsciiString("static const sal_Int16 outlineNbOfAttributesPerLevel = ");
2233 0 : of.writeInt( nAttributes );
2234 0 : 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 0 : for( sal_Int32 i=0; i<nStyles; i++ )
2247 : {
2248 0 : for( sal_Int32 j=0; j<nLevels.back(); j++ )
2249 : {
2250 0 : of.writeAsciiString("static const sal_Unicode* outline");
2251 0 : of.writeAsciiString("Style");
2252 0 : of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2253 0 : of.writeAsciiString("Level");
2254 0 : of.writeInt( sal::static_int_cast<sal_Int16>(j) );
2255 0 : of.writeAsciiString("[] = { ");
2256 :
2257 0 : for( sal_Int32 k=0; k<nAttributes; k++ )
2258 : {
2259 0 : of.writeAsciiString( "outline" );
2260 0 : of.writeAsciiString( attr[k] );
2261 0 : of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2262 0 : of.writeInt( sal::static_int_cast<sal_Int16>(j) );
2263 0 : of.writeAsciiString(", ");
2264 : }
2265 0 : of.writeAsciiString("NULL };\n");
2266 : }
2267 : }
2268 :
2269 0 : of.writeAsciiString("\n");
2270 :
2271 :
2272 0 : for( sal_Int32 i=0; i<nStyles; i++ )
2273 : {
2274 0 : of.writeAsciiString("static const sal_Unicode** outline");
2275 0 : of.writeAsciiString( "Style" );
2276 0 : of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2277 0 : of.writeAsciiString("[] = { ");
2278 :
2279 0 : for( sal_Int32 j=0; j<nLevels.back(); j++ )
2280 : {
2281 0 : of.writeAsciiString("outlineStyle");
2282 0 : of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2283 0 : of.writeAsciiString("Level");
2284 0 : of.writeInt( sal::static_int_cast<sal_Int16>(j) );
2285 0 : of.writeAsciiString(", ");
2286 : }
2287 0 : of.writeAsciiString("NULL };\n");
2288 : }
2289 0 : of.writeAsciiString("\n");
2290 :
2291 0 : of.writeAsciiString("static const sal_Unicode*** LCOutlineNumberingLevelsArray[] = {\n" );
2292 0 : for( sal_Int32 i=0; i<nStyles; i++ )
2293 : {
2294 0 : of.writeAsciiString( "\t" );
2295 0 : of.writeAsciiString( "outlineStyle" );
2296 0 : of.writeInt( sal::static_int_cast<sal_Int16>(i) );
2297 0 : of.writeAsciiString(",\n");
2298 : }
2299 0 : of.writeAsciiString("\tNULL\n};\n\n");
2300 : of.writeFunction3("getOutlineNumberingLevels_", "outlineNbOfStyles", "outlineNbOfLevelsPerStyle",
2301 0 : "outlineNbOfAttributesPerLevel", "LCOutlineNumberingLevelsArray");
2302 : }
2303 :
2304 0 : Attr::Attr (const Reference< XAttributeList > & attr) {
2305 0 : sal_Int16 len = attr->getLength();
2306 0 : name.realloc (len);
2307 0 : value.realloc (len);
2308 0 : for (sal_Int16 i =0; i< len;i++) {
2309 0 : name[i] = attr->getNameByIndex(i);
2310 0 : value[i] = attr -> getValueByIndex(i);
2311 : }
2312 0 : }
2313 :
2314 0 : const OUString& Attr::getValueByName (const sal_Char *str) const {
2315 0 : static OUString empty;
2316 0 : sal_Int32 len = name.getLength();
2317 0 : for (sal_Int32 i = 0;i<len;i++)
2318 0 : if (name[i].equalsAscii(str))
2319 0 : return value[i];
2320 0 : 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 0 : const OUString& Attr::getValueByIndex (sal_Int32 idx) const
2332 : {
2333 0 : return value[idx];
2334 0 : }
2335 :
2336 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|