diff options
author | Peter Breitenlohner <peb@mppmu.mpg.de> | 2009-04-20 18:13:48 +0000 |
---|---|---|
committer | Peter Breitenlohner <peb@mppmu.mpg.de> | 2009-04-20 18:13:48 +0000 |
commit | e5786f530f9555469c01435f86039b06aa53feba (patch) | |
tree | c868e8d32282422d7d445b729db95c3fcdafb6d0 /Build/source/libs/icu/icu-xetex/tools/genpname/genpname.cpp | |
parent | ebaa1768b43c8606d923d2e861b5286b74207b3e (diff) |
new build system: build icu libs and xetex plus misc updates
git-svn-id: svn://tug.org/texlive/trunk@12759 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/libs/icu/icu-xetex/tools/genpname/genpname.cpp')
-rw-r--r-- | Build/source/libs/icu/icu-xetex/tools/genpname/genpname.cpp | 1225 |
1 files changed, 1225 insertions, 0 deletions
diff --git a/Build/source/libs/icu/icu-xetex/tools/genpname/genpname.cpp b/Build/source/libs/icu/icu-xetex/tools/genpname/genpname.cpp new file mode 100644 index 00000000000..84294a62ee0 --- /dev/null +++ b/Build/source/libs/icu/icu-xetex/tools/genpname/genpname.cpp @@ -0,0 +1,1225 @@ +/* +********************************************************************** +* Copyright (C) 2002-2006, International Business Machines +* Corporation and others. All Rights Reserved. +********************************************************************** +* Date Name Description +* 10/11/02 aliu Creation. +********************************************************************** +*/ + +#include "unicode/utypes.h" +#include "unicode/putil.h" +#include "unicode/uclean.h" +#include "cmemory.h" +#include "cstring.h" +#include "filestrm.h" +#include "uarrsort.h" +#include "unewdata.h" +#include "uoptions.h" +#include "uprops.h" +#include "propname.h" +#include "uassert.h" + +#include <stdio.h> + +U_NAMESPACE_USE + +// TODO: Clean up and comment this code. + +//---------------------------------------------------------------------- +// BEGIN DATA +// +// This is the raw data to be output. We define the data structure, +// then include a machine-generated header that contains the actual +// data. + +#include "unicode/uchar.h" +#include "unicode/uscript.h" +#include "unicode/unorm.h" + +class AliasName { +public: + const char* str; + int32_t index; + + AliasName(const char* str, int32_t index); + + int compare(const AliasName& other) const; + + UBool operator==(const AliasName& other) const { + return compare(other) == 0; + } + + UBool operator!=(const AliasName& other) const { + return compare(other) != 0; + } +}; + +AliasName::AliasName(const char* _str, + int32_t _index) : + str(_str), + index(_index) +{ +} + +int AliasName::compare(const AliasName& other) const { + return uprv_comparePropertyNames(str, other.str); +} + +class Alias { +public: + int32_t enumValue; + int32_t nameGroupIndex; + + Alias(int32_t enumValue, + int32_t nameGroupIndex); + + int32_t getUniqueNames(int32_t* nameGroupIndices) const; +}; + +Alias::Alias(int32_t anEnumValue, + int32_t aNameGroupIndex) : + enumValue(anEnumValue), + nameGroupIndex(aNameGroupIndex) +{ +} + +class Property : public Alias { +public: + int32_t valueCount; + const Alias* valueList; + + Property(int32_t enumValue, + int32_t nameGroupIndex, + int32_t valueCount, + const Alias* valueList); +}; + +Property::Property(int32_t _enumValue, + int32_t _nameGroupIndex, + int32_t _valueCount, + const Alias* _valueList) : + Alias(_enumValue, _nameGroupIndex), + valueCount(_valueCount), + valueList(_valueList) +{ +} + +// *** Include the data header *** +#include "data.h" + +/* return a list of unique names, not including "", for this property + * @param stringIndices array of at least MAX_NAMES_PER_GROUP + * elements, will be filled with indices into STRING_TABLE + * @return number of indices, >= 1 + */ +int32_t Alias::getUniqueNames(int32_t* stringIndices) const { + int32_t count = 0; + int32_t i = nameGroupIndex; + UBool done = FALSE; + while (!done) { + int32_t j = NAME_GROUP[i++]; + if (j < 0) { + done = TRUE; + j = -j; + } + if (j == 0) continue; // omit "" entries + UBool dupe = FALSE; + for (int32_t k=0; k<count; ++k) { + if (stringIndices[k] == j) { + dupe = TRUE; + break; + } + // also do a string check for things like "age|Age" + if (STRING_TABLE[stringIndices[k]] == STRING_TABLE[j]) { + //printf("Found dupe %s|%s\n", + // STRING_TABLE[stringIndices[k]].str, + // STRING_TABLE[j].str); + dupe = TRUE; + break; + } + } + if (dupe) continue; // omit duplicates + stringIndices[count++] = j; + } + return count; +} + +// END DATA +//---------------------------------------------------------------------- + +#define MALLOC(type, count) \ + (type*) uprv_malloc(sizeof(type) * count) + +void die(const char* msg) { + fprintf(stderr, "Error: %s\n", msg); + exit(1); +} + +//---------------------------------------------------------------------- + +/** + * A list of Alias objects. + */ +class AliasList { +public: + virtual ~AliasList(); + virtual const Alias& operator[](int32_t i) const = 0; + virtual int32_t count() const = 0; +}; + +AliasList::~AliasList() {} + +/** + * A single array. + */ +class AliasArrayList : public AliasList { + const Alias* a; + int32_t n; +public: + AliasArrayList(const Alias* _a, int32_t _n) { + a = _a; + n = _n; + } + virtual const Alias& operator[](int32_t i) const { + return a[i]; + } + virtual int32_t count() const { + return n; + } +}; + +/** + * A single array. + */ +class PropertyArrayList : public AliasList { + const Property* a; + int32_t n; +public: + PropertyArrayList(const Property* _a, int32_t _n) { + a = _a; + n = _n; + } + virtual const Alias& operator[](int32_t i) const { + return a[i]; + } + virtual int32_t count() const { + return n; + } +}; + +//---------------------------------------------------------------------- + +/** + * An element in a name index. It maps a name (given by index) into + * an enum value. + */ +class NameToEnumEntry { +public: + int32_t nameIndex; + int32_t enumValue; + NameToEnumEntry(int32_t a, int32_t b) { nameIndex=a; enumValue=b; } +}; + +// Sort function for NameToEnumEntry (sort by name) +U_CFUNC int32_t +compareNameToEnumEntry(const void * /*context*/, const void* e1, const void* e2) { + return + STRING_TABLE[((NameToEnumEntry*)e1)->nameIndex]. + compare(STRING_TABLE[((NameToEnumEntry*)e2)->nameIndex]); +} + +//---------------------------------------------------------------------- + +/** + * An element in an enum index. It maps an enum into a name group entry + * (given by index). + */ +class EnumToNameGroupEntry { +public: + int32_t enumValue; + int32_t nameGroupIndex; + EnumToNameGroupEntry(int32_t a, int32_t b) { enumValue=a; nameGroupIndex=b; } + + // are enumValues contiguous for count entries starting with this one? + // ***!!!*** we assume we are in an array and look at neighbors ***!!!*** + UBool isContiguous(int32_t count) const { + const EnumToNameGroupEntry* p = this; + for (int32_t i=1; i<count; ++i) { + if (p[i].enumValue != (this->enumValue + i)) { + return FALSE; + } + } + return TRUE; + } +}; + +// Sort function for EnumToNameGroupEntry (sort by name index) +U_CFUNC int32_t +compareEnumToNameGroupEntry(const void * /*context*/, const void* e1, const void* e2) { + return ((EnumToNameGroupEntry*)e1)->enumValue - ((EnumToNameGroupEntry*)e2)->enumValue; +} + +//---------------------------------------------------------------------- + +/** + * An element in the map from enumerated property enums to value maps. + */ +class EnumToValueEntry { +public: + int32_t enumValue; + EnumToNameGroupEntry* enumToName; + int32_t enumToName_count; + NameToEnumEntry* nameToEnum; + int32_t nameToEnum_count; + + // are enumValues contiguous for count entries starting with this one? + // ***!!!*** we assume we are in an array and look at neighbors ***!!!*** + UBool isContiguous(int32_t count) const { + const EnumToValueEntry* p = this; + for (int32_t i=1; i<count; ++i) { + if (p[i].enumValue != (this->enumValue + i)) { + return FALSE; + } + } + return TRUE; + } +}; + +// Sort function for EnumToValueEntry (sort by enum) +U_CFUNC int32_t +compareEnumToValueEntry(const void * /*context*/, const void* e1, const void* e2) { + return ((EnumToValueEntry*)e1)->enumValue - ((EnumToValueEntry*)e2)->enumValue; +} + +//---------------------------------------------------------------------- +// BEGIN Builder + +#define IS_VALID_OFFSET(x) (((x)>=0)&&((x)<=MAX_OFFSET)) + +class Builder { + // header: + PropertyAliases header; + + // 0: + NonContiguousEnumToOffset* enumToName; + int32_t enumToName_size; + Offset enumToName_offset; + + // 1: (deleted) + + // 2: + NameToEnum* nameToEnum; + int32_t nameToEnum_size; + Offset nameToEnum_offset; + + // 3: + NonContiguousEnumToOffset* enumToValue; + int32_t enumToValue_size; + Offset enumToValue_offset; + + // 4: + ValueMap* valueMap; + int32_t valueMap_size; + int32_t valueMap_count; + Offset valueMap_offset; + + // for any i, one of valueEnumToName[i] or valueNCEnumToName[i] is + // NULL and one is not. valueEnumToName_size[i] is the size of + // the non-NULL one. i=0..valueMapCount-1 + // 5a: + EnumToOffset** valueEnumToName; + // 5b: + NonContiguousEnumToOffset** valueNCEnumToName; + int32_t* valueEnumToName_size; + Offset* valueEnumToName_offset; + // 6: + // arrays of valueMap_count pointers, sizes, & offsets + NameToEnum** valueNameToEnum; + int32_t* valueNameToEnum_size; + Offset* valueNameToEnum_offset; + + // 98: + Offset* nameGroupPool; + int32_t nameGroupPool_count; + int32_t nameGroupPool_size; + Offset nameGroupPool_offset; + + // 99: + char* stringPool; + int32_t stringPool_count; + int32_t stringPool_size; + Offset stringPool_offset; + Offset* stringPool_offsetArray; // relative to stringPool + + int32_t total_size; // size of everything + + int32_t debug; + +public: + + Builder(int32_t debugLevel); + ~Builder(); + + void buildTopLevelProperties(const NameToEnumEntry* propName, + int32_t propNameCount, + const EnumToNameGroupEntry* propEnum, + int32_t propEnumCount); + + void buildValues(const EnumToValueEntry* e2v, + int32_t count); + + void buildStringPool(const AliasName* propertyNames, + int32_t propertyNameCount, + const int32_t* nameGroupIndices, + int32_t nameGroupIndicesCount); + + void fixup(); + + int8_t* createData(int32_t& length) const; + +private: + + static EnumToOffset* buildEnumToOffset(const EnumToNameGroupEntry* e2ng, + int32_t count, + int32_t& size); + static NonContiguousEnumToOffset* + buildNCEnumToNameGroup(const EnumToNameGroupEntry* e2ng, + int32_t count, + int32_t& size); + + static NonContiguousEnumToOffset* + buildNCEnumToValue(const EnumToValueEntry* e2v, + int32_t count, + int32_t& size); + + static NameToEnum* buildNameToEnum(const NameToEnumEntry* nameToEnum, + int32_t count, + int32_t& size); + + Offset stringIndexToOffset(int32_t index, UBool allowNeg=FALSE) const; + void fixupNameToEnum(NameToEnum* n); + void fixupEnumToNameGroup(EnumToOffset* e2ng); + void fixupNCEnumToNameGroup(NonContiguousEnumToOffset* e2ng); + + void computeOffsets(); + void fixupStringPoolOffsets(); + void fixupNameGroupPoolOffsets(); + void fixupMiscellaneousOffsets(); + + static int32_t align(int32_t a); + static void erase(void* p, int32_t size); +}; + +Builder::Builder(int32_t debugLevel) { + debug = debugLevel; + enumToName = 0; + nameToEnum = 0; + enumToValue = 0; + valueMap_count = 0; + valueMap = 0; + valueEnumToName = 0; + valueNCEnumToName = 0; + valueEnumToName_size = 0; + valueEnumToName_offset = 0; + valueNameToEnum = 0; + valueNameToEnum_size = 0; + valueNameToEnum_offset = 0; + nameGroupPool = 0; + stringPool = 0; + stringPool_offsetArray = 0; +} + +Builder::~Builder() { + uprv_free(enumToName); + uprv_free(nameToEnum); + uprv_free(enumToValue); + uprv_free(valueMap); + for (int32_t i=0; i<valueMap_count; ++i) { + uprv_free(valueEnumToName[i]); + uprv_free(valueNCEnumToName[i]); + uprv_free(valueNameToEnum[i]); + } + uprv_free(valueEnumToName); + uprv_free(valueNCEnumToName); + uprv_free(valueEnumToName_size); + uprv_free(valueEnumToName_offset); + uprv_free(valueNameToEnum); + uprv_free(valueNameToEnum_size); + uprv_free(valueNameToEnum_offset); + uprv_free(nameGroupPool); + uprv_free(stringPool); + uprv_free(stringPool_offsetArray); +} + +int32_t Builder::align(int32_t a) { + U_ASSERT(a >= 0); + int32_t k = a % sizeof(int32_t); + if (k == 0) { + return a; + } + a += sizeof(int32_t) - k; + return a; +} + +void Builder::erase(void* p, int32_t size) { + U_ASSERT(size >= 0); + int8_t* q = (int8_t*) p; + while (size--) { + *q++ = 0; + } +} + +EnumToOffset* Builder::buildEnumToOffset(const EnumToNameGroupEntry* e2ng, + int32_t count, + int32_t& size) { + U_ASSERT(e2ng->isContiguous(count)); + size = align(EnumToOffset::getSize(count)); + EnumToOffset* result = (EnumToOffset*) uprv_malloc(size); + erase(result, size); + result->enumStart = e2ng->enumValue; + result->enumLimit = e2ng->enumValue + count; + Offset* p = result->getOffsetArray(); + for (int32_t i=0; i<count; ++i) { + // set these to NGI index values + // fix them up to NGI offset values + U_ASSERT(IS_VALID_OFFSET(e2ng[i].nameGroupIndex)); + p[i] = (Offset) e2ng[i].nameGroupIndex; // FIXUP later + } + return result; +} + +NonContiguousEnumToOffset* +Builder::buildNCEnumToNameGroup(const EnumToNameGroupEntry* e2ng, + int32_t count, + int32_t& size) { + U_ASSERT(!e2ng->isContiguous(count)); + size = align(NonContiguousEnumToOffset::getSize(count)); + NonContiguousEnumToOffset* nc = (NonContiguousEnumToOffset*) uprv_malloc(size); + erase(nc, size); + nc->count = count; + EnumValue* e = nc->getEnumArray(); + Offset* p = nc->getOffsetArray(); + for (int32_t i=0; i<count; ++i) { + // set these to NGI index values + // fix them up to NGI offset values + e[i] = e2ng[i].enumValue; + U_ASSERT(IS_VALID_OFFSET(e2ng[i].nameGroupIndex)); + p[i] = (Offset) e2ng[i].nameGroupIndex; // FIXUP later + } + return nc; +} + +NonContiguousEnumToOffset* +Builder::buildNCEnumToValue(const EnumToValueEntry* e2v, + int32_t count, + int32_t& size) { + U_ASSERT(!e2v->isContiguous(count)); + size = align(NonContiguousEnumToOffset::getSize(count)); + NonContiguousEnumToOffset* result = (NonContiguousEnumToOffset*) uprv_malloc(size); + erase(result, size); + result->count = count; + EnumValue* e = result->getEnumArray(); + for (int32_t i=0; i<count; ++i) { + e[i] = e2v[i].enumValue; + // offset must be set later + } + return result; +} + +/** + * Given an index into the string pool, return an offset. computeOffsets() + * must have been called already. If allowNegative is true, allow negatives + * and preserve their sign. + */ +Offset Builder::stringIndexToOffset(int32_t index, UBool allowNegative) const { + // Index 0 is ""; we turn this into an Offset of zero + if (index == 0) return 0; + if (index < 0) { + if (allowNegative) { + return -Builder::stringIndexToOffset(-index); + } else { + die("Negative string pool index"); + } + } else { + if (index >= stringPool_count) { + die("String pool index too large"); + } + Offset result = stringPool_offset + stringPool_offsetArray[index]; + U_ASSERT(result >= 0 && result < total_size); + return result; + } + return 0; // never executed; make compiler happy +} + +NameToEnum* Builder::buildNameToEnum(const NameToEnumEntry* nameToEnum, + int32_t count, + int32_t& size) { + size = align(NameToEnum::getSize(count)); + NameToEnum* n2e = (NameToEnum*) uprv_malloc(size); + erase(n2e, size); + n2e->count = count; + Offset* p = n2e->getNameArray(); + EnumValue* e = n2e->getEnumArray(); + for (int32_t i=0; i<count; ++i) { + // set these to SP index values + // fix them up to SP offset values + U_ASSERT(IS_VALID_OFFSET(nameToEnum[i].nameIndex)); + p[i] = (Offset) nameToEnum[i].nameIndex; // FIXUP later + e[i] = nameToEnum[i].enumValue; + } + return n2e; +} + + +void Builder::buildTopLevelProperties(const NameToEnumEntry* propName, + int32_t propNameCount, + const EnumToNameGroupEntry* propEnum, + int32_t propEnumCount) { + enumToName = buildNCEnumToNameGroup(propEnum, + propEnumCount, + enumToName_size); + nameToEnum = buildNameToEnum(propName, + propNameCount, + nameToEnum_size); +} + +void Builder::buildValues(const EnumToValueEntry* e2v, + int32_t count) { + int32_t i; + + U_ASSERT(!e2v->isContiguous(count)); + + valueMap_count = count; + + enumToValue = buildNCEnumToValue(e2v, count, + enumToValue_size); + + valueMap_size = align(count * sizeof(ValueMap)); + valueMap = (ValueMap*) uprv_malloc(valueMap_size); + erase(valueMap, valueMap_size); + + valueEnumToName = MALLOC(EnumToOffset*, count); + valueNCEnumToName = MALLOC(NonContiguousEnumToOffset*, count); + valueEnumToName_size = MALLOC(int32_t, count); + valueEnumToName_offset = MALLOC(Offset, count); + valueNameToEnum = MALLOC(NameToEnum*, count); + valueNameToEnum_size = MALLOC(int32_t, count); + valueNameToEnum_offset = MALLOC(Offset, count); + + for (i=0; i<count; ++i) { + UBool isContiguous = + e2v[i].enumToName->isContiguous(e2v[i].enumToName_count); + valueEnumToName[i] = 0; + valueNCEnumToName[i] = 0; + if (isContiguous) { + valueEnumToName[i] = buildEnumToOffset(e2v[i].enumToName, + e2v[i].enumToName_count, + valueEnumToName_size[i]); + } else { + valueNCEnumToName[i] = buildNCEnumToNameGroup(e2v[i].enumToName, + e2v[i].enumToName_count, + valueEnumToName_size[i]); + } + valueNameToEnum[i] = + buildNameToEnum(e2v[i].nameToEnum, + e2v[i].nameToEnum_count, + valueNameToEnum_size[i]); + } +} + +void Builder::buildStringPool(const AliasName* propertyNames, + int32_t propertyNameCount, + const int32_t* nameGroupIndices, + int32_t nameGroupIndicesCount) { + int32_t i; + + nameGroupPool_count = nameGroupIndicesCount; + nameGroupPool_size = sizeof(Offset) * nameGroupPool_count; + nameGroupPool = MALLOC(Offset, nameGroupPool_count); + + for (i=0; i<nameGroupPool_count; ++i) { + // Some indices are negative. + int32_t a = nameGroupIndices[i]; + if (a < 0) a = -a; + U_ASSERT(IS_VALID_OFFSET(a)); + nameGroupPool[i] = (Offset) nameGroupIndices[i]; + } + + stringPool_count = propertyNameCount; + stringPool_size = 0; + // first string must be "" -- we skip it + U_ASSERT(*propertyNames[0].str == 0); + for (i=1 /*sic*/; i<propertyNameCount; ++i) { + stringPool_size += (int32_t)(uprv_strlen(propertyNames[i].str) + 1); + } + stringPool = MALLOC(char, stringPool_size); + stringPool_offsetArray = MALLOC(Offset, stringPool_count); + Offset soFar = 0; + char* p = stringPool; + stringPool_offsetArray[0] = -1; // we don't use this entry + for (i=1 /*sic*/; i<propertyNameCount; ++i) { + const char* str = propertyNames[i].str; + int32_t len = (int32_t)uprv_strlen(str); + uprv_strcpy(p, str); + p += len; + *p++ = 0; + stringPool_offsetArray[i] = soFar; + soFar += (Offset)(len+1); + } + U_ASSERT(soFar == stringPool_size); + U_ASSERT(p == (stringPool + stringPool_size)); +} + +// Confirm that PropertyAliases is a POD (plain old data; see C++ +// std). The following union will _fail to compile_ if +// PropertyAliases is _not_ a POD. (Note: We used to use the offsetof +// macro to check this, but that's not quite right, so that test is +// commented out -- see below.) +typedef union { + int32_t i; + PropertyAliases p; +} PropertyAliasesPODTest; + +void Builder::computeOffsets() { + int32_t i; + Offset off = sizeof(header); + + if (debug>0) { + printf("header \t offset=%4d size=%5d\n", 0, off); + } + + // PropertyAliases must have no v-table and must be + // padded (if necessary) to the next 32-bit boundary. + //U_ASSERT(offsetof(PropertyAliases, enumToName_offset) == 0); // see above + U_ASSERT(sizeof(header) % sizeof(int32_t) == 0); + + #define COMPUTE_OFFSET(foo) COMPUTE_OFFSET2(foo,int32_t) + + #define COMPUTE_OFFSET2(foo,type) \ + if (debug>0)\ + printf(#foo "\t offset=%4d size=%5d\n", off, (int)foo##_size);\ + foo##_offset = off;\ + U_ASSERT(IS_VALID_OFFSET(off + foo##_size));\ + U_ASSERT(foo##_offset % sizeof(type) == 0);\ + off = (Offset) (off + foo##_size); + + COMPUTE_OFFSET(enumToName); // 0: + COMPUTE_OFFSET(nameToEnum); // 2: + COMPUTE_OFFSET(enumToValue); // 3: + COMPUTE_OFFSET(valueMap); // 4: + + for (i=0; i<valueMap_count; ++i) { + if (debug>0) { + printf(" enumToName[%d]\t offset=%4d size=%5d\n", + (int)i, off, (int)valueEnumToName_size[i]); + } + + valueEnumToName_offset[i] = off; // 5: + U_ASSERT(IS_VALID_OFFSET(off + valueEnumToName_size[i])); + off = (Offset) (off + valueEnumToName_size[i]); + + if (debug>0) { + printf(" nameToEnum[%d]\t offset=%4d size=%5d\n", + (int)i, off, (int)valueNameToEnum_size[i]); + } + + valueNameToEnum_offset[i] = off; // 6: + U_ASSERT(IS_VALID_OFFSET(off + valueNameToEnum_size[i])); + off = (Offset) (off + valueNameToEnum_size[i]); + } + + // These last two chunks have weaker alignment needs + COMPUTE_OFFSET2(nameGroupPool,Offset); // 98: + COMPUTE_OFFSET2(stringPool,char); // 99: + + total_size = off; + if (debug>0) printf("total size=%5d\n\n", (int)total_size); + U_ASSERT(total_size <= (MAX_OFFSET+1)); +} + +void Builder::fixupNameToEnum(NameToEnum* n) { + // Fix the string pool offsets in n + Offset* p = n->getNameArray(); + for (int32_t i=0; i<n->count; ++i) { + p[i] = stringIndexToOffset(p[i]); + } +} + +void Builder::fixupStringPoolOffsets() { + int32_t i; + + // 2: + fixupNameToEnum(nameToEnum); + + // 6: + for (i=0; i<valueMap_count; ++i) { + fixupNameToEnum(valueNameToEnum[i]); + } + + // 98: + for (i=0; i<nameGroupPool_count; ++i) { + nameGroupPool[i] = stringIndexToOffset(nameGroupPool[i], TRUE); + } +} + +void Builder::fixupEnumToNameGroup(EnumToOffset* e2ng) { + EnumValue i; + int32_t j; + Offset* p = e2ng->getOffsetArray(); + for (i=e2ng->enumStart, j=0; i<e2ng->enumLimit; ++i, ++j) { + p[j] = nameGroupPool_offset + sizeof(Offset) * p[j]; + } +} + +void Builder::fixupNCEnumToNameGroup(NonContiguousEnumToOffset* e2ng) { + int32_t i; + /*EnumValue* e = e2ng->getEnumArray();*/ + Offset* p = e2ng->getOffsetArray(); + for (i=0; i<e2ng->count; ++i) { + p[i] = nameGroupPool_offset + sizeof(Offset) * p[i]; + } +} + +void Builder::fixupNameGroupPoolOffsets() { + int32_t i; + + // 0: + fixupNCEnumToNameGroup(enumToName); + + // 1: (deleted) + + // 5: + for (i=0; i<valueMap_count; ++i) { + // 5a: + if (valueEnumToName[i] != 0) { + fixupEnumToNameGroup(valueEnumToName[i]); + } + // 5b: + if (valueNCEnumToName[i] != 0) { + fixupNCEnumToNameGroup(valueNCEnumToName[i]); + } + } +} + +void Builder::fixupMiscellaneousOffsets() { + int32_t i; + + // header: + erase(&header, sizeof(header)); + header.enumToName_offset = enumToName_offset; + header.nameToEnum_offset = nameToEnum_offset; + header.enumToValue_offset = enumToValue_offset; + // header meta-info used by Java: + U_ASSERT(total_size > 0 && total_size < 0x7FFF); + header.total_size = (int16_t) total_size; + header.valueMap_offset = valueMap_offset; + header.valueMap_count = (int16_t) valueMap_count; + header.nameGroupPool_offset = nameGroupPool_offset; + header.nameGroupPool_count = (int16_t) nameGroupPool_count; + header.stringPool_offset = stringPool_offset; + header.stringPool_count = (int16_t) stringPool_count - 1; // don't include "" entry + + U_ASSERT(valueMap_count <= 0x7FFF); + U_ASSERT(nameGroupPool_count <= 0x7FFF); + U_ASSERT(stringPool_count <= 0x7FFF); + + // 3: + Offset* p = enumToValue->getOffsetArray(); + /*EnumValue* e = enumToValue->getEnumArray();*/ + U_ASSERT(valueMap_count == enumToValue->count); + for (i=0; i<valueMap_count; ++i) { + p[i] = (Offset)(valueMap_offset + sizeof(ValueMap) * i); + } + + // 4: + for (i=0; i<valueMap_count; ++i) { + ValueMap& v = valueMap[i]; + v.enumToName_offset = v.ncEnumToName_offset = 0; + if (valueEnumToName[i] != 0) { + v.enumToName_offset = valueEnumToName_offset[i]; + } + if (valueNCEnumToName[i] != 0) { + v.ncEnumToName_offset = valueEnumToName_offset[i]; + } + v.nameToEnum_offset = valueNameToEnum_offset[i]; + } +} + +void Builder::fixup() { + computeOffsets(); + fixupStringPoolOffsets(); + fixupNameGroupPoolOffsets(); + fixupMiscellaneousOffsets(); +} + +int8_t* Builder::createData(int32_t& length) const { + length = total_size; + int8_t* result = MALLOC(int8_t, length); + + int8_t* p = result; + int8_t* limit = result + length; + + #define APPEND2(x, size) \ + U_ASSERT((p+size)<=limit); \ + uprv_memcpy(p, x, size); \ + p += size + + #define APPEND(x) APPEND2(x, x##_size) + + APPEND2(&header, sizeof(header)); + APPEND(enumToName); + APPEND(nameToEnum); + APPEND(enumToValue); + APPEND(valueMap); + + for (int32_t i=0; i<valueMap_count; ++i) { + U_ASSERT((valueEnumToName[i] != 0 && valueNCEnumToName[i] == 0) || + (valueEnumToName[i] == 0 && valueNCEnumToName[i] != 0)); + if (valueEnumToName[i] != 0) { + APPEND2(valueEnumToName[i], valueEnumToName_size[i]); + } + if (valueNCEnumToName[i] != 0) { + APPEND2(valueNCEnumToName[i], valueEnumToName_size[i]); + } + APPEND2(valueNameToEnum[i], valueNameToEnum_size[i]); + } + + APPEND(nameGroupPool); + APPEND(stringPool); + + if (p != limit) { + fprintf(stderr, "p != limit; p = %p, limit = %p", p, limit); + exit(1); + } + return result; +} + +// END Builder +//---------------------------------------------------------------------- + +/* UDataInfo cf. udata.h */ +static UDataInfo dataInfo = { + sizeof(UDataInfo), + 0, + + U_IS_BIG_ENDIAN, + U_CHARSET_FAMILY, + sizeof(UChar), + 0, + + {PNAME_SIG_0, PNAME_SIG_1, PNAME_SIG_2, PNAME_SIG_3}, + {PNAME_FORMAT_VERSION, 0, 0, 0}, /* formatVersion */ + {VERSION_0, VERSION_1, VERSION_2, VERSION_3} /* Unicode version */ +}; + +class genpname { + + // command-line options + UBool useCopyright; + UBool verbose; + int32_t debug; + +public: + int MMain(int argc, char *argv[]); + +private: + NameToEnumEntry* createNameIndex(const AliasList& list, + int32_t& nameIndexCount); + + EnumToNameGroupEntry* createEnumIndex(const AliasList& list); + + int32_t writeDataFile(const char *destdir, const Builder&); +}; + +int main(int argc, char *argv[]) { + UErrorCode status = U_ZERO_ERROR; + u_init(&status); + if (U_FAILURE(status) && status != U_FILE_ACCESS_ERROR) { + // Note: u_init() will try to open ICU property data. + // failures here are expected when building ICU from scratch. + // ignore them. + fprintf(stderr, "genpname: can not initialize ICU. Status = %s\n", + u_errorName(status)); + exit(1); + } + + genpname app; + U_MAIN_INIT_ARGS(argc, argv); + int retVal = app.MMain(argc, argv); + u_cleanup(); + return retVal; +} + +static UOption options[]={ + UOPTION_HELP_H, + UOPTION_HELP_QUESTION_MARK, + UOPTION_COPYRIGHT, + UOPTION_DESTDIR, + UOPTION_VERBOSE, + UOPTION_DEF("debug", 'D', UOPT_REQUIRES_ARG), +}; + +NameToEnumEntry* genpname::createNameIndex(const AliasList& list, + int32_t& nameIndexCount) { + + // Build name => enum map + + // This is an n->1 map. There are typically multiple names + // mapping to one enum. The name index is sorted in order of the name, + // as defined by the uprv_compareAliasNames() function. + + int32_t i, j; + int32_t count = list.count(); + + // compute upper limit on number of names in the index + int32_t nameIndexCapacity = count * MAX_NAMES_PER_GROUP; + NameToEnumEntry* nameIndex = MALLOC(NameToEnumEntry, nameIndexCapacity); + + nameIndexCount = 0; + int32_t names[MAX_NAMES_PER_GROUP]; + for (i=0; i<count; ++i) { + const Alias& p = list[i]; + int32_t n = p.getUniqueNames(names); + for (j=0; j<n; ++j) { + U_ASSERT(nameIndexCount < nameIndexCapacity); + nameIndex[nameIndexCount++] = + NameToEnumEntry(names[j], p.enumValue); + } + } + + /* + * use a stable sort to ensure consistent results between + * genpname.cpp and the propname.cpp swapping code + */ + UErrorCode errorCode = U_ZERO_ERROR; + uprv_sortArray(nameIndex, nameIndexCount, sizeof(nameIndex[0]), + compareNameToEnumEntry, NULL, TRUE, &errorCode); + if (debug>1) { + printf("Alias names: %d\n", (int)nameIndexCount); + for (i=0; i<nameIndexCount; ++i) { + printf("%s => %d\n", + STRING_TABLE[nameIndex[i].nameIndex].str, + (int)nameIndex[i].enumValue); + } + printf("\n"); + } + // make sure there are no duplicates. for a sorted list we need + // only compare adjacent items. Alias.getUniqueNames() has + // already eliminated duplicate names for a single property, which + // does occur, so we're checking for duplicate names between two + // properties, which should never occur. + UBool ok = TRUE; + for (i=1; i<nameIndexCount; ++i) { + if (STRING_TABLE[nameIndex[i-1].nameIndex] == + STRING_TABLE[nameIndex[i].nameIndex]) { + printf("Error: Duplicate names in property list: \"%s\", \"%s\"\n", + STRING_TABLE[nameIndex[i-1].nameIndex].str, + STRING_TABLE[nameIndex[i].nameIndex].str); + ok = FALSE; + } + } + if (!ok) { + die("Two or more duplicate names in property list"); + } + + return nameIndex; +} + +EnumToNameGroupEntry* genpname::createEnumIndex(const AliasList& list) { + + // Build the enum => name map + + // This is a 1->n map. Each enum maps to 1 or more names. To + // accomplish this the index entry points to an element of the + // NAME_GROUP array. This is the short name (which may be empty). + // From there, subsequent elements of NAME_GROUP are alternate + // names for this enum, up to and including the first one that is + // negative (negate for actual index). + + int32_t i, j, k; + int32_t count = list.count(); + + EnumToNameGroupEntry* enumIndex = MALLOC(EnumToNameGroupEntry, count); + for (i=0; i<count; ++i) { + const Alias& p = list[i]; + enumIndex[i] = EnumToNameGroupEntry(p.enumValue, p.nameGroupIndex); + } + + UErrorCode errorCode = U_ZERO_ERROR; + uprv_sortArray(enumIndex, count, sizeof(enumIndex[0]), + compareEnumToNameGroupEntry, NULL, FALSE, &errorCode); + if (debug>1) { + printf("Property enums: %d\n", (int)count); + for (i=0; i<count; ++i) { + printf("%d => %d: ", + (int)enumIndex[i].enumValue, + (int)enumIndex[i].nameGroupIndex); + UBool done = FALSE; + for (j=enumIndex[i].nameGroupIndex; !done; ++j) { + k = NAME_GROUP[j]; + if (k < 0) { + k = -k; + done = TRUE; + } + printf("\"%s\"", STRING_TABLE[k].str); + if (!done) printf(", "); + } + printf("\n"); + } + printf("\n"); + } + return enumIndex; +} + +int genpname::MMain(int argc, char* argv[]) +{ + int32_t i, j; + UErrorCode status = U_ZERO_ERROR; + + u_init(&status); + if (U_FAILURE(status) && status != U_FILE_ACCESS_ERROR) { + fprintf(stderr, "Error: u_init returned %s\n", u_errorName(status)); + status = U_ZERO_ERROR; + } + + + /* preset then read command line options */ + options[3].value=u_getDataDirectory(); + argc=u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options); + + /* error handling, printing usage message */ + if (argc<0) { + fprintf(stderr, + "error in command line argument \"%s\"\n", + argv[-argc]); + } + + debug = options[5].doesOccur ? (*options[5].value - '0') : 0; + + if (argc!=1 || options[0].doesOccur || options[1].doesOccur || + debug < 0 || debug > 9) { + fprintf(stderr, + "usage: %s [-options]\n" + "\tcreate " PNAME_DATA_NAME "." PNAME_DATA_TYPE "\n" + "options:\n" + "\t-h or -? or --help this usage text\n" + "\t-v or --verbose turn on verbose output\n" + "\t-c or --copyright include a copyright notice\n" + "\t-d or --destdir destination directory, followed by the path\n" + "\t-D or --debug 0..9 emit debugging messages (if > 0)\n", + argv[0]); + return argc<0 ? U_ILLEGAL_ARGUMENT_ERROR : U_ZERO_ERROR; + } + + /* get the options values */ + useCopyright=options[2].doesOccur; + verbose = options[4].doesOccur; + + // ------------------------------------------------------------ + // Do not sort the string table, instead keep it in data.h order. + // This simplifies data swapping and testing thereof because the string + // table itself need not be sorted during swapping. + // The NameToEnum sorter sorts each such map's string offsets instead. + + if (debug>1) { + printf("String pool: %d\n", (int)STRING_COUNT); + for (i=0; i<STRING_COUNT; ++i) { + if (i != 0) { + printf(", "); + } + printf("%s (%d)", STRING_TABLE[i].str, (int)STRING_TABLE[i].index); + } + printf("\n\n"); + } + + // ------------------------------------------------------------ + // Create top-level property indices + + PropertyArrayList props(PROPERTY, PROPERTY_COUNT); + int32_t propNameCount; + NameToEnumEntry* propName = createNameIndex(props, propNameCount); + EnumToNameGroupEntry* propEnum = createEnumIndex(props); + + // ------------------------------------------------------------ + // Create indices for the value list for each enumerated property + + // This will have more entries than we need... + EnumToValueEntry* enumToValue = MALLOC(EnumToValueEntry, PROPERTY_COUNT); + int32_t enumToValue_count = 0; + for (i=0, j=0; i<PROPERTY_COUNT; ++i) { + if (PROPERTY[i].valueCount == 0) continue; + AliasArrayList values(PROPERTY[i].valueList, + PROPERTY[i].valueCount); + enumToValue[j].enumValue = PROPERTY[i].enumValue; + enumToValue[j].enumToName = createEnumIndex(values); + enumToValue[j].enumToName_count = PROPERTY[i].valueCount; + enumToValue[j].nameToEnum = createNameIndex(values, + enumToValue[j].nameToEnum_count); + ++j; + } + enumToValue_count = j; + + uprv_sortArray(enumToValue, enumToValue_count, sizeof(enumToValue[0]), + compareEnumToValueEntry, NULL, FALSE, &status); + + // ------------------------------------------------------------ + // Build PropertyAliases layout in memory + + Builder builder(debug); + + builder.buildTopLevelProperties(propName, + propNameCount, + propEnum, + PROPERTY_COUNT); + + builder.buildValues(enumToValue, + enumToValue_count); + + builder.buildStringPool(STRING_TABLE, + STRING_COUNT, + NAME_GROUP, + NAME_GROUP_COUNT); + + builder.fixup(); + + //////////////////////////////////////////////////////////// + // Write the output file + //////////////////////////////////////////////////////////// + int32_t wlen = writeDataFile(options[3].value, builder); + if (verbose) { + fprintf(stdout, "Output file: %s.%s, %ld bytes\n", + U_ICUDATA_NAME "_" PNAME_DATA_NAME, PNAME_DATA_TYPE, (long)wlen); + } + + return 0; // success +} + +int32_t genpname::writeDataFile(const char *destdir, const Builder& builder) { + int32_t length; + int8_t* data = builder.createData(length); + + UNewDataMemory *pdata; + UErrorCode status = U_ZERO_ERROR; + + pdata = udata_create(destdir, PNAME_DATA_TYPE, PNAME_DATA_NAME, &dataInfo, + useCopyright ? U_COPYRIGHT_STRING : 0, &status); + if (U_FAILURE(status)) { + die("Unable to create data memory"); + } + + udata_writeBlock(pdata, data, length); + + int32_t dataLength = (int32_t) udata_finish(pdata, &status); + if (U_FAILURE(status)) { + die("Error writing output file"); + } + if (dataLength != length) { + die("Written file doesn't match expected size"); + } + + return dataLength; +} + +//eof |