2 *******************************************************************************
4 * Copyright (C) 1999-2010, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
10 * tab size: 8 (not used)
13 * created on: 2000sep6
14 * created by: Vladimir Weinstein as an ICU workshop example
15 * maintained by: Yves Arrouye <yves@realnames.com>
18 #include "unicode/ucnv.h"
19 #include "unicode/ustring.h"
20 #include "unicode/putil.h"
33 #if defined(U_WINDOWS) || defined(U_CYGWIN)
36 #define USE_FILENO_BINARY_MODE 1
37 /* Windows likes to rename Unix-like functions */
39 #define fileno _fileno
42 #define setmode _setmode
45 #define O_BINARY _O_BINARY
49 #define DERB_VERSION "1.0"
51 #define DERB_DEFAULT_TRUNC 80
53 static UConverter
*defaultConverter
= 0;
55 static const int32_t indentsize
= 4;
56 static int32_t truncsize
= DERB_DEFAULT_TRUNC
;
57 static UBool trunc
= FALSE
;
59 static const char *getEncodingName(const char *encoding
);
60 static void reportError(const char *pname
, UErrorCode
*status
, const char *when
);
61 static UChar
*quotedString(const UChar
*string
);
62 static void printOutBundle(FILE *out
, UConverter
*converter
, UResourceBundle
*resource
, int32_t indent
, const char *pname
, UErrorCode
*status
);
63 static void printString(FILE *out
, UConverter
*converter
, const UChar
*str
, int32_t len
);
64 static void printCString(FILE *out
, UConverter
*converter
, const char *str
, int32_t len
);
65 static void printIndent(FILE *out
, UConverter
*converter
, int32_t indent
);
66 static void printHex(FILE *out
, UConverter
*converter
, uint8_t what
);
68 static UOption options
[]={
70 UOPTION_HELP_QUESTION_MARK
,
71 /* 2 */ UOPTION_ENCODING
,
72 /* 3 */ { "to-stdout", NULL
, NULL
, NULL
, 'c', UOPT_NO_ARG
, 0 } ,
73 /* 4 */ { "truncate", NULL
, NULL
, NULL
, 't', UOPT_OPTIONAL_ARG
, 0 },
74 /* 5 */ UOPTION_VERBOSE
,
75 /* 6 */ UOPTION_DESTDIR
,
76 /* 7 */ UOPTION_SOURCEDIR
,
77 /* 8 */ { "bom", NULL
, NULL
, NULL
, 0, UOPT_NO_ARG
, 0 },
78 /* 9 */ UOPTION_ICUDATADIR
,
79 /* 10 */ UOPTION_VERSION
,
80 /* 11 */ { "suppressAliases", NULL
, NULL
, NULL
, 'A', UOPT_NO_ARG
, 0 }
83 static UBool verbose
= FALSE
;
84 static UBool suppressAliases
= FALSE
;
87 main(int argc
, char* argv
[]) {
88 const char *encoding
= NULL
;
89 const char *outputDir
= NULL
; /* NULL = no output directory, use current */
90 const char *inputDir
= ".";
96 UResourceBundle
*bundle
= NULL
;
97 UErrorCode status
= U_ZERO_ERROR
;
100 UConverter
*converter
;
104 /* Get the name of tool. */
105 pname
= uprv_strrchr(*argv
, U_FILE_SEP_CHAR
);
106 #if U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR
108 pname
= uprv_strrchr(*argv
, U_FILE_ALT_SEP_CHAR
);
117 /* error handling, printing usage message */
118 argc
=u_parseArgs(argc
, argv
, sizeof(options
)/sizeof(options
[0]), options
);
120 /* error handling, printing usage message */
123 "%s: error in command line argument \"%s\"\n", pname
,
126 if(argc
<0 || options
[0].doesOccur
|| options
[1].doesOccur
) {
127 fprintf(argc
< 0 ? stderr
: stdout
,
128 "%csage: %s [ -h, -?, --help ] [ -V, --version ]\n"
129 " [ -v, --verbose ] [ -e, --encoding encoding ] [ --bom ]\n"
130 " [ -t, --truncate [ size ] ]\n"
131 " [ -s, --sourcedir source ] [ -d, --destdir destination ]\n"
132 " [ -i, --icudatadir directory ] [ -c, --to-stdout ]\n"
133 " [ -A, --suppressAliases]\n"
134 " bundle ...\n", argc
< 0 ? 'u' : 'U',
136 return argc
<0 ? U_ILLEGAL_ARGUMENT_ERROR
: U_ZERO_ERROR
;
139 if(options
[10].doesOccur
) {
141 "%s version %s (ICU version %s).\n"
143 pname
, DERB_VERSION
, U_ICU_VERSION
, U_COPYRIGHT_STRING
);
146 if(options
[2].doesOccur
) {
147 encoding
= options
[2].value
;
150 if (options
[3].doesOccur
) {
154 if(options
[4].doesOccur
) {
156 if(options
[4].value
!= NULL
) {
157 truncsize
= atoi(options
[4].value
); /* user defined printable size */
159 truncsize
= DERB_DEFAULT_TRUNC
; /* we'll use default omitting size */
165 if(options
[5].doesOccur
) {
169 if (options
[6].doesOccur
) {
170 outputDir
= options
[6].value
;
173 if(options
[7].doesOccur
) {
174 inputDir
= options
[7].value
; /* we'll use users resources */
177 if (options
[8].doesOccur
) {
181 if (options
[9].doesOccur
) {
182 u_setDataDirectory(options
[9].value
);
185 if (options
[11].doesOccur
) {
186 suppressAliases
= TRUE
;
189 converter
= ucnv_open(encoding
, &status
);
190 if (U_FAILURE(status
)) {
191 fprintf(stderr
, "%s: couldn't create %s converter for encoding\n", pname
, encoding
? encoding
: ucnv_getDefaultName());
194 ucnv_setFromUCallBack(converter
, UCNV_FROM_U_CALLBACK_ESCAPE
, UCNV_ESCAPE_C
, 0, 0, &status
);
195 if (U_FAILURE(status
)) {
196 fprintf(stderr
, "%s: couldn't configure converter for encoding\n", pname
);
200 defaultConverter
= ucnv_open(0, &status
);
201 if (U_FAILURE(status
)) {
202 fprintf(stderr
, "%s: couldn't create %s converter for encoding\n", ucnv_getDefaultName(), pname
);
206 for (i
= 1; i
< argc
; ++i
) {
207 static const UChar sp
[] = { 0x0020 }; /* " " */
208 char infile
[4096]; /* XXX Sloppy. */
210 const char *thename
= 0, *p
, *q
;
211 UBool fromICUData
= FALSE
;
213 arg
= getLongPathname(argv
[i
]);
216 printf("processing bundle \"%s\"\n", argv
[i
]);
219 p
= uprv_strrchr(arg
, U_FILE_SEP_CHAR
);
220 #if U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR
222 p
= uprv_strrchr(arg
, U_FILE_ALT_SEP_CHAR
);
230 q
= uprv_strrchr(p
, '.');
235 uprv_strncpy(locale
, p
, q
- p
);
238 if (!(fromICUData
= !uprv_strcmp(inputDir
, "-"))) {
239 UBool absfilename
= *arg
== U_FILE_SEP_CHAR
;
242 absfilename
= (uprv_strlen(arg
) > 2 && isalpha(arg
[0])
243 && arg
[1] == ':' && arg
[2] == U_FILE_SEP_CHAR
);
249 q
= uprv_strrchr(arg
, U_FILE_SEP_CHAR
);
250 #if U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR
252 q
= uprv_strrchr(arg
, U_FILE_ALT_SEP_CHAR
);
255 uprv_strcpy(infile
, inputDir
);
257 uprv_strcat(infile
, U_FILE_SEP_STRING
);
258 strncat(infile
, arg
, q
-arg
);
263 status
= U_ZERO_ERROR
;
265 bundle
= ures_openDirect(thename
, locale
, &status
);
267 bundle
= ures_open(fromICUData
? 0 : inputDir
, locale
, &status
);
269 if (status
== U_ZERO_ERROR
) {
272 const char *filename
= 0;
275 if (!locale
[0] || !tostdout
) {
276 filename
= uprv_strrchr(arg
, U_FILE_SEP_CHAR
);
278 #if U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR
280 filename
= uprv_strrchr(arg
, U_FILE_ALT_SEP_CHAR
);
288 ext
= uprv_strrchr(arg
, '.');
290 ext
= filename
+ uprv_strlen(filename
);
296 #if defined(U_WINDOWS) || defined(U_CYGWIN)
297 if (setmode(fileno(out
), O_BINARY
) == -1) {
298 fprintf(stderr
, "%s: couldn't set standard output to binary mode\n", pname
);
303 char thefile
[4096], *tp
;
307 uprv_strcpy(thefile
, outputDir
);
308 uprv_strcat(thefile
, U_FILE_SEP_STRING
);
312 uprv_strcat(thefile
, filename
);
313 tp
= thefile
+ uprv_strlen(thefile
);
314 len
= (int32_t)uprv_strlen(ext
);
320 uprv_strcpy(tp
, "txt");
322 out
= fopen(thefile
, "w");
324 fprintf(stderr
, "%s: couldn't create %s\n", pname
, thefile
);
329 if (prbom
) { /* XXX: Should be done only for UTFs */
330 static const UChar bom
[] = { 0xFEFF };
331 printString(out
, converter
, bom
, (int32_t)(sizeof(bom
)/sizeof(*bom
)));
334 printCString(out
, converter
, "// -*- Coding: ", -1);
335 printCString(out
, converter
, encoding
? encoding
: getEncodingName(ucnv_getDefaultName()), -1);
336 printCString(out
, converter
, "; -*-\n//\n", -1);
337 printCString(out
, converter
, "// This file was dumped by derb(8) from ", -1);
339 printCString(out
, converter
, thename
, -1);
340 } else if (fromICUData
) {
341 printCString(out
, converter
, "the ICU internal ", -1);
342 printCString(out
, converter
, locale
, -1);
343 printCString(out
, converter
, " locale", -1);
346 printCString(out
, converter
, "\n// derb(8) by Vladimir Weinstein and Yves Arrouye\n\n", -1);
349 printCString(out
, converter
, locale
, -1);
351 printCString(out
, converter
, filename
, (int32_t)(ext
- filename
));
352 printString(out
, converter
, sp
, (int32_t)(sizeof(sp
)/sizeof(*sp
)));
354 printOutBundle(out
, converter
, bundle
, 0, pname
, &status
);
361 reportError(pname
, &status
, "opening resource file");
367 ucnv_close(defaultConverter
);
368 ucnv_close(converter
);
373 static UChar
*quotedString(const UChar
*string
) {
374 int len
= u_strlen(string
);
379 for (sp
= string
; *sp
; ++sp
) {
388 newstr
= (UChar
*) uprv_malloc((1 + alen
) * sizeof(*newstr
));
389 for (sp
= string
, np
= newstr
; *sp
; ++sp
) {
410 static void printString(FILE *out
, UConverter
*converter
, const UChar
*str
, int32_t len
) {
420 UErrorCode err
= U_ZERO_ERROR
;
421 char *bufp
= buf
, *bufend
= buf
+ sizeof(buf
) - 1 ;
423 ucnv_fromUnicode(converter
, &bufp
, bufend
, &str
, strEnd
, 0, 0, &err
);
426 fprintf(out
, "%s", buf
);
427 } while (str
< strEnd
);
430 static void printCString(FILE *out
, UConverter
*converter
, const char *str
, int32_t len
) {
435 len
= (int32_t)uprv_strlen(str
);
440 UErrorCode err
= U_ZERO_ERROR
;
441 UChar
*bufp
= buf
, *bufend
= buf
+ (sizeof(buf
)/sizeof(buf
[0])) - 1 ;
443 ucnv_toUnicode(defaultConverter
, &bufp
, bufend
, &str
, strEnd
, 0, 0, &err
);
446 printString(out
, converter
, buf
, (int32_t)(bufp
- buf
));
447 } while (str
< strEnd
);
450 static void printIndent(FILE *out
, UConverter
*converter
, int32_t indent
) {
453 for(i
= 0; i
<indent
; i
++) {
458 printString(out
, converter
, inchar
, indent
);
461 static void printHex(FILE *out
, UConverter
*converter
, uint8_t what
) {
462 static const char map
[] = "0123456789ABCDEF";
465 hex
[0] = map
[what
>> 4];
466 hex
[1] = map
[what
& 0xf];
468 printString(out
, converter
, hex
, (int32_t)(sizeof(hex
)/sizeof(*hex
)));
471 static void printOutAlias(FILE *out
, UConverter
*converter
, UResourceBundle
*parent
, Resource r
, const char *key
, int32_t indent
, const char *pname
, UErrorCode
*status
) {
472 static const UChar cr
[] = { '\n' };
474 const UChar
* thestr
= res_getAlias(&(parent
->fResData
), r
, &len
);
475 UChar
*string
= quotedString(thestr
);
476 if(trunc
&& len
> truncsize
) {
478 printIndent(out
, converter
, indent
);
479 sprintf(msg
, "// WARNING: this resource, size %li is truncated to %li\n",
480 (long)len
, (long)truncsize
/2);
481 printCString(out
, converter
, msg
, -1);
484 if(U_SUCCESS(*status
)) {
485 static const UChar openStr
[] = { 0x003A, 0x0061, 0x006C, 0x0069, 0x0061, 0x0073, 0x0020, 0x007B, 0x0020, 0x0022 }; /* ":alias { \"" */
486 static const UChar closeStr
[] = { 0x0022, 0x0020, 0x007D, 0x0020 }; /* "\" } " */
487 printIndent(out
, converter
, indent
);
489 printCString(out
, converter
, key
, -1);
491 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
492 printString(out
, converter
, string
, len
);
493 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
495 printCString(out
, converter
, " // ALIAS", -1);
497 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
499 reportError(pname
, status
, "getting binary value");
504 static void printOutBundle(FILE *out
, UConverter
*converter
, UResourceBundle
*resource
, int32_t indent
, const char *pname
, UErrorCode
*status
)
506 static const UChar cr
[] = { '\n' };
508 /* int32_t noOfElements = ures_getSize(resource);*/
510 const char *key
= ures_getKey(resource
);
512 switch(ures_getType(resource
)) {
516 const UChar
* thestr
= ures_getString(resource
, &len
, status
);
517 UChar
*string
= quotedString(thestr
);
519 /* TODO: String truncation */
520 if(trunc
&& len
> truncsize
) {
522 printIndent(out
, converter
, indent
);
523 sprintf(msg
, "// WARNING: this resource, size %li is truncated to %li\n",
524 (long)len
, (long)(truncsize
/2));
525 printCString(out
, converter
, msg
, -1);
528 printIndent(out
, converter
, indent
);
530 static const UChar openStr
[] = { 0x0020, 0x007B, 0x0020, 0x0022 }; /* " { \"" */
531 static const UChar closeStr
[] = { 0x0022, 0x0020, 0x007D }; /* "\" }" */
532 printCString(out
, converter
, key
, (int32_t)uprv_strlen(key
));
533 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
)/sizeof(*openStr
)));
534 printString(out
, converter
, string
, len
);
535 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
537 static const UChar openStr
[] = { 0x0022 }; /* "\"" */
538 static const UChar closeStr
[] = { 0x0022, 0x002C }; /* "\"," */
540 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
541 printString(out
, converter
, string
, (int32_t)(u_strlen(string
)));
542 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
546 printCString(out
, converter
, "// STRING", -1);
548 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
556 static const UChar openStr
[] = { 0x003A, 0x0069, 0x006E, 0x0074, 0x0020, 0x007B, 0x0020 }; /* ":int { " */
557 static const UChar closeStr
[] = { 0x0020, 0x007D }; /* " }" */
560 printIndent(out
, converter
, indent
);
562 printCString(out
, converter
, key
, -1);
564 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
565 uprv_itou(num
, 20, ures_getInt(resource
, status
), 10, 0);
566 printString(out
, converter
, num
, u_strlen(num
));
567 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
570 printCString(out
, converter
, "// INT", -1);
572 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
578 const int8_t *data
= (const int8_t *)ures_getBinary(resource
, &len
, status
);
579 if(trunc
&& len
> truncsize
) {
581 printIndent(out
, converter
, indent
);
582 sprintf(msg
, "// WARNING: this resource, size %li is truncated to %li\n",
583 (long)len
, (long)(truncsize
/2));
584 printCString(out
, converter
, msg
, -1);
587 if(U_SUCCESS(*status
)) {
588 static const UChar openStr
[] = { 0x003A, 0x0062, 0x0069, 0x006E, 0x0061, 0x0072, 0x0079, 0x0020, 0x007B, 0x0020 }; /* ":binary { " */
589 static const UChar closeStr
[] = { 0x0020, 0x007D, 0x0020 }; /* " } " */
590 printIndent(out
, converter
, indent
);
592 printCString(out
, converter
, key
, -1);
594 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
595 for(i
= 0; i
<len
; i
++) {
596 printHex(out
, converter
, *data
++);
598 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
600 printCString(out
, converter
, " // BINARY", -1);
602 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
604 reportError(pname
, status
, "getting binary value");
608 case URES_INT_VECTOR
:
611 const int32_t *data
= ures_getIntVector(resource
, &len
, status
);
612 if(U_SUCCESS(*status
)) {
613 static const UChar openStr
[] = { 0x003A, 0x0069, 0x006E, 0x0074, 0x0076, 0x0065, 0x0063, 0x0074, 0x006F, 0x0072, 0x0020, 0x007B, 0x0020 }; /* ":intvector { " */
614 static const UChar closeStr
[] = { 0x0020, 0x007D, 0x0020 }; /* " } " */
617 printIndent(out
, converter
, indent
);
619 printCString(out
, converter
, key
, -1);
621 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
622 for(i
= 0; i
< len
- 1; i
++) {
623 int32_t numLen
= uprv_itou(num
, 20, data
[i
], 10, 0);
624 num
[numLen
++] = 0x002C; /* ',' */
625 num
[numLen
++] = 0x0020; /* ' ' */
627 printString(out
, converter
, num
, u_strlen(num
));
630 uprv_itou(num
, 20, data
[len
- 1], 10, 0);
631 printString(out
, converter
, num
, u_strlen(num
));
633 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
635 printCString(out
, converter
, "// INTVECTOR", -1);
637 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
639 reportError(pname
, status
, "getting int vector");
646 static const UChar openStr
[] = { 0x007B }; /* "{" */
647 static const UChar closeStr
[] = { 0x007D, '\n' }; /* "}\n" */
649 UResourceBundle
*t
= NULL
;
650 ures_resetIterator(resource
);
651 printIndent(out
, converter
, indent
);
653 printCString(out
, converter
, key
, -1);
655 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
657 if(ures_getType(resource
) == URES_TABLE
) {
658 printCString(out
, converter
, "// TABLE", -1);
660 printCString(out
, converter
, "// ARRAY", -1);
663 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
665 if(suppressAliases
== FALSE
) {
666 while(U_SUCCESS(*status
) && ures_hasNext(resource
)) {
667 t
= ures_getNextResource(resource
, t
, status
);
668 if(U_SUCCESS(*status
)) {
669 printOutBundle(out
, converter
, t
, indent
+indentsize
, pname
, status
);
671 reportError(pname
, status
, "While processing table");
672 *status
= U_ZERO_ERROR
;
675 } else { /* we have to use low level access to do this */
677 int32_t resSize
= ures_getSize(resource
);
678 UBool isTable
= (UBool
)(ures_getType(resource
) == URES_TABLE
);
679 for(i
= 0; i
< resSize
; i
++) {
680 /* need to know if it's an alias */
682 r
= res_getTableItemByIndex(&resource
->fResData
, resource
->fRes
, i
, &key
);
684 r
= res_getArrayItem(&resource
->fResData
, resource
->fRes
, i
);
686 if(U_SUCCESS(*status
)) {
687 if(res_getPublicType(r
) == URES_ALIAS
) {
688 printOutAlias(out
, converter
, resource
, r
, key
, indent
+indentsize
, pname
, status
);
690 t
= ures_getByIndex(resource
, i
, t
, status
);
691 printOutBundle(out
, converter
, t
, indent
+indentsize
, pname
, status
);
694 reportError(pname
, status
, "While processing table");
695 *status
= U_ZERO_ERROR
;
700 printIndent(out
, converter
, indent
);
701 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
711 static const char *getEncodingName(const char *encoding
) {
716 if (!(enc
= ucnv_getStandardName(encoding
, "MIME", &err
))) {
718 if (!(enc
= ucnv_getStandardName(encoding
, "IANA", &err
))) {
726 static void reportError(const char *pname
, UErrorCode
*status
, const char *when
) {
727 fprintf(stderr
, "%s: error %d while %s: %s\n", pname
, *status
, when
, u_errorName(*status
));
732 * indent-tabs-mode: nil