2 *******************************************************************************
4 * Copyright (C) 1999-2013, 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"
21 #include "unicode/ustdio.h"
30 #if !UCONFIG_NO_FORMATTING
32 #define DERB_VERSION "1.1"
34 #define DERB_DEFAULT_TRUNC 80
36 static const int32_t indentsize
= 4;
37 static int32_t truncsize
= DERB_DEFAULT_TRUNC
;
38 static UBool opt_truncate
= FALSE
;
40 static const char *getEncodingName(const char *encoding
);
41 static void reportError(const char *pname
, UErrorCode
*status
, const char *when
);
42 static UChar
*quotedString(const UChar
*string
);
43 static void printOutBundle(UFILE
*out
, UConverter
*converter
, UResourceBundle
*resource
, int32_t indent
, const char *pname
, UErrorCode
*status
);
44 static void printString(UFILE
*out
, UConverter
*converter
, const UChar
*str
, int32_t len
);
45 static void printCString(UFILE
*out
, UConverter
*converter
, const char *str
, int32_t len
);
46 static void printIndent(UFILE
*out
, UConverter
*converter
, int32_t indent
);
47 static void printHex(UFILE
*out
, UConverter
*converter
, uint8_t what
);
49 static UOption options
[]={
51 UOPTION_HELP_QUESTION_MARK
,
52 /* 2 */ UOPTION_ENCODING
,
53 /* 3 */ { "to-stdout", NULL
, NULL
, NULL
, 'c', UOPT_NO_ARG
, 0 } ,
54 /* 4 */ { "truncate", NULL
, NULL
, NULL
, 't', UOPT_OPTIONAL_ARG
, 0 },
55 /* 5 */ UOPTION_VERBOSE
,
56 /* 6 */ UOPTION_DESTDIR
,
57 /* 7 */ UOPTION_SOURCEDIR
,
58 /* 8 */ { "bom", NULL
, NULL
, NULL
, 0, UOPT_NO_ARG
, 0 },
59 /* 9 */ UOPTION_ICUDATADIR
,
60 /* 10 */ UOPTION_VERSION
,
61 /* 11 */ { "suppressAliases", NULL
, NULL
, NULL
, 'A', UOPT_NO_ARG
, 0 },
64 static UBool verbose
= FALSE
;
65 static UBool suppressAliases
= FALSE
;
66 static UFILE
*ustderr
= NULL
;
69 main(int argc
, char* argv
[]) {
70 const char *encoding
= NULL
;
71 const char *outputDir
= NULL
; /* NULL = no output directory, use current */
72 const char *inputDir
= ".";
78 UResourceBundle
*bundle
= NULL
;
79 UErrorCode status
= U_ZERO_ERROR
;
82 UConverter
*converter
= NULL
; // not used
86 /* Get the name of tool. */
87 pname
= uprv_strrchr(*argv
, U_FILE_SEP_CHAR
);
88 #if U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR
90 pname
= uprv_strrchr(*argv
, U_FILE_ALT_SEP_CHAR
);
99 /* error handling, printing usage message */
100 argc
=u_parseArgs(argc
, argv
, sizeof(options
)/sizeof(options
[0]), options
);
102 /* error handling, printing usage message */
105 "%s: error in command line argument \"%s\"\n", pname
,
108 if(argc
<0 || options
[0].doesOccur
|| options
[1].doesOccur
) {
109 fprintf(argc
< 0 ? stderr
: stdout
,
110 "%csage: %s [ -h, -?, --help ] [ -V, --version ]\n"
111 " [ -v, --verbose ] [ -e, --encoding encoding ] [ --bom ]\n"
112 " [ -t, --truncate [ size ] ]\n"
113 " [ -s, --sourcedir source ] [ -d, --destdir destination ]\n"
114 " [ -i, --icudatadir directory ] [ -c, --to-stdout ]\n"
115 " [ -A, --suppressAliases]\n"
116 " bundle ...\n", argc
< 0 ? 'u' : 'U',
118 return argc
<0 ? U_ILLEGAL_ARGUMENT_ERROR
: U_ZERO_ERROR
;
121 if(options
[10].doesOccur
) {
123 "%s version %s (ICU version %s).\n"
125 pname
, DERB_VERSION
, U_ICU_VERSION
, U_COPYRIGHT_STRING
);
128 if(options
[2].doesOccur
) {
129 encoding
= options
[2].value
;
132 if (options
[3].doesOccur
) {
133 if(options
[2].doesOccur
) {
134 fprintf(stderr
, "%s: Error: don't specify an encoding (-e) when writing to stdout (-c).\n", pname
);
140 if(options
[4].doesOccur
) {
142 if(options
[4].value
!= NULL
) {
143 truncsize
= atoi(options
[4].value
); /* user defined printable size */
145 truncsize
= DERB_DEFAULT_TRUNC
; /* we'll use default omitting size */
148 opt_truncate
= FALSE
;
151 if(options
[5].doesOccur
) {
155 if (options
[6].doesOccur
) {
156 outputDir
= options
[6].value
;
159 if(options
[7].doesOccur
) {
160 inputDir
= options
[7].value
; /* we'll use users resources */
163 if (options
[8].doesOccur
) {
167 if (options
[9].doesOccur
) {
168 u_setDataDirectory(options
[9].value
);
171 if (options
[11].doesOccur
) {
172 suppressAliases
= TRUE
;
175 fflush(stderr
); // use ustderr now.
176 ustderr
= u_finit(stderr
, NULL
, NULL
);
178 for (i
= 1; i
< argc
; ++i
) {
179 static const UChar sp
[] = { 0x0020 }; /* " " */
180 char infile
[4096]; /* XXX Sloppy. */
182 const char *thename
= 0, *p
, *q
;
183 UBool fromICUData
= FALSE
;
185 arg
= getLongPathname(argv
[i
]);
188 u_fprintf(ustderr
, "processing bundle \"%s\"\n", argv
[i
]);
191 p
= uprv_strrchr(arg
, U_FILE_SEP_CHAR
);
192 #if U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR
194 p
= uprv_strrchr(arg
, U_FILE_ALT_SEP_CHAR
);
202 q
= uprv_strrchr(p
, '.');
207 uprv_strncpy(locale
, p
, q
- p
);
210 if (!(fromICUData
= !uprv_strcmp(inputDir
, "-"))) {
211 UBool absfilename
= *arg
== U_FILE_SEP_CHAR
;
212 #if U_PLATFORM_HAS_WIN32_API
214 absfilename
= (uprv_strlen(arg
) > 2 && isalpha(arg
[0])
215 && arg
[1] == ':' && arg
[2] == U_FILE_SEP_CHAR
);
221 q
= uprv_strrchr(arg
, U_FILE_SEP_CHAR
);
222 #if U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR
224 q
= uprv_strrchr(arg
, U_FILE_ALT_SEP_CHAR
);
227 uprv_strcpy(infile
, inputDir
);
229 uprv_strcat(infile
, U_FILE_SEP_STRING
);
230 strncat(infile
, arg
, q
-arg
);
235 status
= U_ZERO_ERROR
;
237 bundle
= ures_openDirect(thename
, locale
, &status
);
239 bundle
= ures_open(fromICUData
? 0 : inputDir
, locale
, &status
);
241 if (status
== U_ZERO_ERROR
) {
244 const char *filename
= 0;
247 if (!locale
[0] || !tostdout
) {
248 filename
= uprv_strrchr(arg
, U_FILE_SEP_CHAR
);
250 #if U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR
252 filename
= uprv_strrchr(arg
, U_FILE_ALT_SEP_CHAR
);
260 ext
= uprv_strrchr(arg
, '.');
262 ext
= filename
+ uprv_strlen(filename
);
267 out
= u_get_stdout();
269 char thefile
[4096], *tp
;
273 uprv_strcpy(thefile
, outputDir
);
274 uprv_strcat(thefile
, U_FILE_SEP_STRING
);
278 uprv_strcat(thefile
, filename
);
279 tp
= thefile
+ uprv_strlen(thefile
);
280 len
= (int32_t)uprv_strlen(ext
);
286 uprv_strcpy(tp
, "txt");
288 out
= u_fopen(thefile
, "w", NULL
, encoding
);
290 u_fprintf(ustderr
, "%s: couldn't create %s\n", pname
, thefile
);
296 // now, set the callback.
297 ucnv_setFromUCallBack(u_fgetConverter(out
), UCNV_FROM_U_CALLBACK_ESCAPE
, UCNV_ESCAPE_C
, 0, 0, &status
);
298 if (U_FAILURE(status
)) {
299 u_fprintf(ustderr
, "%s: couldn't configure converter for encoding\n", pname
);
307 if (prbom
) { /* XXX: Should be done only for UTFs */
308 u_fputc(0xFEFF, out
);
310 u_fprintf(out
, "// -*- Coding: %s; -*-\n//\n", encoding
? encoding
: getEncodingName(ucnv_getDefaultName()));
311 u_fprintf(out
, "// This file was dumped by derb(8) from ");
313 u_fprintf(out
, "%s", thename
);
314 } else if (fromICUData
) {
315 u_fprintf(out
, "the ICU internal %s locale", locale
);
318 u_fprintf(out
, "\n// derb(8) by Vladimir Weinstein and Yves Arrouye\n\n");
321 u_fprintf(out
, "%s", locale
);
323 u_fprintf(out
, "%.*s%.*S", (int32_t)(ext
- filename
), filename
, (int32_t)(sizeof(sp
)/sizeof(*sp
)), sp
);
325 printOutBundle(out
, converter
, bundle
, 0, pname
, &status
);
332 reportError(pname
, &status
, "opening resource file");
338 ucnv_close(converter
);
343 static UChar
*quotedString(const UChar
*string
) {
344 int len
= u_strlen(string
);
349 for (sp
= string
; *sp
; ++sp
) {
358 newstr
= (UChar
*) uprv_malloc((1 + alen
) * sizeof(*newstr
));
359 for (sp
= string
, np
= newstr
; *sp
; ++sp
) {
380 static void printString(UFILE
*out
, UConverter
*converter
, const UChar
*str
, int32_t len
) {
381 u_file_write(str
, len
, out
);
384 static void printCString(UFILE
*out
, UConverter
*converter
, const char *str
, int32_t len
) {
386 u_fprintf(out
, "%s", str
);
388 u_fprintf(out
, "%.*s", len
, str
);
392 static void printIndent(UFILE
*out
, UConverter
*converter
, int32_t indent
) {
395 for(i
= 0; i
<indent
; i
++) {
400 printString(out
, converter
, inchar
, indent
);
403 static void printHex(UFILE
*out
, UConverter
*converter
, uint8_t what
) {
404 static const char map
[] = "0123456789ABCDEF";
407 hex
[0] = map
[what
>> 4];
408 hex
[1] = map
[what
& 0xf];
410 printString(out
, converter
, hex
, (int32_t)(sizeof(hex
)/sizeof(*hex
)));
413 static void printOutAlias(UFILE
*out
, UConverter
*converter
, UResourceBundle
*parent
, Resource r
, const char *key
, int32_t indent
, const char *pname
, UErrorCode
*status
) {
414 static const UChar cr
[] = { '\n' };
416 const UChar
* thestr
= res_getAlias(&(parent
->fResData
), r
, &len
);
417 UChar
*string
= quotedString(thestr
);
418 if(opt_truncate
&& len
> truncsize
) {
420 printIndent(out
, converter
, indent
);
421 sprintf(msg
, "// WARNING: this resource, size %li is truncated to %li\n",
422 (long)len
, (long)truncsize
/2);
423 printCString(out
, converter
, msg
, -1);
426 if(U_SUCCESS(*status
)) {
427 static const UChar openStr
[] = { 0x003A, 0x0061, 0x006C, 0x0069, 0x0061, 0x0073, 0x0020, 0x007B, 0x0020, 0x0022 }; /* ":alias { \"" */
428 static const UChar closeStr
[] = { 0x0022, 0x0020, 0x007D, 0x0020 }; /* "\" } " */
429 printIndent(out
, converter
, indent
);
431 printCString(out
, converter
, key
, -1);
433 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
434 printString(out
, converter
, string
, len
);
435 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
437 printCString(out
, converter
, " // ALIAS", -1);
439 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
441 reportError(pname
, status
, "getting binary value");
446 static void printOutBundle(UFILE
*out
, UConverter
*converter
, UResourceBundle
*resource
, int32_t indent
, const char *pname
, UErrorCode
*status
)
448 static const UChar cr
[] = { '\n' };
450 /* int32_t noOfElements = ures_getSize(resource);*/
452 const char *key
= ures_getKey(resource
);
454 switch(ures_getType(resource
)) {
458 const UChar
* thestr
= ures_getString(resource
, &len
, status
);
459 UChar
*string
= quotedString(thestr
);
461 /* TODO: String truncation */
462 if(opt_truncate
&& len
> truncsize
) {
464 printIndent(out
, converter
, indent
);
465 sprintf(msg
, "// WARNING: this resource, size %li is truncated to %li\n",
466 (long)len
, (long)(truncsize
/2));
467 printCString(out
, converter
, msg
, -1);
470 printIndent(out
, converter
, indent
);
472 static const UChar openStr
[] = { 0x0020, 0x007B, 0x0020, 0x0022 }; /* " { \"" */
473 static const UChar closeStr
[] = { 0x0022, 0x0020, 0x007D }; /* "\" }" */
474 printCString(out
, converter
, key
, (int32_t)uprv_strlen(key
));
475 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
)/sizeof(*openStr
)));
476 printString(out
, converter
, string
, len
);
477 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
479 static const UChar openStr
[] = { 0x0022 }; /* "\"" */
480 static const UChar closeStr
[] = { 0x0022, 0x002C }; /* "\"," */
482 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
483 printString(out
, converter
, string
, (int32_t)(u_strlen(string
)));
484 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
488 printCString(out
, converter
, "// STRING", -1);
490 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
498 static const UChar openStr
[] = { 0x003A, 0x0069, 0x006E, 0x0074, 0x0020, 0x007B, 0x0020 }; /* ":int { " */
499 static const UChar closeStr
[] = { 0x0020, 0x007D }; /* " }" */
502 printIndent(out
, converter
, indent
);
504 printCString(out
, converter
, key
, -1);
506 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
507 uprv_itou(num
, 20, ures_getInt(resource
, status
), 10, 0);
508 printString(out
, converter
, num
, u_strlen(num
));
509 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
512 printCString(out
, converter
, "// INT", -1);
514 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
520 const int8_t *data
= (const int8_t *)ures_getBinary(resource
, &len
, status
);
521 if(opt_truncate
&& len
> truncsize
) {
523 printIndent(out
, converter
, indent
);
524 sprintf(msg
, "// WARNING: this resource, size %li is truncated to %li\n",
525 (long)len
, (long)(truncsize
/2));
526 printCString(out
, converter
, msg
, -1);
529 if(U_SUCCESS(*status
)) {
530 static const UChar openStr
[] = { 0x003A, 0x0062, 0x0069, 0x006E, 0x0061, 0x0072, 0x0079, 0x0020, 0x007B, 0x0020 }; /* ":binary { " */
531 static const UChar closeStr
[] = { 0x0020, 0x007D, 0x0020 }; /* " } " */
532 printIndent(out
, converter
, indent
);
534 printCString(out
, converter
, key
, -1);
536 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
537 for(i
= 0; i
<len
; i
++) {
538 printHex(out
, converter
, *data
++);
540 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
542 printCString(out
, converter
, " // BINARY", -1);
544 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
546 reportError(pname
, status
, "getting binary value");
550 case URES_INT_VECTOR
:
553 const int32_t *data
= ures_getIntVector(resource
, &len
, status
);
554 if(U_SUCCESS(*status
)) {
555 static const UChar openStr
[] = { 0x003A, 0x0069, 0x006E, 0x0074, 0x0076, 0x0065, 0x0063, 0x0074, 0x006F, 0x0072, 0x0020, 0x007B, 0x0020 }; /* ":intvector { " */
556 static const UChar closeStr
[] = { 0x0020, 0x007D, 0x0020 }; /* " } " */
559 printIndent(out
, converter
, indent
);
561 printCString(out
, converter
, key
, -1);
563 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
564 for(i
= 0; i
< len
- 1; i
++) {
565 int32_t numLen
= uprv_itou(num
, 20, data
[i
], 10, 0);
566 num
[numLen
++] = 0x002C; /* ',' */
567 num
[numLen
++] = 0x0020; /* ' ' */
569 printString(out
, converter
, num
, u_strlen(num
));
572 uprv_itou(num
, 20, data
[len
- 1], 10, 0);
573 printString(out
, converter
, num
, u_strlen(num
));
575 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
577 printCString(out
, converter
, "// INTVECTOR", -1);
579 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
581 reportError(pname
, status
, "getting int vector");
588 static const UChar openStr
[] = { 0x007B }; /* "{" */
589 static const UChar closeStr
[] = { 0x007D, '\n' }; /* "}\n" */
591 UResourceBundle
*t
= NULL
;
592 ures_resetIterator(resource
);
593 printIndent(out
, converter
, indent
);
595 printCString(out
, converter
, key
, -1);
597 printString(out
, converter
, openStr
, (int32_t)(sizeof(openStr
) / sizeof(*openStr
)));
599 if(ures_getType(resource
) == URES_TABLE
) {
600 printCString(out
, converter
, "// TABLE", -1);
602 printCString(out
, converter
, "// ARRAY", -1);
605 printString(out
, converter
, cr
, (int32_t)(sizeof(cr
) / sizeof(*cr
)));
607 if(suppressAliases
== FALSE
) {
608 while(U_SUCCESS(*status
) && ures_hasNext(resource
)) {
609 t
= ures_getNextResource(resource
, t
, status
);
610 if(U_SUCCESS(*status
)) {
611 printOutBundle(out
, converter
, t
, indent
+indentsize
, pname
, status
);
613 reportError(pname
, status
, "While processing table");
614 *status
= U_ZERO_ERROR
;
617 } else { /* we have to use low level access to do this */
619 int32_t resSize
= ures_getSize(resource
);
620 UBool isTable
= (UBool
)(ures_getType(resource
) == URES_TABLE
);
621 for(i
= 0; i
< resSize
; i
++) {
622 /* need to know if it's an alias */
624 r
= res_getTableItemByIndex(&resource
->fResData
, resource
->fRes
, i
, &key
);
626 r
= res_getArrayItem(&resource
->fResData
, resource
->fRes
, i
);
628 if(U_SUCCESS(*status
)) {
629 if(res_getPublicType(r
) == URES_ALIAS
) {
630 printOutAlias(out
, converter
, resource
, r
, key
, indent
+indentsize
, pname
, status
);
632 t
= ures_getByIndex(resource
, i
, t
, status
);
633 printOutBundle(out
, converter
, t
, indent
+indentsize
, pname
, status
);
636 reportError(pname
, status
, "While processing table");
637 *status
= U_ZERO_ERROR
;
642 printIndent(out
, converter
, indent
);
643 printString(out
, converter
, closeStr
, (int32_t)(sizeof(closeStr
) / sizeof(*closeStr
)));
653 static const char *getEncodingName(const char *encoding
) {
658 if (!(enc
= ucnv_getStandardName(encoding
, "MIME", &err
))) {
660 if (!(enc
= ucnv_getStandardName(encoding
, "IANA", &err
))) {
668 static void reportError(const char *pname
, UErrorCode
*status
, const char *when
) {
669 u_fprintf(ustderr
, "%s: error %d while %s: %s\n", pname
, *status
, when
, u_errorName(*status
));
674 main(int argc
, char* argv
[]) {
675 /* Changing stdio.h ustdio.h requires that formatting not be disabled. */
678 #endif /* !UCONFIG_NO_FORMATTING */
682 * indent-tabs-mode: nil