1 /*************************************************************************
2 *
3 * © 2016 and later: Unicode, Inc. and others.
4 * License & terms of use: http://www.unicode.org/copyright.html
5 *
6 **************************************************************************
7 **************************************************************************
8 *
9 * Copyright (C) 2001-2006, International Business Machines
10 * Corporation and others. All Rights Reserved.
11 *
12 **************************************************************************
13 *
14 * ufortune - An ICU resources sample program
15 *
16 * Demonstrates
17 * Defining resources for use by an application
18 * Compiling and packaging them into a dll
19 * Referencing the resource-containing dll from application code
20 * Loading resource data using ICU's API
21 *
22 * Created Nov. 7, 2001 by Andy Heninger
23 *
24 * ufortune is a variant of the Unix "fortune" command, with
25 * ICU resources that contain the fortune-cookie sayings.
26 * Using resources allows fortunes in different languages to
27 * be selected based on locale.
28 */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <time.h>
34
35 #include "unicode/udata.h" /* ICU API for data handling. */
36 #include "unicode/ures.h" /* ICU API for resource loading */
37 #include "unicode/ustdio.h" /* ICU API for reading & writing Unicode data */
38 /* to files, possibly including character */
39 /* set conversions. */
40 #include "unicode/ustring.h"
41
42 #ifndef UFORTUNE_NOSETAPPDATA
43 /*
44 * Resource Data Reference. The data is packaged as a dll (or .so or
45 * whatever, depending on the platform) that exports a data
46 * symbol. The application (that's us) references that symbol,
47 * here, and will pass the data address to ICU, which will then
48 * be able to fetch resources from the data.
49 */
50 extern const void U_IMPORT *fortune_resources_dat;
51 #endif
52
53 void u_write(const UChar *what, int len);
54
55
56 /*
57 * main() This one function is all of the application code.
58 */
main(int argc,char ** argv)59 int main(int argc, char **argv)
60 {
61 UBool displayUsage = false; /* Set true if command line err or help */
62 /* option was requested. */
63 UBool verbose = false; /* Set true if -v command line option. */
64 char *optionError = NULL; /* If command line contains an unrecognized */
65 /* option, this will point to it. */
66 char *locale=NULL; /* Locale name. Null for system default, */
67 /* otherwise set from command line. */
68 const char * programName = argv[0]; /* Program invocation name. */
69
70
71 UFILE *u_stdout; /* Unicode stdout file. */
72 UErrorCode err = U_ZERO_ERROR; /* Error return, used for most ICU */
73 /* functions. */
74
75 UResourceBundle *myResources; /* ICU Resource "handles" */
76 UResourceBundle *fortunes_r;
77
78 int32_t numFortunes; /* Number of fortune strings available. */
79 int i;
80
81 const UChar *resString; /* Points to strings fetched from Resources. */
82 int32_t len;
83
84
85 /* Process command line options.
86 * -l locale specify a locale
87 * -v verbose mode. Display extra messages.
88 * -? or --help display a usage line
89 */
90 for (i=1; i<argc; i++) {
91 if (strcmp(argv[i], "-l") ==0) {
92 if (++i < argc) {
93 locale = argv[i];
94 }
95 continue;
96 }
97 if (strcmp(argv[i], "-v") == 0) {
98 verbose = true;
99 continue;}
100 if (strcmp(argv[i], "-?") == 0 ||
101 strcmp(argv[i], "--help") == 0) {
102 displayUsage = true;
103 continue;}
104 optionError = argv[i];
105 displayUsage = true;
106 break;
107 }
108
109 /* ICU's icuio package provides a convenient way to write Unicode
110 * data to stdout. The string data that we get from resources
111 * will be UChar * strings, which icuio can handle nicely.
112 */
113 u_stdout = u_finit(stdout, NULL /*locale*/, NULL /*codepage */);
114 if (verbose) {
115 u_fprintf(u_stdout, "%s: checking output via icuio.\n", programName);
116 }
117
118 #ifndef UFORTUNE_NOSETAPPDATA
119 /* Tell ICU where our resource data is located in memory.
120 * The data lives in the Fortune_Resources dll, and we just
121 * pass the address of an exported symbol from that library
122 * to ICU.
123 */
124 udata_setAppData("fortune_resources", &fortune_resources_dat, &err);
125 if (U_FAILURE(err)) {
126 fprintf(stderr, "%s: udata_setAppData failed with error \"%s\"\n", programName, u_errorName(err));
127 exit(-1);
128 }
129 #endif
130
131 /* Open our resources.
132 */
133 myResources = ures_open("fortune_resources", locale, &err);
134 if (U_FAILURE(err)) {
135 fprintf(stderr, "%s: ures_open failed with error \"%s\"\n", programName, u_errorName(err));
136 exit(-1);
137 }
138 if (verbose) {
139 u_fprintf(u_stdout, "status from ures_open(\"fortune_resources\", %s) is %s\n",
140 locale? locale: " ", u_errorName(err));
141 }
142
143 /*
144 * Display any command line option usage errors and/or the
145 * usage help message. These messages come from our resource bundle.
146 */
147 if (optionError != NULL) {
148 const UChar *msg = ures_getStringByKey(myResources, "optionMessage", &len, &err);
149 if (U_FAILURE(err)) {
150 fprintf(stderr, "%s: ures_getStringByKey(\"optionMessage\") failed, %s\n",
151 programName, u_errorName(err));
152 exit(-1);
153 }
154 u_file_write(msg, len, u_stdout); /* msg is UChar *, from resource */
155 u_fprintf(u_stdout, " %s\n", optionError); /* optionError is char *, from argv */
156 }
157
158 if (displayUsage) {
159 const UChar *usage;
160 int returnValue=0;
161
162 usage = ures_getStringByKey(myResources, "usage", &len, &err);
163 if (U_FAILURE(err)) {
164 fprintf(stderr, "%s: ures_getStringByKey(\"usage\") failed, %s\n", programName, u_errorName(err));
165 exit(-1);
166 }
167 u_file_write(usage, len, u_stdout);
168 if (optionError != NULL) {returnValue = -1;}
169 return returnValue;
170 }
171
172 /*
173 * Open the "fortunes" resources from within the already open resources
174 */
175 fortunes_r = ures_getByKey(myResources, "fortunes", NULL, &err);
176 if (U_FAILURE(err)) {
177 fprintf(stderr, "%s: ures_getByKey(\"fortunes\") failed, %s\n", programName, u_errorName(err));
178 exit(-1);
179 }
180
181
182 /*
183 * Pick up and display a random fortune
184 *
185 */
186 numFortunes = ures_countArrayItems(myResources, "fortunes", &err);
187 if (U_FAILURE(err)) {
188 fprintf(stderr, "%s: ures_countArrayItems(\"fortunes\") failed, %s\n", programName, u_errorName(err));
189 exit(-1);
190 }
191 if (numFortunes <= 0) {
192 fprintf(stderr, "%s: no fortunes found.\n", programName);
193 exit(-1);
194 }
195
196 i = time(NULL) % numFortunes; /* Use time to pick a somewhat-random fortune. */
197 resString = ures_getStringByIndex(fortunes_r, i, &len, &err);
198 if (U_FAILURE(err)) {
199 fprintf(stderr, "%s: ures_getStringByIndex(%d) failed, %s\n", programName, i, u_errorName(err));
200 exit(-1);
201 }
202
203 u_file_write(resString, len, u_stdout); /* Write out the message */
204 u_fputc(0x0a, u_stdout); /* and a trailing newline */
205
206 return 0;
207 }
208
209