1/********************************************************************
2 * COPYRIGHT:
3 * Copyright (C) 2002-2006 IBM, Inc.   All Rights Reserved.
4 *
5 ********************************************************************/
6
7/**
8 * This program demos string collation
9 */
10
11const char gHelpString[] =
12    "usage: coll [options*] -source source_string -target target_string\n"
13    "-help            Display this message.\n"
14    "-locale name     ICU locale to use.  Default is en_US\n"
15    "-rules rule      Collation rules file (overrides locale)\n"
16    "-french          French accent ordering\n"
17    "-norm            Normalizing mode on\n"
18    "-shifted         Shifted mode\n"
19    "-lower           Lower case first\n"
20    "-upper           Upper case first\n"
21    "-case            Enable separate case level\n"
22    "-level n         Sort level, 1 to 5, for Primary, Secndary, Tertiary, Quaternary, Identical\n"
23	"-source string   Source string for comparison\n"
24	"-target string   Target string for comparison\n"
25    "Example coll -rules \\u0026b\\u003ca -source a -target b\n"
26	"The format \\uXXXX is supported for the rules and comparison strings\n"
27	;
28
29#include <stdio.h>
30#include <string.h>
31#include <stdlib.h>
32
33#include <unicode/utypes.h>
34#include <unicode/ucol.h>
35#include <unicode/ustring.h>
36
37/**
38 * Command line option variables
39 *    These global variables are set according to the options specified
40 *    on the command line by the user.
41 */
42char * opt_locale     = "en_US";
43char * opt_rules      = 0;
44UBool  opt_help       = FALSE;
45UBool  opt_norm       = FALSE;
46UBool  opt_french     = FALSE;
47UBool  opt_shifted    = FALSE;
48UBool  opt_lower      = FALSE;
49UBool  opt_upper      = FALSE;
50UBool  opt_case       = FALSE;
51int    opt_level      = 0;
52char * opt_source     = "abc";
53char * opt_target     = "abd";
54UCollator * collator  = 0;
55
56/**
57 * Definitions for the command line options
58 */
59struct OptSpec {
60    const char *name;
61    enum {FLAG, NUM, STRING} type;
62    void *pVar;
63};
64
65OptSpec opts[] = {
66    {"-locale",      OptSpec::STRING, &opt_locale},
67    {"-rules",       OptSpec::STRING, &opt_rules},
68	{"-source",      OptSpec::STRING, &opt_source},
69    {"-target",      OptSpec::STRING, &opt_target},
70    {"-norm",        OptSpec::FLAG,   &opt_norm},
71    {"-french",      OptSpec::FLAG,   &opt_french},
72    {"-shifted",     OptSpec::FLAG,   &opt_shifted},
73    {"-lower",       OptSpec::FLAG,   &opt_lower},
74    {"-upper",       OptSpec::FLAG,   &opt_upper},
75    {"-case",        OptSpec::FLAG,   &opt_case},
76    {"-level",       OptSpec::NUM,    &opt_level},
77    {"-help",        OptSpec::FLAG,   &opt_help},
78    {"-?",           OptSpec::FLAG,   &opt_help},
79    {0, OptSpec::FLAG, 0}
80};
81
82/**
83 * processOptions()  Function to read the command line options.
84 */
85UBool processOptions(int argc, const char **argv, OptSpec opts[])
86{
87    for (int argNum = 1; argNum < argc; argNum ++) {
88        const char *pArgName = argv[argNum];
89        OptSpec *pOpt;
90        for (pOpt = opts;  pOpt->name != 0; pOpt ++) {
91            if (strcmp(pOpt->name, pArgName) == 0) {
92                switch (pOpt->type) {
93                case OptSpec::FLAG:
94                    *(UBool *)(pOpt->pVar) = TRUE;
95                    break;
96                case OptSpec::STRING:
97                    argNum ++;
98                    if (argNum >= argc) {
99                        fprintf(stderr, "value expected for \"%s\" option.\n",
100							    pOpt->name);
101                        return FALSE;
102                    }
103                    *(const char **)(pOpt->pVar) = argv[argNum];
104                    break;
105                case OptSpec::NUM:
106                    argNum ++;
107                    if (argNum >= argc) {
108                        fprintf(stderr, "value expected for \"%s\" option.\n",
109							    pOpt->name);
110                        return FALSE;
111                    }
112                    char *endp;
113                    int i = strtol(argv[argNum], &endp, 0);
114                    if (endp == argv[argNum]) {
115                        fprintf(stderr,
116							    "integer value expected for \"%s\" option.\n",
117								pOpt->name);
118                        return FALSE;
119                    }
120                    *(int *)(pOpt->pVar) = i;
121                }
122                break;
123            }
124        }
125        if (pOpt->name == 0)
126        {
127            fprintf(stderr, "Unrecognized option \"%s\"\n", pArgName);
128            return FALSE;
129        }
130    }
131	return TRUE;
132}
133
134/**
135 * ICU string comparison
136 */
137int strcmp()
138{
139	UChar source[100];
140	UChar target[100];
141	u_unescape(opt_source, source, 100);
142	u_unescape(opt_target, target, 100);
143    UCollationResult result = ucol_strcoll(collator, source, -1, target, -1);
144    if (result == UCOL_LESS) {
145		return -1;
146	}
147    else if (result == UCOL_GREATER) {
148		return 1;
149	}
150	return 0;
151}
152
153/**
154 * Creates a collator
155 */
156UBool processCollator()
157{
158	// Set up an ICU collator
159    UErrorCode status = U_ZERO_ERROR;
160	UChar rules[100];
161
162    if (opt_rules != 0) {
163		u_unescape(opt_rules, rules, 100);
164        collator = ucol_openRules(rules, -1, UCOL_OFF, UCOL_TERTIARY,
165			                  NULL, &status);
166    }
167    else {
168        collator = ucol_open(opt_locale, &status);
169    }
170	if (U_FAILURE(status)) {
171        fprintf(stderr, "Collator creation failed.: %d\n", status);
172        return FALSE;
173    }
174    if (status == U_USING_DEFAULT_WARNING) {
175        fprintf(stderr, "Warning, U_USING_DEFAULT_WARNING for %s\n",
176			    opt_locale);
177    }
178    if (status == U_USING_FALLBACK_WARNING) {
179        fprintf(stderr, "Warning, U_USING_FALLBACK_ERROR for %s\n",
180			    opt_locale);
181    }
182    if (opt_norm) {
183        ucol_setAttribute(collator, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
184    }
185    if (opt_french) {
186        ucol_setAttribute(collator, UCOL_FRENCH_COLLATION, UCOL_ON, &status);
187    }
188    if (opt_lower) {
189        ucol_setAttribute(collator, UCOL_CASE_FIRST, UCOL_LOWER_FIRST,
190			              &status);
191    }
192    if (opt_upper) {
193        ucol_setAttribute(collator, UCOL_CASE_FIRST, UCOL_UPPER_FIRST,
194			              &status);
195    }
196    if (opt_case) {
197        ucol_setAttribute(collator, UCOL_CASE_LEVEL, UCOL_ON, &status);
198    }
199    if (opt_shifted) {
200        ucol_setAttribute(collator, UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED,
201			              &status);
202    }
203    if (opt_level != 0) {
204        switch (opt_level) {
205        case 1:
206            ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_PRIMARY, &status);
207            break;
208        case 2:
209            ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_SECONDARY,
210				              &status);
211            break;
212        case 3:
213            ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_TERTIARY, &status);
214            break;
215        case 4:
216            ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_QUATERNARY,
217				              &status);
218            break;
219        case 5:
220            ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_IDENTICAL,
221				              &status);
222            break;
223        default:
224            fprintf(stderr, "-level param must be between 1 and 5\n");
225            return FALSE;
226        }
227    }
228    if (U_FAILURE(status)) {
229        fprintf(stderr, "Collator attribute setting failed.: %d\n", status);
230        return FALSE;
231    }
232	return TRUE;
233}
234
235/**
236 * Main   --  process command line, read in and pre-process the test file,
237 *            call other functions to do the actual tests.
238 */
239int main(int argc, const char** argv)
240{
241    if (processOptions(argc, argv, opts) != TRUE || opt_help) {
242        printf(gHelpString);
243        return -1;
244    }
245
246    if (processCollator() != TRUE) {
247		fprintf(stderr, "Error creating collator for comparison\n");
248		return -1;
249	}
250
251	fprintf(stdout, "Comparing source=%s and target=%s\n", opt_source,
252			opt_target);
253	int result = strcmp();
254	if (result == 0) {
255		fprintf(stdout, "source is equals to target\n");
256	}
257	else if (result < 0) {
258		fprintf(stdout, "source is less than target\n");
259	}
260	else {
261		fprintf(stdout, "source is greater than target\n");
262	}
263
264	ucol_close(collator);
265	return 0;
266}
267