Beispiel #1
0
int main(int argc, char* argv[])
{
    char* localedir = fcitx_utils_get_fcitx_path("localedir");
    setlocale(LC_ALL, "");
    bindtextdomain("fcitx", localedir);
    free(localedir);
    bind_textdomain_codeset("fcitx", "UTF-8");
    textdomain("fcitx");
    if (pipe(selfpipe) < 0) {
        fprintf(stderr, "Could not create self-pipe.\n");
        exit(1);
    }
    fcntl(selfpipe[0], F_SETFL, O_NONBLOCK);
    fcntl(selfpipe[1], F_SETFL, O_NONBLOCK);

    SetMyExceptionHandler();

    int instanceCount = 1;

    sem_t sem;
    sem_init(&sem, 0, 0);

    instance = FcitxInstanceCreateWithFD(&sem, argc, argv, selfpipe[0]);
    WaitForEnd(&sem, instanceCount);

    if (instance->loadingFatalError) {
        return 1;
    }
    return 0;
}
Beispiel #2
0
FCITX_EXPORT_API
char* fcitx_utils_get_fcitx_path_with_filename(const char* type, const char* filename)
{
    char* path = fcitx_utils_get_fcitx_path(type);
    if (path == NULL)
        return NULL;
    char *result;
    fcitx_utils_alloc_cat_str(result, path, "/", filename);
    free(path);
    return result;
}
Beispiel #3
0
int main(int argc, char* argv[])
{
    char* localedir = fcitx_utils_get_fcitx_path("localedir");
    setlocale(LC_ALL, "");
    bindtextdomain("fcitx", localedir);
    free(localedir);
    bind_textdomain_codeset("fcitx", "UTF-8");
    textdomain("fcitx");
    WrapperApp app(argc, argv);
    return app.exec();
}
Beispiel #4
0
void* fcitx_keyboard_init(FcitxAddonManager* manager, const FcitxAddonConfig* config)
{
    FCITX_UNUSED(manager);
    FCITX_UNUSED(config);
    FcitxKeyboard* keyboard = fcitx_utils_new(FcitxKeyboard);
    char* localepath = fcitx_utils_get_fcitx_path("localedir");
    bindtextdomain("xkeyboard-config", localepath);
    bind_textdomain_codeset("xkeyboard-config", "UTF-8");
    free(localepath);

    return keyboard;
}
Beispiel #5
0
/**
 * Open the dict file, return -1 if failed.
 **/
