]> granicus.if.org Git - onig/blob - src/unicode.c
add encoding argument into str_dup()
[onig] / src / unicode.c
1 /**********************************************************************
2   unicode.c -  Oniguruma (regular expression library)
3 **********************************************************************/
4 /*-
5  * Copyright (c) 2002-2017  K.Kosako  <sndgk393 AT ybb DOT ne DOT jp>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include "regint.h"
31
32 struct PoolPropertyNameCtype {
33   short int name;
34   short int ctype;
35 };
36
37 #define ONIGENC_IS_UNICODE_ISO_8859_1_CTYPE(code,ctype) \
38   ((EncUNICODE_ISO_8859_1_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
39
40 static const unsigned short EncUNICODE_ISO_8859_1_CtypeTable[256] = {
41   0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
42   0x4008, 0x428c, 0x4289, 0x4288, 0x4288, 0x4288, 0x4008, 0x4008,
43   0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
44   0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
45   0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
46   0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
47   0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
48   0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
49   0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
50   0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
51   0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
52   0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
53   0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
54   0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
55   0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
56   0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
57   0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0288, 0x0008, 0x0008,
58   0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
59   0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
60   0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
61   0x0284, 0x01a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0,
62   0x00a0, 0x00a0, 0x30e2, 0x01a0, 0x00a0, 0x00a8, 0x00a0, 0x00a0,
63   0x00a0, 0x00a0, 0x10a0, 0x10a0, 0x00a0, 0x30e2, 0x00a0, 0x01a0,
64   0x00a0, 0x10a0, 0x30e2, 0x01a0, 0x10a0, 0x10a0, 0x10a0, 0x01a0,
65   0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
66   0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
67   0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x00a0,
68   0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x30e2,
69   0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
70   0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
71   0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x00a0,
72   0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2
73 };
74
75 #include "st.h"
76
77 #include "unicode_fold_data.c"
78
79 extern int
80 onigenc_unicode_mbc_case_fold(OnigEncoding enc,
81     OnigCaseFoldType flag ARG_UNUSED, const UChar** pp, const UChar* end,
82     UChar* fold)
83 {
84   const struct ByUnfoldKey* buk;
85
86   OnigCodePoint code;
87   int i, len, rlen;
88   const UChar *p = *pp;
89
90   code = ONIGENC_MBC_TO_CODE(enc, p, end);
91   len = enclen(enc, p);
92   *pp += len;
93
94 #ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
95   if ((flag & ONIGENC_CASE_FOLD_TURKISH_AZERI) != 0) {
96     if (code == 0x0130) {
97       return ONIGENC_CODE_TO_MBC(enc, 0x0069, fold);
98     }
99 #if 0
100     if (code == 0x0049) {
101       return ONIGENC_CODE_TO_MBC(enc, 0x0131, fold);
102     }
103 #endif
104   }
105 #endif
106
107   buk = unicode_unfold_key(code);
108   if (buk != 0) {
109     if (buk->fold_len == 1) {
110       return ONIGENC_CODE_TO_MBC(enc, *FOLDS1_FOLD(buk->index), fold);
111     }
112     else {
113       OnigCodePoint* addr;
114
115       FOLDS_FOLD_ADDR_BUK(buk, addr);
116       rlen = 0;
117       for (i = 0; i < buk->fold_len; i++) {
118         OnigCodePoint c = addr[i];
119         len = ONIGENC_CODE_TO_MBC(enc, c, fold);
120         fold += len;
121         rlen += len;
122       }
123       return rlen;
124     }
125   }
126
127   for (i = 0; i < len; i++) {
128     *fold++ = *p++;
129   }
130   return len;
131 }
132
133 static int
134 apply_case_fold1(int from, int to, OnigApplyAllCaseFoldFunc f, void* arg)
135 {
136   int i, j, k, n, r;
137
138   for (i = from; i < to; ) {
139     OnigCodePoint fold = *FOLDS1_FOLD(i);
140     n = FOLDS1_UNFOLDS_NUM(i);
141     for (j = 0; j < n; j++) {
142       OnigCodePoint unfold = FOLDS1_UNFOLDS(i)[j];
143
144       r = (*f)(fold, &unfold, 1, arg);
145       if (r != 0) return r;
146       r = (*f)(unfold, &fold, 1, arg);
147       if (r != 0) return r;
148
149       for (k = 0; k < j; k++) {
150         OnigCodePoint unfold2 = FOLDS1_UNFOLDS(i)[k];
151         r = (*f)(unfold, &unfold2, 1, arg);
152         if (r != 0) return r;
153         r = (*f)(unfold2, &unfold, 1, arg);
154         if (r != 0) return r;
155       }
156     }
157
158     i = FOLDS1_NEXT_INDEX(i);
159   }
160
161   return 0;
162 }
163
164 static int
165 apply_case_fold2(int from, int to, OnigApplyAllCaseFoldFunc f, void* arg)
166 {
167   int i, j, k, n, r;
168
169   for (i = from; i < to; ) {
170     OnigCodePoint* fold = FOLDS2_FOLD(i);
171     n = FOLDS2_UNFOLDS_NUM(i);
172     for (j = 0; j < n; j++) {
173       OnigCodePoint unfold = FOLDS2_UNFOLDS(i)[j];
174
175       r = (*f)(unfold, fold, 2, arg);
176       if (r != 0) return r;
177
178       for (k = 0; k < j; k++) {
179         OnigCodePoint unfold2 = FOLDS2_UNFOLDS(i)[k];
180         r = (*f)(unfold, &unfold2, 1, arg);
181         if (r != 0) return r;
182         r = (*f)(unfold2, &unfold, 1, arg);
183         if (r != 0) return r;
184       }
185     }
186
187     i = FOLDS2_NEXT_INDEX(i);
188   }
189
190   return 0;
191 }
192
193 static int
194 apply_case_fold3(int from, int to, OnigApplyAllCaseFoldFunc f, void* arg)
195 {
196   int i, j, k, n, r;
197
198   for (i = from; i < to; ) {
199     OnigCodePoint* fold = FOLDS3_FOLD(i);
200     n = FOLDS3_UNFOLDS_NUM(i);
201     for (j = 0; j < n; j++) {
202       OnigCodePoint unfold = FOLDS3_UNFOLDS(i)[j];
203
204       r = (*f)(unfold, fold, 3, arg);
205       if (r != 0) return r;
206
207       for (k = 0; k < j; k++) {
208         OnigCodePoint unfold2 = FOLDS3_UNFOLDS(i)[k];
209         r = (*f)(unfold, &unfold2, 1, arg);
210         if (r != 0) return r;
211         r = (*f)(unfold2, &unfold, 1, arg);
212         if (r != 0) return r;
213       }
214     }
215
216     i = FOLDS3_NEXT_INDEX(i);
217   }
218
219   return 0;
220 }
221
222 extern int
223 onigenc_unicode_apply_all_case_fold(OnigCaseFoldType flag,
224                                     OnigApplyAllCaseFoldFunc f, void* arg)
225 {
226   int r;
227
228   r = apply_case_fold1(0, FOLDS1_NORMAL_END_INDEX, f, arg);
229   if (r != 0) return r;
230
231 #ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
232   if ((flag & ONIGENC_CASE_FOLD_TURKISH_AZERI) != 0) {
233     code = 0x0131;
234     r = (*f)(0x0049, &code, 1, arg);
235     if (r != 0) return r;
236     code = 0x0049;
237     r = (*f)(0x0131, &code, 1, arg);
238     if (r != 0) return r;
239
240     code = 0x0130;
241     r = (*f)(0x0069, &code, 1, arg);
242     if (r != 0) return r;
243     code = 0x0069;
244     r = (*f)(0x0130, &code, 1, arg);
245     if (r != 0) return r;
246   }
247   else {
248 #endif
249     r = apply_case_fold1(FOLDS1_NORMAL_END_INDEX, FOLDS1_END_INDEX, f, arg);
250     if (r != 0) return r;
251 #ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
252   }
253 #endif
254
255   if ((flag & INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR) == 0)
256     return 0;
257
258   r = apply_case_fold2(0, FOLDS2_NORMAL_END_INDEX, f, arg);
259   if (r != 0) return r;
260
261 #ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
262   if ((flag & ONIGENC_CASE_FOLD_TURKISH_AZERI) == 0) {
263 #endif
264     r = apply_case_fold2(FOLDS2_NORMAL_END_INDEX, FOLDS2_END_INDEX, f, arg);
265     if (r != 0) return r;
266 #ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
267   }
268 #endif
269
270   r = apply_case_fold3(0, FOLDS3_NORMAL_END_INDEX, f, arg);
271   if (r != 0) return r;
272
273   return 0;
274 }
275
276 extern int
277 onigenc_unicode_get_case_fold_codes_by_str(OnigEncoding enc,
278     OnigCaseFoldType flag, const OnigUChar* p, const OnigUChar* end,
279     OnigCaseFoldCodeItem items[])
280 {
281   int n, m, i, j, k, len;
282   OnigCodePoint code, codes[3];
283   const struct ByUnfoldKey* buk;
284
285   n = 0;
286
287   code = ONIGENC_MBC_TO_CODE(enc, p, end);
288   len = enclen(enc, p);
289
290 #ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
291   if ((flag & ONIGENC_CASE_FOLD_TURKISH_AZERI) != 0) {
292     if (code == 0x0049) {
293       items[0].byte_len = len;
294       items[0].code_len = 1;
295       items[0].code[0]  = 0x0131;
296       return 1;
297     }
298     else if (code == 0x0130) {
299       items[0].byte_len = len;
300       items[0].code_len = 1;
301       items[0].code[0]  = 0x0069;
302       return 1;
303     }
304     else if (code == 0x0131) {
305       items[0].byte_len = len;
306       items[0].code_len = 1;
307       items[0].code[0]  = 0x0049;
308       return 1;
309     }
310     else if (code == 0x0069) {
311       items[0].byte_len = len;
312       items[0].code_len = 1;
313       items[0].code[0]  = 0x0130;
314       return 1;
315     }
316   }
317 #endif
318
319   buk = unicode_unfold_key(code);
320   if (buk != 0) {
321     if (buk->fold_len == 1) {
322       int un;
323       items[0].byte_len = len;
324       items[0].code_len = 1;
325       items[0].code[0]  = *FOLDS1_FOLD(buk->index);
326       n++;
327
328       un = FOLDS1_UNFOLDS_NUM(buk->index);
329       for (i = 0; i < un; i++) {
330         OnigCodePoint unfold = FOLDS1_UNFOLDS(buk->index)[i];
331         if (unfold != code) {
332           items[n].byte_len = len;
333           items[n].code_len = 1;
334           items[n].code[0]  = unfold;
335           n++;
336         }
337       }
338       code = items[0].code[0]; // for multi-code to unfold search.
339     }
340     else if ((flag & INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR) != 0) {
341       OnigCodePoint cs[3][4];
342       int fn, ncs[3];
343
344       if (buk->fold_len == 2) {
345         m = FOLDS2_UNFOLDS_NUM(buk->index);
346         for (i = 0; i < m; i++) {
347           OnigCodePoint unfold = FOLDS2_UNFOLDS(buk->index)[i];
348           if (unfold == code) continue;
349
350           items[n].byte_len = len;
351           items[n].code_len = 1;
352           items[n].code[0]  = unfold;
353           n++;
354         }
355
356         for (fn = 0; fn < 2; fn++) {
357           int index;
358           cs[fn][0] = FOLDS2_FOLD(buk->index)[fn];
359           index = unicode_fold1_key(&cs[fn][0]);
360           if (index >= 0) {
361             int m = FOLDS1_UNFOLDS_NUM(index);
362             for (i = 0; i < m; i++) {
363               cs[fn][i+1] = FOLDS1_UNFOLDS(index)[i];
364             }
365             ncs[fn] = m + 1;
366           }
367           else
368             ncs[fn] = 1;
369         }
370
371         for (i = 0; i < ncs[0]; i++) {
372           for (j = 0; j < ncs[1]; j++) {
373             items[n].byte_len = len;
374             items[n].code_len = 2;
375             items[n].code[0]  = cs[0][i];
376             items[n].code[1]  = cs[1][j];
377             n++;
378           }
379         }
380       }
381       else { /* fold_len == 3 */
382         m = FOLDS3_UNFOLDS_NUM(buk->index);
383         for (i = 0; i < m; i++) {
384           OnigCodePoint unfold = FOLDS3_UNFOLDS(buk->index)[i];
385           if (unfold == code) continue;
386
387           items[n].byte_len = len;
388           items[n].code_len = 1;
389           items[n].code[0]  = unfold;
390           n++;
391         }
392
393         for (fn = 0; fn < 3; fn++) {
394           int index;
395           cs[fn][0] = FOLDS3_FOLD(buk->index)[fn];
396           index = unicode_fold1_key(&cs[fn][0]);
397           if (index >= 0) {
398             int m = FOLDS1_UNFOLDS_NUM(index);
399             for (i = 0; i < m; i++) {
400               cs[fn][i+1] = FOLDS1_UNFOLDS(index)[i];
401             }
402             ncs[fn] = m + 1;
403           }
404           else
405             ncs[fn] = 1;
406         }
407
408         for (i = 0; i < ncs[0]; i++) {
409           for (j = 0; j < ncs[1]; j++) {
410             for (k = 0; k < ncs[2]; k++) {
411               items[n].byte_len = len;
412               items[n].code_len = 3;
413               items[n].code[0]  = cs[0][i];
414               items[n].code[1]  = cs[1][j];
415               items[n].code[2]  = cs[2][k];
416               n++;
417             }
418           }
419         }
420       }
421
422       /* multi char folded code is not head of another folded multi char */
423       return n;
424     }
425   }
426   else {
427     int index = unicode_fold1_key(&code);
428     if (index >= 0) {
429       int m = FOLDS1_UNFOLDS_NUM(index);
430       for (i = 0; i < m; i++) {
431         items[n].byte_len = len;
432         items[n].code_len = 1;
433         items[n].code[0]  = FOLDS1_UNFOLDS(index)[i];
434         n++;
435       }
436     }
437   }
438
439   if ((flag & INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR) == 0)
440     return n;
441
442   p += len;
443   if (p < end) {
444     int clen;
445     int index;
446
447     codes[0] = code;
448     code = ONIGENC_MBC_TO_CODE(enc, p, end);
449
450     buk = unicode_unfold_key(code);
451     if (buk != 0 && buk->fold_len == 1) {
452       codes[1] = *FOLDS1_FOLD(buk->index);
453     }
454     else
455       codes[1] = code;
456
457     clen = enclen(enc, p);
458     len += clen;
459
460     index = unicode_fold2_key(codes);
461     if (index >= 0) {
462       m = FOLDS2_UNFOLDS_NUM(index);
463       for (i = 0; i < m; i++) {
464         items[n].byte_len = len;
465         items[n].code_len = 1;
466         items[n].code[0]  = FOLDS2_UNFOLDS(index)[i];
467         n++;
468       }
469     }
470
471     p += clen;
472     if (p < end) {
473       code = ONIGENC_MBC_TO_CODE(enc, p, end);
474       buk = unicode_unfold_key(code);
475       if (buk != 0 && buk->fold_len == 1) {
476         codes[2] = *FOLDS1_FOLD(buk->index);
477       }
478       else
479         codes[2] = code;
480
481       clen = enclen(enc, p);
482       len += clen;
483
484       index = unicode_fold3_key(codes);
485       if (index >= 0) {
486         m = FOLDS3_UNFOLDS_NUM(index);
487         for (i = 0; i < m; i++) {
488           items[n].byte_len = len;
489           items[n].code_len = 1;
490           items[n].code[0]  = FOLDS3_UNFOLDS(index)[i];
491           n++;
492         }
493       }
494     }
495   }
496
497   return n;
498 }
499
500
501 #ifdef USE_UNICODE_EXTENDED_GRAPHEME_CLUSTER
502
503 enum EGCB_BREAK_TYPE {
504   EGCB_NOT_BREAK = 0,
505   EGCB_BREAK     = 1,
506   EGCB_BREAK_UNDEF_E_MODIFIER = 2,
507   EGCB_BREAK_UNDEF_RI_RI = 3
508 };
509
510 enum EGCB_TYPE {
511   EGCB_Other   = 0,
512   EGCB_CR      = 1,
513   EGCB_LF      = 2,
514   EGCB_Control = 3,
515   EGCB_Extend  = 4,
516   EGCB_Prepend = 5,
517   EGCB_Regional_Indicator = 6,
518   EGCB_SpacingMark = 7,
519   EGCB_ZWJ         = 8,
520   EGCB_E_Base         = 9,
521   EGCB_E_Base_GAZ     = 10,
522   EGCB_E_Modifier     = 11,
523   EGCB_Glue_After_Zwj = 12,
524   EGCB_L   = 13,
525   EGCB_LV  = 14,
526   EGCB_LVT = 15,
527   EGCB_T   = 16,
528   EGCB_V   = 17
529 };
530
531 typedef struct {
532   OnigCodePoint  start;
533   OnigCodePoint  end;
534   enum EGCB_TYPE type;
535 } EGCB_RANGE_TYPE;
536
537 #include "unicode_egcb_data.c"
538
539 static enum EGCB_TYPE
540 egcb_get_type(OnigCodePoint code)
541 {
542   OnigCodePoint low, high, x;
543   enum EGCB_TYPE type;
544
545   for (low = 0, high = (OnigCodePoint )EGCB_RANGE_NUM; low < high; ) {
546     x = (low + high) >> 1;
547     if (code > EGCB_RANGES[x].end)
548       low = x + 1;
549     else
550       high = x;
551   }
552
553   type = (low < (OnigCodePoint )EGCB_RANGE_NUM &&
554           code >= EGCB_RANGES[low].start) ?
555     EGCB_RANGES[low].type : EGCB_Other;
556
557   return type;
558 }
559
560 #define IS_CONTROL_CR_LF(code)   ((code) <= EGCB_Control && (code) >= EGCB_CR)
561 #define IS_HANGUL(code)          ((code) >= EGCB_L)
562
563 /* GB1 and GB2 are outside of this function. */
564 static enum EGCB_BREAK_TYPE
565 unicode_egcb_is_break_2code(OnigCodePoint from_code, OnigCodePoint to_code)
566 {
567   enum EGCB_TYPE from;
568   enum EGCB_TYPE to;
569
570   from = egcb_get_type(from_code);
571   to   = egcb_get_type(to_code);
572
573   /* short cut */
574   if (from == 0 && to == 0) goto GB999;
575
576   /* GB3 */
577   if (from == EGCB_CR && to == EGCB_LF) return EGCB_NOT_BREAK;
578   /* GB4 */
579   if (IS_CONTROL_CR_LF(from)) return EGCB_BREAK;
580   /* GB5 */
581   if (IS_CONTROL_CR_LF(to)) return EGCB_BREAK;
582
583   if (IS_HANGUL(from) && IS_HANGUL(to)) {
584     /* GB6 */
585     if (from == EGCB_L && to != EGCB_T) return EGCB_NOT_BREAK;
586     /* GB7 */
587     if ((from == EGCB_LV || from == EGCB_V)
588         && (to == EGCB_V || to == EGCB_T)) return EGCB_NOT_BREAK;
589
590     /* GB8 */
591     if ((from == EGCB_LVT || from == EGCB_T) && (to == EGCB_T))
592       return EGCB_NOT_BREAK;
593
594     goto GB999;
595   }
596
597   /* GB9 */
598   if (to == EGCB_Extend || to == EGCB_ZWJ) return EGCB_NOT_BREAK;
599
600   /* GB9a */
601   if (to == EGCB_SpacingMark) return EGCB_NOT_BREAK;
602   /* GB9b */
603   if (from == EGCB_Prepend) return EGCB_NOT_BREAK;
604
605   /* GB10 */
606   if (to == EGCB_E_Modifier) {
607     if (from == EGCB_E_Base || from == EGCB_E_Base_GAZ) return EGCB_NOT_BREAK;
608     if (from == EGCB_Extend) return EGCB_BREAK_UNDEF_E_MODIFIER;
609     goto GB999;
610   }
611
612   /* GB11 */
613   if (from == EGCB_ZWJ) {
614     if (to == EGCB_Glue_After_Zwj || to == EGCB_E_Base_GAZ) return EGCB_NOT_BREAK;
615     goto GB999;
616   }
617
618   /* GB12, GB13 */
619   if (from == EGCB_Regional_Indicator && to == EGCB_Regional_Indicator) {
620     return EGCB_BREAK_UNDEF_RI_RI;
621   }
622
623  GB999:
624   return EGCB_BREAK;
625 }
626
627 #endif /* USE_UNICODE_EXTENDED_GRAPHEME_CLUSTER */
628
629 extern int
630 onigenc_egcb_is_break_position(OnigEncoding enc, UChar* p, UChar* prev,
631                                const UChar* start, const UChar* end)
632 {
633   OnigCodePoint from;
634   OnigCodePoint to;
635 #ifdef USE_UNICODE_EXTENDED_GRAPHEME_CLUSTER
636   enum EGCB_BREAK_TYPE btype;
637   enum EGCB_TYPE type;
638 #endif
639
640   /* GB1 and GB2 */
641   if (p == start) return 1;
642   if (p == end)   return 1;
643
644   if (IS_NULL(prev)) {
645     prev = onigenc_get_prev_char_head(enc, start, p);
646     if (IS_NULL(prev)) return 1;
647   }
648
649   from = ONIGENC_MBC_TO_CODE(enc, prev, end);
650   to   = ONIGENC_MBC_TO_CODE(enc, p, end);
651
652 #ifdef USE_UNICODE_EXTENDED_GRAPHEME_CLUSTER
653   if (! ONIGENC_IS_UNICODE_ENCODING(enc)) {
654     if (from == 0x000d && to == 0x000a) return 0;
655     else return 1;
656   }
657
658   btype = unicode_egcb_is_break_2code(from, to);
659   switch (btype) {
660   case EGCB_NOT_BREAK:
661     return 0;
662     break;
663   case EGCB_BREAK:
664     return 1;
665     break;
666
667   case EGCB_BREAK_UNDEF_E_MODIFIER:
668     while ((prev = onigenc_get_prev_char_head(enc, start, prev)) != NULL) {
669       from = ONIGENC_MBC_TO_CODE(enc, prev, end);
670       type = egcb_get_type(from);
671       if (type == EGCB_E_Base || type == EGCB_E_Base_GAZ)
672         return 0;
673       if (type != EGCB_Extend)
674         break;
675     }
676     break;
677
678   case EGCB_BREAK_UNDEF_RI_RI:
679     {
680       int n = 0;
681       while ((prev = onigenc_get_prev_char_head(enc, start, prev)) != NULL) {
682         from = ONIGENC_MBC_TO_CODE(enc, prev, end);
683         type = egcb_get_type(from);
684         if (type != EGCB_Regional_Indicator)
685           break;
686
687         n++;
688       }
689       if ((n % 2) == 0) return 0;
690     }
691     break;
692   }
693
694   return 1;
695
696 #else
697   if (from == 0x000d && to == 0x000a) return 0;
698   else return 1;
699 #endif /* USE_UNICODE_EXTENDED_GRAPHEME_CLUSTER */
700 }
701
702
703 /*
704  Undefine __GNUC__ for Escape warnings in Clang.
705
706 ./unicode_property_data.c:26730:44: warning: static variable
707       'unicode_prop_name_pool_contents' is used in an inline function with
708       external linkage [-Wstatic-in-inline]
709               register const char *s = o + unicode_prop_name_pool;
710 */
711
712 #ifdef __clang__
713 #undef __GNUC__
714 #endif
715
716 #ifdef USE_UNICODE_PROPERTIES
717 #include "unicode_property_data.c"
718 #else
719 #include "unicode_property_data_posix.c"
720 #endif
721
722 #define USER_DEFINED_PROPERTY_MAX_NUM  20
723
724 typedef struct {
725   int ctype;
726   OnigCodePoint* ranges;
727 } UserDefinedPropertyValue;
728
729 static int UserDefinedPropertyNum;
730 static UserDefinedPropertyValue
731 UserDefinedPropertyRanges[USER_DEFINED_PROPERTY_MAX_NUM];
732 static st_table* UserDefinedPropertyTable;
733
734 extern int
735 onig_unicode_define_user_property(const char* name, OnigCodePoint* ranges)
736 {
737   UserDefinedPropertyValue* e;
738   int r;
739   int i;
740   int n;
741   int len;
742   int c;
743   char* s;
744
745   if (UserDefinedPropertyNum >= USER_DEFINED_PROPERTY_MAX_NUM)
746     return ONIGERR_TOO_MANY_USER_DEFINED_OBJECTS;
747
748   len = (int )strlen(name);
749   if (len >= PROPERTY_NAME_MAX_SIZE)
750     return ONIGERR_TOO_LONG_PROPERTY_NAME;
751
752   s = (char* )xmalloc(len + 1);
753   if (s == 0)
754     return ONIGERR_MEMORY;
755
756   n = 0;
757   for (i = 0; i < len; i++) {
758     c = name[i];
759     if (c <= 0 || c >= 0x80) {
760       xfree(s);
761       return ONIGERR_INVALID_CHAR_PROPERTY_NAME;
762     }
763
764     if (c != ' ' && c != '-' && c != '_') {
765       s[n] = c;
766       n++;
767     }
768   }
769   s[n] = '\0';
770
771   if (UserDefinedPropertyTable == 0) {
772     UserDefinedPropertyTable = onig_st_init_strend_table_with_size(10);
773   }
774
775   e = UserDefinedPropertyRanges + UserDefinedPropertyNum;
776   e->ctype = CODE_RANGES_NUM + UserDefinedPropertyNum;
777   e->ranges = ranges;
778   r = onig_st_insert_strend(UserDefinedPropertyTable,
779                             (const UChar* )s, (const UChar* )s + n,
780                             (hash_data_type )((void* )e));
781   if (r < 0) return r;
782
783   UserDefinedPropertyNum++;
784   return 0;
785 }
786
787 extern int
788 onigenc_unicode_is_code_ctype(OnigCodePoint code, unsigned int ctype)
789 {
790   if (
791 #ifdef USE_UNICODE_PROPERTIES
792       ctype <= ONIGENC_MAX_STD_CTYPE &&
793 #endif
794       code < 256) {
795     return ONIGENC_IS_UNICODE_ISO_8859_1_CTYPE(code, ctype);
796   }
797
798   if (ctype >= CODE_RANGES_NUM) {
799     int index = ctype - CODE_RANGES_NUM;
800     if (index < UserDefinedPropertyNum)
801       return onig_is_in_code_range((UChar* )UserDefinedPropertyRanges[index].ranges, code);
802     else
803       return ONIGERR_TYPE_BUG;
804   }
805
806   return onig_is_in_code_range((UChar* )CodeRanges[ctype], code);
807 }
808
809
810 extern int
811 onigenc_unicode_ctype_code_range(OnigCtype ctype, const OnigCodePoint* ranges[])
812 {
813   if (ctype >= CODE_RANGES_NUM) {
814     int index = ctype - CODE_RANGES_NUM;
815     if (index < UserDefinedPropertyNum) {
816       *ranges = UserDefinedPropertyRanges[index].ranges;
817       return 0;
818     }
819     else
820       return ONIGERR_TYPE_BUG;
821   }
822
823   *ranges = CodeRanges[ctype];
824   return 0;
825 }
826
827 extern int
828 onigenc_utf16_32_get_ctype_code_range(OnigCtype ctype, OnigCodePoint* sb_out,
829                                       const OnigCodePoint* ranges[])
830 {
831   *sb_out = 0x00;
832   return onigenc_unicode_ctype_code_range(ctype, ranges);
833 }
834
835 extern int
836 onigenc_unicode_property_name_to_ctype(OnigEncoding enc, UChar* name, UChar* end)
837 {
838   int len;
839   UChar *p;
840   OnigCodePoint code;
841   const struct PoolPropertyNameCtype* pc;
842   char buf[PROPERTY_NAME_MAX_SIZE];
843
844   p = name;
845   len = 0;
846   while (p < end) {
847     code = ONIGENC_MBC_TO_CODE(enc, p, end);
848     if (code >= 0x80)
849       return ONIGERR_INVALID_CHAR_PROPERTY_NAME;
850
851     if (code != ' ' && code != '-' && code != '_') {
852       buf[len++] = (char )code;
853       if (len >= PROPERTY_NAME_MAX_SIZE)
854         return ONIGERR_INVALID_CHAR_PROPERTY_NAME;
855     }
856
857     p += enclen(enc, p);
858   }
859
860   buf[len] = 0;
861
862   if (UserDefinedPropertyTable != 0) {
863     UserDefinedPropertyValue* e;
864     e = (UserDefinedPropertyValue* )NULL;
865     onig_st_lookup_strend(UserDefinedPropertyTable,
866                           (const UChar* )buf, (const UChar* )buf + len,
867                           (hash_data_type* )((void* )(&e)));
868     if (e != 0) {
869       return e->ctype;
870     }
871   }
872
873   pc = unicode_lookup_property_name(buf, len);
874   if (pc != 0) {
875     /* fprintf(stderr, "LOOKUP: %s: %d\n", buf, pc->ctype); */
876 #ifndef USE_UNICODE_PROPERTIES
877     if (pc->ctype > ONIGENC_MAX_STD_CTYPE)
878       return ONIGERR_INVALID_CHAR_PROPERTY_NAME;
879 #endif
880
881     return (int )pc->ctype;
882   }
883
884   return ONIGERR_INVALID_CHAR_PROPERTY_NAME;
885 }