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 */
44extern  const void U_IMPORT *fortune_resources_dat;
45#endif
46
47void u_write(const UChar *what, int len);
48
49
50/*
51 *  main()   This one function is all of the application code.
52 */
53int 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