Home | History | Annotate | Download | only in genbidi
      1 /*
      2 *******************************************************************************
      3 *
      4 *   Copyright (C) 2004-2008, International Business Machines
      5 *   Corporation and others.  All Rights Reserved.
      6 *
      7 *******************************************************************************
      8 *   file name:  genbidi.c
      9 *   encoding:   US-ASCII
     10 *   tab size:   8 (not used)
     11 *   indentation:4
     12 *
     13 *   created on: 2004dec30
     14 *   created by: Markus W. Scherer
     15 *
     16 *   This program reads several of the Unicode character database text files,
     17 *   parses them, and extracts the bidi/shaping properties for each character.
     18 *   It then writes a binary file containing the properties
     19 *   that is designed to be used directly for random-access to
     20 *   the properties of each Unicode character.
     21 */
     22 
     23 #include <stdio.h>
     24 #include "unicode/utypes.h"
     25 #include "unicode/uchar.h"
     26 #include "unicode/putil.h"
     27 #include "unicode/uclean.h"
     28 #include "cmemory.h"
     29 #include "cstring.h"
     30 #include "uarrsort.h"
     31 #include "unewdata.h"
     32 #include "uoptions.h"
     33 #include "uparse.h"
     34 #include "propsvec.h"
     35 #include "ubidi_props.h"
     36 #include "genbidi.h"
     37 
     38 #define LENGTHOF(array) (sizeof(array)/sizeof((array)[0]))
     39 
     40 /* data --------------------------------------------------------------------- */
     41 
     42 UPropsVectors *pv;
     43 
     44 UBool beVerbose=FALSE, haveCopyright=TRUE;
     45 
     46 /* prototypes --------------------------------------------------------------- */
     47 
     48 static UBool
     49 isToken(const char *token, const char *s);
     50 
     51 static void
     52 parseBidiMirroring(const char *filename, UErrorCode *pErrorCode);
     53 
     54 static void
     55 parseDB(const char *filename, UErrorCode *pErrorCode);
     56 
     57 /* miscellaneous ------------------------------------------------------------ */
     58 
     59 /* TODO: more common code, move functions to uparse.h|c */
     60 
     61 static char *
     62 trimTerminateField(char *s, char *limit) {
     63     /* trim leading whitespace */
     64     s=(char *)u_skipWhitespace(s);
     65 
     66     /* trim trailing whitespace */
     67     while(s<limit && (*(limit-1)==' ' || *(limit-1)=='\t')) {
     68         --limit;
     69     }
     70     *limit=0;
     71 
     72     return s;
     73 }
     74 
     75 static void
     76 parseTwoFieldFile(char *filename, char *basename,
     77                   const char *ucdFile, const char *suffix,
     78                   UParseLineFn *lineFn,
     79                   UErrorCode *pErrorCode) {
     80     char *fields[2][2];
     81 
     82     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
     83         return;
     84     }
     85 
     86     writeUCDFilename(basename, ucdFile, suffix);
     87 
     88     u_parseDelimitedFile(filename, ';', fields, 2, lineFn, NULL, pErrorCode);
     89     if(U_FAILURE(*pErrorCode)) {
     90         fprintf(stderr, "error parsing %s.txt: %s\n", ucdFile, u_errorName(*pErrorCode));
     91     }
     92 }
     93 
     94 static void U_CALLCONV
     95 bidiClassLineFn(void *context,
     96                 char *fields[][2], int32_t fieldCount,
     97                 UErrorCode *pErrorCode);
     98 
     99 /* parse files with single enumerated properties ---------------------------- */
    100 
    101 /* TODO: more common code, move functions to uparse.h|c */
    102 
    103 struct SingleEnum {
    104     const char *ucdFile, *propName;
    105     UProperty prop;
    106     int32_t vecWord, vecShift;
    107     uint32_t vecMask;
    108 };
    109 typedef struct SingleEnum SingleEnum;
    110 
    111 static void
    112 parseSingleEnumFile(char *filename, char *basename, const char *suffix,
    113                     const SingleEnum *sen,
    114                     UErrorCode *pErrorCode);
    115 
    116 static const SingleEnum jtSingleEnum={
    117     "DerivedJoiningType", "joining type",
    118     UCHAR_JOINING_TYPE,
    119     0, UBIDI_JT_SHIFT, UBIDI_JT_MASK
    120 };
    121 
    122 static const SingleEnum jgSingleEnum={
    123     "DerivedJoiningGroup", "joining group",
    124     UCHAR_JOINING_GROUP,
    125     1, 0, 0xff                  /* column 1 bits 7..0 */
    126 };
    127 
    128 static void U_CALLCONV
    129 singleEnumLineFn(void *context,
    130                  char *fields[][2], int32_t fieldCount,
    131                  UErrorCode *pErrorCode) {
    132     const SingleEnum *sen;
    133     char *s;
    134     uint32_t start, end, uv;
    135     int32_t value;
    136 
    137     sen=(const SingleEnum *)context;
    138 
    139     u_parseCodePointRange(fields[0][0], &start, &end, pErrorCode);
    140     if(U_FAILURE(*pErrorCode)) {
    141         fprintf(stderr, "genbidi: syntax error in %s.txt field 0 at %s\n", sen->ucdFile, fields[0][0]);
    142         exit(*pErrorCode);
    143     }
    144 
    145     /* parse property alias */
    146     s=trimTerminateField(fields[1][0], fields[1][1]);
    147     value=u_getPropertyValueEnum(sen->prop, s);
    148     if(value<0) {
    149         if(sen->prop==UCHAR_BLOCK) {
    150             if(isToken("Greek", s)) {
    151                 value=UBLOCK_GREEK; /* Unicode 3.2 renames this to "Greek and Coptic" */
    152             } else if(isToken("Combining Marks for Symbols", s)) {
    153                 value=UBLOCK_COMBINING_MARKS_FOR_SYMBOLS; /* Unicode 3.2 renames this to "Combining Diacritical Marks for Symbols" */
    154             } else if(isToken("Private Use", s)) {
    155                 value=UBLOCK_PRIVATE_USE; /* Unicode 3.2 renames this to "Private Use Area" */
    156             }
    157         }
    158     }
    159     if(value<0) {
    160         fprintf(stderr, "genbidi error: unknown %s name in %s.txt field 1 at %s\n",
    161                         sen->propName, sen->ucdFile, s);
    162         exit(U_PARSE_ERROR);
    163     }
    164 
    165     uv=(uint32_t)(value<<sen->vecShift);
    166     if((uv&sen->vecMask)!=uv) {
    167         fprintf(stderr, "genbidi error: %s value overflow (0x%x) at %s\n",
    168                         sen->propName, (int)uv, s);
    169         exit(U_INTERNAL_PROGRAM_ERROR);
    170     }
    171 
    172     upvec_setValue(pv, start, end, sen->vecWord, uv, sen->vecMask, pErrorCode);
    173     if(U_FAILURE(*pErrorCode)) {
    174         fprintf(stderr, "genbidi error: unable to set %s code: %s\n",
    175                         sen->propName, u_errorName(*pErrorCode));
    176         exit(*pErrorCode);
    177     }
    178 }
    179 
    180 static void
    181 parseSingleEnumFile(char *filename, char *basename, const char *suffix,
    182                     const SingleEnum *sen,
    183                     UErrorCode *pErrorCode) {
    184     char *fields[2][2];
    185 
    186     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    187         return;
    188     }
    189 
    190     writeUCDFilename(basename, sen->ucdFile, suffix);
    191 
    192     u_parseDelimitedFile(filename, ';', fields, 2, singleEnumLineFn, (void *)sen, pErrorCode);
    193     if(U_FAILURE(*pErrorCode)) {
    194         fprintf(stderr, "error parsing %s.txt: %s\n", sen->ucdFile, u_errorName(*pErrorCode));
    195     }
    196 }
    197 
    198 /* parse files with multiple binary properties ------------------------------ */
    199 
    200 /* TODO: more common code, move functions to uparse.h|c */
    201 
    202 /* TODO: similar to genbidi/props2.c but not the same; same as in gencase/gencase.c */
    203 
    204 struct Binary {
    205     const char *propName;
    206     int32_t vecWord;
    207     uint32_t vecValue, vecMask;
    208 };
    209 typedef struct Binary Binary;
    210 
    211 struct Binaries {
    212     const char *ucdFile;
    213     const Binary *binaries;
    214     int32_t binariesCount;
    215 };
    216 typedef struct Binaries Binaries;
    217 
    218 static const Binary
    219 propListNames[]={
    220     { "Bidi_Control",                       0, U_MASK(UBIDI_BIDI_CONTROL_SHIFT), U_MASK(UBIDI_BIDI_CONTROL_SHIFT) },
    221     { "Join_Control",                       0, U_MASK(UBIDI_JOIN_CONTROL_SHIFT), U_MASK(UBIDI_JOIN_CONTROL_SHIFT) }
    222 };
    223 
    224 static const Binaries
    225 propListBinaries={
    226     "PropList", propListNames, LENGTHOF(propListNames)
    227 };
    228 
    229 static void U_CALLCONV
    230 binariesLineFn(void *context,
    231                char *fields[][2], int32_t fieldCount,
    232                UErrorCode *pErrorCode) {
    233     const Binaries *bin;
    234     char *s;
    235     uint32_t start, end;
    236     int32_t i;
    237 
    238     bin=(const Binaries *)context;
    239 
    240     u_parseCodePointRange(fields[0][0], &start, &end, pErrorCode);
    241     if(U_FAILURE(*pErrorCode)) {
    242         fprintf(stderr, "genbidi: syntax error in %s.txt field 0 at %s\n", bin->ucdFile, fields[0][0]);
    243         exit(*pErrorCode);
    244     }
    245 
    246     /* parse binary property name */
    247     s=(char *)u_skipWhitespace(fields[1][0]);
    248     for(i=0;; ++i) {
    249         if(i==bin->binariesCount) {
    250             /* ignore unrecognized properties */
    251             return;
    252         }
    253         if(isToken(bin->binaries[i].propName, s)) {
    254             break;
    255         }
    256     }
    257 
    258     if(bin->binaries[i].vecMask==0) {
    259         fprintf(stderr, "genbidi error: mask value %d==0 for %s %s\n",
    260                         (int)bin->binaries[i].vecMask, bin->ucdFile, bin->binaries[i].propName);
    261         exit(U_INTERNAL_PROGRAM_ERROR);
    262     }
    263 
    264     upvec_setValue(pv, start, end, bin->binaries[i].vecWord, bin->binaries[i].vecValue, bin->binaries[i].vecMask, pErrorCode);
    265     if(U_FAILURE(*pErrorCode)) {
    266         fprintf(stderr, "genbidi error: unable to set %s, code: %s\n",
    267                         bin->binaries[i].propName, u_errorName(*pErrorCode));
    268         exit(*pErrorCode);
    269     }
    270 }
    271 
    272 static void
    273 parseBinariesFile(char *filename, char *basename, const char *suffix,
    274                   const Binaries *bin,
    275                   UErrorCode *pErrorCode) {
    276     char *fields[2][2];
    277 
    278     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    279         return;
    280     }
    281 
    282     writeUCDFilename(basename, bin->ucdFile, suffix);
    283 
    284     u_parseDelimitedFile(filename, ';', fields, 2, binariesLineFn, (void *)bin, pErrorCode);
    285     if(U_FAILURE(*pErrorCode)) {
    286         fprintf(stderr, "error parsing %s.txt: %s\n", bin->ucdFile, u_errorName(*pErrorCode));
    287     }
    288 }
    289 
    290 /* -------------------------------------------------------------------------- */
    291 
    292 enum {
    293     HELP_H,
    294     HELP_QUESTION_MARK,
    295     VERBOSE,
    296     COPYRIGHT,
    297     DESTDIR,
    298     SOURCEDIR,
    299     UNICODE_VERSION,
    300     ICUDATADIR,
    301     CSOURCE
    302 };
    303 
    304 /* Keep these values in sync with the above enums */
    305 static UOption options[]={
    306     UOPTION_HELP_H,
    307     UOPTION_HELP_QUESTION_MARK,
    308     UOPTION_VERBOSE,
    309     UOPTION_COPYRIGHT,
    310     UOPTION_DESTDIR,
    311     UOPTION_SOURCEDIR,
    312     UOPTION_DEF("unicode", 'u', UOPT_REQUIRES_ARG),
    313     UOPTION_ICUDATADIR,
    314     UOPTION_DEF("csource", 'C', UOPT_NO_ARG)
    315 };
    316 
    317 extern int
    318 main(int argc, char* argv[]) {
    319     char filename[300];
    320     const char *srcDir=NULL, *destDir=NULL, *suffix=NULL;
    321     char *basename=NULL;
    322     UErrorCode errorCode=U_ZERO_ERROR;
    323 
    324     U_MAIN_INIT_ARGS(argc, argv);
    325 
    326     /* preset then read command line options */
    327     options[DESTDIR].value=u_getDataDirectory();
    328     options[SOURCEDIR].value="";
    329     options[UNICODE_VERSION].value="";
    330     options[ICUDATADIR].value=u_getDataDirectory();
    331     argc=u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options);
    332 
    333     /* error handling, printing usage message */
    334     if(argc<0) {
    335         fprintf(stderr,
    336             "error in command line argument \"%s\"\n",
    337             argv[-argc]);
    338     }
    339     if(argc<0 || options[HELP_H].doesOccur || options[HELP_QUESTION_MARK].doesOccur) {
    340         /*
    341          * Broken into chucks because the C89 standard says the minimum
    342          * required supported string length is 509 bytes.
    343          */
    344         fprintf(stderr,
    345             "Usage: %s [-options] [suffix]\n"
    346             "\n"
    347             "read the UnicodeData.txt file and other Unicode properties files and\n"
    348             "create a binary file " UBIDI_DATA_NAME "." UBIDI_DATA_TYPE " with the bidi/shaping properties\n"
    349             "\n",
    350             argv[0]);
    351         fprintf(stderr,
    352             "Options:\n"
    353             "\t-h or -? or --help  this usage text\n"
    354             "\t-v or --verbose     verbose output\n"
    355             "\t-c or --copyright   include a copyright notice\n"
    356             "\t-u or --unicode     Unicode version, followed by the version like 3.0.0\n"
    357             "\t-C or --csource     generate a .c source file rather than the .icu binary\n");
    358         fprintf(stderr,
    359             "\t-d or --destdir     destination directory, followed by the path\n"
    360             "\t-s or --sourcedir   source directory, followed by the path\n"
    361             "\t-i or --icudatadir  directory for locating any needed intermediate data files,\n"
    362             "\t                    followed by path, defaults to %s\n"
    363             "\tsuffix              suffix that is to be appended with a '-'\n"
    364             "\t                    to the source file basenames before opening;\n"
    365             "\t                    'genbidi new' will read UnicodeData-new.txt etc.\n",
    366             u_getDataDirectory());
    367         return argc<0 ? U_ILLEGAL_ARGUMENT_ERROR : U_ZERO_ERROR;
    368     }
    369 
    370     /* get the options values */
    371     beVerbose=options[VERBOSE].doesOccur;
    372     haveCopyright=options[COPYRIGHT].doesOccur;
    373     srcDir=options[SOURCEDIR].value;
    374     destDir=options[DESTDIR].value;
    375 
    376     if(argc>=2) {
    377         suffix=argv[1];
    378     } else {
    379         suffix=NULL;
    380     }
    381 
    382     if(options[UNICODE_VERSION].doesOccur) {
    383         setUnicodeVersion(options[UNICODE_VERSION].value);
    384     }
    385     /* else use the default dataVersion in store.c */
    386 
    387     if (options[ICUDATADIR].doesOccur) {
    388         u_setDataDirectory(options[ICUDATADIR].value);
    389     }
    390 
    391     /* prepare the filename beginning with the source dir */
    392     uprv_strcpy(filename, srcDir);
    393     basename=filename+uprv_strlen(filename);
    394     if(basename>filename && *(basename-1)!=U_FILE_SEP_CHAR) {
    395         *basename++=U_FILE_SEP_CHAR;
    396     }
    397 
    398     /* initialize */
    399     pv=upvec_open(2, &errorCode);
    400 
    401     /* process BidiMirroring.txt */
    402     writeUCDFilename(basename, "BidiMirroring", suffix);
    403     parseBidiMirroring(filename, &errorCode);
    404 
    405     /* process additional properties files */
    406     *basename=0;
    407 
    408     parseBinariesFile(filename, basename, suffix, &propListBinaries, &errorCode);
    409 
    410     parseSingleEnumFile(filename, basename, suffix, &jtSingleEnum, &errorCode);
    411 
    412     parseSingleEnumFile(filename, basename, suffix, &jgSingleEnum, &errorCode);
    413 
    414     /* process UnicodeData.txt */
    415     writeUCDFilename(basename, "UnicodeData", suffix);
    416     parseDB(filename, &errorCode);
    417 
    418     /* set proper bidi class for unassigned code points (Cn) */
    419     parseTwoFieldFile(filename, basename, "DerivedBidiClass", suffix, bidiClassLineFn, &errorCode);
    420 
    421     /* process parsed data */
    422     if(U_SUCCESS(errorCode)) {
    423         /* write the properties data file */
    424         generateData(destDir, options[CSOURCE].doesOccur);
    425     }
    426 
    427     u_cleanup();
    428     return errorCode;
    429 }
    430 
    431 U_CFUNC void
    432 writeUCDFilename(char *basename, const char *filename, const char *suffix) {
    433     int32_t length=(int32_t)uprv_strlen(filename);
    434     uprv_strcpy(basename, filename);
    435     if(suffix!=NULL) {
    436         basename[length++]='-';
    437         uprv_strcpy(basename+length, suffix);
    438         length+=(int32_t)uprv_strlen(suffix);
    439     }
    440     uprv_strcpy(basename+length, ".txt");
    441 }
    442 
    443 /* TODO: move to toolutil */
    444 static UBool
    445 isToken(const char *token, const char *s) {
    446     const char *z;
    447     int32_t j;
    448 
    449     s=u_skipWhitespace(s);
    450     for(j=0;; ++j) {
    451         if(token[j]!=0) {
    452             if(s[j]!=token[j]) {
    453                 break;
    454             }
    455         } else {
    456             z=u_skipWhitespace(s+j);
    457             if(*z==';' || *z==0) {
    458                 return TRUE;
    459             } else {
    460                 break;
    461             }
    462         }
    463     }
    464 
    465     return FALSE;
    466 }
    467 
    468 /* parser for BidiMirroring.txt --------------------------------------------- */
    469 
    470 static void U_CALLCONV
    471 mirrorLineFn(void *context,
    472              char *fields[][2], int32_t fieldCount,
    473              UErrorCode *pErrorCode) {
    474     char *end;
    475     UChar32 src, mirror;
    476 
    477     src=(UChar32)uprv_strtoul(fields[0][0], &end, 16);
    478     if(end<=fields[0][0] || end!=fields[0][1]) {
    479         fprintf(stderr, "genbidi: syntax error in BidiMirroring.txt field 0 at %s\n", fields[0][0]);
    480         *pErrorCode=U_PARSE_ERROR;
    481         exit(U_PARSE_ERROR);
    482     }
    483 
    484     mirror=(UChar32)uprv_strtoul(fields[1][0], &end, 16);
    485     if(end<=fields[1][0] || end!=fields[1][1]) {
    486         fprintf(stderr, "genbidi: syntax error in BidiMirroring.txt field 1 at %s\n", fields[1][0]);
    487         *pErrorCode=U_PARSE_ERROR;
    488         exit(U_PARSE_ERROR);
    489     }
    490 
    491     addMirror(src, mirror);
    492 }
    493 
    494 static void
    495 parseBidiMirroring(const char *filename, UErrorCode *pErrorCode) {
    496     char *fields[2][2];
    497 
    498     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    499         return;
    500     }
    501 
    502     u_parseDelimitedFile(filename, ';', fields, 2, mirrorLineFn, NULL, pErrorCode);
    503 }
    504 
    505 /* parser for UnicodeData.txt ----------------------------------------------- */
    506 
    507 static void U_CALLCONV
    508 unicodeDataLineFn(void *context,
    509                   char *fields[][2], int32_t fieldCount,
    510                   UErrorCode *pErrorCode) {
    511     char *end;
    512     UErrorCode errorCode;
    513     UChar32 c;
    514 
    515     errorCode=U_ZERO_ERROR;
    516 
    517     /* get the character code, field 0 */
    518     c=(UChar32)uprv_strtoul(fields[0][0], &end, 16);
    519     if(end<=fields[0][0] || end!=fields[0][1]) {
    520         fprintf(stderr, "genbidi: syntax error in field 0 at %s\n", fields[0][0]);
    521         *pErrorCode=U_PARSE_ERROR;
    522         exit(U_PARSE_ERROR);
    523     }
    524 
    525     /* get Mirrored flag, field 9 */
    526     if(*fields[9][0]=='Y') {
    527         upvec_setValue(pv, c, c, 0, U_MASK(UBIDI_IS_MIRRORED_SHIFT), U_MASK(UBIDI_IS_MIRRORED_SHIFT), &errorCode);
    528         if(U_FAILURE(*pErrorCode)) {
    529             fprintf(stderr, "genbidi error: unable to set 'is mirrored' for U+%04lx, code: %s\n",
    530                             (long)c, u_errorName(errorCode));
    531             exit(errorCode);
    532         }
    533     } else if(fields[9][1]-fields[9][0]!=1 || *fields[9][0]!='N') {
    534         fprintf(stderr, "genbidi: syntax error in field 9 at U+%04lx\n",
    535             (long)c);
    536         *pErrorCode=U_PARSE_ERROR;
    537         exit(U_PARSE_ERROR);
    538     }
    539 }
    540 
    541 static void
    542 parseDB(const char *filename, UErrorCode *pErrorCode) {
    543     /* default Bidi classes for unassigned code points */
    544     static const UChar32 defaultBidi[][3]={ /* { start, end, class } */
    545         /* R: U+0590..U+05FF, U+07C0..U+08FF, U+FB1D..U+FB4F, U+10800..U+10FFF */
    546         { 0x0590, 0x05FF, U_RIGHT_TO_LEFT },
    547         { 0x07C0, 0x08FF, U_RIGHT_TO_LEFT },
    548         { 0xFB1D, 0xFB4F, U_RIGHT_TO_LEFT },
    549         { 0x10800, 0x10FFF, U_RIGHT_TO_LEFT },
    550 
    551         /* AL: U+0600..U+07BF, U+FB50..U+FDCF, U+FDF0..U+FDFF, U+FE70..U+FEFE */
    552         { 0x0600, 0x07BF, U_RIGHT_TO_LEFT_ARABIC },
    553         { 0xFB50, 0xFDCF, U_RIGHT_TO_LEFT_ARABIC },
    554         { 0xFDF0, 0xFDFF, U_RIGHT_TO_LEFT_ARABIC },
    555         { 0xFE70, 0xFEFE, U_RIGHT_TO_LEFT_ARABIC }
    556 
    557         /* L otherwise */
    558     };
    559 
    560     char *fields[15][2];
    561     UChar32 start, end;
    562     int32_t i;
    563 
    564     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    565         return;
    566     }
    567 
    568     /*
    569      * Set default Bidi classes for unassigned code points.
    570      * See the documentation for Bidi_Class in UCD.html in the Unicode data.
    571      * http://www.unicode.org/Public/
    572      *
    573      * Starting with Unicode 5.0, DerivedBidiClass.txt should (re)set
    574      * the Bidi_Class values for all code points including unassigned ones
    575      * and including L values for these.
    576      * This code becomes unnecesary but harmless. Leave it for now in case
    577      * someone uses genbidi on pre-Unicode 5.0 data.
    578      */
    579     for(i=0; i<LENGTHOF(defaultBidi); ++i) {
    580         start=defaultBidi[i][0];
    581         end=defaultBidi[i][1];
    582         upvec_setValue(pv, start, end, 0, (uint32_t)defaultBidi[i][2], UBIDI_CLASS_MASK, pErrorCode);
    583         if(U_FAILURE(*pErrorCode)) {
    584             fprintf(stderr, "genbidi error: unable to set default bidi class for U+%04lx..U+%04lx, code: %s\n",
    585                             (long)start, (long)end, u_errorName(*pErrorCode));
    586             exit(*pErrorCode);
    587         }
    588     }
    589 
    590     u_parseDelimitedFile(filename, ';', fields, 15, unicodeDataLineFn, NULL, pErrorCode);
    591 
    592     if(U_FAILURE(*pErrorCode)) {
    593         return;
    594     }
    595 }
    596 
    597 /* DerivedBidiClass.txt ----------------------------------------------------- */
    598 
    599 static void U_CALLCONV
    600 bidiClassLineFn(void *context,
    601                 char *fields[][2], int32_t fieldCount,
    602                 UErrorCode *pErrorCode) {
    603     char *s;
    604     uint32_t start, end, value;
    605 
    606     /* get the code point range */
    607     u_parseCodePointRange(fields[0][0], &start, &end, pErrorCode);
    608     if(U_FAILURE(*pErrorCode)) {
    609         fprintf(stderr, "genbidi: syntax error in DerivedBidiClass.txt field 0 at %s\n", fields[0][0]);
    610         exit(*pErrorCode);
    611     }
    612 
    613     /* parse bidi class */
    614     s=trimTerminateField(fields[1][0], fields[1][1]);
    615     value=u_getPropertyValueEnum(UCHAR_BIDI_CLASS, s);
    616     if((int32_t)value<0) {
    617         fprintf(stderr, "genbidi error: unknown bidi class in DerivedBidiClass.txt field 1 at %s\n", s);
    618         exit(U_PARSE_ERROR);
    619     }
    620 
    621     upvec_setValue(pv, start, end, 0, value, UBIDI_CLASS_MASK, pErrorCode);
    622     if(U_FAILURE(*pErrorCode)) {
    623         fprintf(stderr, "genbidi error: unable to set derived bidi class for U+%04x..U+%04x - %s\n",
    624                 (int)start, (int)end, u_errorName(*pErrorCode));
    625         exit(*pErrorCode);
    626     }
    627 }
    628 
    629 /*
    630  * Hey, Emacs, please set the following:
    631  *
    632  * Local Variables:
    633  * indent-tabs-mode: nil
    634  * End:
    635  *
    636  */
    637