static int
SpellCustomGetSysDictFile(FcitxSpell *spell, const char *lang)
{
    int fd;
    char *path;
    char *fname;
    path = fcitx_utils_get_fcitx_path("pkgdatadir");
    fcitx_utils_alloc_cat_str(fname, path, "/data/", lang, "_dict.fscd");
    free(path);
    fd = open(fname, O_RDONLY);
    free(fname);
    return fd;
}
Beispiel #6
0
FCITX_EXPORT_API
FILE *FcitxXDGGetLibFile(const char *filename, const char *mode, char **retFile)
{
    size_t len;
    char ** path;
    char* libdir = fcitx_utils_get_fcitx_path("libdir");
    path = FcitxXDGGetPath(&len, "XDG_CONFIG_HOME", ".config", PACKAGE "/lib" , libdir, PACKAGE);
    free(libdir);

    FILE* fp = FcitxXDGGetFile(filename, path, mode, len, retFile);

    FcitxXDGFreePath(path);

    return fp;

}
Beispiel #7
0
FCITX_EXPORT_API
FILE *FcitxXDGGetFileWithPrefix(const char* prefix, const char *fileName, const char *mode, char **retFile)
{
    size_t len;
    char *prefixpath;
    asprintf(&prefixpath, "%s/%s", PACKAGE, prefix);
    char* datadir = fcitx_utils_get_fcitx_path("datadir");
    char ** path = FcitxXDGGetPath(&len, "XDG_CONFIG_HOME", ".config", prefixpath , datadir, prefixpath);
    free(datadir);
    free(prefixpath);

    FILE* fp = FcitxXDGGetFile(fileName, path, mode, len, retFile);

    FcitxXDGFreePath(path);

    return fp;
}
Beispiel #8
0
FcitxStringList* fcitx_standard_default_paths_construct(const char* env, const char* defaultPath, const char* fcitxPath)
{
    FcitxStringList* dirs = fcitx_utils_string_list_new();

    if (fcitxPath) {
        char* path = fcitx_utils_get_fcitx_path(fcitxPath);
        fcitx_utils_string_list_append_no_copy(dirs, path);
    }

    const char* dir = getenv(env);
    if (!dir) {
        dir = defaultPath;
    }

    dirs = fcitx_utils_string_list_append_split_full(dirs, dir, ":", false);

    return dirs;
}
Beispiel #9
0
FCITX_EXPORT_API
FcitxStringHashSet* FcitxXDGGetFiles(
    char* path,
    char* prefix,
    char* suffix
)
{
    char **xdgPath;
    size_t len;
    char *pathBuf;
    size_t i = 0;
    DIR *dir;
    struct dirent *drt;
    struct stat fileStat;

    FcitxStringHashSet* sset = NULL;

    char *prefixpath;
    asprintf(&prefixpath, "%s/%s", PACKAGE, path);
    char* datadir = fcitx_utils_get_fcitx_path("datadir");
    xdgPath = FcitxXDGGetPath(&len, "XDG_CONFIG_HOME", ".config" , prefixpath , datadir , prefixpath);
    free(datadir);
    free(prefixpath);

    for (i = 0; i < len; i++) {
        asprintf(&pathBuf, "%s", xdgPath[i]);

        dir = opendir(pathBuf);
        free(pathBuf);
        if (dir == NULL)
            continue;

        size_t suffixlen = 0;
        size_t prefixlen = 0;

        if (suffix) suffixlen = strlen(suffix);
        if (prefix) prefixlen = strlen(prefix);

        /* collect all *.conf files */
        while ((drt = readdir(dir)) != NULL) {
            size_t nameLen = strlen(drt->d_name);
            if (nameLen <= suffixlen + prefixlen)
                continue;

            if (suffix && strcmp(drt->d_name + nameLen - suffixlen, suffix) != 0)
                continue;
            if (prefix && strncmp(drt->d_name, prefix, prefixlen) != 0)
                continue;
            asprintf(&pathBuf, "%s/%s", xdgPath[i], drt->d_name);

            int statresult = stat(pathBuf, &fileStat);
            free(pathBuf);
            if (statresult == -1)
                continue;

            if (fileStat.st_mode & S_IFREG) {
                FcitxStringHashSet *string;
                HASH_FIND_STR(sset, drt->d_name, string);
                if (!string) {
                    char *bStr = strdup(drt->d_name);
                    string = malloc(sizeof(FcitxStringHashSet));
                    memset(string, 0, sizeof(FcitxStringHashSet));
                    string->name = bStr;
                    HASH_ADD_KEYPTR(hh, sset, string->name, strlen(string->name), string);
                }
            }
        }

        closedir(dir);
    }

    FcitxXDGFreePath(xdgPath);

    return sset;
}
Beispiel #10
0
boolean LoadTableDict(TableMetaData* tableMetaData)
{
    char            strCode[MAX_CODE_LENGTH + 1];
    char           *strHZ = 0;
    FILE           *fpDict;
    RECORD         *recTemp;
    unsigned int    i = 0;
    uint32_t        iTemp, iTempCount;
    char            cChar = 0, cTemp;
    int8_t          iVersion = 1;
    int             iRecordIndex;
    TableDict      *tableDict;

    //读入码表
    FcitxLog(DEBUG, _("Loading Table Dict"));

    int reload = 0;
    do {
        boolean error = false;
        if (!reload) {
            /**
             * kcm saves a absolute path here but it is then interpreted as
             * a relative path?
             **/
            fpDict = FcitxXDGGetFileWithPrefix("table", tableMetaData->strPath,
                                               "r", NULL);
        } else {
            char *tablepath;
            char *path = fcitx_utils_get_fcitx_path("pkgdatadir");
            fcitx_utils_alloc_cat_str(tablepath, path, "/table/",
                                      tableMetaData->strPath);
            fpDict = fopen(tablepath, "r");
            free(tablepath);
        }
        if (!fpDict)
            return false;

        tableMetaData->tableDict = fcitx_utils_new(TableDict);

        tableDict = tableMetaData->tableDict;
        tableDict->pool = fcitx_memory_pool_create();
#define CHECK_LOAD_TABLE_ERROR(SIZE) if (size < (SIZE)) { error = true; goto table_load_error; }

        //先读取码表的信息
        //判断版本信息
        size_t size;
        size = fcitx_utils_read_uint32(fpDict, &iTemp);
        CHECK_LOAD_TABLE_ERROR(1);

        if (!iTemp) {
            size = fread(&iVersion, sizeof(int8_t), 1, fpDict);
            CHECK_LOAD_TABLE_ERROR(1);
            iVersion = (iVersion < INTERNAL_VERSION);
            size = fcitx_utils_read_uint32(fpDict, &iTemp);
            CHECK_LOAD_TABLE_ERROR(1);
        }

        tableDict->strInputCode = (char*)realloc(tableDict->strInputCode, sizeof(char) * (iTemp + 1));
        size = fread(tableDict->strInputCode, sizeof(char), iTemp + 1, fpDict);
        CHECK_LOAD_TABLE_ERROR(iTemp + 1);
        /*
         * 建立索引,加26是为了为拼音编码预留空间
         */
        size_t tmp_len = strlen(tableDict->strInputCode) + 26;
        tableDict->recordIndex = (RECORD_INDEX*)fcitx_memory_pool_alloc(tableDict->pool, tmp_len * sizeof(RECORD_INDEX));
        for (iTemp = 0; iTemp < tmp_len; iTemp++) {
            tableDict->recordIndex[iTemp].cCode = 0;
            tableDict->recordIndex[iTemp].record = NULL;
        }
        /********************************************************************/

        size = fread(&(tableDict->iCodeLength), sizeof(uint8_t), 1, fpDict);
        CHECK_LOAD_TABLE_ERROR(1);
        UpdateTableMetaData(tableMetaData);

        if (!iVersion) {
            size = fread(&(tableDict->iPYCodeLength), sizeof(uint8_t), 1, fpDict);
            CHECK_LOAD_TABLE_ERROR(1);
        }
        else
            tableDict->iPYCodeLength = tableDict->iCodeLength;

        size = fcitx_utils_read_uint32(fpDict, &iTemp);
        CHECK_LOAD_TABLE_ERROR(1);
        tableDict->strIgnoreChars = (char*)fcitx_memory_pool_alloc(tableDict->pool, sizeof(char) * (iTemp + 1));
        size = fread(tableDict->strIgnoreChars, sizeof(char), iTemp + 1, fpDict);
        CHECK_LOAD_TABLE_ERROR(iTemp + 1);

        size = fread(&(tableDict->bRule), sizeof(unsigned char), 1, fpDict);
        CHECK_LOAD_TABLE_ERROR(1);

        if (tableDict->bRule) { //表示有组词规则
            tableDict->rule = (RULE*)fcitx_memory_pool_alloc(tableDict->pool, sizeof(RULE) * (tableDict->iCodeLength - 1));
            for (i = 0; i < tableDict->iCodeLength - 1; i++) {
                size = fread(&(tableDict->rule[i].iFlag), sizeof(unsigned char), 1, fpDict);
                CHECK_LOAD_TABLE_ERROR(1);
                size = fread(&(tableDict->rule[i].iWords), sizeof(unsigned char), 1, fpDict);
                CHECK_LOAD_TABLE_ERROR(1);
                tableDict->rule[i].rule = (RULE_RULE*)fcitx_memory_pool_alloc(tableDict->pool, sizeof(RULE_RULE) * tableDict->iCodeLength);
                for (iTemp = 0; iTemp < tableDict->iCodeLength; iTemp++) {
                    size = fread(&(tableDict->rule[i].rule[iTemp].iFlag), sizeof(unsigned char), 1, fpDict);
                    CHECK_LOAD_TABLE_ERROR(1);
                    size = fread(&(tableDict->rule[i].rule[iTemp].iWhich), sizeof(unsigned char), 1, fpDict);
                    CHECK_LOAD_TABLE_ERROR(1);
                    size = fread(&(tableDict->rule[i].rule[iTemp].iIndex), sizeof(unsigned char), 1, fpDict);
                    CHECK_LOAD_TABLE_ERROR(1);
                }
            }
        }

        tableDict->recordHead = (RECORD*)fcitx_memory_pool_alloc(tableDict->pool, sizeof(RECORD));
        tableDict->currentRecord = tableDict->recordHead;

        size = fcitx_utils_read_uint32(fpDict, &tableDict->iRecordCount);
        CHECK_LOAD_TABLE_ERROR(1);

        for (i = 0; i < SINGLE_HZ_COUNT; i++) {
            tableDict->tableSingleHZ[i] = (RECORD*)NULL;
            tableDict->tableSingleHZCons[i] = (RECORD*)NULL;
        }

        iRecordIndex = 0;
        size_t bufSize = 0;
        for (i = 0; i < tableDict->iRecordCount; i++) {
            size = fread(strCode, sizeof(int8_t), tableDict->iPYCodeLength + 1, fpDict);
            CHECK_LOAD_TABLE_ERROR(tableDict->iPYCodeLength + 1);
            size = fcitx_utils_read_uint32(fpDict, &iTemp);
            CHECK_LOAD_TABLE_ERROR(1);
            /* we don't actually have such limit, but sometimes, broken table
             * may break this, so we need to give a limitation.
             */
            if (iTemp > UTF8_MAX_LENGTH * 30) {
                error = true;
                goto table_load_error;
            }
            if (iTemp > bufSize) {
                bufSize = iTemp;
                strHZ = realloc(strHZ, bufSize);
            }
            size = fread(strHZ, sizeof(int8_t), iTemp, fpDict);
            CHECK_LOAD_TABLE_ERROR(iTemp);
            recTemp = (RECORD*)fcitx_memory_pool_alloc(tableDict->pool, sizeof(RECORD));
            recTemp->strCode = (char*)fcitx_memory_pool_alloc(tableDict->pool, sizeof(char) * (tableDict->iPYCodeLength + 1));
            memset(recTemp->strCode, 0, sizeof(char) * (tableDict->iPYCodeLength + 1));
            strcpy(recTemp->strCode, strCode);
            recTemp->strHZ = (char*)fcitx_memory_pool_alloc(tableDict->pool, sizeof(char) * iTemp);
            strcpy(recTemp->strHZ, strHZ);

            if (!iVersion) {
                size = fread(&cTemp, sizeof(int8_t), 1, fpDict);
                CHECK_LOAD_TABLE_ERROR(1);
                recTemp->type = cTemp;
            }

            size = fcitx_utils_read_uint32(fpDict, &recTemp->iHit);
            CHECK_LOAD_TABLE_ERROR(1);
            size = fcitx_utils_read_uint32(fpDict, &recTemp->iIndex);
            CHECK_LOAD_TABLE_ERROR(1);
            if (recTemp->iIndex > tableDict->iTableIndex)
                tableDict->iTableIndex = recTemp->iIndex;

            /* 建立索引 */
            if (cChar != recTemp->strCode[0]) {
                cChar = recTemp->strCode[0];
                tableDict->recordIndex[iRecordIndex].cCode = cChar;
                tableDict->recordIndex[iRecordIndex].record = recTemp;
                iRecordIndex++;
            }
            /******************************************************************/
            /** 为单字生成一个表   */
            if (fcitx_utf8_strlen(recTemp->strHZ) == 1 && !IsIgnoreChar(tableDict, strCode[0]))
            {
                RECORD** tableSingleHZ = NULL;
                if (recTemp->type == RECORDTYPE_NORMAL)
                    tableSingleHZ = tableDict->tableSingleHZ;
                else if (recTemp->type == RECORDTYPE_CONSTRUCT)
                    tableSingleHZ = tableDict->tableSingleHZCons;

                if (tableSingleHZ) {
                    iTemp = CalHZIndex(recTemp->strHZ);
                    if (iTemp < SINGLE_HZ_COUNT) {
                        if (tableSingleHZ[iTemp]) {
                            if (strlen(strCode) > strlen(tableDict->tableSingleHZ[iTemp]->strCode))
                                tableSingleHZ[iTemp] = recTemp;
                        } else
                            tableSingleHZ[iTemp] = recTemp;
                    }
                }
            }

            if (recTemp->type == RECORDTYPE_PINYIN)
                tableDict->bHasPinyin = true;

            if (recTemp->type == RECORDTYPE_PROMPT && strlen(recTemp->strCode) == 1)
                tableDict->promptCode[(uint8_t) recTemp->strCode[0]] = recTemp;

            tableDict->currentRecord->next = recTemp;
            recTemp->prev = tableDict->currentRecord;
            tableDict->currentRecord = recTemp;
        }
        if (strHZ) {
            free(strHZ);
            strHZ = NULL;
        }

        tableDict->currentRecord->next = tableDict->recordHead;
        tableDict->recordHead->prev = tableDict->currentRecord;

table_load_error:
        fclose(fpDict);
        if (error) {
            fcitx_memory_pool_destroy(tableDict->pool);
            tableDict->pool = NULL;
            reload++;
        } else {
            break;
        }
    } while(reload < 2);

    if (!tableDict->pool)
        return false;

    FcitxLog(DEBUG, _("Load Table Dict OK"));

    //读取相应的特殊符号表
    fpDict = FcitxXDGGetFileWithPrefix("table", tableMetaData->strSymbolFile, "r", NULL);

    if (fpDict) {
        tableDict->iFH = fcitx_utils_calculate_record_number(fpDict);
        tableDict->fh = (FH*)fcitx_memory_pool_alloc(tableDict->pool, sizeof(FH) * tableDict->iFH);

        char* strBuf = NULL;
        size_t bufLen = 0;
        for (i = 0; i < tableDict->iFH; i++) {
            if (getline(&strBuf, &bufLen, fpDict) == -1)
                break;

            if (!fcitx_utf8_check_string(strBuf))
                break;

            if (fcitx_utf8_strlen(strBuf) > FH_MAX_LENGTH)
                break;

            strcpy(tableDict->fh[i].strFH, strBuf);
        }
        fcitx_utils_free(strBuf);
        tableDict->iFH = i;

        fclose(fpDict);
    }

    tableDict->strNewPhraseCode = (char*)fcitx_memory_pool_alloc(tableDict->pool, sizeof(char) * (tableDict->iCodeLength + 1));
    tableDict->strNewPhraseCode[tableDict->iCodeLength] = '\0';

    tableDict->iAutoPhrase = 0;
    if (tableMetaData->bAutoPhrase) {
        tableDict->autoPhrase = (AUTOPHRASE*)fcitx_memory_pool_alloc(tableDict->pool, sizeof(AUTOPHRASE) * AUTO_PHRASE_COUNT);

        //读取上次保存的自动词组信息
        FcitxLog(DEBUG, _("Loading Autophrase."));

        char *temppath;
        fcitx_utils_alloc_cat_str(temppath, tableMetaData->uniqueName,
                                  "_LastAutoPhrase.tmp");
        fpDict = FcitxXDGGetFileWithPrefix("table", temppath, "r", NULL);
        free(temppath);
        i = 0;
        if (fpDict) {
            size_t size = fcitx_utils_read_int32(fpDict, &tableDict->iAutoPhrase);
            if (size == 1) {
                for (; i < tableDict->iAutoPhrase; i++) {
                    tableDict->autoPhrase[i].strCode = (char*)fcitx_memory_pool_alloc(tableDict->pool, sizeof(char) * (tableDict->iCodeLength + 1));
                    tableDict->autoPhrase[i].strHZ = (char*)fcitx_memory_pool_alloc(tableDict->pool, sizeof(char) * (PHRASE_MAX_LENGTH * UTF8_MAX_LENGTH + 1));
                    size = fread(tableDict->autoPhrase[i].strCode, tableDict->iCodeLength + 1, 1, fpDict);
                    if (size != 1) {
                        tableDict->iAutoPhrase = i;
                        break;
                    }
                    size = fread(tableDict->autoPhrase[i].strHZ, PHRASE_MAX_LENGTH * UTF8_MAX_LENGTH + 1, 1, fpDict);
                    tableDict->autoPhrase[i].strHZ[PHRASE_MAX_LENGTH * UTF8_MAX_LENGTH] = 0;
                    if (size != 1 || !fcitx_utf8_check_string(tableDict->autoPhrase[i].strHZ)) {
                        tableDict->iAutoPhrase = i;
                        break;
                    }
                    size = fcitx_utils_read_uint32(fpDict, &iTempCount);
                    if (size != 1) {
                        tableDict->iAutoPhrase = i;
                        break;
                    }

                    tableDict->autoPhrase[i].iSelected = iTempCount;
                    if (i == AUTO_PHRASE_COUNT - 1)
                        tableDict->autoPhrase[i].next = &tableDict->autoPhrase[0];
                    else
                        tableDict->autoPhrase[i].next = &tableDict->autoPhrase[i + 1];
                }
            }
            fclose(fpDict);
        }

        for (; i < AUTO_PHRASE_COUNT; i++) {
            tableDict->autoPhrase[i].strCode = (char*)fcitx_memory_pool_alloc(tableDict->pool, sizeof(char) * (tableDict->iCodeLength + 1));
            tableDict->autoPhrase[i].strHZ = (char*)fcitx_memory_pool_alloc(tableDict->pool, sizeof(char) * (PHRASE_MAX_LENGTH * UTF8_MAX_LENGTH + 1));
            tableDict->autoPhrase[i].iSelected = 0;
            if (i == AUTO_PHRASE_COUNT - 1)
                tableDict->autoPhrase[i].next = &tableDict->autoPhrase[0];
            else
                tableDict->autoPhrase[i].next = &tableDict->autoPhrase[i + 1];
        }

        if (i == AUTO_PHRASE_COUNT)
            tableDict->insertPoint = &tableDict->autoPhrase[0];
        else
            tableDict->insertPoint = &tableDict->autoPhrase[i - 1];

        FcitxLog(DEBUG, _("Load Autophrase OK"));
    } else
        tableDict->autoPhrase = (AUTOPHRASE *) NULL;

    return true;
}
Beispiel #11
0
int main(int argc, char* argv[])
{
    char* localedir = fcitx_utils_get_fcitx_path("localedir");
    setlocale(LC_ALL, "");
    bindtextdomain("fcitx", localedir);
    free(localedir);
    bind_textdomain_codeset("fcitx", "UTF-8");
    textdomain("fcitx");

    FcitxLogSetLevel(FCITX_NONE);

    int c;
    char* addonList = NULL, *sandboxDirectory = NULL;
    char *buf = NULL, *buf1 = NULL;
    FILE* fp = NULL;
    char* enableAddon = NULL;
    char* imname = NULL;
    int ret = 1;
    int fd = -1;
    while ((c = getopt(argc, argv, "d:i:h")) != EOF) {
        switch (c) {
            case 'i':
                imname = strdup(optarg);
                break;
            case 'd':
                sandboxDirectory = strdup(optarg);
                break;
            case 'h':
            default:
                goto option_error_end;
        }
    }

    /* processs [addon list] */
    if (optind >= argc)
        goto option_error_end;
    addonList = strdup(argv[optind]);

    /* script file */
    if (optind + 1 < argc) {
        fp = fopen(argv[optind + 1], "rt");
    }
    else {
        fp = stdin;
    }
    if (!fp) {
        goto option_error_end;
    }

    if (!addonList) {
        goto option_error_end;
    }

    sem_t sem;
    sem_init(&sem, 0, 0);
    asprintf(&enableAddon, "fcitx-simple-module,fcitx-simple-frontend,%s", addonList);

    /* reset optind, since FcitxInstanceCreatePause will use getopt again */
    optind = 1;

    char* args[] = {
        argv[0],
        "-D",
        "--disable",
        "all",
        "--enable",
        enableAddon,
        "--ui",
        "fcitx-simple-ui"
    };

    char temp[] = "/tmp/fcitx_sandbox_XXXXXX";
    if (sandboxDirectory) {
        setenv("XDG_CONFIG_HOME", sandboxDirectory, 1);
    } else {
        /*
         * we make a file on purpose, since XDG_CONFIG_HOME should be a directory
         * hence this will prevent every write operation under XDG_CONFIG_HOME
         */
        fd = mkstemp(temp);
        if (fd == -1) {
            setenv("XDG_CONFIG_HOME", "/", 1);
        }
        else {
            close(fd);
            setenv("XDG_CONFIG_HOME", temp, 1);
        }
    }

    instance = FcitxInstanceCreatePause(&sem, 8, args, -1);
    if (sem_trywait(&sem) == 0)
        goto option_error_end;

    FcitxSimpleInit(instance, TestbedCallback, NULL);
    FcitxInstanceStart(instance);
    size_t len = 0;

    if (imname) {
        FcitxSimpleSetCurrentIM(instance, imname);
    }
    while (getline(&buf, &len, fp) != -1) {
        fcitx_utils_free(buf1);
        buf1 = fcitx_utils_trim(buf);

        FcitxKeySym sym = FcitxKey_None;
        unsigned int state = 0;
        FcitxHotkeyParseKey(buf1, &sym, &state);

        if (FcitxSimpleSendKeyEvent(instance, false, sym, state, 0) == 0) {
            fprintf(stderr, "FORWARD:%s\n", buf1);
        }

        usleep(1000);
    }

    FcitxSimpleEnd(instance);
    FcitxInstanceWaitForEnd(instance);
    ret = 0;
option_error_end:
    if (fd >= 0)
        unlink(temp);

    if (fp)
        fclose(fp);

    if (ret)
        usage();

    fcitx_utils_free(imname);
    fcitx_utils_free(buf);
    fcitx_utils_free(buf1);
    fcitx_utils_free(enableAddon);
    fcitx_utils_free(addonList);
    fcitx_utils_free(sandboxDirectory);
    return ret;
}