LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1291|回复: 13

G五笔原码学习笔记

[复制链接]
发表于 2003-3-6 14:42:55 | 显示全部楼层 |阅读模式
我象很多初学者一样,一直想通过学习原代码增加对电脑的认识。现在先从G五笔原码学习开始。希望抛砖引玉...

首先要学习汉字与编码的数据结构。
struct TWBRECORD {
    char            strCode[WB_CODE_LENGTH + 1];    //编码
    char           *strHZ;                                                        //汉字
    struct TWBRECORD *next;                                                //双向列表指针
    struct TWBRECORD *prev;
};
typedef struct TWBRECORD WBRecord;
发表于 2003-3-6 14:50:45 | 显示全部楼层
好啊好啊!光看源码有点枯燥,不妨自己定个任务,比如实现一个自己的功能,或者修改一个bug,这也是帮Yuking大哥哦:)
 楼主| 发表于 2003-3-6 15:17:32 | 显示全部楼层
再看装载码表到内存的子程序

int LoadWBDict (void)
{
    int             iCount;
    char            strText[1024];
    char           *pstr;
    FILE           *fpDict;
    WBRecord       *recTemp;
    char            strPath[256];

    strcpy (strPath, (char *) getenv ("HOME"));
    strcat (strPath, "/.gWuBi/wbx.mb");

    if (access (strPath, 0)) {
        if (bRunLocal) {
            strcpy (strPath, (char *) getenv ("HOME"));
            strcat (strPath, "/fcitx/");
        }
        else
            strcpy (strPath, DATA_DIR);
        strcat (strPath, WUBI_DICT_FILENAME);
        fpDict = fopen (strPath, "rt");//打开码表文件
    }
    else
        fpDict = fopen (strPath, "rt");
    if (!fpDict)
        return FILE_NOT_FOUND;

    iRecordNumber = 0;
    wubiDictHead = (WBRecord *) malloc (sizeof (WBRecord));
    if (!wubiDictHead)
        return CANNOT_ALLOC_MEMORY;
    wubiDictCurrent = wubiDictHead;

    for (;;) {
        if (!fgets (strText, 1024, fpDict))//读取码表中的一行
            break;
        iCount = strlen (strText) - 1;//取得字符串最大下标

        while ((strText[iCount] == '\n') || (strText[iCount] == ' ')) {//将尾部的回车或空格删除
            if (!iCount)//若为空行,跳出
                break;
            iCount--;
        }

        if (iCount) {
            recTemp = (WBRecord *) malloc (sizeof (WBRecord));//分配内存
            if (!recTemp)
                return False;
            wubiDictCurrent->next = recTemp;
            recTemp->prev = wubiDictCurrent;
            wubiDictCurrent = recTemp;//将新分配的内存加入双向链表,wubiDictCurrent指向recTemp

            strText[iCount + 1] = '\0';//在字符串空格标志
            pstr = strText;
            iCount = 0;
            while (*pstr != ' ')
                recTemp->strCode[iCount++] = *pstr++;//从如下的型段程序可以看出,码表中编码与汉字符中要有一个空格
            recTemp->strCode[iCount] = '\0';
            pstr++;
            recTemp->strHZ = (char *) malloc (sizeof (char) * strlen (pstr) + 1);
            if (!recTemp->strHZ)
                return False;
            strcpy (recTemp->strHZ, pstr);
            iRecordNumber++;
        }
    }
    wubiDictCurrent->next = wubiDictHead;
    wubiDictHead->prev = wubiDictCurrent;//所有行装载完毕,将最后的结构与第一个结构建立关系,形成闭合

    fclose (fpDict);

    return LOAD_DICT_SUCCESS;
}
发表于 2003-3-7 14:28:32 | 显示全部楼层

--

程序有点乱,我还想以后好好改改代码
 楼主| 发表于 2003-3-8 09:30:55 | 显示全部楼层
看了原码,才知道两位作者,特别是Yuking大哥真的很辛苦。我也从中学了不少东西,原来从来没有在linux下编程过,只是学了C,现在揣摩着G五笔的原码,感觉学到许多东西,虽然很多不能完全理解,所以如果有揣测错误的地方,敬请两位作者指出。
再次感谢两位作者,特别是Yuking大哥。
 楼主| 发表于 2003-3-8 10:32:38 | 显示全部楼层
关于区位码,我原先不怎么清楚,但从程序中可以了解一些,再加上用google查一些书面此方面知识,多少增加了些知识。

汉字的内码通常与所使用的计算机系统有关。目前,对于国内大多数的计算机系统,一个汉字的内码占两个字节,分别称为高位字节与低位字节,且这两位字节与区位码的关系如下: 内码高位=区码+A0H(H表示十六进制) 内码低位=位码+A0H 例如,汉字"啊"的区位码为"1601",区码和位码分别用十六进制表示即为"1001H",则它的内码为"B0A1H"。其中B0H为内码的高位字节,A1H为内码的低位字节。

