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