ICU sorting works correct now. Had forgotten to pass on the correct length of the...
[pazpar2-moved-to-github.git] / src / icu_bug_2.c
1 // Make command on debian 64 bit testing dist  
2 /*
3 gcc -g -Wall `icu-config --cppflags`  `icu-config --ldflags` -o icu_bug_2 icu_bug_2.c
4 snatched from http://www.icu-project.org/userguide/Collate_API.html 
5 and changed.
6 added a struct icu_termmap such that I actually can see the output
7 */
8
9 #include <string.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12
13 #include <unicode/ustring.h>  /* some more string fcns*/
14 #include <unicode/uchar.h>    /* char names           */
15
16
17 //#include <unicode/ustdio.h>
18 //#include <unicode/utypes.h>   /* Basic ICU data types */
19 #include <unicode/ucol.h> 
20 //#include <unicode/ucnv.h>     /* C   Converter API    */
21 //#include <unicode/uloc.h>
22 //#include <unicode/ubrk.h>
23 //#include <unicode/unistr.h> 
24
25
26 #define MAX_KEY_SIZE 256
27
28 struct icu_buf_utf16
29 {
30   UChar * utf16;
31   int32_t utf16_len;
32   int32_t utf16_cap;
33 };
34
35
36 struct icu_buf_utf16 * icu_buf_utf16_create(size_t capacity)
37 {
38   struct icu_buf_utf16 * buf16 
39     = (struct icu_buf_utf16 *) malloc(sizeof(struct icu_buf_utf16));
40
41   buf16->utf16 = 0;
42   buf16->utf16_len = 0;
43   buf16->utf16_cap = 0;
44
45   if (capacity > 0){
46     buf16->utf16 = (UChar *) malloc(sizeof(UChar) * capacity);
47     buf16->utf16[0] = (UChar) 0;
48     buf16->utf16_cap = capacity;
49   }
50   return buf16;
51 };
52
53
54 struct icu_buf_utf16 * icu_buf_utf16_resize(struct icu_buf_utf16 * buf16,
55                                             size_t capacity)
56 {
57   //printf("buf16 resize: %d\n", (int)capacity);
58   if (buf16){
59     if (capacity >  0){
60       if (0 == buf16->utf16)
61         buf16->utf16 = (UChar *) malloc(sizeof(UChar) * capacity);
62       else
63         buf16->utf16 
64           = (UChar *) realloc(buf16->utf16, sizeof(UChar) * capacity);
65       buf16->utf16[0] = (UChar) 0;
66       buf16->utf16_len = 0;
67       buf16->utf16_cap = capacity;
68     } 
69     else { 
70       if (buf16->utf16)
71         free(buf16->utf16);
72       buf16->utf16 = 0;
73       buf16->utf16_len = 0;
74       buf16->utf16_cap = 0;
75     }
76   }
77
78   return buf16;
79 };
80
81
82 void icu_buf_utf16_destroy(struct icu_buf_utf16 * buf16)
83 {
84   if (buf16){
85     if (buf16->utf16)
86       free(buf16->utf16);
87     free(buf16);
88   }
89 };
90
91
92
93 struct icu_buf_utf8
94 {
95   uint8_t * utf8;
96   int32_t utf8_len;
97   int32_t utf8_cap;
98 };
99
100
101
102 struct icu_buf_utf8 * icu_buf_utf8_create(size_t capacity)
103 {
104   struct icu_buf_utf8 * buf8 
105     = (struct icu_buf_utf8 *) malloc(sizeof(struct icu_buf_utf8));
106
107   buf8->utf8 = 0;
108   buf8->utf8_len = 0;
109   buf8->utf8_cap = 0;
110
111   if (capacity > 0){
112     buf8->utf8 = (uint8_t *) malloc(sizeof(uint8_t) * capacity);
113     buf8->utf8[0] = (uint8_t) 0;
114     buf8->utf8_cap = capacity;
115   }
116   return buf8;
117 };
118
119
120
121 struct icu_buf_utf8 * icu_buf_utf8_resize(struct icu_buf_utf8 * buf8,
122                                           size_t capacity)
123 {
124   //printf("buf8  resize: %d\n", (int)capacity);
125   if (buf8){
126     if (capacity >  0){
127       if (0 == buf8->utf8)
128         buf8->utf8 = (uint8_t *) malloc(sizeof(uint8_t) * capacity);
129       else
130         buf8->utf8 
131           = (uint8_t *) realloc(buf8->utf8, sizeof(uint8_t) * capacity);
132       buf8->utf8[0] = (uint8_t) 0;
133       buf8->utf8_len = 0;
134       buf8->utf8_cap = capacity;
135     } 
136     else { 
137       if (buf8->utf8)
138         free(buf8->utf8);
139       buf8->utf8 = 0;
140       buf8->utf8_len = 0;
141       buf8->utf8_cap = 0;
142     }
143   }
144
145   return buf8;
146 };
147
148
149
150 void icu_buf_utf8_destroy(struct icu_buf_utf8 * buf8)
151 {
152   if (buf8){
153     if (buf8->utf8)
154       free(buf8->utf8);
155     free(buf8);
156   }
157 };
158
159
160
161 UErrorCode icu_utf16_from_utf8(struct icu_buf_utf16 * dest16,
162                                struct icu_buf_utf8 * src8,
163                                UErrorCode * status)
164 {
165   //if(!U_SUCCESS(*status))
166   //  return *status;
167   printf("icu_utf16_from_utf8 - needs correcting, see icu_utf16_from_utf8_cstr\n");
168
169   u_strFromUTF8(dest16->utf16, dest16->utf16_cap, &(dest16->utf16_len),
170                 (const char *) src8->utf8, src8->utf8_len, status);
171
172   // check for buffer overflow, resize and retry
173   if (dest16->utf16_len > dest16->utf16_cap){
174     printf("icu_utf16_from_utf8 need resize\n");
175     icu_buf_utf16_resize(dest16, dest16->utf16_len * 2);
176     *status = U_ZERO_ERROR;
177     u_strFromUTF8(dest16->utf16, dest16->utf16_cap, &(dest16->utf16_len),
178                   (const char*) src8->utf8, src8->utf8_len, status);
179   }
180
181   return *status;
182 };
183
184  
185
186 UErrorCode icu_utf16_from_utf8_cstr(struct icu_buf_utf16 * dest16,
187                                     const char * src8cstr,
188                                     UErrorCode * status)
189 {
190   size_t src8cstr_len = 0;
191   int32_t utf16_len = 0;
192
193   //if(!U_SUCCESS(status))
194   //  return *status;
195
196   //printf("icu_utf16_from_utf8_cstr working\n");  
197   src8cstr_len = strlen(src8cstr);
198   
199   u_strFromUTF8(dest16->utf16, dest16->utf16_cap,
200                 &utf16_len,
201                 //&(dest16->utf16_len),
202                 src8cstr, src8cstr_len, status);
203   
204   // check for buffer overflow, resize and retry
205   if (*status == U_BUFFER_OVERFLOW_ERROR
206       //|| dest16->utf16_len > dest16->utf16_cap
207       ){
208     //printf("icu_utf16_from_utf8_cstr need resize\n");
209     icu_buf_utf16_resize(dest16, utf16_len * 2);
210     *status = U_ZERO_ERROR;
211     u_strFromUTF8(dest16->utf16, dest16->utf16_cap,
212                   &utf16_len,
213                   //&(dest16->utf16_len),
214                   src8cstr, src8cstr_len, status);
215   }
216
217   if (*status != U_BUFFER_OVERFLOW_ERROR
218       && utf16_len < dest16->utf16_cap)
219     dest16->utf16_len = utf16_len;
220   else {
221     dest16->utf16[0] = (UChar) 0;
222     dest16->utf16_len = 0;
223   }
224   
225   return *status;
226 };
227
228
229 UErrorCode icu_sortkey8_from_utf16(UCollator *coll,
230                                    struct icu_buf_utf8 * dest8, 
231                                    struct icu_buf_utf16 * src16,
232                                    UErrorCode * status)
233
234   
235   int32_t sortkey_len = 0;
236   //if(!U_SUCCESS(status))
237   //  return *status;
238
239   //printf("icu_sortkey8_from_utf16 working\n");  
240   sortkey_len = ucol_getSortKey(coll, src16->utf16, src16->utf16_len,
241                                 dest8->utf8, dest8->utf8_cap);
242
243   // check for buffer overflow, resize and retry
244   if (sortkey_len > dest8->utf8_cap) {
245     //printf("icu_sortkey8_from_utf16 need resize\n");
246     icu_buf_utf8_resize(dest8, sortkey_len * 2);
247     sortkey_len = ucol_getSortKey(coll, src16->utf16, src16->utf16_len,
248                                   dest8->utf8, dest8->utf8_cap);
249   }
250
251   if (sortkey_len > 0)
252     dest8->utf8_len = sortkey_len;
253  
254   return *status;
255 };
256
257  
258
259
260 struct icu_termmap
261 {
262   uint8_t sort_key[MAX_KEY_SIZE]; // standard C string '\0' terminated
263   char disp_term[MAX_KEY_SIZE];  // standard C utf-8 string
264 };
265
266
267
268 int icu_termmap_cmp(const void *vp1, const void *vp2)
269 {
270   struct icu_termmap *itmp1 = *(struct icu_termmap **) vp1;
271   struct icu_termmap *itmp2 = *(struct icu_termmap **) vp2;
272
273   int cmp = 0;
274     
275   cmp = strcmp((const char *)itmp1->sort_key, 
276                (const char *)itmp2->sort_key);
277   return cmp;
278 }
279
280
281 int icu_check_status(UErrorCode status)
282 {
283   if(!U_SUCCESS(status))
284     printf("ICU status: %d %s\n", status, u_errorName(status));
285   return status;
286 }
287
288
289
290 int icu_coll_sort(const char * locale, int src_list_len,
291                   const char ** src_list, const char ** chk_list)
292 {
293   UErrorCode status = U_ZERO_ERROR;
294   
295   struct icu_buf_utf8 * buf8 = icu_buf_utf8_create(0);
296   struct icu_buf_utf16 * buf16 = icu_buf_utf16_create(0);
297
298   int i;
299
300   struct icu_termmap * list[src_list_len];
301
302   UCollator *coll = ucol_open(locale, &status); 
303   icu_check_status(status);
304
305   if(!U_SUCCESS(status))
306     return 0;
307
308   // assigning display terms and sort keys using buf 8 and buf16
309   for( i = 0; i < src_list_len; i++) 
310     {
311
312       list[i] = (struct icu_termmap *) malloc(sizeof(struct icu_termmap));
313
314       // copy display term
315       strcpy(list[i]->disp_term, src_list[i]);    
316
317       // transforming to UTF16
318       icu_utf16_from_utf8_cstr(buf16, list[i]->disp_term, &status);
319       icu_check_status(status);
320
321       // computing sortkeys
322       icu_sortkey8_from_utf16(coll, buf8, buf16, &status);
323       icu_check_status(status);
324     
325       // assigning sortkeys
326       memcpy(list[i]->sort_key, buf8->utf8, buf8->utf8_len);    
327       //strncpy(list[i]->sort_key, buf8->utf8, buf8->utf8_len);    
328       //strcpy((char *) list[i]->sort_key, (const char *) buf8->utf8);
329       //printf("strcp: %s (%d) [%d]\n", list[i]->sort_key, 
330       //       strlen(list[i]->sort_key), buf8->utf8_len);
331     } 
332
333   printf("\n"); 
334   printf("Input str: '%s' : ", locale); 
335   for (i = 0; i < src_list_len; i++) {
336     printf(" '%s'", list[i]->disp_term); 
337   }
338   printf("\n");
339
340   // do the sorting
341   qsort(list, src_list_len, 
342         sizeof(struct icu_termmap *), icu_termmap_cmp);
343   
344   
345   printf("ICU sort:  '%s' : ", locale); 
346   for (i = 0; i < src_list_len; i++) {
347     printf(" '%s'", list[i]->disp_term); 
348     //printf("(%d|%d)", list[i]->sort_key[0],list[i]->sort_key[1]); 
349   }
350   printf("\n"); 
351   
352   ucol_close(coll);
353
354   icu_buf_utf8_destroy(buf8);
355   icu_buf_utf16_destroy(buf16);
356
357   return 1;
358 };
359
360
361 int main(int argc, char **argv)
362 {
363   
364   size_t en_1_len = 6;
365   const char * en_1_src[6] = {"z", "K", "a", "A", "Z", "k"};
366   const char * en_1_cck[6] = {"a", "A", "K", "k", "z", "Z"};
367   icu_coll_sort("en", en_1_len, en_1_src, en_1_cck);
368   icu_coll_sort("en_AU", en_1_len, en_1_src, en_1_cck);
369   icu_coll_sort("en_CA", en_1_len, en_1_src, en_1_cck);
370   icu_coll_sort("en_GB", en_1_len, en_1_src, en_1_cck);
371   icu_coll_sort("en_US", en_1_len, en_1_src, en_1_cck);
372     
373     
374   size_t da_1_len = 6;
375   const char * da_1_src[6] = {"z", "å", "o", "æ", "a", "ø"};
376   const char * da_1_cck[6] = {"a", "o", "z", "æ", "ø", "å"};
377   icu_coll_sort("da", da_1_len, da_1_src, da_1_cck);
378   icu_coll_sort("da_DK", da_1_len, da_1_src, da_1_cck);
379
380
381   size_t de_1_len = 9;
382   const char * de_1_src[9] = {"u", "ä", "o", "t", "s", "ß", "ü", "ö", "a"};
383   const char * de_1_cck[9] = {"ä", "a", "o", "ö", "s", "ß", "t", "u", "ü"};
384   icu_coll_sort("de", de_1_len, de_1_src, de_1_cck);
385   icu_coll_sort("de_AT", de_1_len, de_1_src, de_1_cck);
386   icu_coll_sort("de_DE", de_1_len, de_1_src, de_1_cck);
387
388   return 0;
389 };
390