diff src/farsi.c @ 0:76efa0be13f1

Initial revision
author atsuki
date Sat, 10 Nov 2007 15:07:22 +0900
parents
children e170173ecb68
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/farsi.c	Sat Nov 10 15:07:22 2007 +0900
@@ -0,0 +1,2312 @@
+/* vi:set ts=8 sts=4 sw=4:
+ *
+ * VIM - Vi IMproved	by Bram Moolenaar
+ *
+ * Do ":help uganda"  in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+
+/*
+ * farsi.c: functions for Farsi language
+ *
+ * Included by main.c, when FEAT_FKMAP is defined.
+ */
+
+static int toF_Xor_X_ __ARGS((int c));
+static int F_is_TyE __ARGS((int c));
+static int F_is_TyC_TyD __ARGS((int c));
+static int F_is_TyB_TyC_TyD __ARGS((int src, int offset));
+static int toF_TyB __ARGS((int c));
+static void put_curr_and_l_to_X __ARGS((int c));
+static void put_and_redo __ARGS((int c));
+static void chg_c_toX_orX __ARGS((void));
+static void chg_c_to_X_orX_ __ARGS((void));
+static void chg_c_to_X_or_X __ARGS((void));
+static void chg_l_to_X_orX_ __ARGS((void));
+static void chg_l_toXor_X __ARGS((void));
+static void chg_r_to_Xor_X_ __ARGS((void));
+static int toF_leading __ARGS((int c));
+static int toF_Rjoin __ARGS((int c));
+static int canF_Ljoin __ARGS((int c));
+static int canF_Rjoin __ARGS((int c));
+static int F_isterm __ARGS((int c));
+static int toF_ending __ARGS((int c));
+static void lrswapbuf __ARGS((char_u *buf, int len));
+
+/*
+** Convert the given Farsi character into a _X or _X_ type
+*/
+    static int
+toF_Xor_X_(c)
+    int	c;
+{
+    int tempc;
+
+    switch (c)
+    {
+	case BE:
+		return _BE;
+	case PE:
+		return _PE;
+	case TE:
+		return _TE;
+	case SE:
+		return _SE;
+	case JIM:
+		return _JIM;
+	case CHE:
+		return _CHE;
+	case HE_J:
+		return _HE_J;
+	case XE:
+		return _XE;
+	case SIN:
+		return _SIN;
+	case SHIN:
+		return _SHIN;
+	case SAD:
+		return _SAD;
+	case ZAD:
+		return _ZAD;
+	case AYN:
+		return _AYN;
+	case AYN_:
+		return _AYN_;
+	case GHAYN:
+		return _GHAYN;
+	case GHAYN_:
+		return _GHAYN_;
+	case FE:
+		return _FE;
+	case GHAF:
+		return _GHAF;
+	case KAF:
+		return _KAF;
+	case GAF:
+		return _GAF;
+	case LAM:
+		return _LAM;
+	case MIM:
+		return _MIM;
+	case NOON:
+		return _NOON;
+	case YE:
+	case YE_:
+		return _YE;
+	case YEE:
+	case YEE_:
+		return _YEE;
+	case IE:
+	case IE_:
+		return _IE;
+	case F_HE:
+		tempc = _HE;
+
+		if (p_ri && (curwin->w_cursor.col+1 < STRLEN(ml_get_curline())))
+		{
+		    inc_cursor();
+
+		    if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+			tempc = _HE_;
+
+		    dec_cursor();
+		}
+		if (!p_ri && STRLEN(ml_get_curline()))
+		{
+		    dec_cursor();
+
+		    if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+			tempc = _HE_;
+
+		    inc_cursor();
+		}
+
+		return tempc;
+    }
+    return 0;
+}
+
+/*
+** Convert the given Farsi character into Farsi capital character .
+*/
+    int
+toF_TyA(c)
+    int	c ;
+{
+    switch (c)
+    {
+	case ALEF_:
+		return ALEF;
+	case ALEF_U_H_:
+		return ALEF_U_H;
+	case _BE:
+		return BE;
+	case _PE:
+		return PE;
+	case _TE:
+		return TE;
+	case _SE:
+		return SE;
+	case _JIM:
+		return JIM;
+	case _CHE:
+		return CHE;
+	case _HE_J:
+		return HE_J;
+	case _XE:
+		return XE;
+	case _SIN:
+		return SIN;
+	case _SHIN:
+		return SHIN;
+	case _SAD:
+		return SAD;
+	case _ZAD:
+		return ZAD;
+	case _AYN:
+	case AYN_:
+	case _AYN_:
+		return AYN;
+	case _GHAYN:
+	case GHAYN_:
+	case _GHAYN_:
+		return GHAYN;
+	case _FE:
+		return FE;
+	case _GHAF:
+		return GHAF;
+/* I am not sure what it is !!!	    case _KAF_H: */
+	case _KAF:
+		return KAF;
+	case _GAF:
+		return GAF;
+	case _LAM:
+		return LAM;
+	case _MIM:
+		return MIM;
+	case _NOON:
+		return NOON;
+	case _YE:
+	case YE_:
+		return YE;
+	case _YEE:
+	case YEE_:
+		return YEE;
+	case TEE_:
+		return TEE;
+	case _IE:
+	case IE_:
+		return IE;
+	case _HE:
+	case _HE_:
+		return F_HE;
+    }
+    return c;
+}
+
+/*
+** Is the character under the cursor+offset in the given buffer a join type.
+** That is a character that is combined with the others.
+** Note: the offset is used only for command line buffer.
+*/
+    static int
+F_is_TyB_TyC_TyD(src, offset)
+    int		src, offset;
+{
+    int		c;
+
+    if (src == SRC_EDT)
+	c = gchar_cursor();
+    else
+	c = cmd_gchar(AT_CURSOR+offset);
+
+    switch (c)
+    {
+	case _LAM:
+	case _BE:
+	case _PE:
+	case _TE:
+	case _SE:
+	case _JIM:
+	case _CHE:
+	case _HE_J:
+	case _XE:
+	case _SIN:
+	case _SHIN:
+	case _SAD:
+	case _ZAD:
+	case _TA:
+	case _ZA:
+	case _AYN:
+	case _AYN_:
+	case _GHAYN:
+	case _GHAYN_:
+	case _FE:
+	case _GHAF:
+	case _KAF:
+	case _KAF_H:
+	case _GAF:
+	case _MIM:
+	case _NOON:
+	case _YE:
+	case _YEE:
+	case _IE:
+	case _HE_:
+	case _HE:
+		return TRUE;
+    }
+    return FALSE;
+}
+
+/*
+** Is the Farsi character one of the terminating only type.
+*/
+    static int
+F_is_TyE(c)
+    int	    c;
+{
+    switch (c)
+    {
+	case ALEF_A:
+	case ALEF_D_H:
+	case DAL:
+	case ZAL:
+	case RE:
+	case ZE:
+	case JE:
+	case WAW:
+	case WAW_H:
+	case HAMZE:
+		return TRUE;
+    }
+    return FALSE;
+}
+
+/*
+** Is the Farsi character one of the none leading type.
+*/
+    static int
+F_is_TyC_TyD(c)
+    int	    c;
+{
+    switch (c)
+    {
+	case ALEF_:
+	case ALEF_U_H_:
+	case _AYN_:
+	case AYN_:
+	case _GHAYN_:
+	case GHAYN_:
+	case _HE_:
+	case YE_:
+	case IE_:
+	case TEE_:
+	case YEE_:
+		return TRUE;
+    }
+    return FALSE;
+}
+
+/*
+** Convert a none leading Farsi char into a leading type.
+*/
+    static int
+toF_TyB(c)
+    int	    c;
+{
+    switch (c)
+    {
+	case ALEF_:	return ALEF;
+	case ALEF_U_H_:	    return ALEF_U_H;
+	case _AYN_:	return _AYN;
+	case AYN_:	return AYN;	/* exception - there are many of them */
+	case _GHAYN_:	return _GHAYN;
+	case GHAYN_:	return GHAYN;	/* exception - there are many of them */
+	case _HE_:	return _HE;
+	case YE_:	return YE;
+	case IE_:	return IE;
+	case TEE_:	return TEE;
+	case YEE_:	return YEE;
+    }
+    return c;
+}
+
+/*
+** Overwrite the current redo and cursor characters + left adjust
+*/
+    static void
+put_curr_and_l_to_X(c)
+    int		  c;
+{
+    int	tempc;
+
+    if (curwin->w_p_rl && p_ri)
+	return;
+
+    if ( (curwin->w_cursor.col < STRLEN(ml_get_curline())))
+    {
+	if ((p_ri && curwin->w_cursor.col) || !p_ri)
+	{
+	    if (p_ri)
+		dec_cursor();
+	    else
+		inc_cursor();
+
+	    if (F_is_TyC_TyD((tempc = gchar_cursor())))
+	    {
+		pchar_cursor(toF_TyB(tempc));
+		AppendCharToRedobuff(K_BS);
+		AppendCharToRedobuff(tempc);
+	    }
+
+	    if (p_ri)
+		inc_cursor();
+	    else
+		dec_cursor();
+	}
+    }
+
+    put_and_redo(c);
+}
+
+    static void
+put_and_redo(c)
+    int c;
+{
+    pchar_cursor(c);
+    AppendCharToRedobuff(K_BS);
+    AppendCharToRedobuff(c);
+}
+
+/*
+** Change the char. under the cursor to a X_ or X type
+*/
+    static void
+chg_c_toX_orX()
+{
+    int	tempc, curc;
+
+    switch ((curc = gchar_cursor()))
+    {
+	case _BE:
+		tempc = BE;
+		break;
+	case _PE:
+		tempc = PE;
+		break;
+	case _TE:
+		tempc = TE;
+		break;
+	case _SE:
+		tempc = SE;
+		break;
+	case _JIM:
+		tempc = JIM;
+		break;
+	case _CHE:
+		tempc = CHE;
+		break;
+	case _HE_J:
+		tempc = HE_J;
+		break;
+	case _XE:
+		tempc = XE;
+		break;
+	case _SIN:
+		tempc = SIN;
+		break;
+	case _SHIN:
+		tempc = SHIN;
+		break;
+	case _SAD:
+		tempc = SAD;
+		break;
+	case _ZAD:
+		tempc = ZAD;
+		break;
+	case _FE:
+		tempc = FE;
+		break;
+	case _GHAF:
+		tempc = GHAF;
+		break;
+	case _KAF_H:
+	case _KAF:
+		tempc = KAF;
+		break;
+	case _GAF:
+		tempc = GAF;
+		break;
+	case _AYN:
+		tempc = AYN;
+		break;
+	case _AYN_:
+		tempc = AYN_;
+		break;
+	case _GHAYN:
+		tempc = GHAYN;
+		break;
+	case _GHAYN_:
+		tempc = GHAYN_;
+		break;
+	case _LAM:
+		tempc = LAM;
+		break;
+	case _MIM:
+		tempc = MIM;
+		break;
+	case _NOON:
+		tempc = NOON;
+		break;
+	case _HE:
+	case _HE_:
+		tempc = F_HE;
+		break;
+	case _YE:
+	case _IE:
+	case _YEE:
+		if (p_ri)
+		{
+		    inc_cursor();
+		    if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+			    tempc = (curc == _YE ? YE_ :
+			    (curc == _IE ? IE_ : YEE_));
+		    else
+			    tempc = (curc == _YE ? YE :
+			    (curc == _IE ? IE : YEE));
+		    dec_cursor();
+		}
+		else
+		{
+		    if (curwin->w_cursor.col)
+		    {
+			dec_cursor();
+			if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+				tempc = (curc == _YE ? YE_ :
+				(curc == _IE ? IE_ : YEE_));
+			else
+				tempc = (curc == _YE ? YE :
+				(curc == _IE ? IE : YEE));
+			inc_cursor();
+		    }
+		    else
+			    tempc = (curc == _YE ? YE :
+			    (curc == _IE ? IE : YEE));
+		}
+		break;
+	default:
+		tempc = 0;
+    }
+
+    if (tempc)
+	put_and_redo(tempc);
+}
+
+/*
+** Change the char. under the cursor to a _X_ or X_ type
+*/
+
+    static void
+chg_c_to_X_orX_()
+{
+    int	tempc;
+
+    switch (gchar_cursor())
+    {
+	case ALEF:
+		tempc = ALEF_;
+		break;
+	case ALEF_U_H:
+		tempc = ALEF_U_H_;
+		break;
+	case _AYN:
+		tempc = _AYN_;
+		break;
+	case AYN:
+		tempc = AYN_;
+		break;
+	case _GHAYN:
+		tempc = _GHAYN_;
+		break;
+	case GHAYN:
+		tempc = GHAYN_;
+		break;
+	case _HE:
+		tempc = _HE_;
+		break;
+	case YE:
+		tempc = YE_;
+		break;
+	case IE:
+		tempc = IE_;
+		break;
+	case TEE:
+		tempc = TEE_;
+		break;
+	case YEE:
+		tempc = YEE_;
+		break;
+	default:
+		tempc = 0;
+    }
+
+    if (tempc)
+	put_and_redo(tempc);
+}
+
+/*
+** Change the char. under the cursor to a _X_ or _X type
+*/
+    static void
+chg_c_to_X_or_X ()
+{
+    int	tempc;
+
+    tempc = gchar_cursor();
+
+    if (curwin->w_cursor.col+1 < STRLEN(ml_get_curline()))
+    {
+	inc_cursor();
+
+	if ((tempc == F_HE) && (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)))
+	{
+	    tempc = _HE_;
+
+	    dec_cursor();
+
+	    put_and_redo(tempc);
+	    return;
+	}
+
+	dec_cursor();
+    }
+
+    if ((tempc = toF_Xor_X_(tempc)) != 0)
+	put_and_redo(tempc);
+}
+
+/*
+** Change the character left to the cursor to a _X_ or X_ type
+*/
+    static void
+chg_l_to_X_orX_ ()
+{
+    int	tempc;
+
+    if (!curwin->w_cursor.col &&
+	(curwin->w_cursor.col+1 == STRLEN(ml_get_curline())))
+	return;
+
+    if (!curwin->w_cursor.col && p_ri)
+	return;
+
+    if (p_ri)
+	dec_cursor();
+    else
+	inc_cursor();
+
+    switch (gchar_cursor())
+    {
+	case ALEF:
+		tempc = ALEF_;
+		break;
+	case ALEF_U_H:
+		tempc = ALEF_U_H_;
+		break;
+	case _AYN:
+		tempc = _AYN_;
+		break;
+	case AYN:
+		tempc = AYN_;
+		break;
+	case _GHAYN:
+		tempc = _GHAYN_;
+		break;
+	case GHAYN:
+		tempc = GHAYN_;
+		break;
+	case _HE:
+		tempc = _HE_;
+		break;
+	case YE:
+		tempc = YE_;
+		break;
+	case IE:
+		tempc = IE_;
+		break;
+	case TEE:
+		tempc = TEE_;
+		break;
+	case YEE:
+		tempc = YEE_;
+		break;
+	default:
+		tempc = 0;
+    }
+
+    if (tempc)
+	put_and_redo(tempc);
+
+    if (p_ri)
+	inc_cursor();
+    else
+	dec_cursor();
+}
+
+/*
+** Change the character left to the cursor to a X or _X type
+*/
+
+    static void
+chg_l_toXor_X ()
+{
+    int	tempc;
+
+    if (!curwin->w_cursor.col &&
+	(curwin->w_cursor.col+1 == STRLEN(ml_get_curline())))
+	return;
+
+    if (!curwin->w_cursor.col && p_ri)
+	return;
+
+    if (p_ri)
+	dec_cursor();
+    else
+	inc_cursor();
+
+    switch (gchar_cursor())
+    {
+	case ALEF_:
+		tempc = ALEF;
+		break;
+	case ALEF_U_H_:
+		tempc = ALEF_U_H;
+		break;
+	case _AYN_:
+		tempc = _AYN;
+		break;
+	case AYN_:
+		tempc = AYN;
+		break;
+	case _GHAYN_:
+		tempc = _GHAYN;
+		break;
+	case GHAYN_:
+		tempc = GHAYN;
+		break;
+	case _HE_:
+		tempc = _HE;
+		break;
+	case YE_:
+		tempc = YE;
+		break;
+	case IE_:
+		tempc = IE;
+		break;
+	case TEE_:
+		tempc = TEE;
+		break;
+	case YEE_:
+		tempc = YEE;
+		break;
+	default:
+		tempc = 0;
+    }
+
+    if (tempc)
+	put_and_redo(tempc);
+
+    if (p_ri)
+	inc_cursor();
+    else
+	dec_cursor();
+}
+
+/*
+** Change the character right to the cursor to a _X or _X_ type
+*/
+
+    static void
+chg_r_to_Xor_X_()
+{
+    int tempc, c;
+
+    if (curwin->w_cursor.col)
+    {
+	if (!p_ri)
+	    dec_cursor();
+
+	tempc = gchar_cursor();
+
+	if ((c = toF_Xor_X_(tempc)) != 0)
+	    put_and_redo(c);
+
+	if (!p_ri)
+	    inc_cursor();
+
+    }
+}
+
+/*
+** Map Farsi keyboard when in fkmap mode.
+*/
+
+    int
+fkmap(c)
+    int c;
+{
+    int		tempc;
+    static int	revins;
+
+    if (IS_SPECIAL(c))
+	return c;
+
+    if (VIM_ISDIGIT(c) || ((c == '.' || c == '+' || c == '-' ||
+	c == '^' || c == '%' || c == '#' || c == '=')  && revins))
+    {
+	if (!revins)
+	{
+	    if (curwin->w_cursor.col)
+	    {
+		if (!p_ri)
+		    dec_cursor();
+
+		    chg_c_toX_orX ();
+		    chg_l_toXor_X ();
+
+		if (!p_ri)
+		    inc_cursor();
+	    }
+	}
+
+	arrow_used = TRUE;
+	(void)stop_arrow();
+
+	if (!curwin->w_p_rl && revins)
+	    inc_cursor();
+
+	++revins;
+	p_ri=1;
+    }
+    else
+    {
+	if (revins)
+	{
+	    arrow_used = TRUE;
+	    (void)stop_arrow();
+
+	    revins = 0;
+	    if (curwin->w_p_rl)
+	    {
+		while ((F_isdigit(gchar_cursor())
+			    || (gchar_cursor() == F_PERIOD
+				|| gchar_cursor() == F_PLUS
+				|| gchar_cursor() == F_MINUS
+				|| gchar_cursor() == F_MUL
+				|| gchar_cursor() == F_DIVIDE
+				|| gchar_cursor() == F_PERCENT
+				|| gchar_cursor() == F_EQUALS))
+			&& gchar_cursor() != NUL)
+		    ++curwin->w_cursor.col;
+	    }
+	    else
+	    {
+		if (curwin->w_cursor.col)
+		    while ((F_isdigit(gchar_cursor())
+			    || (gchar_cursor() == F_PERIOD
+				|| gchar_cursor() == F_PLUS
+				|| gchar_cursor() == F_MINUS
+				|| gchar_cursor() == F_MUL
+				|| gchar_cursor() == F_DIVIDE
+				|| gchar_cursor() == F_PERCENT
+				|| gchar_cursor() == F_EQUALS))
+			    && --curwin->w_cursor.col)
+			;
+
+		if (!F_isdigit(gchar_cursor()))
+		    ++curwin->w_cursor.col;
+	    }
+	}
+    }
+
+    if (!revins)
+    {
+	if (curwin->w_p_rl)
+	    p_ri=0;
+	if (!curwin->w_p_rl)
+	    p_ri=1;
+    }
+
+    if ((c < 0x100) && (isalpha(c) || c == '&' ||   c == '^' ||	c == ';' ||
+			    c == '\''||	c == ',' || c == '[' ||
+			    c == ']' ||	c == '{' || c == '}'	))
+	chg_r_to_Xor_X_();
+
+    tempc = 0;
+
+    switch (c)
+    {
+	case '`':
+	case ' ':
+	case '.':
+	case '!':
+	case '"':
+	case '$':
+	case '%':
+	case '^':
+	case '&':
+	case '/':
+	case '(':
+	case ')':
+	case '=':
+	case '\\':
+	case '?':
+	case '+':
+	case '-':
+	case '_':
+	case '*':
+	case ':':
+	case '#':
+	case '~':
+	case '@':
+	case '<':
+	case '>':
+	case '{':
+	case '}':
+	case '|':
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	case 'B':
+	case 'E':
+	case 'F':
+	case 'H':
+	case 'I':
+	case 'K':
+	case 'L':
+	case 'M':
+	case 'O':
+	case 'P':
+	case 'Q':
+	case 'R':
+	case 'T':
+	case 'U':
+	case 'W':
+	case 'Y':
+	case  NL:
+	case  TAB:
+
+	    if (p_ri && c == NL && curwin->w_cursor.col)
+	    {
+		/*
+		** If the char before the cursor is _X_ or X_ do not change
+		** the one under the cursor with X type.
+		*/
+
+		dec_cursor();
+
+		if (F_isalpha(gchar_cursor()))
+		{
+		    inc_cursor();
+		    return NL;
+		}
+
+		inc_cursor();
+	    }
+
+	    if (!p_ri)
+	    if (!curwin->w_cursor.col)
+	    {
+		switch (c)
+		{
+		    case '0':	return FARSI_0;
+		    case '1':	return FARSI_1;
+		    case '2':	return FARSI_2;
+		    case '3':	return FARSI_3;
+		    case '4':	return FARSI_4;
+		    case '5':	return FARSI_5;
+		    case '6':	return FARSI_6;
+		    case '7':	return FARSI_7;
+		    case '8':	return FARSI_8;
+		    case '9':	return FARSI_9;
+		    case 'B':	return F_PSP;
+		    case 'E':	return JAZR_N;
+		    case 'F':	return ALEF_D_H;
+		    case 'H':	return ALEF_A;
+		    case 'I':	return TASH;
+		    case 'K':	return F_LQUOT;
+		    case 'L':	return F_RQUOT;
+		    case 'M':	return HAMZE;
+		    case 'O':	return '[';
+		    case 'P':	return ']';
+		    case 'Q':	return OO;
+		    case 'R':	return MAD_N;
+		    case 'T':	return OW;
+		    case 'U':	return MAD;
+		    case 'W':	return OW_OW;
+		    case 'Y':	return JAZR;
+		    case '`':	return F_PCN;
+		    case '!':	return F_EXCL;
+		    case '@':	return F_COMMA;
+		    case '#':	return F_DIVIDE;
+		    case '$':	return F_CURRENCY;
+		    case '%':	return F_PERCENT;
+		    case '^':	return F_MUL;
+		    case '&':	return F_BCOMMA;
+		    case '*':	return F_STAR;
+		    case '(':	return F_LPARENT;
+		    case ')':	return F_RPARENT;
+		    case '-':	return F_MINUS;
+		    case '_':	return F_UNDERLINE;
+		    case '=':	return F_EQUALS;
+		    case '+':	return F_PLUS;
+		    case '\\':	return F_BSLASH;
+		    case '|':	return F_PIPE;
+		    case ':':	return F_DCOLON;
+		    case '"':	return F_SEMICOLON;
+		    case '.':	return F_PERIOD;
+		    case '/':	return F_SLASH;
+		    case '<':	return F_LESS;
+		    case '>':	return F_GREATER;
+		    case '?':	return F_QUESTION;
+		    case ' ':	return F_BLANK;
+		}
+		break;
+	    }
+	    if (!p_ri)
+		dec_cursor();
+
+	    switch ((tempc = gchar_cursor()))
+	    {
+		case _BE:
+		case _PE:
+		case _TE:
+		case _SE:
+		case _JIM:
+		case _CHE:
+		case _HE_J:
+		case _XE:
+		case _SIN:
+		case _SHIN:
+		case _SAD:
+		case _ZAD:
+		case _FE:
+		case _GHAF:
+		case _KAF:
+		case _KAF_H:
+		case _GAF:
+		case _LAM:
+		case _MIM:
+		case _NOON:
+		case _HE:
+		case _HE_:
+		case _TA:
+		case _ZA:
+			put_curr_and_l_to_X(toF_TyA(tempc));
+			break;
+		case _AYN:
+		case _AYN_:
+
+			if (!p_ri)
+			    if (!curwin->w_cursor.col)
+			    {
+				put_curr_and_l_to_X(AYN);
+				break;
+			    }
+
+			if (p_ri)
+			    inc_cursor();
+			else
+			    dec_cursor();
+
+			if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+			    tempc = AYN_;
+			else
+			    tempc = AYN;
+
+			if (p_ri)
+			    dec_cursor();
+			else
+			    inc_cursor();
+
+			put_curr_and_l_to_X(tempc);
+
+			break;
+		case _GHAYN:
+		case _GHAYN_:
+
+			if (!p_ri)
+			    if (!curwin->w_cursor.col)
+			    {
+				put_curr_and_l_to_X(GHAYN);
+				break;
+			    }
+
+			if (p_ri)
+			    inc_cursor();
+			else
+			    dec_cursor();
+
+			if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+			    tempc = GHAYN_;
+			else
+			    tempc = GHAYN;
+
+			if (p_ri)
+			    dec_cursor();
+			else
+			    inc_cursor();
+
+			put_curr_and_l_to_X(tempc);
+			break;
+		case _YE:
+		case _IE:
+		case _YEE:
+			if (!p_ri)
+			    if (!curwin->w_cursor.col)
+			    {
+				put_curr_and_l_to_X((tempc == _YE ? YE :
+					    (tempc == _IE ? IE : YEE)));
+				break;
+			    }
+
+			if (p_ri)
+			    inc_cursor();
+			else
+			    dec_cursor();
+
+			if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+				tempc = (tempc == _YE ? YE_ :
+				    (tempc == _IE ? IE_ : YEE_));
+			else
+				tempc = (tempc == _YE ? YE :
+				    (tempc == _IE ? IE : YEE));
+
+			if (p_ri)
+			    dec_cursor();
+			else
+			    inc_cursor();
+
+			put_curr_and_l_to_X(tempc);
+			break;
+		}
+
+		if (!p_ri)
+		    inc_cursor();
+
+		tempc = 0;
+
+		switch (c)
+		{
+		    case '0':	return FARSI_0;
+		    case '1':	return FARSI_1;
+		    case '2':	return FARSI_2;
+		    case '3':	return FARSI_3;
+		    case '4':	return FARSI_4;
+		    case '5':	return FARSI_5;
+		    case '6':	return FARSI_6;
+		    case '7':	return FARSI_7;
+		    case '8':	return FARSI_8;
+		    case '9':	return FARSI_9;
+		    case 'B':	return F_PSP;
+		    case 'E':	return JAZR_N;
+		    case 'F':	return ALEF_D_H;
+		    case 'H':	return ALEF_A;
+		    case 'I':	return TASH;
+		    case 'K':	return F_LQUOT;
+		    case 'L':	return F_RQUOT;
+		    case 'M':	return HAMZE;
+		    case 'O':	return '[';
+		    case 'P':	return ']';
+		    case 'Q':	return OO;
+		    case 'R':	return MAD_N;
+		    case 'T':	return OW;
+		    case 'U':	return MAD;
+		    case 'W':	return OW_OW;
+		    case 'Y':	return JAZR;
+		    case '`':	return F_PCN;
+		    case '!':	return F_EXCL;
+		    case '@':	return F_COMMA;
+		    case '#':	return F_DIVIDE;
+		    case '$':	return F_CURRENCY;
+		    case '%':	return F_PERCENT;
+		    case '^':	return F_MUL;
+		    case '&':	return F_BCOMMA;
+		    case '*':	return F_STAR;
+		    case '(':	return F_LPARENT;
+		    case ')':	return F_RPARENT;
+		    case '-':	return F_MINUS;
+		    case '_':	return F_UNDERLINE;
+		    case '=':	return F_EQUALS;
+		    case '+':	return F_PLUS;
+		    case '\\':	return F_BSLASH;
+		    case '|':	return F_PIPE;
+		    case ':':	return F_DCOLON;
+		    case '"':	return F_SEMICOLON;
+		    case '.':	return F_PERIOD;
+		    case '/':	return F_SLASH;
+		    case '<':	return F_LESS;
+		    case '>':	return F_GREATER;
+		    case '?':	return F_QUESTION;
+		    case ' ':	return F_BLANK;
+		}
+		break;
+
+	case 'a':
+		tempc = _SHIN;
+	    break;
+	case 'A':
+		tempc = WAW_H;
+	    break;
+	case 'b':
+		tempc = ZAL;
+	    break;
+	case 'c':
+		tempc = ZE;
+	    break;
+	case 'C':
+		tempc = JE;
+	    break;
+	case 'd':
+		tempc = _YE;
+	    break;
+	case 'D':
+		tempc = _YEE;
+	    break;
+	case 'e':
+		tempc = _SE;
+	    break;
+	case 'f':
+		tempc = _BE;
+	    break;
+	case 'g':
+		tempc = _LAM;
+	    break;
+	case 'G':
+	    if (!curwin->w_cursor.col  &&  STRLEN(ml_get_curline()))
+		{
+
+		if (gchar_cursor() == _LAM)
+		    chg_c_toX_orX ();
+		else
+		    if (p_ri)
+			chg_c_to_X_or_X ();
+	    }
+
+	    if (!p_ri)
+		if (!curwin->w_cursor.col)
+		    return ALEF_U_H;
+
+	    if (!p_ri)
+		dec_cursor();
+
+	    if (gchar_cursor() == _LAM)
+	    {
+		chg_c_toX_orX ();
+		chg_l_toXor_X ();
+		    tempc = ALEF_U_H;
+	    }
+	    else
+		if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+		{
+			tempc = ALEF_U_H_;
+		    chg_l_toXor_X ();
+		}
+		else
+			tempc = ALEF_U_H;
+
+	    if (!p_ri)
+		inc_cursor();
+
+	    return tempc;
+	case 'h':
+	    if (!curwin->w_cursor.col  &&  STRLEN(ml_get_curline()))
+		{
+		if (p_ri)
+		    chg_c_to_X_or_X ();
+
+	    }
+
+	    if (!p_ri)
+		if (!curwin->w_cursor.col)
+		    return ALEF;
+
+	    if (!p_ri)
+		dec_cursor();
+
+	    if (gchar_cursor() == _LAM)
+	    {
+		chg_l_toXor_X();
+		del_char(FALSE);
+		AppendCharToRedobuff(K_BS);
+
+		if (!p_ri)
+		    dec_cursor();
+
+		    tempc = LA;
+	    }
+	    else
+	    {
+		if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+		{
+			tempc = ALEF_;
+		    chg_l_toXor_X ();
+		}
+		else
+			tempc = ALEF;
+	    }
+
+	    if (!p_ri)
+		inc_cursor();
+
+	    return tempc;
+	case 'i':
+	    if (!curwin->w_cursor.col  &&  STRLEN(ml_get_curline()))
+		{
+		if (!p_ri && !F_is_TyE(tempc))
+		    chg_c_to_X_orX_ ();
+		if (p_ri)
+		    chg_c_to_X_or_X ();
+
+	    }
+
+	    if (!p_ri && !curwin->w_cursor.col)
+		return _HE;
+
+	    if (!p_ri)
+		dec_cursor();
+
+	    if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+		    tempc = _HE_;
+	    else
+		    tempc = _HE;
+
+	    if (!p_ri)
+		inc_cursor();
+	    break;
+	case 'j':
+		tempc = _TE;
+	    break;
+	case 'J':
+	    if (!curwin->w_cursor.col  &&  STRLEN(ml_get_curline()))
+		{
+		if (p_ri)
+		    chg_c_to_X_or_X ();
+
+	    }
+
+	    if (!p_ri)
+		if (!curwin->w_cursor.col)
+		    return TEE;
+
+	    if (!p_ri)
+		dec_cursor();
+
+	    if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+	    {
+		    tempc = TEE_;
+		chg_l_toXor_X ();
+	    }
+	    else
+			tempc = TEE;
+
+	    if (!p_ri)
+		inc_cursor();
+
+	    return tempc;
+	case 'k':
+		tempc = _NOON;
+	    break;
+	case 'l':
+		tempc = _MIM;
+	    break;
+	case 'm':
+		tempc = _PE;
+	    break;
+	case 'n':
+	case 'N':
+		tempc = DAL;
+	    break;
+	case 'o':
+		tempc = _XE;
+	    break;
+	case 'p':
+		tempc = _HE_J;
+	    break;
+	case 'q':
+		tempc = _ZAD;
+	    break;
+	case 'r':
+		tempc = _GHAF;
+	    break;
+	case 's':
+		tempc = _SIN;
+	    break;
+	case 'S':
+		tempc = _IE;
+	    break;
+	case 't':
+		tempc = _FE;
+	    break;
+	case 'u':
+		if (!curwin->w_cursor.col  &&  STRLEN(ml_get_curline()))
+		{
+		    if (!p_ri && !F_is_TyE(tempc))
+			chg_c_to_X_orX_ ();
+		    if (p_ri)
+			chg_c_to_X_or_X ();
+
+		}
+
+		if (!p_ri && !curwin->w_cursor.col)
+		    return _AYN;
+
+		if (!p_ri)
+		    dec_cursor();
+
+		if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+		    tempc = _AYN_;
+		else
+		    tempc = _AYN;
+
+		if (!p_ri)
+		    inc_cursor();
+	    break;
+	case 'v':
+	case 'V':
+		tempc = RE;
+	    break;
+	case 'w':
+		tempc = _SAD;
+	    break;
+	case 'x':
+	case 'X':
+		tempc = _TA;
+	    break;
+	case 'y':
+	    if (!curwin->w_cursor.col  &&  STRLEN(ml_get_curline()))
+		{
+		if (!p_ri && !F_is_TyE(tempc))
+		    chg_c_to_X_orX_ ();
+		if (p_ri)
+		    chg_c_to_X_or_X ();
+
+	    }
+
+	    if (!p_ri && !curwin->w_cursor.col)
+		return _GHAYN;
+
+	    if (!p_ri)
+		dec_cursor();
+
+	    if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+		tempc = _GHAYN_;
+	    else
+		tempc = _GHAYN;
+
+	    if (!p_ri)
+		inc_cursor();
+
+	    break;
+	case 'z':
+		tempc = _ZA;
+	    break;
+	case 'Z':
+		tempc = _KAF_H;
+	    break;
+	case ';':
+		tempc = _KAF;
+	    break;
+	case '\'':
+		tempc = _GAF;
+	    break;
+	case ',':
+		tempc = WAW;
+	    break;
+	case '[':
+		tempc = _JIM;
+	    break;
+	case ']':
+		tempc = _CHE;
+	    break;
+    }
+
+    if ((F_isalpha(tempc) || F_isdigit(tempc)))
+    {
+	if (!curwin->w_cursor.col  &&  STRLEN(ml_get_curline()))
+	    {
+	    if (!p_ri && !F_is_TyE(tempc))
+		chg_c_to_X_orX_ ();
+	    if (p_ri)
+		chg_c_to_X_or_X ();
+	}
+
+	if (curwin->w_cursor.col)
+	{
+	    if (!p_ri)
+		dec_cursor();
+
+	    if (F_is_TyE(tempc))
+		chg_l_toXor_X ();
+	    else
+		chg_l_to_X_orX_ ();
+
+	    if (!p_ri)
+		inc_cursor();
+	}
+    }
+    if (tempc)
+	return tempc;
+    return c;
+}
+
+/*
+** Convert a none leading Farsi char into a leading type.
+*/
+    static int
+toF_leading(c)
+    int	    c;
+{
+    switch (c)
+    {
+	case ALEF_:	return ALEF;
+	case ALEF_U_H_:	    return ALEF_U_H;
+	case BE:    return _BE;
+	case PE:    return _PE;
+	case TE:    return _TE;
+	case SE:    return _SE;
+	case JIM:   return _JIM;
+	case CHE:   return _CHE;
+	case HE_J:  return _HE_J;
+	case XE:    return _XE;
+	case SIN:   return _SIN;
+	case SHIN:  return _SHIN;
+	case SAD:   return _SAD;
+	case ZAD:   return _ZAD;
+
+	case AYN:
+	case AYN_:
+	case _AYN_: return _AYN;
+
+	case GHAYN:
+	case GHAYN_:
+	case _GHAYN_:	return _GHAYN;
+
+	case FE:    return _FE;
+	case GHAF:  return _GHAF;
+	case KAF:   return _KAF;
+	case GAF:   return _GAF;
+	case LAM:   return _LAM;
+	case MIM:   return _MIM;
+	case NOON:  return _NOON;
+
+	case _HE_:
+	case F_HE:	return _HE;
+
+	case YE:
+	case YE_:	return _YE;
+
+	case IE_:
+	case IE:	return _IE;
+
+	case YEE:
+	case YEE_:	return _YEE;
+    }
+    return c;
+}
+
+/*
+** Convert a given Farsi char into right joining type.
+*/
+    static int
+toF_Rjoin(c)
+    int	    c;
+{
+    switch (c)
+    {
+	case ALEF:  return ALEF_;
+	case ALEF_U_H:	return ALEF_U_H_;
+	case BE:    return _BE;
+	case PE:    return _PE;
+	case TE:    return _TE;
+	case SE:    return _SE;
+	case JIM:   return _JIM;
+	case CHE:   return _CHE;
+	case HE_J:  return _HE_J;
+	case XE:    return _XE;
+	case SIN:   return _SIN;
+	case SHIN:  return _SHIN;
+	case SAD:   return _SAD;
+	case ZAD:   return _ZAD;
+
+	case AYN:
+	case AYN_:
+	case _AYN:  return _AYN_;
+
+	case GHAYN:
+	case GHAYN_:
+	case _GHAYN_:	return _GHAYN_;
+
+	case FE:    return _FE;
+	case GHAF:  return _GHAF;
+	case KAF:   return _KAF;
+	case GAF:   return _GAF;
+	case LAM:   return _LAM;
+	case MIM:   return _MIM;
+	case NOON:  return _NOON;
+
+	case _HE:
+	case F_HE:	return _HE_;
+
+	case YE:
+	case YE_:	return _YE;
+
+	case IE_:
+	case IE:	return _IE;
+
+	case TEE:	return TEE_;
+
+	case YEE:
+	case YEE_:	return _YEE;
+    }
+    return c;
+}
+
+/*
+** Can a given Farsi character join via its left edj.
+*/
+    static int
+canF_Ljoin(c)
+    int	c;
+{
+    switch (c)
+    {
+	case _BE:
+	case BE:
+	case PE:
+	case _PE:
+	case TE:
+	case _TE:
+	case SE:
+	case _SE:
+	case JIM:
+	case _JIM:
+	case CHE:
+	case _CHE:
+	case HE_J:
+	case _HE_J:
+	case XE:
+	case _XE:
+	case SIN:
+	case _SIN:
+	case SHIN:
+	case _SHIN:
+	case SAD:
+	case _SAD:
+	case ZAD:
+	case _ZAD:
+	case _TA:
+	case _ZA:
+	case AYN:
+	case _AYN:
+	case _AYN_:
+	case AYN_:
+	case GHAYN:
+	case GHAYN_:
+	case _GHAYN_:
+	case _GHAYN:
+	case FE:
+	case _FE:
+	case GHAF:
+	case _GHAF:
+	case _KAF_H:
+	case KAF:
+	case _KAF:
+	case GAF:
+	case _GAF:
+	case LAM:
+	case _LAM:
+	case MIM:
+	case _MIM:
+	case NOON:
+	case _NOON:
+	case IE:
+	case _IE:
+	case IE_:
+	case YE:
+	case _YE:
+	case YE_:
+	case YEE:
+	case _YEE:
+	case YEE_:
+	case F_HE:
+	case _HE:
+	case _HE_:
+	    return TRUE;
+    }
+    return FALSE;
+}
+
+/*
+** Can a given Farsi character join via its right edj.
+*/
+    static int
+canF_Rjoin(c)
+    int	    c;
+{
+    switch (c)
+    {
+	case ALEF:
+	case ALEF_:
+	case ALEF_U_H:
+	case ALEF_U_H_:
+	case DAL:
+	case ZAL:
+	case RE:
+	case JE:
+	case ZE:
+	case TEE:
+	case TEE_:
+	case WAW:
+	case WAW_H:
+	    return TRUE;
+    }
+
+    return canF_Ljoin(c);
+
+}
+
+/*
+** is a given Farsi character a terminating type.
+*/
+    static int
+F_isterm(c)
+    int	    c;
+{
+    switch (c)
+    {
+	case ALEF:
+	case ALEF_:
+	case ALEF_U_H:
+	case ALEF_U_H_:
+	case DAL:
+	case ZAL:
+	case RE:
+	case JE:
+	case ZE:
+	case WAW:
+	case WAW_H:
+	case TEE:
+	case TEE_:
+	    return TRUE;
+    }
+
+    return FALSE;
+}
+
+/*
+** Convert the given Farsi character into a ending type .
+*/
+    static int
+toF_ending(c)
+    int	    c;
+{
+
+    switch (c)
+    {
+	case _BE:
+		return BE;
+	case _PE:
+		return PE;
+	case _TE:
+		return TE;
+	case _SE:
+		return SE;
+	case _JIM:
+		return JIM;
+	case _CHE:
+		return CHE;
+	case _HE_J:
+		return HE_J;
+	case _XE:
+		return XE;
+	case _SIN:
+		return SIN;
+	case _SHIN:
+		return SHIN;
+	case _SAD:
+		return SAD;
+	case _ZAD:
+		return ZAD;
+	case _AYN:
+		return AYN;
+	case _AYN_:
+		return AYN_;
+	case _GHAYN:
+		return GHAYN;
+	case _GHAYN_:
+		return GHAYN_;
+	case _FE:
+		return FE;
+	case _GHAF:
+		return GHAF;
+	case _KAF_H:
+	case _KAF:
+		return KAF;
+	case _GAF:
+		return GAF;
+	case _LAM:
+		return LAM;
+	case _MIM:
+		return MIM;
+	case _NOON:
+		return NOON;
+	case _YE:
+		return YE_;
+	case YE_:
+		return YE;
+	case _YEE:
+		return YEE_;
+	case YEE_:
+		return YEE;
+	case TEE:
+		return TEE_;
+	case _IE:
+		return IE_;
+	case IE_:
+		return IE;
+	case _HE:
+	case _HE_:
+		return F_HE;
+    }
+    return c;
+}
+
+/*
+** Convert the Farsi 3342 standard into Farsi VIM.
+*/
+    void
+conv_to_pvim()
+{
+    char_u	*ptr;
+    int		lnum, llen, i;
+
+    for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
+    {
+	ptr = ml_get((linenr_T)lnum);
+
+	llen = (int)STRLEN(ptr);
+
+	for ( i = 0; i < llen-1; i++)
+	{
+	    if (canF_Ljoin(ptr[i]) && canF_Rjoin(ptr[i+1]))
+	    {
+		ptr[i] = toF_leading(ptr[i]);
+		++i;
+
+		while(canF_Rjoin(ptr[i]) && (i < llen))
+		{
+		    ptr[i] = toF_Rjoin(ptr[i]);
+		    if (F_isterm(ptr[i]) || !F_isalpha(ptr[i]))
+			break;
+		    ++i;
+		}
+		if (!F_isalpha(ptr[i]) || !canF_Rjoin(ptr[i]))
+		    ptr[i-1] = toF_ending(ptr[i-1]);
+	    }
+	    else
+		ptr[i] = toF_TyA(ptr[i]);
+	}
+    }
+
+    /*
+     * Following lines contains Farsi encoded character.
+     */
+
+    do_cmdline_cmd((char_u *)"%s/\202\231/\232/g");
+    do_cmdline_cmd((char_u *)"%s/\201\231/\370\334/g");
+
+    /* Assume the screen has been messed up: clear it and redraw. */
+    redraw_later(CLEAR);
+    MSG_ATTR(farsi_text_1, hl_attr(HLF_S));
+}
+
+/*
+ * Convert the Farsi VIM into Farsi 3342 standad.
+ */
+    void
+conv_to_pstd()
+{
+    char_u	*ptr;
+    int		lnum, llen, i;
+
+    /*
+     * Following line contains Farsi encoded character.
+     */
+
+    do_cmdline_cmd((char_u *)"%s/\232/\202\231/g");
+
+    for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
+    {
+	ptr = ml_get((linenr_T)lnum);
+
+	llen = (int)STRLEN(ptr);
+
+	for ( i = 0; i < llen; i++)
+	{
+	    ptr[i] = toF_TyA(ptr[i]);
+
+	}
+    }
+
+    /* Assume the screen has been messed up: clear it and redraw. */
+    redraw_later(CLEAR);
+    MSG_ATTR(farsi_text_2, hl_attr(HLF_S));
+}
+
+/*
+ * left-right swap the characters in buf[len].
+ */
+    static void
+lrswapbuf(buf, len)
+    char_u	*buf;
+    int		len;
+{
+    char_u	*s, *e;
+    int		c;
+
+    s = buf;
+    e = buf + len - 1;
+
+    while (e > s)
+    {
+	c = *s;
+	*s = *e;
+	*e = c;
+	++s;
+	--e;
+    }
+}
+
+/*
+ * swap all the characters in reverse direction
+ */
+    char_u *
+lrswap(ibuf)
+    char_u	*ibuf;
+{
+    if (ibuf != NULL && *ibuf != NUL)
+	lrswapbuf(ibuf, (int)STRLEN(ibuf));
+    return ibuf;
+}
+
+/*
+ * swap all the Farsi characters in reverse direction
+ */
+    char_u *
+lrFswap(cmdbuf, len)
+    char_u	*cmdbuf;
+    int		len;
+{
+    int		i, cnt;
+
+    if (cmdbuf == NULL)
+	return cmdbuf;
+
+    if (len == 0 && (len = (int)STRLEN(cmdbuf)) == 0)
+	return cmdbuf;
+
+    for (i = 0; i < len; i++)
+    {
+	for (cnt = 0; i + cnt < len
+			&& (F_isalpha(cmdbuf[i + cnt])
+			    || F_isdigit(cmdbuf[i + cnt])
+			    || cmdbuf[i + cnt] == ' '); ++cnt)
+	    ;
+
+	lrswapbuf(cmdbuf + i, cnt);
+	i += cnt;
+    }
+    return cmdbuf;
+}
+
+/*
+ * Reverse the characters in the search path and substitute section accordingly
+ */
+    char_u *
+lrF_sub(ibuf)
+    char_u	*ibuf;
+{
+    char_u	*p, *ep;
+    int		i, cnt;
+
+    p = ibuf;
+
+    /* Find the boundary of the search path */
+    while (((p = vim_strchr(p + 1, '/')) != NULL) && p[-1] == '\\')
+	;
+
+    if (p == NULL)
+	return ibuf;
+
+    /* Reverse the Farsi characters in the search path. */
+    lrFswap(ibuf, (int)(p-ibuf));
+
+    /* Now find the boundary of the substitute section */
+    if ((ep = (char_u *)strrchr((char *)++p, '/')) != NULL)
+	cnt = (int)(ep - p);
+    else
+	cnt = (int)STRLEN(p);
+
+    /* Reverse the characters in the substitute section and take care of '\' */
+    for (i = 0; i < cnt-1; i++)
+	if (p[i] == '\\')
+	{
+	    p[i] = p[i+1] ;
+	    p[++i] = '\\';
+	}
+
+    lrswapbuf(p, cnt);
+
+    return ibuf;
+}
+
+/*
+ * Map Farsi keyboard when in cmd_fkmap mode.
+ */
+    int
+cmdl_fkmap(c)
+    int c;
+{
+    int	    tempc;
+
+    switch (c)
+    {
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	case '`':
+	case ' ':
+	case '.':
+	case '!':
+	case '"':
+	case '$':
+	case '%':
+	case '^':
+	case '&':
+	case '/':
+	case '(':
+	case ')':
+	case '=':
+	case '\\':
+	case '?':
+	case '+':
+	case '-':
+	case '_':
+	case '*':
+	case ':':
+	case '#':
+	case '~':
+	case '@':
+	case '<':
+	case '>':
+	case '{':
+	case '}':
+	case '|':
+	case 'B':
+	case 'E':
+	case 'F':
+	case 'H':
+	case 'I':
+	case 'K':
+	case 'L':
+	case 'M':
+	case 'O':
+	case 'P':
+	case 'Q':
+	case 'R':
+	case 'T':
+	case 'U':
+	case 'W':
+	case 'Y':
+	case  NL:
+	case  TAB:
+
+	       switch ((tempc = cmd_gchar(AT_CURSOR)))
+	       {
+	    case _BE:
+	    case _PE:
+	    case _TE:
+	    case _SE:
+	    case _JIM:
+	    case _CHE:
+	    case _HE_J:
+	    case _XE:
+	    case _SIN:
+	    case _SHIN:
+	    case _SAD:
+	    case _ZAD:
+	    case _AYN:
+	    case _GHAYN:
+	    case _FE:
+	    case _GHAF:
+	    case _KAF:
+	    case _GAF:
+	    case _LAM:
+	    case _MIM:
+	    case _NOON:
+	    case _HE:
+	    case _HE_:
+			cmd_pchar(toF_TyA(tempc), AT_CURSOR);
+		break;
+	    case _AYN_:
+			cmd_pchar(AYN_, AT_CURSOR);
+		break;
+	    case _GHAYN_:
+			cmd_pchar(GHAYN_, AT_CURSOR);
+		break;
+	    case _IE:
+		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR+1))
+			    cmd_pchar(IE_, AT_CURSOR);
+		else
+			    cmd_pchar(IE, AT_CURSOR);
+		break;
+	    case _YEE:
+		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR+1))
+			    cmd_pchar(YEE_, AT_CURSOR);
+			else
+			    cmd_pchar(YEE, AT_CURSOR);
+		break;
+	    case _YE:
+		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR+1))
+			    cmd_pchar(YE_, AT_CURSOR);
+			else
+			    cmd_pchar(YE, AT_CURSOR);
+	    }
+
+	    switch (c)
+	    {
+		case '0':   return FARSI_0;
+		case '1':   return FARSI_1;
+		case '2':   return FARSI_2;
+		case '3':   return FARSI_3;
+		case '4':   return FARSI_4;
+		case '5':   return FARSI_5;
+		case '6':   return FARSI_6;
+		case '7':   return FARSI_7;
+		case '8':   return FARSI_8;
+		case '9':   return FARSI_9;
+		case 'B':   return F_PSP;
+		case 'E':   return JAZR_N;
+		case 'F':   return ALEF_D_H;
+		case 'H':   return ALEF_A;
+		case 'I':   return TASH;
+		case 'K':   return F_LQUOT;
+		case 'L':   return F_RQUOT;
+		case 'M':   return HAMZE;
+		case 'O':   return '[';
+		case 'P':   return ']';
+		case 'Q':   return OO;
+		case 'R':   return MAD_N;
+		case 'T':   return OW;
+		case 'U':   return MAD;
+		case 'W':   return OW_OW;
+		case 'Y':   return JAZR;
+		case '`':   return F_PCN;
+		case '!':   return F_EXCL;
+		case '@':   return F_COMMA;
+		case '#':   return F_DIVIDE;
+		case '$':   return F_CURRENCY;
+		case '%':   return F_PERCENT;
+		case '^':   return F_MUL;
+		case '&':   return F_BCOMMA;
+		case '*':   return F_STAR;
+		case '(':   return F_LPARENT;
+		case ')':   return F_RPARENT;
+		case '-':   return F_MINUS;
+		case '_':   return F_UNDERLINE;
+		case '=':   return F_EQUALS;
+		case '+':   return F_PLUS;
+		case '\\':  return F_BSLASH;
+		case '|':   return F_PIPE;
+		case ':':   return F_DCOLON;
+		case '"':   return F_SEMICOLON;
+		case '.':   return F_PERIOD;
+		case '/':   return F_SLASH;
+		case '<':   return F_LESS;
+		case '>':   return F_GREATER;
+		case '?':   return F_QUESTION;
+		case ' ':   return F_BLANK;
+	    }
+
+	    break;
+
+	case 'a':   return _SHIN;
+	case 'A':   return WAW_H;
+	case 'b':   return ZAL;
+	case 'c':   return ZE;
+	case 'C':   return JE;
+	case 'd':   return _YE;
+	case 'D':   return _YEE;
+	case 'e':   return _SE;
+	case 'f':   return _BE;
+	case 'g':   return _LAM;
+	case 'G':
+		    if (cmd_gchar(AT_CURSOR) == _LAM )
+		{
+		    cmd_pchar(LAM, AT_CURSOR);
+			    return ALEF_U_H;
+		}
+
+		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
+			return ALEF_U_H_;
+		else
+			return ALEF_U_H;
+	case 'h':
+		    if (cmd_gchar(AT_CURSOR) == _LAM )
+		{
+		    cmd_pchar(LA, AT_CURSOR);
+		    redrawcmdline();
+		    return K_IGNORE;
+		}
+
+		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
+			return ALEF_;
+		else
+			return ALEF;
+	case 'i':
+		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
+			return _HE_;
+		else
+			return _HE;
+	case 'j':   return _TE;
+	case 'J':
+		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
+			return TEE_;
+		else
+			return TEE;
+	case 'k':   return _NOON;
+	case 'l':   return _MIM;
+	case 'm':   return _PE;
+	case 'n':
+	case 'N':   return DAL;
+	case 'o':   return _XE;
+	case 'p':   return _HE_J;
+	case 'q':   return _ZAD;
+	case 'r':   return _GHAF;
+	case 's':   return _SIN;
+	case 'S':   return _IE;
+	case 't':   return _FE;
+	case 'u':
+		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
+			return _AYN_;
+		else
+			return _AYN;
+	case 'v':
+	case 'V':   return RE;
+	case 'w':   return _SAD;
+	case 'x':
+	case 'X':   return _TA;
+	case 'y':
+		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
+			return _GHAYN_;
+		else
+			return _GHAYN;
+	case 'z':
+	case 'Z':   return _ZA;
+	case ';':   return _KAF;
+	case '\'':  return _GAF;
+	case ',':   return WAW;
+	case '[':   return _JIM;
+	case ']':   return _CHE;
+	}
+
+	return c;
+}
+
+/*
+ * F_isalpha returns TRUE if 'c' is a Farsi alphabet
+ */
+    int
+F_isalpha(c)
+    int	c;
+{
+    return (( c >= TEE_ && c <= _YE)
+	    || (c >= ALEF_A && c <= YE)
+	    || (c >= _IE && c <= YE_));
+}
+
+/*
+ * F_isdigit returns TRUE if 'c' is a Farsi digit
+ */
+    int
+F_isdigit(c)
+    int	c;
+{
+    return (c >= FARSI_0 && c <= FARSI_9);
+}
+
+/*
+ * F_ischar returns TRUE if 'c' is a Farsi character.
+ */
+    int
+F_ischar(c)
+    int	c;
+{
+    return (c >= TEE_ && c <= YE_);
+}
+
+    void
+farsi_fkey(cap)
+    cmdarg_T	*cap;
+{
+    int		c = cap->cmdchar;
+
+    if (c == K_F8)
+    {
+	if (p_altkeymap)
+	{
+	    if (curwin->w_farsi & W_R_L)
+	    {
+		p_fkmap = 0;
+		do_cmdline_cmd((char_u *)"set norl");
+		MSG("");
+	    }
+	    else
+	    {
+		p_fkmap = 1;
+		do_cmdline_cmd((char_u *)"set rl");
+		MSG("");
+	    }
+
+	    curwin->w_farsi = curwin->w_farsi ^ W_R_L;
+	}
+    }
+
+    if (c == K_F9)
+    {
+	if (p_altkeymap && curwin->w_p_rl)
+	{
+	    curwin->w_farsi = curwin->w_farsi ^ W_CONV;
+	    if (curwin->w_farsi & W_CONV)
+		conv_to_pvim();
+	    else
+		conv_to_pstd();
+	}
+    }
+}