OSDN Git Service

Fix the symbol not found error.
[ludiafuncs/senna-1.1.2-fast.git] / lib / str.c
1 /* Copyright(C) 2004 Brazil
2
3   This library is free software; you can redistribute it and/or
4   modify it under the terms of the GNU Lesser General Public
5   License as published by the Free Software Foundation; either
6   version 2.1 of the License, or (at your option) any later version.
7
8   This library is distributed in the hope that it will be useful,
9   but WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   Lesser General Public License for more details.
12
13   You should have received a copy of the GNU Lesser General Public
14   License along with this library; if not, write to the Free Software
15   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16 */
17 /* Changelog:
18    2013/01/07
19    Add fast string-normalization function into Senna.
20    Author: NTT DATA Corporation
21  */
22 #include "senna_in.h"
23 #include <stdio.h>
24 #include <string.h>
25 #include "ctx.h"
26 #include "str.h"
27 #include "set.h"
28
29 #define __USE_ISOC99
30 #include <math.h>
31
32 static sen_set *prefix = NULL;
33 static sen_set *suffix = NULL;
34
35 #define N_PREFIX 2048
36 #define N_SUFFIX 0
37
38 #define PREFIX_PATH SENNA_HOME PATH_SEPARATOR "prefix"
39 #define SUFFIX_PATH SENNA_HOME PATH_SEPARATOR "suffix"
40
41 inline static void
42 prefix_init(void)
43 {
44   int i, *ip;
45   FILE *fp;
46   char buffer[4];
47   prefix = sen_set_open(2, sizeof(int), 0);
48   if (!prefix) { SEN_LOG(sen_log_alert, "sen_set_open on prefix_init failed !"); return; }
49   if ((fp = fopen(PREFIX_PATH, "r"))) {
50     for (i = 0; i < N_PREFIX; i++) {
51       if (!fgets(buffer, 4, fp)) { break; }
52       sen_set_get(prefix, buffer, (void **)&ip);
53       *ip = i;
54     }
55     fclose(fp);
56   }
57 }
58
59 inline static void
60 suffix_init(void)
61 {
62   int i;
63   FILE *fp;
64   char buffer[4];
65   suffix = sen_set_open(2, 0, 0);
66   if (!suffix) { SEN_LOG(sen_log_alert, "sen_set_open on suffix_init failed !"); return; }
67   if ((fp = fopen(SUFFIX_PATH, "r"))) {
68     for (i = N_SUFFIX; i; i--) {
69       if (!fgets(buffer, 4, fp)) { break; }
70       sen_set_get(suffix, buffer, NULL);
71     }
72     fclose(fp);
73   }
74 }
75
76 static inline size_t
77 sen_str_charlen_utf8(const unsigned char *str, const unsigned char *end)
78 {
79   /* MEMO: This function allows non-null-terminated string as str. */
80   /*       But requires the end of string. */
81   const unsigned char *p = str;
82   if (!*p || p >= end) { return 0; }
83   if (*p & 0x80) {
84     int b, w;
85     size_t size;
86     for (b = 0x40, w = 0; b && (*p & b); b >>= 1, w++);
87     if (!w) {
88       SEN_LOG(sen_log_warning, "invalid utf8 string(1) on sen_str_charlen_utf8");
89       return 0;
90     }
91     for (size = 1; w--; size++) {
92       if (++p >= end || !*p || (*p & 0xc0) != 0x80) {
93         SEN_LOG(sen_log_warning, "invalid utf8 string(2) on sen_str_charlen_utf8");
94         return 0;
95       }
96     }
97     return size;
98   } else {
99     return 1;
100   }
101   return 0;
102 }
103
104 inline static size_t
105 fast_sen_str_charlen_utf8(const unsigned char *s, const unsigned char *e)
106 {
107         size_t          len;
108
109         if (s >= e)
110                 return 0;
111
112     if ((*s & 0x80) == 0)
113         len = 1;
114     else if ((*s & 0xe0) == 0xc0)
115         len = 2;
116     else if ((*s & 0xf0) == 0xe0)
117         len = 3;
118     else if ((*s & 0xf8) == 0xf0)
119         len = 4;
120     else if ((*s & 0xfc) == 0xf8)
121         len = 5;
122     else if ((*s & 0xfe) == 0xfc)
123         len = 6;
124     else
125         len = 1;
126     return len;
127 }
128
129 unsigned int
130 sen_str_charlen(const char *str, sen_encoding encoding)
131 {
132   /* MEMO: This function requires null-terminated string as str.*/
133   unsigned char *p = (unsigned char *) str;
134   if (!*p) { return 0; }
135   switch (encoding) {
136   case sen_enc_euc_jp :
137     if (*p & 0x80) {
138       if (*(p + 1)) {
139         return 2;
140       } else {
141         /* This is invalid character */
142         SEN_LOG(sen_log_warning, "invalid euc-jp string end on sen_str_charlen");
143         return 0;
144       }
145     }
146     return 1;
147     break;
148   case sen_enc_utf8 :
149     if (*p & 0x80) {
150       int b, w;
151       size_t size;
152       for (b = 0x40, w = 0; b && (*p & b); b >>= 1, w++);
153       if (!w) {
154         SEN_LOG(sen_log_warning, "invalid utf8 string(1) on sen_str_charlen");
155         return 0;
156       }
157       for (size = 1; w--; size++) {
158         if (!*++p || (*p & 0xc0) != 0x80) {
159           SEN_LOG(sen_log_warning, "invalid utf8 string(2) on sen_str_charlen");
160           return 0;
161         }
162       }
163       return size;
164     } else {
165       return 1;
166     }
167     break;
168   case sen_enc_sjis :
169     if (*p & 0x80) {
170       /* we regard 0xa0 as JIS X 0201 KANA. adjusted to other tools. */
171       if (0xa0 <= *p && *p <= 0xdf) {
172         /* hankaku-kana */
173         return 1;
174       } else if (!(*(p + 1))) {
175         /* This is invalid character */
176         SEN_LOG(sen_log_warning, "invalid sjis string end on sen_str_charlen");
177         return 0;
178       } else {
179         return 2;
180       }
181     } else {
182       return 1;
183     }
184     break;
185   default :
186     return 1;
187     break;
188   }
189   return 0;
190 }
191
192 size_t
193 sen_str_charlen_nonnull(const char *str, const char *end, sen_encoding encoding)
194 {
195   /* MEMO: This function allows non-null-terminated string as str. */
196   /*       But requires the end of string. */
197   unsigned char *p = (unsigned char *) str;
198   if (p >= (unsigned char *)end) { return 0; }
199   switch (encoding) {
200   case sen_enc_euc_jp :
201     if (*p & 0x80) {
202       if ((p + 1) < (unsigned char *)end) {
203         return 2;
204       } else {
205         /* This is invalid character */
206         SEN_LOG(sen_log_warning, "invalid euc-jp string end on sen_str_charlen_nonnull");
207         return 0;
208       }
209     }
210     return 1;
211     break;
212   case sen_enc_utf8 :
213     return sen_str_charlen_utf8(p, (unsigned char *)end);
214     break;
215   case sen_enc_sjis :
216     if (*p & 0x80) {
217       /* we regard 0xa0 as JIS X 0201 KANA. adjusted to other tools. */
218       if (0xa0 <= *p && *p <= 0xdf) {
219         /* hankaku-kana */
220         return 1;
221       } else if (++p >= (unsigned char *)end) {
222         /* This is invalid character */
223         SEN_LOG(sen_log_warning, "invalid sjis string end on sen_str_charlen_nonnull");
224         return 0;
225       } else {
226         return 2;
227       }
228     } else {
229       return 1;
230     }
231     break;
232   default :
233     return 1;
234     break;
235   }
236   return 0;
237 }
238
239 sen_rc
240 sen_str_fin(void)
241 {
242   if (prefix) { sen_set_close(prefix); }
243   if (suffix) { sen_set_close(suffix); }
244   return sen_success;
245 }
246
247 int
248 sen_str_get_prefix_order(const char *str)
249 {
250   int *ip;
251   if (!str) { return -1; }
252   if (!prefix) { prefix_init(); }
253   if (prefix && sen_set_at(prefix, str, (void **)&ip)) {
254     return *ip;
255   } else {
256     return -1;
257   }
258 }
259
260 static unsigned char symbol[] = {
261   ',', '.', 0, ':', ';', '?', '!', 0, 0, 0, '`', 0, '^', '~', '_', 0, 0, 0,
262   0, 0, 0, 0, 0, 0, 0, '-', '-', '/', '\\', 0, 0, '|', 0, 0, 0, '\'', 0,
263   '"', '(', ')', 0, 0, '[', ']', '{', '}', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
264   '+', '-', 0, 0, 0, '=', 0, '<', '>', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
265   '$', 0, 0, '%', '#', '&', '*', '@', 0, 0, 0, 0, 0, 0, 0, 0
266 };
267
268 inline static sen_rc
269 normalize_euc(sen_nstr *nstr)
270 {
271   static uint16_t hankana[] = {
272     0xa1a1, 0xa1a3, 0xa1d6, 0xa1d7, 0xa1a2, 0xa1a6, 0xa5f2, 0xa5a1, 0xa5a3,
273     0xa5a5, 0xa5a7, 0xa5a9, 0xa5e3, 0xa5e5, 0xa5e7, 0xa5c3, 0xa1bc, 0xa5a2,
274     0xa5a4, 0xa5a6, 0xa5a8, 0xa5aa, 0xa5ab, 0xa5ad, 0xa5af, 0xa5b1, 0xa5b3,
275     0xa5b5, 0xa5b7, 0xa5b9, 0xa5bb, 0xa5bd, 0xa5bf, 0xa5c1, 0xa5c4, 0xa5c6,
276     0xa5c8, 0xa5ca, 0xa5cb, 0xa5cc, 0xa5cd, 0xa5ce, 0xa5cf, 0xa5d2, 0xa5d5,
277     0xa5d8, 0xa5db, 0xa5de, 0xa5df, 0xa5e0, 0xa5e1, 0xa5e2, 0xa5e4, 0xa5e6,
278     0xa5e8, 0xa5e9, 0xa5ea, 0xa5eb, 0xa5ec, 0xa5ed, 0xa5ef, 0xa5f3, 0xa1ab,
279     0xa1eb
280   };
281   static unsigned char dakuten[] = {
282     0xf4, 0, 0, 0, 0, 0xac, 0, 0xae, 0, 0xb0, 0, 0xb2, 0, 0xb4, 0, 0xb6, 0,
283     0xb8, 0, 0xba, 0, 0xbc, 0, 0xbe, 0, 0xc0, 0, 0xc2, 0, 0, 0xc5, 0, 0xc7,
284     0, 0xc9, 0, 0, 0, 0, 0, 0, 0xd0, 0, 0, 0xd3, 0, 0, 0xd6, 0, 0, 0xd9, 0,
285     0, 0xdc
286   };
287   static unsigned char handaku[] = {
288     0xd1, 0, 0, 0xd4, 0, 0, 0xd7, 0, 0, 0xda, 0, 0, 0xdd
289   };
290   int16_t *ch;
291   sen_ctx *ctx = nstr->ctx;
292   const unsigned char *s, *s_, *e;
293   unsigned char *d, *d0, *d_, b;
294   uint_least8_t *cp, *ctypes, ctype;
295   size_t size = nstr->orig_blen, length = 0;
296   int removeblankp = nstr->flags & SEN_STR_REMOVEBLANK;
297   if (!(nstr->norm = SEN_MALLOC(size * 2 + 1))) {
298     return sen_memory_exhausted;
299   }
300   d0 = (unsigned char *) nstr->norm;
301   if (nstr->flags & SEN_STR_WITH_CHECKS) {
302     if (!(nstr->checks = SEN_MALLOC(size * 2 * sizeof(int16_t) + 1))) {
303       SEN_FREE(nstr->norm);
304       nstr->norm = NULL;
305       return sen_memory_exhausted;
306     }
307   }
308   ch = nstr->checks;
309   if (nstr->flags & SEN_STR_WITH_CTYPES) {
310     if (!(nstr->ctypes = SEN_MALLOC(size + 1))) {
311       SEN_FREE(nstr->checks);
312       SEN_FREE(nstr->norm);
313       nstr->checks = NULL;
314       nstr->norm = NULL;
315       return sen_memory_exhausted;
316     }
317   }
318   cp = ctypes = nstr->ctypes;
319   e = (unsigned char *)nstr->orig + size;
320   for (s = s_ = (unsigned char *) nstr->orig, d = d_ = d0; s < e; s++) {
321     if ((*s & 0x80)) {
322       if (((s + 1) < e) && (*(s + 1) & 0x80)) {
323         unsigned char c1 = *s++, c2 = *s, c3 = 0;
324         switch (c1 >> 4) {
325         case 0x08 :
326           if (c1 == 0x8e && 0xa0 <= c2 && c2 <= 0xdf) {
327             uint16_t c = hankana[c2 - 0xa0];
328             switch (c) {
329             case 0xa1ab :
330               if (d > d0 + 1 && d[-2] == 0xa5
331                   && 0xa6 <= d[-1] && d[-1] <= 0xdb && (b = dakuten[d[-1] - 0xa6])) {
332                 *(d - 1) = b;
333                 if (ch) { ch[-1] += 2; s_ += 2; }
334                 continue;
335               } else {
336                 *d++ = c >> 8; *d = c & 0xff;
337               }
338               break;
339             case 0xa1eb :
340               if (d > d0 + 1 && d[-2] == 0xa5
341                   && 0xcf <= d[-1] && d[-1] <= 0xdb && (b = handaku[d[-1] - 0xcf])) {
342                 *(d - 1) = b;
343                 if (ch) { ch[-1] += 2; s_ += 2; }
344                 continue;
345               } else {
346                 *d++ = c >> 8; *d = c & 0xff;
347               }
348               break;
349             default :
350               *d++ = c >> 8; *d = c & 0xff;
351               break;
352             }
353             ctype = sen_str_katakana;
354           } else {
355             *d++ = c1; *d = c2;
356             ctype = sen_str_others;
357           }
358           break;
359         case 0x09 :
360           *d++ = c1; *d = c2;
361           ctype = sen_str_others;
362           break;
363         case 0x0a :
364           switch (c1 & 0x0f) {
365           case 1 :
366             switch (c2) {
367             case 0xbc :
368               *d++ = c1; *d = c2;
369               ctype = sen_str_katakana;
370               break;
371             case 0xb9 :
372               *d++ = c1; *d = c2;
373               ctype = sen_str_kanji;
374               break;
375             case 0xa1 :
376               if (removeblankp) {
377                 if (cp > ctypes) { *(cp - 1) |= SEN_NSTR_BLANK; }
378                 continue;
379               } else {
380                 *d = ' ';
381                 ctype = SEN_NSTR_BLANK|sen_str_symbol;
382               }
383               break;
384             default :
385               if (c2 >= 0xa4 && (c3 = symbol[c2 - 0xa4])) {
386                 *d = c3;
387                 ctype = sen_str_symbol;
388               } else {
389                 *d++ = c1; *d = c2;
390                 ctype = sen_str_others;
391               }
392               break;
393             }
394             break;
395           case 2 :
396             *d++ = c1; *d = c2;
397             ctype = sen_str_symbol;
398             break;
399           case 3 :
400             c3 = c2 - 0x80;
401             if ('a' <= c3 && c3 <= 'z') {
402               ctype = sen_str_alpha;
403               *d = c3;
404             } else if ('A' <= c3 && c3 <= 'Z') {
405               ctype = sen_str_alpha;
406               *d = c3 + 0x20;
407             } else if ('0' <= c3 && c3 <= '9') {
408               ctype = sen_str_digit;
409               *d = c3;
410             } else {
411               ctype = sen_str_others;
412               *d++ = c1; *d = c2;
413             }
414             break;
415           case 4 :
416             *d++ = c1; *d = c2;
417             ctype = sen_str_hiragana;
418             break;
419           case 5 :
420             *d++ = c1; *d = c2;
421             ctype = sen_str_katakana;
422             break;
423           case 6 :
424           case 7 :
425           case 8 :
426             *d++ = c1; *d = c2;
427             ctype = sen_str_symbol;
428             break;
429           default :
430             *d++ = c1; *d = c2;
431             ctype = sen_str_others;
432             break;
433           }
434           break;
435         default :
436           *d++ = c1; *d = c2;
437           ctype = sen_str_kanji;
438           break;
439         }
440       } else {
441         /* skip invalid character */
442         continue;
443       }
444     } else {
445       unsigned char c = *s;
446       switch (c >> 4) {
447       case 0 :
448       case 1 :
449         /* skip unprintable ascii */
450         if (cp > ctypes) { *(cp - 1) |= SEN_NSTR_BLANK; }
451         continue;
452       case 2 :
453         if (c == 0x20) {
454           if (removeblankp) {
455             if (cp > ctypes) { *(cp - 1) |= SEN_NSTR_BLANK; }
456             continue;
457           } else {
458             *d = ' ';
459             ctype = SEN_NSTR_BLANK|sen_str_symbol;
460           }
461         } else {
462           *d = c;
463           ctype = sen_str_symbol;
464         }
465         break;
466       case 3 :
467         *d = c;
468         ctype = (c <= 0x39) ? sen_str_digit : sen_str_symbol;
469         break;
470       case 4 :
471         *d = ('A' <= c) ? c + 0x20 : c;
472         ctype = (c == 0x40) ? sen_str_symbol : sen_str_alpha;
473         break;
474       case 5 :
475         *d = (c <= 'Z') ? c + 0x20 : c;
476         ctype = (c <= 0x5a) ? sen_str_alpha : sen_str_symbol;
477         break;
478       case 6 :
479         *d = c;
480         ctype = (c == 0x60) ? sen_str_symbol : sen_str_alpha;
481         break;
482       case 7 :
483         *d = c;
484         ctype = (c <= 0x7a) ? sen_str_alpha : (c == 0x7f ? sen_str_others : sen_str_symbol);
485         break;
486       default :
487         *d = c;
488         ctype = sen_str_others;
489         break;
490       }
491     }
492     d++;
493     length++;
494     if (cp) { *cp++ = ctype; }
495     if (ch) {
496       *ch++ = (int16_t)(s + 1 - s_);
497       s_ = s + 1;
498       while (++d_ < d) { *ch++ = 0; }
499     }
500   }
501   if (cp) { *cp = sen_str_null; }
502   *d = '\0';
503   nstr->length = length;
504   nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
505   return sen_success;
506 }
507
508 #ifndef NO_NFKC
509 uint_least8_t sen_nfkc_ctype(const unsigned char *str);
510 const char *sen_nfkc_map1(const unsigned char *str);
511 const char *sen_nfkc_map2(const unsigned char *prefix, const unsigned char *suffix);
512
513 /*
514  * We backported all changes about normalize_utf8 from Senna 1.1.5.
515  * Because normalize_utf8() in Senna 1.1.2 has the bug; the buffer
516  * overflow can happen when U+FDFA or U+3316 is given.
517  */
518 inline static sen_rc
519 normalize_utf8(sen_nstr *nstr)
520 {
521   int16_t *ch;
522   sen_ctx *ctx = nstr->ctx;
523   const unsigned char *s, *s_, *s__, *p, *p2, *pe, *e;
524   unsigned char *d, *d_, *de;
525   uint_least8_t *cp;
526   size_t length = 0, ls, lp, size = nstr->orig_blen, ds = size * 3;
527   int removeblankp = nstr->flags & SEN_STR_REMOVEBLANK;
528   if (!(nstr->norm = SEN_MALLOC(ds + 1))) {
529     return sen_memory_exhausted;
530   }
531   if (nstr->flags & SEN_STR_WITH_CHECKS) {
532     if (!(nstr->checks = SEN_MALLOC(ds * sizeof(int16_t) + 1))) {
533       SEN_FREE(nstr->norm);
534       nstr->norm = NULL;
535       return sen_memory_exhausted;
536     }
537   }
538   ch = nstr->checks;
539   if (nstr->flags & SEN_STR_WITH_CTYPES) {
540     if (!(nstr->ctypes = SEN_MALLOC(ds + 1))) {
541       if (nstr->checks) {
542         SEN_FREE(nstr->checks); nstr->checks = NULL;
543       }
544       SEN_FREE(nstr->norm); nstr->norm = NULL;
545       return sen_memory_exhausted;
546     }
547   }
548   cp = nstr->ctypes;
549   d = (unsigned char *)nstr->norm;
550   de = d + ds;
551   d_ = NULL;
552   e = (unsigned char *)nstr->orig + size;
553   for (s = s_ = (unsigned char *)nstr->orig; ; s += ls) {
554     if (!(ls = sen_str_charlen_utf8(s, e))) {
555       break;
556     }
557     if ((p = (unsigned char *)sen_nfkc_map1(s))) {
558       pe = p + strlen((char *)p);
559     } else {
560       p = s;
561       pe = p + ls;
562     }
563     if (d_ && (p2 = (unsigned char *)sen_nfkc_map2(d_, p))) {
564       p = p2;
565       pe = p + strlen((char *)p);
566       if (cp) { cp--; }
567       if (ch) {
568         ch -= (d - d_);
569         s_ = s__;
570       }
571       d = d_;
572       length--;
573     }
574     for (; ; p += lp) {
575       if (!(lp = sen_str_charlen_utf8(p, pe))) {
576         break;
577       }
578       if ((*p == ' ' && removeblankp) || *p < 0x20  /* skip unprintable ascii */ ) {
579         if (cp > nstr->ctypes) { *(cp - 1) |= SEN_NSTR_BLANK; }
580       } else {
581         if (de <= d + lp) {
582           unsigned char *norm;
583           ds += (ds >> 1) + lp;
584           if (!(norm = SEN_REALLOC(nstr->norm, ds + 1))) {
585             if (nstr->ctypes) { SEN_FREE(nstr->ctypes); nstr->ctypes = NULL; }
586             if (nstr->checks) { SEN_FREE(nstr->checks); nstr->checks = NULL; }
587             SEN_FREE(nstr->norm); nstr->norm = NULL;
588             return sen_memory_exhausted;
589           }
590           de = norm + ds;
591           d = norm + (d - (unsigned char *)nstr->norm);
592           nstr->norm = norm;
593           if (ch) {
594             int16_t *checks;
595             if (!(checks = SEN_REALLOC(nstr->checks, ds * sizeof(int16_t)+ 1))) {
596               if (nstr->ctypes) { SEN_FREE(nstr->ctypes); nstr->ctypes = NULL; }
597               SEN_FREE(nstr->checks); nstr->checks = NULL;
598               SEN_FREE(nstr->norm); nstr->norm = NULL;
599               return sen_memory_exhausted;
600             }
601             ch = checks + (ch - nstr->checks);
602             nstr->checks = checks;
603           }
604           if (cp) {
605             uint_least8_t *ctypes;
606             if (!(ctypes = SEN_REALLOC(nstr->ctypes, ds + 1))) {
607               SEN_FREE(nstr->ctypes); nstr->ctypes = NULL;
608               if (nstr->checks) { SEN_FREE(nstr->checks); nstr->checks = NULL; }
609               SEN_FREE(nstr->norm); nstr->norm = NULL;
610               return sen_memory_exhausted;
611             }
612             cp = ctypes + (cp - nstr->ctypes);
613             nstr->ctypes = ctypes;
614           }
615         }
616
617         memcpy(d, p, lp);
618         d_ = d;
619         d += lp;
620         length++;
621         if (cp) { *cp++ = sen_nfkc_ctype(p); }
622         if (ch) {
623           size_t i;
624           if (s_ == s + ls) {
625             *ch++ = -1;
626           } else {
627             *ch++ = (int16_t)(s + ls - s_);
628             s__ = s_;
629             s_ = s + ls;
630           }
631           for (i = lp; i > 1; i--) { *ch++ = 0; }
632         }
633       }
634     }
635   }
636   if (cp) { *cp = sen_str_null; }
637   *d = '\0';
638   nstr->length = length;
639   nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
640   return sen_success;
641 }
642
643 /* Assume that nstr->flags is always zero */
644 inline static sen_rc
645 fast_normalize_utf8(sen_nstr *nstr)
646 {
647         sen_ctx *ctx = nstr->ctx;
648         const unsigned char *s, *s_, *p, *p2, *pe, *e;
649         unsigned char *d, *d_, *de;
650         size_t ls, lp, size = nstr->orig_blen;
651         int             normed = 0;
652         size_t  ds = 0;
653
654         ds = size * 3;
655         nstr->norm = SEN_MALLOC(ds + 1);
656         if (nstr->norm == NULL)
657                 return sen_memory_exhausted;
658
659         d = (unsigned char *)nstr->norm;
660         de = d + ds;
661         d_ = NULL;
662         e = (unsigned char *)nstr->orig + size;
663
664         for (s = s_ = (unsigned char *)nstr->orig; ; s += ls)
665         {
666                 if (!(ls = fast_sen_str_charlen_utf8(s, e)))
667                         break;
668
669                 if ((p = (unsigned char *)sen_nfkc_map1(s)))
670                 {
671                         pe = p + strlen((char *)p);
672                         normed = 1;
673                 }
674                 else
675                 {
676                         p = s;
677                         pe = p + ls;
678                 }
679
680                 if (d_ && (p2 = (unsigned char *)sen_nfkc_map2(d_, p)))
681                 {
682                         p = p2;
683                         pe = p + strlen((char *)p);
684                         d = d_;
685                         normed = 1;
686                 }
687
688                 /* Skip unprintable ascii */
689                 if (*p < 0x20)
690                 {
691                         normed = 0;
692                         continue;
693                 }
694
695                 if (normed)
696                 {
697                         for (; ; p += lp)
698                         {
699                                 if (!(lp = fast_sen_str_charlen_utf8(p, pe)))
700                                         break;
701
702                                 if (de <= d + lp)
703                                 {
704                                         unsigned char *norm;
705
706                                         ds += (ds >> 1) + lp;
707                                         if (!(norm = SEN_REALLOC(nstr->norm, ds + 1)))
708                                         {
709                                                 SEN_FREE(nstr->norm); nstr->norm = NULL;
710                                                 return sen_memory_exhausted;
711                                         }
712                                         de = norm + ds;
713                                         d = norm + (d - (unsigned char *)nstr->norm);
714                                         nstr->norm = norm;
715                                 }
716
717                                 memcpy(d, p, lp);
718                                 d_ = d;
719                                 d += lp;
720                         }
721
722                         normed = 0;
723                 }
724                 else
725                 {
726                         if (de <= d + ls)
727                         {
728                                 unsigned char *norm;
729
730                                 ds += (ds >> 1) + ls;
731                                 if (!(norm = SEN_REALLOC(nstr->norm, ds + 1)))
732                                 {
733                                         SEN_FREE(nstr->norm); nstr->norm = NULL;
734                                         return sen_memory_exhausted;
735                                 }
736                                 de = norm + ds;
737                                 d = norm + (d - (unsigned char *)nstr->norm);
738                                 nstr->norm = norm;
739                         }
740
741                         memcpy(d, p, ls);
742                         d_ = d;
743                         d += ls;
744                 }
745         }
746         *d = '\0';
747         nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
748         return sen_success;
749 }
750 #endif /* NO_NFKC */
751
752 inline static sen_rc
753 normalize_sjis(sen_nstr *nstr)
754 {
755   static uint16_t hankana[] = {
756     0x8140, 0x8142, 0x8175, 0x8176, 0x8141, 0x8145, 0x8392, 0x8340, 0x8342,
757     0x8344, 0x8346, 0x8348, 0x8383, 0x8385, 0x8387, 0x8362, 0x815b, 0x8341,
758     0x8343, 0x8345, 0x8347, 0x8349, 0x834a, 0x834c, 0x834e, 0x8350, 0x8352,
759     0x8354, 0x8356, 0x8358, 0x835a, 0x835c, 0x835e, 0x8360, 0x8363, 0x8365,
760     0x8367, 0x8369, 0x836a, 0x836b, 0x836c, 0x836d, 0x836e, 0x8371, 0x8374,
761     0x8377, 0x837a, 0x837d, 0x837e, 0x8380, 0x8381, 0x8382, 0x8384, 0x8386,
762     0x8388, 0x8389, 0x838a, 0x838b, 0x838c, 0x838d, 0x838f, 0x8393, 0x814a,
763     0x814b
764   };
765   static unsigned char dakuten[] = {
766     0x94, 0, 0, 0, 0, 0x4b, 0, 0x4d, 0, 0x4f, 0, 0x51, 0, 0x53, 0, 0x55, 0,
767     0x57, 0, 0x59, 0, 0x5b, 0, 0x5d, 0, 0x5f, 0, 0x61, 0, 0, 0x64, 0, 0x66,
768     0, 0x68, 0, 0, 0, 0, 0, 0, 0x6f, 0, 0, 0x72, 0, 0, 0x75, 0, 0, 0x78, 0,
769     0, 0x7b
770   };
771   static unsigned char handaku[] = {
772     0x70, 0, 0, 0x73, 0, 0, 0x76, 0, 0, 0x79, 0, 0, 0x7c
773   };
774   int16_t *ch;
775   sen_ctx *ctx = nstr->ctx;
776   const unsigned char *s, *s_;
777   unsigned char *d, *d0, *d_, b, *e;
778   uint_least8_t *cp, *ctypes, ctype;
779   size_t size = nstr->orig_blen, length = 0;
780   int removeblankp = nstr->flags & SEN_STR_REMOVEBLANK;
781   if (!(nstr->norm = SEN_MALLOC(size * 2 + 1))) {
782     return sen_memory_exhausted;
783   }
784   d0 = (unsigned char *) nstr->norm;
785   if (nstr->flags & SEN_STR_WITH_CHECKS) {
786     if (!(nstr->checks = SEN_MALLOC(size * 2 * sizeof(int16_t) + 1))) {
787       SEN_FREE(nstr->norm);
788       nstr->norm = NULL;
789       return sen_memory_exhausted;
790     }
791   }
792   ch = nstr->checks;
793   if (nstr->flags & SEN_STR_WITH_CTYPES) {
794     if (!(nstr->ctypes = SEN_MALLOC(size + 1))) {
795       SEN_FREE(nstr->checks);
796       SEN_FREE(nstr->norm);
797       nstr->checks = NULL;
798       nstr->norm = NULL;
799       return sen_memory_exhausted;
800     }
801   }
802   cp = ctypes = nstr->ctypes;
803   e = (unsigned char *)nstr->orig + size;
804   for (s = s_ = (unsigned char *) nstr->orig, d = d_ = d0; s < e; s++) {
805     if ((*s & 0x80)) {
806       if (0xa0 <= *s && *s <= 0xdf) {
807         uint16_t c = hankana[*s - 0xa0];
808         switch (c) {
809         case 0x814a :
810           if (d > d0 + 1 && d[-2] == 0x83
811               && 0x45 <= d[-1] && d[-1] <= 0x7a && (b = dakuten[d[-1] - 0x45])) {
812             *(d - 1) = b;
813             if (ch) { ch[-1]++; s_++; }
814             continue;
815           } else {
816             *d++ = c >> 8; *d = c & 0xff;
817           }
818           break;
819         case 0x814b :
820           if (d > d0 + 1 && d[-2] == 0x83
821               && 0x6e <= d[-1] && d[-1] <= 0x7a && (b = handaku[d[-1] - 0x6e])) {
822             *(d - 1) = b;
823             if (ch) { ch[-1]++; s_++; }
824             continue;
825           } else {
826             *d++ = c >> 8; *d = c & 0xff;
827           }
828           break;
829         default :
830           *d++ = c >> 8; *d = c & 0xff;
831           break;
832         }
833         ctype = sen_str_katakana;
834       } else {
835         if ((s + 1) < e && 0x40 <= *(s + 1) && *(s + 1) <= 0xfc) {
836           unsigned char c1 = *s++, c2 = *s, c3 = 0;
837           if (0x81 <= c1 && c1 <= 0x87) {
838             switch (c1 & 0x0f) {
839             case 1 :
840               switch (c2) {
841               case 0x5b :
842                 *d++ = c1; *d = c2;
843                 ctype = sen_str_katakana;
844                 break;
845               case 0x58 :
846                 *d++ = c1; *d = c2;
847                 ctype = sen_str_kanji;
848                 break;
849               case 0x40 :
850                 if (removeblankp) {
851                   if (cp > ctypes) { *(cp - 1) |= SEN_NSTR_BLANK; }
852                   continue;
853                 } else {
854                   *d = ' ';
855                   ctype = SEN_NSTR_BLANK|sen_str_symbol;
856                 }
857                 break;
858               default :
859                 if (0x43 <= c2 && c2 <= 0x7e && (c3 = symbol[c2 - 0x43])) {
860                   *d = c3;
861                   ctype = sen_str_symbol;
862                 } else if (0x7f <= c2 && c2 <= 0x97 && (c3 = symbol[c2 - 0x44])) {
863                   *d = c3;
864                   ctype = sen_str_symbol;
865                 } else {
866                   *d++ = c1; *d = c2;
867                   ctype = sen_str_others;
868                 }
869                 break;
870               }
871               break;
872             case 2 :
873               c3 = c2 - 0x1f;
874               if (0x4f <= c2 && c2 <= 0x58) {
875                 ctype = sen_str_digit;
876                 *d = c2 - 0x1f;
877               } else if (0x60 <= c2 && c2 <= 0x79) {
878                 ctype = sen_str_alpha;
879                 *d = c2 + 0x01;
880               } else if (0x81 <= c2 && c2 <= 0x9a) {
881                 ctype = sen_str_alpha;
882                 *d = c2 - 0x20;
883               } else if (0x9f <= c2 && c2 <= 0xf1) {
884                 *d++ = c1; *d = c2;
885                 ctype = sen_str_hiragana;
886               } else {
887                 *d++ = c1; *d = c2;
888                 ctype = sen_str_others;
889               }
890               break;
891             case 3 :
892               if (0x40 <= c2 && c2 <= 0x96) {
893                 *d++ = c1; *d = c2;
894                 ctype = sen_str_katakana;
895               } else {
896                 *d++ = c1; *d = c2;
897                 ctype = sen_str_symbol;
898               }
899               break;
900             case 4 :
901             case 7 :
902               *d++ = c1; *d = c2;
903               ctype = sen_str_symbol;
904               break;
905             default :
906               *d++ = c1; *d = c2;
907               ctype = sen_str_others;
908               break;
909             }
910           } else {
911             *d++ = c1; *d = c2;
912             ctype = sen_str_kanji;
913           }
914         } else {
915           /* skip invalid character */
916           continue;
917         }
918       }
919     } else {
920       unsigned char c = *s;
921       switch (c >> 4) {
922       case 0 :
923       case 1 :
924         /* skip unprintable ascii */
925         if (cp > ctypes) { *(cp - 1) |= SEN_NSTR_BLANK; }
926         continue;
927       case 2 :
928         if (c == 0x20) {
929           if (removeblankp) {
930             if (cp > ctypes) { *(cp - 1) |= SEN_NSTR_BLANK; }
931             continue;
932           } else {
933             *d = ' ';
934             ctype = SEN_NSTR_BLANK|sen_str_symbol;
935           }
936         } else {
937           *d = c;
938           ctype = sen_str_symbol;
939         }
940         break;
941       case 3 :
942         *d = c;
943         ctype = (c <= 0x39) ? sen_str_digit : sen_str_symbol;
944         break;
945       case 4 :
946         *d = ('A' <= c) ? c + 0x20 : c;
947         ctype = (c == 0x40) ? sen_str_symbol : sen_str_alpha;
948         break;
949       case 5 :
950         *d = (c <= 'Z') ? c + 0x20 : c;
951         ctype = (c <= 0x5a) ? sen_str_alpha : sen_str_symbol;
952         break;
953       case 6 :
954         *d = c;
955         ctype = (c == 0x60) ? sen_str_symbol : sen_str_alpha;
956         break;
957       case 7 :
958         *d = c;
959         ctype = (c <= 0x7a) ? sen_str_alpha : (c == 0x7f ? sen_str_others : sen_str_symbol);
960         break;
961       default :
962         *d = c;
963         ctype = sen_str_others;
964         break;
965       }
966     }
967     d++;
968     length++;
969     if (cp) { *cp++ = ctype; }
970     if (ch) {
971       *ch++ = (int16_t)(s + 1 - s_);
972       s_ = s + 1;
973       while (++d_ < d) { *ch++ = 0; }
974     }
975   }
976   if (cp) { *cp = sen_str_null; }
977   *d = '\0';
978   nstr->length = length;
979   nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
980   return sen_success;
981 }
982
983 inline static sen_rc
984 normalize_none(sen_nstr *nstr)
985 {
986   int16_t *ch;
987   sen_ctx *ctx = nstr->ctx;
988   const unsigned char *s, *s_, *e;
989   unsigned char *d, *d0, *d_;
990   uint_least8_t *cp, *ctypes, ctype;
991   size_t size = nstr->orig_blen, length = 0;
992   int removeblankp = nstr->flags & SEN_STR_REMOVEBLANK;
993   if (!(nstr->norm = SEN_MALLOC(size + 1))) {
994     return sen_memory_exhausted;
995   }
996   d0 = (unsigned char *) nstr->norm;
997   if (nstr->flags & SEN_STR_WITH_CHECKS) {
998     if (!(nstr->checks = SEN_MALLOC(size * sizeof(int16_t) + 1))) {
999       SEN_FREE(nstr->norm);
1000       nstr->norm = NULL;
1001       return sen_memory_exhausted;
1002     }
1003   }
1004   ch = nstr->checks;
1005   if (nstr->flags & SEN_STR_WITH_CTYPES) {
1006     if (!(nstr->ctypes = SEN_MALLOC(size + 1))) {
1007       SEN_FREE(nstr->checks);
1008       SEN_FREE(nstr->norm);
1009       nstr->checks = NULL;
1010       nstr->norm = NULL;
1011       return sen_memory_exhausted;
1012     }
1013   }
1014   cp = ctypes = nstr->ctypes;
1015   e = (unsigned char *)nstr->orig + size;
1016   for (s = s_ = (unsigned char *) nstr->orig, d = d_ = d0; s < e; s++) {
1017     unsigned char c = *s;
1018     switch (c >> 4) {
1019     case 0 :
1020     case 1 :
1021       /* skip unprintable ascii */
1022       if (cp > ctypes) { *(cp - 1) |= SEN_NSTR_BLANK; }
1023       continue;
1024     case 2 :
1025       if (c == 0x20) {
1026         if (removeblankp) {
1027           if (cp > ctypes) { *(cp - 1) |= SEN_NSTR_BLANK; }
1028           continue;
1029         } else {
1030           *d = ' ';
1031           ctype = SEN_NSTR_BLANK|sen_str_symbol;
1032         }
1033       } else {
1034         *d = c;
1035         ctype = sen_str_symbol;
1036       }
1037       break;
1038     case 3 :
1039       *d = c;
1040       ctype = (c <= 0x39) ? sen_str_digit : sen_str_symbol;
1041       break;
1042     case 4 :
1043       *d = ('A' <= c) ? c + 0x20 : c;
1044       ctype = (c == 0x40) ? sen_str_symbol : sen_str_alpha;
1045       break;
1046     case 5 :
1047       *d = (c <= 'Z') ? c + 0x20 : c;
1048       ctype = (c <= 0x5a) ? sen_str_alpha : sen_str_symbol;
1049       break;
1050     case 6 :
1051       *d = c;
1052       ctype = (c == 0x60) ? sen_str_symbol : sen_str_alpha;
1053       break;
1054     case 7 :
1055       *d = c;
1056       ctype = (c <= 0x7a) ? sen_str_alpha : (c == 0x7f ? sen_str_others : sen_str_symbol);
1057       break;
1058     default :
1059       *d = c;
1060       ctype = sen_str_others;
1061       break;
1062     }
1063     d++;
1064     length++;
1065     if (cp) { *cp++ = ctype; }
1066     if (ch) {
1067       *ch++ = (int16_t)(s + 1 - s_);
1068       s_ = s + 1;
1069       while (++d_ < d) { *ch++ = 0; }
1070     }
1071   }
1072   if (cp) { *cp = sen_str_null; }
1073   *d = '\0';
1074   nstr->length = length;
1075   nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
1076   return sen_success;
1077 }
1078
1079 /* use cp1252 as latin1 */
1080 inline static sen_rc
1081 normalize_latin1(sen_nstr *nstr)
1082 {
1083   int16_t *ch;
1084   sen_ctx *ctx = nstr->ctx;
1085   const unsigned char *s, *s_, *e;
1086   unsigned char *d, *d0, *d_;
1087   uint_least8_t *cp, *ctypes, ctype;
1088   size_t size = strlen(nstr->orig), length = 0;
1089   int removeblankp = nstr->flags & SEN_STR_REMOVEBLANK;
1090   if (!(nstr->norm = SEN_MALLOC(size + 1))) {
1091     return sen_memory_exhausted;
1092   }
1093   d0 = (unsigned char *) nstr->norm;
1094   if (nstr->flags & SEN_STR_WITH_CHECKS) {
1095     if (!(nstr->checks = SEN_MALLOC(size * sizeof(int16_t) + 1))) {
1096       SEN_FREE(nstr->norm);
1097       nstr->norm = NULL;
1098       return sen_memory_exhausted;
1099     }
1100   }
1101   ch = nstr->checks;
1102   if (nstr->flags & SEN_STR_WITH_CTYPES) {
1103     if (!(nstr->ctypes = SEN_MALLOC(size + 1))) {
1104       SEN_FREE(nstr->checks);
1105       SEN_FREE(nstr->norm);
1106       nstr->checks = NULL;
1107       nstr->norm = NULL;
1108       return sen_memory_exhausted;
1109     }
1110   }
1111   cp = ctypes = nstr->ctypes;
1112   e = (unsigned char *)nstr->orig + size;
1113   for (s = s_ = (unsigned char *) nstr->orig, d = d_ = d0; s < e; s++) {
1114     unsigned char c = *s;
1115     switch (c >> 4) {
1116     case 0 :
1117     case 1 :
1118       /* skip unprintable ascii */
1119       if (cp > ctypes) { *(cp - 1) |= SEN_NSTR_BLANK; }
1120       continue;
1121     case 2 :
1122       if (c == 0x20) {
1123         if (removeblankp) {
1124           if (cp > ctypes) { *(cp - 1) |= SEN_NSTR_BLANK; }
1125           continue;
1126         } else {
1127           *d = ' ';
1128           ctype = SEN_NSTR_BLANK|sen_str_symbol;
1129         }
1130       } else {
1131         *d = c;
1132         ctype = sen_str_symbol;
1133       }
1134       break;
1135     case 3 :
1136       *d = c;
1137       ctype = (c <= 0x39) ? sen_str_digit : sen_str_symbol;
1138       break;
1139     case 4 :
1140       *d = ('A' <= c) ? c + 0x20 : c;
1141       ctype = (c == 0x40) ? sen_str_symbol : sen_str_alpha;
1142       break;
1143     case 5 :
1144       *d = (c <= 'Z') ? c + 0x20 : c;
1145       ctype = (c <= 0x5a) ? sen_str_alpha : sen_str_symbol;
1146       break;
1147     case 6 :
1148       *d = c;
1149       ctype = (c == 0x60) ? sen_str_symbol : sen_str_alpha;
1150       break;
1151     case 7 :
1152       *d = c;
1153       ctype = (c <= 0x7a) ? sen_str_alpha : (c == 0x7f ? sen_str_others : sen_str_symbol);
1154       break;
1155     case 8 :
1156       if (c == 0x8a || c == 0x8c || c == 0x8e) {
1157         *d = c + 0x10;
1158         ctype = sen_str_alpha;
1159       } else {
1160         *d = c;
1161         ctype = sen_str_symbol;
1162       }
1163       break;
1164     case 9 :
1165       if (c == 0x9a || c == 0x9c || c == 0x9e || c == 0x9f) {
1166         *d = (c == 0x9f) ? c + 0x60 : c;
1167         ctype = sen_str_alpha;
1168       } else {
1169         *d = c;
1170         ctype = sen_str_symbol;
1171       }
1172       break;
1173     case 0x0c :
1174       *d = c + 0x20;
1175       ctype = sen_str_alpha;
1176       break;
1177     case 0x0d :
1178       *d = (c == 0xd7 || c == 0xdf) ? c : c + 0x20;
1179       ctype = (c == 0xd7) ? sen_str_symbol : sen_str_alpha;
1180       break;
1181     case 0x0e :
1182       *d = c;
1183       ctype = sen_str_alpha;
1184       break;
1185     case 0x0f :
1186       *d = c;
1187       ctype = (c == 0xf7) ? sen_str_symbol : sen_str_alpha;
1188       break;
1189     default :
1190       *d = c;
1191       ctype = sen_str_others;
1192       break;
1193     }
1194     d++;
1195     length++;
1196     if (cp) { *cp++ = ctype; }
1197     if (ch) {
1198       *ch++ = (int16_t)(s + 1 - s_);
1199       s_ = s + 1;
1200       while (++d_ < d) { *ch++ = 0; }
1201     }
1202   }
1203   if (cp) { *cp = sen_str_null; }
1204   *d = '\0';
1205   nstr->length = length;
1206   nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
1207   return sen_success;
1208 }
1209
1210 inline static sen_rc
1211 normalize_koi8r(sen_nstr *nstr)
1212 {
1213   int16_t *ch;
1214   sen_ctx *ctx = nstr->ctx;
1215   const unsigned char *s, *s_, *e;
1216   unsigned char *d, *d0, *d_;
1217   uint_least8_t *cp, *ctypes, ctype;
1218   size_t size = strlen(nstr->orig), length = 0;
1219   int removeblankp = nstr->flags & SEN_STR_REMOVEBLANK;
1220   if (!(nstr->norm = SEN_MALLOC(size + 1))) {
1221     return sen_memory_exhausted;
1222   }
1223   d0 = (unsigned char *) nstr->norm;
1224   if (nstr->flags & SEN_STR_WITH_CHECKS) {
1225     if (!(nstr->checks = SEN_MALLOC(size * sizeof(int16_t) + 1))) {
1226       SEN_FREE(nstr->norm);
1227       nstr->norm = NULL;
1228       return sen_memory_exhausted;
1229     }
1230   }
1231   ch = nstr->checks;
1232   if (nstr->flags & SEN_STR_WITH_CTYPES) {
1233     if (!(nstr->ctypes = SEN_MALLOC(size + 1))) {
1234       SEN_FREE(nstr->checks);
1235       SEN_FREE(nstr->norm);
1236       nstr->checks = NULL;
1237       nstr->norm = NULL;
1238       return sen_memory_exhausted;
1239     }
1240   }
1241   cp = ctypes = nstr->ctypes;
1242   e = (unsigned char *)nstr->orig + size;
1243   for (s = s_ = (unsigned char *) nstr->orig, d = d_ = d0; s < e; s++) {
1244     unsigned char c = *s;
1245     switch (c >> 4) {
1246     case 0 :
1247     case 1 :
1248       /* skip unprintable ascii */
1249       if (cp > ctypes) { *(cp - 1) |= SEN_NSTR_BLANK; }
1250       continue;
1251     case 2 :
1252       if (c == 0x20) {
1253         if (removeblankp) {
1254           if (cp > ctypes) { *(cp - 1) |= SEN_NSTR_BLANK; }
1255           continue;
1256         } else {
1257           *d = ' ';
1258           ctype = SEN_NSTR_BLANK|sen_str_symbol;
1259         }
1260       } else {
1261         *d = c;
1262         ctype = sen_str_symbol;
1263       }
1264       break;
1265     case 3 :
1266       *d = c;
1267       ctype = (c <= 0x39) ? sen_str_digit : sen_str_symbol;
1268       break;
1269     case 4 :
1270       *d = ('A' <= c) ? c + 0x20 : c;
1271       ctype = (c == 0x40) ? sen_str_symbol : sen_str_alpha;
1272       break;
1273     case 5 :
1274       *d = (c <= 'Z') ? c + 0x20 : c;
1275       ctype = (c <= 0x5a) ? sen_str_alpha : sen_str_symbol;
1276       break;
1277     case 6 :
1278       *d = c;
1279       ctype = (c == 0x60) ? sen_str_symbol : sen_str_alpha;
1280       break;
1281     case 7 :
1282       *d = c;
1283       ctype = (c <= 0x7a) ? sen_str_alpha : (c == 0x7f ? sen_str_others : sen_str_symbol);
1284       break;
1285     case 0x0a :
1286       *d = c;
1287       ctype = (c == 0xa3) ? sen_str_alpha : sen_str_others;
1288       break;
1289     case 0x0b :
1290       if (c == 0xb3) {
1291         *d = c - 0x10;
1292         ctype = sen_str_alpha;
1293       } else {
1294         *d = c;
1295         ctype = sen_str_others;
1296       }
1297       break;
1298     case 0x0c :
1299     case 0x0d :
1300       *d = c;
1301       ctype = sen_str_alpha;
1302       break;
1303     case 0x0e :
1304     case 0x0f :
1305       *d = c - 0x20;
1306       ctype = sen_str_alpha;
1307       break;
1308     default :
1309       *d = c;
1310       ctype = sen_str_others;
1311       break;
1312     }
1313     d++;
1314     length++;
1315     if (cp) { *cp++ = ctype; }
1316     if (ch) {
1317       *ch++ = (int16_t)(s + 1 - s_);
1318       s_ = s + 1;
1319       while (++d_ < d) { *ch++ = 0; }
1320     }
1321   }
1322   if (cp) { *cp = sen_str_null; }
1323   *d = '\0';
1324   nstr->length = length;
1325   nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
1326   return sen_success;
1327 }
1328
1329 sen_nstr *
1330 sen_nstr_open(const char *str, size_t str_len, sen_encoding encoding, int flags)
1331 {
1332   sen_rc rc;
1333   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
1334   sen_nstr *nstr;
1335   if (!str) { return NULL; }
1336   if (!(nstr = SEN_MALLOC(sizeof(sen_nstr)))) {
1337     SEN_LOG(sen_log_alert, "memory allocation on sen_fakenstr_open failed !");
1338     return NULL;
1339   }
1340   nstr->orig = str;
1341   nstr->orig_blen = str_len;
1342   nstr->norm = NULL;
1343   nstr->norm_blen = 0;
1344   nstr->checks = NULL;
1345   nstr->ctypes = NULL;
1346   nstr->encoding = encoding;
1347   nstr->flags = flags;
1348   nstr->ctx = ctx;
1349   switch (encoding) {
1350   case sen_enc_euc_jp :
1351     rc = normalize_euc(nstr);
1352     break;
1353   case sen_enc_utf8 :
1354 #ifdef NO_NFKC
1355     rc = normalize_none(nstr);
1356 #else /* NO_NFKC */
1357     rc = normalize_utf8(nstr);
1358 #endif /* NO_NFKC */
1359     break;
1360   case sen_enc_sjis :
1361     rc = normalize_sjis(nstr);
1362     break;
1363   case sen_enc_latin1 :
1364     rc = normalize_latin1(nstr);
1365     break;
1366   case sen_enc_koi8r :
1367     rc = normalize_koi8r(nstr);
1368     break;
1369   default :
1370     rc = normalize_none(nstr);
1371     break;
1372   }
1373   if (rc) {
1374     sen_nstr_close(nstr);
1375     return NULL;
1376   }
1377   return nstr;
1378 }
1379
1380 /* Assume that current encoding is UTF8 */
1381 sen_nstr *
1382 fast_sen_nstr_open(const char *str, size_t str_len)
1383 {
1384         sen_ctx *ctx = &sen_gctx;
1385         sen_nstr *nstr = NULL;
1386
1387         if (!str)
1388                 return NULL;
1389
1390         nstr = SEN_MALLOC(sizeof(sen_nstr));
1391         if (nstr == NULL)
1392         {
1393                 SEN_LOG(sen_log_alert, "memory allocation on sen_fakenstr_open failed !");
1394                 return NULL;
1395         }
1396
1397         nstr->orig = str;
1398         nstr->orig_blen = str_len;
1399         nstr->norm = NULL;
1400         nstr->norm_blen = 0;
1401         nstr->checks = NULL;
1402         nstr->ctypes = NULL;
1403         nstr->encoding = sen_enc_utf8;
1404         nstr->flags = 0;
1405         nstr->ctx = ctx;
1406
1407         if (fast_normalize_utf8(nstr))
1408         {
1409                 sen_nstr_close(nstr);
1410                 nstr = NULL;
1411         }
1412
1413         return nstr;
1414 }
1415
1416 sen_nstr *
1417 sen_fakenstr_open(const char *str, size_t str_len, sen_encoding encoding, int flags)
1418 {
1419   /* TODO: support SEN_STR_REMOVEBLANK flag and ctypes */
1420   sen_nstr *nstr;
1421   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
1422
1423   if (!(nstr = SEN_MALLOC(sizeof(sen_nstr)))) {
1424     SEN_LOG(sen_log_alert, "memory allocation on sen_fakenstr_open failed !");
1425     return NULL;
1426   }
1427   if (!(nstr->norm = SEN_MALLOC(str_len + 1))) {
1428     SEN_LOG(sen_log_alert, "memory allocation for keyword on sen_snip_add_cond failed !");
1429     SEN_FREE(nstr);
1430     return NULL;
1431   }
1432   nstr->orig = str;
1433   nstr->orig_blen = str_len;
1434   memcpy(nstr->norm, str, str_len);
1435   nstr->norm[str_len] = '\0';
1436   nstr->norm_blen = str_len;
1437   nstr->ctypes = NULL;
1438   nstr->flags = flags;
1439   nstr->ctx = ctx;
1440
1441   if (flags & SEN_STR_WITH_CHECKS) {
1442     int16_t f = 0;
1443     unsigned char c;
1444     size_t i;
1445     if (!(nstr->checks = (int16_t *) SEN_MALLOC(sizeof(int16_t) * str_len))) {
1446       SEN_FREE(nstr->norm);
1447       SEN_FREE(nstr);
1448       return NULL;
1449     }
1450     switch (encoding) {
1451     case sen_enc_euc_jp:
1452       for (i = 0; i < str_len; i++) {
1453         if (!f) {
1454           c = (unsigned char) str[i];
1455           f = ((c >= 0xa1U && c <= 0xfeU) || c == 0x8eU ? 2 : (c == 0x8fU ? 3 : 1)
1456             );
1457           nstr->checks[i] = f;
1458         } else {
1459           nstr->checks[i] = 0;
1460         }
1461         f--;
1462       }
1463       break;
1464     case sen_enc_sjis:
1465       for (i = 0; i < str_len; i++) {
1466         if (!f) {
1467           c = (unsigned char) str[i];
1468           f = (c >= 0x81U && ((c <= 0x9fU) || (c >= 0xe0U && c <= 0xfcU)) ? 2 : 1);
1469           nstr->checks[i] = f;
1470         } else {
1471           nstr->checks[i] = 0;
1472         }
1473         f--;
1474       }
1475       break;
1476     case sen_enc_utf8:
1477       for (i = 0; i < str_len; i++) {
1478         if (!f) {
1479           c = (unsigned char) str[i];
1480           f = (c & 0x80U ? (c & 0x20U ? (c & 0x10U ? 4 : 3)
1481                            : 2)
1482                : 1);
1483           nstr->checks[i] = f;
1484         } else {
1485           nstr->checks[i] = 0;
1486         }
1487         f--;
1488       }
1489       break;
1490     default:
1491       for (i = 0; i < str_len; i++) {
1492         nstr->checks[i] = 1;
1493       }
1494       break;
1495     }
1496   }
1497   else {
1498     nstr->checks = NULL;
1499   }
1500   return nstr;
1501 }
1502
1503 sen_rc
1504 sen_nstr_close(sen_nstr *nstr)
1505 {
1506   if (nstr) {
1507     sen_ctx *ctx = nstr->ctx;
1508     if (nstr->norm) { SEN_FREE(nstr->norm); }
1509     if (nstr->ctypes) { SEN_FREE(nstr->ctypes); }
1510     if (nstr->checks) { SEN_FREE(nstr->checks); }
1511     SEN_FREE(nstr);
1512     return sen_success;
1513   } else {
1514     return sen_invalid_argument;
1515   }
1516 }
1517
1518 static const char *sen_enc_string[] = {
1519   "default",
1520   "none",
1521   "euc_jp",
1522   "utf8",
1523   "sjis",
1524   "latin1",
1525   "koi8r"
1526 };
1527
1528 const char *
1529 sen_enctostr(sen_encoding enc)
1530 {
1531   if (enc < (sizeof(sen_enc_string) / sizeof(char *))) {
1532     return sen_enc_string[enc];
1533   } else {
1534     return "unknown";
1535   }
1536 }
1537
1538 sen_encoding
1539 sen_strtoenc(const char *str)
1540 {
1541   sen_encoding e = sen_enc_euc_jp;
1542   int i = sizeof(sen_enc_string) / sizeof(sen_enc_string[0]);
1543   while (i--) {
1544     if (!strcmp(str, sen_enc_string[i])) {
1545       e = (sen_encoding)i;
1546     }
1547   }
1548   return e;
1549 }
1550
1551 size_t
1552 sen_str_len(const char *str, sen_encoding encoding, const char **last)
1553 {
1554   size_t len, tlen;
1555   const char *p = NULL;
1556   for (len = 0; ; len++) {
1557     p = str;
1558     if (!(tlen = sen_str_charlen(str, encoding))) {
1559       break;
1560     }
1561     str += tlen;
1562   }
1563   if (last) { *last = p; }
1564   return len;
1565 }
1566
1567 int
1568 sen_isspace(const char *str, sen_encoding encoding)
1569 {
1570   const unsigned char *s = (const unsigned char *) str;
1571   if (!s) { return 0; }
1572   switch (s[0]) {
1573   case ' ' :
1574   case '\f' :
1575   case '\n' :
1576   case '\r' :
1577   case '\t' :
1578   case '\v' :
1579     return 1;
1580   case 0x81 :
1581     if (encoding == sen_enc_sjis && s[1] == 0x40) { return 2; }
1582     break;
1583   case 0xA1 :
1584     if (encoding == sen_enc_euc_jp && s[1] == 0xA1) { return 2; }
1585     break;
1586   case 0xE3 :
1587     if (encoding == sen_enc_utf8 && s[1] == 0x80 && s[2] == 0x80) { return 3; }
1588     break;
1589   default :
1590     break;
1591   }
1592   return 0;
1593 }
1594
1595 int
1596 sen_atoi(const char *nptr, const char *end, const char **rest)
1597 {
1598   /* FIXME: INT_MIN is not supported */
1599   const char *p = nptr;
1600   int v = 0, t, n = 0, o = 0;
1601   if (p < end && *p == '-') {
1602     p++;
1603     n = 1;
1604     o = 1;
1605   }
1606   while (p < end && *p >= '0' && *p <= '9') {
1607     t = v * 10 + (*p - '0');
1608     if (t < v) { v =0; break; }
1609     v = t;
1610     o = 0;
1611     p++;
1612   }
1613   if (rest) { *rest = o ? nptr : p; }
1614   return n ? -v : v;
1615 }
1616
1617 unsigned int
1618 sen_atoui(const char *nptr, const char *end, const char **rest)
1619 {
1620   unsigned int v = 0, t;
1621   while (nptr < end && *nptr >= '0' && *nptr <= '9') {
1622     t = v * 10 + (*nptr - '0');
1623     if (t < v) { v = 0; break; }
1624     v = t;
1625     nptr++;
1626   }
1627   if (rest) { *rest = nptr; }
1628   return v;
1629 }
1630
1631 int64_t
1632 sen_atoll(const char *nptr, const char *end, const char **rest)
1633 {
1634   /* FIXME: INT_MIN is not supported */
1635   const char *p = nptr;
1636   int n = 0, o = 0;
1637   int64_t v = 0, t;
1638   if (p < end && *p == '-') {
1639     p++;
1640     n = 1;
1641     o = 1;
1642   }
1643   while (p < end && *p >= '0' && *p <= '9') {
1644     t = v * 10 + (*p - '0');
1645     if (t < v) { v = 0; break; }
1646     v = t;
1647     o = 0;
1648     p++;
1649   }
1650   if (rest) { *rest = o ? nptr : p; }
1651   return n ? -v : v;
1652 }
1653
1654 unsigned int
1655 sen_htoui(const char *nptr, const char *end, const char **rest)
1656 {
1657   unsigned int v = 0, t;
1658   while (nptr < end) {
1659     switch (*nptr) {
1660     case '0' :
1661     case '1' :
1662     case '2' :
1663     case '3' :
1664     case '4' :
1665     case '5' :
1666     case '6' :
1667     case '7' :
1668     case '8' :
1669     case '9' :
1670       t = v * 16 + (*nptr++ - '0');
1671       break;
1672     case 'a' :
1673     case 'b' :
1674     case 'c' :
1675     case 'd' :
1676     case 'e' :
1677     case 'f' :
1678       t = v * 16 + (*nptr++ - 'a') + 10;
1679       break;
1680     case 'A' :
1681     case 'B' :
1682     case 'C' :
1683     case 'D' :
1684     case 'E' :
1685     case 'F' :
1686       t = v * 16 + (*nptr++ - 'A') + 10;
1687       break;
1688     default :
1689       v = 0; goto exit;
1690     }
1691     if (t < v) { v = 0; goto exit; }
1692     v = t;
1693   }
1694 exit :
1695   if (rest) { *rest = nptr; }
1696   return v;
1697 }
1698
1699 void
1700 sen_str_itoh(unsigned int i, char *p, unsigned int len)
1701 {
1702   static const char *hex = "0123456789ABCDEF";
1703   p += len;
1704   *p-- = '\0';
1705   while (len--) {
1706     *p-- = hex[i & 0xf];
1707     i >>= 4;
1708   }
1709 }
1710
1711 sen_rc
1712 sen_str_itoa(int i, char *p, char *end, char **rest)
1713 {
1714   /* FIXME: INT_MIN is not supported */
1715   char *q;
1716   if (p >= end) { return sen_invalid_argument; }
1717   if (i < 0) {
1718     *p++ = '-';
1719     i = -i;
1720   }
1721   q = p;
1722   do {
1723     if (p >= end) { return sen_invalid_argument; }
1724     *p++ = i % 10 + '0';
1725   } while ((i /= 10) > 0);
1726   if (rest) { *rest = p; }
1727   for (p--; q < p; q++, p--) {
1728     char t = *q;
1729     *q = *p;
1730     *p = t;
1731   }
1732   return sen_success;
1733 }
1734
1735 sen_rc
1736 sen_str_lltoa(int64_t i, char *p, char *end, char **rest)
1737 {
1738   /* FIXME: INT_MIN is not supported */
1739   char *q;
1740   if (p >= end) { return sen_invalid_argument; }
1741   if (i < 0) {
1742     *p++ = '-';
1743     i = -i;
1744   }
1745   q = p;
1746   do {
1747     if (p >= end) { return sen_invalid_argument; }
1748     *p++ = i % 10 + '0';
1749   } while ((i /= 10) > 0);
1750   if (rest) { *rest = p; }
1751   for (p--; q < p; q++, p--) {
1752     char t = *q;
1753     *q = *p;
1754     *p = t;
1755   }
1756   return sen_success;
1757 }
1758
1759 #define I2B(i) \
1760  ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(i) & 0x3f])
1761
1762 #define B2I(b) \
1763  (((b) < '+' || 'z' < (b)) ? 0xff : "\x3e\xff\xff\xff\x3f\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\xff\xff\xff\xff\xff\xff\xff\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\xff\xff\xff\xff\xff\xff\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33"[(b) - '+'])
1764
1765 #define MASK 0x34d34d34
1766
1767 char *
1768 sen_str_itob(sen_id id, char *p)
1769 {
1770   id ^= MASK;
1771   *p++ = I2B(id >> 24);
1772   *p++ = I2B(id >> 18);
1773   *p++ = I2B(id >> 12);
1774   *p++ = I2B(id >> 6);
1775   *p++ = I2B(id);
1776   return p;
1777 }
1778
1779 sen_id
1780 sen_str_btoi(char *b)
1781 {
1782   uint8_t i;
1783   sen_id id = 0;
1784   int len = 5;
1785   while (len--) {
1786     char c = *b++;
1787     if ((i = B2I(c)) == 0xff) { return 0; }
1788     id = (id << 6) + i;
1789   }
1790   return id ^ MASK;
1791 }
1792
1793 int
1794 sen_str_tok(char *str, size_t str_len, char delim, char **tokbuf, int buf_size, char **rest)
1795 {
1796   char **tok = tokbuf, **tok_end = tokbuf + buf_size;
1797   if (buf_size > 0) {
1798     char *str_end = str + str_len;
1799     for (;;str++) {
1800       if (str == str_end) {
1801         *tok++ = str;
1802         break;
1803       }
1804       if (delim == *str) {
1805         *str = '\0';
1806         *tok++ = str;
1807         if (tok == tok_end) { break; }
1808       }
1809     }
1810   }
1811   if (rest) { *rest = str; }
1812   return tok - tokbuf;
1813 }
1814
1815 inline static void
1816 op_getopt_flag(int *flags, const sen_str_getopt_opt *o,
1817                int argc, char * const argv[], int *i)
1818 {
1819   switch (o->op) {
1820     case getopt_op_none:
1821       break;
1822     case getopt_op_on:
1823       *flags |= o->flag;
1824       break;
1825     case getopt_op_off:
1826       *flags &= ~o->flag;
1827       break;
1828     case getopt_op_update:
1829       *flags = o->flag;
1830       break;
1831     default:
1832       return;
1833   }
1834   if (o->arg) {
1835     if (++(*i) < argc) {
1836       *o->arg = argv[*i];
1837     } else {
1838       /* TODO: error */
1839     }
1840   }
1841 }
1842
1843 int
1844 sen_str_getopt(int argc, char * const argv[], const sen_str_getopt_opt *opts,
1845                int *flags)
1846 {
1847   int i;
1848   for (i = 1; i < argc; i++) {
1849     const char * v = argv[i];
1850     if (*v == '-') {
1851       const sen_str_getopt_opt *o;
1852       int found;
1853       if (*++v == '-') {
1854         found = 0;
1855         for (o = opts; o->opt != '\0' || o->longopt != NULL; o++) {
1856           if (o->longopt && !strcmp(v, o->longopt)) {
1857             op_getopt_flag(flags, o, argc, argv, &i);
1858             found = 1;
1859             break;
1860           }
1861         }
1862         if (!found) { goto exit; }
1863       } else {
1864         const char *p;
1865         for (p = v; *p; p++) {
1866           found = 0;
1867           for (o = opts; o->opt != '\0' || o->longopt != NULL; o++) {
1868             if (o->opt && *p == o->opt) {
1869               op_getopt_flag(flags, o, argc, argv, &i);
1870               found = 1;
1871               break;
1872             }
1873           }
1874           if (!found) { goto exit; }
1875         }
1876       }
1877     } else {
1878       break;
1879     }
1880   }
1881   return i;
1882 exit:
1883   fprintf(stderr, "cannot recognize option '%s'.\n", argv[i]);
1884   return -1;
1885 }
1886
1887 #define UNIT_SIZE (1 << 12)
1888 #define UNIT_MASK (UNIT_SIZE - 1)
1889
1890 int sen_rbuf_margin_size = 0;
1891
1892 sen_rc
1893 sen_rbuf_init(sen_rbuf *buf, size_t size)
1894 {
1895   buf->head = NULL;
1896   buf->curr = NULL;
1897   buf->tail = NULL;
1898   return size ? sen_rbuf_resize(buf, size) : sen_success;
1899 }
1900
1901 sen_rc
1902 sen_rbuf_resize(sen_rbuf *buf, size_t newsize)
1903 {
1904   char *head;
1905   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
1906   newsize += sen_rbuf_margin_size + 1;
1907   newsize = (newsize + (UNIT_MASK)) & ~UNIT_MASK;
1908   head = buf->head - (buf->head ? sen_rbuf_margin_size : 0);
1909   if (!(head = SEN_REALLOC(head, newsize))) { return sen_memory_exhausted; }
1910   buf->curr = head + sen_rbuf_margin_size + SEN_RBUF_VSIZE(buf);
1911   buf->head = head + sen_rbuf_margin_size;
1912   buf->tail = head + newsize;
1913   return sen_success;
1914 }
1915
1916 sen_rc
1917 sen_rbuf_reinit(sen_rbuf *buf, size_t size)
1918 {
1919   SEN_RBUF_REWIND(buf);
1920   return sen_rbuf_resize(buf, size);
1921 }
1922
1923 sen_rc
1924 sen_rbuf_write(sen_rbuf *buf, const char *str, size_t len)
1925 {
1926   sen_rc rc = sen_success;
1927   if (SEN_RBUF_REST(buf) < len) {
1928     if ((rc = sen_rbuf_resize(buf, SEN_RBUF_VSIZE(buf) + len))) { return rc; }
1929   }
1930   memcpy(buf->curr, str, len);
1931   buf->curr += len;
1932   return rc;
1933 }
1934
1935 sen_rc
1936 sen_rbuf_reserve(sen_rbuf *buf, size_t len)
1937 {
1938   sen_rc rc = sen_success;
1939   if (SEN_RBUF_REST(buf) < len) {
1940     if ((rc = sen_rbuf_resize(buf, SEN_RBUF_VSIZE(buf) + len))) { return rc; }
1941   }
1942   return rc;
1943 }
1944
1945 sen_rc
1946 sen_rbuf_space(sen_rbuf *buf, size_t len)
1947 {
1948   sen_rc rc = sen_rbuf_reserve(buf, len);
1949   if (!rc) { buf->curr += len; }
1950   return rc;
1951 }
1952
1953 sen_rc
1954 sen_rbuf_itoa(sen_rbuf *buf, int i)
1955 {
1956   sen_rc rc = sen_success;
1957   while (sen_str_itoa(i, buf->curr, buf->tail, &buf->curr)) {
1958     if ((rc = sen_rbuf_resize(buf, SEN_RBUF_WSIZE(buf) + UNIT_SIZE))) { return rc; }
1959   }
1960   return rc;
1961 }
1962
1963 sen_rc
1964 sen_rbuf_lltoa(sen_rbuf *buf, int64_t i)
1965 {
1966   sen_rc rc = sen_success;
1967   while (sen_str_lltoa(i, buf->curr, buf->tail, &buf->curr)) {
1968     if ((rc = sen_rbuf_resize(buf, SEN_RBUF_WSIZE(buf) + UNIT_SIZE))) { return rc; }
1969   }
1970   return rc;
1971 }
1972
1973 sen_rc
1974 sen_rbuf_ftoa(sen_rbuf *buf, double d)
1975 {
1976   size_t len = 32;
1977   sen_rc rc = sen_success;
1978   if (SEN_RBUF_REST(buf) < len) {
1979     if ((rc = sen_rbuf_resize(buf, SEN_RBUF_VSIZE(buf) + len))) { return rc; }
1980   }
1981   switch (fpclassify(d)) {
1982   CASE_FP_NAN
1983     SEN_RBUF_PUTS(buf, "#<nan>");
1984     break;
1985   CASE_FP_INFINITE
1986     SEN_RBUF_PUTS(buf, d > 0 ? "#i1/0" : "#i-1/0");
1987     break;
1988   default :
1989     len = sprintf(buf->curr, "%#.15g", d);
1990     if (buf->curr[len - 1] == '.') {
1991       buf->curr += len;
1992       SEN_RBUF_PUTC(buf, '0');
1993     } else {
1994       char *p, *q;
1995       buf->curr[len] = '\0';
1996       if ((p = strchr(buf->curr, 'e'))) {
1997         for (q = p; *(q - 2) != '.' && *(q - 1) == '0'; q--) { len--; }
1998         memmove(q, p, buf->curr + len - q);
1999       } else {
2000         for (q = buf->curr + len; *(q - 2) != '.' && *(q - 1) == '0'; q--) { len--; }
2001       }
2002       buf->curr += len;
2003     }
2004     break;
2005   }
2006   return rc;
2007 }
2008
2009 sen_rc
2010 sen_rbuf_itoh(sen_rbuf *buf, int i)
2011 {
2012   size_t len = 8;
2013   sen_rc rc = sen_success;
2014   if (SEN_RBUF_REST(buf) < len) {
2015     if ((rc = sen_rbuf_resize(buf, SEN_RBUF_VSIZE(buf) + len))) { return rc; }
2016   }
2017   sen_str_itoh(i, buf->curr, len);
2018   buf->curr += len;
2019   return rc;
2020 }
2021
2022 sen_rc
2023 sen_rbuf_itob(sen_rbuf *buf, sen_id id)
2024 {
2025   size_t len = 5;
2026   sen_rc rc = sen_success;
2027   if (SEN_RBUF_REST(buf) < len) {
2028     if ((rc = sen_rbuf_resize(buf, SEN_RBUF_VSIZE(buf) + len))) { return rc; }
2029   }
2030   sen_str_itob(id, buf->curr);
2031   buf->curr += len;
2032   return rc;
2033 }
2034
2035 void
2036 sen_rbuf_str_esc(sen_rbuf *buf, const char *s, int len, sen_encoding encoding)
2037 {
2038   const char *e;
2039   unsigned int l;
2040   if (len < 0) { len = strlen(s); }
2041   SEN_RBUF_PUTC(buf, '"');
2042   for (e = s + len; s < e; s += l) {
2043     if (!(l = sen_str_charlen_nonnull(s, e, encoding))) { break; }
2044     if (l == 1) {
2045       switch (*s) {
2046       case '\n' :
2047         sen_rbuf_write(buf, "\\n", 2);
2048         break;
2049       case '"' :
2050         sen_rbuf_write(buf, "\\\"", 2);
2051         break;
2052       case '\\' :
2053         sen_rbuf_write(buf, "\\\\", 2);
2054         break;
2055       default :
2056         SEN_RBUF_PUTC(buf, *s);
2057       }
2058     } else {
2059       sen_rbuf_write(buf, s, l);
2060     }
2061   }
2062   SEN_RBUF_PUTC(buf, '"');
2063 }
2064
2065 sen_rc
2066 sen_rbuf_fin(sen_rbuf *buf)
2067 {
2068   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
2069   if (buf->head) {
2070     SEN_REALLOC(buf->head - sen_rbuf_margin_size, 0);
2071     buf->head = NULL;
2072   }
2073   return sen_success;
2074 }
2075
2076 struct _sen_lbuf_node {
2077   sen_lbuf_node *next;
2078   size_t size;
2079   char val[1];
2080 };
2081
2082 sen_rc
2083 sen_lbuf_init(sen_lbuf *buf)
2084 {
2085   buf->head = NULL;
2086   buf->tail = &buf->head;
2087   return sen_success;
2088 }
2089
2090 void *
2091 sen_lbuf_add(sen_lbuf *buf, size_t size)
2092 {
2093   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
2094   sen_lbuf_node *node = SEN_MALLOC(size + (size_t)(&((sen_lbuf_node *)0)->val));
2095   if (!node) { return NULL;  }
2096   node->next = NULL;
2097   node->size = size;
2098   *buf->tail = node;
2099   buf->tail = &node->next;
2100   return node->val;
2101 }
2102
2103 sen_rc
2104 sen_lbuf_fin(sen_lbuf *buf)
2105 {
2106   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
2107   sen_lbuf_node *cur, *next;
2108   for (cur = buf->head; cur; cur = next) {
2109     next = cur->next;
2110     SEN_FREE(cur);
2111   }
2112   return sen_success;
2113 }
2114
2115 sen_rc
2116 sen_substring(char **str, char **str_end, int start, int end, sen_encoding encoding)
2117 {
2118   int i;
2119   size_t l;
2120   char *s = *str, *e = *str_end;
2121   for (i = 0; s < e; i++, s += l) {
2122     if (i == start) { *str = s; }
2123     if (!(l = sen_str_charlen_nonnull(s, e, encoding))) {
2124       return sen_invalid_argument;
2125     }
2126     if (i == end) {
2127       *str_end = s;
2128       break;
2129     }
2130   }
2131   return sen_success;
2132 }
2133
2134 int
2135 sen_str_normalize(const char *str, unsigned int str_len,
2136                   sen_encoding encoding, int flags,
2137                   char *nstrbuf, int buf_size)
2138 {
2139   int len;
2140   sen_nstr *nstr;
2141   if (!(nstr = sen_nstr_open(str, str_len, encoding, flags))) {
2142     return -1;
2143   }
2144   /* if the buffer size is short to store for the normalized string,
2145      the required size is returned
2146      (to inform the caller to cast me again). */
2147   len = (int)nstr->norm_blen;
2148   if (buf_size > len) {
2149     memcpy(nstrbuf, nstr->norm, len + 1);
2150   } else if (buf_size == len) {
2151     /* NB: non-NULL-terminated */
2152     memcpy(nstrbuf, nstr->norm, len);
2153   }
2154   sen_nstr_close(nstr);
2155   return len;
2156 }
2157
2158 /* Assume that current encoding is UTF-8 */
2159 int
2160 fast_sen_str_normalize(const char *str, unsigned int str_len,
2161                                            char *nstrbuf, int buf_size)
2162 {
2163         int len;
2164         sen_nstr *nstr;
2165
2166         if (!(nstr = fast_sen_nstr_open(str, str_len)))
2167                 return -1;
2168
2169         /*
2170          * If the buffer size is short to store for the normalized string,
2171      * the required size is returned (to inform the caller to cast me again).
2172          */
2173         len = (int)nstr->norm_blen;
2174
2175         if (buf_size > len)
2176                 memcpy(nstrbuf, nstr->norm, len + 1);
2177         else if (buf_size == len)
2178                 /* NB: non-NULL-terminated */
2179                 memcpy(nstrbuf, nstr->norm, len);
2180         sen_nstr_close(nstr);
2181         return len;
2182 }