GBK与GB2312相兼容中,码位分配总体上采用十六进制数8140H-FEFEH的矩形区域,剔除xx7FH一条线,共计23940个码位。

void GetCandWordsByQW ()
{
    int             iQu, iWei;
    int             i;
    char            strTemp[2];

    strCandString[0] = '\0';
    strTemp[1] = '\0';

    iQu = (strCodeInput[0] - '0') * 10 + strCodeInput[1] - '0';//由输入的三个数字得到区码与位码的十位部分。
    iWei = (strCodeInput[2] - '0') * 10;//由变量strCodeInput得到键盘输入

    for (i = 0; i < 10; i++) {//位码的个位部分作为预选
        strTemp[0] = i + '0';
        strcat (strCandString, strTemp);
        strcat (strCandString, ".");
        strcat (strCandString, GetQuWei (iQu, iWei + i));//由变量strCandString输出到预选框显示
        strcat (strCandString, " ");
    }
}


char           *GetQuWei (int iQu, int iWei)
{
    static char     strHZ[3];

    if (iQu >= 95) {                /* Process extend Qu 95 and 96 *///95,96区扩展
        strHZ[0] = iQu - 95 + 0xA8;
        strHZ[1] = iWei + 0x40;

        /* skip 0xa87f and 0xa97f */
        if ((unsigned char) strHZ[1] >= 0x7f)//由于GBK剔除xx7FH一条线,所以位码大于7FH的要加一
            strHZ[1]++;
    }
    else {
        strHZ[0] = iQu + 0xa0;
        strHZ[1] = iWei + 0xa0;
    }

    strHZ[2] = '\0';

    return strHZ;
}
 楼主| 发表于 2003-3-8 10:39:31 | 显示全部楼层
最先要看的首先是main.c,它是主文件,然后根据它调用函数再顺藤摸瓜看相应的文件。

int main (int argc, char **argv)
{
    XEvent          event;

    /*CopyRight (); */
    SetMyExceptionHandler ();
    if (!InitX ())
        exit (1);
    LoadProfile ();
    LoadConfig ();

    GetLocale ();

    AllocColor ();
    CreateFont ();
    SetLocale ();

    if (!CreateMainWindow ()) {
        fprintf (stderr, "无法创建主窗口!\n");
        exit (3);
    }
    if (!CreateInputWindow ()) {
        fprintf (stderr, "无法创建输入窗口!\n");
        exit (3);
    }
    if (!CreateAddPhraseWindow ()) {
        fprintf (stderr, "无法创建增加词组窗口!\n");
        exit (3);
    }

    InitGC (MainWindow);

    if (!InitXIM (argc, argv, MainWindow))
        exit (4);

    if (!bHideMainLogo)
        DisplayMainWindow ();

    if (LoadWBDict ()) {
        fprintf (stderr, "无法读取五笔码表!\n");
        exit (2);
    }
    if (LoadPuncDict ())
        fprintf (stderr, "无法读取标点码表!\n将无法输入中文标点。");
    if (LoadPYDict ())
        fprintf (stderr, "无法读取拼音码表!\n将不能使用拼音输入法。\n");
    InitPY ();
    ResetInput ();

    for (;;) {
        XNextEvent (dpy, &event);

        if (XFilterEvent (&event, None) == True)
            continue;
        MyXEventHandler (InputWindow, &event);
    }

    return 0;
}
 楼主| 发表于 2003-3-8 10:58:43 | 显示全部楼层
void SetMyExceptionHandler (void)
{
    int             signo;

    for (signo = SIGHUP; signo < SIGUNUSED; signo++) {
        if (signo != SIGINT && signo != SIGQUIT && signo != SIGWINCH)
            signal (signo, OnException);
    }
}

/usr/include/signal.h中有
extern __sighandler_t signal (int __sig, __sighandler_t __handler) __THROW;
这一段可能是将信号及信号的处理程序建立关系。  我一时找不到SIGHUP等在哪里define,请yuking大哥指点。
 楼主| 发表于 2003-3-8 12:51:49 | 显示全部楼层
Bool InitX (void)
{
    if ((dpy = XOpenDisplay ((char *) NULL)) == NULL) {
        fprintf (stderr, "gWuBi can only run under X\n");
        return False;
    }

    SetMyXErrorHandler ();
    iScreen = DefaultScreen (dpy);

    return True;
}
这段程序初始化X窗口,其中调用的函数:

/usr/include/X11/Xlib.h中有

extern Display *XOpenDisplay(
#if NeedFunctionPrototypes
    _Xconst char*        /* display_name */
#endif
);



#define DefaultScreen(dpy)         (((_XPrivDisplay)dpy)->default_screen)

MyErrorsHandlers.c中有

