(mfont_list): If FONT is null, use a temporary font.
[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,
219                                  MTEXTPROP_VOLATILE_WEAK | MTEXTPROP_NO_MERGE);
220           mtext_attach_property (mt, last, from + wordcut_result.start[i],
221                                  this);
222           if (pos >= last && pos < from + wordcut_result.start[i])
223             prop = this;
224           M17N_OBJECT_UNREF (this);
225         }
226
227       this = mtext_property (Mthai_wordseg, Mt,
228                              MTEXTPROP_VOLATILE_WEAK | MTEXTPROP_NO_MERGE);
229       last = from + wordcut_result.start[i];
230       mtext_attach_property (mt, last, last + wordcut_result.offset[i], this);
231       if (pos >= last && pos < last + wordcut_result.offset[i])
232         prop = this;
233       m17n_object_unref (this);
234       last += wordcut_result.offset[i];
235     }
236   return prop;
237 }
238
239 #endif  /* not HAVE_LIBTHA, HAVE_WORDCUT nor HAVE_WORDCUT_OLD */
240
241 int
242 thai_wordseg (MText *mt, int pos, int *from, int *to)
243 {
244   /* TIS620 code sequence.  */
245   unsigned char *tis;
246   MTextProperty *prop;
247   int in_word;
248
249   if (pos >= mtext_nchars (mt))
250     {
251       *from = *to = pos;
252       return 0;
253     }
254
255   prop = mtext_get_property (mt, pos, Mthai_wordseg);
256
257   if (! prop)
258     {
259       int beg, end;
260       int c;
261
262       /* Extra 1-byte is for 0 terminating.  */
263       tis = alloca ((*to - *from) + 1);
264
265       for (beg = pos; beg > *from; beg--)
266         {
267           if ((c = mtext_ref_char (mt, beg - 1)) < THAI_BEG || c > THAI_END)
268             break;
269           tis[beg - 1 - *from] = 0xA1 + (c - THAI_BEG);
270         }
271       for (end = pos; end < *to; end++)
272         {
273           if ((c = mtext_ref_char (mt, end)) < THAI_BEG || c > THAI_END)
274             break;
275           tis[end - *from] = 0xA1 + (c - THAI_BEG);
276         }           
277           
278       if (pos == end)
279         {
280           *from = *to = pos;
281           return 0;
282         }
283
284       /* Make it terminate by 0.  */
285       tis[end - *from] = 0;
286       prop = wordseg_propertize (mt, pos, beg, end, tis + (beg - *from));
287     }
288
289   *from = MTEXTPROP_START (prop);
290   *to = MTEXTPROP_END (prop);
291   in_word = MTEXTPROP_VAL (prop) == Mt;
292   return in_word;
293 }
294
295 #endif  /* HAVE_THAI_WORDSEG */
296
297 \f
298 /* Internal API */
299
300 int
301 mtext__word_thai_init ()
302 {
303 #ifdef HAVE_THAI_WORDSEG
304   if (! wordseg_library_initialized)
305     {
306       if (init_wordseg_library () < 0)
307         return -1;
308       wordseg_library_initialized = 1;
309       Mthai_wordseg = msymbol (" wordcut-wordseg");
310     }
311   mchartable_set_range (wordseg_func_table, THAI_BEG, THAI_END,
312                         (void *) thai_wordseg);
313 #endif
314   return 0;
315 }
316
317 void
318 mtext__word_thai_fini ()
319 {
320 #ifdef HAVE_THAI_WORDSEG
321   if (wordseg_library_initialized)
322     {
323       fini_wordseg_library ();
324       wordseg_library_initialized = 0;
325     }
326 #endif
327 }
328
329 /*** @} */
330 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */