*** empty log message ***
[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 #include <stdio.h>
24 #include <stdlib.h>
25
26 #include "config.h"
27
28 #ifdef HAVE_THAI_WORDSEG
29
30 #include "m17n-core.h"
31 #include "m17n-misc.h"
32 #include "internal.h"
33 #include "textprop.h"
34 #include "character.h"
35 #include "mtext.h"
36
37 static int init_wordseg_library (void);
38 static void fini_wordseg_library (void);
39 static MTextProperty *wordseg_propertize (MText *mt, int pos, int from, int to,
40                                           unsigned char *tis);
41
42 #define THAI_BEG 0x0E01
43 #define THAI_END 0x0E6F
44
45 static int wordseg_library_initialized;
46 static MSymbol Mthai_wordseg;
47
48 #ifdef HAVE_LIBTHAI
49
50 #include <thai/thbrk.h>
51
52 static int
53 init_wordseg_library (void)
54 {
55   return 0;
56 }
57
58 static void
59 fini_wordseg_library (void)
60 {
61   return;
62 }
63
64 static MTextProperty *
65 wordseg_propertize (MText *mt, int pos, int from, int to, unsigned char *tis)
66 {
67   int len = to - from;
68   int *breaks = alloca ((sizeof (int)) * len);
69   int count = th_brk ((thchar_t *) tis, breaks, len);
70   MTextProperty *prop = NULL;
71
72   if (count == 0)
73     {
74       prop = mtext_property (Mthai_wordseg, Mt,
75                              MTEXTPROP_VOLATILE_WEAK | MTEXTPROP_NO_MERGE);
76       mtext_attach_property (mt, from, to, prop);
77       M17N_OBJECT_UNREF (prop);
78     }
79   else
80     {
81       int last, i;
82       MTextProperty *this;
83
84       for (i = 0, last = from; i < count; i++)
85         {
86           this = mtext_property (Mthai_wordseg, Mt,
87                                  MTEXTPROP_VOLATILE_WEAK | MTEXTPROP_NO_MERGE);
88           mtext_attach_property (mt, last, from + breaks[i], this);
89           if (pos >= last && pos < from + breaks[i])
90             prop = this;
91           M17N_OBJECT_UNREF (this);
92           last = from + breaks[i];
93         }
94       if (last < to)
95         {
96           this = mtext_property (Mthai_wordseg, Mt,
97                                  MTEXTPROP_VOLATILE_WEAK | MTEXTPROP_NO_MERGE);
98           mtext_attach_property (mt, last, to, this);
99           if (pos >= last && pos < to)
100             prop = this;
101           M17N_OBJECT_UNREF (this);
102         }
103     }
104
105   if (! prop)
106     mdebug_hook ();
107   return prop;
108 }
109
110 #elif HAVE_WORDCUT
111
112 #include <wordcut/wcwordcut.h>
113
114 static WcWordcut wordcut;
115 static WcWordVector *word_vector;
116
117 static int
118 init_wordseg_library (void)
119 {  
120   wc_wordcut_init (&wordcut);
121   return 0;
122 }
123
124 static void
125 fini_wordseg_library (void)
126 {
127   if (word_vector)
128     wc_word_vector_delete (word_vector);
129   wc_wordcut_destroy (&wordcut);
130   return;
131 }
132
133 static MTextProperty *
134 wordseg_propertize (MText *mt, int pos, int from, int to, unsigned char *tis)
135 {
136   gulong i, count;
137   MTextProperty *prop = NULL;
138
139   if (! word_vector)
140     word_vector = wc_word_vector_new ();
141   else
142     {
143       wc_word_vector_destroy (word_vector);
144       wc_word_vector_init (word_vector);
145     }
146
147   wc_wordcut_cut (&wordcut, (gchar *) tis, (gint) (to - from),
148                   word_vector);
149   count = wc_word_vector_get_count (word_vector);
150   for (i = 0; i < count; i++)
151     {
152       WcWord *word = wc_word_vector_get_word (word_vector, i);
153
154       if (word->type != WC_WORDTYPE_DELETED)
155         {
156           MSymbol val = ((word->type == WC_WORDTYPE_DICTIONARY
157                           || word->type == WC_WORDTYPE_WORDUNIT
158                           || word->type == WC_WORDTYPE_JOINED)
159                          ? Mt : Mnil);
160           MTextProperty *this
161             = mtext_property (Mthai_wordseg, val,
162                               MTEXTPROP_VOLATILE_WEAK | MTEXTPROP_NO_MERGE);
163
164           mtext_attach_property (mt, from, from + word->len, this);
165           if (pos >= from && pos < from + word->len)
166             prop = this;
167           M17N_OBJECT_UNREF (this);
168           from += word->len;
169         }
170     }
171   return prop;
172 }
173
174 #else  /* HAVE_WORDCUT_OLD */
175
176 #include <wordcut/wordcut.h>
177
178 static Wordcut wordcut;
179 static WordcutResult wordcut_result;
180 static int wordcut_result_used;
181
182 static int
183 init_wordseg_library (void)
184 {  
185   return (wordcut_init (&wordcut, WORDCUT_TDICT) == 0 ? 0 : -1);
186 }
187
188 static void
189 fini_wordseg_library (void)
190 {
191   if (wordcut_result_used)
192     {
193       wordcut_result_close (&wordcut_result);
194       wordcut_result_used = 0;
195     }
196   wordcut_close (&wordcut);
197   return;
198 }
199
200 static MTextProperty *
201 wordseg_propertize (MText *mt, int pos, int from, int to, unsigned char *tis)
202 {
203   int i, last;
204   MTextProperty *prop = NULL;
205
206   wordcut_cut (&wordcut, (char *) tis, &wordcut_result);
207   wordcut_result_used = 1;
208   for (i = 0, last = from; i < wordcut_result.count; i++)
209     {
210       MTextProperty *this;
211
212       if (last < from + wordcut_result.start[i])
213         {
214           this = mtext_property (Mthai_wordseg, Mnil,
215                                  MTEXTPROP_VOLATILE_WEAK | MTEXTPROP_NO_MERGE);
216           mtext_attach_property (mt, last, from + wordcut_result.start[i],
217                                  this);
218           if (pos >= last && pos < from + wordcut_result.start[i])
219             prop = this;
220           M17N_OBJECT_UNREF (this);
221         }
222
223       this = mtext_property (Mthai_wordseg, Mt,
224                              MTEXTPROP_VOLATILE_WEAK | MTEXTPROP_NO_MERGE);
225       last = from + wordcut_result.start[i];
226       mtext_attach_property (mt, last, last + wordcut_result.offset[i], this);
227       if (pos >= last && pos < last + wordcut_result.offset[i])
228         prop = this;
229       m17n_object_unref (this);
230       last += wordcut_result.offset[i];
231     }
232   return prop;
233 }
234
235 #endif  /* not HAVE_LIBTHA, HAVE_WORDCUT nor HAVE_WORDCUT_OLD */
236
237 int
238 thai_wordseg (MText *mt, int pos, int *from, int *to)
239 {
240   /* TIS620 code sequence.  */
241   unsigned char *tis;
242   MTextProperty *prop;
243   int in_word;
244
245   if (pos >= mtext_nchars (mt))
246     {
247       *from = *to = pos;
248       return 0;
249     }
250
251   prop = mtext_get_property (mt, pos, Mthai_wordseg);
252
253   if (! prop)
254     {
255       int beg, end;
256       int c;
257
258       /* Extra 1-byte is for 0 terminating.  */
259       tis = alloca ((*to - *from) + 1);
260
261       for (beg = pos; beg > *from; beg--)
262         {
263           if ((c = mtext_ref_char (mt, beg - 1)) < THAI_BEG || c > THAI_END)
264             break;
265           tis[beg - 1 - *from] = 0xA1 + (c - THAI_BEG);
266         }
267       for (end = pos; end < *to; end++)
268         {
269           if ((c = mtext_ref_char (mt, end)) < THAI_BEG || c > THAI_END)
270             break;
271           tis[end - *from] = 0xA1 + (c - THAI_BEG);
272         }           
273           
274       if (pos == end)
275         {
276           *from = *to = pos;
277           return 0;
278         }
279
280       /* Make it terminate by 0.  */
281       tis[end - *from] = 0;
282       prop = wordseg_propertize (mt, pos, beg, end, tis + (beg - *from));
283     }
284
285   *from = MTEXTPROP_START (prop);
286   *to = MTEXTPROP_END (prop);
287   in_word = MTEXTPROP_VAL (prop) == Mt;
288   return in_word;
289 }
290
291 #endif  /* HAVE_THAI_WORDSEG */
292
293 \f
294 /* Internal API */
295
296 int
297 mtext__word_thai_init ()
298 {
299 #ifdef HAVE_THAI_WORDSEG
300   if (! wordseg_library_initialized)
301     {
302       if (init_wordseg_library () < 0)
303         return -1;
304       wordseg_library_initialized = 1;
305       Mthai_wordseg = msymbol (" wordcut-wordseg");
306     }
307   mchartable_set_range (wordseg_func_table, THAI_BEG, THAI_END,
308                         (void *) thai_wordseg);
309 #endif
310   return 0;
311 }
312
313 void
314 mtext__word_thai_fini ()
315 {
316 #ifdef HAVE_THAI_WORDSEG
317   if (wordseg_library_initialized)
318     {
319       fini_wordseg_library ();
320       wordseg_library_initialized = 0;
321     }
322 #endif
323 }