2 *******************************************************************************
4 * Copyright (C) 1999-2006, 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
|| !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 derb_getString(const ResourceData
*pResData
, const Resource res
, int32_t *pLength
) {
473 int32_t *p
=(int32_t *)RES_GET_POINTER(pResData
->pRoot
, res
);
487 derb_getTableKey(const Resource
*pRoot
, const Resource res
, uint16_t indexS
) {
488 uint16_t *p
=(uint16_t *)RES_GET_POINTER(pRoot
, res
);
490 return ((const char *)(pRoot
)+(p
[indexS
+1])); /*RES_GET_KEY(pRoot, p[indexS+1]);*/
492 return NULL
; /* indexS>itemCount */
497 derb_getArrayItem(Resource
*pRoot
, Resource res
, int32_t indexR
) {
498 int32_t *p
=(int32_t *)RES_GET_POINTER(pRoot
, res
);
500 return ((Resource
*)(p
))[1+indexR
];
502 return RES_BOGUS
; /* indexR>itemCount */
507 derb_getTableItem(const Resource
*pRoot
, const Resource res
, uint16_t indexR
) {
508 uint16_t *p
=(uint16_t *)RES_GET_POINTER(pRoot
, res
);
511 return ((Resource
*)(p
+1+count
+(~count
&1)))[indexR
];
513 return RES_BOGUS
; /* indexR>itemCount */
518 static void printOutAlias(FILE *out
, UConverter
*converter
, UResourceBundle
*parent
, Resource r
, const char *key
, int32_t indent
, const char *pname
, UErrorCode
*status
) {
519 static const UChar cr
[] = { '\n' };
521 const UChar
* thestr
= derb_getString(&(parent
->fResData
), r
, &len
);
522 UChar
*string
= quotedString(thestr
);
523 if(trunc
&& len
> truncsize
) {
525 printIndent(out
, converter
, indent
);
526 sprintf(msg
, "// WARNING: this resource, size %li is truncated to %li\n",
527 (long)len
, (long)truncsize
/2);
528 printCString(out
, converter
, msg
, -1);
531 if(U_SUCCESS(*status
)) {
532 static const UChar openStr
[] = { 0x003A, 0x0061, 0x006C, 0x0069, 0x0061, 0x0073, 0x0020, 0x007B, 0x0020, 0x0022 }; /* ":alias { \"" */
533 static const UChar closeStr
[] = { 0x0022, 0x0020, 0x007D, 0x0020 }; /* "\" } " */
534 printIndent(out
, converter
, indent
);
536 printCString(out
, converter
, key
, -1);
538 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
539 printString(out
, converter
, string
, len
);
540 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
542 printCString(out
, converter
, " // ALIAS", -1);
544 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
546 reportError(pname
, status
, "getting binary value");
550 static void printOutBundle(FILE *out
, UConverter
*converter
, UResourceBundle
*resource
, int32_t indent
, const char *pname
, UErrorCode
*status
)
552 static const UChar cr
[] = { '\n' };
554 /* int32_t noOfElements = ures_getSize(resource);*/
556 const char *key
= ures_getKey(resource
);
558 switch(ures_getType(resource
)) {
562 const UChar
* thestr
= ures_getString(resource
, &len
, status
);
563 UChar
*string
= quotedString(thestr
);
565 /* TODO: String truncation */
566 if(trunc
&& len
> truncsize
) {
568 printIndent(out
, converter
, indent
);
569 sprintf(msg
, "// WARNING: this resource, size %li is truncated to %li\n",
570 (long)len
, (long)(truncsize
/2));
571 printCString(out
, converter
, msg
, -1);
574 printIndent(out
, converter
, indent
);
576 static const UChar openStr
[] = { 0x0020, 0x007B, 0x0020, 0x0022 }; /* " { \"" */
577 static const UChar closeStr
[] = { 0x0022, 0x0020, 0x007D }; /* "\" }" */
578 printCString(out
, converter
, key
, (int32_t)uprv_strlen(key
));
579 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
)/sizeof(*openStr
)));
580 printString(out
, converter
, string
, len
);
581 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
583 static const UChar openStr
[] = { 0x0022 }; /* "\"" */
584 static const UChar closeStr
[] = { 0x0022, 0x002C }; /* "\"," */
586 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
587 printString(out
, converter
, string
, (int32_t)(u_strlen(string
)));
588 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
592 printCString(out
, converter
, "// STRING", -1);
594 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
602 static const UChar openStr
[] = { 0x003A, 0x0069, 0x006E, 0x0074, 0x0020, 0x007B, 0x0020 }; /* ":int { " */
603 static const UChar closeStr
[] = { 0x0020, 0x007D }; /* " }" */
606 printIndent(out
, converter
, indent
);
608 printCString(out
, converter
, key
, -1);
610 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
611 uprv_itou(num
, 20, ures_getInt(resource
, status
), 10, 0);
612 printString(out
, converter
, num
, u_strlen(num
));
613 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
616 printCString(out
, converter
, "// INT", -1);
618 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
624 const int8_t *data
= (const int8_t *)ures_getBinary(resource
, &len
, status
);
625 if(trunc
&& len
> truncsize
) {
627 printIndent(out
, converter
, indent
);
628 sprintf(msg
, "// WARNING: this resource, size %li is truncated to %li\n",
629 (long)len
, (long)(truncsize
/2));
630 printCString(out
, converter
, msg
, -1);
633 if(U_SUCCESS(*status
)) {
634 static const UChar openStr
[] = { 0x003A, 0x0062, 0x0069, 0x006E, 0x0061, 0x0072, 0x0079, 0x0020, 0x007B, 0x0020 }; /* ":binary { " */
635 static const UChar closeStr
[] = { 0x0020, 0x007D, 0x0020 }; /* " } " */
636 printIndent(out
, converter
, indent
);
638 printCString(out
, converter
, key
, -1);
640 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
641 for(i
= 0; i
<len
; i
++) {
642 printHex(out
, converter
, *data
++);
644 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
646 printCString(out
, converter
, " // BINARY", -1);
648 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
650 reportError(pname
, status
, "getting binary value");
654 case RES_INT_VECTOR
:
657 const int32_t *data
= ures_getIntVector(resource
, &len
, status
);
658 if(U_SUCCESS(*status
)) {
659 static const UChar openStr
[] = { 0x003A, 0x0069, 0x006E, 0x0074, 0x0076, 0x0065, 0x0063, 0x0074, 0x006F, 0x0072, 0x0020, 0x007B, 0x0020 }; /* ":intvector { " */
660 static const UChar closeStr
[] = { 0x0020, 0x007D, 0x0020 }; /* " } " */
663 printIndent(out
, converter
, indent
);
665 printCString(out
, converter
, key
, -1);
667 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
668 for(i
= 0; i
< len
- 1; i
++) {
669 int32_t numLen
= uprv_itou(num
, 20, data
[i
], 10, 0);
670 num
[numLen
++] = 0x002C; /* ',' */
671 num
[numLen
++] = 0x0020; /* ' ' */
673 printString(out
, converter
, num
, u_strlen(num
));
676 uprv_itou(num
, 20, data
[len
- 1], 10, 0);
677 printString(out
, converter
, num
, u_strlen(num
));
679 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
681 printCString(out
, converter
, "// INTVECTOR", -1);
683 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
685 reportError(pname
, status
, "getting int vector");
692 static const UChar openStr
[] = { 0x007B }; /* "{" */
693 static const UChar closeStr
[] = { 0x007D, '\n' }; /* "}\n" */
695 UResourceBundle
*t
= NULL
;
696 ures_resetIterator(resource
);
697 printIndent(out
, converter
, indent
);
699 printCString(out
, converter
, key
, -1);
701 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
703 if(ures_getType(resource
) == RES_TABLE
) {
704 printCString(out
, converter
, "// TABLE", -1);
706 printCString(out
, converter
, "// ARRAY", -1);
709 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
711 if(suppressAliases
== FALSE
) {
712 while(U_SUCCESS(*status
) && ures_hasNext(resource
)) {
713 t
= ures_getNextResource(resource
, t
, status
);
714 if(U_SUCCESS(*status
)) {
715 printOutBundle(out
, converter
, t
, indent
+indentsize
, pname
, status
);
717 reportError(pname
, status
, "While processing table");
718 *status
= U_ZERO_ERROR
;
721 } else { /* we have to use low level access to do this */
722 Resource r
= RES_BOGUS
;
723 for(i
= 0; i
< ures_getSize(resource
); i
++) {
724 /* need to know if it's an alias */
725 if(ures_getType(resource
) == RES_TABLE
) {
726 r
= derb_getTableItem(resource
->fResData
.pRoot
, resource
->fRes
, (int16_t)i
);
727 key
= derb_getTableKey(resource
->fResData
.pRoot
, resource
->fRes
, (int16_t)i
);
729 r
= derb_getArrayItem(resource
->fResData
.pRoot
, resource
->fRes
, i
);
731 if(U_SUCCESS(*status
)) {
732 if(RES_GET_TYPE(r
) == RES_ALIAS
) {
733 printOutAlias(out
, converter
, resource
, r
, key
, indent
+indentsize
, pname
, status
);
735 t
= ures_getByIndex(resource
, i
, t
, status
);
736 printOutBundle(out
, converter
, t
, indent
+indentsize
, pname
, status
);
739 reportError(pname
, status
, "While processing table");
740 *status
= U_ZERO_ERROR
;
745 printIndent(out
, converter
, indent
);
746 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
756 static const char *getEncodingName(const char *encoding
) {
761 if (!(enc
= ucnv_getStandardName(encoding
, "MIME", &err
))) {
763 if (!(enc
= ucnv_getStandardName(encoding
, "IANA", &err
))) {
771 static void reportError(const char *pname
, UErrorCode
*status
, const char *when
) {
772 fprintf(stderr
, "%s: error %d while %s: %s\n", pname
, *status
, when
, u_errorName(*status
));
777 * indent-tabs-mode: nil