1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
6 * Copyright (C) 1999-2016, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 *******************************************************************************
12 * tab size: 8 (not used)
15 * created on: 2000sep6
16 * created by: Vladimir Weinstein as an ICU workshop example
17 * maintained by: Yves Arrouye <yves@realnames.com>
20 #include "unicode/stringpiece.h"
21 #include "unicode/ucnv.h"
22 #include "unicode/unistr.h"
23 #include "unicode/ustring.h"
24 #include "unicode/putil.h"
25 #include "unicode/ustdio.h"
35 #if !UCONFIG_NO_FORMATTING
37 #define DERB_VERSION "1.1"
39 #define DERB_DEFAULT_TRUNC 80
41 static const int32_t indentsize
= 4;
42 static int32_t truncsize
= DERB_DEFAULT_TRUNC
;
43 static UBool opt_truncate
= FALSE
;
45 static const char *getEncodingName(const char *encoding
);
46 static void reportError(const char *pname
, UErrorCode
*status
, const char *when
);
47 static UChar
*quotedString(const UChar
*string
);
48 static void printOutBundle(UFILE
*out
, UResourceBundle
*resource
, int32_t indent
, const char *pname
, UErrorCode
*status
);
49 static void printString(UFILE
*out
, const UChar
*str
, int32_t len
);
50 static void printCString(UFILE
*out
, const char *str
, int32_t len
);
51 static void printIndent(UFILE
*out
, int32_t indent
);
52 static void printHex(UFILE
*out
, uint8_t what
);
54 static UOption options
[]={
56 UOPTION_HELP_QUESTION_MARK
,
57 /* 2 */ UOPTION_ENCODING
,
58 /* 3 */ { "to-stdout", NULL
, NULL
, NULL
, 'c', UOPT_NO_ARG
, 0 } ,
59 /* 4 */ { "truncate", NULL
, NULL
, NULL
, 't', UOPT_OPTIONAL_ARG
, 0 },
60 /* 5 */ UOPTION_VERBOSE
,
61 /* 6 */ UOPTION_DESTDIR
,
62 /* 7 */ UOPTION_SOURCEDIR
,
63 /* 8 */ { "bom", NULL
, NULL
, NULL
, 0, UOPT_NO_ARG
, 0 },
64 /* 9 */ UOPTION_ICUDATADIR
,
65 /* 10 */ UOPTION_VERSION
,
66 /* 11 */ { "suppressAliases", NULL
, NULL
, NULL
, 'A', UOPT_NO_ARG
, 0 },
69 static UBool verbose
= FALSE
;
70 static UBool suppressAliases
= FALSE
;
71 static UFILE
*ustderr
= NULL
;
74 main(int argc
, char* argv
[]) {
75 const char *encoding
= NULL
;
76 const char *outputDir
= NULL
; /* NULL = no output directory, use current */
77 const char *inputDir
= ".";
83 UResourceBundle
*bundle
= NULL
;
88 /* Get the name of tool. */
89 pname
= uprv_strrchr(*argv
, U_FILE_SEP_CHAR
);
90 #if U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR
92 pname
= uprv_strrchr(*argv
, U_FILE_ALT_SEP_CHAR
);
101 /* error handling, printing usage message */
102 argc
=u_parseArgs(argc
, argv
, UPRV_LENGTHOF(options
), options
);
104 /* error handling, printing usage message */
107 "%s: error in command line argument \"%s\"\n", pname
,
110 if(argc
<0 || options
[0].doesOccur
|| options
[1].doesOccur
) {
111 fprintf(argc
< 0 ? stderr
: stdout
,
112 "%csage: %s [ -h, -?, --help ] [ -V, --version ]\n"
113 " [ -v, --verbose ] [ -e, --encoding encoding ] [ --bom ]\n"
114 " [ -t, --truncate [ size ] ]\n"
115 " [ -s, --sourcedir source ] [ -d, --destdir destination ]\n"
116 " [ -i, --icudatadir directory ] [ -c, --to-stdout ]\n"
117 " [ -A, --suppressAliases]\n"
118 " bundle ...\n", argc
< 0 ? 'u' : 'U',
120 return argc
<0 ? U_ILLEGAL_ARGUMENT_ERROR
: U_ZERO_ERROR
;
123 if(options
[10].doesOccur
) {
125 "%s version %s (ICU version %s).\n"
127 pname
, DERB_VERSION
, U_ICU_VERSION
, U_COPYRIGHT_STRING
);
130 if(options
[2].doesOccur
) {
131 encoding
= options
[2].value
;
134 if (options
[3].doesOccur
) {
135 if(options
[2].doesOccur
) {
136 fprintf(stderr
, "%s: Error: don't specify an encoding (-e) when writing to stdout (-c).\n", pname
);
142 if(options
[4].doesOccur
) {
144 if(options
[4].value
!= NULL
) {
145 truncsize
= atoi(options
[4].value
); /* user defined printable size */
147 truncsize
= DERB_DEFAULT_TRUNC
; /* we'll use default omitting size */
150 opt_truncate
= FALSE
;
153 if(options
[5].doesOccur
) {
157 if (options
[6].doesOccur
) {
158 outputDir
= options
[6].value
;
161 if(options
[7].doesOccur
) {
162 inputDir
= options
[7].value
; /* we'll use users resources */
165 if (options
[8].doesOccur
) {
169 if (options
[9].doesOccur
) {
170 u_setDataDirectory(options
[9].value
);
173 if (options
[11].doesOccur
) {
174 suppressAliases
= TRUE
;
177 fflush(stderr
); // use ustderr now.
178 ustderr
= u_finit(stderr
, NULL
, NULL
);
180 for (i
= 1; i
< argc
; ++i
) {
181 static const UChar sp
[] = { 0x0020 }; /* " " */
183 arg
= getLongPathname(argv
[i
]);
186 u_fprintf(ustderr
, "processing bundle \"%s\"\n", argv
[i
]);
189 icu::CharString locale
;
190 UErrorCode status
= U_ZERO_ERROR
;
192 const char *p
= findBasename(arg
);
193 const char *q
= uprv_strrchr(p
, '.');
195 locale
.append(p
, status
);
197 locale
.append(p
, (int32_t)(q
- p
), status
);
200 if (U_FAILURE(status
)) {
204 icu::CharString infile
;
205 const char *thename
= NULL
;
206 UBool fromICUData
= !uprv_strcmp(inputDir
, "-");
208 UBool absfilename
= *arg
== U_FILE_SEP_CHAR
;
209 #if U_PLATFORM_HAS_WIN32_API
211 absfilename
= (uprv_strlen(arg
) > 2 && isalpha(arg
[0])
212 && arg
[1] == ':' && arg
[2] == U_FILE_SEP_CHAR
);
218 const char *q
= uprv_strrchr(arg
, U_FILE_SEP_CHAR
);
219 #if U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR
221 q
= uprv_strrchr(arg
, U_FILE_ALT_SEP_CHAR
);
224 infile
.append(inputDir
, status
);
226 infile
.appendPathPart(icu::StringPiece(arg
, (int32_t)(q
- arg
)), status
);
228 if (U_FAILURE(status
)) {
231 thename
= infile
.data();
235 bundle
= ures_openDirect(thename
, locale
.data(), &status
);
237 bundle
= ures_open(fromICUData
? 0 : inputDir
, locale
.data(), &status
);
239 if (U_SUCCESS(status
)) {
242 const char *filename
= 0;
245 if (locale
.isEmpty() || !tostdout
) {
246 filename
= findBasename(arg
);
247 ext
= uprv_strrchr(filename
, '.');
249 ext
= uprv_strchr(filename
, 0);
254 out
= u_get_stdout();
256 icu::CharString thefile
;
258 thefile
.append(outputDir
, status
);
260 thefile
.appendPathPart(filename
, status
);
262 thefile
.truncate(thefile
.length() - (int32_t)uprv_strlen(ext
));
264 thefile
.append(".txt", status
);
265 if (U_FAILURE(status
)) {
269 out
= u_fopen(thefile
.data(), "w", NULL
, encoding
);
271 u_fprintf(ustderr
, "%s: couldn't create %s\n", pname
, thefile
.data());
277 // now, set the callback.
278 ucnv_setFromUCallBack(u_fgetConverter(out
), UCNV_FROM_U_CALLBACK_ESCAPE
, UCNV_ESCAPE_C
, 0, 0, &status
);
279 if (U_FAILURE(status
)) {
280 u_fprintf(ustderr
, "%s: couldn't configure converter for encoding\n", pname
);
288 if (prbom
) { /* XXX: Should be done only for UTFs */
289 u_fputc(0xFEFF, out
);
291 u_fprintf(out
, "// -*- Coding: %s; -*-\n//\n", encoding
? encoding
: getEncodingName(ucnv_getDefaultName()));
292 u_fprintf(out
, "// This file was dumped by derb(8) from ");
294 u_fprintf(out
, "%s", thename
);
295 } else if (fromICUData
) {
296 u_fprintf(out
, "the ICU internal %s locale", locale
.data());
299 u_fprintf(out
, "\n// derb(8) by Vladimir Weinstein and Yves Arrouye\n\n");
301 if (!locale
.isEmpty()) {
302 u_fprintf(out
, "%s", locale
.data());
304 u_fprintf(out
, "%.*s%.*S", (int32_t)(ext
- filename
), filename
, UPRV_LENGTHOF(sp
), sp
);
306 printOutBundle(out
, bundle
, 0, pname
, &status
);
313 reportError(pname
, &status
, "opening resource file");
322 static UChar
*quotedString(const UChar
*string
) {
323 int len
= u_strlen(string
);
328 for (sp
= string
; *sp
; ++sp
) {
337 newstr
= (UChar
*) uprv_malloc((1 + alen
) * U_SIZEOF_UCHAR
);
338 for (sp
= string
, np
= newstr
; *sp
; ++sp
) {
359 static void printString(UFILE
*out
, const UChar
*str
, int32_t len
) {
360 u_file_write(str
, len
, out
);
363 static void printCString(UFILE
*out
, const char *str
, int32_t len
) {
365 u_fprintf(out
, "%s", str
);
367 u_fprintf(out
, "%.*s", len
, str
);
371 static void printIndent(UFILE
*out
, int32_t indent
) {
372 icu::UnicodeString
inchar(indent
, 0x20, indent
);
373 printString(out
, (const UChar
*)inchar
.getBuffer(), indent
);
376 static void printHex(UFILE
*out
, uint8_t what
) {
377 static const char map
[] = "0123456789ABCDEF";
380 hex
[0] = map
[what
>> 4];
381 hex
[1] = map
[what
& 0xf];
383 printString(out
, hex
, 2);
386 static void printOutAlias(UFILE
*out
, UResourceBundle
*parent
, Resource r
, const char *key
, int32_t indent
, const char *pname
, UErrorCode
*status
) {
387 static const UChar cr
[] = { 0xA }; // LF
389 const UChar
* thestr
= res_getAlias(&(parent
->fResData
), r
, &len
);
390 UChar
*string
= quotedString(thestr
);
391 if(opt_truncate
&& len
> truncsize
) {
393 printIndent(out
, indent
);
394 sprintf(msg
, "// WARNING: this resource, size %li is truncated to %li\n",
395 (long)len
, (long)truncsize
/2);
396 printCString(out
, msg
, -1);
399 if(U_SUCCESS(*status
)) {
400 static const UChar openStr
[] = { 0x003A, 0x0061, 0x006C, 0x0069, 0x0061, 0x0073, 0x0020, 0x007B, 0x0020, 0x0022 }; /* ":alias { \"" */
401 static const UChar closeStr
[] = { 0x0022, 0x0020, 0x007D, 0x0020 }; /* "\" } " */
402 printIndent(out
, indent
);
404 printCString(out
, key
, -1);
406 printString(out
, openStr
, UPRV_LENGTHOF(openStr
));
407 printString(out
, string
, len
);
408 printString(out
, closeStr
, UPRV_LENGTHOF(closeStr
));
410 printCString(out
, " // ALIAS", -1);
412 printString(out
, cr
, UPRV_LENGTHOF(cr
));
414 reportError(pname
, status
, "getting binary value");
419 static void printOutBundle(UFILE
*out
, UResourceBundle
*resource
, int32_t indent
, const char *pname
, UErrorCode
*status
)
421 static const UChar cr
[] = { 0xA }; // LF
423 /* int32_t noOfElements = ures_getSize(resource);*/
425 const char *key
= ures_getKey(resource
);
427 switch(ures_getType(resource
)) {
431 const UChar
* thestr
= ures_getString(resource
, &len
, status
);
432 UChar
*string
= quotedString(thestr
);
434 /* TODO: String truncation */
435 if(opt_truncate
&& len
> truncsize
) {
437 printIndent(out
, indent
);
438 sprintf(msg
, "// WARNING: this resource, size %li is truncated to %li\n",
439 (long)len
, (long)(truncsize
/2));
440 printCString(out
, msg
, -1);
443 printIndent(out
, indent
);
445 static const UChar openStr
[] = { 0x0020, 0x007B, 0x0020, 0x0022 }; /* " { \"" */
446 static const UChar closeStr
[] = { 0x0022, 0x0020, 0x007D }; /* "\" }" */
447 printCString(out
, key
, (int32_t)uprv_strlen(key
));
448 printString(out
, openStr
, UPRV_LENGTHOF(openStr
));
449 printString(out
, string
, len
);
450 printString(out
, closeStr
, UPRV_LENGTHOF(closeStr
));
452 static const UChar openStr
[] = { 0x0022 }; /* "\"" */
453 static const UChar closeStr
[] = { 0x0022, 0x002C }; /* "\"," */
455 printString(out
, openStr
, UPRV_LENGTHOF(openStr
));
456 printString(out
, string
, (int32_t)(u_strlen(string
)));
457 printString(out
, closeStr
, UPRV_LENGTHOF(closeStr
));
461 printCString(out
, "// STRING", -1);
463 printString(out
, cr
, UPRV_LENGTHOF(cr
));
471 static const UChar openStr
[] = { 0x003A, 0x0069, 0x006E, 0x0074, 0x0020, 0x007B, 0x0020 }; /* ":int { " */
472 static const UChar closeStr
[] = { 0x0020, 0x007D }; /* " }" */
475 printIndent(out
, indent
);
477 printCString(out
, key
, -1);
479 printString(out
, openStr
, UPRV_LENGTHOF(openStr
));
480 uprv_itou(num
, 20, ures_getInt(resource
, status
), 10, 0);
481 printString(out
, num
, u_strlen(num
));
482 printString(out
, closeStr
, UPRV_LENGTHOF(closeStr
));
485 printCString(out
, "// INT", -1);
487 printString(out
, cr
, UPRV_LENGTHOF(cr
));
493 const int8_t *data
= (const int8_t *)ures_getBinary(resource
, &len
, status
);
494 if(opt_truncate
&& len
> truncsize
) {
496 printIndent(out
, indent
);
497 sprintf(msg
, "// WARNING: this resource, size %li is truncated to %li\n",
498 (long)len
, (long)(truncsize
/2));
499 printCString(out
, msg
, -1);
502 if(U_SUCCESS(*status
)) {
503 static const UChar openStr
[] = { 0x003A, 0x0062, 0x0069, 0x006E, 0x0061, 0x0072, 0x0079, 0x0020, 0x007B, 0x0020 }; /* ":binary { " */
504 static const UChar closeStr
[] = { 0x0020, 0x007D, 0x0020 }; /* " } " */
505 printIndent(out
, indent
);
507 printCString(out
, key
, -1);
509 printString(out
, openStr
, UPRV_LENGTHOF(openStr
));
510 for(i
= 0; i
<len
; i
++) {
511 printHex(out
, *data
++);
513 printString(out
, closeStr
, UPRV_LENGTHOF(closeStr
));
515 printCString(out
, " // BINARY", -1);
517 printString(out
, cr
, UPRV_LENGTHOF(cr
));
519 reportError(pname
, status
, "getting binary value");
523 case URES_INT_VECTOR
:
526 const int32_t *data
= ures_getIntVector(resource
, &len
, status
);
527 if(U_SUCCESS(*status
)) {
528 static const UChar openStr
[] = { 0x003A, 0x0069, 0x006E, 0x0074, 0x0076, 0x0065, 0x0063, 0x0074, 0x006F, 0x0072, 0x0020, 0x007B, 0x0020 }; /* ":intvector { " */
529 static const UChar closeStr
[] = { 0x0020, 0x007D, 0x0020 }; /* " } " */
532 printIndent(out
, indent
);
534 printCString(out
, key
, -1);
536 printString(out
, openStr
, UPRV_LENGTHOF(openStr
));
537 for(i
= 0; i
< len
- 1; i
++) {
538 int32_t numLen
= uprv_itou(num
, 20, data
[i
], 10, 0);
539 num
[numLen
++] = 0x002C; /* ',' */
540 num
[numLen
++] = 0x0020; /* ' ' */
542 printString(out
, num
, u_strlen(num
));
545 uprv_itou(num
, 20, data
[len
- 1], 10, 0);
546 printString(out
, num
, u_strlen(num
));
548 printString(out
, closeStr
, UPRV_LENGTHOF(closeStr
));
550 printCString(out
, "// INTVECTOR", -1);
552 printString(out
, cr
, UPRV_LENGTHOF(cr
));
554 reportError(pname
, status
, "getting int vector");
561 static const UChar openStr
[] = { 0x007B }; /* "{" */
562 static const UChar closeStr
[] = { 0x007D, '\n' }; /* "}\n" */
564 UResourceBundle
*t
= NULL
;
565 ures_resetIterator(resource
);
566 printIndent(out
, indent
);
568 printCString(out
, key
, -1);
570 printString(out
, openStr
, UPRV_LENGTHOF(openStr
));
572 if(ures_getType(resource
) == URES_TABLE
) {
573 printCString(out
, "// TABLE", -1);
575 printCString(out
, "// ARRAY", -1);
578 printString(out
, cr
, UPRV_LENGTHOF(cr
));
580 if(suppressAliases
== FALSE
) {
581 while(U_SUCCESS(*status
) && ures_hasNext(resource
)) {
582 t
= ures_getNextResource(resource
, t
, status
);
583 if(U_SUCCESS(*status
)) {
584 printOutBundle(out
, t
, indent
+indentsize
, pname
, status
);
586 reportError(pname
, status
, "While processing table");
587 *status
= U_ZERO_ERROR
;
590 } else { /* we have to use low level access to do this */
592 int32_t resSize
= ures_getSize(resource
);
593 UBool isTable
= (UBool
)(ures_getType(resource
) == URES_TABLE
);
594 for(i
= 0; i
< resSize
; i
++) {
595 /* need to know if it's an alias */
597 r
= res_getTableItemByIndex(&resource
->fResData
, resource
->fRes
, i
, &key
);
599 r
= res_getArrayItem(&resource
->fResData
, resource
->fRes
, i
);
601 if(U_SUCCESS(*status
)) {
602 if(res_getPublicType(r
) == URES_ALIAS
) {
603 printOutAlias(out
, resource
, r
, key
, indent
+indentsize
, pname
, status
);
605 t
= ures_getByIndex(resource
, i
, t
, status
);
606 printOutBundle(out
, t
, indent
+indentsize
, pname
, status
);
609 reportError(pname
, status
, "While processing table");
610 *status
= U_ZERO_ERROR
;
615 printIndent(out
, indent
);
616 printString(out
, closeStr
, UPRV_LENGTHOF(closeStr
));
626 static const char *getEncodingName(const char *encoding
) {
631 if (!(enc
= ucnv_getStandardName(encoding
, "MIME", &err
))) {
633 if (!(enc
= ucnv_getStandardName(encoding
, "IANA", &err
))) {
641 static void reportError(const char *pname
, UErrorCode
*status
, const char *when
) {
642 u_fprintf(ustderr
, "%s: error %d while %s: %s\n", pname
, *status
, when
, u_errorName(*status
));
647 main(int argc
, char* argv
[]) {
648 /* Changing stdio.h ustdio.h requires that formatting not be disabled. */
651 #endif /* !UCONFIG_NO_FORMATTING */
655 * indent-tabs-mode: nil