d791abadd5f4b6e7e4c439439dc185327e82f83f
[pazpar2-moved-to-github.git] / src / icu_I18N.c
1 /* $Id: icu_I18N.c,v 1.16 2007-05-16 19:50:01 marc Exp $
2    Copyright (c) 2006-2007, Index Data.
3
4    This file is part of Pazpar2.
5
6    Pazpar2 is free software; you can redistribute it and/or modify it under
7    the terms of the GNU General Public License as published by the Free
8    Software Foundation; either version 2, or (at your option) any later
9    version.
10
11    Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY
12    WARRANTY; without even the implied warranty of MERCHANTABILITY or
13    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14    for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with Pazpar2; see the file LICENSE.  If not, write to the
18    Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19    02111-1307, USA.
20 */
21
22 #if HAVE_CONFIG_H
23 #include "cconfig.h"
24 #endif
25
26 #define USE_TIMING 0
27 #if USE_TIMING
28 #include <yaz/timing.h>
29 #endif
30
31
32 #ifdef HAVE_ICU
33 #include "icu_I18N.h"
34
35 #include <yaz/log.h>
36
37 #include <string.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40
41 #include <unicode/ustring.h>  /* some more string fcns*/
42 #include <unicode/uchar.h>    /* char names           */
43
44
45 //#include <unicode/ustdio.h>
46 //#include <unicode/utypes.h>   /* Basic ICU data types */
47 #include <unicode/ucol.h> 
48 //#include <unicode/ucnv.h>     /* C   Converter API    */
49 //#include <unicode/uloc.h>
50 //#include <unicode/ubrk.h>
51 /* #include <unicode/unistr.h> */
52
53
54
55
56 int icu_check_status (UErrorCode status)
57 {
58     if(U_FAILURE(status)){
59         yaz_log(YLOG_WARN, 
60                 "ICU: %d %s\n", status, u_errorName(status));
61         return 0;   
62     }
63     return 1;
64     
65 }
66
67
68
69 struct icu_buf_utf16 * icu_buf_utf16_create(size_t capacity)
70 {
71     struct icu_buf_utf16 * buf16 
72         = (struct icu_buf_utf16 *) malloc(sizeof(struct icu_buf_utf16));
73
74     buf16->utf16 = 0;
75     buf16->utf16_len = 0;
76     buf16->utf16_cap = 0;
77
78     if (capacity > 0){
79         buf16->utf16 = (UChar *) malloc(sizeof(UChar) * capacity);
80         buf16->utf16[0] = (UChar) 0;
81         buf16->utf16_cap = capacity;
82     }
83     return buf16;
84 };
85
86
87 struct icu_buf_utf16 * icu_buf_utf16_resize(struct icu_buf_utf16 * buf16,
88                                             size_t capacity)
89 {
90     if (buf16){
91         if (capacity >  0){
92             if (0 == buf16->utf16)
93                 buf16->utf16 = (UChar *) malloc(sizeof(UChar) * capacity);
94             else
95                 buf16->utf16 
96                     = (UChar *) realloc(buf16->utf16, sizeof(UChar) * capacity);
97             buf16->utf16[0] = (UChar) 0;
98             buf16->utf16_len = 0;
99             buf16->utf16_cap = capacity;
100         } 
101         else { 
102             if (buf16->utf16)
103                 free(buf16->utf16);
104             buf16->utf16 = 0;
105             buf16->utf16_len = 0;
106             buf16->utf16_cap = 0;
107         }
108     }
109
110     return buf16;
111 };
112
113
114 struct icu_buf_utf16 * icu_buf_utf16_copy(struct icu_buf_utf16 * dest16,
115                                           struct icu_buf_utf16 * src16)
116 {
117     if(!dest16 || !src16
118        || dest16 == src16)
119         return 0;
120
121     if (dest16->utf16_cap < src16->utf16_len)
122         icu_buf_utf16_resize(dest16, src16->utf16_len * 2);
123
124     u_strncpy(dest16->utf16, src16->utf16, src16->utf16_len);
125     dest16->utf16_len = src16->utf16_len;
126
127     return dest16;
128 };
129
130
131 void icu_buf_utf16_destroy(struct icu_buf_utf16 * buf16)
132 {
133     if (buf16){
134         if (buf16->utf16)
135             free(buf16->utf16);
136         free(buf16);
137     }
138 };
139
140
141
142
143
144
145 struct icu_buf_utf8 * icu_buf_utf8_create(size_t capacity)
146 {
147     struct icu_buf_utf8 * buf8 
148         = (struct icu_buf_utf8 *) malloc(sizeof(struct icu_buf_utf8));
149
150     buf8->utf8 = 0;
151     buf8->utf8_len = 0;
152     buf8->utf8_cap = 0;
153
154     if (capacity > 0){
155         buf8->utf8 = (uint8_t *) malloc(sizeof(uint8_t) * capacity);
156         buf8->utf8[0] = (uint8_t) 0;
157         buf8->utf8_cap = capacity;
158     }
159     return buf8;
160 };
161
162
163
164 struct icu_buf_utf8 * icu_buf_utf8_resize(struct icu_buf_utf8 * buf8,
165                                           size_t capacity)
166 {
167     if (buf8){
168         if (capacity >  0){
169             if (0 == buf8->utf8)
170                 buf8->utf8 = (uint8_t *) malloc(sizeof(uint8_t) * capacity);
171             else
172                 buf8->utf8 
173                     = (uint8_t *) realloc(buf8->utf8, 
174                                           sizeof(uint8_t) * capacity);
175             buf8->utf8[0] = (uint8_t) 0;
176             buf8->utf8_len = 0;
177             buf8->utf8_cap = capacity;
178         } 
179         else { 
180             if (buf8->utf8)
181                 free(buf8->utf8);
182             buf8->utf8 = 0;
183             buf8->utf8_len = 0;
184             buf8->utf8_cap = 0;
185         }
186     }
187
188     return buf8;
189 };
190
191
192 struct icu_buf_utf8 * icu_buf_utf8_copy(struct icu_buf_utf8 * dest8,
193                                           struct icu_buf_utf8 * src8)
194 {
195     if(!dest8 || !src8
196        || dest8 == src8)
197         return 0;
198     
199
200     if (dest8->utf8_cap < src8->utf8_len)
201         icu_buf_utf8_resize(dest8, src8->utf8_len * 2);
202
203     strncpy((char*) dest8->utf8, (char*) src8->utf8, src8->utf8_len);
204
205     return dest8;
206 };
207
208
209
210 void icu_buf_utf8_destroy(struct icu_buf_utf8 * buf8)
211 {
212     if (buf8){
213         if (buf8->utf8)
214             free(buf8->utf8);
215         free(buf8);
216     }
217 };
218
219
220
221 UErrorCode icu_utf16_from_utf8(struct icu_buf_utf16 * dest16,
222                                struct icu_buf_utf8 * src8,
223                                UErrorCode * status)
224 {
225     int32_t utf16_len = 0;
226   
227     u_strFromUTF8(dest16->utf16, dest16->utf16_cap,
228                   &utf16_len,
229                   (const char *) src8->utf8, src8->utf8_len, status);
230   
231     // check for buffer overflow, resize and retry
232     if (*status == U_BUFFER_OVERFLOW_ERROR
233         //|| dest16->utf16_len > dest16->utf16_cap
234         ){
235         icu_buf_utf16_resize(dest16, utf16_len * 2);
236         *status = U_ZERO_ERROR;
237         u_strFromUTF8(dest16->utf16, dest16->utf16_cap,
238                       &utf16_len,
239                       (const char *) src8->utf8, src8->utf8_len, status);
240     }
241
242     //if (*status != U_BUFFER_OVERFLOW_ERROR
243     if (U_SUCCESS(*status)  
244         && utf16_len < dest16->utf16_cap)
245         dest16->utf16_len = utf16_len;
246     else {
247         dest16->utf16[0] = (UChar) 0;
248         dest16->utf16_len = 0;
249     }
250   
251     return *status;
252 };
253
254  
255
256 UErrorCode icu_utf16_from_utf8_cstr(struct icu_buf_utf16 * dest16,
257                                     const char * src8cstr,
258                                     UErrorCode * status)
259 {
260     size_t src8cstr_len = 0;
261     int32_t utf16_len = 0;
262
263     src8cstr_len = strlen(src8cstr);
264   
265     u_strFromUTF8(dest16->utf16, dest16->utf16_cap,
266                   &utf16_len,
267                   src8cstr, src8cstr_len, status);
268   
269     // check for buffer overflow, resize and retry
270     if (*status == U_BUFFER_OVERFLOW_ERROR
271         //|| dest16->utf16_len > dest16->utf16_cap
272         ){
273         icu_buf_utf16_resize(dest16, utf16_len * 2);
274         *status = U_ZERO_ERROR;
275         u_strFromUTF8(dest16->utf16, dest16->utf16_cap,
276                       &utf16_len,
277                       src8cstr, src8cstr_len, status);
278     }
279
280     //  if (*status != U_BUFFER_OVERFLOW_ERROR
281     if (U_SUCCESS(*status)  
282         && utf16_len < dest16->utf16_cap)
283         dest16->utf16_len = utf16_len;
284     else {
285         dest16->utf16[0] = (UChar) 0;
286         dest16->utf16_len = 0;
287     }
288   
289     return *status;
290 };
291
292
293
294
295 UErrorCode icu_utf16_to_utf8(struct icu_buf_utf8 * dest8,
296                              struct icu_buf_utf16 * src16,
297                              UErrorCode * status)
298 {
299     int32_t utf8_len = 0;
300   
301     u_strToUTF8((char *) dest8->utf8, dest8->utf8_cap,
302                 &utf8_len,
303                 src16->utf16, src16->utf16_len, status);
304   
305     // check for buffer overflow, resize and retry
306     if (*status == U_BUFFER_OVERFLOW_ERROR
307         //|| dest8->utf8_len > dest8->utf8_cap
308         ){
309         icu_buf_utf8_resize(dest8, utf8_len * 2);
310         *status = U_ZERO_ERROR;
311         u_strToUTF8((char *) dest8->utf8, dest8->utf8_cap,
312                     &utf8_len,
313                     src16->utf16, src16->utf16_len, status);
314
315     }
316
317     //if (*status != U_BUFFER_OVERFLOW_ERROR
318     if (U_SUCCESS(*status)  
319         && utf8_len < dest8->utf8_cap)
320         dest8->utf8_len = utf8_len;
321     else {
322         dest8->utf8[0] = (uint8_t) 0;
323         dest8->utf8_len = 0;
324     }
325   
326     return *status;
327 };
328
329
330
331 int icu_utf16_casemap(struct icu_buf_utf16 * dest16,
332                       struct icu_buf_utf16 * src16,
333                       const char *locale, char action,
334                       UErrorCode *status)
335 {
336     int32_t dest16_len = 0;
337     
338     switch(action) {    
339     case 'l':    
340         dest16_len = u_strToLower(dest16->utf16, dest16->utf16_cap,
341                                   src16->utf16, src16->utf16_len, 
342                                   locale, status);
343         break;
344     case 'u':    
345         dest16_len = u_strToUpper(dest16->utf16, dest16->utf16_cap,
346                                   src16->utf16, src16->utf16_len, 
347                                   locale, status);
348         break;
349     case 't':    
350         dest16_len = u_strToTitle(dest16->utf16, dest16->utf16_cap,
351                                   src16->utf16, src16->utf16_len,
352                                   0, locale, status);
353         break;
354     case 'f':    
355         dest16_len = u_strFoldCase(dest16->utf16, dest16->utf16_cap,
356                                    src16->utf16, src16->utf16_len,
357                                    U_FOLD_CASE_DEFAULT, status);
358         break;
359         
360     default:
361         return U_UNSUPPORTED_ERROR;
362         break;
363     }
364
365     // check for buffer overflow, resize and retry
366     if (*status == U_BUFFER_OVERFLOW_ERROR
367         && dest16 != src16        // do not resize if in-place conversion 
368         //|| dest16_len > dest16->utf16_cap
369         ){
370         icu_buf_utf16_resize(dest16, dest16_len * 2);
371         *status = U_ZERO_ERROR;
372
373     
374         switch(action) {    
375         case 'l':    
376             dest16_len = u_strToLower(dest16->utf16, dest16->utf16_cap,
377                                       src16->utf16, src16->utf16_len, 
378                                       locale, status);
379             break;
380         case 'u':    
381             dest16_len = u_strToUpper(dest16->utf16, dest16->utf16_cap,
382                                       src16->utf16, src16->utf16_len, 
383                                       locale, status);
384             break;
385         case 't':    
386             dest16_len = u_strToTitle(dest16->utf16, dest16->utf16_cap,
387                                       src16->utf16, src16->utf16_len,
388                                       0, locale, status);
389             break;
390         case 'f':    
391             dest16_len = u_strFoldCase(dest16->utf16, dest16->utf16_cap,
392                                        src16->utf16, src16->utf16_len,
393                                        U_FOLD_CASE_DEFAULT, status);
394             break;
395         
396         default:
397             return U_UNSUPPORTED_ERROR;
398             break;
399         }
400     }
401     
402     if (U_SUCCESS(*status)
403         && dest16_len < dest16->utf16_cap)
404         dest16->utf16_len = dest16_len;
405     else {
406         dest16->utf16[0] = (UChar) 0;
407         dest16->utf16_len = 0;
408     }
409   
410     return *status;
411 };
412
413
414
415 UErrorCode icu_sortkey8_from_utf16(UCollator *coll,
416                                    struct icu_buf_utf8 * dest8, 
417                                    struct icu_buf_utf16 * src16,
418                                    UErrorCode * status)
419
420   
421     int32_t sortkey_len = 0;
422
423     sortkey_len = ucol_getSortKey(coll, src16->utf16, src16->utf16_len,
424                                   dest8->utf8, dest8->utf8_cap);
425
426     // check for buffer overflow, resize and retry
427     if (sortkey_len > dest8->utf8_cap) {
428         icu_buf_utf8_resize(dest8, sortkey_len * 2);
429         sortkey_len = ucol_getSortKey(coll, src16->utf16, src16->utf16_len,
430                                       dest8->utf8, dest8->utf8_cap);
431     }
432
433     if (U_SUCCESS(*status)
434         && sortkey_len > 0)
435         dest8->utf8_len = sortkey_len;
436     else {
437         dest8->utf8[0] = (UChar) 0;
438         dest8->utf8_len = 0;
439     }
440
441     return sortkey_len;
442 };
443
444
445
446 struct icu_tokenizer * icu_tokenizer_create(const char *locale, char action,
447                                             UErrorCode *status)
448 {
449     struct icu_tokenizer * tokenizer
450         = (struct icu_tokenizer *) malloc(sizeof(struct icu_tokenizer));
451
452     strcpy(tokenizer->locale, locale);
453     tokenizer->action = action;
454     tokenizer->bi = 0;
455     tokenizer->buf16 = 0;
456     tokenizer->token_count = 0;
457     tokenizer->token_id = 0;
458     tokenizer->token_start = 0;
459     tokenizer->token_end = 0;
460
461
462     switch(tokenizer->action) {    
463     case 'l':
464         tokenizer->bi
465             = ubrk_open(UBRK_LINE, tokenizer->locale,
466                         0, 0, status);
467         break;
468     case 's':
469         tokenizer->bi
470             = ubrk_open(UBRK_SENTENCE, tokenizer->locale,
471                         0, 0, status);
472         break;
473     case 'w':
474         tokenizer->bi 
475             = ubrk_open(UBRK_WORD, tokenizer->locale,
476                         0, 0, status);
477         break;
478     case 'c':
479         tokenizer->bi 
480             = ubrk_open(UBRK_CHARACTER, tokenizer->locale,
481                         0, 0, status);
482         break;
483     case 't':
484         tokenizer->bi 
485             = ubrk_open(UBRK_TITLE, tokenizer->locale,
486                         0, 0, status);
487         break;
488     default:
489         *status = U_UNSUPPORTED_ERROR;
490         return 0;
491         break;
492     }
493     
494     // ICU error stuff is a very  funny business
495     if (U_SUCCESS(*status))
496         return tokenizer;
497
498     // freeing if failed
499     icu_tokenizer_destroy(tokenizer);
500     return 0;
501 };
502
503 void icu_tokenizer_destroy(struct icu_tokenizer * tokenizer)
504 {
505     if (tokenizer) {
506         if (tokenizer->bi)
507             ubrk_close(tokenizer->bi);
508         free(tokenizer);
509     }
510 };
511
512 int icu_tokenizer_attach(struct icu_tokenizer * tokenizer, 
513                          struct icu_buf_utf16 * src16, 
514                          UErrorCode *status)
515 {
516     if (!tokenizer || !tokenizer->bi || !src16)
517         return 0;
518
519
520     tokenizer->buf16 = src16;
521     tokenizer->token_count = 0;
522     tokenizer->token_id = 0;
523     tokenizer->token_start = 0;
524     tokenizer->token_end = 0;
525
526     ubrk_setText(tokenizer->bi, src16->utf16, src16->utf16_len, status);
527     
528  
529     if (U_FAILURE(*status))
530         return 0;
531
532     return 1;
533 };
534
535 int32_t icu_tokenizer_next_token(struct icu_tokenizer * tokenizer, 
536                          struct icu_buf_utf16 * tkn16, 
537                          UErrorCode *status)
538 {
539     int32_t tkn_start = 0;
540     int32_t tkn_end = 0;
541     int32_t tkn_len = 0;
542     
543
544     if (!tokenizer || !tokenizer->bi
545         || !tokenizer->buf16 || !tokenizer->buf16->utf16_len)
546         return 0;
547
548     // never change tokenizer->buf16 and keep always invariant
549     // 0 <= tokenizer->token_start 
550     //   <= tokenizer->token_end 
551     //   <= tokenizer->buf16->utf16_len
552     // returns length of token
553
554     if (0 == tokenizer->token_end) // first call
555         tkn_start = ubrk_first(tokenizer->bi);
556     else //successive calls
557         tkn_start = tokenizer->token_end;
558
559     // get next position
560     tkn_end = ubrk_next(tokenizer->bi);
561
562     // repairing invariant at end of ubrk, which is UBRK_DONE = -1 
563     if (UBRK_DONE == tkn_end)
564         tkn_end = tokenizer->buf16->utf16_len;
565
566     // copy out if everything is well
567     if(U_FAILURE(*status))
568         return 0;        
569     
570     // everything OK, now update internal state
571     tkn_len = tkn_end - tkn_start;
572
573     if (0 < tkn_len){
574         tokenizer->token_count++;
575         tokenizer->token_id++;
576     } else {
577         tokenizer->token_id = 0;    
578     }
579     tokenizer->token_start = tkn_start;
580     tokenizer->token_end = tkn_end;
581     
582
583     // copying into token buffer if it exists 
584     if (tkn16){
585         if (tkn16->utf16_cap < tkn_len)
586             icu_buf_utf16_resize(tkn16, (size_t) tkn_len * 2);
587
588         u_strncpy(tkn16->utf16, &(tokenizer->buf16->utf16)[tkn_start], 
589                   tkn_len);
590
591         tkn16->utf16_len = tkn_len;
592     }
593
594     return tkn_len;
595 }
596
597
598 int32_t icu_tokenizer_token_id(struct icu_tokenizer * tokenizer)
599 {
600     return tokenizer->token_id;
601 };
602
603 int32_t icu_tokenizer_token_start(struct icu_tokenizer * tokenizer)
604 {
605     return tokenizer->token_start;
606 };
607
608 int32_t icu_tokenizer_token_end(struct icu_tokenizer * tokenizer)
609 {
610     return tokenizer->token_end;
611 };
612
613 int32_t icu_tokenizer_token_length(struct icu_tokenizer * tokenizer)
614 {
615     return (tokenizer->token_end - tokenizer->token_start);
616 };
617
618 int32_t icu_tokenizer_token_count(struct icu_tokenizer * tokenizer)
619 {
620     return tokenizer->token_count;
621 };
622
623
624
625 //struct icu_normalizer
626 //{
627 //  char action;
628 //  struct icu_buf_utf16 * rules16;
629 //  UParseError parse_error[256];
630 //  UTransliterator * trans;
631 //};
632
633
634 struct icu_normalizer * icu_normalizer_create(const char *rules, char action,
635                                               UErrorCode *status)
636 {
637
638     struct icu_normalizer * normalizer
639         = (struct icu_normalizer *) malloc(sizeof(struct icu_normalizer));
640
641     normalizer->action = action;
642     normalizer->trans = 0;
643     normalizer->rules16 =  icu_buf_utf16_create(0);
644     icu_utf16_from_utf8_cstr(normalizer->rules16, rules, status);
645      
646     switch(normalizer->action) {    
647     case 'f':
648         normalizer->trans
649             = utrans_openU(normalizer->rules16->utf16, 
650                            normalizer->rules16->utf16_len,
651                            UTRANS_FORWARD,
652                            0, 0, 
653                            normalizer->parse_error, status);
654         break;
655     case 'r':
656         normalizer->trans
657             = utrans_openU(normalizer->rules16->utf16,
658                            normalizer->rules16->utf16_len,
659                            UTRANS_REVERSE ,
660                            0, 0,
661                            normalizer->parse_error, status);
662         break;
663     default:
664         *status = U_UNSUPPORTED_ERROR;
665         return 0;
666         break;
667     }
668     
669     if (U_SUCCESS(*status))
670         return normalizer;
671
672     // freeing if failed
673     icu_normalizer_destroy(normalizer);
674     return 0;
675 };
676
677
678 void icu_normalizer_destroy(struct icu_normalizer * normalizer){
679     if (normalizer) {
680         if (normalizer->rules16) 
681             icu_buf_utf16_destroy(normalizer->rules16);
682         if (normalizer->trans)
683             utrans_close(normalizer->trans);
684         free(normalizer);
685     }
686 };
687
688
689
690 int icu_normalizer_normalize(struct icu_normalizer * normalizer,
691                              struct icu_buf_utf16 * dest16,
692                              struct icu_buf_utf16 * src16,
693                              UErrorCode *status)
694 {
695     if (!normalizer || !normalizer->trans || !src16 || !dest16)
696         return 0;
697
698     if (!icu_buf_utf16_copy(dest16, src16))
699         return 0;
700
701     utrans_transUChars (normalizer->trans, 
702                         dest16->utf16, &(dest16->utf16_len),
703                         dest16->utf16_cap,
704                         0, &(src16->utf16_len), status);
705
706     if (U_FAILURE(*status)){
707         dest16->utf16[0] = (UChar) 0;
708         dest16->utf16_len = 0;
709     }
710     
711     return dest16->utf16_len;
712 }
713
714
715
716
717 struct icu_chain_step * icu_chain_step_create(struct icu_chain * chain,
718                                               enum icu_chain_step_type type,
719                                               const uint8_t * rule,
720                                               struct icu_buf_utf16 * buf16,
721                                               UErrorCode *status)
722 {
723     struct icu_chain_step * step = 0;
724     
725     if(!chain || !type || !rule)
726         return 0;
727
728     step = (struct icu_chain_step *) malloc(sizeof(struct icu_chain_step));
729
730     step->type = type;
731     step->more_tokens = 0;
732
733     if (buf16)
734         step->buf16 = buf16;
735     else
736         step->buf16 = 0;
737
738     // create auxilary objects
739     switch(step->type) {
740     case ICU_chain_step_type_display:
741         break;
742     case ICU_chain_step_type_norm:
743         break;
744     case ICU_chain_step_type_sort:
745         break;
746     case ICU_chain_step_type_charmap:
747         break;
748     case ICU_chain_step_type_normalize:
749         step->u.normalizer = icu_normalizer_create((char *) rule, 'f', status);
750         break;
751     case ICU_chain_step_type_tokenize:
752         step->u.tokenizer = icu_tokenizer_create((char *) chain->locale, 
753                                                  (char) rule[0], status);
754         break;
755     default:
756         break;
757     }
758
759     return step;
760 };
761
762
763 void icu_chain_step_destroy(struct icu_chain_step * step){
764     
765     if (!step)
766         return;
767
768     icu_chain_step_destroy(step->previous);
769
770     switch(step->type) {
771     case ICU_chain_step_type_display:
772         break;
773     case ICU_chain_step_type_norm:
774         break;
775     case ICU_chain_step_type_sort:
776         break;
777     case ICU_chain_step_type_charmap:
778         icu_buf_utf16_destroy(step->buf16);
779         break;
780     case ICU_chain_step_type_normalize:
781         icu_normalizer_destroy(step->u.normalizer);
782         icu_buf_utf16_destroy(step->buf16);
783         break;
784     case ICU_chain_step_type_tokenize:
785         icu_tokenizer_destroy(step->u.tokenizer);
786         icu_buf_utf16_destroy(step->buf16);
787         break;
788     default:
789         break;
790     }
791
792
793 };
794
795
796
797 struct icu_chain * icu_chain_create(const uint8_t * identifier,
798                                     const uint8_t * locale)
799 {
800
801     struct icu_chain * chain 
802         = (struct icu_chain *) malloc(sizeof(struct icu_chain));
803
804     strncpy((char *) chain->identifier, (const char *) identifier, 128);
805     chain->identifier[128 - 1] = '\0';
806     strncpy((char *) chain->locale, (const char *) locale, 16);    
807     chain->locale[16 - 1] = '\0';
808
809     chain->token_count = 0;
810
811     chain->display8 = icu_buf_utf8_create(0);
812     chain->norm8 = icu_buf_utf8_create(0);
813     chain->sort8 = icu_buf_utf8_create(0);
814
815     chain->src16 = icu_buf_utf16_create(0);
816
817     chain->steps = 0;
818
819     return chain;
820 };
821
822
823 void icu_chain_destroy(struct icu_chain * chain)
824 {
825     icu_buf_utf8_destroy(chain->display8);
826     icu_buf_utf8_destroy(chain->norm8);
827     icu_buf_utf8_destroy(chain->sort8);
828
829     icu_buf_utf16_destroy(chain->src16);
830
831     icu_chain_step_destroy(chain->steps);
832 };
833
834
835 struct icu_chain_step * icu_chain_insert_step(struct icu_chain * chain,
836                                               enum icu_chain_step_type type,
837                                               const uint8_t * rule,
838                                               UErrorCode *status)
839 {    
840     struct icu_chain_step * step = 0;
841     struct icu_buf_utf16 * src16 = 0;
842     struct icu_buf_utf16 * buf16 = 0;
843
844     if (!chain || !type || !rule)
845         return 0;
846
847     // assign utf16 src buffers as needed 
848     if (chain->steps && chain->steps->buf16)
849         src16 = chain->steps->buf16;
850     else if (chain->src16)
851         src16 = chain->src16;
852     else
853         return 0;
854
855     
856     // assign utf16 destination buffers as needed, or
857     // re-use previous uft18 buffer if this step does not touch it
858     switch(type) {
859     case ICU_chain_step_type_display:
860         buf16 = src16;
861         break;
862     case ICU_chain_step_type_norm:
863         buf16 = src16;
864         break;
865     case ICU_chain_step_type_sort:
866         buf16 = src16;
867         break;
868     case ICU_chain_step_type_charmap:
869         buf16 = icu_buf_utf16_create(0);
870         break;
871     case ICU_chain_step_type_normalize:
872         buf16 = icu_buf_utf16_create(0);
873         break;
874     case ICU_chain_step_type_tokenize:
875         buf16 = icu_buf_utf16_create(0);
876         break;
877     default:
878         break;
879     }
880
881     // create actual chain step with this buffer
882     step = icu_chain_step_create(chain, type, rule, buf16, status);
883
884     step->previous = chain->steps;
885     chain->steps = step;
886
887     return step;
888 };
889
890
891 int icu_chain_step_next_token(struct icu_chain * chain,
892                               struct icu_chain_step * step,
893                               UErrorCode *status)
894 {
895     struct icu_buf_utf16 * src16 = 0;
896     
897     printf("icu_chain_step_next_token %d\n", (int) step);
898
899     if (!chain || !chain->src16 || !step || !step->more_tokens)
900         return 0;
901
902     // assign utf16 src buffers as neeed, advance in previous steps
903     // tokens, and setting stop condition
904     if (step->previous){
905         src16 = step->previous->buf16;
906         step->more_tokens 
907             = icu_chain_step_next_token(chain, step->previous, status);
908     }
909     else { // first step can only work once on chain->src16 input buffer
910         src16 = chain->src16;
911         step->more_tokens = 1;
912     }
913
914     // stop if nothing to process 
915     // i.e new token source was not properly assigned
916     if (!step->more_tokens || !src16 || !src16->utf16_len) //  
917         return 0;
918
919     printf("icu_chain_step_next_token %d working\n", (int) step);
920
921
922     // perform the work, eventually put this steps output in 
923     // step->buf16 or the chains UTF8 output buffers 
924     switch(step->type) {
925     case ICU_chain_step_type_display:
926         icu_utf16_to_utf8(chain->display8, src16, status);
927         break;
928     case ICU_chain_step_type_norm:
929         icu_utf16_to_utf8(chain->norm8, src16, status);
930         break;
931     case ICU_chain_step_type_sort:
932         icu_utf16_to_utf8(chain->sort8, src16, status);
933         break;
934     case ICU_chain_step_type_charmap:
935         break;
936     case ICU_chain_step_type_normalize:
937         icu_normalizer_normalize(step->u.normalizer,
938                                  step->buf16, src16, status);
939         break;
940     case ICU_chain_step_type_tokenize:
941         icu_tokenizer_attach(step->u.tokenizer, src16, status);
942         step->more_tokens
943             = icu_tokenizer_next_token(step->u.tokenizer,
944                                        step->buf16, status);
945         break;
946     default:
947         return 0;
948         break;
949     }
950     
951
952     // stop further token processing if last step
953     if (!step->previous)
954         step->more_tokens = 0;
955
956
957     if (U_FAILURE(*status))
958         return 0;
959
960     return 1;
961 };
962
963
964
965 int icu_chain_assign_cstr(struct icu_chain * chain,
966                           const char * src8cstr, 
967                           UErrorCode *status)
968 {
969     struct icu_chain_step * stp = chain->steps;
970
971     if (!chain || !src8cstr)
972         return 0;
973     
974     // clear token count
975     chain->token_count = 0;
976
977     // clear all steps stop states
978
979     while (stp){
980         stp->more_tokens = 1;
981         stp = stp->previous;
982     }
983     
984     // finally convert UTF8 to UTF16 string
985     icu_utf16_from_utf8_cstr(chain->src16, src8cstr, status);
986             
987     if (U_FAILURE(*status))
988         return 0;
989
990     return 1;
991 };
992
993
994
995 int icu_chain_next_token(struct icu_chain * chain,
996                          UErrorCode *status)
997 {
998     int success = 0;
999     
1000     if (!chain || !chain->steps)
1001         return 0;
1002
1003     success = icu_chain_step_next_token(chain, chain->steps, status);
1004     
1005     if (success){
1006         chain->token_count++;
1007         return chain->token_count;
1008     }
1009
1010     return 0;
1011 };
1012
1013 int icu_chain_get_token_count(struct icu_chain * chain)
1014 {
1015     if (!chain)
1016         return 0;
1017     
1018     return chain->token_count;
1019 };
1020
1021
1022
1023 const char * icu_chain_get_display(struct icu_chain * chain)
1024 {
1025     if (chain->display8)
1026         return (const char *) chain->display8->utf8;
1027     
1028     return 0;
1029 };
1030
1031 const char * icu_chain_get_norm(struct icu_chain * chain)
1032 {
1033     if (chain->norm8)
1034         return (const char *) chain->norm8->utf8;
1035     
1036     return 0;
1037 };
1038
1039 const char * icu_chain_get_sort(struct icu_chain * chain)
1040 {
1041     if (chain->sort8)
1042         return (const char *) chain->sort8->utf8;
1043     
1044     return 0;
1045 };
1046
1047
1048
1049
1050 #endif // HAVE_ICU    
1051
1052
1053
1054
1055 /*
1056  * Local variables:
1057  * c-basic-offset: 4
1058  * indent-tabs-mode: nil
1059  * End:
1060  * vim: shiftwidth=4 tabstop=8 expandtab
1061  */