1 #include "gcin.h"
2 #include "pho.h"
3 #include "config.h"
4 #if GCIN_i18n_message
5 #include <libintl.h>
6 #endif
7 #include "lang.h"
8 #include "tsin.h"
9 #include "gtab.h"
10 
11 extern char *current_tsin_fname;
12 typedef unsigned int u_int32_t;
13 
14 void init_TableDir();
15 void init_gtab(int inmdno);
16 gboolean init_tsin_table_fname(INMD *p, char *fname);
17 void load_tsin_db0(char *infname, gboolean is_gtab_i);
18 
19 INMD *pinmd;
20 char gtab_tsin_fname[256];
21 char is_gtab;
22 
23 char *phokey2pinyin(phokey_t k);
24 gboolean b_pinyin;
25 GtkWidget *hbox_buttons;
26 char current_str[MAX_PHRASE_LEN*CH_SZ+1];
27 extern gboolean is_chs;
28 
29 GtkWidget *mainwin;
30 GtkTextBuffer *buffer;
31 
32 static char **phrase;
33 static int phraseN=0;
34 
35 
cp_ph_key(void * in,int idx,void * dest)36 void cp_ph_key(void *in, int idx, void *dest)
37 {
38   if (tsin_hand.ph_key_sz==2) {
39     phokey_t *pharr = (phokey_t *)in;
40     in = &pharr[idx];
41   } else
42   if (tsin_hand.ph_key_sz==4) {
43     u_int32_t *pharr4 = (u_int32_t *)in;
44     in = &pharr4[idx];
45   } else {
46     u_int64_t *pharr8 = (u_int64_t *)in;
47     in = &pharr8[idx];
48   }
49 
50   memcpy(dest, in, tsin_hand.ph_key_sz);
51 }
52 
get_ph_key_ptr(void * in,int idx)53 void *get_ph_key_ptr(void *in, int idx)
54 {
55   if (tsin_hand.ph_key_sz==2) {
56     phokey_t *pharr = (phokey_t *)in;
57     return &pharr[idx];
58   } else
59   if (tsin_hand.ph_key_sz==4) {
60     u_int32_t *pharr4 = (u_int32_t *)in;
61     return &pharr4[idx];
62   } else {
63     u_int64_t *pharr8 = (u_int64_t *)in;
64     return &pharr8[idx];
65   }
66 }
67 
lookup_gtab_key(char * ch,void * out)68 int lookup_gtab_key(char *ch, void *out)
69 {
70   int outN=0;
71   INMD *tinmd = &inmd[default_input_method];
72 
73   int i;
74   for(i=0; i < tinmd->DefChars; i++) {
75     char *chi = (char *)tblch2(tinmd, i);
76 
77     if (!(chi[0] & 0x80))
78       continue;
79     if (!utf8_eq(chi, ch))
80       continue;
81 
82     u_int64_t key = CONVT2(tinmd, i);
83     if (tsin_hand.ph_key_sz==4) {
84       u_int32_t key32 = (u_int32_t)key;
85       memcpy(get_ph_key_ptr(out, outN), &key32, tsin_hand.ph_key_sz);
86     } else
87       memcpy(get_ph_key_ptr(out, outN), &key, tsin_hand.ph_key_sz);
88     outN++;
89   }
90 
91   return outN;
92 }
93 
94 
qcmp_str(const void * aa,const void * bb)95 static int qcmp_str(const void *aa, const void *bb)
96 {
97   char *a = * (char **)aa, *b = * (char **)bb;
98 
99   return strcmp(a,b);
100 }
101 
102 extern FILE *fph;
103 
load_ts_phrase()104 void load_ts_phrase()
105 {
106   FILE *fp = tsin_hand.fph;
107 
108   int i;
109   for(i=0; i < phraseN; i++)
110     free(phrase[i]);
111   free(phrase); phrase = NULL;
112   phraseN = 0;
113 
114   dbg("fname %s\n", tsin_hand.tsin_fname);
115 
116   int ofs = is_gtab ? sizeof(TSIN_GTAB_HEAD):0;
117   fseek(fp, ofs, SEEK_SET);
118 
119   while (!feof(fp)) {
120     u_int64_t phbuf[MAX_PHRASE_LEN];
121     char chbuf[MAX_PHRASE_LEN * CH_SZ + 1];
122     u_char clen;
123     usecount_t usecount;
124 
125     clen = 0;
126 
127 	int rn;
128     rn = fread(&clen,1,1,fp);
129 
130     if (clen > MAX_PHRASE_LEN)
131       p_err("bad tsin db clen %d > MAX_PHRASE_LEN %d\n", clen, MAX_PHRASE_LEN);
132 
133     rn = fread(&usecount,sizeof(usecount_t), 1, fp);
134     rn = fread(phbuf, tsin_hand.ph_key_sz, clen, fp);
135     int tlen = 0;
136 
137     for(i=0; i < clen; i++) {
138       int n = fread(&chbuf[tlen], 1, 1, fp);
139       if (n<=0)
140         goto stop;
141       int len=utf8_sz(&chbuf[tlen]);
142       rn = fread(&chbuf[tlen+1], 1, len-1, fp);
143       tlen+=len;
144     }
145 
146     if (clen < 2)
147       continue;
148 
149     chbuf[tlen]=0;
150     phrase = trealloc(phrase, char *, phraseN+1);
151 
152     phrase[phraseN++] = strdup(chbuf);
153   }
154 
155 
156 stop:
157 
158 //  fclose(fp);
159 
160   qsort(phrase, phraseN, sizeof(char *), qcmp_str);
161 
162   dbg("phraseN: %d\n", phraseN);
163 }
164 
pharse_search(char * s)165 gboolean pharse_search(char *s)
166 {
167   return bsearch(&s, phrase, phraseN, sizeof(char *), qcmp_str) != NULL;
168 }
169 
all_wrap()170 void all_wrap()
171 {
172   GtkTextIter mstart,mend;
173 
174   gtk_text_buffer_get_bounds (buffer, &mstart, &mend);
175   gtk_text_buffer_apply_tag_by_name (buffer, "char_wrap", &mstart, &mend);
176 }
177 
178 
cb_button_parse(GtkButton * button,gpointer user_data)179 static void cb_button_parse(GtkButton *button, gpointer user_data)
180 {
181   int char_count = gtk_text_buffer_get_char_count (buffer);
182 
183   int i;
184 
185   load_ts_phrase();
186 
187   char_count = gtk_text_buffer_get_char_count (buffer);
188 
189   all_wrap();
190 
191   dbg("parse char_count:%d\n", char_count);
192 
193   for(i=0; i < char_count; ) {
194     int len;
195 
196     for(len=MAX_PHRASE_LEN; len>=2 ; len--) {
197       u_char txt[MAX_PHRASE_LEN*CH_SZ + 1];
198       int txtN=0, u8chN=0;
199 
200       gboolean b_ignore = FALSE;
201       int k;
202       for(k=0; k<len && i+k < char_count; k++) {
203         GtkTextIter start,end;
204         gtk_text_buffer_get_iter_at_offset (buffer, &start, i+k);
205         gtk_text_buffer_get_iter_at_offset (buffer, &end, i+k+1);
206         char *utf8 = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
207 
208         if (!(utf8[0] & 128))
209           b_ignore = TRUE;
210 
211         int wn = strlen(utf8);
212 
213         memcpy(&txt[txtN], utf8, wn);
214 
215         txtN+= wn;
216         u8chN++;
217       }
218 
219       if (b_ignore || txtN < 2)
220         continue;
221 
222       txt[txtN] = 0;
223 //      dbg("try len:%d txtN:%d %s\n", len, txtN, txt);
224       if (!pharse_search((char *)txt))
225         continue;
226 
227 //      dbg("match .... %d %d\n", i, len);
228 
229       GtkTextIter mstart,mend;
230 
231       gtk_text_buffer_get_iter_at_offset (buffer, &mstart, i);
232       gtk_text_buffer_get_iter_at_offset (buffer, &mend, i+len);
233       gtk_text_buffer_apply_tag_by_name (buffer, "blue_background", &mstart, &mend);
234 #if 1
235       // why do I have to repeat this
236       gtk_text_buffer_get_iter_at_offset (buffer, &mstart, i);
237       gtk_text_buffer_get_iter_at_offset (buffer, &mend, i+len);
238       gtk_text_buffer_apply_tag_by_name (buffer, "blue_background", &mstart, &mend);
239 #endif
240       gdk_flush();
241     }
242 
243     i+=len;
244   }
245 }
246 
247 #define MAX_SAME_CHAR_PHO (16)
248 
249 typedef struct {
250   u_int64_t phokeys[MAX_SAME_CHAR_PHO];
251   int phokeysN;
252   GtkWidget *opt_menu;
253 } char_pho;
254 
255 
256 
257 static char_pho bigpho[MAX_PHRASE_LEN];
258 static int bigphoN;
259 
260 static GtkWidget *hbox_pho_sel;
261 
destroy_pho_sel_area()262 void destroy_pho_sel_area()
263 {
264   gtk_widget_destroy(hbox_pho_sel);
265 }
266 
cb_button_ok(GtkButton * button,gpointer user_data)267 static void cb_button_ok(GtkButton *button, gpointer user_data)
268 {
269   u_int64_t pharr8[MAX_PHRASE_LEN];
270 
271   int i;
272   for(i=0; i < bigphoN; i++) {
273     int idx = gtk_combo_box_get_active(GTK_COMBO_BOX(bigpho[i].opt_menu));
274     void *dest = get_ph_key_ptr(pharr8, i);
275 
276     cp_ph_key(bigpho[i].phokeys, idx, dest);
277   }
278 
279   save_phrase_to_db(&tsin_hand, pharr8, current_str, bigphoN, 0);
280 
281   destroy_pho_sel_area();
282 
283   GtkTextMark *selebound =  gtk_text_buffer_get_selection_bound(buffer);
284   gtk_text_mark_set_visible(selebound, FALSE);
285 
286   cb_button_parse(NULL, NULL);
287 
288 }
289 
cb_button_cancel(GtkButton * button,gpointer user_data)290 static void cb_button_cancel(GtkButton *button, gpointer user_data)
291 {
292   destroy_pho_sel_area();
293 }
294 
295 int gtab_key2name(INMD *tinmd, u_int64_t key, char *t, int *rtlen);
create_pho_sel_area()296 GtkWidget *create_pho_sel_area()
297 {
298   hbox_pho_sel = gtk_hbox_new (FALSE, 0);
299 
300   int i;
301 
302   for(i=0; i < bigphoN; i++) {
303     bigpho[i].opt_menu = gtk_combo_box_new_text ();
304 #if !GTK_CHECK_VERSION(2,4,0)
305     GtkWidget *menu = gtk_menu_new ();
306 #endif
307     gtk_box_pack_start (GTK_BOX (hbox_pho_sel), bigpho[i].opt_menu, FALSE, FALSE, 0);
308 
309     int j;
310     for(j=0; j < bigpho[i].phokeysN; j++) {
311       char t[128];
312       char *phostr;
313 
314       if (is_gtab) {
315         int tlen;
316         u_int64_t key64;
317         if (tsin_hand.ph_key_sz == 4) {
318           u_int32_t key32;
319           cp_ph_key(bigpho[i].phokeys,j, &key32);
320           key64 = key32;
321         } else
322           cp_ph_key(bigpho[i].phokeys,j, &key64);
323 
324         gtab_key2name(pinmd, key64, t, &tlen);
325 //        dbg("%d,%d] %s\n", i,j, t);
326         phostr = t;
327       } else {
328         phokey_t k;
329         cp_ph_key(bigpho[i].phokeys, j, &k);
330         phostr = b_pinyin?
331         phokey2pinyin(k):phokey_to_str(k);
332       }
333 
334 #if GTK_CHECK_VERSION(2,4,0)
335       gtk_combo_box_append_text (GTK_COMBO_BOX_TEXT (bigpho[i].opt_menu), phostr);
336 #else
337       GtkWidget *item = gtk_menu_item_new_with_label (phostr);
338       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
339 #endif
340     }
341 
342 #if GTK_CHECK_VERSION(2,4,0)
343     gtk_combo_box_set_active (GTK_COMBO_BOX(bigpho[i].opt_menu), 0);
344 #else
345     gtk_option_menu_set_menu (GTK_OPTION_MENU (bigpho[i].opt_menu), menu);
346 #endif
347 
348   }
349 
350 
351   GtkWidget *button_ok = gtk_button_new_with_label("OK to add");
352   gtk_box_pack_start (GTK_BOX (hbox_pho_sel), button_ok, FALSE, FALSE, 20);
353   g_signal_connect (G_OBJECT (button_ok), "clicked",
354      G_CALLBACK (cb_button_ok), NULL);
355 #if GTK_CHECK_VERSION(3,10,0)
356   GtkWidget *button_cancel = gtk_button_new_with_label ("取消");
357 #else
358   GtkWidget *button_cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
359 #endif
360   gtk_box_pack_start (GTK_BOX (hbox_pho_sel), button_cancel, FALSE, FALSE, 20);
361   g_signal_connect (G_OBJECT (button_cancel), "clicked",
362      G_CALLBACK (cb_button_cancel), NULL);
363 
364 
365   return hbox_pho_sel;
366 }
367 
368 
cb_button_add(GtkButton * button,gpointer user_data)369 static void cb_button_add(GtkButton *button, gpointer user_data)
370 {
371   GtkTextIter start, end;
372 
373   if (!gtk_text_buffer_get_selection_bounds(buffer, &start, &end))
374     return;
375 
376   char *utf8 = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
377   strcpy(current_str, utf8);
378 
379   g_free(utf8);
380 
381   bigphoN = 0;
382   char *p = current_str;
383   while (*p) {
384     char_pho *pbigpho = &bigpho[bigphoN++];
385 
386     if (tsin_hand.ph_key_sz==2) {
387       pbigpho->phokeysN = utf8_pho_keys(p, (phokey_t*)pbigpho->phokeys);
388     } else {
389       pbigpho->phokeysN = lookup_gtab_key(p, pbigpho->phokeys);
390     }
391 
392     p+=utf8_sz(p);
393 
394     if (!pbigpho->phokeysN) {
395       dbg(" no mapping to pho\n");
396       return;
397     }
398   }
399 
400   GtkWidget *sel =  create_pho_sel_area();
401   gtk_box_pack_start (GTK_BOX (hbox_buttons), sel, FALSE, FALSE, 20);
402 
403   gtk_widget_show_all(hbox_buttons);
404 
405 }
406 
407 Display *dpy;
408 
do_exit()409 void do_exit()
410 {
411   send_gcin_message(
412 #if UNIX
413 	  dpy,
414 #endif
415 	  RELOAD_TSIN_DB);
416 
417   exit(0);
418 }
419 
420 void load_tsin_db();
421 void set_window_gcin_icon(GtkWidget *window);
422 #if WIN32
423 void init_gcin_program_files();
424 #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
425 #endif
426 
427 gboolean is_pinyin_kbm();
428 
main(int argc,char ** argv)429 int main(int argc, char **argv)
430 {
431   init_TableDir();
432   set_is_chs();
433   gtk_init (&argc, &argv);
434   load_setttings();
435   load_gtab_list(TRUE);
436 
437   b_pinyin = is_pinyin_kbm();
438 
439 
440 #if GCIN_i18n_message
441   bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
442   textdomain(GETTEXT_PACKAGE);
443 #endif
444 
445   pinmd = &inmd[default_input_method];
446 
447   if (pinmd->method_type == method_type_TSIN) {
448     dbg("is tsin\n");
449     pho_load();
450     load_tsin_db();
451     tsin_hand.ph_key_sz = 2;
452   } else
453   if (pinmd->filename) {
454     dbg("gtab filename %s\n", pinmd->filename);
455     init_gtab(default_input_method);
456     is_gtab = TRUE;
457     init_tsin_table_fname(pinmd, gtab_tsin_fname);
458     load_tsin_db0(gtab_tsin_fname, TRUE);
459   } else
460     p_err("Your default input method %s doesn't use phrase database",
461       pinmd->cname);
462 
463   dbg("ph_key_sz: %d\n", tsin_hand.ph_key_sz);
464 
465 #if UNIX
466   dpy = GDK_DISPLAY();
467 #endif
468 
469   mainwin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
470   gtk_window_set_has_resize_grip(GTK_WINDOW(mainwin), FALSE);
471   gtk_window_set_default_size(GTK_WINDOW (mainwin), 640, 520);
472   set_window_gcin_icon(mainwin);
473 
474   GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
475   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
476                                   GTK_POLICY_AUTOMATIC,
477                                   GTK_POLICY_AUTOMATIC);
478 
479   GtkWidget *vbox_top = gtk_vbox_new (FALSE, 0);
480   gtk_container_add (GTK_CONTAINER(mainwin), vbox_top);
481 
482   GtkWidget *view = gtk_text_view_new ();
483   gtk_widget_set_hexpand (view, TRUE);
484   gtk_widget_set_vexpand (view, TRUE);
485   gtk_container_add (GTK_CONTAINER(sw), view);
486 
487   gtk_box_pack_start (GTK_BOX (vbox_top), sw, TRUE, TRUE, 0);
488 
489   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
490 
491 #if UNIX
492   char *text = _(_L("按滑鼠中鍵, 貼上你要 tslearn 學習的文章。"));
493 #else
494   char *text = _(_L("按 ctrl-V, 貼上你要 tslearn 學習的文章。"));
495 #endif
496 
497   gtk_text_buffer_set_text (buffer, text, -1);
498 
499   gtk_text_buffer_create_tag (buffer,
500      "blue_background", "background", "blue", "foreground", "white", NULL);
501 
502   gtk_text_buffer_create_tag (buffer, "char_wrap",
503 			      "wrap_mode", GTK_WRAP_CHAR, NULL);
504 
505   hbox_buttons = gtk_hbox_new (FALSE, 0);
506   gtk_box_pack_start (GTK_BOX (vbox_top), hbox_buttons, FALSE, FALSE, 0);
507 
508   GtkWidget *button_parse = gtk_button_new_with_label(_(_L("標示已知詞")));
509   gtk_box_pack_start (GTK_BOX (hbox_buttons), button_parse, FALSE, FALSE, 0);
510   g_signal_connect (G_OBJECT (button_parse), "clicked",
511      G_CALLBACK (cb_button_parse), NULL);
512 
513   GtkWidget *button_add = gtk_button_new_with_label(_(_L("新增詞")));
514   gtk_box_pack_start (GTK_BOX (hbox_buttons), button_add, TRUE, TRUE, 0);
515   g_signal_connect (G_OBJECT (button_add), "clicked",
516      G_CALLBACK (cb_button_add), NULL);
517 
518 #if GTK_CHECK_VERSION(3,10,0)
519   GtkWidget *button_quit = gtk_button_new_with_label ("離開");
520 #else
521   GtkWidget *button_quit = gtk_button_new_from_stock (GTK_STOCK_QUIT);
522 #endif
523   gtk_box_pack_start (GTK_BOX (hbox_buttons), button_quit, FALSE, FALSE, 0);
524   g_signal_connect (G_OBJECT (button_quit), "clicked",
525      G_CALLBACK (do_exit), NULL);
526 
527 
528   g_signal_connect (G_OBJECT (mainwin), "delete_event",
529                     G_CALLBACK (do_exit), NULL);
530 
531   all_wrap();
532 
533   gtk_widget_show_all(mainwin);
534 #if WIN32
535   gtk_window_present(GTK_WINDOW(mainwin));
536 #endif
537 
538   gtk_main();
539   return 0;
540 }
541