void SetMyXErrorHandler (void)
{
    oldXErrorHandler = XSetErrorHandler (MyXErrorHandler);
}

而XSetErrorHandler (MyXErrorHandler)一时找不到来自哪里?
 楼主| 发表于 2003-3-8 13:22:11 | 显示全部楼层
void LoadProfile (void)
{
    FILE           *fp;
    char            str[PATH_MAX], *pstr;
    char            strPath[PATH_MAX];
    int             i;

    strcpy (strFontName, "*");
   
    #ifndef _USE_XFT
    strcpy (strFontLocale, "zh_CN.GBK");
    #endif
   
    strcpy (strPath, (char *) getenv ("HOME"));
    strcat (strPath, "/.gWuBi/profile");
    fp = fopen (strPath, "rt");
    if (!fp)
        SaveProfile ();
    else {
        for (;; ) {
            if (!fgets (str, PATH_MAX, fp))
                break;
            if (str[0] == '#')//如果行头为#,略过此行
                continue;
            i = strlen (str) - 1;
            while (str == ' ' || str == '\n')//除去行尾空格回车,并加字符串结束标志
                str[i--] = '\0';
            pstr = str;
            if (!strncmp (str, "区域设置=", 9)) {   //比较行首9个字符是否是"区域设置="
                pstr += 9;
                if (pstr[0] != '\0')//如果在"区域设置="没有内容,pstr[0]为刚才所加字符串结束标志
                    strcpy (strUserLocale, pstr);
            }
            else if (strstr (str, "字体=")) {
                pstr += 5;
                if (pstr[0] != '\0')
                    strcpy (strFontName, pstr);
            }
            #ifndef _USE_XFT
            else if (strstr (str, "字体区域设置=")) {
                pstr += 13;
                if (pstr[0] != '\0')
                    strcpy (strFontLocale, pstr);
            }
            #endif
            else if (strstr (str, "是否自动隐藏输入条=")) {
                pstr += 19;
                bAutoHide = atoi (pstr);
            }
            else if (strstr (str, "是否隐藏主图标=")) {
                pstr += 15;
                bHideMainLogo = atoi (pstr);
            }
            else if (strstr (str, "是否光标跟随=")) {
                pstr += 13;
                bTrackCursor = atoi (pstr);
            }
            else if (strstr (str, "是否使用Z输入拼音=")) {
                pstr += 18;
                bUseZPinYin = atoi (pstr);
            }
            else if (strstr (str, "出错时是否响铃=")) {
                pstr += 15;
                bBell = atoi (pstr);
            }
            else if (strstr (str, "是否切换区位输入法=")) {
                pstr += 19;
                bSwitchQW = atoi (pstr);
            }
            else if (strstr (str, "拼音单字重码调整方式=")) {
                pstr += 21;
                baseOrder = (ADJUSTORDER) atoi (pstr);
            }
            else if (strstr (str, "拼音词组重码调整方式=")) {
                pstr += 21;
                phraseOrder = (ADJUSTORDER) atoi (pstr);
            }
            else if (strstr (str, "拼音常用词重码调整方式=")) {
                pstr += 23;
                freqOrder = (ADJUSTORDER) atoi (pstr);
            }

            else if (strstr (str, "是否模糊an和ang=")) {
                pstr += 16;
                MHPY_C[0].bMode = atoi (pstr);
            }
            else if (strstr (str, "是否模糊en和eng=")) {
                pstr += 16;
                MHPY_C[1].bMode = atoi (pstr);
            }
            else if (strstr (str, "是否模糊ian和iang=")) {
                pstr += 18;
                MHPY_C[2].bMode = atoi (pstr);
            }
            else if (strstr (str, "是否模糊in和ing=")) {
                pstr += 16;
                MHPY_C[3].bMode = atoi (pstr);
            }
            else if (strstr (str, "是否模糊ou和u=")) {
                pstr += 14;
                MHPY_C[4].bMode = atoi (pstr);
            }
            else if (strstr (str, "是否模糊uan和uang=")) {
                pstr += 18;
                MHPY_C[5].bMode = atoi (pstr);
            }
            else if (strstr (str, "是否模糊c和ch=")) {
                pstr += 14;
                MHPY_S[0].bMode = atoi (pstr);
            }
            else if (strstr (str, "是否模糊f和h=")) {
                pstr += 13;
                MHPY_S[1].bMode = atoi (pstr);
            }
            else if (strstr (str, "是否模糊l和n=")) {
                pstr += 13;
                MHPY_S[2].bMode = atoi (pstr);
            }
            else if (strstr (str, "是否模糊s和sh=")) {
                pstr += 14;
                MHPY_S[3].bMode = atoi (pstr);
            }
            else if (strstr (str, "是否模糊z和zh=")) {
                pstr += 14;
                MHPY_S[4].bMode = atoi (pstr);
            }
        }
        fclose (fp);
    }
}
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表