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