]> git.saurik.com Git - apple/icu.git/blame - icuSources/tools/genpname/genpname.cpp
ICU-6.2.10.tar.gz
[apple/icu.git] / icuSources / tools / genpname / genpname.cpp
CommitLineData
b75a7d8f
A
1/*
2**********************************************************************
374ca955 3* Copyright (C) 2002-2004, International Business Machines
b75a7d8f
A
4* Corporation and others. All Rights Reserved.
5**********************************************************************
6* Date Name Description
7* 10/11/02 aliu Creation.
8**********************************************************************
9*/
10
b75a7d8f
A
11#include "unicode/utypes.h"
12#include "unicode/putil.h"
374ca955 13#include "unicode/uclean.h"
b75a7d8f
A
14#include "cmemory.h"
15#include "cstring.h"
16#include "filestrm.h"
374ca955 17#include "uarrsort.h"
b75a7d8f
A
18#include "unewdata.h"
19#include "uoptions.h"
20#include "uprops.h"
21#include "propname.h"
22#include "uassert.h"
23
374ca955
A
24#include <stdio.h>
25
b75a7d8f
A
26// TODO: Clean up and comment this code.
27
28//----------------------------------------------------------------------
29// BEGIN DATA
30//
31// This is the raw data to be output. We define the data structure,
32// then include a machine-generated header that contains the actual
33// data.
34
35#include "unicode/uchar.h"
36#include "unicode/uscript.h"
374ca955 37#include "unicode/unorm.h"
b75a7d8f
A
38
39class AliasName {
40public:
41 const char* str;
42 int32_t index;
43
44 AliasName(const char* str, int32_t index);
45
46 int compare(const AliasName& other) const;
47
48 UBool operator==(const AliasName& other) const {
49 return compare(other) == 0;
50 }
51
52 UBool operator!=(const AliasName& other) const {
53 return compare(other) != 0;
54 }
55};
56
57AliasName::AliasName(const char* _str,
58 int32_t _index) :
59 str(_str),
60 index(_index)
61{
62}
63
64int AliasName::compare(const AliasName& other) const {
65 return uprv_comparePropertyNames(str, other.str);
66}
67
68class Alias {
69public:
70 int32_t enumValue;
71 int32_t nameGroupIndex;
72
73 Alias(int32_t enumValue,
74 int32_t nameGroupIndex);
75
76 int32_t getUniqueNames(int32_t* nameGroupIndices) const;
77};
78
79Alias::Alias(int32_t anEnumValue,
80 int32_t aNameGroupIndex) :
81 enumValue(anEnumValue),
82 nameGroupIndex(aNameGroupIndex)
83{
84}
85
86class Property : public Alias {
87public:
88 int32_t valueCount;
89 const Alias* valueList;
90
91 Property(int32_t enumValue,
92 int32_t nameGroupIndex,
93 int32_t valueCount,
94 const Alias* valueList);
95};
96
97Property::Property(int32_t _enumValue,
98 int32_t _nameGroupIndex,
99 int32_t _valueCount,
100 const Alias* _valueList) :
101 Alias(_enumValue, _nameGroupIndex),
102 valueCount(_valueCount),
103 valueList(_valueList)
104{
105}
106
107// *** Include the data header ***
108#include "data.h"
109
110/* return a list of unique names, not including "", for this property
111 * @param stringIndices array of at least MAX_NAMES_PER_GROUP
112 * elements, will be filled with indices into STRING_TABLE
113 * @return number of indices, >= 1
114 */
115int32_t Alias::getUniqueNames(int32_t* stringIndices) const {
116 int32_t count = 0;
117 int32_t i = nameGroupIndex;
118 UBool done = FALSE;
119 while (!done) {
120 int32_t j = NAME_GROUP[i++];
121 if (j < 0) {
122 done = TRUE;
123 j = -j;
124 }
125 if (j == 0) continue; // omit "" entries
126 UBool dupe = FALSE;
127 for (int32_t k=0; k<count; ++k) {
128 if (stringIndices[k] == j) {
129 dupe = TRUE;
130 break;
131 }
132 // also do a string check for things like "age|Age"
133 if (STRING_TABLE[stringIndices[k]] == STRING_TABLE[j]) {
134 //printf("Found dupe %s|%s\n",
135 // STRING_TABLE[stringIndices[k]].str,
136 // STRING_TABLE[j].str);
137 dupe = TRUE;
138 break;
139 }
140 }
141 if (dupe) continue; // omit duplicates
142 stringIndices[count++] = j;
143 }
144 return count;
145}
146
147// END DATA
148//----------------------------------------------------------------------
149
150#define MALLOC(type, count) \
151 (type*) uprv_malloc(sizeof(type) * count)
152
153void die(const char* msg) {
154 fprintf(stderr, "Error: %s\n", msg);
155 exit(1);
156}
157
158//----------------------------------------------------------------------
159
160/**
161 * A list of Alias objects.
162 */
163class AliasList {
164public:
165 virtual const Alias& operator[](int32_t i) const = 0;
166 virtual int32_t count() const = 0;
167};
168
169/**
170 * A single array.
171 */
172class AliasArrayList : public AliasList {
173 const Alias* a;
174 int32_t n;
175public:
176 AliasArrayList(const Alias* _a, int32_t _n) {
177 a = _a;
178 n = _n;
179 }
180 virtual const Alias& operator[](int32_t i) const {
181 return a[i];
182 }
183 virtual int32_t count() const {
184 return n;
185 }
186};
187
188/**
189 * A single array.
190 */
191class PropertyArrayList : public AliasList {
192 const Property* a;
193 int32_t n;
194public:
195 PropertyArrayList(const Property* _a, int32_t _n) {
196 a = _a;
197 n = _n;
198 }
199 virtual const Alias& operator[](int32_t i) const {
200 return a[i];
201 }
202 virtual int32_t count() const {
203 return n;
204 }
205};
206
207//----------------------------------------------------------------------
208
209/**
210 * An element in a name index. It maps a name (given by index) into
211 * an enum value.
212 */
213class NameToEnumEntry {
214public:
215 int32_t nameIndex;
216 int32_t enumValue;
217 NameToEnumEntry(int32_t a, int32_t b) { nameIndex=a; enumValue=b; }
218};
219
374ca955
A
220// Sort function for NameToEnumEntry (sort by name)
221U_CFUNC int32_t
222compareNameToEnumEntry(const void * /*context*/, const void* e1, const void* e2) {
223 return
224 STRING_TABLE[((NameToEnumEntry*)e1)->nameIndex].
225 compare(STRING_TABLE[((NameToEnumEntry*)e2)->nameIndex]);
b75a7d8f
A
226}
227
228//----------------------------------------------------------------------
229
230/**
231 * An element in an enum index. It maps an enum into a name group entry
232 * (given by index).
233 */
234class EnumToNameGroupEntry {
235public:
236 int32_t enumValue;
237 int32_t nameGroupIndex;
238 EnumToNameGroupEntry(int32_t a, int32_t b) { enumValue=a; nameGroupIndex=b; }
239
240 // are enumValues contiguous for count entries starting with this one?
241 // ***!!!*** we assume we are in an array and look at neighbors ***!!!***
242 UBool isContiguous(int32_t count) const {
243 const EnumToNameGroupEntry* p = this;
244 for (int32_t i=1; i<count; ++i) {
245 if (p[i].enumValue != (this->enumValue + i)) {
246 return FALSE;
247 }
248 }
249 return TRUE;
250 }
251};
252
253// Sort function for EnumToNameGroupEntry (sort by name index)
374ca955
A
254U_CFUNC int32_t
255compareEnumToNameGroupEntry(const void * /*context*/, const void* e1, const void* e2) {
b75a7d8f
A
256 return ((EnumToNameGroupEntry*)e1)->enumValue - ((EnumToNameGroupEntry*)e2)->enumValue;
257}
258
259//----------------------------------------------------------------------
260
261/**
262 * An element in the map from enumerated property enums to value maps.
263 */
264class EnumToValueEntry {
265public:
266 int32_t enumValue;
267 EnumToNameGroupEntry* enumToName;
268 int32_t enumToName_count;
269 NameToEnumEntry* nameToEnum;
270 int32_t nameToEnum_count;
271
272 // are enumValues contiguous for count entries starting with this one?
273 // ***!!!*** we assume we are in an array and look at neighbors ***!!!***
274 UBool isContiguous(int32_t count) const {
275 const EnumToValueEntry* p = this;
276 for (int32_t i=1; i<count; ++i) {
277 if (p[i].enumValue != (this->enumValue + i)) {
278 return FALSE;
279 }
280 }
281 return TRUE;
282 }
283};
284
285// Sort function for EnumToValueEntry (sort by enum)
374ca955
A
286U_CFUNC int32_t
287compareEnumToValueEntry(const void * /*context*/, const void* e1, const void* e2) {
b75a7d8f
A
288 return ((EnumToValueEntry*)e1)->enumValue - ((EnumToValueEntry*)e2)->enumValue;
289}
290
291//----------------------------------------------------------------------
292// BEGIN Builder
293
294#define IS_VALID_OFFSET(x) (((x)>=0)&&((x)<=MAX_OFFSET))
295
296class Builder {
297 // header:
298 PropertyAliases header;
299
300 // 0:
301 NonContiguousEnumToOffset* enumToName;
302 int32_t enumToName_size;
303 Offset enumToName_offset;
304
305 // 1: (deleted)
306
307 // 2:
308 NameToEnum* nameToEnum;
309 int32_t nameToEnum_size;
310 Offset nameToEnum_offset;
311
312 // 3:
313 NonContiguousEnumToOffset* enumToValue;
314 int32_t enumToValue_size;
315 Offset enumToValue_offset;
316
317 // 4:
318 ValueMap* valueMap;
319 int32_t valueMap_size;
320 int32_t valueMap_count;
321 Offset valueMap_offset;
322
323 // for any i, one of valueEnumToName[i] or valueNCEnumToName[i] is
324 // NULL and one is not. valueEnumToName_size[i] is the size of
325 // the non-NULL one. i=0..valueMapCount-1
326 // 5a:
327 EnumToOffset** valueEnumToName;
328 // 5b:
329 NonContiguousEnumToOffset** valueNCEnumToName;
330 int32_t* valueEnumToName_size;
331 Offset* valueEnumToName_offset;
332 // 6:
333 // arrays of valueMap_count pointers, sizes, & offsets
334 NameToEnum** valueNameToEnum;
335 int32_t* valueNameToEnum_size;
336 Offset* valueNameToEnum_offset;
337
338 // 98:
339 Offset* nameGroupPool;
340 int32_t nameGroupPool_count;
341 int32_t nameGroupPool_size;
342 Offset nameGroupPool_offset;
343
344 // 99:
345 char* stringPool;
346 int32_t stringPool_count;
347 int32_t stringPool_size;
348 Offset stringPool_offset;
349 Offset* stringPool_offsetArray; // relative to stringPool
350
351 int32_t total_size; // size of everything
352
353 int32_t debug;
354
355public:
356
357 Builder(int32_t debugLevel);
358 ~Builder();
359
360 void buildTopLevelProperties(const NameToEnumEntry* propName,
361 int32_t propNameCount,
362 const EnumToNameGroupEntry* propEnum,
363 int32_t propEnumCount);
364
365 void buildValues(const EnumToValueEntry* e2v,
366 int32_t count);
367
368 void buildStringPool(const AliasName* propertyNames,
369 int32_t propertyNameCount,
370 const int32_t* nameGroupIndices,
371 int32_t nameGroupIndicesCount);
372
373 void fixup();
374
375 int8_t* createData(int32_t& length) const;
376
377private:
378
379 static EnumToOffset* buildEnumToOffset(const EnumToNameGroupEntry* e2ng,
380 int32_t count,
381 int32_t& size);
382 static NonContiguousEnumToOffset*
383 buildNCEnumToNameGroup(const EnumToNameGroupEntry* e2ng,
384 int32_t count,
385 int32_t& size);
386
387 static NonContiguousEnumToOffset*
388 buildNCEnumToValue(const EnumToValueEntry* e2v,
389 int32_t count,
390 int32_t& size);
391
392 static NameToEnum* buildNameToEnum(const NameToEnumEntry* nameToEnum,
393 int32_t count,
394 int32_t& size);
395
396 Offset stringIndexToOffset(int32_t index, UBool allowNeg=FALSE) const;
397 void fixupNameToEnum(NameToEnum* n);
398 void fixupEnumToNameGroup(EnumToOffset* e2ng);
399 void fixupNCEnumToNameGroup(NonContiguousEnumToOffset* e2ng);
400
401 void computeOffsets();
402 void fixupStringPoolOffsets();
403 void fixupNameGroupPoolOffsets();
404 void fixupMiscellaneousOffsets();
405
406 static int32_t align(int32_t a);
407 static void erase(void* p, int32_t size);
408};
409
410Builder::Builder(int32_t debugLevel) {
411 debug = debugLevel;
412 enumToName = 0;
413 nameToEnum = 0;
414 enumToValue = 0;
415 valueMap_count = 0;
416 valueMap = 0;
417 valueEnumToName = 0;
418 valueNCEnumToName = 0;
419 valueEnumToName_size = 0;
420 valueEnumToName_offset = 0;
421 valueNameToEnum = 0;
422 valueNameToEnum_size = 0;
423 valueNameToEnum_offset = 0;
424 nameGroupPool = 0;
425 stringPool = 0;
426 stringPool_offsetArray = 0;
427}
428
429Builder::~Builder() {
430 uprv_free(enumToName);
431 uprv_free(nameToEnum);
432 uprv_free(enumToValue);
433 uprv_free(valueMap);
434 for (int32_t i=0; i<valueMap_count; ++i) {
435 uprv_free(valueEnumToName[i]);
436 uprv_free(valueNCEnumToName[i]);
437 uprv_free(valueNameToEnum[i]);
438 }
439 uprv_free(valueEnumToName);
440 uprv_free(valueNCEnumToName);
441 uprv_free(valueEnumToName_size);
442 uprv_free(valueEnumToName_offset);
443 uprv_free(valueNameToEnum);
444 uprv_free(valueNameToEnum_size);
445 uprv_free(valueNameToEnum_offset);
446 uprv_free(nameGroupPool);
447 uprv_free(stringPool);
448 uprv_free(stringPool_offsetArray);
449}
450
451int32_t Builder::align(int32_t a) {
452 U_ASSERT(a >= 0);
453 int32_t k = a % sizeof(int32_t);
454 if (k == 0) {
455 return a;
456 }
457 a += sizeof(int32_t) - k;
458 return a;
459}
460
461void Builder::erase(void* p, int32_t size) {
462 U_ASSERT(size >= 0);
463 int8_t* q = (int8_t*) p;
464 while (size--) {
465 *q++ = 0;
466 }
467}
468
469EnumToOffset* Builder::buildEnumToOffset(const EnumToNameGroupEntry* e2ng,
470 int32_t count,
471 int32_t& size) {
472 U_ASSERT(e2ng->isContiguous(count));
473 size = align(EnumToOffset::getSize(count));
474 EnumToOffset* result = (EnumToOffset*) uprv_malloc(size);
475 erase(result, size);
476 result->enumStart = e2ng->enumValue;
477 result->enumLimit = e2ng->enumValue + count;
478 Offset* p = result->getOffsetArray();
479 for (int32_t i=0; i<count; ++i) {
480 // set these to NGI index values
481 // fix them up to NGI offset values
482 U_ASSERT(IS_VALID_OFFSET(e2ng[i].nameGroupIndex));
483 p[i] = (Offset) e2ng[i].nameGroupIndex; // FIXUP later
484 }
485 return result;
486}
487
488NonContiguousEnumToOffset*
489Builder::buildNCEnumToNameGroup(const EnumToNameGroupEntry* e2ng,
490 int32_t count,
491 int32_t& size) {
492 U_ASSERT(!e2ng->isContiguous(count));
493 size = align(NonContiguousEnumToOffset::getSize(count));
494 NonContiguousEnumToOffset* nc = (NonContiguousEnumToOffset*) uprv_malloc(size);
495 erase(nc, size);
496 nc->count = count;
497 EnumValue* e = nc->getEnumArray();
498 Offset* p = nc->getOffsetArray();
499 for (int32_t i=0; i<count; ++i) {
500 // set these to NGI index values
501 // fix them up to NGI offset values
502 e[i] = e2ng[i].enumValue;
503 U_ASSERT(IS_VALID_OFFSET(e2ng[i].nameGroupIndex));
504 p[i] = (Offset) e2ng[i].nameGroupIndex; // FIXUP later
505 }
506 return nc;
507}
508
509NonContiguousEnumToOffset*
510Builder::buildNCEnumToValue(const EnumToValueEntry* e2v,
511 int32_t count,
512 int32_t& size) {
513 U_ASSERT(!e2v->isContiguous(count));
514 size = align(NonContiguousEnumToOffset::getSize(count));
515 NonContiguousEnumToOffset* result = (NonContiguousEnumToOffset*) uprv_malloc(size);
516 erase(result, size);
517 result->count = count;
518 EnumValue* e = result->getEnumArray();
519 for (int32_t i=0; i<count; ++i) {
520 e[i] = e2v[i].enumValue;
521 // offset must be set later
522 }
523 return result;
524}
525
526/**
527 * Given an index into the string pool, return an offset. computeOffsets()
528 * must have been called already. If allowNegative is true, allow negatives
529 * and preserve their sign.
530 */
531Offset Builder::stringIndexToOffset(int32_t index, UBool allowNegative) const {
532 // Index 0 is ""; we turn this into an Offset of zero
533 if (index == 0) return 0;
534 if (index < 0) {
535 if (allowNegative) {
536 return -Builder::stringIndexToOffset(-index);
537 } else {
538 die("Negative string pool index");
539 }
540 } else {
541 if (index >= stringPool_count) {
542 die("String pool index too large");
543 }
544 Offset result = stringPool_offset + stringPool_offsetArray[index];
545 U_ASSERT(result >= 0 && result < total_size);
546 return result;
547 }
548 return 0; // never executed; make compiler happy
549}
550
551NameToEnum* Builder::buildNameToEnum(const NameToEnumEntry* nameToEnum,
552 int32_t count,
553 int32_t& size) {
554 size = align(NameToEnum::getSize(count));
555 NameToEnum* n2e = (NameToEnum*) uprv_malloc(size);
556 erase(n2e, size);
557 n2e->count = count;
558 Offset* p = n2e->getNameArray();
559 EnumValue* e = n2e->getEnumArray();
560 for (int32_t i=0; i<count; ++i) {
561 // set these to SP index values
562 // fix them up to SP offset values
563 U_ASSERT(IS_VALID_OFFSET(nameToEnum[i].nameIndex));
564 p[i] = (Offset) nameToEnum[i].nameIndex; // FIXUP later
565 e[i] = nameToEnum[i].enumValue;
566 }
567 return n2e;
568}
569
570
571void Builder::buildTopLevelProperties(const NameToEnumEntry* propName,
572 int32_t propNameCount,
573 const EnumToNameGroupEntry* propEnum,
574 int32_t propEnumCount) {
575 enumToName = buildNCEnumToNameGroup(propEnum,
576 propEnumCount,
577 enumToName_size);
578 nameToEnum = buildNameToEnum(propName,
579 propNameCount,
580 nameToEnum_size);
581}
582
583void Builder::buildValues(const EnumToValueEntry* e2v,
584 int32_t count) {
585 int32_t i;
586
587 U_ASSERT(!e2v->isContiguous(count));
588
589 valueMap_count = count;
590
591 enumToValue = buildNCEnumToValue(e2v, count,
592 enumToValue_size);
593
594 valueMap_size = align(count * sizeof(ValueMap));
595 valueMap = (ValueMap*) uprv_malloc(valueMap_size);
596 erase(valueMap, valueMap_size);
597
598 valueEnumToName = MALLOC(EnumToOffset*, count);
599 valueNCEnumToName = MALLOC(NonContiguousEnumToOffset*, count);
600 valueEnumToName_size = MALLOC(int32_t, count);
601 valueEnumToName_offset = MALLOC(Offset, count);
602 valueNameToEnum = MALLOC(NameToEnum*, count);
603 valueNameToEnum_size = MALLOC(int32_t, count);
604 valueNameToEnum_offset = MALLOC(Offset, count);
605
606 for (i=0; i<count; ++i) {
607 UBool isContiguous =
608 e2v[i].enumToName->isContiguous(e2v[i].enumToName_count);
609 valueEnumToName[i] = 0;
610 valueNCEnumToName[i] = 0;
611 if (isContiguous) {
612 valueEnumToName[i] = buildEnumToOffset(e2v[i].enumToName,
613 e2v[i].enumToName_count,
614 valueEnumToName_size[i]);
615 } else {
616 valueNCEnumToName[i] = buildNCEnumToNameGroup(e2v[i].enumToName,
617 e2v[i].enumToName_count,
618 valueEnumToName_size[i]);
619 }
620 valueNameToEnum[i] =
621 buildNameToEnum(e2v[i].nameToEnum,
622 e2v[i].nameToEnum_count,
623 valueNameToEnum_size[i]);
624 }
625}
626
627void Builder::buildStringPool(const AliasName* propertyNames,
628 int32_t propertyNameCount,
629 const int32_t* nameGroupIndices,
630 int32_t nameGroupIndicesCount) {
631 int32_t i;
632
633 nameGroupPool_count = nameGroupIndicesCount;
634 nameGroupPool_size = sizeof(Offset) * nameGroupPool_count;
635 nameGroupPool = MALLOC(Offset, nameGroupPool_count);
636
637 for (i=0; i<nameGroupPool_count; ++i) {
638 // Some indices are negative.
639 int32_t a = nameGroupIndices[i];
640 if (a < 0) a = -a;
641 U_ASSERT(IS_VALID_OFFSET(a));
642 nameGroupPool[i] = (Offset) nameGroupIndices[i];
643 }
644
645 stringPool_count = propertyNameCount;
646 stringPool_size = 0;
647 // first string must be "" -- we skip it
648 U_ASSERT(*propertyNames[0].str == 0);
649 for (i=1 /*sic*/; i<propertyNameCount; ++i) {
374ca955 650 stringPool_size += (int32_t)(uprv_strlen(propertyNames[i].str) + 1);
b75a7d8f
A
651 }
652 stringPool = MALLOC(char, stringPool_size);
653 stringPool_offsetArray = MALLOC(Offset, stringPool_count);
654 Offset soFar = 0;
655 char* p = stringPool;
656 stringPool_offsetArray[0] = -1; // we don't use this entry
657 for (i=1 /*sic*/; i<propertyNameCount; ++i) {
658 const char* str = propertyNames[i].str;
374ca955 659 int32_t len = (int32_t)uprv_strlen(str);
b75a7d8f
A
660 uprv_strcpy(p, str);
661 p += len;
662 *p++ = 0;
663 stringPool_offsetArray[i] = soFar;
664 soFar += (Offset)(len+1);
665 }
666 U_ASSERT(soFar == stringPool_size);
667 U_ASSERT(p == (stringPool + stringPool_size));
668}
669
670// Confirm that PropertyAliases is a POD (plain old data; see C++
671// std). The following union will _fail to compile_ if
672// PropertyAliases is _not_ a POD. (Note: We used to use the offsetof
673// macro to check this, but that's not quite right, so that test is
674// commented out -- see below.)
675typedef union {
676 int32_t i;
677 PropertyAliases p;
678} PropertyAliasesPODTest;
679
680void Builder::computeOffsets() {
681 int32_t i;
682 Offset off = sizeof(header);
683
684 if (debug>0) {
685 printf("header \t offset=%4d size=%5d\n", 0, off);
686 }
687
688 // PropertyAliases must have no v-table and must be
689 // padded (if necessary) to the next 32-bit boundary.
690 //U_ASSERT(offsetof(PropertyAliases, enumToName_offset) == 0); // see above
691 U_ASSERT(sizeof(header) % sizeof(int32_t) == 0);
692
693 #define COMPUTE_OFFSET(foo) COMPUTE_OFFSET2(foo,int32_t)
694
695 #define COMPUTE_OFFSET2(foo,type) \
374ca955
A
696 if (debug>0)\
697 printf(#foo "\t offset=%4d size=%5d\n", off, (int)foo##_size);\
698 foo##_offset = off;\
699 U_ASSERT(IS_VALID_OFFSET(off + foo##_size));\
700 U_ASSERT(foo##_offset % sizeof(type) == 0);\
b75a7d8f
A
701 off = (Offset) (off + foo##_size);
702
703 COMPUTE_OFFSET(enumToName); // 0:
374ca955
A
704 COMPUTE_OFFSET(nameToEnum); // 2:
705 COMPUTE_OFFSET(enumToValue); // 3:
706 COMPUTE_OFFSET(valueMap); // 4:
b75a7d8f
A
707
708 for (i=0; i<valueMap_count; ++i) {
709 if (debug>0) {
710 printf(" enumToName[%d]\t offset=%4d size=%5d\n",
374ca955 711 (int)i, off, (int)valueEnumToName_size[i]);
b75a7d8f
A
712 }
713
714 valueEnumToName_offset[i] = off; // 5:
715 U_ASSERT(IS_VALID_OFFSET(off + valueEnumToName_size[i]));
716 off = (Offset) (off + valueEnumToName_size[i]);
717
718 if (debug>0) {
719 printf(" nameToEnum[%d]\t offset=%4d size=%5d\n",
374ca955 720 (int)i, off, (int)valueNameToEnum_size[i]);
b75a7d8f
A
721 }
722
723 valueNameToEnum_offset[i] = off; // 6:
724 U_ASSERT(IS_VALID_OFFSET(off + valueNameToEnum_size[i]));
725 off = (Offset) (off + valueNameToEnum_size[i]);
726 }
727
728 // These last two chunks have weaker alignment needs
729 COMPUTE_OFFSET2(nameGroupPool,Offset); // 98:
730 COMPUTE_OFFSET2(stringPool,char); // 99:
731
732 total_size = off;
374ca955 733 if (debug>0) printf("total size=%5d\n\n", (int)total_size);
b75a7d8f
A
734 U_ASSERT(total_size <= (MAX_OFFSET+1));
735}
736
737void Builder::fixupNameToEnum(NameToEnum* n) {
738 // Fix the string pool offsets in n
739 Offset* p = n->getNameArray();
740 for (int32_t i=0; i<n->count; ++i) {
741 p[i] = stringIndexToOffset(p[i]);
742 }
743}
744
745void Builder::fixupStringPoolOffsets() {
746 int32_t i;
747
748 // 2:
749 fixupNameToEnum(nameToEnum);
750
751 // 6:
752 for (i=0; i<valueMap_count; ++i) {
753 fixupNameToEnum(valueNameToEnum[i]);
754 }
755
756 // 98:
757 for (i=0; i<nameGroupPool_count; ++i) {
758 nameGroupPool[i] = stringIndexToOffset(nameGroupPool[i], TRUE);
759 }
760}
761
762void Builder::fixupEnumToNameGroup(EnumToOffset* e2ng) {
763 EnumValue i;
764 int32_t j;
765 Offset* p = e2ng->getOffsetArray();
766 for (i=e2ng->enumStart, j=0; i<e2ng->enumLimit; ++i, ++j) {
767 p[j] = nameGroupPool_offset + sizeof(Offset) * p[j];
768 }
769}
770
771void Builder::fixupNCEnumToNameGroup(NonContiguousEnumToOffset* e2ng) {
772 int32_t i;
374ca955 773 /*EnumValue* e = e2ng->getEnumArray();*/
b75a7d8f
A
774 Offset* p = e2ng->getOffsetArray();
775 for (i=0; i<e2ng->count; ++i) {
776 p[i] = nameGroupPool_offset + sizeof(Offset) * p[i];
777 }
778}
779
780void Builder::fixupNameGroupPoolOffsets() {
781 int32_t i;
782
783 // 0:
784 fixupNCEnumToNameGroup(enumToName);
785
786 // 1: (deleted)
787
788 // 5:
789 for (i=0; i<valueMap_count; ++i) {
790 // 5a:
791 if (valueEnumToName[i] != 0) {
792 fixupEnumToNameGroup(valueEnumToName[i]);
793 }
794 // 5b:
795 if (valueNCEnumToName[i] != 0) {
796 fixupNCEnumToNameGroup(valueNCEnumToName[i]);
797 }
798 }
799}
800
801void Builder::fixupMiscellaneousOffsets() {
802 int32_t i;
803
804 // header:
805 erase(&header, sizeof(header));
806 header.enumToName_offset = enumToName_offset;
807 header.nameToEnum_offset = nameToEnum_offset;
808 header.enumToValue_offset = enumToValue_offset;
809 // header meta-info used by Java:
374ca955 810 U_ASSERT(total_size > 0 && total_size < 0x7FFF);
b75a7d8f
A
811 header.total_size = (int16_t) total_size;
812 header.valueMap_offset = valueMap_offset;
813 header.valueMap_count = (int16_t) valueMap_count;
814 header.nameGroupPool_offset = nameGroupPool_offset;
815 header.nameGroupPool_count = (int16_t) nameGroupPool_count;
816 header.stringPool_offset = stringPool_offset;
817 header.stringPool_count = (int16_t) stringPool_count - 1; // don't include "" entry
818
374ca955
A
819 U_ASSERT(valueMap_count <= 0x7FFF);
820 U_ASSERT(nameGroupPool_count <= 0x7FFF);
821 U_ASSERT(stringPool_count <= 0x7FFF);
b75a7d8f
A
822
823 // 3:
824 Offset* p = enumToValue->getOffsetArray();
374ca955 825 /*EnumValue* e = enumToValue->getEnumArray();*/
b75a7d8f
A
826 U_ASSERT(valueMap_count == enumToValue->count);
827 for (i=0; i<valueMap_count; ++i) {
828 p[i] = (Offset)(valueMap_offset + sizeof(ValueMap) * i);
829 }
830
831 // 4:
832 for (i=0; i<valueMap_count; ++i) {
833 ValueMap& v = valueMap[i];
834 v.enumToName_offset = v.ncEnumToName_offset = 0;
835 if (valueEnumToName[i] != 0) {
836 v.enumToName_offset = valueEnumToName_offset[i];
837 }
838 if (valueNCEnumToName[i] != 0) {
839 v.ncEnumToName_offset = valueEnumToName_offset[i];
840 }
841 v.nameToEnum_offset = valueNameToEnum_offset[i];
842 }
843}
844
845void Builder::fixup() {
846 computeOffsets();
847 fixupStringPoolOffsets();
848 fixupNameGroupPoolOffsets();
849 fixupMiscellaneousOffsets();
850}
851
852int8_t* Builder::createData(int32_t& length) const {
853 length = total_size;
854 int8_t* result = MALLOC(int8_t, length);
855
856 int8_t* p = result;
857 int8_t* limit = result + length;
858
859 #define APPEND2(x, size) \
860 U_ASSERT((p+size)<=limit); \
861 uprv_memcpy(p, x, size); \
862 p += size
863
864 #define APPEND(x) APPEND2(x, x##_size)
865
866 APPEND2(&header, sizeof(header));
867 APPEND(enumToName);
868 APPEND(nameToEnum);
869 APPEND(enumToValue);
870 APPEND(valueMap);
871
872 for (int32_t i=0; i<valueMap_count; ++i) {
873 U_ASSERT((valueEnumToName[i] != 0 && valueNCEnumToName[i] == 0) ||
874 (valueEnumToName[i] == 0 && valueNCEnumToName[i] != 0));
875 if (valueEnumToName[i] != 0) {
876 APPEND2(valueEnumToName[i], valueEnumToName_size[i]);
877 }
878 if (valueNCEnumToName[i] != 0) {
879 APPEND2(valueNCEnumToName[i], valueEnumToName_size[i]);
880 }
881 APPEND2(valueNameToEnum[i], valueNameToEnum_size[i]);
882 }
883
884 APPEND(nameGroupPool);
885 APPEND(stringPool);
886
374ca955
A
887 if (p != limit) {
888 fprintf(stderr, "p != limit; p = %p, limit = %p", p, limit);
889 exit(1);
890 }
b75a7d8f
A
891 return result;
892}
893
894// END Builder
895//----------------------------------------------------------------------
896
897/* UDataInfo cf. udata.h */
898static UDataInfo dataInfo = {
899 sizeof(UDataInfo),
900 0,
901
902 U_IS_BIG_ENDIAN,
903 U_CHARSET_FAMILY,
904 sizeof(UChar),
905 0,
906
907 {PNAME_SIG_0, PNAME_SIG_1, PNAME_SIG_2, PNAME_SIG_3},
908 {PNAME_FORMAT_VERSION, 0, 0, 0}, /* formatVersion */
909 {VERSION_0, VERSION_1, VERSION_2, VERSION_3} /* Unicode version */
910};
911
b75a7d8f
A
912class genpname {
913
914 // command-line options
915 UBool useCopyright;
916 UBool verbose;
917 int32_t debug;
918
919public:
920 int MMain(int argc, char *argv[]);
921
922private:
923 NameToEnumEntry* createNameIndex(const AliasList& list,
924 int32_t& nameIndexCount);
925
926 EnumToNameGroupEntry* createEnumIndex(const AliasList& list);
927
928 int32_t writeDataFile(const char *destdir, const Builder&);
929};
930
931int main(int argc, char *argv[]) {
374ca955
A
932 UErrorCode status = U_ZERO_ERROR;
933 u_init(&status);
934 if (U_FAILURE(status) && status != U_FILE_ACCESS_ERROR) {
935 // Note: u_init() will try to open ICU property data.
936 // failures here are expected when building ICU from scratch.
937 // ignore them.
938 fprintf(stderr, "genpname: can not initialize ICU. Status = %s\n",
939 u_errorName(status));
940 exit(1);
941 }
942
b75a7d8f
A
943 genpname app;
944 U_MAIN_INIT_ARGS(argc, argv);
374ca955
A
945 int retVal = app.MMain(argc, argv);
946 u_cleanup();
947 return retVal;
b75a7d8f
A
948}
949
950static UOption options[]={
951 UOPTION_HELP_H,
952 UOPTION_HELP_QUESTION_MARK,
953 UOPTION_COPYRIGHT,
954 UOPTION_DESTDIR,
955 UOPTION_VERBOSE,
956 UOPTION_DEF("debug", 'D', UOPT_REQUIRES_ARG),
957};
958
959NameToEnumEntry* genpname::createNameIndex(const AliasList& list,
960 int32_t& nameIndexCount) {
961
962 // Build name => enum map
963
964 // This is an n->1 map. There are typically multiple names
965 // mapping to one enum. The name index is sorted in order of the name,
966 // as defined by the uprv_compareAliasNames() function.
967
968 int32_t i, j;
969 int32_t count = list.count();
970
971 // compute upper limit on number of names in the index
972 int32_t nameIndexCapacity = count * MAX_NAMES_PER_GROUP;
973 NameToEnumEntry* nameIndex = MALLOC(NameToEnumEntry, nameIndexCapacity);
974
975 nameIndexCount = 0;
976 int32_t names[MAX_NAMES_PER_GROUP];
977 for (i=0; i<count; ++i) {
978 const Alias& p = list[i];
979 int32_t n = p.getUniqueNames(names);
980 for (j=0; j<n; ++j) {
981 U_ASSERT(nameIndexCount < nameIndexCapacity);
982 nameIndex[nameIndexCount++] =
983 NameToEnumEntry(names[j], p.enumValue);
984 }
985 }
374ca955
A
986
987 /*
988 * use a stable sort to ensure consistent results between
989 * genpname.cpp and the propname.cpp swapping code
990 */
991 UErrorCode errorCode = U_ZERO_ERROR;
992 uprv_sortArray(nameIndex, nameIndexCount, sizeof(nameIndex[0]),
993 compareNameToEnumEntry, NULL, TRUE, &errorCode);
b75a7d8f 994 if (debug>1) {
374ca955 995 printf("Alias names: %d\n", (int)nameIndexCount);
b75a7d8f
A
996 for (i=0; i<nameIndexCount; ++i) {
997 printf("%s => %d\n",
998 STRING_TABLE[nameIndex[i].nameIndex].str,
374ca955 999 (int)nameIndex[i].enumValue);
b75a7d8f
A
1000 }
1001 printf("\n");
1002 }
1003 // make sure there are no duplicates. for a sorted list we need
1004 // only compare adjacent items. Alias.getUniqueNames() has
1005 // already eliminated duplicate names for a single property, which
1006 // does occur, so we're checking for duplicate names between two
1007 // properties, which should never occur.
1008 UBool ok = TRUE;
1009 for (i=1; i<nameIndexCount; ++i) {
1010 if (STRING_TABLE[nameIndex[i-1].nameIndex] ==
1011 STRING_TABLE[nameIndex[i].nameIndex]) {
1012 printf("Error: Duplicate names in property list: \"%s\", \"%s\"\n",
1013 STRING_TABLE[nameIndex[i-1].nameIndex].str,
1014 STRING_TABLE[nameIndex[i].nameIndex].str);
1015 ok = FALSE;
1016 }
1017 }
1018 if (!ok) {
1019 die("Two or more duplicate names in property list");
1020 }
1021
1022 return nameIndex;
1023}
1024
1025EnumToNameGroupEntry* genpname::createEnumIndex(const AliasList& list) {
1026
1027 // Build the enum => name map
1028
1029 // This is a 1->n map. Each enum maps to 1 or more names. To
1030 // accomplish this the index entry points to an element of the
1031 // NAME_GROUP array. This is the short name (which may be empty).
1032 // From there, subsequent elements of NAME_GROUP are alternate
1033 // names for this enum, up to and including the first one that is
1034 // negative (negate for actual index).
1035
1036 int32_t i, j, k;
1037 int32_t count = list.count();
1038
1039 EnumToNameGroupEntry* enumIndex = MALLOC(EnumToNameGroupEntry, count);
1040 for (i=0; i<count; ++i) {
1041 const Alias& p = list[i];
1042 enumIndex[i] = EnumToNameGroupEntry(p.enumValue, p.nameGroupIndex);
1043 }
374ca955
A
1044
1045 UErrorCode errorCode = U_ZERO_ERROR;
1046 uprv_sortArray(enumIndex, count, sizeof(enumIndex[0]),
1047 compareEnumToNameGroupEntry, NULL, FALSE, &errorCode);
b75a7d8f 1048 if (debug>1) {
374ca955 1049 printf("Property enums: %d\n", (int)count);
b75a7d8f
A
1050 for (i=0; i<count; ++i) {
1051 printf("%d => %d: ",
374ca955
A
1052 (int)enumIndex[i].enumValue,
1053 (int)enumIndex[i].nameGroupIndex);
b75a7d8f
A
1054 UBool done = FALSE;
1055 for (j=enumIndex[i].nameGroupIndex; !done; ++j) {
1056 k = NAME_GROUP[j];
1057 if (k < 0) {
1058 k = -k;
1059 done = TRUE;
1060 }
1061 printf("\"%s\"", STRING_TABLE[k].str);
1062 if (!done) printf(", ");
1063 }
1064 printf("\n");
1065 }
1066 printf("\n");
1067 }
1068 return enumIndex;
1069}
1070
374ca955
A
1071int genpname::MMain(int argc, char* argv[])
1072{
b75a7d8f 1073 int32_t i, j;
374ca955
A
1074 UErrorCode status = U_ZERO_ERROR;
1075
1076 u_init(&status);
1077 if (U_FAILURE(status) && status != U_FILE_ACCESS_ERROR) {
1078 fprintf(stderr, "Error: u_init returned %s\n", u_errorName(status));
1079 status = U_ZERO_ERROR;
1080 }
1081
b75a7d8f
A
1082
1083 /* preset then read command line options */
1084 options[3].value=u_getDataDirectory();
1085 argc=u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options);
1086
1087 /* error handling, printing usage message */
1088 if (argc<0) {
1089 fprintf(stderr,
1090 "error in command line argument \"%s\"\n",
1091 argv[-argc]);
1092 }
1093
1094 debug = options[5].doesOccur ? (*options[5].value - '0') : 0;
1095
1096 if (argc!=1 || options[0].doesOccur || options[1].doesOccur ||
1097 debug < 0 || debug > 9) {
1098 fprintf(stderr,
1099 "usage: %s [-options]\n"
374ca955 1100 "\tcreate " PNAME_DATA_NAME "." PNAME_DATA_TYPE "\n"
b75a7d8f
A
1101 "options:\n"
1102 "\t-h or -? or --help this usage text\n"
1103 "\t-v or --verbose turn on verbose output\n"
1104 "\t-c or --copyright include a copyright notice\n"
1105 "\t-d or --destdir destination directory, followed by the path\n"
1106 "\t-D or --debug 0..9 emit debugging messages (if > 0)\n",
1107 argv[0]);
1108 return argc<0 ? U_ILLEGAL_ARGUMENT_ERROR : U_ZERO_ERROR;
1109 }
1110
1111 /* get the options values */
1112 useCopyright=options[2].doesOccur;
1113 verbose = options[4].doesOccur;
1114
1115 // ------------------------------------------------------------
374ca955
A
1116 // Do not sort the string table, instead keep it in data.h order.
1117 // This simplifies data swapping and testing thereof because the string
1118 // table itself need not be sorted during swapping.
1119 // The NameToEnum sorter sorts each such map's string offsets instead.
1120
b75a7d8f 1121 if (debug>1) {
374ca955
A
1122 printf("String pool: %d\n", (int)STRING_COUNT);
1123 for (i=0; i<STRING_COUNT; ++i) {
1124 if (i != 0) {
1125 printf(", ");
1126 }
1127 printf("%s (%d)", STRING_TABLE[i].str, (int)STRING_TABLE[i].index);
b75a7d8f 1128 }
b75a7d8f
A
1129 printf("\n\n");
1130 }
1131
b75a7d8f
A
1132 // ------------------------------------------------------------
1133 // Create top-level property indices
1134
1135 PropertyArrayList props(PROPERTY, PROPERTY_COUNT);
1136 int32_t propNameCount;
1137 NameToEnumEntry* propName = createNameIndex(props, propNameCount);
1138 EnumToNameGroupEntry* propEnum = createEnumIndex(props);
1139
1140 // ------------------------------------------------------------
1141 // Create indices for the value list for each enumerated property
1142
1143 // This will have more entries than we need...
1144 EnumToValueEntry* enumToValue = MALLOC(EnumToValueEntry, PROPERTY_COUNT);
1145 int32_t enumToValue_count = 0;
1146 for (i=0, j=0; i<PROPERTY_COUNT; ++i) {
1147 if (PROPERTY[i].valueCount == 0) continue;
1148 AliasArrayList values(PROPERTY[i].valueList,
1149 PROPERTY[i].valueCount);
1150 enumToValue[j].enumValue = PROPERTY[i].enumValue;
1151 enumToValue[j].enumToName = createEnumIndex(values);
1152 enumToValue[j].enumToName_count = PROPERTY[i].valueCount;
1153 enumToValue[j].nameToEnum = createNameIndex(values,
1154 enumToValue[j].nameToEnum_count);
1155 ++j;
1156 }
1157 enumToValue_count = j;
374ca955
A
1158
1159 uprv_sortArray(enumToValue, enumToValue_count, sizeof(enumToValue[0]),
1160 compareEnumToValueEntry, NULL, FALSE, &status);
b75a7d8f
A
1161
1162 // ------------------------------------------------------------
1163 // Build PropertyAliases layout in memory
1164
1165 Builder builder(debug);
1166
1167 builder.buildTopLevelProperties(propName,
1168 propNameCount,
1169 propEnum,
1170 PROPERTY_COUNT);
1171
1172 builder.buildValues(enumToValue,
1173 enumToValue_count);
1174
1175 builder.buildStringPool(STRING_TABLE,
1176 STRING_COUNT,
1177 NAME_GROUP,
1178 NAME_GROUP_COUNT);
1179
1180 builder.fixup();
1181
1182 ////////////////////////////////////////////////////////////
1183 // Write the output file
1184 ////////////////////////////////////////////////////////////
1185 int32_t wlen = writeDataFile(options[3].value, builder);
1186 if (verbose) {
1187 fprintf(stdout, "Output file: %s.%s, %ld bytes\n",
1188 U_ICUDATA_NAME "_" PNAME_DATA_NAME, PNAME_DATA_TYPE, (long)wlen);
1189 }
1190
1191 return 0; // success
1192}
1193
1194int32_t genpname::writeDataFile(const char *destdir, const Builder& builder) {
1195 int32_t length;
1196 int8_t* data = builder.createData(length);
1197
1198 UNewDataMemory *pdata;
1199 UErrorCode status = U_ZERO_ERROR;
1200
374ca955 1201 pdata = udata_create(destdir, PNAME_DATA_TYPE, PNAME_DATA_NAME, &dataInfo,
b75a7d8f
A
1202 useCopyright ? U_COPYRIGHT_STRING : 0, &status);
1203 if (U_FAILURE(status)) {
1204 die("Unable to create data memory");
1205 }
1206
1207 udata_writeBlock(pdata, data, length);
1208
1209 int32_t dataLength = (int32_t) udata_finish(pdata, &status);
1210 if (U_FAILURE(status)) {
1211 die("Error writing output file");
1212 }
1213 if (dataLength != length) {
1214 die("Written file doesn't match expected size");
1215 }
1216
1217 return dataLength;
1218}
1219
1220//eof