コード例 #1
0
ファイル: test-config.c プロジェクト: chiehwen/libchewing
void test_set_easySymbolInput()
{
	ChewingContext *ctx;
	int value;
	int mode;

	chewing_Init( 0, 0 );

	ctx = chewing_new();

	for ( value = 0; value < 2; ++value ) {
		chewing_set_easySymbolInput( ctx, value );
		mode = chewing_get_easySymbolInput( ctx );
		ok( mode == value,
			"easySymbolInput `%d', shall be `%d'", mode, value );

		chewing_set_easySymbolInput( ctx, -1 );
		mode = chewing_get_easySymbolInput( ctx );
		ok( mode == value,
			"easySymbolInput `%d', shall be `%d'", mode, value );

		chewing_set_easySymbolInput( ctx, 2 );
		mode = chewing_get_easySymbolInput( ctx );
		ok( mode == value,
			"easySymbolInput `%d', shall be `%d'", mode, value );
	}

	chewing_delete( ctx );
	chewing_Terminate();
}
コード例 #2
0
void ibus_chewing_engine_handle_Default(IBusChewingEngine *self, guint keyval, gboolean shiftPressed){
    G_DEBUG_MSG(2,"[I2] handle_Default(-,%u) plainZhuyin=%s inputMode=%d",
	    keyval,(self->chewingFlags & CHEWING_FLAG_PLAIN_ZHUYIN)? "TRUE": "FALSE",self->inputMode);
    ibus_chewing_engine_set_status_flag(self, ENGINE_STATUS_NEED_COMMIT);
    self->hasCommit=0;
#ifdef EASY_SYMBOL_INPUT_WORK_AROUND
    if (self->chewingFlags & CHEWING_FLAG_EASY_SYMBOL_INPUT){
	/* If shift is pressed, turn on the  easySymbolInput, turn off
	 * otherwise
	 */
	chewing_set_easySymbolInput(self->context,(shiftPressed)? 1:0);
    }
#endif
    if (self->chewingFlags & CHEWING_FLAG_FORCE_LOWERCASE_ENGLISH){
	if (isupper(keyval) && !shiftPressed){
	    keyval=tolower(keyval);
	}else if (islower(keyval) && shiftPressed){
	    keyval=toupper(keyval);
	}
    }
    chewing_handle_Default(self->context,keyval);
    if (self->chewingFlags & CHEWING_FLAG_PLAIN_ZHUYIN){
	if (self_is_selectKey(self,self->_priv->key_last) &&
		self->inputMode==CHEWING_INPUT_MODE_SELECTING){
	    chewing_handle_Enter(self->context);
	    self->inputMode= CHEWING_INPUT_MODE_SELECTION_DONE;
	}
    }
}
コード例 #3
0
gboolean easySymbolInput_apply_callback(PropertyContext * ctx,
					gpointer userData)
{
    GValue *value = &(ctx->value);
    IBusChewingPreEdit *icPreEdit = (IBusChewingPreEdit *) ctx->parent;
    chewing_set_easySymbolInput(icPreEdit->context,
				(g_value_get_boolean(value)) ? 1 : 0);
    /* Use MkdgProperty directly, no need to keep flag */
    return TRUE;
}
コード例 #4
0
static void easySymbolInput_set_callback(PropertyContext *ctx, GValue *value){
#ifdef IBUS_CHEWING_MAIN
    IBusChewingEngine *engine=(IBusChewingEngine *) ctx->userData;
    chewing_set_easySymbolInput(engine->context,(g_value_get_boolean(value)) ? 1: 0);
    if (g_value_get_boolean(value)){
	engine->chewingFlags |= CHEWING_FLAG_EASY_SYMBOL_INPUT;
    }else{
	engine->chewingFlags &= ~CHEWING_FLAG_EASY_SYMBOL_INPUT;
    }
#endif
}
コード例 #5
0
ファイル: chewingio.c プロジェクト: shaform/ibus-freearray
CHEWING_API int chewing_Configure( ChewingContext *ctx, ChewingConfigData *pcd )
{
	chewing_set_candPerPage( ctx, pcd->candPerPage );
	chewing_set_maxChiSymbolLen( ctx, pcd->maxChiSymbolLen );
	chewing_set_selKey( ctx, pcd->selKey, MAX_SELKEY );
	chewing_set_addPhraseDirection( ctx, pcd->bAddPhraseForward );
	chewing_set_spaceAsSelection( ctx, pcd->bSpaceAsSelection );
	chewing_set_escCleanAllBuf( ctx, pcd->bEscCleanAllBuf );
	chewing_set_autoShiftCur( ctx, pcd->bAutoShiftCur );
	chewing_set_easySymbolInput( ctx, pcd->bEasySymbolInput );
	chewing_set_phraseChoiceRearward( ctx, pcd->bPhraseChoiceRearward );

	return 0;
}
コード例 #6
0
void test_mode_change()
{
    ChewingContext *ctx;


    ctx = chewing_new();

    chewing_set_maxChiSymbolLen( ctx, 16 );

    type_keystroke_by_string( ctx, CHINESE.token );
    ok_commit_buffer( ctx, CHINESE.expected );

    chewing_set_easySymbolInput( ctx, 1 );
    type_keystroke_by_string( ctx, EASY_SYMBOL[0].token );
    type_keystroke_by_string( ctx, "<E>" );
    ok_commit_buffer( ctx, EASY_SYMBOL[0].expected );

    chewing_set_easySymbolInput( ctx, 0 );
    type_keystroke_by_string( ctx, CHINESE.token );
    ok_commit_buffer( ctx, CHINESE.expected );

    chewing_delete( ctx );
}
コード例 #7
0
ファイル: test-easy-symbol.c プロジェクト: kanru/libchewing
void test_mode_change()
{
	chewing_Init( NULL, NULL );

	ChewingContext *ctx = chewing_new();
	ok( ctx, "chewing_new shall not return NULL" );

	chewing_set_maxChiSymbolLen( ctx, 16 );

	type_keystoke_by_string( ctx, CHINESE.token );
	ok_commit_buffer( ctx, CHINESE.expected );

	chewing_set_easySymbolInput( ctx, 1 );
	type_keystoke_by_string( ctx, EASY_SYMBOL[0].token );
	ok_commit_buffer( ctx, EASY_SYMBOL[0].expected );

	chewing_set_easySymbolInput( ctx, 0 );
	type_keystoke_by_string( ctx, CHINESE.token );
	ok_commit_buffer( ctx, CHINESE.expected );

	chewing_delete( ctx );
	chewing_Terminate();
}
コード例 #8
0
ファイル: test-easy-symbol.c プロジェクト: kanru/libchewing
void test_type_easy_symbol()
{
	chewing_Init( NULL, NULL );

	ChewingContext *ctx = chewing_new();
	ok( ctx, "chewing_new shall not return NULL" );

	chewing_set_maxChiSymbolLen( ctx, 16 );
	chewing_set_easySymbolInput( ctx, 1 );

	for ( int i = 0; i < ARRAY_SIZE( EASY_SYMBOL ); ++i ) {
		type_keystoke_by_string( ctx, EASY_SYMBOL[i].token );
		ok_commit_buffer( ctx, EASY_SYMBOL[i].expected );
	}

	chewing_delete( ctx );
	chewing_Terminate();
}
コード例 #9
0
void test_in_easy_symbol_mode()
{
	ChewingContext *ctx;
	size_t i;


	ctx = chewing_new();

	chewing_set_maxChiSymbolLen( ctx, 16 );
	chewing_set_easySymbolInput( ctx, 1 );

	for ( i = 0; i < ARRAY_SIZE( SPECIAL_SYMBOL_TABLE ); ++i ) {
		type_keystroke_by_string( ctx, SPECIAL_SYMBOL_TABLE[i].token );
		ok_preedit_buffer( ctx, SPECIAL_SYMBOL_TABLE[i].expected );
		type_keystroke_by_string( ctx, "<E>" );
		ok_commit_buffer( ctx, SPECIAL_SYMBOL_TABLE[i].expected );
	}

	chewing_delete( ctx );
}
コード例 #10
0
ファイル: test-config.c プロジェクト: aitjcize/libchewing
void test_maxChiSymbolLen()
{
	ChewingContext *ctx;
	int i;

	ctx = chewing_new();
	start_testcase( ctx, fd );

	chewing_set_maxChiSymbolLen( ctx, MAX_CHI_SYMBOL_LEN );

	for ( i = 0; i < MAX_CHI_SYMBOL_LEN; ++i ) {
		type_keystroke_by_string( ctx, "hk4" );
	}

	// Use easy symbol 'Orz' as last input for worst case scenario.
	chewing_set_easySymbolInput( ctx, 1 );
	type_keystroke_by_string( ctx, "L" );

	chewing_delete( ctx );
}
コード例 #11
0
ファイル: chewing.cpp プロジェクト: rocfatcat/windows-chewing
void Chewing::SetEasySymbolInput(int bSet)
{
    chewing_set_easySymbolInput(ctx, bSet);
}
コード例 #12
0
void test_null()
{
    int ret;
    char *buf;
    const char *const_buf;
    int *key;
    unsigned short *phone;

    start_testcase(NULL, fd);

    chewing_Reset(NULL);        // shall not crash

    ret = chewing_set_KBType(NULL, 0);
    ok(ret == -1, "chewing_set_KBType() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_get_KBType(NULL);
    ok(ret == -1, "chewing_get_KBType() returns `%d' shall be `%d'", ret, -1);

    buf = chewing_get_KBString(NULL);
    ok(strcmp(buf, "") == 0, "chewing_get_KBString() returns `%s' shall be `%s'", buf, "");
    chewing_free(buf);

    chewing_delete(NULL);       // shall not crash

    chewing_free(NULL);         // shall not crash

    chewing_set_candPerPage(NULL, 0);   // shall not crash

    ret = chewing_get_candPerPage(NULL);
    ok(ret == -1, "chewing_get_candPerPage() returns `%d' shall be `%d'", ret, -1);

    chewing_set_maxChiSymbolLen(NULL, 0);       // shall not crash

    ret = chewing_get_maxChiSymbolLen(NULL);
    ok(ret == -1, "chewing_get_maxChiSymbolLen() returns `%d' shall be `%d'", ret, -1);

    chewing_set_selKey(NULL, NULL, 0);  // shall not crash

    key = chewing_get_selKey(NULL);
    ok(key == NULL, "chewing_get_selKey() returns NULL");
    chewing_free(key);

    chewing_set_addPhraseDirection(NULL, 0);    // shall not crash

    ret = chewing_get_addPhraseDirection(NULL);
    ok(ret == -1, "chewing_get_addPhraseDirection() returns `%d' shall be `%d'", ret, -1);

    chewing_set_spaceAsSelection(NULL, 0);      // shall not crash

    ret = chewing_get_spaceAsSelection(NULL);
    ok(ret == -1, "chewing_get_spaceAsSelection() returns `%d' shall be `%d'", ret, -1);

    chewing_set_escCleanAllBuf(NULL, 0);        // shall not crash

    ret = chewing_get_escCleanAllBuf(NULL);
    ok(ret == -1, "chewing_get_escCleanAllBuf() returns `%d' shall be `%d'", ret, -1);

    chewing_set_autoShiftCur(NULL, 0);  // shall not crash

    ret = chewing_get_autoShiftCur(NULL);
    ok(ret == -1, "chewing_get_autoShiftCur() returns `%d' shall be `%d'", ret, -1);

    chewing_set_easySymbolInput(NULL, 0);       // shall not crash

    ret = chewing_get_easySymbolInput(NULL);
    ok(ret == -1, "chewing_get_easySymbolInput() returns `%d' shall be `%d'", ret, -1);

    chewing_set_phraseChoiceRearward(NULL, 0);

    ret = chewing_get_phraseChoiceRearward(NULL);
    ok(ret == -1, "chewing_get_phraseChoiceRearward() returns `%d' shall be `%d'", ret, -1);

    chewing_set_ChiEngMode(NULL, 0);    // shall not crash

    ret = chewing_get_ChiEngMode(NULL);
    ok(ret == -1, "chewing_get_ChiEngMode() returns `%d' shall be `%d'", ret, -1);

    chewing_set_ShapeMode(NULL, 0);     // shall not crash

    ret = chewing_handle_Space(NULL);
    ok(ret == -1, "chewing_handle_Space() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_Esc(NULL);
    ok(ret == -1, "chewing_handle_Esc() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_Enter(NULL);
    ok(ret == -1, "chewing_handle_Enter() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_Del(NULL);
    ok(ret == -1, "chewing_handle_Del() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_Backspace(NULL);
    ok(ret == -1, "chewing_handle_Backspace() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_Up(NULL);
    ok(ret == -1, "chewing_handle_Up() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_Down(NULL);
    ok(ret == -1, "chewing_handle_Down() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_ShiftLeft(NULL);
    ok(ret == -1, "chewing_handle_ShiftLeft() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_Left(NULL);
    ok(ret == -1, "chewing_handle_Left() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_ShiftRight(NULL);
    ok(ret == -1, "chewing_handle_ShiftRight() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_Right(NULL);
    ok(ret == -1, "chewing_handle_Right() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_Tab(NULL);
    ok(ret == -1, "chewing_handle_Tab() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_DblTab(NULL);
    ok(ret == -1, "chewing_handle_DblTab() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_Capslock(NULL);
    ok(ret == -1, "chewing_handle_Capslock() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_Home(NULL);
    ok(ret == -1, "chewing_handle_Home() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_PageUp(NULL);
    ok(ret == -1, "chewing_handle_PageUp() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_PageDown(NULL);
    ok(ret == -1, "chewing_handle_PageDown() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_Default(NULL, 0);
    ok(ret == -1, "chewing_handle_Default() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_CtrlNum(NULL, 0);
    ok(ret == -1, "chewing_handle_CtrlNum() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_ShiftSpace(NULL);
    ok(ret == -1, "chewing_handle_ShiftSpace() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_handle_Numlock(NULL, 0);
    ok(ret == -1, "chewing_handle_Numlock() returns `%d' shall be `%d'", ret, -1);

    phone = chewing_get_phoneSeq(NULL);
    ok(phone == NULL, "chewing_get_phoneSeq() returns NULL");
    chewing_free(phone);

    ret = chewing_get_phoneSeqLen(NULL);
    ok(ret == -1, "chewing_get_phoneSeqLen() returns `%d' shall be `%d'", ret, -1);

    chewing_set_logger(NULL, NULL, NULL);

    ret = chewing_userphrase_enumerate(NULL);
    ok(ret == -1, "chewing_userphrase_enumerate() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_userphrase_has_next(NULL, NULL, NULL);
    ok(ret == 0, "chewing_userphrase_has_next() returns `%d' shall be `%d'", ret, 0);

    ret = chewing_userphrase_get(NULL, NULL, 0, NULL, 0);
    ok(ret == -1, "chewing_userphrase_get() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_userphrase_add(NULL, NULL, NULL);
    ok(ret == -1, "chewing_userphrase_add() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_userphrase_remove(NULL, NULL, NULL);
    ok(ret == -1, "chewing_userphrase_remove() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_userphrase_lookup(NULL, NULL, NULL);
    ok(ret == 0, "chewing_userphrase_lookup() returns `%d' shall be `%d'", ret, 0);

    ret = chewing_cand_open(NULL);
    ok(ret == -1, "chewing_cand_open() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_cand_close(NULL);
    ok(ret == -1, "chewing_cand_open() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_cand_choose_by_index(NULL, 0);
    ok(ret == -1, "chewing_cand_choose_by_index() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_cand_list_first(NULL);
    ok(ret == -1, "chewing_cand_list_first() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_cand_list_last(NULL);
    ok(ret == -1, "chewing_cand_list_last() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_cand_list_has_next(NULL);
    ok(ret == 0, "chewing_cand_list_has_next() returns `%d' shall be `%d'", ret, 0);

    ret = chewing_cand_list_has_prev(NULL);
    ok(ret == 0, "chewing_cand_list_has_prev() returns `%d' shall be `%d'", ret, 0);

    ret = chewing_cand_list_next(NULL);
    ok(ret == -1, "chewing_cand_list_next() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_cand_list_prev(NULL);
    ok(ret == -1, "chewing_cand_list_prev() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_commit_preedit_buf(NULL);
    ok(ret == -1, "chewing_commit_preedit_buf() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_clean_preedit_buf(NULL);
    ok(ret == -1, "chewing_clean_preedit_buf() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_clean_bopomofo_buf(NULL);
    ok(ret == -1, "chewing_clean_bopomofo_buf() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_commit_Check(NULL);
    ok(ret == -1, "chewing_commit_Check() returns `%d' shall be `%d'", ret, -1);

    buf = chewing_commit_String(NULL);
    ok(strcmp(buf, "") == 0, "chewing_commit_String() returns `%s' shall be `%s'", buf, "");
    chewing_free(buf);

    const_buf = chewing_commit_String_static(NULL);
    ok(strcmp(const_buf, "") == 0, "chewing_commit_String() returns `%s' shall be `%s'", const_buf, "");

    ret = chewing_buffer_Check(NULL);
    ok(ret == -1, "chewing_buffer_Check() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_buffer_Len(NULL);
    ok(ret == -1, "chewing_buffer_Len() returns `%d' shall be `%d'", ret, -1);

    buf = chewing_buffer_String(NULL);
    ok(strcmp(buf, "") == 0, "chewing_buffer_String() returns `%s' shall be `%s'", buf, "");
    chewing_free(buf);

    const_buf = chewing_buffer_String_static(NULL);
    ok(strcmp(const_buf, "") == 0, "chewing_buffer_String_static() returns `%s' shall be `%s'", const_buf, "");

    const_buf = chewing_bopomofo_String_static(NULL);
    ok(strcmp(const_buf, "") == 0, "chewing_bopomofo_String_static() returns `%s' shall be `%s'", const_buf, "");

BEGIN_IGNORE_DEPRECATIONS
    buf = chewing_zuin_String(NULL, NULL);
END_IGNORE_DEPRECATIONS
    ok(strcmp(buf, "") == 0, "chewing_zuin_String() returns `%s' shall be `%s'", buf, "");
    chewing_free(buf);

    ret = chewing_bopomofo_Check(NULL);
    ok(ret == -1, "chewing_bopomofo_Check() returns `%d' shall be `%d'", ret, -1);

BEGIN_IGNORE_DEPRECATIONS
    chewing_zuin_Check(NULL); // shall not crash
END_IGNORE_DEPRECATIONS

    ret = chewing_cursor_Current(NULL);
    ok(ret == -1, "chewing_cursor_Current() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_cand_CheckDone(NULL);
    ok(ret == -1, "chewing_cand_CheckDone() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_cand_TotalPage(NULL);
    ok(ret == -1, "chewing_cand_TotalPage() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_cand_ChoicePerPage(NULL);
    ok(ret == -1, "chewing_cand_ChoicePerPage() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_cand_TotalChoice(NULL);
    ok(ret == -1, "chewing_cand_TotalChoice() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_cand_CurrentPage(NULL);
    ok(ret == -1, "chewing_cand_CurrentPage() returns `%d' shall be `%d'", ret, -1);

    chewing_cand_Enumerate(NULL);       // shall not crash

    ret = chewing_cand_hasNext(NULL);
    ok(ret == -1, "chewing_cand_hasNext() returns `%d' shall be `%d'", ret, -1);

    const_buf = chewing_cand_String_static(NULL);
    ok(strcmp(const_buf, "") == 0, "chewing_cand_String_static() returns `%s' shall be `%s'", const_buf, "");

    buf = chewing_cand_String(NULL);
    ok(strcmp(buf, "") == 0, "chewing_cand_String() returns `%s' shall be `%s'", buf, "");
    chewing_free(buf);

    chewing_interval_Enumerate(NULL);   // shall not crash

    ret = chewing_interval_hasNext(NULL);
    ok(ret == -1, "chewing_interval_hasNext() returns `%d' shall be `%d'", ret, -1);

    chewing_interval_Get(NULL, NULL);   // shall not crash

    ret = chewing_aux_Check(NULL);
    ok(ret == -1, "chewing_aux_Check() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_aux_Length(NULL);
    ok(ret == -1, "chewing_aux_Length() returns `%d' shall be `%d'", ret, -1);

    const_buf = chewing_aux_String_static(NULL);
    ok(strcmp(const_buf, "") == 0, "chewing_aux_String_static() returns `%s' shall be `%s'", const_buf, "");

    buf = chewing_aux_String(NULL);
    ok(strcmp(buf, "") == 0, "chewing_aux_String() returns `%s' shall be `%s'", buf, "");
    chewing_free(buf);

    ret = chewing_keystroke_CheckIgnore(NULL);
    ok(ret == -1, "chewing_keystroke_CheckIgnore() returns `%d' shall be `%d'", ret, -1);

    ret = chewing_keystroke_CheckAbsorb(NULL);
    ok(ret == -1, "chewing_keystroke_CheckAbsorb() returns `%d' shall be `%d'", ret, -1);

    chewing_kbtype_Enumerate(NULL);     // shall not crash

    ret = chewing_kbtype_hasNext(NULL);
    ok(ret == -1, "chewing_kbtype_hasNext() returns `%d' shall be `%d'", ret, -1);

    const_buf = chewing_kbtype_String_static(NULL);
    ok(strcmp(const_buf, "") == 0, "chewing_kbtype_String_static() returns `%s' shall be `%s'", const_buf, "");

    buf = chewing_kbtype_String(NULL);
    ok(strcmp(buf, "") == 0, "chewing_kbtype_String() returns `%s' shall be `%s'", buf, "");
    chewing_free(buf);
}
コード例 #13
0
ファイル: stress.c プロジェクト: closer76/libchewing
int main(int argc, char *argv[])
{
    size_t i;
    int flag_random_init = 0;
    int flag_random_extra = 0;
    int flag_loop = -1;
    int (*get_input)() = &random256;

    for (i = 1; i < argc; i++) {
	if (strcmp(argv[i], "-init") == 0)
	    flag_random_init = 1;
	else if (strcmp(argv[i], "-extra") == 0 && argv[i + 1])
	    flag_random_extra = 1;
	else if (strcmp(argv[i], "-loop") == 0 && argv[i + 1])
	    flag_loop = atoi(argv[++i]);
	else if (strcmp(argv[i], "-stdin") == 0)
	    get_input = &get_stdin;
	else {
	    printf("Usage: %s [-init] [-extra] [-loop N] [-stdin]\n", argv[0]);
	    printf("\t-init           Random initial configuration\n");
	    printf("\t-extra          Random change all configurations during input.\n");
	    printf("\t                This is usually unexpected.\n");
	    printf("\t-stdin          Get random input from stdin\n");
	    printf("\t-loop N         How many iterations to test (default infinite=-1)\n");
	    exit(1);
	}
    }

    /* Initialize libchewing */
    putenv("CHEWING_PATH=" CHEWING_DATA_PREFIX);
    /* for the sake of testing, we should not change existing hash data */
    putenv("CHEWING_USER_PATH=" TEST_HASH_DIR);

    for (i = 0; i != flag_loop; i++) {
	ChewingContext *ctx = chewing_new();

	/* typical configuration */
	chewing_set_KBType(ctx, chewing_KBStr2Num("KB_DEFAULT"));
	chewing_set_candPerPage(ctx, 9);
	chewing_set_maxChiSymbolLen(ctx, 16);
	chewing_set_addPhraseDirection(ctx, 1);
	chewing_set_selKey(ctx, selKey_define, 10);
	chewing_set_spaceAsSelection(ctx, 1);

	if (flag_random_init) {
	    chewing_set_KBType(ctx, get_input());
	    chewing_set_candPerPage(ctx, get_input());
	    chewing_set_maxChiSymbolLen(ctx, get_input());
	    chewing_set_addPhraseDirection(ctx, get_input());
	    chewing_set_selKey(ctx, selKey_define, get_input() % 11);
	    chewing_set_spaceAsSelection(ctx, get_input());
	    chewing_set_escCleanAllBuf(ctx, get_input());
	    chewing_set_autoShiftCur(ctx, get_input());
	    chewing_set_easySymbolInput(ctx, get_input());
	    chewing_set_phraseChoiceRearward(ctx, get_input());
	}

	while (1) {
	    /* Random value: [0, max_key) for keys, [max_key, 0xff] for
	     * configurations. Use a fixed range here because I don't want the
	     * meaning of input changed a lot frequently if we add more keys in
	     * the future. */
	    const int max_key = 192;  /* arbitrary number */
	    int v = get_input();
	    if (v == EOF)
		break;
	    assert(max_key * sizeof(all_key[0]) >= sizeof(all_key));
	    if (v >= max_key) {
		const int typical = 2;
		int handled = 1;
		v = v - max_key;
		if (flag_random_extra || v < typical) {
		    switch (v) {
			/* typical configurations may be changed during input */
			case 0:
			    chewing_set_ChiEngMode(ctx, get_input());
			    break;
			case 1:
			    chewing_set_ShapeMode(ctx, get_input());
			    break;

			/* usually not changed during input */
			case 2:
			    chewing_set_KBType(ctx, get_input());
			    break;
			case 3:
			    chewing_set_candPerPage(ctx, get_input());
			    break;
			case 4:
			    chewing_set_maxChiSymbolLen(ctx, get_input());
			    break;
			case 5:
			    chewing_set_addPhraseDirection(ctx, get_input());
			    break;
			case 6:
			    chewing_set_selKey(ctx, selKey_define, get_input() % 11);
			    break;
			case 7:
			    chewing_set_spaceAsSelection(ctx, get_input());
			    break;
			case 8:
			    chewing_set_escCleanAllBuf(ctx, get_input());
			    break;
			case 9:
			    chewing_set_autoShiftCur(ctx, get_input());
			    break;
			case 10:
			    chewing_set_easySymbolInput(ctx, get_input());
			    break;
			case 11:
			    chewing_set_phraseChoiceRearward(ctx, get_input());
			    break;
			default:
			    handled = 0;
			    break;
		    }
		} else {
		    handled = 0;
		}
		if (!handled)
		    break;
	    } else {
		if (0 <= v && v < max_key) {
		    int key = all_key[v];
		    type_single_keystroke(ctx, key);
		} else {
		    break;
		}
	    }
	    commit_string(ctx);
	}
	chewing_delete(ctx);

	if (i % 10000 == 0)
	    printf("%zu\n", i);
	if (getenv("AFL_PERSISTENT"))
	    raise(SIGSTOP);
    }

    return 0;
}