(wordseg_propertize): If the property value is nil,
[m17n/m17n-lib.git] / src / word-thai.c
1 /* word-thai.c -- Find a word segment in Thai text.
2    Copyright (C) 2005
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
24 /*** @addtogroup m17nInternal
25      @{ */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include "config.h"
31
32 #ifdef HAVE_THAI_WORDSEG
33
34 #include "m17n-core.h"
35 #include "m17n-misc.h"
36 #include "internal.h"
37 #include "textprop.h"
38 #include "character.h"
39 #include "mtext.h"
40
41 static int init_wordseg_library (void);
42 static void fini_wordseg_library (void);
43 static MTextProperty *wordseg_propertize (MText *mt, int pos, int from, int to,
44                                           unsigned char *tis);
45
46 #define THAI_BEG 0x0E01
47 #define THAI_END 0x0E6F
48
49 static int wordseg_library_initialized;
50 static MSymbol Mthai_wordseg;
51
52 #ifdef HAVE_LIBTHAI
53
54 #include <thai/thbrk.h>
55
56 static int
57 init_wordseg_library (void)
58 {
59   return 0;
60 }
61
62 static void
63 fini_wordseg_library (void)
64 {
65   return;
66 }
67
68 static MTextProperty *
69 wordseg_propertize (MText *mt, int pos, int from, int to, unsigned char *tis)
70 {
71   int len = to - from;
72   int *breaks = alloca ((sizeof (int)) * len);
73   int count = th_brk ((thchar_t *) tis, breaks, len);
74   MTextProperty *prop = NULL;
75
76   if (count == 0)
77     {
78       prop = mtext_property (Mthai_wordseg, Mt,
79                              MTEXTPROP_VOLATILE_WEAK | MTEXTPROP_NO_MERGE);
80       mtext_attach_property (mt, from, to, prop);
81       M17N_OBJECT_UNREF (prop);
82     }
83   else
84     {
85       int last, i;
86       MTextProperty *this;
87
88       for (i = 0, last = from; i < count; i++)
89         {
90           this = mtext_property (Mthai_wordseg, Mt,
91                                  MTEXTPROP_VOLATILE_WEAK | MTEXTPROP_NO_MERGE);
92           mtext_attach_property (mt, last, from + breaks[i], this);
93           if (pos >= last && pos < from + breaks[i])
94             prop = this;
95           M17N_OBJECT_UNREF (this);
96           last = from + breaks[i];
97         }
98       if (last < to)
99         {
100           this = mtext_property (Mthai_wordseg, Mt,
101                                  MTEXTPROP_VOLATILE_WEAK | MTEXTPROP_NO_MERGE);
102           mtext_attach_property (mt, last, to, this);
103           if (pos >= last && pos < to)
104             prop = this;
105           M17N_OBJECT_UNREF (this);
106         }
107     }
108
109   if (! prop)
110     mdebug_hook ();
111   return prop;
112 }
113
114 #elif HAVE_WORDCUT
115
116 #include <wordcut/wcwordcut.h>
117
118 static WcWordcut wordcut;
119 static WcWordVector *word_vector;
120
121 static int
122 init_wordseg_library (void)
123 {  
124   wc_wordcut_init (&wordcut);
125   return 0;
126 }
127
128 static void
129 fini_wordseg_library (void)
130 {
131   if (word_vector)
132     wc_word_vector_delete (word_vector);
133   wc_wordcut_destroy (&wordcut);
134   return;
135 }
136
137 static MTextProperty *
138 wordseg_propertize (MText *mt, int pos, int from, int to, unsigned char *tis)
139 {
140   gulong i, count;
141   MTextProperty *prop = NULL;
142
143   if (! word_vector)
144     word_vector = wc_word_vector_new ();
145   else
146     {
147       wc_word_vector_destroy (word_vector);
148       wc_word_vector_init (word_vector);
149     }
150
151   wc_wordcut_cut (&wordcut, (gchar *) tis, (gint) (to - from),
152                   word_vector);
153   count = wc_word_vector_get_count (word_vector);
154   for (i = 0; i < count; i++)
155     {
156       WcWord *word = wc_word_vector_get_word (word_vector, i);
157
158       if (word->type != WC_WORDTYPE_DELETED)
159         {
160           MSymbol val = ((word->type == WC_WORDTYPE_DICTIONARY
161                           || word->type == WC_WORDTYPE_WORDUNIT
162                           || word->type == WC_WORDTYPE_JOINED)
163                          ? Mt : Mnil);
164           MTextProperty *this
165             = mtext_property (Mthai_wordseg, val,
166                               MTEXTPROP_VOLATILE_WEAK | MTEXTPROP_NO_MERGE);
167
168           mtext_attach_property (mt, from, from + word->len, this);
169           if (pos >= from && pos < from + word->len)
170             prop = this;
171           M17N_OBJECT_UNREF (this);
172           from += word->len;
173         }
174     }
175   return prop;
176 }
177
178 #else  /* HAVE_WORDCUT_OLD */
179
180 #include <wordcut/wordcut.h>
181
182 static Wordcut wordcut;
183 static WordcutResult wordcut_result;
184 static int wordcut_result_used;
185
186 static int
187 init_wordseg_library (void)
188 {  
189   return (wordcut_init (&wordcut, WORDCUT_TDICT) == 0 ? 0 : -1);
190 }
191
192 static void
193 fini_wordseg_library (void)
194 {
195   if (wordcut_result_used)
196     {
197       wordcut_result_close (&wordcut_result);
198       wordcut_result_used = 0;
199     }
200   wordcut_close (&wordcut);
201   return;
202 }
203
204 static MTextProperty *
205 wordseg_propertize (MText *mt, int pos, int from, int to, unsigned char *tis)
206 {
207   int i, last;
208   MTextProperty *prop = NULL;
209
210   wordcut_cut (&wordcut, (char *) tis, &wordcut_result);
211   wordcut_result_used = 1;
212   for (i = 0, last = from; i < wordcut_result.count; i++)
213     {
214       MTextProperty *this;
215
216       if (last < from + wordcut_result.start[i])
217         {
218           this = mtext_property (Mthai_wordseg, Mnil, MTEXTPROP_VOLATILE_WEAK);
219           mtext_attach_property (mt, last, from + wordcut_result.start[i],
220                                  this);
221           if (pos >= last && pos < from + wordcut_result.start[i])
222             prop = this;
223           M17N_OBJECT_UNREF (this);
224         }
225
226       this = mtext_property (Mthai_wordseg, Mt,
227                              MTEXTPROP_VOLATILE_WEAK | MTEXTPROP_NO_MERGE);
228       last = from + wordcut_result.start[i];
229       mtext_attach_property (mt, last, last + wordcut_result.offset[i], this);
230       if (pos >= last && pos < last + wordcut_result.offset[i])
231         prop = this;
232       m17n_object_unref (this);
233       last += wordcut_result.offset[i];
234     }
235   return prop;
236 }
237
238 #endif  /* not HAVE_LIBTHA, HAVE_WORDCUT nor HAVE_WORDCUT_OLD */
239
240 int
241 thai_wordseg (MText *mt, int pos, int *from, int *to)
242 {
243   int len = mtext_nchars (mt);
244   /* TIS620 code sequence.  */
245   unsigned char *tis;
246   MTextProperty *prop;
247   int beg, end;
248   int c;
249
250   /* It is assured that there's a Thai character at POS.  */
251   prop = mtext_get_property (mt, pos, Mthai_wordseg);
252   if (prop)
253     {
254       beg = MTEXTPROP_START (prop);
255       if (beg > 0
256           && ((c = mtext_ref_char (mt, beg - 1)) < THAI_BEG || c > THAI_END))
257         beg = -1;
258       end = MTEXTPROP_END (prop);
259       if (end < len
260           && ((c = mtext_ref_char (mt, end)) < THAI_BEG || c > THAI_END))
261         end = -1;
262     }
263   else
264     {
265       int i;
266
267       for (beg = pos; beg > 0; beg--)
268         if ((c = mtext_ref_char (mt, beg - 1)) < THAI_BEG || c > THAI_END)
269           break;
270       for (end = pos + 1; end < len; end++)
271         if ((c = mtext_ref_char (mt, end)) < THAI_BEG || c > THAI_END)
272           break;
273
274       /* Extra 1-byte for 0 terminating.  */
275       tis = alloca ((end - beg) + 1);
276
277       for (i = beg; i < end; i++)
278         tis[i - beg] = 0xA1 + (mtext_ref_char (mt, i) - THAI_BEG);
279       tis[i - beg] = 0;
280       prop = wordseg_propertize (mt, pos, beg, end, tis);
281       i = MTEXTPROP_START (prop);
282       beg = (i > beg || i == 0) ? i : -1;
283       i = MTEXTPROP_END (prop);
284       end = (i < end || i == len) ? i : -1;
285     }
286
287   if (from)
288     *from = beg;
289   if (to)
290     *to = end;
291   return (MTEXTPROP_VAL (prop) == Mt);
292 }
293
294 #endif  /* HAVE_THAI_WORDSEG */
295
296 \f
297 /* Internal API */
298
299 int
300 mtext__word_thai_init ()
301 {
302 #ifdef HAVE_THAI_WORDSEG
303   if (! wordseg_library_initialized)
304     {
305       if (init_wordseg_library () < 0)
306         return -1;
307       wordseg_library_initialized = 1;
308       Mthai_wordseg = msymbol ("  wordcut-wordseg");
309     }
310   mchartable_set_range (wordseg_func_table, THAI_BEG, THAI_END,
311                         (void *) thai_wordseg);
312 #endif
313   return 0;
314 }
315
316 void
317 mtext__word_thai_fini ()
318 {
319 #ifdef HAVE_THAI_WORDSEG
320   if (wordseg_library_initialized)
321     {
322       fini_wordseg_library ();
323       wordseg_library_initialized = 0;
324     }
325 #endif
326 }
327
328 /*** @} */
329 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */