2 *******************************************************************************
4 * Copyright (C) 2009-2010, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * file name: gennorm2.cpp
10 * tab size: 8 (not used)
13 * created on: 2009nov25
14 * created by: Markus W. Scherer
16 * This program reads text files that define Unicode normalization,
17 * parses them, and builds a binary data file.
20 #include "unicode/utypes.h"
21 #include "n2builder.h"
26 #include "unicode/errorcode.h"
27 #include "unicode/localpointer.h"
28 #include "unicode/putil.h"
29 #include "unicode/uchar.h"
30 #include "unicode/unistr.h"
32 #include "normalizer2impl.h"
37 #if UCONFIG_NO_NORMALIZATION
41 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
45 UBool beVerbose
=FALSE
, haveCopyright
=TRUE
;
47 U_DEFINE_LOCAL_OPEN_POINTER(LocalStdioFilePointer
, FILE, fclose
);
49 #if !UCONFIG_NO_NORMALIZATION
50 void parseFile(FILE *f
, Normalizer2DataBuilder
&builder
);
53 /* -------------------------------------------------------------------------- */
66 static UOption options
[]={
68 UOPTION_HELP_QUESTION_MARK
,
72 UOPTION_DEF("output", 'o', UOPT_REQUIRES_ARG
),
73 UOPTION_DEF("unicode", 'u', UOPT_REQUIRES_ARG
),
74 UOPTION_DEF("fast", '\1', UOPT_NO_ARG
)
78 main(int argc
, char* argv
[]) {
79 U_MAIN_INIT_ARGS(argc
, argv
);
81 /* preset then read command line options */
82 options
[SOURCEDIR
].value
="";
83 options
[UNICODE_VERSION
].value
=U_UNICODE_VERSION
;
84 argc
=u_parseArgs(argc
, argv
, sizeof(options
)/sizeof(options
[HELP_H
]), options
);
86 /* error handling, printing usage message */
89 "error in command line argument \"%s\"\n",
92 if(!options
[OUTPUT_FILENAME
].doesOccur
) {
96 options
[HELP_H
].doesOccur
|| options
[HELP_QUESTION_MARK
].doesOccur
99 * Broken into chunks because the C89 standard says the minimum
100 * required supported string length is 509 bytes.
103 "Usage: %s [-options] infiles+ -o outputfilename\n"
105 "Reads the infiles with normalization data and\n"
106 "creates a binary file (outputfilename) with the data.\n"
111 "\t-h or -? or --help this usage text\n"
112 "\t-v or --verbose verbose output\n"
113 "\t-c or --copyright include a copyright notice\n"
114 "\t-u or --unicode Unicode version, followed by the version like 5.2.0\n");
116 "\t-s or --sourcedir source directory, followed by the path\n"
117 "\t-o or --output output filename\n");
119 "\t --fast optimize the .nrm file for fast normalization,\n"
120 "\t which might increase its size (Writes fully decomposed\n"
121 "\t regular mappings instead of delta mappings.\n"
122 "\t You should measure the runtime speed to make sure that\n"
123 "\t this is a good trade-off.)\n");
124 return argc
<0 ? U_ILLEGAL_ARGUMENT_ERROR
: U_ZERO_ERROR
;
127 beVerbose
=options
[VERBOSE
].doesOccur
;
128 haveCopyright
=options
[COPYRIGHT
].doesOccur
;
130 IcuToolErrorCode
errorCode("gennorm2/main()");
132 #if UCONFIG_NO_NORMALIZATION
135 "gennorm2 writes a dummy binary data file "
136 "because UCONFIG_NO_NORMALIZATION is set, \n"
137 "see icu/source/common/unicode/uconfig.h\n");
138 udata_createDummy(NULL
, NULL
, options
[OUTPUT_FILENAME
].value
, errorCode
);
139 // Should not return an error since this is the expected behaviour if UCONFIG_NO_NORMALIZATION is on.
140 // return U_UNSUPPORTED_ERROR;
145 LocalPointer
<Normalizer2DataBuilder
> builder(new Normalizer2DataBuilder(errorCode
));
146 errorCode
.assertSuccess();
148 builder
->setUnicodeVersion(options
[UNICODE_VERSION
].value
);
150 if(options
[OPT_FAST
].doesOccur
) {
151 builder
->setOptimization(Normalizer2DataBuilder::OPTIMIZE_FAST
);
154 // prepare the filename beginning with the source dir
155 CharString
filename(options
[SOURCEDIR
].value
, errorCode
);
156 int32_t pathLength
=filename
.length();
158 filename
[pathLength
-1]!=U_FILE_SEP_CHAR
&&
159 filename
[pathLength
-1]!=U_FILE_ALT_SEP_CHAR
161 filename
.append(U_FILE_SEP_CHAR
, errorCode
);
162 pathLength
=filename
.length();
165 for(int i
=1; i
<argc
; ++i
) {
166 printf("gennorm2: processing %s\n", argv
[i
]);
167 filename
.append(argv
[i
], errorCode
);
168 LocalStdioFilePointer
f(fopen(filename
.data(), "r"));
170 fprintf(stderr
, "gennorm2 error: unable to open %s\n", filename
.data());
171 exit(U_FILE_ACCESS_ERROR
);
173 builder
->setOverrideHandling(Normalizer2DataBuilder::OVERRIDE_PREVIOUS
);
174 parseFile(f
.getAlias(), *builder
);
175 filename
.truncate(pathLength
);
178 builder
->writeBinaryFile(options
[OUTPUT_FILENAME
].value
);
180 return errorCode
.get();
185 #if !UCONFIG_NO_NORMALIZATION
187 void parseFile(FILE *f
, Normalizer2DataBuilder
&builder
) {
188 IcuToolErrorCode
errorCode("gennorm2/parseFile()");
190 uint32_t startCP
, endCP
;
191 while(NULL
!=fgets(line
, (int)sizeof(line
), f
)) {
192 char *comment
=(char *)strchr(line
, '#');
198 continue; // skip empty and comment-only lines
201 continue; // reserved syntax
203 const char *delimiter
;
205 u_parseCodePointRangeAnyTerminator(line
, &startCP
, &endCP
, &delimiter
, errorCode
);
206 if(errorCode
.isFailure()) {
207 fprintf(stderr
, "gennorm2 error: parsing code point range from %s\n", line
);
208 exit(errorCode
.reset());
210 delimiter
=u_skipWhitespace(delimiter
);
211 if(*delimiter
==':') {
212 const char *s
=u_skipWhitespace(delimiter
+1);
214 unsigned long value
=strtoul(s
, &end
, 10);
215 if(end
<=s
|| *u_skipWhitespace(end
)!=0 || value
>=0xff) {
216 fprintf(stderr
, "gennorm2 error: parsing ccc from %s\n", line
);
219 for(UChar32 c
=(UChar32
)startCP
; c
<=(UChar32
)endCP
; ++c
) {
220 builder
.setCC(c
, (uint8_t)value
);
224 if(*delimiter
=='-') {
225 if(*u_skipWhitespace(delimiter
+1)!=0) {
226 fprintf(stderr
, "gennorm2 error: parsing remove-mapping %s\n", line
);
229 for(UChar32 c
=(UChar32
)startCP
; c
<=(UChar32
)endCP
; ++c
) {
230 builder
.removeMapping(c
);
234 if(*delimiter
=='=' || *delimiter
=='>') {
235 UChar uchars
[Normalizer2Impl::MAPPING_LENGTH_MASK
];
236 int32_t length
=u_parseString(delimiter
+1, uchars
, LENGTHOF(uchars
), NULL
, errorCode
);
237 if(errorCode
.isFailure()) {
238 fprintf(stderr
, "gennorm2 error: parsing mapping string from %s\n", line
);
239 exit(errorCode
.reset());
241 UnicodeString
mapping(FALSE
, uchars
, length
);
242 if(*delimiter
=='=') {
245 "gennorm2 error: round-trip mapping for more than 1 code point on %s\n",
249 builder
.setRoundTripMapping((UChar32
)startCP
, mapping
);
251 for(UChar32 c
=(UChar32
)startCP
; c
<=(UChar32
)endCP
; ++c
) {
252 builder
.setOneWayMapping(c
, mapping
);
257 fprintf(stderr
, "gennorm2 error: unrecognized data line %s\n", line
);
262 #endif // !UCONFIG_NO_NORMALIZATION
267 * Hey, Emacs, please set the following:
270 * indent-tabs-mode: nil