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); }
FcitxYaTableInfo* FcitxYaTableGetAllCFG() { FcitxYaTableInfo* head = NULL,* prev = NULL,* cur = NULL; FcitxStringHashSet* configfiles = FcitxXDGGetFiles("yatable", NULL, ".conf"); HASH_FOREACH(file, configfiles, FcitxStringHashSet) { FcitxConfigFileDesc* cfgdesc = FcitxYaTableConfigDesc(); if(cfgdesc == NULL) continue; FILE* fcfg = FcitxXDGGetFileWithPrefix("yatable", file->name, "r", NULL); if(fcfg == NULL) continue; FcitxConfigFile* cfgfile = FcitxConfigParseConfigFileFp(fcfg, cfgdesc); cur = fcitx_utils_malloc0(sizeof(FcitxYaTableInfo)); cur->next = NULL; if(head == NULL) { head = cur; } else { prev->next = cur; } prev = cur; YaTableInfoConfigBind(&(cur->info), cfgfile, cfgdesc); FcitxConfigBindSync((FcitxGenericConfig*) &(cur->info)); FcitxConfigFreeConfigFile(cfgfile); fclose(fcfg); }
static int LoadLuaConfig(LuaModule *luamodule) { int count = 0; FcitxStringHashSet *sset = FcitxXDGGetFiles("lua", NULL, ".lua"); FcitxStringHashSet *str; for (str = sset; str != NULL;) { FcitxStringHashSet *tmp = str->hh.next; char *path; FILE *f = FcitxXDGGetFileWithPrefix("lua", str->name, "r", &path); if (f && path) { if (LoadExtension(luamodule, path)) { FcitxLog(INFO, "lua load extension file:%s", path); ++count; } else { FcitxLog(ERROR, "LoadExtension() failed"); } } if (f) { fclose(f); } if (path) { free(path); } HASH_DEL(sset, str); free(str->name); free(str); str = tmp; } return count; }
CharSelectData* CharSelectDataCreate() { CharSelectData* charselect = fcitx_utils_new(CharSelectData); do { FILE* fp = FcitxXDGGetFileWithPrefix("data", "charselectdata", "r", NULL); if (!fp) break; fseek(fp, 0, SEEK_END); long int size = ftell(fp); fseek(fp, 0, SEEK_SET); charselect->size = size; charselect->dataFile = fcitx_utils_malloc0(size); fread(charselect->dataFile, 1, size, fp); fclose(fp); CharSelectDataCreateIndex(charselect); return charselect; } while(0); free(charselect); return NULL; }
/** * 加载快速输入词典 * @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); }
void open_native_file(GtkButton *button, gpointer user_data) { FcitxSubConfigWidget* widget = (FcitxSubConfigWidget*) user_data; char *newpath = NULL; char* qtguiwrapper = fcitx_utils_get_fcitx_path_with_filename ("libdir", "fcitx/libexec/fcitx-qt-gui-wrapper"); if (qtguiwrapper) { gchar* argv[4]; argv[0] = qtguiwrapper; argv[1] = "--test"; argv[2] = widget->subconfig->nativepath; argv[3] = 0; int exit_status = 1; g_spawn_sync(NULL, argv, NULL, 0, NULL, NULL, NULL, NULL, &exit_status, NULL); if (exit_status == 0) { gchar* argv2[3]; argv2[0] = qtguiwrapper; argv2[1] = widget->subconfig->nativepath; argv2[2] = 0; g_spawn_async(NULL, argv2, NULL, 0, NULL, NULL, NULL, NULL); free(newpath); } g_free(qtguiwrapper); if (exit_status == 0) { return; } } if (g_hash_table_size(widget->subconfig->filelist) > 0) { GHashTableIter iter; g_hash_table_iter_init(&iter, widget->subconfig->filelist); gpointer key; if (g_hash_table_iter_next(&iter, &key, NULL)) { FILE* fp = FcitxXDGGetFileWithPrefix("", key, "r", &newpath); if (fp) fclose(fp); } } else { FILE* fp = FcitxXDGGetFileUserWithPrefix("", widget->subconfig->nativepath, "w", &newpath); if (fp) { g_hash_table_insert(widget->subconfig->filelist, widget->subconfig->nativepath, NULL); fclose(fp); } } if (newpath) { gchar* filename = newpath; gchar* argv[3]; argv[0] = "xdg-open"; argv[1] = filename; argv[2] = 0; g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL); free(newpath); } }
SkinImage* LoadImage(FcitxSkin* sc, const char* name, boolean fallback) { cairo_surface_t *png = NULL; SkinImage *image = NULL; HASH_FIND_STR(sc->imageTable, name, image); if (image != NULL) { return image; } if (strlen(name) > 0 && strcmp(name , "NONE") != 0) { char *skintype = strdup(*sc->skinType); char *filename; while (true) { char* buf = NULL; asprintf(&buf, "skin/%s", skintype); FILE* fp = FcitxXDGGetFileWithPrefix(buf, name, "r", &filename); free(buf); Bool flagNoFile = (fp == NULL); if (fp) { fclose(fp); png = cairo_image_surface_create_from_png(filename); break; } if (flagNoFile && (!fallback || strcmp(skintype, "default") == 0)) { png = NULL; break; } free(filename); free(skintype); skintype = strdup("default"); } free(filename); free(skintype); } if (png != NULL) { image = fcitx_utils_malloc0(sizeof(SkinImage)); image->name = strdup(name); image->image = png; HASH_ADD_KEYPTR(hh, sc->imageTable, image->name, strlen(image->name), image); return image; } return NULL; }
void DictModel::load() { FILE* fp = FcitxXDGGetFileWithPrefix("kkc", "dictionary_list", "r", NULL); if (!fp) { return; } QFile f; if (!f.open(fp, QIODevice::ReadOnly)) { fclose(fp); return; } load(f); f.close(); fclose(fp); }
/** * 该函数装载data/gbks2t.tab的简体转繁体的码表, * 然后按码表将GBK字符转换成GBK繁体字符。 * * WARNING: 该函数返回新分配内存字符串,请调用者 * 注意释放。 */ char *ConvertGBKTradition2Simple(FcitxChttrans* transState, const char *strHZ) { if (strHZ == NULL) return NULL; switch (transState->engine) { case ENGINE_OPENCC: #ifdef ENABLE_OPENCC do { if (transState->odt2s == NULL) { OpenCCInit(transState); if (transState->odt2s == NULL) { break; } } char * res = OpenCCConvert(transState->odt2s, strHZ, (size_t) - 1); if (!res || res == (char *) - 1) { return NULL; } return res; } while(0); #endif case ENGINE_NATIVE: { FILE *fp; char *ret; int i, len, ret_len; const char *ps; if (!transState->t2s_table) { char *strBuf = NULL; size_t bufLen = 0; fp = FcitxXDGGetFileWithPrefix("data", TABLE_GBKS2T, "r", NULL); if (!fp) { ret = (char *) malloc(sizeof(char) * (strlen(strHZ) + 1)); strcpy(ret, strHZ); return ret; } while (getline(&strBuf, &bufLen, fp) != -1) { simple2trad_t *t2s = NULL; char *ps; uint32_t wc; ps = fcitx_utf8_get_char(strBuf, &wc); HASH_FIND_INT(transState->s2t_table, &wc, t2s); if (t2s) { continue; } t2s = (simple2trad_t*) malloc(sizeof(simple2trad_t)); fcitx_utf8_get_char(ps, &wc); t2s->wc = wc; t2s->len = fcitx_utf8_char_len(strBuf); strncpy(t2s->str, strBuf, t2s->len); t2s->str[t2s->len] = '\0'; HASH_ADD_INT(transState->t2s_table, wc, t2s); } fcitx_utils_free(strBuf); } i = 0; len = fcitx_utf8_strlen(strHZ); ret_len = 0; ret = fcitx_utils_malloc0(UTF8_MAX_LENGTH * len + 1); ps = strHZ; ret[0] = '\0'; for (; i < len; ++i) { uint32_t wc; simple2trad_t *t2s = NULL; int chr_len = fcitx_utf8_char_len(ps); char *nps; nps = fcitx_utf8_get_char(ps , &wc); HASH_FIND_INT(transState->t2s_table, &wc, t2s); if (t2s) { strcat(ret, t2s->str); ret_len += t2s->len; } else { strncat(ret, ps, chr_len); ret_len += chr_len; } ps = nps; } ret[ret_len] = '\0'; return ret; } } return NULL; }
/** * 该函数装载data/gbks2t.tab的简体转繁体的码表, * 然后按码表将GBK字符转换成GBK繁体字符。 * * WARNING: 该函数返回新分配内存字符串,请调用者 * 注意释放。 */ char *ConvertGBKTradition2Simple(FcitxChttrans* transState, const char *strHZ) { if (strHZ == NULL) return NULL; switch (transState->engine) { case ENGINE_OPENCC: #ifdef _ENABLE_OPENCC { if (transState->odt2s == NULL) { transState->odt2s = opencc_open(OPENCC_DEFAULT_CONFIG_TRAD_TO_SIMP); if (transState->odt2s == NULL) { opencc_perror(_("OpenCC initialization error")); return NULL; } } char * res = opencc_convert_utf8(transState->odt2s, strHZ, (size_t) - 1); if (res == (char *) - 1) { opencc_perror(_("OpenCC error")); return NULL; } return res; } #endif case ENGINE_NATIVE: { FILE *fp; char *ret; int i, len, ret_len; char *strBuf = NULL; size_t bufLen = 0; const char *ps; if (!transState->t2s_table) { len = 0; fp = FcitxXDGGetFileWithPrefix("data", TABLE_GBKS2T, "r", NULL); if (!fp) { ret = (char *) malloc(sizeof(char) * (strlen(strHZ) + 1)); strcpy(ret, strHZ); return ret; } while (getline(&strBuf, &bufLen, fp) != -1) { simple2trad_t *t2s; char *ps; unsigned int wc; ps = fcitx_utf8_get_char(strBuf, &wc); t2s = (simple2trad_t*) malloc(sizeof(simple2trad_t)); fcitx_utf8_get_char(ps, &wc); t2s->wc = wc; t2s->len = fcitx_utf8_char_len(strBuf); strncpy(t2s->str, strBuf, t2s->len); t2s->str[t2s->len] = '\0'; HASH_ADD_INT(transState->t2s_table, wc, t2s); } if (strBuf) free(strBuf); } i = 0; len = fcitx_utf8_strlen(strHZ); ret_len = 0; ret = (char *) fcitx_utils_malloc0(sizeof(char) * (UTF8_MAX_LENGTH * len + 1)); ps = strHZ; ret[0] = '\0'; for (; i < len; ++i) { unsigned int wc; simple2trad_t *t2s = NULL; int chr_len = fcitx_utf8_char_len(ps); char *nps; nps = fcitx_utf8_get_char(ps , &wc); HASH_FIND_INT(transState->t2s_table, &wc, t2s); if (t2s) { strcat(ret, t2s->str); ret_len += t2s->len; } else { strncat(ret, ps, chr_len); ret_len += chr_len; } ps = nps; } ret[ret_len] = '\0'; return ret; } } return NULL; }
static void fcitx_config_widget_setup_ui(FcitxConfigWidget *self) { FcitxConfigFileDesc* cfdesc = self->cfdesc; GtkWidget *cvbox = GTK_WIDGET(self); GtkWidget *configNotebook = gtk_notebook_new(); gtk_box_pack_start(GTK_BOX(cvbox), configNotebook, TRUE, TRUE, 0); if (cfdesc) { bindtextdomain(cfdesc->domain, LOCALEDIR); bind_textdomain_codeset(cfdesc->domain, "UTF-8"); FILE *fp; fp = FcitxXDGGetFileWithPrefix(self->prefix, self->name, "r", NULL); self->gconfig.configFile = FcitxConfigParseConfigFileFp(fp, cfdesc); FcitxConfigGroupDesc *cgdesc = NULL; FcitxConfigOptionDesc *codesc = NULL; for (cgdesc = cfdesc->groupsDesc; cgdesc != NULL; cgdesc = (FcitxConfigGroupDesc*)cgdesc->hh.next) { codesc = cgdesc->optionsDesc; if (codesc == NULL) continue; GtkWidget* hbox = gtk_hbox_new(FALSE, 0); GtkWidget *table = gtk_table_new(2, HASH_COUNT(codesc), FALSE); GtkWidget *plabel = gtk_label_new(D_(cfdesc->domain, cgdesc->groupName)); GtkWidget *scrollwnd = gtk_scrolled_window_new(NULL, NULL); gtk_container_set_border_width(GTK_CONTAINER(table), 0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwnd), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollwnd), table); gtk_box_pack_start(GTK_BOX(hbox), scrollwnd, TRUE, TRUE, 0); gtk_notebook_append_page(GTK_NOTEBOOK(configNotebook), hbox, plabel); int i = 0; for (; codesc != NULL; codesc = (FcitxConfigOptionDesc*)codesc->hh.next, i++) { const char *s; if (codesc->desc && strlen(codesc->desc) != 0) s = D_(cfdesc->domain, codesc->desc); else s = D_(cfdesc->domain, codesc->optionName); GtkWidget *inputWidget = NULL; void *argument = NULL; switch (codesc->type) { case T_Integer: inputWidget = gtk_spin_button_new_with_range(-1.0, 10000.0, 1.0); argument = inputWidget; break; case T_Color: inputWidget = gtk_color_button_new(); argument = inputWidget; break; case T_Boolean: inputWidget = gtk_check_button_new(); argument = inputWidget; break; case T_Font: { inputWidget = gtk_hbox_new(FALSE, 0); argument = gtk_font_button_new(); GtkWidget *button = gtk_button_new_with_label(_("Clear font setting")); gtk_box_pack_start(GTK_BOX(inputWidget), argument, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(inputWidget), button, FALSE, FALSE, 0); gtk_font_button_set_use_size(GTK_FONT_BUTTON(argument), FALSE); gtk_font_button_set_show_size(GTK_FONT_BUTTON(argument), FALSE); g_signal_connect(G_OBJECT(button), "clicked", (GCallback) set_none_font_clicked, argument); } break; case T_Enum: { int i; FcitxConfigEnum *e = &codesc->configEnum; #if GTK_CHECK_VERSION(2, 24, 0) inputWidget = gtk_combo_box_text_new(); for (i = 0; i < e->enumCount; i ++) { gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(inputWidget), D_(cfdesc->domain, e->enumDesc[i])); } #else inputWidget = gtk_combo_box_new_text(); for (i = 0; i < e->enumCount; i ++) { gtk_combo_box_append_text(GTK_COMBO_BOX(inputWidget), D_(cfdesc->domain, e->enumDesc[i])); } #endif argument = inputWidget; } break; case T_Hotkey: { GtkWidget *button[2]; button[0] = keygrab_button_new(); button[1] = keygrab_button_new(); inputWidget = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(inputWidget), button[0], FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(inputWidget), button[1], FALSE, TRUE, 0); argument = g_array_new(FALSE, FALSE, sizeof(void*)); g_array_append_val(argument, button[0]); g_array_append_val(argument, button[1]); } break; case T_File: case T_Char: case T_String: inputWidget = gtk_entry_new(); argument = inputWidget; break; default: break; } if (inputWidget) { GtkWidget* label = gtk_label_new(s); g_object_set(label, "xalign", 0.0f, NULL); gtk_table_attach(GTK_TABLE(table), label, 0, 1, i, i + 1, GTK_FILL, GTK_SHRINK, 5, 5); gtk_table_attach(GTK_TABLE(table), inputWidget, 1, 2, i, i + 1, GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 4); FcitxConfigBindValue(self->gconfig.configFile, cgdesc->groupName, codesc->optionName, NULL, sync_filter, argument); } } } FcitxConfigBindSync(&self->gconfig); } if (self->parser) { GHashTable* subconfigs = self->parser->subconfigs; if (g_hash_table_size(subconfigs) != 0) { GtkWidget *table = gtk_table_new(2, g_hash_table_size(subconfigs), FALSE); GtkWidget *plabel = gtk_label_new(_("Other")); GtkWidget *scrollwnd = gtk_scrolled_window_new(NULL, NULL); GtkWidget *viewport = gtk_viewport_new(NULL, NULL); gtk_container_set_border_width(GTK_CONTAINER(table), 4); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwnd), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(scrollwnd), viewport); gtk_container_add(GTK_CONTAINER(viewport), table); gtk_notebook_append_page(GTK_NOTEBOOK(configNotebook), scrollwnd, plabel); HashForeachContext context; context.i = 0; context.table = table; context.widget = self; g_hash_table_foreach(subconfigs, hash_foreach_cb, &context); } } gtk_widget_set_size_request(configNotebook, 500, -1); gtk_notebook_set_scrollable(GTK_NOTEBOOK(configNotebook), TRUE); }
/* * 读取虚拟键盘映射文件 */ void LoadVKMapFile(FcitxVKState *vkstate) { int i, j; FILE *fp; char *buf = NULL; char *pstr; VKS* vks = vkstate->vks; size_t len; for (j = 0; j < VK_MAX; j++) { for (i = 0; i < VK_NUMBERS; i++) { vks[j].strSymbol[i][0][0] = '\0'; vks[j].strSymbol[i][1][0] = '\0'; } if (vks[j].strName) { free(vks[j].strName); vks[j].strName = NULL; } } fp = FcitxXDGGetFileWithPrefix("data", VK_FILE, "r", NULL); if (!fp) return; vkstate->iVKCount = 0; while (getline(&buf, &len, fp) != -1) { pstr = buf; while (*pstr == ' ' || *pstr == '\t') pstr++; if (pstr[0] == '#') continue; i = strlen(pstr) - 1; if (pstr[i] == '\n') pstr[i] = '\0'; if (!strlen(pstr)) continue; if (!strcmp(pstr, "[VK]")) vkstate->iVKCount++; else if (!strncmp(pstr, "NAME=", 5)) vks[vkstate->iVKCount - 1].strName = strdup(gettext(pstr + 5)); else { if (pstr[1] != '=' && !vkstate->iVKCount) continue; for (i = 0; i < VK_NUMBERS; i++) { if (vkTable[i] == tolower(pstr[0])) { pstr += 2; while (*pstr == ' ' || *pstr == '\t') pstr++; if (!(*pstr)) break; j = 0; while (*pstr && (*pstr != ' ' && *pstr != '\t')) vks[vkstate->iVKCount - 1].strSymbol[i][0][j++] = *pstr++; vks[vkstate->iVKCount - 1].strSymbol[i][0][j] = '\0'; j = 0; while (*pstr == ' ' || *pstr == '\t') pstr++; if (*pstr) { while (*pstr && (*pstr != ' ' && *pstr != '\t')) vks[vkstate->iVKCount - 1].strSymbol[i][1][j++] = *pstr++; vks[vkstate->iVKCount - 1].strSymbol[i][1][j] = '\0'; } break; } } } } if (buf) free(buf); fclose(fp); }
void* DBusCreate(FcitxInstance* instance) { FcitxDBus *dbusmodule = (FcitxDBus*) fcitx_utils_malloc0(sizeof(FcitxDBus)); FcitxAddon* dbusaddon = FcitxAddonsGetAddonByName(FcitxInstanceGetAddons(instance), FCITX_DBUS_NAME); dbusmodule->owner = instance; DBusError err; if (FcitxInstanceIsTryReplace(instance)) { fcitx_utils_launch_tool("fcitx-remote", "-e"); sleep(1); } dbus_threads_init_default(); // first init dbus dbus_error_init(&err); int retry = 0; DBusConnection* conn = NULL; char* servicename = NULL; asprintf(&servicename, "%s-%d", FCITX_DBUS_SERVICE, fcitx_utils_get_display_number()); /* do session dbus initialize */ do { if (!getenv("DISPLAY") && !getenv("DBUS_SESSION_BUS_ADDRESS")) { FcitxLog(WARNING, "Without DISPLAY or DBUS_SESSION_BUS_ADDRESS session bus will not work"); break; } /* try to get session dbus */ while (1) { conn = dbus_bus_get(DBUS_BUS_SESSION, &err); if (dbus_error_is_set(&err)) { FcitxLog(WARNING, "Connection Error (%s)", err.message); dbus_error_free(&err); dbus_error_init(&err); } if (NULL == conn && retry < MAX_RETRY_TIMES) { retry ++; sleep(RETRY_INTERVAL * retry); } else { break; } } if (NULL == conn) { break; } if (!dbus_connection_add_filter(conn, DBusModuleFilter, dbusmodule, NULL)) break; if (!dbus_connection_set_watch_functions(conn, DBusAddWatch, DBusRemoveWatch, NULL, &dbusmodule->watches, NULL)) { FcitxLog(WARNING, "Add Watch Function Error"); dbus_error_free(&err); dbus_error_init(&err); dbus_connection_unref(conn); conn = NULL; break; } /* from here we know dbus connection is successful, now we need to register the service */ dbus_connection_set_exit_on_disconnect(conn, FALSE); dbusmodule->conn = conn; boolean request_retry = false; int replaceCountdown = FcitxInstanceIsTryReplace(instance) ? 3 : 0; FcitxInstanceResetTryReplace(instance); do { request_retry = false; // request a name on the bus int ret = dbus_bus_request_name(conn, servicename, DBUS_NAME_FLAG_DO_NOT_QUEUE, &err); if (dbus_error_is_set(&err)) { FcitxLog(WARNING, "Name Error (%s)", err.message); goto dbus_init_failed; } if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { FcitxLog(WARNING, "DBus Service Already Exists"); if (replaceCountdown > 0) { replaceCountdown --; fcitx_utils_launch_tool("fcitx-remote", "-e"); /* sleep for a while and retry */ sleep(1); request_retry = true; continue; } /* if we know fcitx exists, we should exit. */ dbus_error_free(&err); free(servicename); free(dbusmodule); FcitxInstanceEnd(instance); return NULL; } } while (request_retry); dbus_connection_flush(dbusmodule->conn); } while(0); DBusConnection* privconn = NULL; do { int noPrivateDBus = fcitx_utils_get_boolean_env("FCITX_NO_PRIVATE_DBUS", false); if (noPrivateDBus) break; char* file; FILE* dbusfp = FcitxXDGGetFileWithPrefix("dbus", "daemon.conf", "r", &file); if (dbusfp) { fclose(dbusfp); } else { free(file); file = NULL; } dbusmodule->daemon = DBusLaunch(file); fcitx_utils_free(file); if (dbusmodule->daemon.pid == 0) break; privconn = dbus_connection_open(dbusmodule->daemon.address, &err); if (dbus_error_is_set(&err)) { FcitxLog(ERROR, "Private dbus daemon connection error (%s)", err.message); break; } dbus_bus_register(privconn, &err); if (dbus_error_is_set(&err)) { FcitxLog(ERROR, "Private dbus bus register error (%s)", err.message); break; } int ret = dbus_bus_request_name(privconn, servicename, DBUS_NAME_FLAG_DO_NOT_QUEUE, &err); if (dbus_error_is_set(&err)) { FcitxLog(WARNING, "Private Name Error (%s)", err.message); break; } if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { FcitxLog(ERROR, "Private DBus Service Already Exists, fcitx being hacked?"); break; } if (!dbus_connection_add_filter(privconn, DBusModuleFilter, dbusmodule, NULL)) break; if (!dbus_connection_set_watch_functions(privconn, DBusAddWatch, DBusRemoveWatch, NULL, &dbusmodule->watches, NULL)) { FcitxLog(WARNING, "Add Watch Function Error"); break; } char* addressFile = NULL; char* localMachineId = dbus_get_local_machine_id(); asprintf(&addressFile, "%s-%d", localMachineId, fcitx_utils_get_display_number()); dbus_free(localMachineId); FILE* fp = FcitxXDGGetFileUserWithPrefix("dbus", addressFile, "w", NULL); free(addressFile); if (!fp) break; fprintf(fp, "%s", dbusmodule->daemon.address); fwrite("\0", sizeof(char), 1, fp); pid_t curPid = getpid(); fwrite(&dbusmodule->daemon.pid, sizeof(pid_t), 1, fp); fwrite(&curPid, sizeof(pid_t), 1, fp); fclose(fp); dbusmodule->privconn = privconn; char* command = fcitx_utils_get_fcitx_path_with_filename("bindir", "/fcitx-dbus-watcher"); char* pidstring = NULL; asprintf(&pidstring, "%d", dbusmodule->daemon.pid); char* args[] = { command, dbusmodule->daemon.address, pidstring, NULL }; fcitx_utils_start_process(args); free(command); free(pidstring); } while(0); if (!dbusmodule->privconn) { if (privconn) { dbus_connection_unref(privconn); DBusKill(&dbusmodule->daemon); } } FcitxModuleAddFunction(dbusaddon, DBusGetConnection); FcitxModuleAddFunction(dbusaddon, DBusGetPrivateConnection); dbus_error_free(&err); dbusmodule->serviceName = servicename; return dbusmodule; dbus_init_failed: dbus_error_free(&err); fcitx_utils_free(servicename); if (conn) dbus_connection_unref(conn); DBusKill(&dbusmodule->daemon); fcitx_utils_free(dbusmodule); return NULL; }
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; }
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); }
SkinImage* LoadImageFromTable(SkinImage** imageTable, const char* skinType, const char* name, int flag) { cairo_surface_t *png = NULL; SkinImage *image = NULL; char *buf; fcitx_utils_alloc_cat_str(buf, "skin/", skinType); const char* fallbackChainNoFallback[] = { buf }; const char* fallbackChainPanel[] = { buf, "skin/default" }; const char* fallbackChainTray[] = { "imicon" }; const char* fallbackChainPanelIMIcon[] = { buf, "imicon", "skin/default" }; HASH_FIND_STR(*imageTable, name, image); if (image != NULL) { free(buf); return image; } const char** fallbackChain; int fallbackSize; switch(flag) { case 1: fallbackChain = fallbackChainPanel; fallbackSize = 2; break; case 2: fallbackChain = fallbackChainTray; fallbackSize = 1; break; case 3: fallbackChain = fallbackChainPanelIMIcon; fallbackSize = 3; break; case 0: default: /* fall through */ fallbackChain = fallbackChainNoFallback; fallbackSize = 1; break; } if (strlen(name) > 0 && strcmp(name , "NONE") != 0) { int i = 0; for (i = 0; i < fallbackSize; i ++) { char* filename; const char* skintype = fallbackChain[i]; FILE* fp = FcitxXDGGetFileWithPrefix(skintype, name, "r", &filename); if (fp) { png = cairo_image_surface_create_from_png(filename); if (cairo_surface_status (png)) { png = NULL; } } free(filename); if (png) break; } } free(buf); if (png != NULL) { image = fcitx_utils_new(SkinImage); image->name = strdup(name); image->image = png; HASH_ADD_KEYPTR(hh, *imageTable, image->name, strlen(image->name), image); return image; } return NULL; }
/** @加载皮肤配置文件 */ int LoadSkinConfig(FcitxSkin* sc, char** skinType) { FILE *fp; boolean isreload = False; int ret = 0; if (sc->config.configFile) { utarray_done(&sc->skinMainBar.skinPlacement); FcitxConfigFree(&sc->config); UnloadImage(sc); } memset(sc, 0, sizeof(FcitxSkin)); utarray_init(&sc->skinMainBar.skinPlacement, &place_icd); reload: if (!isreload) { char *buf; fcitx_utils_alloc_cat_str(buf, *skinType, "/fcitx_skin.conf"); fp = FcitxXDGGetFileWithPrefix("skin", buf, "r", NULL); free(buf); } else { char *path = fcitx_utils_get_fcitx_path_with_filename( "pkgdatadir", "/skin/default/fcitx_skin.conf"); fp = fopen(path, "r"); free(path); } if (fp) { FcitxConfigFile *cfile; FcitxConfigFileDesc* skinDesc = GetSkinDesc(); if (sc->config.configFile == NULL) { cfile = FcitxConfigParseConfigFileFp(fp, skinDesc); } else { cfile = sc->config.configFile; cfile = FcitxConfigParseIniFp(fp, cfile); } if (!cfile) { fclose(fp); fp = NULL; } else { FcitxSkinConfigBind(sc, cfile, skinDesc); FcitxConfigBindSync((FcitxGenericConfig*)sc); } } if (!fp) { if (isreload) { FcitxLog(FATAL, _("Can not load default skin, is installion correct?")); perror("fopen"); ret = 1; // 如果安装目录里面也没有配置文件,那就只好告诉用户,无法运行了 } else { perror("fopen"); FcitxLog(WARNING, _("Can not load skin %s, return to default"), *skinType); if (*skinType) free(*skinType); *skinType = strdup("default"); isreload = true; goto reload; } } if (fp) fclose(fp); sc->skinType = skinType; return ret; }
FcitxPunc* LoadPuncFile(const char* filename) { FILE *fpDict; // 词典文件指针 int iRecordNo; char strText[4 + MAX_PUNC_LENGTH * UTF8_MAX_LENGTH]; char *pstr; // 临时指针 int i; fpDict = FcitxXDGGetFileWithPrefix("data", filename, "r", NULL); if (strlen(filename) < strlen(PUNC_DICT_FILENAME)) return NULL; if (!fpDict) { FcitxLog(WARNING, _("Can't open punc file.")); return NULL; } /* 计算词典里面有多少的数据 * 这个函数非常简单,就是计算该文件有多少行(包含空行)。 * 因为空行,在下面会略去,所以,这儿存在内存的浪费现象。 * 没有一个空行就是浪费sizeof (WidePunc)字节内存*/ iRecordNo = fcitx_utils_calculate_record_number(fpDict); // 申请空间,用来存放这些数据。这儿没有检查是否申请到内存,严格说有小隐患 WidePunc* punc = (WidePunc *) fcitx_utils_malloc0(sizeof(WidePunc) * (iRecordNo + 1)); iRecordNo = 0; // 下面这个循环,就是一行一行的读入词典文件的数据。并将其放入到curPunc里面去。 for (;;) { if (!fgets(strText, (MAX_PUNC_LENGTH * UTF8_MAX_LENGTH + 3), fpDict)) break; i = strlen(strText) - 1; // 先找到最后一个字符 while ((strText[i] == '\n') || (strText[i] == ' ')) { if (!i) break; i--; } // 如果找到,进行出入。当是空行时,肯定找不到。所以,也就略过了空行的处理 if (i) { strText[i + 1] = '\0'; // 在字符串的最后加个封口 pstr = strText; // 将pstr指向第一个非空字符 while (*pstr == ' ') pstr++; punc[iRecordNo].ASCII = *pstr++; // 这个就是中文符号所对应的ASCII码值 while (*pstr == ' ') // 然后,将pstr指向下一个非空字符 pstr++; punc[iRecordNo].iCount = 0; // 该符号有几个转化,比如英文"就可以转换成“和” // 依次将该ASCII码所对应的符号放入到结构中 while (*pstr) { i = 0; // 因为中文符号都是多字节(这里读取并不像其他地方是固定两个,所以没有问题)的,所以,要一直往后读,知道空格或者字符串的末尾 while (*pstr != ' ' && *pstr) { punc[iRecordNo].strWidePunc[punc[iRecordNo].iCount][i] = *pstr; i++; pstr++; } // 每个中文符号用'\0'隔开 punc[iRecordNo].strWidePunc[punc[iRecordNo].iCount][i] = '\0'; while (*pstr == ' ') pstr++; punc[iRecordNo].iCount++; } iRecordNo++; } } punc[iRecordNo].ASCII = '\0'; fclose(fpDict); FcitxPunc* p = fcitx_utils_malloc0(sizeof(FcitxPunc)); p->langCode = ""; const char* langcode = filename + strlen(PUNC_DICT_FILENAME); if (*langcode == '\0') p->langCode = strdup("C"); else p->langCode = strdup(langcode + 1); p->curPunc = punc; return p; }