2 *******************************************************************************
4 * Copyright (C) 1999-2004, 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(WIN32) || defined(U_CYGWIN)
38 #define DERB_VERSION "1.0"
40 #define DERB_DEFAULT_TRUNC 80
42 static UConverter
*defaultConverter
= 0;
44 static const int32_t indentsize
= 4;
45 static int32_t truncsize
= DERB_DEFAULT_TRUNC
;
46 static UBool trunc
= FALSE
;
48 static const UChar baderror
[] = { 0x0042, 0x0041, 0x0044, 0x0000 };
50 static const char *getEncodingName(const char *encoding
);
51 static void reportError(const char *pname
, UErrorCode
*status
, const char *when
);
52 static UChar
*quotedString(const UChar
*string
);
53 static void printOutBundle(FILE *out
, UConverter
*converter
, UResourceBundle
*resource
, int32_t indent
, const char *pname
, UErrorCode
*status
);
54 static void printString(FILE *out
, UConverter
*converter
, const UChar
*str
, int32_t len
);
55 static void printCString(FILE *out
, UConverter
*converter
, const char *str
, int32_t len
);
56 static void printIndent(FILE *out
, UConverter
*converter
, int32_t indent
);
57 static void printHex(FILE *out
, UConverter
*converter
, uint8_t what
);
59 static UOption options
[]={
61 UOPTION_HELP_QUESTION_MARK
,
62 /* 2 */ UOPTION_ENCODING
,
63 /* 3 */ { "to-stdout", NULL
, NULL
, NULL
, 'c', UOPT_NO_ARG
, 0 } ,
64 /* 4 */ { "truncate", NULL
, NULL
, NULL
, 't', UOPT_OPTIONAL_ARG
, 0 },
65 /* 5 */ UOPTION_VERBOSE
,
66 /* 6 */ UOPTION_DESTDIR
,
67 /* 7 */ UOPTION_SOURCEDIR
,
68 /* 8 */ { "bom", NULL
, NULL
, NULL
, 0, UOPT_NO_ARG
, 0 },
69 /* 9 */ UOPTION_ICUDATADIR
,
70 /* 10 */ UOPTION_VERSION
,
71 /* 11 */ { "suppressAliases", NULL
, NULL
, NULL
, 'A', UOPT_NO_ARG
, 0 }
74 static UBool verbose
= FALSE
;
75 static UBool suppressAliases
= FALSE
;
78 main(int argc
, char* argv
[]) {
79 const char *encoding
= NULL
;
80 const char *outputDir
= NULL
; /* NULL = no output directory, use current */
81 const char *inputDir
= ".";
87 UResourceBundle
*bundle
= NULL
;
88 UErrorCode status
= U_ZERO_ERROR
;
91 UConverter
*converter
;
95 /* Get the name of tool. */
96 pname
= uprv_strrchr(*argv
, U_FILE_SEP_CHAR
);
99 pname
= uprv_strrchr(*argv
, '/');
108 /* error handling, printing usage message */
109 argc
=u_parseArgs(argc
, argv
, sizeof(options
)/sizeof(options
[0]), options
);
111 /* error handling, printing usage message */
114 "%s: error in command line argument \"%s\"\n", pname
,
117 if(argc
<0 || options
[0].doesOccur
|| options
[1].doesOccur
) {
118 fprintf(argc
< 0 ? stderr
: stdout
,
119 "%csage: %s [ -h, -?, --help ] [ -V, --version ]\n"
120 " [ -v, --verbose ] [ -e, --encoding encoding ] [ --bom ]\n"
121 " [ -t, --truncate [ size ] ]\n"
122 " [ -s, --sourcedir source ] [ -d, --destdir destination ]\n"
123 " [ -i, --icudatadir directory ] [ -c, --to-stdout ]\n"
124 " [ -A, --suppressAliases]\n"
125 " bundle ...\n", argc
< 0 ? 'u' : 'U',
127 return argc
<0 ? U_ILLEGAL_ARGUMENT_ERROR
: U_ZERO_ERROR
;
130 if(options
[10].doesOccur
) {
132 "%s version %s (ICU version %s).\n"
134 pname
, DERB_VERSION
, U_ICU_VERSION
, U_COPYRIGHT_STRING
);
137 if(options
[2].doesOccur
) {
138 encoding
= options
[2].value
;
141 if (options
[3].doesOccur
) {
145 if(options
[4].doesOccur
) {
147 if(options
[4].value
!= NULL
) {
148 truncsize
= atoi(options
[4].value
); /* user defined printable size */
150 truncsize
= DERB_DEFAULT_TRUNC
; /* we'll use default omitting size */
156 if(options
[5].doesOccur
) {
160 if (options
[6].doesOccur
) {
161 outputDir
= options
[6].value
;
164 if(options
[7].doesOccur
) {
165 inputDir
= options
[7].value
; /* we'll use users resources */
168 if (options
[8].doesOccur
) {
172 if (options
[9].doesOccur
) {
173 u_setDataDirectory(options
[9].value
);
176 if (options
[11].doesOccur
) {
177 suppressAliases
= TRUE
;
180 converter
= ucnv_open(encoding
, &status
);
181 if (U_FAILURE(status
)) {
182 fprintf(stderr
, "%s: couldn't create %s converter for encoding\n", pname
, encoding
? encoding
: ucnv_getDefaultName());
185 ucnv_setFromUCallBack(converter
, UCNV_FROM_U_CALLBACK_ESCAPE
, UCNV_ESCAPE_C
, 0, 0, &status
);
186 if (U_FAILURE(status
)) {
187 fprintf(stderr
, "%s: couldn't configure converter for encoding\n", pname
);
191 defaultConverter
= ucnv_open(0, &status
);
192 if (U_FAILURE(status
)) {
193 fprintf(stderr
, "%s: couldn't create %s converter for encoding\n", ucnv_getDefaultName(), pname
);
197 for (i
= 1; i
< argc
; ++i
) {
198 static const UChar sp
[] = { 0x0020 }; /* " " */
199 char infile
[4096]; /* XXX Sloppy. */
201 const char *thename
= 0, *p
, *q
;
202 UBool fromICUData
= FALSE
;
204 arg
= getLongPathname(argv
[i
]);
207 printf("processing bundle \"%s\"\n", argv
[i
]);
210 p
= uprv_strrchr(arg
, U_FILE_SEP_CHAR
);
216 q
= uprv_strrchr(p
, '.');
218 for (q
= p
; *q
; ++q
);
220 uprv_strncpy(locale
, p
, q
- p
);
223 if (!(fromICUData
= !uprv_strcmp(inputDir
, "-"))) {
224 UBool absfilename
= *arg
== U_FILE_SEP_CHAR
;
227 absfilename
= (uprv_strlen(arg
) > 2 && isalpha(arg
[0])
228 && arg
[1] == ':' && arg
[2] == U_FILE_SEP_CHAR
);
234 q
= uprv_strrchr(arg
, U_FILE_SEP_CHAR
);
235 uprv_strcpy(infile
, inputDir
);
237 uprv_strcat(infile
, U_FILE_SEP_STRING
),
238 strncat(infile
, arg
, q
-arg
);
243 status
= U_ZERO_ERROR
;
245 bundle
= ures_openDirect(thename
, locale
, &status
);
247 bundle
= ures_open(fromICUData
? 0 : inputDir
, locale
, &status
);
249 if (status
== U_ZERO_ERROR
) {
252 const char *filename
= 0;
255 if (!locale
|| !tostdout
) {
256 filename
= uprv_strrchr(arg
, U_FILE_SEP_CHAR
);
260 filename
= uprv_strrchr(arg
, '/');
268 ext
= uprv_strrchr(arg
, '.');
270 ext
= filename
+ uprv_strlen(filename
);
276 #if defined(WIN32) || defined(U_CYGWIN)
277 if (_setmode(_fileno(out
), _O_BINARY
) == -1) {
278 fprintf(stderr
, "%s: couldn't set standard output to binary mode\n", pname
);
283 char thefile
[4096], *tp
;
287 uprv_strcpy(thefile
, outputDir
);
288 uprv_strcat(thefile
, U_FILE_SEP_STRING
);
292 uprv_strcat(thefile
, filename
);
293 tp
= thefile
+ uprv_strlen(thefile
);
294 len
= (int32_t)uprv_strlen(ext
);
300 uprv_strcpy(tp
, "txt");
302 out
= fopen(thefile
, "w");
304 fprintf(stderr
, "%s: couldn't create %s\n", pname
, thefile
);
309 if (prbom
) { /* XXX: Should be done only for UTFs */
310 static const UChar bom
[] = { 0xFEFF };
311 printString(out
, converter
, bom
, (int32_t)(sizeof(bom
)/sizeof(*bom
)));
314 printCString(out
, converter
, "// -*- Coding: ", -1);
315 printCString(out
, converter
, encoding
? encoding
: getEncodingName(ucnv_getDefaultName()), -1);
316 printCString(out
, converter
, "; -*-\n//\n", -1);
317 printCString(out
, converter
, "// This file was dumped by derb(8) from ", -1);
319 printCString(out
, converter
, thename
, -1);
320 } else if (fromICUData
) {
321 printCString(out
, converter
, "the ICU internal ", -1);
322 printCString(out
, converter
, locale
, -1);
323 printCString(out
, converter
, " locale", -1);
326 printCString(out
, converter
, "\n// derb(8) by Vladimir Weinstein and Yves Arrouye\n\n", -1);
329 printCString(out
, converter
, locale
, -1);
331 printCString(out
, converter
, filename
, (int32_t)(ext
- filename
));
332 printString(out
, converter
, sp
, (int32_t)(sizeof(sp
)/sizeof(*sp
)));
334 printOutBundle(out
, converter
, bundle
, 0, pname
, &status
);
340 reportError(pname
, &status
, "opening resource file");
346 ucnv_close(defaultConverter
);
347 ucnv_close(converter
);
352 static UChar
*quotedString(const UChar
*string
) {
353 int len
= u_strlen(string
);
358 for (sp
= string
; *sp
; ++sp
) {
367 newstr
= (UChar
*) uprv_malloc((1 + alen
) * sizeof(*newstr
));
368 for (sp
= string
, np
= newstr
; *sp
; ++sp
) {
389 static void printString(FILE *out
, UConverter
*converter
, const UChar
*str
, int32_t len
) {
399 UErrorCode err
= U_ZERO_ERROR
;
400 char *bufp
= buf
, *bufend
= buf
+ sizeof(buf
) - 1 ;
402 ucnv_fromUnicode(converter
, &bufp
, bufend
, &str
, strEnd
, 0, 0, &err
);
405 fprintf(out
, "%s", buf
);
406 } while (str
< strEnd
);
409 static void printCString(FILE *out
, UConverter
*converter
, const char *str
, int32_t len
) {
414 len
= (int32_t)uprv_strlen(str
);
419 UErrorCode err
= U_ZERO_ERROR
;
420 UChar
*bufp
= buf
, *bufend
= buf
+ (sizeof(buf
)/sizeof(buf
[0])) - 1 ;
422 ucnv_toUnicode(defaultConverter
, &bufp
, bufend
, &str
, strEnd
, 0, 0, &err
);
425 printString(out
, converter
, buf
, (int32_t)(bufp
- buf
));
426 } while (str
< strEnd
);
429 static void printIndent(FILE *out
, UConverter
*converter
, int32_t indent
) {
432 for(i
= 0; i
<indent
; i
++) {
437 printString(out
, converter
, inchar
, indent
);
440 static void printHex(FILE *out
, UConverter
*converter
, uint8_t what
) {
441 static const char map
[] = "0123456789ABCDEF";
444 hex
[0] = map
[what
>> 4];
445 hex
[1] = map
[what
& 0xf];
447 printString(out
, converter
, hex
, (int32_t)(sizeof(hex
)/sizeof(*hex
)));
450 derb_getString(const ResourceData
*pResData
, const Resource res
, int32_t *pLength
) {
452 int32_t *p
=(int32_t *)RES_GET_POINTER(pResData
->pRoot
, res
);
466 derb_getTableKey(const Resource
*pRoot
, const Resource res
, uint16_t indexS
) {
467 uint16_t *p
=(uint16_t *)RES_GET_POINTER(pRoot
, res
);
469 return ((const char *)(pRoot
)+(p
[indexS
+1])); /*RES_GET_KEY(pRoot, p[indexS+1]);*/
471 return NULL
; /* indexS>itemCount */
476 derb_getArrayItem(Resource
*pRoot
, Resource res
, int32_t indexR
) {
477 int32_t *p
=(int32_t *)RES_GET_POINTER(pRoot
, res
);
479 return ((Resource
*)(p
))[1+indexR
];
481 return RES_BOGUS
; /* indexR>itemCount */
486 derb_getTableItem(const Resource
*pRoot
, const Resource res
, uint16_t indexR
) {
487 uint16_t *p
=(uint16_t *)RES_GET_POINTER(pRoot
, res
);
490 return ((Resource
*)(p
+1+count
+(~count
&1)))[indexR
];
492 return RES_BOGUS
; /* indexR>itemCount */
497 static void printOutAlias(FILE *out
, UConverter
*converter
, UResourceBundle
*parent
, Resource r
, const char *key
, int32_t indent
, const char *pname
, UErrorCode
*status
) {
498 static const UChar cr
[] = { '\n' };
500 const UChar
* thestr
= derb_getString(&(parent
->fResData
), r
, &len
);
501 UChar
*string
= quotedString(thestr
);
502 if(trunc
&& len
> truncsize
) {
504 printIndent(out
, converter
, indent
);
505 sprintf(msg
, "// WARNING: this resource, size %li is truncated to %li\n",
506 (long)len
, (long)truncsize
/2);
507 printCString(out
, converter
, msg
, -1);
510 if(U_SUCCESS(*status
)) {
511 static const UChar openStr
[] = { 0x003A, 0x0061, 0x006C, 0x0069, 0x0061, 0x0073, 0x0020, 0x007B, 0x0020, 0x0022 }; /* ":alias { \"" */
512 static const UChar closeStr
[] = { 0x0022, 0x0020, 0x007D, 0x0020 }; /* "\" } " */
513 printIndent(out
, converter
, indent
);
515 printCString(out
, converter
, key
, -1);
517 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
518 printString(out
, converter
, string
, len
);
519 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
521 printCString(out
, converter
, " // ALIAS", -1);
523 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
525 reportError(pname
, status
, "getting binary value");
529 static void printOutBundle(FILE *out
, UConverter
*converter
, UResourceBundle
*resource
, int32_t indent
, const char *pname
, UErrorCode
*status
)
531 static const UChar cr
[] = { '\n' };
533 /* int32_t noOfElements = ures_getSize(resource);*/
535 const char *key
= ures_getKey(resource
);
537 switch(ures_getType(resource
)) {
541 const UChar
* thestr
= ures_getString(resource
, &len
, status
);
542 UChar
*string
= quotedString(thestr
);
544 /* TODO: String truncation */
545 if(trunc
&& len
> truncsize
) {
547 printIndent(out
, converter
, indent
);
548 sprintf(msg
, "// WARNING: this resource, size %li is truncated to %li\n",
549 (long)len
, (long)(truncsize
/2));
550 printCString(out
, converter
, msg
, -1);
553 printIndent(out
, converter
, indent
);
555 static const UChar openStr
[] = { 0x0020, 0x007B, 0x0020, 0x0022 }; /* " { \"" */
556 static const UChar closeStr
[] = { 0x0022, 0x0020, 0x007D }; /* "\" }" */
557 printCString(out
, converter
, key
, (int32_t)uprv_strlen(key
));
558 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
)/sizeof(*openStr
)));
559 printString(out
, converter
, string
, len
);
560 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
562 static const UChar openStr
[] = { 0x0022 }; /* "\"" */
563 static const UChar closeStr
[] = { 0x0022, 0x002C }; /* "\"," */
565 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
566 printString(out
, converter
, string
, (int32_t)(u_strlen(string
)));
567 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
571 printCString(out
, converter
, "// STRING", -1);
573 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
581 static const UChar openStr
[] = { 0x003A, 0x0069, 0x006E, 0x0074, 0x0020, 0x007B, 0x0020 }; /* ":int { " */
582 static const UChar closeStr
[] = { 0x0020, 0x007D }; /* " }" */
585 printIndent(out
, converter
, indent
);
587 printCString(out
, converter
, key
, -1);
589 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
590 uprv_itou(num
, 20, ures_getInt(resource
, status
), 10, 0);
591 printString(out
, converter
, num
, u_strlen(num
));
592 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
595 printCString(out
, converter
, "// INT", -1);
597 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
603 const int8_t *data
= (const int8_t *)ures_getBinary(resource
, &len
, status
);
604 if(trunc
&& len
> truncsize
) {
606 printIndent(out
, converter
, indent
);
607 sprintf(msg
, "// WARNING: this resource, size %li is truncated to %li\n",
608 (long)len
, (long)(truncsize
/2));
609 printCString(out
, converter
, msg
, -1);
612 if(U_SUCCESS(*status
)) {
613 static const UChar openStr
[] = { 0x003A, 0x0062, 0x0069, 0x006E, 0x0061, 0x0072, 0x0079, 0x0020, 0x007B, 0x0020 }; /* ":binary { " */
614 static const UChar closeStr
[] = { 0x0020, 0x007D, 0x0020 }; /* " } " */
615 printIndent(out
, converter
, indent
);
617 printCString(out
, converter
, key
, -1);
619 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
620 for(i
= 0; i
<len
; i
++) {
621 printHex(out
, converter
, *data
++);
623 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
625 printCString(out
, converter
, " // BINARY", -1);
627 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
629 reportError(pname
, status
, "getting binary value");
633 case RES_INT_VECTOR
:
636 const int32_t *data
= ures_getIntVector(resource
, &len
, status
);
637 if(U_SUCCESS(*status
)) {
638 static const UChar openStr
[] = { 0x003A, 0x0069, 0x006E, 0x0074, 0x0076, 0x0065, 0x0063, 0x0074, 0x006F, 0x0072, 0x0020, 0x007B, 0x0020 }; /* ":intvector { " */
639 static const UChar closeStr
[] = { 0x0020, 0x007D, 0x0020 }; /* " } " */
642 printIndent(out
, converter
, indent
);
644 printCString(out
, converter
, key
, -1);
646 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
647 for(i
= 0; i
< len
- 1; i
++) {
648 int32_t numLen
= uprv_itou(num
, 20, data
[i
], 10, 0);
649 num
[numLen
++] = 0x002C; /* ',' */
650 num
[numLen
++] = 0x0020; /* ' ' */
652 printString(out
, converter
, num
, u_strlen(num
));
655 uprv_itou(num
, 20, data
[len
- 1], 10, 0);
656 printString(out
, converter
, num
, u_strlen(num
));
658 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
660 printCString(out
, converter
, "// INTVECTOR", -1);
662 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
664 reportError(pname
, status
, "getting int vector");
671 static const UChar openStr
[] = { 0x007B }; /* "{" */
672 static const UChar closeStr
[] = { 0x007D, '\n' }; /* "}\n" */
674 UResourceBundle
*t
= NULL
;
675 ures_resetIterator(resource
);
676 printIndent(out
, converter
, indent
);
678 printCString(out
, converter
, key
, -1);
680 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
682 if(ures_getType(resource
) == RES_TABLE
) {
683 printCString(out
, converter
, "// TABLE", -1);
685 printCString(out
, converter
, "// ARRAY", -1);
688 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
690 if(suppressAliases
== FALSE
) {
691 while(U_SUCCESS(*status
) && ures_hasNext(resource
)) {
692 t
= ures_getNextResource(resource
, t
, status
);
693 if(U_SUCCESS(*status
)) {
694 printOutBundle(out
, converter
, t
, indent
+indentsize
, pname
, status
);
696 reportError(pname
, status
, "While processing table");
697 *status
= U_ZERO_ERROR
;
700 } else { /* we have to use low level access to do this */
701 Resource r
= RES_BOGUS
;
702 for(i
= 0; i
< ures_getSize(resource
); i
++) {
703 /* need to know if it's an alias */
704 if(ures_getType(resource
) == RES_TABLE
) {
705 r
= derb_getTableItem(resource
->fResData
.pRoot
, resource
->fRes
, (int16_t)i
);
706 key
= derb_getTableKey(resource
->fResData
.pRoot
, resource
->fRes
, (int16_t)i
);
708 r
= derb_getArrayItem(resource
->fResData
.pRoot
, resource
->fRes
, i
);
710 if(U_SUCCESS(*status
)) {
711 if(RES_GET_TYPE(r
) == RES_ALIAS
) {
712 printOutAlias(out
, converter
, resource
, r
, key
, indent
+indentsize
, pname
, status
);
714 t
= ures_getByIndex(resource
, i
, t
, status
);
715 printOutBundle(out
, converter
, t
, indent
+indentsize
, pname
, status
);
718 reportError(pname
, status
, "While processing table");
719 *status
= U_ZERO_ERROR
;
724 printIndent(out
, converter
, indent
);
725 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
735 static const char *getEncodingName(const char *encoding
) {
740 if (!(enc
= ucnv_getStandardName(encoding
, "MIME", &err
))) {
742 if (!(enc
= ucnv_getStandardName(encoding
, "IANA", &err
))) {
750 static void reportError(const char *pname
, UErrorCode
*status
, const char *when
) {
751 fprintf(stderr
, "%s: error %d while %s: %s\n", pname
, *status
, when
, u_errorName(*status
));
756 * indent-tabs-mode: nil