/* * * UNICON - The Console Chinese & I18N * Copyright (c) 1999-2002 * * This file is part of UNICON, a console Chinese & I18N * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * See the file COPYING directory of this archive * Author: see CREDITS */ #include #include #include #include #include #include #include #include #include #include // #include // #include // #include // #include // #include #include //#include #define fatal printf #define message printf static int LoadPinyinTable(InputModule* p, char* pathname); static int LoadSysPhrase(InputModule *inmd,char *pathname); static int LoadUsrPhrase(InputModule* inmd,char *pathname); static int LoadPhraseFrequency(InputModule *inmd,char *pathname); int SavePhraseFrequency(InputModule *inmd,char *pathname); static void FindMatchPhrase(InputModule *inmd,PYString pinyin[],int lenpy); static void SortOutput(InputModule *inmd, int start); static void FillForwardSelection(InputModule *inmd,int startpos); static void FillBackwardSelection(InputModule *inmd,int lastpos); static int AdjustPhraseFreq(InputModule *p); static void CreatePyMsg(InputModule *inmd); static int ParsePy(InputModule *inmd, char *pybuf, PYString pinyin[]); /************************************************************************** * Structure of the Char/Phrases * * u_char len; // char/phrase len * * u_char count; // how many char/phrases in this node * * u_char key[len+1]; // pinyin key, 1+len encoding * * u_char char_freq[]; phrase/freq,phrase/freq pairs * **************************************************************************/ //Get PYahead for key u_short KeyAhead(u_char *key) { u_short py; py = '\0'; py |= key[0] << 2 & 0x3ff; py |= key[1] >> 6; return py; } //Compare two keys, return 0 if match int KeyCmp(u_char *longkey, u_char *shortkey, u_char len) { int i; int bitnum=len*10; for (i=0; i>(8-bitnum)) ^ (shortkey[i]>>(8-bitnum))) ) return 1; return 0; } //Convert PY_Key to Phrase_Key, init a key or add a pykey void KeyAdd(u_char *key, u_short pykey, u_char index) { int j,p; j = index*10/8; p = index*10%8; if (p == 0) key[j] = '\0'; key[j+1] = '\0'; key[j] |= (pykey & 0x3ff) >> (2 + p); key[j+1] |= pykey << (6 - p) ; } //Append a key by adding another void KeyApp(u_char *key, u_char *keyadd, u_char index, u_char count) { int i,j,p; j = index*10/8; p = index*10%8; key[j] = key[j] >> (8-p) << (8-p); for (i=1; i> p); key[j+i+1] |= keyadd[i] << (8-p); } } inline u_char *GetPhrase(ChoiceItem *p, char *pBuf) { char *temp = pBuf; /* [2*MAX_PHRASE_LEN+1]; */ int len; if (!p || !(p->head) || !(p->head->key)) temp[0]='\0'; len= (int)(p->head->len); strncpy(temp,p->head->key + KEYLEN(len) + p->index *(2*len+1),2*len); temp[2*len] = '\0'; return temp; } inline u_char *GetFreq(ChoiceItem *p) { int len = (int)(p->head->len); return (u_char*)(p->head->key + KEYLEN(len) + p->index *(2*len+1)+ 2*len); } /* static int ConfigFuzzyPinyin(const char *confstr) { bool value = BoolConf(confstr); FuzzyPinyin = value; if (value) { message("zh/z-ch/c-sh/s fuzzy pinyin enabled.\r\n"); } return SUCCESS; } */ /*************************************************************************** * Init/Cleanup * ***************************************************************************/ /* Initiate the InputModule structure */ int InitPinyinInput (InputModule *p, char *szPath) { char buf[256]; struct stat st; sprintf (buf, "%s%s", szPath, "/pinyin.map"); if (LoadPinyinTable (p,buf) == -1) return -1; sprintf (buf, "%s%s", szPath, "/sysphrase.tab"); if (LoadSysPhrase (p,buf) == -1) return -1; sprintf(buf, "%s/.pyinput", getenv("HOME")); if(stat(buf, &st) == -1) mkdir(buf, 0755); sprintf(buf, "%s/.pyinput/usrphrase.tab", getenv("HOME")); if(stat(buf, &st) == -1) { creat(buf, 0740); sprintf (buf, "%s%s", szPath, "/usrphrase.tab"); } if (LoadUsrPhrase(p,buf) == -1) { sprintf (buf, "%s%s", szPath,"/usrphrase.tab"); LoadUsrPhrase(p,buf); } sprintf(buf, "%s/.pyinput/sysfrequency.tab", getenv("HOME")); if(stat(buf, &st) == -1 || LoadPhraseFrequency(p,buf)==-1) { creat(buf, 0740); p->BootCount=0; SavePhraseFrequency(p,buf); } return 1; } /* Read the pinyin.map, fill the pytab structure */ static int LoadPinyinTable(InputModule* p, char* pathname) { FILE *stream; char str[1024],strpy[15]; int i=0, j=0, lastpy=0, curpy; bzero(p->pytab,sizeof(p->pytab)); if ( (stream = fopen( pathname, "r" )) == NULL ) { fatal("%s file not found\n",pathname); return -1; } while ( !feof( stream )) { if ( fgets(str,1024,stream) != NULL) { sscanf(str,"%s ",strpy); curpy = strpy[0]-'a'; if (curpy != lastpy) j = 0; strcpy(p->pytab[curpy][j].py,strpy); p->pytab[curpy][j].key = i+1; lastpy = curpy; i++,j++; } } #ifdef DEBUG warn("sizeof(pytab=%d\n",sizeof(p->pytab)); #endif fclose(stream); return SUCCESS; } /* need to combine the same pinyin/phrases */ int SaveUsrPhrase(InputModule* inmd,char *pathname) { int i, tmpcount; FILE *out; UsrPhrase *p0,*q0; u_short total; u_char len, *buf, *p; long t; if ((out = fopen(pathname,"wb")) == NULL) fatal("Not enough memory1\n"); if ((buf = malloc (256 * 8)) == NULL) fatal("Not enough memory2\n"); for (i=1; iusrph[i]; p0 != NULL; p0 = p0->next) { len = p0->len; for (q0 = inmd->usrph[i]; q0 != p0; q0 = q0->next) if (q0->len == len && !memcmp(p0->key, q0->key, KEYLEN(len))) break; if (p0 == q0) { total++; fwrite (&(q0->len), sizeof(q0->len), 1, out); fwrite (&(q0->count), sizeof(q0->count), 1, out); fwrite (q0->key, sizeof(u_char), KEYLEN(q0->len), out); fwrite (q0->key + KEYLEN(q0->len), (2*q0->len+1), q0->count, out); } } if (total == 0) continue; fseek (out, t, SEEK_SET); fwrite(&total,sizeof(total),1,out); fseek (out, 0, SEEK_END); } t = ftell (out); fwrite(&t,sizeof(t),1,out); free (buf); fclose(out); return 0; } int UnloadUserPhrase (InputModule* inmd) { int i; UsrPhrase *p0,*q0; for (i=1; iusrph[i]; p0 != NULL; ) { q0 = p0; p0 = p0->next; free (q0); } inmd->usrph[i] = NULL; } return 0; } int SavePhraseFrequency(InputModule *inmd,char *pathname) { FILE *stream; Phrase *sph; SysPhrase *sysph_tmp; u_char *f; char *p; int i,j,k,index,pcount; f = (u_char *) malloc (inmd->sys_num); if ( (stream = fopen(pathname , "wb" )) == NULL ) { fatal("%s file can't open\n",pathname); free(f); return -1; } pcount=0; for(i = 1; i < MAX_PY_NUM; i++) { sysph_tmp = inmd->sysph[i]; assert (sysph_tmp != NULL); p = (char*)sysph_tmp->phrase; // count = total pinyin number for(j = 0; j < sysph_tmp->count; j++) { sph = (Phrase *)p; assert (sph != NULL); for(k = 0; k < sph->count; k++) { index = KEYLEN(sph->len) + (2*sph->len+1)*k + 2*sph->len; f[pcount]=sph->key[index]; pcount++; } p += SizeOfPhrase(sph->len,sph->count); } } assert (pcount==inmd->sys_num); fseek(stream,0,SEEK_SET); fwrite(f, sizeof(u_char),inmd->sys_num, stream); fwrite(&(inmd->sys_size),sizeof(int),1,stream); fwrite(&(inmd->sys_num),sizeof(int),1,stream); fwrite(&(inmd->BootCount),sizeof(int),1,stream); fclose(stream); free(f); return 0; } int UnloadSysPhrase (InputModule *inmd) { char *p = (char*)(inmd->sysph[1]); free (p); return 0; } static int LoadUsrPhrase(InputModule* inmd,char *pathname) { FILE *stream; UsrPhrase *kph,*tmp; int i,j,ahead,fsize; u_short count; u_short len; u_short size; if ((stream = fopen(pathname, "r")) == NULL ) { fatal("%s file can't open\n",pathname); return -1; } if (fseek(stream,-4,SEEK_END) == -1 || fread(&fsize,sizeof(int),1,stream) != 1 || fsize != ftell(stream)-4) // error!! { // warn("user file size=%d\n",fsize); fatal("%s is not a valid pinyin phrase file.\n",pathname); return -1; } fseek(stream,0,SEEK_SET); for(i = 1; i < MAX_PY_NUM; i++) { inmd->usrph[i] = NULL; if (fread(&count,sizeof(count),1,stream) != 1) { fatal("Error in Reading....\n"); return -1; } if (count == 0) continue; for(j = 0; j < count; j++) { if (fread(&len,sizeof(len),1,stream) != 1) { fatal("Error in Reading....1\n"); return -1; } if (fread(&size,sizeof(size),1,stream) != 1) { fatal("Error in Reading....2\n"); return -1; } if ((kph = (UsrPhrase *)malloc(8+KEYLEN(len)+(2*len+1)*size)) == NULL) { fatal("Not enough memory3\n"); return -1; } kph->len = len; kph->count = size; kph->next = NULL; if (fread(kph->key,sizeof(u_char),KEYLEN(len),stream) != KEYLEN(len)) { fatal("Error in Reading....3\n"); return -1; } if (fread(kph->key + KEYLEN(len), 2*len+1,size,stream) != size) { fatal("Error in Reading....4\n"); return -1; } ahead = KeyAhead(kph->key); if (inmd->usrph[ahead] == NULL) inmd->usrph[ahead] = kph; else { tmp = inmd->usrph[ahead]; while (tmp->next != NULL) tmp = tmp->next; tmp->next = kph; } } } fclose(stream); return 0; } // Load the system and user phrase library // the phrase file can be combined just by cat a >> b static int LoadSysPhrase(InputModule *inmd,char *pathname) { FILE *stream; Phrase *kph; SysPhrase *sysph_tmp; char *p; int i,j; if ( (stream = fopen(pathname , "rb" )) == NULL ) { fatal("%s file can't open\n",pathname); return -1; } if (fseek(stream,-4,SEEK_END) == -1 || fread(&(inmd->sys_size),sizeof(int),1,stream) != 1 || inmd->sys_size != ftell(stream)-4) // error!! { fatal("%s is not a valid pinyin phrase file.\n",pathname); return -1; } fseek(stream,0,SEEK_SET); p = (char *) malloc (inmd->sys_size); memset (p, 0, inmd->sys_size); inmd->sys_num = 0; /* Attach the shared segment to local address space */ if (fread(p, inmd->sys_size, 1, stream) != 1) { fatal("Load File %s Error.\n", pathname); return -1; } kph=((SysPhrase*)p)->phrase; for(i = 1; i < MAX_PY_NUM; i++) { inmd->sysph[i] = sysph_tmp = (SysPhrase*)p; p = (char*)sysph_tmp->phrase; for(j = 0; j < sysph_tmp->count; j++) { kph = (Phrase*)p; p += SizeOfPhrase(kph->len,kph->count); // skip the string inmd->sys_num +=kph->count; } } fclose(stream); return 0; } static int LoadPhraseFrequency(InputModule *inmd,char *pathname) { FILE *stream; Phrase *sph; SysPhrase *sysph_tmp; u_char *f; char *p; int i,j,k,index,sys_size_tmp,sys_num_tmp,pcount; f = (char *) malloc (inmd->sys_num); if ( (stream = fopen(pathname , "rb" )) == NULL ) { fatal("%s file can't open\n",pathname); free(f); return -1; } if (fseek(stream,-sizeof(int)*3,SEEK_END) == -1 || fread(&(sys_size_tmp),sizeof(int),1,stream) != 1 || fread(&(sys_num_tmp),sizeof(int),1,stream) != 1 || inmd->sys_size != sys_size_tmp|| sys_num_tmp != ftell(stream)-sizeof(int)*2 || inmd->sys_num != sys_num_tmp) // error!! { fatal("%s is not a valid pinyin phrase freqency file.\n",pathname); free(f); return -1; } fseek(stream,0,SEEK_SET); if (fread(f, inmd->sys_num, 1, stream) != 1) { fatal("Load File %s Error.\n", pathname); free(f); return -1; } // pcount=0; for(i = 1; i < MAX_PY_NUM; i++) { sysph_tmp = inmd->sysph[i]; assert (sysph_tmp != NULL); p = (char*)sysph_tmp->phrase; // count = total pinyin number for(j = 0; j < sysph_tmp->count; j++) { sph = (Phrase *)p; assert (sph != NULL); for(k = 0; k < sph->count; k++) { index = KEYLEN(sph->len) + (2*sph->len+1)*k + 2*sph->len; sph->key[index] = f[pcount]; pcount++; } p += SizeOfPhrase(sph->len,sph->count); } } assert (pcount == inmd->sys_num); free(f); fseek(stream,-4,SEEK_END); fread(&(inmd->BootCount),sizeof(int),1,stream); fclose(stream); AdjustPhraseFreq(inmd); (inmd->BootCount)++; return 0; } // When loading the phrase library, save it in memory // structure, dynamic linklist /* str, hanzi codes, key: pinyin codes, len: length, pass: system/user */ // pass=1 system phrase, pass=0 user phrase(search first) static void SaveUsrPhraseToMem(InputModule* inmd, u_char *str,u_char *key,int len,int freq) { UsrPhrase *kph, *tmp, *p0; short ahead; int ct; if (len<1) return; ahead = (short)KeyAhead(key); for (p0 = inmd->usrph[ahead]; p0 != NULL; p0 = p0->next) if (p0->len == len && !memcmp(p0->key, key, KEYLEN(len))) break; if (p0 != NULL) { ct=p0->count; if ((kph = (UsrPhrase *)malloc(4+SizeOfPhrase(len,ct+1))) == NULL) fatal("Not enough memory\n"); memcpy(kph,p0,4+SizeOfPhrase(len,ct)); memcpy(kph->key+KEYLEN(len)+(2*len+1)*ct,str,len*2); kph->key[KEYLEN(len)+(2*len+1)*ct+len*2] = freq; kph->count=ct+1; if (p0 != inmd->usrph[ahead]) { for (tmp=inmd->usrph[ahead];tmp->next!=p0;tmp=tmp->next); tmp->next=kph; } else inmd->usrph[ahead]=kph; free(p0); } else { if ((kph = (UsrPhrase *)malloc(4+SizeOfPhrase(len,1))) == NULL) fatal("Not enough memory\n"); kph->len = len; memcpy(kph->key,key,KEYLEN(len)); kph->count = 1; kph->next = NULL; memcpy(kph->key + KEYLEN(len),str,len*2); kph->key[KEYLEN(len)+2*len] = freq; if (inmd->usrph[ahead] == NULL) inmd->usrph[ahead] = kph; else { tmp = inmd->usrph[ahead]; while (tmp->next != NULL) tmp = tmp->next; tmp->next = kph; } } } /* freq 0-255, simple algorithm save freq each time or don't save ( all set to 0 again?) make 0-255 -> 0-100 better 0-25, keep it 25-255, (freq-25)/10+25 25->48 */ static int AdjustPhraseFreq (InputModule *inmd) { UsrPhrase *uph; SysPhrase *sysph_tmp; Phrase *sph; int i,j,k,index; char *p; for(i = 1; i < MAX_PY_NUM; i++) { // user phrases for(uph = inmd->usrph[i]; uph != NULL; uph = uph->next) { for(k =0; k < uph->count; k++) { index = KEYLEN(uph->len) + (2*uph->len+1)*k + 2*uph->len; uph->key[index] = uph->key[index]*225/255; } } // system phrases sysph_tmp = inmd->sysph[i]; assert (sysph_tmp != NULL); p = (char*)sysph_tmp->phrase; // count = total pinyin number for(j = 0; j < sysph_tmp->count; j++) { sph = (Phrase *)p; assert (sph != NULL); for(k = 0; k < sph->count; k++) { index = KEYLEN(sph->len) + (2*sph->len+1)*k + 2*sph->len; if (inmd->BootCount < 4) { if(sph->key[index]<220) sph->key[index]=sph->key[index]*3/4; } else if (inmd->BootCount < 8) { if(sph->key[index]<250) sph->key[index] = sph->key[index]*210/255; } else if (inmd->BootCount < 20) sph->key[index] = (sph->key[index]*240.0/255+0.5); else sph->key[index] = (sph->key[index]*250.0/255+0.5); } p += SizeOfPhrase(sph->len,sph->count); } } return SUCCESS; } static int QueryPhrase(InputModule *inmd, u_char *key, int len, int wt) { u_short ahead; UsrPhrase *uph; char *p; SysPhrase *sysph_tmp; Phrase *sph; int j,count = 0; if (len<1) return 0; if (inmd->seltotal[len-1] >=MAX_TMP_SELECT) return 0; ahead = (u_short)KeyAhead(key); // for(i=0;iusrph[ahead]; uph != NULL && inmd->seltotal[len-1]next) { if (uph->len < len) continue; if (!KeyCmp(uph->key,key,len)) // match { if (uph->len == len ) // exact match { inmd->tempselwt[len-1][inmd->seltotal[len-1]] = wt; inmd->tempsel[len-1][ inmd->seltotal[len-1]++ ] = (Phrase*)( ((char*)uph) + 4 ); } else count++; // calculate the phrase longer than len } } // search in user phrase lib first, then system phrase libray sysph_tmp = inmd->sysph[ahead]; p = (char*)sysph_tmp->phrase; // count = total pinyin number assert (p != NULL); for(j = 0; j < sysph_tmp->count && inmd->seltotal[len-1]len >= len) { if (!KeyCmp(sph->key,key,len)) // match { if (sph->len == len) { inmd->tempselwt[len-1][inmd->seltotal[len-1]] = wt; inmd->tempsel[len-1][ inmd->seltotal[len-1]++ ] = sph; } else count++; } } p += SizeOfPhrase(sph->len,sph->count); } return count; } // given key and len, pass out kphs, original kphs = NULL // a big bug, if the phrase exists in system phrase, then the new user phrase // can't be showed void ResetPinyinInput(InputModule *inmd) { bzero(inmd->inbuf, sizeof(inmd->inbuf)); bzero(inmd->inbuftmp, sizeof(inmd->inbuftmp)); bzero(inmd->pybuftmp, sizeof(inmd->pybuftmp)); bzero(inmd->pinyin, sizeof(inmd->pinyin)); bzero(inmd->key, sizeof(inmd->key)); bzero(inmd->sel, sizeof(inmd->sel)); bzero(inmd->tempsel, sizeof(inmd->tempsel)); bzero(inmd->tempselwt, sizeof(inmd->tempselwt)); bzero(inmd->selwt,sizeof(inmd->selwt)); bzero(inmd->seltotal, sizeof(inmd->seltotal)); bzero(inmd->iapybuf, sizeof(inmd->iapybuf)); bzero(inmd->iahzbuf, sizeof(inmd->iahzbuf)); inmd->lenpy = 0; inmd->pinyinpos=0; inmd->lenkey=0; inmd->len = 0; inmd->startpos = 0; inmd->endpos = 0; inmd->nTotalCurSel = 0; inmd->flg_english = 0; } // pinyin[0]-pinyin[len-1], parsed pinyin chars // this routine calculate the a-z beginning and exclude the i/u/v begining static int EffectPyNum(PYString pinyin[],int len) { int i; char ch; int count=0; for(i=0; i'z') continue; count++; } return count; } static int SelectKeyPressed(InputModule *inmd,char ch,char *strbuf) { ChoiceItem *phr=inmd->sel; char *pybuftmp=inmd->pybuftmp; /* already selected Hanzi buffer */ char *inbuftmp=inmd->inbuftmp; /* inputed pinyin buffer */ char temp[2*MAX_PHRASE_LEN+1]; int j; u_char *fq; char strhz[MAX_PHRASE_LEN*2+1]; int pos,idx; if (ch == '\n') { strcpy(strbuf,inmd->inbuf); ResetPinyinInput(inmd); return 2; } if (!inmd->len) return 1; if (ch == ' ') idx = 0; else if (ch == '0') idx = 9; else idx = (int)ch-(int)'1'; idx += inmd->startpos; if (idx > inmd->endpos) return 1; // out of range selection! if (!(phr[idx].head)) return 1; // cannot find head! phr[idx] is zeroed strcpy(strhz,GetPhrase(phr+idx, temp)); strcat(pybuftmp,strhz); // for (i=0; ilen); i++) // inmd->key[i]=phr[idx].head->key[i]; // inmd->key[0] |= phr[idx].head->key[0] << inmd->lenkey; // for(i=1; i<=phr[idx].head->len; i++) // { // inmd->key[(inmd->lenkey)++ +1] = phr[idx].head->key[i]; // } /* pybuftmp, already selected chars */ if (inmd->lenkey + phr[idx].head->len > KEYLEN(MAX_PHRASE_LEN)) printf("Key is TOO LONG!!!\n"); KeyApp(inmd->key, phr[idx].head->key, inmd->lenkey, phr[idx].head->len); inmd->lenkey += phr[idx].head->len; if (strlen(pybuftmp)/2 == (size_t)EffectPyNum(inmd->pinyin,inmd->lenpy)) { if (strlen(strhz) == strlen(pybuftmp) ) { fq = GetFreq(phr+idx); if (*fq < 250) (*fq)++; /* strhz is the last phrase/char, equal, existing phrase/char increase its frequency */ } else if(strlen(pybuftmp) > 2) { SaveUsrPhraseToMem (inmd,pybuftmp,inmd->key,strlen(pybuftmp)/2,1); // not equal and pybuftmp, save the new phrase, 0 is user phrase } strcpy(strbuf,pybuftmp); ResetPinyinInput(inmd); return 2; /* All the pinyin are translated to char/phrases! */ } else // not yet, some unselected pinyin exist { inmd->flg_english = 0; // forward the pinyinpos pointer for(pos = strlen(strhz)/2; pos > 0 ; inmd->pinyinpos++) { ch = inmd->pinyin[inmd->pinyinpos][0]; if (ch=='i' || ch=='u' || ch=='v' || ch<'a' || ch>'z') { inmd->flg_english = 1; continue; } pos--; } FindMatchPhrase(inmd, inmd->pinyin + inmd->pinyinpos, inmd->lenpy - inmd->pinyinpos); FillForwardSelection(inmd,0); *inbuftmp = '\0'; // put the rest of the pinyin into inbuftmp for(j = inmd->pinyinpos; j < inmd->lenpy; j++) strcat(inbuftmp, inmd->pinyin[j]); CreatePyMsg(inmd); return 1; } } /* Always return 0, input pinyin, no key output available */ static int PinyinKeyPressed (InputModule *inmd, char ch, char *strbuf) { /* parameter strbuf is the newly inputed pinyin, inbuf the is the whole inputed pinyin, inbuftmp is the unselected pinyin */ char *inbuf=inmd->inbuf; char *pybuftmp=inmd->pybuftmp; /* already selected Hanzi buffer */ char *inbuftmp=inmd->inbuftmp; /* inputed pinyin buffer */ char chtmp; int count; int i; char tmpbuf[128]; /* \010 = Ctrl+H, \177 = BackSpace */ if (ch == '\010' || ch == '\177') // BackSpace { if (!strlen(inbuf)) return 0; else if (!strlen(inbuftmp)) { strcpy(inbuftmp,inbuf); inbuf[strlen(inbuf)-1] = '\0'; *pybuftmp='\0'; // clear all the selected chars, reparse } else { inbuf[strlen(inbuf)-1] = '\0'; if(inmd->flg_english) strcpy(inbuftmp,inbuf); else inbuftmp[strlen(inbuftmp)-1] = '\0'; // cut one pinyin-char off if (!strlen(inbuf)) { ResetPinyinInput(inmd); return 1; // mark that we will clear all, refresh } } } else //other than BackSpace, ch = a-z or ' { strcat(inbuf,strbuf); strcat(inbuftmp,strbuf); } if (!strlen(pybuftmp)) inmd->pinyinpos = 0; /* first pinyin char */ // parse the unselected pinyin(inbuftmp) input count = ParsePy(inmd,inbuftmp,inmd->pinyin + inmd->pinyinpos); inmd->lenpy = inmd->pinyinpos + count; /* exclude the last i/u/v-beginning pinyin */ if (inmd->lenpy > 0) { chtmp = inmd->pinyin[inmd->lenpy-1][0]; if (chtmp=='i' || chtmp=='u' || chtmp=='v') { // inbuf[strlen(inbuf)-1] = '\0'; inmd->flg_english = 1; inbuftmp[strlen(inbuftmp)-1] = '\0'; inmd->lenpy--; return 1; } } /* Too many chars now */ if (EffectPyNum(inmd->pinyin,inmd->lenpy) > MAX_PHRASE_LEN) { // inbuf[strlen(inbuf)-1] = '\0'; inbuftmp[strlen(inbuftmp)-1] = '\0'; inmd->lenpy--; return 1; } FindMatchPhrase(inmd,inmd->pinyin + inmd->pinyinpos, inmd->lenpy-inmd->pinyinpos); FillForwardSelection(inmd,0); CreatePyMsg(inmd); tmpbuf[0]='\0'; for (i = 0; ilenpy; i++) { strcat(tmpbuf,inmd->pinyin[i]); } if (strcmp(inmd->inbuf,tmpbuf)) inmd->flg_english = 1; else inmd->flg_english = 0; // printf("%s,%s\n",inmd->inbuf,tmpbuf); return 1; } static int PinyinParseInput(InputModule *inmd, char ch, char *strbuf) { // if ( (ch>='a' && ch<='z') || ch=='\''|| ch=='\010' || ch=='\177') if ( (ch>='a' && ch<='z') || (ch == '\'' && inmd->inbuf[0] != 0) || ch=='\010' || ch=='\177') return PinyinKeyPressed (inmd, ch, strbuf); if (!strlen(inmd->inbuf)) return 0; switch(ch) { case '=': case '>': case ']': case '.': // Select Forward FillForwardSelection(inmd,inmd->endpos+1); return 1; case '-': case '<': case '[': case ',': // Select Backward FillBackwardSelection(inmd,inmd->startpos-1); return 1; case '\033': //ESCAPE /* case 0x09: */ /* tab key */ if (inmd->len != 0) { ResetPinyinInput(inmd); return 1; } return 0; default: // select some keys if ( (ch>='1' && ch<='9') || ch=='0' || ch==' ' || ch=='\n') return SelectKeyPressed (inmd, ch, strbuf); break; } return 0; } /* pybuf, current inputed unselected pinyin buffer, MAX_PY_LEN=7 */ /* return the total chars parsed ? */ static int ParsePy(InputModule *inmd, char *pybuf, PYString pinyin[]) { int len, ahead,i, total = 0; int offset = 0, count, valid; len = strlen(pybuf); if (len < 1 || len > MAX_PHRASE_LEN * (MAX_PY_LEN+1) ) return 0; count = 2; /* 1 always valid */ while (offset + count <= len) { if (pybuf[offset] == '\'') // delimitor ' { strcpy(pinyin[total++],"\'"); offset++; count = 2; continue; } if (pybuf[offset] == 'v' || pybuf[offset] == 'i' || pybuf[offset] == 'u') { offset++; count = 2; continue; } ahead = pybuf[offset] - 'a'; if (ahead < 0 || ahead > 25) return 0; // test if this is a valid pinyin prefix valid = 0; for(i=0; inmd->pytab[ahead][i].key; i++) { if ( !strncmp(inmd->pytab[ahead][i].py,pybuf+offset,count) ) { valid = 1; break; } } if (valid) count++; else { strncpy(pinyin[total], pybuf+offset, count-1); pinyin[total++][count-1] = '\0'; offset += count-1; count = 2; } } // copy the remaining pinyin if (offset < len) { strncpy(pinyin[total], pybuf+offset, count-1); pinyin[total++][count-1] = '\0'; } return total; } /* create char/phrase according to the pinyin, lenpy is the length of pinyin array */ static void FindMatchPhrase(InputModule *inmd,PYString pinyin[],int lenpy) { int lenkey,keytmp; int i,j,k; int ahead,tmplen, count=0; int pykey[MAX_PHRASE_LEN][MAX_EACH_PY+1]; // MAX_PHRASE_LEN=6, MAX_EACH_PY = 38, a[], b[] int pykeywt[MAX_PHRASE_LEN][MAX_EACH_PY+1]; int wttmp; u_char py[MAX_PY_LEN+2]; u_char key[KEYLEN(MAX_PHRASE_LEN)]; u_char keyarr[MAX_PHRASE_LEN][MAX_TMP_SELECT][KEYLEN(MAX_PHRASE_LEN)]; // temporary array, 500 items int lenarr[MAX_PHRASE_LEN],result; char ch,ch2='\0'; if (!lenpy) { inmd->len = 0; return; } if (lenpy > MAX_PHRASE_LEN) lenpy=MAX_PHRASE_LEN; /* first of all, fill the pykey array */ for (i=0; i 'z') continue; // ignore the i/u/v beginning and non a-z ahead = pinyin[i][0] - 'a'; lenkey=0; tmplen=strlen(pinyin[i]); if(tmplen >1) ch2 = pinyin[i][1]; for(j=0; (keytmp = inmd->pytab[ahead][j].key); j++) { if ( tmplen == 1 || !strncmp(pinyin[i],inmd->pytab[ahead][j].py,tmplen) // if ( tmplen == 1 || !strcmp(pinyin[i],inmd->pytab[ahead][j].py) || ((tmplen==2) &&(!(inmd->FuzzyPinyin))&&(ch=='z'||ch=='c'||ch=='s') &&(ch2=='h'))) // prefix match { pykeywt[count][lenkey] = strlen(inmd->pytab[ahead][j].py) - tmplen; pykey[count][lenkey++] = keytmp; continue; } else if (inmd->FuzzyPinyin && (ch == 'z' || ch == 'c' || ch == 's')) { if (pinyin[i][1] != 'h') { strcpy(py+1,pinyin[i]); py[0] = py[1]; py[1] = 'h'; } else { strcpy(py,pinyin[i]+1); py[0] = ch; } if (!strncmp(py,inmd->pytab[ahead][j].py,strlen(py))) pykey[count][lenkey++] = keytmp; } } pykey[count++][lenkey] = 0; } // for i = 1 to lenpy, pykey array filled for(i=0; iseltotal[i] = 0; /* for the first char */ for(k=0; pykey[0][k]&&lenarr[0] 0) //save the possible multiple-char phrases memcpy(keyarr[0][lenarr[0]++],key,2); } /* count is the real pinyin number, parse the remaining */ for(i=1; i 0) { pykeywt[i][lenarr[i]]=wttmp; memcpy(keyarr[i][lenarr[i]++], key,KEYLEN(i+1)); } } } static void SortOutput(InputModule *inmd, int start) { int i,j,k,totalph = 0; ChoiceItem phtmp, *ph = inmd->sel; int end; u_char wttmp; if (start == 0) { totalph = 0; for(i = MAX_PHRASE_LEN-1; i >= 0; i--) { j=k=0; while(totalph < MAX_SELECT_PH && j < inmd->seltotal[i]) { inmd->sel[totalph].head = inmd->tempsel[i][j]; inmd->sel[totalph].index = k; inmd->selwt[totalph]=(u_char)(240-(inmd->tempselwt[i][j])*40/(i+1)); totalph++; if (++k >= inmd->tempsel[i][j]->count) { k=0; j++; } } } inmd->len = totalph; // total possible phrase selection } // sort the phrases end=start+10; if (end > (inmd->len)-1) end=(inmd->len)-1; for(k=start;klen; for(j=k+1;jlen && klen==ph[j].head->len;j++) { if((int)(*GetFreq(ph+k))+inmd->selwt[k] < (int)(*GetFreq(ph+j))+inmd->selwt[j]) { wttmp = inmd->selwt[k]; inmd->selwt[k] = inmd->selwt[j]; inmd->selwt[j] = wttmp; phtmp = ph[k]; ph[k] = ph[j]; ph[j] = phtmp; } } } } /* startpos = 0 -> len-1 */ static void FillForwardSelection(InputModule *inmd,int startpos) { char *iahzbuf=inmd->iahzbuf; char temp[2*MAX_PHRASE_LEN+1]; int i,count; int SelAreaWidth = inmd->SelectionLen; // GetScreenWidth() - 12 - PINYIN_AREA_WIDTH; char strtmp[2*MAX_PHRASE_LEN+10]; SortOutput(inmd,startpos); if (startpos > inmd->len - 1 || startpos < 0) return ; // non-forwardable, keep the iahzbuf intact iahzbuf[0] = '\0'; if (inmd->len < 1) return; // clear the iahzbuf count = 0; // backup the starting position inmd->startpos = startpos; inmd->endpos = startpos - 1; if (inmd->startpos > 0) sprintf(inmd->iahzbuf,"< "); else sprintf(inmd->iahzbuf," "); while(inmd->endpos < inmd->len-1 && count < 10) { sprintf(strtmp,"%d%s ",(count+1)%10, GetPhrase(inmd->sel+inmd->endpos+1, temp)); if ( (strlen(iahzbuf)+strlen(strtmp)+2) <= (u_int)SelAreaWidth) { strcat(iahzbuf,strtmp); inmd->endpos++; count++; } else break; } inmd->nTotalCurSel = count; if (inmd->endpos < inmd->len - 1 && count >= 1) { for(i = strlen(iahzbuf); i < SelAreaWidth-2; i++) iahzbuf[i] = ' '; iahzbuf[SelAreaWidth-2] = '>'; iahzbuf[SelAreaWidth-1] = '\0'; // strncat(iahzbuf,strspace,SelAreaWidth-strlen(iahzbuf)-2); // strcat(iahzbuf,">"); } } static void FillBackwardSelection(InputModule *inmd,int lastpos) { char *iahzbuf=inmd->iahzbuf; char temp[2*MAX_PHRASE_LEN+1]; int SelAreaWidth = inmd->SelectionLen; //GetScreenWidth() - 10 - PINYIN_AREA_WIDTH; int count,ialen; char strbuf[2*MAX_PHRASE_LEN+10]; if (lastpos < 0 || lastpos > inmd->len-1) return; // iahzbuf intact iahzbuf[0] = '\0'; if (inmd->len < 1) return; // clear iahzbuf count = 0; inmd->endpos = lastpos; ialen = 2; // leftmost "< " or " " inmd->startpos = lastpos+1; while(inmd->startpos > 0 && count < 10) { strcpy(strbuf,GetPhrase(inmd->sel+inmd->startpos-1, temp)); ialen += strlen(strbuf)+2; if (ialen+2 > SelAreaWidth) break; count++; inmd->startpos--; } FillForwardSelection(inmd,inmd->startpos); } /* PY Area: User's PinYin string */ /* hzstr, the prefix HZ string, str: destination string */ static void CreatePyMsg(InputModule *inmd) { int i; strcpy(inmd->iapybuf,inmd->pybuftmp); for(i=inmd->pinyinpos; ilenpy; i++) { strcat(inmd->iapybuf,inmd->pinyin[i]); // MAX_PY_LEN = 7 if (inmd->pinyin[i+1][0] == '\'' || inmd->pinyin[i][0] == '\'') continue; else strcat(inmd->iapybuf," "); } } InputModule *pCCE_OpenPinyin (char *szPath) { InputModule *p; p = (InputModule *) malloc (sizeof (InputModule)); if (p != NULL) ResetPinyinInput (p); p->SelectionLen = 80 - 12 - PINYIN_AREA_WIDTH; p->FuzzyPinyin = 0; if (InitPinyinInput (p,szPath) == -1) return NULL; return p; } void CCE_ClosePinyin (InputModule *p) { char buf[256]; ResetPinyinInput(p); AdjustPhraseFreq(p); sprintf(buf, "%s/.pyinput/sysfrequency.tab", getenv("HOME")); SavePhraseFrequency(p,buf); sprintf(buf,"%s/.pyinput/usrphrase.tab",getenv("HOME")); SaveUsrPhrase(p,buf); UnloadSysPhrase (p); UnloadUserPhrase (p); free (p); } void CCE_Flush (InputModule *pClient) { char name[128]; ResetPinyinInput(pClient); sprintf(name,"%s/.pyinput/usrphrase.tab",getenv("HOME")); SaveUsrPhrase(pClient,name); sprintf(name,"%s/.pyinput/sysfrequency.tab",getenv("HOME")); SavePhraseFrequency(pClient,name); } int Pinyin_KeyFilter (InputModule *pClient, u_char key, char *buf, int *len) { int r; buf[0] = key; buf[1] = '\0'; r = PinyinParseInput (pClient, key, buf); switch (r) { case -1: return 0; case 2: *len = strlen (buf); return 2; case 1: case 0: break; default: printf ("r = %d\n", r); assert (false); break; } return r; } char *Pinyin_szGetSelItem (InputModule *pClient, int n, char *buf) { ChoiceItem *phr=pClient->sel; int idx = n; char temp[256]; if (n >= 0 && n < pClient->nTotalCurSel) { if (!pClient->len) return NULL; idx = pClient->startpos + n; if (idx > pClient->endpos) return NULL; // out of range selection! strcpy (buf, GetPhrase(phr+idx, temp)); return buf; } return NULL; } int Pinyin_ConfigureInputArea (InputModule * p, int SelectionLen0) { p->SelectionLen = SelectionLen0; return 1; } int CCE_GetInputDisplay (InputModule * p, char *buf) { // strcpy (buf, p->iapybuf); if(p->flg_english) strcpy (buf, p->inbuf); else strcpy (buf, p->iapybuf); return 1; } int CCE_GetSelectDisplay (InputModule *p, char *buf) { if(p->flg_english) strcpy (buf, p->inbuf); else strcpy (buf, p->iahzbuf); return p->nTotalCurSel; }