1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
2 /* IM-JA Japanese Input Method Module for GTK-2.0
3 *
4 * Copyright (C) 2004 Botond Botyanszki <boti@rocketmail.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 *
21 * Authors: Botond Botyanszki <boti@rocketmail.com>
22 */
23
24 #include <config.h>
25
26 #include <glib.h>
27 #include <string.h>
28
29 #include "../error.h"
30 #include "../common.h"
31 #include "../romakana.h"
32
33 #include "skklib.h"
34 #include "skkconv.h"
35
36
skkconv_destroy_skkclause(SKKClause * clause,gpointer data)37 void skkconv_destroy_skkclause(SKKClause *clause, gpointer data) {
38 IM_JA_DEBUG("skkconv_destroy_skkcand()\n");
39 if (clause == NULL) IM_JA_DEBUG("**ERROR** can't destroy NULL clause!\n");
40 if (clause->cand != NULL) freeCand(clause->cand);
41 g_free(clause);
42 }
43
skkconv_free_clauselist(SKKContext * skkctx)44 void skkconv_free_clauselist(SKKContext *skkctx) {
45 g_list_foreach(skkctx->clauselist, (GFunc) skkconv_destroy_skkclause, NULL);
46 g_list_free(skkctx->clauselist);
47 skkctx->clauselist = NULL;
48 skkctx->curr_clause = NULL;
49 }
50
skkconv_reset_ctx(SKKContext * skkctx)51 void skkconv_reset_ctx(SKKContext *skkctx) {
52 memset(skkctx->kana_buf, 0, BUFFERSIZE);
53 skkctx->cursor_pos = 0;
54 skkctx->conv_state = SKKCONV_UNCONVERTED;
55 skkconv_free_clauselist(skkctx);
56 }
57
skkconv_select_candidate(SKKContext * skkctx,gint direction)58 void skkconv_select_candidate(SKKContext *skkctx, gint direction) {
59 SKKClause *clause;
60 CandList cand;
61
62 IM_JA_DEBUG("skkconv_select_candidate(%d)\n", direction);
63
64 clause = (SKKClause *) skkctx->curr_clause->data;
65 cand = clause->selected_cand;
66 if (cand != NULL) {
67 if (direction == SKKCONV_NEXT) {
68 if (cand->nextcand == NULL) clause->selected_cand = clause->cand;
69 else clause->selected_cand = clause->selected_cand->nextcand;
70 }
71 else { /* PREV */
72 if (cand->prevcand == NULL) {
73 while (cand->nextcand != NULL) cand = cand->nextcand;
74 clause->selected_cand = cand;
75 }
76 else clause->selected_cand = clause->selected_cand->prevcand;
77 }
78 }
79 }
80
skkconv_fix_selected_candidate(SKKContext * skkctx,gint selected)81 void skkconv_fix_selected_candidate(SKKContext *skkctx, gint selected) {
82 SKKClause *clause;
83 CandList cand;
84 gint candnum = 0;
85
86 IM_JA_DEBUG("skkconv_fix_selected_candidate(%d)\n", selected);
87 /* selectCand(*first,cand) */
88
89 clause = (SKKClause *) skkctx->curr_clause->data;
90 cand = clause->cand;
91 while (cand != NULL) {
92 if (selected == candnum) {
93 clause->selected_cand = cand;
94 IM_JA_DEBUG("Select: %s\n", clause->selected_cand->candword);
95 break;
96 }
97 candnum++;
98 cand = cand->nextcand;
99 }
100 }
101
skkconv_unconvert_all(SKKContext * skkctx)102 void skkconv_unconvert_all(SKKContext *skkctx) {
103 IM_JA_DEBUG("skkconv_unconvert_all()\n");
104
105 skkctx->conv_state = SKKCONV_UNCONVERTED;
106 skkconv_free_clauselist(skkctx);
107 skkctx->cursor_pos = strlen(skkctx->kana_buf);
108 }
109
skkconv_unconvert_clause(SKKClause * clause)110 void skkconv_unconvert_clause(SKKClause *clause) {
111 IM_JA_DEBUG("skkconv_unconvert_clause()\n");
112 if (clause->conv_state == SKKCONV_UNCONVERTED) return;
113 clause->conv_state = SKKCONV_UNCONVERTED;
114 clause->selected_cand = clause->cand;
115 }
116
skkconv_unconvert_current_clause(SKKContext * skkctx)117 void skkconv_unconvert_current_clause(SKKContext *skkctx) {
118 SKKClause *clause;
119
120 clause = (SKKClause *) skkctx->curr_clause->data;
121 skkconv_unconvert_clause(clause);
122 }
123
skkconv_convert_all(SKKContext * skkctx)124 void skkconv_convert_all(SKKContext *skkctx) {
125 SKKClause *clause;
126 gchar *start, *end;
127
128 IM_JA_DEBUG("skkconv_convert_all()\n");
129
130 start = skkctx->kana_buf;
131 end = start + strlen(start);
132
133 while (TRUE) {
134 clause = skkconv_convert_clause(start, end, TRUE);
135 if (clause == NULL) break;
136 else {
137 skkctx->clauselist = g_list_append(skkctx->clauselist, clause);
138 skkctx->conv_state = SKKCONV_CONVERTED;
139 if (clause->kana_start < skkctx->kana_buf + strlen(skkctx->kana_buf)) {
140 start = clause->kana_end;
141 }
142 else break;
143 }
144 }
145 skkctx->curr_clause = skkctx->clauselist;
146 IM_JA_DEBUG("skkconv_convert_all done\n");
147 }
148
skkconv_convert_clause(gchar * conversion_start,gchar * conversion_end,gboolean shrink)149 SKKClause *skkconv_convert_clause(gchar *conversion_start, gchar *conversion_end, gboolean shrink) {
150 gchar *eucstrg, *utfstrg, *kana, *kata;
151 gchar *conv_start, *conv_end;
152 CandList curr_cand, cand = NULL, cand_kana = NULL;
153 CandList *first_cand_entry;
154 SKKClause *skkclause = NULL;
155 gboolean conversion_done = FALSE;
156 conv_start = conversion_start;
157 conv_end = conversion_end;
158
159 /* IM_JA_DEBUG("skkconv_convert_clause()\n"); */
160
161 if (conv_start == conv_end) return NULL;
162
163 while (conversion_done != TRUE) {
164 utfstrg = g_strdup(conv_start);
165 utfstrg[conv_end - conv_start] = 0;
166
167 eucstrg = utf82euc(utfstrg);
168 g_free(utfstrg);
169
170 curr_cand = getCandFromServer(eucstrg);
171 if (curr_cand != NULL) {
172 curr_cand = searchOkuri(curr_cand, eucstrg, &first_cand_entry);
173 if (curr_cand->okuri != NULL) {
174 IM_JA_DEBUG("Okuri: %s\n", curr_cand->okuri->candword);
175 }
176 skkclause = g_new0(SKKClause, 1);
177 skkclause->kana_start = conv_start;
178 skkclause->kana_end = conv_end;
179 skkclause->cand = curr_cand;
180 skkclause->selected_cand = curr_cand;
181 skkclause->conv_state = SKKCONV_CONVERTED;
182 /*
183 while (curr_cand != NULL) {
184 if (curr_cand->okuri != NULL) {
185 okuri_cand = curr_cand->okuri;
186 while (okuri_cand != NULL) {
187 IM_JA_DEBUG("Okuri: %s\n", okuri_cand->candword);
188 okuri_cand = okuri_cand->nextcand;
189 }
190 }
191 else {
192 IM_JA_DEBUG("Cand: %s\n", curr_cand->candword);
193 }
194 curr_cand = curr_cand->nextcand;
195 }
196 */
197 conversion_done = TRUE;
198 }
199 else {
200 /* IM_JA_DEBUG("couldn't convert\n"); */
201 if (shrink == TRUE) {
202 /* IM_JA_DEBUG("couldn't convert [zero length]\n"); */
203 if (conv_start == g_utf8_prev_char(conv_end)) { /* one char length */
204 conversion_done = TRUE;
205 }
206 else conv_end = g_utf8_prev_char(conv_end);
207 }
208 else {
209 conv_start = conversion_start;
210 conv_end = conversion_end;
211 conversion_done = TRUE;
212 }
213 if (conv_end == conv_start) {
214 /* IM_JA_DEBUG("couldn't convert [zero length]\n"); */
215 conversion_done = TRUE;
216 skkclause = NULL;
217 }
218 else { /* create an unconverted clause */
219 /* IM_JA_DEBUG("couldn't convert\n"); */
220 skkclause = g_new0(SKKClause, 1);
221 skkclause->kana_start = conv_start;
222 skkclause->kana_end = conv_end;
223 skkclause->cand = NULL;
224 skkclause->selected_cand = NULL;
225 skkclause->conv_state = SKKCONV_UNCONVERTED;
226 }
227 }
228 g_free(eucstrg);
229 }
230
231 if (skkclause != NULL) cand = skkclause->cand;
232 kana = g_strdup(skkclause->kana_start);
233 kana[skkclause->kana_end - skkclause->kana_start] = 0;
234 /* Add katakana candidate */
235 kata = hira2kata(kana);
236 eucstrg = utf82euc(kata);
237 cand_kana = _NEW2(CandList, strlen(eucstrg) + 1);
238 g_strlcpy(cand_kana->candword, eucstrg, strlen(eucstrg) + 1);
239 g_free(kata);
240 g_free(eucstrg);
241 if (cand != NULL) cand->prevcand = cand_kana;
242 cand_kana->nextcand = cand;
243 cand_kana->okuri = NULL;
244 if (cand != NULL) cand_kana->dicitem = cand->dicitem;
245 cand = cand_kana;
246
247 /* Add hiragana candidate */
248 eucstrg = utf82euc(kana);
249 cand_kana = _NEW2(CandList, strlen(eucstrg) + 1);
250 g_strlcpy(cand_kana->candword, eucstrg, strlen(eucstrg) + 1);
251 cand->prevcand = cand_kana;
252 cand_kana->nextcand = cand;
253 cand_kana->prevcand = NULL;
254 cand_kana->okuri = NULL;
255 cand_kana->dicitem = cand->dicitem;
256 cand = cand_kana;
257 g_free(kana);
258 g_free(eucstrg);
259 skkclause->cand = cand;
260 if (skkclause->selected_cand == NULL) skkclause->selected_cand = cand;
261 return skkclause;
262 }
263
skkconv_insert_string(SKKContext * skkctx,gchar * strg)264 void skkconv_insert_string(SKKContext *skkctx, gchar *strg) {
265 gchar *tmpstrg;
266
267 IM_JA_DEBUG("skkconv_insert_string: \"%s\"\n", strg);
268 tmpstrg = g_strdup(skkctx->kana_buf + skkctx->cursor_pos);
269 skkctx->kana_buf[skkctx->cursor_pos] = 0;
270 g_strlcat(skkctx->kana_buf, strg, BUFFERSIZE);
271 g_strlcat(skkctx->kana_buf, tmpstrg, BUFFERSIZE);
272 g_free(tmpstrg);
273
274 }
275
skkconv_roma2kana(SKKContext * skkctx,gint input_method)276 void skkconv_roma2kana(SKKContext *skkctx, gint input_method) {
277 gchar *tmpstr, *firstpart, *secondpart;
278
279 firstpart = g_strdup(skkctx->kana_buf);
280 secondpart = g_strdup(skkctx->kana_buf + skkctx->cursor_pos + 1);
281 firstpart[skkctx->cursor_pos + 1] = 0;
282 tmpstr = roma2kana(firstpart, input_method);
283 g_free(firstpart);
284 g_strlcpy(skkctx->kana_buf, tmpstr, BUFFERSIZE);
285 g_strlcat(skkctx->kana_buf, secondpart, BUFFERSIZE);
286 g_free(tmpstr);
287 g_free(secondpart);
288 }
289
skkconv_delete_char(SKKContext * skkctx,gint direction)290 void skkconv_delete_char(SKKContext *skkctx, gint direction) {
291 gchar *tmpstrg;
292
293 if (direction == SKKCONV_BACKWARD) { /* Backspace */
294 if (skkctx->cursor_pos == 0) return;
295 tmpstrg = g_strdup(skkctx->kana_buf + skkctx->cursor_pos);
296 skkctx->cursor_pos = g_utf8_prev_char(skkctx->kana_buf + skkctx->cursor_pos) - skkctx->kana_buf;
297 *(skkctx->kana_buf + skkctx->cursor_pos) = 0;
298 g_strlcat(skkctx->kana_buf, tmpstrg, BUFFERSIZE);
299 g_free(tmpstrg);
300 }
301 else { /* Delete */
302 if ((size_t) (skkctx->cursor_pos) == strlen(skkctx->kana_buf)) return;
303 tmpstrg = g_strdup(g_utf8_next_char(skkctx->kana_buf + skkctx->cursor_pos));
304 *(skkctx->kana_buf + skkctx->cursor_pos) = 0;
305 g_strlcat(skkctx->kana_buf, tmpstrg, BUFFERSIZE);
306 g_free(tmpstrg);
307 }
308 }
309
skkconv_select_clause(SKKContext * skkctx,gint direction)310 void skkconv_select_clause(SKKContext *skkctx, gint direction) {
311 GList *curr_clause;
312
313 if (skkctx->conv_state == SKKCONV_UNCONVERTED) return;
314 if (direction == SKKCONV_NEXT) {
315 curr_clause = g_list_next(skkctx->curr_clause);
316 if (curr_clause != NULL) skkctx->curr_clause = curr_clause;
317 }
318 else {
319 curr_clause = g_list_previous(skkctx->curr_clause);
320 if (curr_clause != NULL) skkctx->curr_clause = curr_clause;
321 }
322 }
323
skkconv_move_cursor(SKKContext * skkctx,gint direction)324 void skkconv_move_cursor(SKKContext *skkctx, gint direction) {
325 gchar *buf = skkctx->kana_buf;
326
327 IM_JA_DEBUG("skkconv_move_cursor(%d)\n", direction);
328 if (direction == SKKCONV_FORWARD) {
329 if ((size_t) (skkctx->cursor_pos) == strlen(buf)) {
330 return;
331 }
332 else {
333 skkctx->cursor_pos = g_utf8_next_char(buf + skkctx->cursor_pos) - buf;
334 }
335 }
336 else {
337 if (skkctx->cursor_pos == 0) {
338 return;
339 }
340 else {
341 skkctx->cursor_pos = g_utf8_prev_char(buf + skkctx->cursor_pos) - buf;
342 }
343 }
344 }
345
skkconv_resize_clause(SKKContext * skkctx,gint direction)346 void skkconv_resize_clause(SKKContext *skkctx, gint direction) {
347 GList *clause_list;
348 GList *curr_clause, *next_clause;
349 SKKClause *curr_new = NULL, *next_new = NULL;
350 gint len;
351
352 IM_JA_DEBUG("skkconv_resize_clause(%d)\n", direction);
353
354 skkconv_unconvert_current_clause(skkctx);
355 clause_list = skkctx->clauselist;
356
357 if (direction == SKKCONV_FORWARD) { /* == EXPAND */
358 IM_JA_DEBUG("EXPAND!\n");
359 /* can't expand if there is no next clause */
360 if (g_list_next(skkctx->curr_clause) == NULL) {
361 IM_JA_DEBUG("NO NEXT CLAUSE!\n");
362 return;
363 }
364 curr_clause = skkctx->curr_clause;
365 next_clause = g_list_next(skkctx->curr_clause);
366 skkconv_unconvert_clause(next_clause->data);
367 len = ((SKKClause *)next_clause->data)->kana_end - ((SKKClause *)next_clause->data)->kana_start;
368 ((SKKClause *)curr_clause->data)->kana_end = g_utf8_next_char(((SKKClause *)curr_clause->data)->kana_end);
369 IM_JA_DEBUG("NEXT CLAUSE LENGTH: %d\n", (int) g_utf8_strlen(((SKKClause *)next_clause->data)->kana_start, len));
370 if (g_utf8_strlen(((SKKClause *)next_clause->data)->kana_start, len) == 1) {
371 /* Delete clause if it's one char only (merge into current) */
372 IM_JA_DEBUG("ONE CHAR CLAUSE: deleting\n");
373 skkconv_destroy_skkclause(((SKKClause *)next_clause->data), NULL);
374 clause_list = g_list_delete_link(clause_list, next_clause);
375 next_clause = NULL;
376 next_new = NULL;
377 }
378 else {
379 /* create a new next clause */
380 ((SKKClause *)next_clause->data)->kana_start = g_utf8_next_char(((SKKClause *)next_clause->data)->kana_start);
381 next_new = skkconv_convert_clause(((SKKClause *)next_clause->data)->kana_start,
382 ((SKKClause *)next_clause->data)->kana_end, FALSE);
383 }
384 curr_new = skkconv_convert_clause(((SKKClause *)curr_clause->data)->kana_start,
385 ((SKKClause *)curr_clause->data)->kana_end, FALSE);
386
387 skkconv_destroy_skkclause(((SKKClause *)curr_clause->data), NULL);
388 curr_clause->data = curr_new;
389 if (next_new != NULL) {
390 skkconv_destroy_skkclause(((SKKClause *)next_clause->data), NULL);
391 next_clause->data = next_new;
392 }
393 }
394 else { /* BACKWARD == SHRINK */
395 IM_JA_DEBUG("SHRINK!\n");
396 curr_clause = skkctx->curr_clause;
397 /* one character width, don't do anything */
398 if (g_utf8_next_char(((SKKClause *)curr_clause->data)->kana_start) == ((SKKClause *)curr_clause->data)->kana_end) return;
399
400 next_clause = g_list_next(skkctx->curr_clause);
401 if (next_clause == NULL) {
402 /* create a new next clause */
403 next_new = skkconv_convert_clause(g_utf8_prev_char(((SKKClause *)curr_clause->data)->kana_end),
404 ((SKKClause *)curr_clause->data)->kana_end, FALSE);
405 clause_list = g_list_append(clause_list, next_new);
406 ((SKKClause *)curr_clause->data)->kana_end = g_utf8_prev_char(((SKKClause *)curr_clause->data)->kana_end);
407 curr_new = skkconv_convert_clause(((SKKClause *)curr_clause->data)->kana_start,
408 ((SKKClause *)curr_clause->data)->kana_end, FALSE);
409 skkconv_destroy_skkclause(((SKKClause *)curr_clause->data), NULL);
410 curr_clause->data = curr_new;
411 }
412 else {
413 skkconv_unconvert_clause(((SKKClause *)next_clause->data));
414 ((SKKClause *)next_clause->data)->kana_start = g_utf8_prev_char(((SKKClause *)next_clause->data)->kana_start);
415 next_new = skkconv_convert_clause(((SKKClause *)next_clause->data)->kana_start,
416 ((SKKClause *)next_clause->data)->kana_end, FALSE);
417 skkconv_destroy_skkclause(((SKKClause *)next_clause->data), NULL);
418 next_clause->data = next_new;
419
420 ((SKKClause *)curr_clause->data)->kana_end = g_utf8_prev_char(((SKKClause *)curr_clause->data)->kana_end);
421 curr_new = skkconv_convert_clause(((SKKClause *)curr_clause->data)->kana_start,
422 ((SKKClause *)curr_clause->data)->kana_end, FALSE);
423 skkconv_destroy_skkclause(((SKKClause *)curr_clause->data), NULL);
424 curr_clause->data = curr_new;
425 }
426 }
427 }
428