1 /************************************************************************* 2 * 3 * 2016 and later: Unicode, Inc. and others. 4 * License & terms of use: http://www.unicode.org/copyright.html#License 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 */ 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 = (int)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