void LoadAutoEng(FcitxAutoEngState* autoEngState) { FILE *fp; char *buf = NULL; size_t length = 0; LoadAutoEngConfig(&autoEngState->config); fp = FcitxXDGGetFileWithPrefix("data", "AutoEng.dat", "r", NULL); if (!fp) return; utarray_new(autoEngState->autoEng, &autoeng_icd); AUTO_ENG autoeng; while (getline(&buf, &length, fp) != -1) { char* line = fcitx_utils_trim(buf); if (strlen(line) > MAX_AUTO_TO_ENG) FcitxLog(WARNING, _("Too long item for AutoEng")); strncpy(autoeng.str, line, MAX_AUTO_TO_ENG); free(line); autoeng.str[MAX_AUTO_TO_ENG] = '\0'; utarray_push_back(autoEngState->autoEng, &autoeng); } free(buf); fclose(fp); }
void _fcitx_compose_table_parse_include(FcitxComposeTable* table, const char* line) { // Parse something that looks like: // include "/usr/share/X11/locale/en_US.UTF-8/Compose" char* p = strchr(line + strlen("include"), '"'); if (!p) { return; } char* trimLine = fcitx_utils_trim(p); size_t l = strlen(trimLine); if (l > 0 && trimLine[l - 1] == '\"' ) { trimLine[l - 1] = '\0'; char* result; result = fcitx_utils_string_replace(trimLine, "%H", getenv("HOME"), true); if (result) { free(trimLine); trimLine = result; } result = fcitx_utils_string_replace(trimLine, "%L", table->locale, true); if (result) { free(trimLine); trimLine = result; } result = fcitx_utils_string_replace(trimLine, "%S", table->systemComposeDir, true); if (result) { free(trimLine); trimLine = result; } _fcitx_compose_table_process_file(table, trimLine); } free(trimLine); }
/** * 加载快速输入词典 * @param void * @return void * @note 快速输入是在;的行为定义为2,并且输入;以后才可以使用的。 * 加载快速输入词典.如:输入“zg”就直接出现“中华人民共和国”等等。 * 文件中每一行数据的定义为:<字符组合> <短语> * 如:“zg 中华人民共和国” */ void LoadQuickPhrase(QuickPhraseState * qpstate) { FILE *fp; char *buf = NULL; size_t len = 0; char *buf1 = NULL; QUICK_PHRASE tempQuickPhrase; qpstate->uQuickPhraseCount = 0; fp = FcitxXDGGetFileWithPrefix("data", "QuickPhrase.mb", "r", NULL); if (!fp) return; // 这儿的处理比较简单。因为是单索引对单值。 // 应该注意的是,它在内存中是以单链表保存的。 utarray_new(qpstate->quickPhrases, &qp_icd); while (getline(&buf, &len, fp) != -1) { if (buf1) free(buf1); buf1 = fcitx_utils_trim(buf); char *p = buf1; while (*p && !isspace(*p)) p ++; if (*p == '\0') continue; while (isspace(*p)) { *p = '\0'; p ++; } if (strlen(buf1) >= QUICKPHRASE_CODE_LEN) continue; if (strlen(p) >= QUICKPHRASE_PHRASE_LEN * UTF8_MAX_LENGTH) continue; strcpy(tempQuickPhrase.strCode, buf1); strcpy(tempQuickPhrase.strPhrase, p); utarray_push_back(qpstate->quickPhrases, &tempQuickPhrase); } if (buf) free(buf); if (buf1) free(buf1); if (qpstate->quickPhrases) { utarray_sort(qpstate->quickPhrases, PhraseCmp); } fclose(fp); }
FCITX_EXPORT_API void FcitxHotkeySetKey(const char *str, FcitxHotkey * hotkey) { char *p; char *strKey; int i = 0, j = 0, k; char* strKeys = fcitx_utils_trim(str); p = strKeys; for (k = 0; k < 2; k++) { FcitxKeySym sym; unsigned int state; i = 0; while (p[i] != ' ' && p[i] != '\0') i++; strKey = strndup(p, i); strKey[i] = '\0'; if (FcitxHotkeyParseKey(strKey, &sym, &state)) { hotkey[j].sym = sym; hotkey[j].state = state; hotkey[j].desc = fcitx_utils_trim(strKey); j ++; } free(strKey); if (p[i] == '\0') break; p = &p[i + 1]; } for (; j < 2; j++) { hotkey[j].sym = 0; hotkey[j].state = 0; hotkey[j].desc = NULL; } free(strKeys); }
void QQParseKey(FcitxCloudPinyin* cloudpinyin, CurlQueue* queue) { char* str = fcitx_utils_trim(queue->str); const char* ime_patch_key = "{\"key\":\""; if (strncmp(str, ime_patch_key, strlen(ime_patch_key)) == 0) { if (sscanf(str,"{\"key\":\"%32s\",\"ret\":\"suc\"}", cloudpinyin->key) > 0) { cloudpinyin->initialized = true; cloudpinyin->key[QQ_KEY_LENGTH] = '\0'; } } free(str); }
void SogouParseKey(FcitxCloudPinyin* cloudpinyin, CurlQueue* queue) { char* str = fcitx_utils_trim(queue->str); const char* ime_patch_key = "ime_patch_key = \""; size_t len = strlen(str); if (len == SOGOU_KEY_LENGTH + strlen(ime_patch_key) + 1 && strncmp(str, ime_patch_key, strlen(ime_patch_key)) == 0 && str[len - 1] == '\"') { sscanf(str,"ime_patch_key = \"%s\"", cloudpinyin->key); cloudpinyin->initialized = true; cloudpinyin->key[SOGOU_KEY_LENGTH] = '\0'; } free(str); }
void _fcitx_compose_table_read_locale_mappings(FcitxComposeTable* table) { char* mappingsDir; fcitx_utils_alloc_cat_str(mappingsDir, table->systemComposeDir, "/compose.dir"); FILE* mappings = fopen(mappingsDir, "r"); if (mappings) { char* line = NULL; size_t bufSize = 0; while (getline(&line, &bufSize, mappings) != -1) { char* trimLine = fcitx_utils_trim(line); if (trimLine[0] != '#' && trimLine[0] != '\0' && fcitx_utils_islower(trimLine[0])) { FcitxStringList* list = fcitx_utils_string_split_full(trimLine, FCITX_WHITESPACE, false); if (utarray_len(list) >= 2) { char **plocale = utarray_eltptr(list, 1); char **pitem = utarray_eltptr(list, 0); char *locale = *plocale, *item = *pitem; // we steal this string from list *pitem = NULL; size_t itemLen = strlen(item); if (itemLen > 0 && item[itemLen - 1] == ':') { item[itemLen - 1] = '\0'; } char* p = locale; while(*p) { *p = fcitx_utils_toupper(*p); p++; } fcitx_dict_insert_by_str(table->localeToTable, locale, item, true); } fcitx_utils_string_list_free(list); } free(trimLine); } free(line); fclose(mappings); } free(mappingsDir); }
FCITX_EXPORT_API char* fcitx_utils_get_process_name() { #if defined(__linux__) const size_t bufsize = 4096; char buf[bufsize]; char *result = NULL; ssize_t len; if ((len = readlink("/proc/self/exe", buf, bufsize)) != -1) { buf[len] = '\0'; result = basename(buf); } else { buf[0] = '\0'; result = buf; } return fcitx_utils_trim(result); #elif defined(LIBKVM_FOUND) kvm_t *vm = kvm_open(0, "/dev/null", 0, O_RDONLY, NULL); if (vm == 0) return strdup(""); int cnt; int mypid = getpid(); struct kinfo_proc * kp = kvm_getprocs(vm, KERN_PROC_PID, mypid, &cnt); if ((cnt != 1) || (kp == 0)) return strdup(""); int i; for (i = 0; i < cnt; i++) if (kp->ki_pid == mypid) break; char* result = NULL; if (i != cnt) result = strdup(kp->ki_comm); else result = strdup(""); kvm_close(vm); return result; #else return strdup(""); #endif }
void RulesHandlerCharacters(void *ctx, const xmlChar *ch, int len) { FcitxXkbRulesHandler* ruleshandler = (FcitxXkbRulesHandler*) ctx; FcitxXkbRules* rules = ruleshandler->rules; char* temp = strndup(XMLCHAR_CAST ch, len); char* trimmed = fcitx_utils_trim(temp); free(temp); if ( strlen(trimmed) != 0 ) { char* strPath = fcitx_utils_join_string_list(ruleshandler->path, '/'); FcitxXkbLayoutInfo* layoutInfo = (FcitxXkbLayoutInfo*) utarray_back(rules->layoutInfos); FcitxXkbModelInfo* modelInfo = (FcitxXkbModelInfo*) utarray_back(rules->modelInfos); FcitxXkbOptionGroupInfo* optionGroupInfo = (FcitxXkbOptionGroupInfo*) utarray_back(rules->optionGroupInfos); if ( StringEndsWith(strPath, "layoutList/layout/configItem/name") ) { if ( layoutInfo != NULL ) layoutInfo->name = strdup(trimmed); } else if ( StringEndsWith(strPath, "layoutList/layout/configItem/description") ) { layoutInfo->description = strdup(trimmed); } else if ( StringEndsWith(strPath, "layoutList/layout/configItem/languageList/iso639Id") ) { utarray_push_back(layoutInfo->languages, &trimmed); } else if ( StringEndsWith(strPath, "layoutList/layout/variantList/variant/configItem/name") ) { FcitxXkbVariantInfo* variantInfo = (FcitxXkbVariantInfo*) utarray_back(layoutInfo->variantInfos); variantInfo->name = strdup(trimmed); } else if ( StringEndsWith(strPath, "layoutList/layout/variantList/variant/configItem/description") ) { FcitxXkbVariantInfo* variantInfo = (FcitxXkbVariantInfo*) utarray_back(layoutInfo->variantInfos); fcitx_utils_free(variantInfo->description); variantInfo->description = strdup(trimmed); } else if ( StringEndsWith(strPath, "layoutList/layout/variantList/variant/configItem/languageList/iso639Id") ) { FcitxXkbVariantInfo* variantInfo = (FcitxXkbVariantInfo*) utarray_back(layoutInfo->variantInfos); utarray_push_back(variantInfo->languages, &trimmed); } else if ( StringEndsWith(strPath, "modelList/model/configItem/name") ) { modelInfo->name = strdup(trimmed); } else if ( StringEndsWith(strPath, "modelList/model/configItem/description") ) { modelInfo->description = strdup(trimmed); } else if ( StringEndsWith(strPath, "modelList/model/configItem/vendor") ) { modelInfo->vendor = strdup(trimmed); } else if ( StringEndsWith(strPath, "optionList/group/configItem/name") ) { optionGroupInfo->name = strdup(trimmed); } else if ( StringEndsWith(strPath, "optionList/group/configItem/description") ) { optionGroupInfo->description = strdup(trimmed); } else if ( StringEndsWith(strPath, "optionList/group/option/configItem/name") ) { FcitxXkbOptionInfo* optionInfo = (FcitxXkbOptionInfo*) utarray_back(optionGroupInfo->optionInfos); optionInfo->name = strdup(trimmed); } else if ( StringEndsWith(strPath, "optionList/group/option/configItem/description") ) { FcitxXkbOptionInfo* optionInfo = (FcitxXkbOptionInfo*) utarray_back(optionGroupInfo->optionInfos); fcitx_utils_free(optionInfo->description); optionInfo->description = strdup(trimmed); } free(strPath); } free(trimmed); }
boolean FcitxKkcLoadDictionary(FcitxKkc* kkc) { FILE* fp = FcitxXDGGetFileWithPrefix("kkc", "dictionary_list", "r", NULL); if (!fp) { return false; } UT_array dictionaries; utarray_init(&dictionaries, &dict_icd); char *buf = NULL; size_t len = 0; char *trimmed = NULL; while (getline(&buf, &len, fp) != -1) { if (trimmed) free(trimmed); trimmed = fcitx_utils_trim(buf); UT_array* list = fcitx_utils_split_string(trimmed, ','); do { if (utarray_len(list) < 3) { break; } boolean typeFile = false; char* path = NULL; int mode = 0; utarray_foreach(item, list, char*) { char* key = *item; char* value = strchr(*item, '='); if (!value) continue; *value = '\0'; value++; if (strcmp(key, "type") == 0) { if (strcmp(value, "file") == 0) { typeFile = true; } } else if (strcmp(key, "file") == 0) { path = value; } else if (strcmp(key, "mode") == 0) { if (strcmp(value, "readonly") == 0) { mode = 1; } else if (strcmp(value, "readwrite") == 0) { mode = 2; } } } if (mode == 0 || path == NULL || !typeFile) { break; } if (mode == 1) { KkcSystemSegmentDictionary* dict = kkc_system_segment_dictionary_new(path, "EUC-JP", NULL); if (dict) { utarray_push_back(&dictionaries, &dict); } } else { char* needfree = NULL; char* realpath = NULL; if (strncmp(path, "$FCITX_CONFIG_DIR/", strlen("$FCITX_CONFIG_DIR/")) == 0) { FcitxXDGGetFileUserWithPrefix("", path + strlen("$FCITX_CONFIG_DIR/"), NULL, &needfree); realpath = needfree; } else { realpath = path; } KkcUserDictionary* userdict = kkc_user_dictionary_new(realpath, NULL); if (needfree) { free(needfree); } if (userdict) { utarray_push_back(&dictionaries, &userdict); } } } while(0); fcitx_utils_free_string_list(list); }
int main(int argc, char *argv[]) { FILE *fpDict, *fpNew; RECORD *temp, *head, *newRec, *current; uint32_t s = 0; int i; uint32_t iTemp; char *pstr = 0; char strTemp[10]; unsigned char bRule; RULE *rule = NULL; unsigned int l; unsigned char iCodeLength = 0; unsigned char iPYCodeLength = 0; int8_t type; if (argc != 3) { printf("\nUsage: txt2mb <Source File> <IM File>\n\n"); exit(1); } fpDict = fopen(argv[1], "r"); if (!fpDict) { printf("\nCannot read source file!\n\n"); exit(2); } head = (RECORD *) malloc(sizeof(RECORD)); head->next = head; head->prev = head; current = head; bRule = 0; l = 0; char* buf = NULL, *buf1 = NULL; size_t len; for (;;) { l++; if (getline(&buf, &len, fpDict) == -1) break; i = strlen(buf) - 1; while ((i >= 0) && (buf[i] == ' ' || buf[i] == '\n' || buf[i] == '\r')) buf[i--] = '\0'; pstr = buf; if (*pstr == ' ') pstr++; if (pstr[0] == '#') continue; if (CHECK_OPTION(pstr, STR_KEYCODE)) { pstr += ADD_LENGTH(pstr, STR_KEYCODE); strcpy(strInputCode, pstr); } else if (CHECK_OPTION(pstr, STR_CODELEN)) { pstr += ADD_LENGTH(pstr, STR_CODELEN); iCodeLength = atoi(pstr); if (iCodeLength > MAX_CODE_LENGTH) { iCodeLength = MAX_CODE_LENGTH; printf("Max Code Length is %d\n", MAX_CODE_LENGTH); } } else if (CHECK_OPTION(pstr, STR_IGNORECHAR)) { pstr += ADD_LENGTH(pstr, STR_IGNORECHAR); strcpy(strIgnoreChars, pstr); } else if (CHECK_OPTION(pstr, STR_PINYIN)) { pstr += ADD_LENGTH(pstr, STR_PINYIN); while (*pstr == ' ' && *pstr != '\0') pstr++; cPinyinKey = *pstr; } else if (CHECK_OPTION(pstr, STR_PROMPT)) { pstr += ADD_LENGTH(pstr, STR_PROMPT); while (*pstr == ' ' && *pstr != '\0') pstr++; cPromptKey = *pstr; } else if (CHECK_OPTION(pstr, STR_CONSTRUCTPHRASE)) { pstr += ADD_LENGTH(pstr, STR_CONSTRUCTPHRASE); while (*pstr == ' ' && *pstr != '\0') pstr++; cPhraseKey = *pstr; } else if (CHECK_OPTION(pstr, STR_PINYINLEN)) { pstr += ADD_LENGTH(pstr, STR_PINYINLEN); iPYCodeLength = atoi(pstr); } else if (CHECK_OPTION(pstr, STR_DATA)) break; else if (CHECK_OPTION(pstr, STR_RULE)) { bRule = 1; break; } } if (iCodeLength <= 0 || !strInputCode[0]) { printf("Source File Format Error!\n"); exit(1); } if (bRule) { /* * 组词规则数应该比键码长度小1 */ rule = (RULE *) malloc(sizeof(RULE) * (iCodeLength - 1)); for (iTemp = 0; iTemp < (iCodeLength - 1); iTemp++) { l++; if (getline(&buf, &len, fpDict) == -1) break; rule[iTemp].rule = (RULE_RULE *) malloc(sizeof(RULE_RULE) * iCodeLength); i = strlen(buf) - 1; while ((i >= 0) && (buf[i] == ' ' || buf[i] == '\n' || buf[i] == '\r')) buf[i--] = '\0'; pstr = buf; if (*pstr == ' ') pstr++; if (pstr[0] == '#') continue; if (CHECK_OPTION(pstr, STR_DATA)) break; switch (*pstr) { case 'e': case 'E': rule[iTemp].iFlag = 0; break; case 'a': case 'A': rule[iTemp].iFlag = 1; break; default: printf("2 Phrase rules are not suitable!\n"); printf("\t\t%s\n", buf); exit(1); } pstr++; char* p = pstr; while (*p && *p != '=') p++; if (!(*p)) { printf("3 Phrase rules are not suitable!\n"); printf("\t\t%s\n", buf); exit(1); } strncpy(strTemp, pstr, p - pstr); strTemp[p - pstr] = '\0'; rule[iTemp].iWords = atoi(strTemp); p++; for (i = 0; i < iCodeLength; i++) { while (*p == ' ') p++; switch (*p) { case 'p': case 'P': rule[iTemp].rule[i].iFlag = 1; break; case 'n': case 'N': rule[iTemp].rule[i].iFlag = 0; break; default: printf("4 Phrase rules are not suitable!\n"); printf("\t\t%s\n", buf); exit(1); } p++; rule[iTemp].rule[i].iWhich = *p++ - '0'; rule[iTemp].rule[i].iIndex = *p++ - '0'; while (*p == ' ') p++; if (i != (iCodeLength - 1)) { if (*p != '+') { printf("5 Phrase rules are not suitable!\n"); printf("\t\t%s %d\n", buf, iCodeLength); exit(1); } p++; } } } if (iTemp != iCodeLength - 1) { printf("6 Phrase rules are not suitable!\n"); exit(1); } for (iTemp = 0; iTemp < (iCodeLength - 1); iTemp++) { l++; if (getline(&buf, &len, fpDict) == -1) break; i = strlen(buf) - 1; while ((i >= 0) && (buf[i] == ' ' || buf[i] == '\n' || buf[i] == '\r')) buf[i--] = '\0'; pstr = buf; if (*pstr == ' ') pstr++; if (pstr[0] == '#') continue; if (CHECK_OPTION(pstr, STR_DATA)) break; } } if (iPYCodeLength < iCodeLength) iPYCodeLength = iCodeLength; if (!CHECK_OPTION(pstr, STR_DATA)) { printf("Source File Format Error!\n"); exit(1); } while (getline(&buf, &len, fpDict) != -1) { l++; if (buf1) free(buf1); buf1 = fcitx_utils_trim(buf); char *p = buf1; while (*p && !isspace(*p)) p ++; if (*p == '\0') continue; while (isspace(*p)) { *p = '\0'; p ++; } char* strHZ = p; if (!IsValidCode(buf1[0])) { printf("Invalid Format: Line-%d %s %s\n", l, buf1, strHZ); exit(1); } if (((buf1[0] != cPinyinKey) && (strlen(buf1) > iCodeLength)) || ((buf1[0] == cPinyinKey) && (strlen(buf1) > (iPYCodeLength + 1))) || ((buf1[0] == cPhraseKey) && (strlen(buf1) > (iCodeLength + 1))) || ((buf1[0] == cPromptKey) && (strlen(buf1) > (iPYCodeLength + 1))) ) { printf("Delete: %s %s, Too long\n", buf1, strHZ); continue; } size_t hzLen = fcitx_utf8_strlen(strHZ); if (buf1[0] == cPhraseKey && hzLen != 1) { printf("Delete: %s %s, Too long\n", buf1, strHZ); continue; } type = RECORDTYPE_NORMAL; pstr = buf1; if (buf1[0] == cPinyinKey) { pstr ++; type = RECORDTYPE_PINYIN; } else if (buf1[0] == cPhraseKey) { pstr ++; type = RECORDTYPE_CONSTRUCT; } else if (buf1[0] == cPromptKey) { pstr ++; type = RECORDTYPE_PROMPT; } //查找是否重复 temp = current; if (temp != head) { if (strcmp(temp->strCode, pstr) >= 0) { while (temp != head && strcmp(temp->strCode, pstr) >= 0) { if (!strcmp(temp->strHZ, strHZ) && !strcmp(temp->strCode, pstr) && temp->type == type) { printf("Delete: %s %s\n", pstr, strHZ); goto _next; } temp = temp->prev; } if (temp == head) temp = temp->next; while (temp != head && strcmp(temp->strCode, pstr) <= 0) temp = temp->next; } else { while (temp != head && strcmp(temp->strCode, pstr) <= 0) { if (!strcmp(temp->strHZ, strHZ) && !strcmp(temp->strCode, pstr) && temp->type == type) { printf("Delete: %s %s\n", pstr, strHZ); goto _next; } temp = temp->next; } } } //插在temp的前面 newRec = (RECORD *) fcitx_utils_malloc0(sizeof(RECORD)); newRec->strCode = (char *) fcitx_utils_malloc0(sizeof(char) * (iPYCodeLength + 1)); newRec->strHZ = (char *) fcitx_utils_malloc0(sizeof(char) * strlen(strHZ) + 1); strcpy(newRec->strCode, pstr); strcpy(newRec->strHZ, strHZ); newRec->type = type; newRec->iHit = 0; newRec->iIndex = 0; temp->prev->next = newRec; newRec->next = temp; newRec->prev = temp->prev; temp->prev = newRec; current = newRec; s++; _next: continue; } if (buf) free(buf); if (buf1) free(buf1); fclose(fpDict); printf("\nReading %d records.\n\n", s); fpNew = fopen(argv[2], "w"); if (!fpNew) { printf("\nCannot create target file!\n\n"); exit(3); } int8_t iInternalVersion = INTERNAL_VERSION; //写入版本号--如果第一个字为0,表示后面那个字节为版本号 fcitx_utils_write_uint32(fpNew, 0); fwrite(&iInternalVersion, sizeof(int8_t), 1, fpNew); iTemp = (uint32_t)strlen(strInputCode); fcitx_utils_write_uint32(fpNew, iTemp); fwrite(strInputCode, sizeof(char), iTemp + 1, fpNew); fwrite(&iCodeLength, sizeof(unsigned char), 1, fpNew); fwrite(&iPYCodeLength, sizeof(unsigned char), 1, fpNew); iTemp = (uint32_t)strlen(strIgnoreChars); fcitx_utils_write_uint32(fpNew, iTemp); fwrite(strIgnoreChars, sizeof(char), iTemp + 1, fpNew); fwrite(&bRule, sizeof(unsigned char), 1, fpNew); if (bRule) { for (i = 0; i < iCodeLength - 1; i++) { fwrite(&(rule[i].iFlag), sizeof(unsigned char), 1, fpNew); fwrite(&(rule[i].iWords), sizeof(unsigned char), 1, fpNew); for (iTemp = 0; iTemp < iCodeLength; iTemp++) { fwrite(&(rule[i].rule[iTemp].iFlag), sizeof(unsigned char), 1, fpNew); fwrite(&(rule[i].rule[iTemp].iWhich), sizeof(unsigned char), 1, fpNew); fwrite(&(rule[i].rule[iTemp].iIndex), sizeof(unsigned char), 1, fpNew); } } } fcitx_utils_write_uint32(fpNew, s); current = head->next; while (current != head) { fwrite(current->strCode, sizeof(char), iPYCodeLength + 1, fpNew); s = strlen(current->strHZ) + 1; fcitx_utils_write_uint32(fpNew, s); fwrite(current->strHZ, sizeof(char), s, fpNew); fwrite(&(current->type), sizeof(int8_t), 1, fpNew); fcitx_utils_write_uint32(fpNew, current->iHit); fcitx_utils_write_uint32(fpNew, current->iIndex); current = current->next; } fclose(fpNew); return 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; }