c3f1ade5713d0cb8dfd36ea4ac314e51b948bab8
[platform/framework/web/crosswalk.git] / src / third_party / icu / source / tools / gensprep / gensprep.c
1 /*
2 *******************************************************************************
3 *
4 *   Copyright (C) 2003-2009, International Business Machines
5 *   Corporation and others.  All Rights Reserved.
6 *
7 *******************************************************************************
8 *   file name:  gensprep.c
9 *   encoding:   US-ASCII
10 *   tab size:   8 (not used)
11 *   indentation:4
12 *
13 *   created on: 2003-02-06
14 *   created by: Ram Viswanadha
15 *
16 *   This program reads the Profile.txt files,
17 *   parses them, and extracts the data for StringPrep profile.
18 *   It then preprocesses it and writes a binary file for efficient use
19 *   in various StringPrep conversion processes.
20 */
21
22 #define USPREP_TYPE_NAMES_ARRAY 1
23
24 #include <stdio.h>
25 #include <stdlib.h>
26
27 #include "cmemory.h"
28 #include "cstring.h"
29 #include "unewdata.h"
30 #include "uoptions.h"
31 #include "uparse.h"
32 #include "sprpimpl.h"
33
34 #include "unicode/udata.h"
35 #include "unicode/utypes.h"
36 #include "unicode/putil.h"
37
38
39 U_CDECL_BEGIN
40 #include "gensprep.h"
41 U_CDECL_END
42
43 UBool beVerbose=FALSE, haveCopyright=TRUE;
44
45 #define NORM_CORRECTIONS_FILE_NAME "NormalizationCorrections.txt"
46
47 #define NORMALIZE_DIRECTIVE "normalize"
48 #define NORMALIZE_DIRECTIVE_LEN 9
49 #define CHECK_BIDI_DIRECTIVE "check-bidi"
50 #define CHECK_BIDI_DIRECTIVE_LEN 10
51
52 /* prototypes --------------------------------------------------------------- */
53
54 static void
55 parseMappings(const char *filename, UBool reportError, UErrorCode *pErrorCode);
56
57 static void
58 parseNormalizationCorrections(const char *filename, UErrorCode *pErrorCode);
59
60
61 /* -------------------------------------------------------------------------- */
62
63 static UOption options[]={
64     UOPTION_HELP_H,
65     UOPTION_HELP_QUESTION_MARK,
66     UOPTION_VERBOSE,
67     UOPTION_COPYRIGHT,
68     UOPTION_DESTDIR,
69     UOPTION_SOURCEDIR,
70     UOPTION_ICUDATADIR,
71     UOPTION_BUNDLE_NAME,
72     { "normalization", NULL, NULL, NULL, 'n', UOPT_REQUIRES_ARG, 0 },
73     { "norm-correction", NULL, NULL, NULL, 'm', UOPT_REQUIRES_ARG, 0 },
74     { "check-bidi", NULL, NULL, NULL,  'k', UOPT_NO_ARG, 0},
75     { "unicode", NULL, NULL, NULL, 'u', UOPT_REQUIRES_ARG, 0 },
76 };
77
78 enum{
79     HELP,
80     HELP_QUESTION_MARK,
81     VERBOSE,
82     COPYRIGHT,
83     DESTDIR,
84     SOURCEDIR,
85     ICUDATADIR,
86     BUNDLE_NAME,
87     NORMALIZE,
88     NORM_CORRECTION_DIR,
89     CHECK_BIDI,
90     UNICODE_VERSION
91 };
92
93 static int printHelp(int argc, char* argv[]){
94     /*
95      * Broken into chucks because the C89 standard says the minimum
96      * required supported string length is 509 bytes.
97      */
98     fprintf(stderr,
99         "Usage: %s [-options] [file_name]\n"
100         "\n"
101         "Read the files specified and\n"
102         "create a binary file [package-name]_[bundle-name]." DATA_TYPE " with the StringPrep profile data\n"
103         "\n",
104         argv[0]);
105     fprintf(stderr,
106         "Options:\n"
107         "\t-h or -? or --help       print this usage text\n"
108         "\t-v or --verbose          verbose output\n"
109         "\t-c or --copyright        include a copyright notice\n");
110     fprintf(stderr,
111         "\t-d or --destdir          destination directory, followed by the path\n"
112         "\t-s or --sourcedir        source directory of ICU data, followed by the path\n"
113         "\t-b or --bundle-name      generate the ouput data file with the name specified\n"
114         "\t-i or --icudatadir       directory for locating any needed intermediate data files,\n"
115         "\t                         followed by path, defaults to %s\n",
116         u_getDataDirectory());
117     fprintf(stderr,
118         "\t-n or --normalize        turn on the option for normalization and include mappings\n"
119         "\t                         from NormalizationCorrections.txt from the given path,\n"
120         "\t                         e.g: /test/icu/source/data/unidata\n");
121     fprintf(stderr,
122         "\t-m or --norm-correction  use NormalizationCorrections.txt from the given path\n"
123         "\t                         when the input file contains a normalization directive.\n"
124         "\t                         unlike -n/--normalize, this option does not force the\n"
125         "\t                         normalization.\n");
126     fprintf(stderr,
127         "\t-k or --check-bidi       turn on the option for checking for BiDi in the profile\n"
128         "\t-u or --unicode          version of Unicode to be used with this profile followed by the version\n"
129         );
130     return argc<0 ? U_ILLEGAL_ARGUMENT_ERROR : U_ZERO_ERROR;
131 }
132
133
134 extern int
135 main(int argc, char* argv[]) {
136 #if !UCONFIG_NO_IDNA
137     char* filename = NULL;
138 #endif
139     const char *srcDir=NULL, *destDir=NULL, *icuUniDataDir=NULL;
140     const char *bundleName=NULL, *inputFileName = NULL;
141     char *basename=NULL;
142     int32_t sprepOptions = 0;
143
144     UErrorCode errorCode=U_ZERO_ERROR;
145
146     U_MAIN_INIT_ARGS(argc, argv);
147
148     /* preset then read command line options */
149     options[DESTDIR].value=u_getDataDirectory();
150     options[SOURCEDIR].value="";
151     options[UNICODE_VERSION].value="0"; /* don't assume the unicode version */
152     options[BUNDLE_NAME].value = DATA_NAME;
153     options[NORMALIZE].value = "";
154
155     argc=u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options);
156
157     /* error handling, printing usage message */
158     if(argc<0) {
159         fprintf(stderr,
160             "error in command line argument \"%s\"\n",
161             argv[-argc]);
162     }
163     if(argc<0 || options[HELP].doesOccur || options[HELP_QUESTION_MARK].doesOccur) {
164         return printHelp(argc, argv);
165         
166     }
167
168     /* get the options values */
169     beVerbose=options[VERBOSE].doesOccur;
170     haveCopyright=options[COPYRIGHT].doesOccur;
171     srcDir=options[SOURCEDIR].value;
172     destDir=options[DESTDIR].value;
173     bundleName = options[BUNDLE_NAME].value;
174     if(options[NORMALIZE].doesOccur) {
175         icuUniDataDir = options[NORMALIZE].value;
176     } else {
177         icuUniDataDir = options[NORM_CORRECTION_DIR].value;
178     }
179
180     if(argc<2) {
181         /* print the help message */
182         return printHelp(argc, argv);
183     } else {
184         inputFileName = argv[1];
185     }
186     if(!options[UNICODE_VERSION].doesOccur){
187         return printHelp(argc, argv);
188     }
189     if(options[ICUDATADIR].doesOccur) {
190         u_setDataDirectory(options[ICUDATADIR].value);
191     }
192 #if UCONFIG_NO_IDNA
193
194     fprintf(stderr,
195         "gensprep writes dummy " U_ICUDATA_NAME "_" DATA_NAME "." DATA_TYPE
196         " because UCONFIG_NO_IDNA is set, \n"
197         "see icu/source/common/unicode/uconfig.h\n");
198     generateData(destDir, bundleName);
199
200 #else
201
202     setUnicodeVersion(options[UNICODE_VERSION].value);
203     filename = (char* ) uprv_malloc(uprv_strlen(srcDir) + 300); /* hopefully this should be enough */
204    
205     /* prepare the filename beginning with the source dir */
206     if(uprv_strchr(srcDir,U_FILE_SEP_CHAR) == NULL && uprv_strchr(srcDir,U_FILE_ALT_SEP_CHAR) == NULL){
207         filename[0] = '.';
208         filename[1] = U_FILE_SEP_CHAR;
209         uprv_strcpy(filename+2,srcDir);
210     }else{
211         uprv_strcpy(filename, srcDir);
212     }
213     
214     basename=filename+uprv_strlen(filename);
215     if(basename>filename && *(basename-1)!=U_FILE_SEP_CHAR) {
216         *basename++=U_FILE_SEP_CHAR;
217     }
218     
219     /* initialize */
220     init();
221
222     /* process the file */
223     uprv_strcpy(basename,inputFileName);
224     parseMappings(filename,FALSE, &errorCode);
225     if(U_FAILURE(errorCode)) {
226         fprintf(stderr, "Could not open file %s for reading. Error: %s \n", filename, u_errorName(errorCode));
227         return errorCode;
228     }
229     
230     if(options[NORMALIZE].doesOccur){ /* this option might be set by @normalize;; in the source file */
231         /* set up directory for NormalizationCorrections.txt */
232         uprv_strcpy(filename,icuUniDataDir);
233         basename=filename+uprv_strlen(filename);
234         if(basename>filename && *(basename-1)!=U_FILE_SEP_CHAR) {
235             *basename++=U_FILE_SEP_CHAR;
236         }
237
238         *basename++=U_FILE_SEP_CHAR;
239         uprv_strcpy(basename,NORM_CORRECTIONS_FILE_NAME);
240     
241         parseNormalizationCorrections(filename,&errorCode);
242         if(U_FAILURE(errorCode)){
243             fprintf(stderr,"Could not open file %s for reading \n", filename);
244             return errorCode;
245         }
246         sprepOptions |= _SPREP_NORMALIZATION_ON;
247     }
248     
249     if(options[CHECK_BIDI].doesOccur){ /* this option might be set by @check-bidi;; in the source file */
250         sprepOptions |= _SPREP_CHECK_BIDI_ON;
251     }
252
253     setOptions(sprepOptions);
254
255     /* process parsed data */
256     if(U_SUCCESS(errorCode)) {
257         /* write the data file */
258         generateData(destDir, bundleName);
259
260         cleanUpData();
261     }
262
263     uprv_free(filename);
264
265 #endif
266
267     return errorCode;
268 }
269
270 #if !UCONFIG_NO_IDNA
271
272 static void U_CALLCONV
273 normalizationCorrectionsLineFn(void *context,
274                     char *fields[][2], int32_t fieldCount,
275                     UErrorCode *pErrorCode) {
276     uint32_t mapping[40];
277     char *end, *s;
278     uint32_t code;
279     int32_t length;
280     UVersionInfo version;
281     UVersionInfo thisVersion;
282
283     /* get the character code, field 0 */
284     code=(uint32_t)uprv_strtoul(fields[0][0], &end, 16);
285     if(U_FAILURE(*pErrorCode)) {
286         fprintf(stderr, "gensprep: error parsing NormalizationCorrections.txt mapping at %s\n", fields[0][0]);
287         exit(*pErrorCode);
288     }
289     /* Original (erroneous) decomposition */
290     s = fields[1][0];
291
292     /* parse the mapping string */
293     length=u_parseCodePoints(s, mapping, sizeof(mapping)/4, pErrorCode);
294
295     /* ignore corrected decomposition */
296
297     u_versionFromString(version,fields[3][0] );
298     u_versionFromString(thisVersion, "3.2.0");
299
300
301
302     if(U_FAILURE(*pErrorCode)) {
303         fprintf(stderr, "gensprep error parsing NormalizationCorrections.txt of U+%04lx - %s\n",
304                 (long)code, u_errorName(*pErrorCode));
305         exit(*pErrorCode);
306     }
307
308     /* store the mapping */
309     if( version[0] > thisVersion[0] || 
310         ((version[0]==thisVersion[0]) && (version[1] > thisVersion[1]))
311         ){
312         storeMapping(code,mapping, length, USPREP_MAP, pErrorCode);
313     }
314     setUnicodeVersionNC(version);
315 }
316
317 static void
318 parseNormalizationCorrections(const char *filename, UErrorCode *pErrorCode) {
319     char *fields[4][2];
320
321     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
322         return;
323     }
324
325     u_parseDelimitedFile(filename, ';', fields, 4, normalizationCorrectionsLineFn, NULL, pErrorCode);
326
327     /* fprintf(stdout,"Number of code points that have NormalizationCorrections mapping with length >1 : %i\n",len); */
328
329     if(U_FAILURE(*pErrorCode) && ( *pErrorCode!=U_FILE_ACCESS_ERROR)) {
330         fprintf(stderr, "gensprep error: u_parseDelimitedFile(\"%s\") failed - %s\n", filename, u_errorName(*pErrorCode));
331         exit(*pErrorCode);
332     }
333 }
334
335 static void U_CALLCONV
336 strprepProfileLineFn(void *context,
337               char *fields[][2], int32_t fieldCount,
338               UErrorCode *pErrorCode) {
339     uint32_t mapping[40];
340     char *end, *map;
341     uint32_t code;
342     int32_t length;
343    /*UBool* mapWithNorm = (UBool*) context;*/
344     const char* typeName;
345     uint32_t rangeStart=0,rangeEnd =0;
346     const char* filename = (const char*) context;
347     const char *s;
348
349     s = u_skipWhitespace(fields[0][0]);
350     if (*s == '@') {
351         /* special directive */
352         s++;
353         length = fields[0][1] - s;
354         if (length >= NORMALIZE_DIRECTIVE_LEN
355             && uprv_strncmp(s, NORMALIZE_DIRECTIVE, NORMALIZE_DIRECTIVE_LEN) == 0) {
356             options[NORMALIZE].doesOccur = TRUE;
357             return;
358         }
359         else if (length >= CHECK_BIDI_DIRECTIVE_LEN
360             && uprv_strncmp(s, CHECK_BIDI_DIRECTIVE, CHECK_BIDI_DIRECTIVE_LEN) == 0) {
361             options[CHECK_BIDI].doesOccur = TRUE;
362             return;
363         }
364         else {
365             fprintf(stderr, "gensprep error parsing a directive %s.", fields[0][0]);
366         }
367     }
368
369     typeName = fields[2][0];
370     map = fields[1][0];
371
372     if(uprv_strstr(typeName, usprepTypeNames[USPREP_UNASSIGNED])!=NULL){
373
374         u_parseCodePointRange(s, &rangeStart,&rangeEnd, pErrorCode);
375         if(U_FAILURE(*pErrorCode)){
376             fprintf(stderr, "Could not parse code point range. Error: %s\n",u_errorName(*pErrorCode));
377             return;
378         }
379
380         /* store the range */
381         storeRange(rangeStart,rangeEnd,USPREP_UNASSIGNED, pErrorCode);
382
383     }else if(uprv_strstr(typeName, usprepTypeNames[USPREP_PROHIBITED])!=NULL){
384
385         u_parseCodePointRange(s, &rangeStart,&rangeEnd, pErrorCode);
386         if(U_FAILURE(*pErrorCode)){
387             fprintf(stderr, "Could not parse code point range. Error: %s\n",u_errorName(*pErrorCode));
388             return;
389         }
390
391         /* store the range */
392         storeRange(rangeStart,rangeEnd,USPREP_PROHIBITED, pErrorCode);
393
394     }else if(uprv_strstr(typeName, usprepTypeNames[USPREP_MAP])!=NULL){
395
396         /* get the character code, field 0 */
397         code=(uint32_t)uprv_strtoul(s, &end, 16);
398         if(end<=s || end!=fields[0][1]) {
399             fprintf(stderr, "gensprep: syntax error in field 0 at %s\n", fields[0][0]);
400             *pErrorCode=U_PARSE_ERROR;
401             exit(U_PARSE_ERROR);
402         }
403
404         /* parse the mapping string */
405         length=u_parseCodePoints(map, mapping, sizeof(mapping)/4, pErrorCode);
406         
407         /* store the mapping */
408         storeMapping(code,mapping, length,USPREP_MAP, pErrorCode);
409
410     }else{
411         *pErrorCode = U_INVALID_FORMAT_ERROR;
412     }
413     
414     if(U_FAILURE(*pErrorCode)) {
415         fprintf(stderr, "gensprep error parsing  %s line %s at %s. Error: %s\n",filename,
416                fields[0][0],fields[2][0],u_errorName(*pErrorCode));
417         exit(*pErrorCode);
418     }
419
420 }
421
422 static void
423 parseMappings(const char *filename, UBool reportError, UErrorCode *pErrorCode) {
424     char *fields[3][2];
425
426     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
427         return;
428     }
429
430     u_parseDelimitedFile(filename, ';', fields, 3, strprepProfileLineFn, (void*)filename, pErrorCode);
431
432     /*fprintf(stdout,"Number of code points that have mappings with length >1 : %i\n",len);*/
433
434     if(U_FAILURE(*pErrorCode) && (reportError || *pErrorCode!=U_FILE_ACCESS_ERROR)) {
435         fprintf(stderr, "gensprep error: u_parseDelimitedFile(\"%s\") failed - %s\n", filename, u_errorName(*pErrorCode));
436         exit(*pErrorCode);
437     }
438 }
439
440
441 #endif /* #if !UCONFIG_NO_IDNA */
442
443 /*
444  * Hey, Emacs, please set the following:
445  *
446  * Local Variables:
447  * indent-tabs-mode: nil
448  * End:
449  *
450  */