1/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved	by Bram Moolenaar
4 *
5 * Do ":help uganda"  in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * farsi.c: functions for Farsi language
12 *
13 * Included by main.c, when FEAT_FKMAP is defined.
14 */
15
16static int toF_Xor_X_ __ARGS((int c));
17static int F_is_TyE __ARGS((int c));
18static int F_is_TyC_TyD __ARGS((int c));
19static int F_is_TyB_TyC_TyD __ARGS((int src, int offset));
20static int toF_TyB __ARGS((int c));
21static void put_curr_and_l_to_X __ARGS((int c));
22static void put_and_redo __ARGS((int c));
23static void chg_c_toX_orX __ARGS((void));
24static void chg_c_to_X_orX_ __ARGS((void));
25static void chg_c_to_X_or_X __ARGS((void));
26static void chg_l_to_X_orX_ __ARGS((void));
27static void chg_l_toXor_X __ARGS((void));
28static void chg_r_to_Xor_X_ __ARGS((void));
29static int toF_leading __ARGS((int c));
30static int toF_Rjoin __ARGS((int c));
31static int canF_Ljoin __ARGS((int c));
32static int canF_Rjoin __ARGS((int c));
33static int F_isterm __ARGS((int c));
34static int toF_ending __ARGS((int c));
35static void lrswapbuf __ARGS((char_u *buf, int len));
36
37/*
38** Convert the given Farsi character into a _X or _X_ type
39*/
40    static int
41toF_Xor_X_(c)
42    int	c;
43{
44    int tempc;
45
46    switch (c)
47    {
48	case BE:
49		return _BE;
50	case PE:
51		return _PE;
52	case TE:
53		return _TE;
54	case SE:
55		return _SE;
56	case JIM:
57		return _JIM;
58	case CHE:
59		return _CHE;
60	case HE_J:
61		return _HE_J;
62	case XE:
63		return _XE;
64	case SIN:
65		return _SIN;
66	case SHIN:
67		return _SHIN;
68	case SAD:
69		return _SAD;
70	case ZAD:
71		return _ZAD;
72	case AYN:
73		return _AYN;
74	case AYN_:
75		return _AYN_;
76	case GHAYN:
77		return _GHAYN;
78	case GHAYN_:
79		return _GHAYN_;
80	case FE:
81		return _FE;
82	case GHAF:
83		return _GHAF;
84	case KAF:
85		return _KAF;
86	case GAF:
87		return _GAF;
88	case LAM:
89		return _LAM;
90	case MIM:
91		return _MIM;
92	case NOON:
93		return _NOON;
94	case YE:
95	case YE_:
96		return _YE;
97	case YEE:
98	case YEE_:
99		return _YEE;
100	case IE:
101	case IE_:
102		return _IE;
103	case F_HE:
104		tempc = _HE;
105
106		if (p_ri && (curwin->w_cursor.col + 1
107					 < (colnr_T)STRLEN(ml_get_curline())))
108		{
109		    inc_cursor();
110
111		    if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
112			tempc = _HE_;
113
114		    dec_cursor();
115		}
116		if (!p_ri && STRLEN(ml_get_curline()))
117		{
118		    dec_cursor();
119
120		    if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
121			tempc = _HE_;
122
123		    inc_cursor();
124		}
125
126		return tempc;
127    }
128    return 0;
129}
130
131/*
132** Convert the given Farsi character into Farsi capital character .
133*/
134    int
135toF_TyA(c)
136    int	c ;
137{
138    switch (c)
139    {
140	case ALEF_:
141		return ALEF;
142	case ALEF_U_H_:
143		return ALEF_U_H;
144	case _BE:
145		return BE;
146	case _PE:
147		return PE;
148	case _TE:
149		return TE;
150	case _SE:
151		return SE;
152	case _JIM:
153		return JIM;
154	case _CHE:
155		return CHE;
156	case _HE_J:
157		return HE_J;
158	case _XE:
159		return XE;
160	case _SIN:
161		return SIN;
162	case _SHIN:
163		return SHIN;
164	case _SAD:
165		return SAD;
166	case _ZAD:
167		return ZAD;
168	case _AYN:
169	case AYN_:
170	case _AYN_:
171		return AYN;
172	case _GHAYN:
173	case GHAYN_:
174	case _GHAYN_:
175		return GHAYN;
176	case _FE:
177		return FE;
178	case _GHAF:
179		return GHAF;
180/* I am not sure what it is !!!	    case _KAF_H: */
181	case _KAF:
182		return KAF;
183	case _GAF:
184		return GAF;
185	case _LAM:
186		return LAM;
187	case _MIM:
188		return MIM;
189	case _NOON:
190		return NOON;
191	case _YE:
192	case YE_:
193		return YE;
194	case _YEE:
195	case YEE_:
196		return YEE;
197	case TEE_:
198		return TEE;
199	case _IE:
200	case IE_:
201		return IE;
202	case _HE:
203	case _HE_:
204		return F_HE;
205    }
206    return c;
207}
208
209/*
210** Is the character under the cursor+offset in the given buffer a join type.
211** That is a character that is combined with the others.
212** Note: the offset is used only for command line buffer.
213*/
214    static int
215F_is_TyB_TyC_TyD(src, offset)
216    int		src, offset;
217{
218    int		c;
219
220    if (src == SRC_EDT)
221	c = gchar_cursor();
222    else
223	c = cmd_gchar(AT_CURSOR+offset);
224
225    switch (c)
226    {
227	case _LAM:
228	case _BE:
229	case _PE:
230	case _TE:
231	case _SE:
232	case _JIM:
233	case _CHE:
234	case _HE_J:
235	case _XE:
236	case _SIN:
237	case _SHIN:
238	case _SAD:
239	case _ZAD:
240	case _TA:
241	case _ZA:
242	case _AYN:
243	case _AYN_:
244	case _GHAYN:
245	case _GHAYN_:
246	case _FE:
247	case _GHAF:
248	case _KAF:
249	case _KAF_H:
250	case _GAF:
251	case _MIM:
252	case _NOON:
253	case _YE:
254	case _YEE:
255	case _IE:
256	case _HE_:
257	case _HE:
258		return TRUE;
259    }
260    return FALSE;
261}
262
263/*
264** Is the Farsi character one of the terminating only type.
265*/
266    static int
267F_is_TyE(c)
268    int	    c;
269{
270    switch (c)
271    {
272	case ALEF_A:
273	case ALEF_D_H:
274	case DAL:
275	case ZAL:
276	case RE:
277	case ZE:
278	case JE:
279	case WAW:
280	case WAW_H:
281	case HAMZE:
282		return TRUE;
283    }
284    return FALSE;
285}
286
287/*
288** Is the Farsi character one of the none leading type.
289*/
290    static int
291F_is_TyC_TyD(c)
292    int	    c;
293{
294    switch (c)
295    {
296	case ALEF_:
297	case ALEF_U_H_:
298	case _AYN_:
299	case AYN_:
300	case _GHAYN_:
301	case GHAYN_:
302	case _HE_:
303	case YE_:
304	case IE_:
305	case TEE_:
306	case YEE_:
307		return TRUE;
308    }
309    return FALSE;
310}
311
312/*
313** Convert a none leading Farsi char into a leading type.
314*/
315    static int
316toF_TyB(c)
317    int	    c;
318{
319    switch (c)
320    {
321	case ALEF_:	return ALEF;
322	case ALEF_U_H_:	    return ALEF_U_H;
323	case _AYN_:	return _AYN;
324	case AYN_:	return AYN;	/* exception - there are many of them */
325	case _GHAYN_:	return _GHAYN;
326	case GHAYN_:	return GHAYN;	/* exception - there are many of them */
327	case _HE_:	return _HE;
328	case YE_:	return YE;
329	case IE_:	return IE;
330	case TEE_:	return TEE;
331	case YEE_:	return YEE;
332    }
333    return c;
334}
335
336/*
337** Overwrite the current redo and cursor characters + left adjust
338*/
339    static void
340put_curr_and_l_to_X(c)
341    int		  c;
342{
343    int	tempc;
344
345    if (curwin->w_p_rl && p_ri)
346	return;
347
348    if ((curwin->w_cursor.col < (colnr_T)STRLEN(ml_get_curline())))
349    {
350	if ((p_ri && curwin->w_cursor.col) || !p_ri)
351	{
352	    if (p_ri)
353		dec_cursor();
354	    else
355		inc_cursor();
356
357	    if (F_is_TyC_TyD((tempc = gchar_cursor())))
358	    {
359		pchar_cursor(toF_TyB(tempc));
360		AppendCharToRedobuff(K_BS);
361		AppendCharToRedobuff(tempc);
362	    }
363
364	    if (p_ri)
365		inc_cursor();
366	    else
367		dec_cursor();
368	}
369    }
370
371    put_and_redo(c);
372}
373
374    static void
375put_and_redo(c)
376    int c;
377{
378    pchar_cursor(c);
379    AppendCharToRedobuff(K_BS);
380    AppendCharToRedobuff(c);
381}
382
383/*
384** Change the char. under the cursor to a X_ or X type
385*/
386    static void
387chg_c_toX_orX()
388{
389    int	tempc, curc;
390
391    switch ((curc = gchar_cursor()))
392    {
393	case _BE:
394		tempc = BE;
395		break;
396	case _PE:
397		tempc = PE;
398		break;
399	case _TE:
400		tempc = TE;
401		break;
402	case _SE:
403		tempc = SE;
404		break;
405	case _JIM:
406		tempc = JIM;
407		break;
408	case _CHE:
409		tempc = CHE;
410		break;
411	case _HE_J:
412		tempc = HE_J;
413		break;
414	case _XE:
415		tempc = XE;
416		break;
417	case _SIN:
418		tempc = SIN;
419		break;
420	case _SHIN:
421		tempc = SHIN;
422		break;
423	case _SAD:
424		tempc = SAD;
425		break;
426	case _ZAD:
427		tempc = ZAD;
428		break;
429	case _FE:
430		tempc = FE;
431		break;
432	case _GHAF:
433		tempc = GHAF;
434		break;
435	case _KAF_H:
436	case _KAF:
437		tempc = KAF;
438		break;
439	case _GAF:
440		tempc = GAF;
441		break;
442	case _AYN:
443		tempc = AYN;
444		break;
445	case _AYN_:
446		tempc = AYN_;
447		break;
448	case _GHAYN:
449		tempc = GHAYN;
450		break;
451	case _GHAYN_:
452		tempc = GHAYN_;
453		break;
454	case _LAM:
455		tempc = LAM;
456		break;
457	case _MIM:
458		tempc = MIM;
459		break;
460	case _NOON:
461		tempc = NOON;
462		break;
463	case _HE:
464	case _HE_:
465		tempc = F_HE;
466		break;
467	case _YE:
468	case _IE:
469	case _YEE:
470		if (p_ri)
471		{
472		    inc_cursor();
473		    if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
474			    tempc = (curc == _YE ? YE_ :
475			    (curc == _IE ? IE_ : YEE_));
476		    else
477			    tempc = (curc == _YE ? YE :
478			    (curc == _IE ? IE : YEE));
479		    dec_cursor();
480		}
481		else
482		{
483		    if (curwin->w_cursor.col)
484		    {
485			dec_cursor();
486			if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
487				tempc = (curc == _YE ? YE_ :
488				(curc == _IE ? IE_ : YEE_));
489			else
490				tempc = (curc == _YE ? YE :
491				(curc == _IE ? IE : YEE));
492			inc_cursor();
493		    }
494		    else
495			    tempc = (curc == _YE ? YE :
496			    (curc == _IE ? IE : YEE));
497		}
498		break;
499	default:
500		tempc = 0;
501    }
502
503    if (tempc)
504	put_and_redo(tempc);
505}
506
507/*
508** Change the char. under the cursor to a _X_ or X_ type
509*/
510
511    static void
512chg_c_to_X_orX_()
513{
514    int	tempc;
515
516    switch (gchar_cursor())
517    {
518	case ALEF:
519		tempc = ALEF_;
520		break;
521	case ALEF_U_H:
522		tempc = ALEF_U_H_;
523		break;
524	case _AYN:
525		tempc = _AYN_;
526		break;
527	case AYN:
528		tempc = AYN_;
529		break;
530	case _GHAYN:
531		tempc = _GHAYN_;
532		break;
533	case GHAYN:
534		tempc = GHAYN_;
535		break;
536	case _HE:
537		tempc = _HE_;
538		break;
539	case YE:
540		tempc = YE_;
541		break;
542	case IE:
543		tempc = IE_;
544		break;
545	case TEE:
546		tempc = TEE_;
547		break;
548	case YEE:
549		tempc = YEE_;
550		break;
551	default:
552		tempc = 0;
553    }
554
555    if (tempc)
556	put_and_redo(tempc);
557}
558
559/*
560** Change the char. under the cursor to a _X_ or _X type
561*/
562    static void
563chg_c_to_X_or_X ()
564{
565    int	tempc;
566
567    tempc = gchar_cursor();
568
569    if (curwin->w_cursor.col + 1 < (colnr_T)STRLEN(ml_get_curline()))
570    {
571	inc_cursor();
572
573	if ((tempc == F_HE) && (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)))
574	{
575	    tempc = _HE_;
576
577	    dec_cursor();
578
579	    put_and_redo(tempc);
580	    return;
581	}
582
583	dec_cursor();
584    }
585
586    if ((tempc = toF_Xor_X_(tempc)) != 0)
587	put_and_redo(tempc);
588}
589
590/*
591** Change the character left to the cursor to a _X_ or X_ type
592*/
593    static void
594chg_l_to_X_orX_ ()
595{
596    int	tempc;
597
598    if (curwin->w_cursor.col != 0 &&
599	(curwin->w_cursor.col + 1 == (colnr_T)STRLEN(ml_get_curline())))
600	return;
601
602    if (!curwin->w_cursor.col && p_ri)
603	return;
604
605    if (p_ri)
606	dec_cursor();
607    else
608	inc_cursor();
609
610    switch (gchar_cursor())
611    {
612	case ALEF:
613		tempc = ALEF_;
614		break;
615	case ALEF_U_H:
616		tempc = ALEF_U_H_;
617		break;
618	case _AYN:
619		tempc = _AYN_;
620		break;
621	case AYN:
622		tempc = AYN_;
623		break;
624	case _GHAYN:
625		tempc = _GHAYN_;
626		break;
627	case GHAYN:
628		tempc = GHAYN_;
629		break;
630	case _HE:
631		tempc = _HE_;
632		break;
633	case YE:
634		tempc = YE_;
635		break;
636	case IE:
637		tempc = IE_;
638		break;
639	case TEE:
640		tempc = TEE_;
641		break;
642	case YEE:
643		tempc = YEE_;
644		break;
645	default:
646		tempc = 0;
647    }
648
649    if (tempc)
650	put_and_redo(tempc);
651
652    if (p_ri)
653	inc_cursor();
654    else
655	dec_cursor();
656}
657
658/*
659** Change the character left to the cursor to a X or _X type
660*/
661
662    static void
663chg_l_toXor_X ()
664{
665    int	tempc;
666
667    if (curwin->w_cursor.col != 0 &&
668	(curwin->w_cursor.col + 1 == (colnr_T)STRLEN(ml_get_curline())))
669	return;
670
671    if (!curwin->w_cursor.col && p_ri)
672	return;
673
674    if (p_ri)
675	dec_cursor();
676    else
677	inc_cursor();
678
679    switch (gchar_cursor())
680    {
681	case ALEF_:
682		tempc = ALEF;
683		break;
684	case ALEF_U_H_:
685		tempc = ALEF_U_H;
686		break;
687	case _AYN_:
688		tempc = _AYN;
689		break;
690	case AYN_:
691		tempc = AYN;
692		break;
693	case _GHAYN_:
694		tempc = _GHAYN;
695		break;
696	case GHAYN_:
697		tempc = GHAYN;
698		break;
699	case _HE_:
700		tempc = _HE;
701		break;
702	case YE_:
703		tempc = YE;
704		break;
705	case IE_:
706		tempc = IE;
707		break;
708	case TEE_:
709		tempc = TEE;
710		break;
711	case YEE_:
712		tempc = YEE;
713		break;
714	default:
715		tempc = 0;
716    }
717
718    if (tempc)
719	put_and_redo(tempc);
720
721    if (p_ri)
722	inc_cursor();
723    else
724	dec_cursor();
725}
726
727/*
728** Change the character right to the cursor to a _X or _X_ type
729*/
730
731    static void
732chg_r_to_Xor_X_()
733{
734    int tempc, c;
735
736    if (curwin->w_cursor.col)
737    {
738	if (!p_ri)
739	    dec_cursor();
740
741	tempc = gchar_cursor();
742
743	if ((c = toF_Xor_X_(tempc)) != 0)
744	    put_and_redo(c);
745
746	if (!p_ri)
747	    inc_cursor();
748
749    }
750}
751
752/*
753** Map Farsi keyboard when in fkmap mode.
754*/
755
756    int
757fkmap(c)
758    int c;
759{
760    int		tempc;
761    static int	revins;
762
763    if (IS_SPECIAL(c))
764	return c;
765
766    if (VIM_ISDIGIT(c) || ((c == '.' || c == '+' || c == '-' ||
767	c == '^' || c == '%' || c == '#' || c == '=')  && revins))
768    {
769	if (!revins)
770	{
771	    if (curwin->w_cursor.col)
772	    {
773		if (!p_ri)
774		    dec_cursor();
775
776		    chg_c_toX_orX ();
777		    chg_l_toXor_X ();
778
779		if (!p_ri)
780		    inc_cursor();
781	    }
782	}
783
784	arrow_used = TRUE;
785	(void)stop_arrow();
786
787	if (!curwin->w_p_rl && revins)
788	    inc_cursor();
789
790	++revins;
791	p_ri=1;
792    }
793    else
794    {
795	if (revins)
796	{
797	    arrow_used = TRUE;
798	    (void)stop_arrow();
799
800	    revins = 0;
801	    if (curwin->w_p_rl)
802	    {
803		while ((F_isdigit(gchar_cursor())
804			    || (gchar_cursor() == F_PERIOD
805				|| gchar_cursor() == F_PLUS
806				|| gchar_cursor() == F_MINUS
807				|| gchar_cursor() == F_MUL
808				|| gchar_cursor() == F_DIVIDE
809				|| gchar_cursor() == F_PERCENT
810				|| gchar_cursor() == F_EQUALS))
811			&& gchar_cursor() != NUL)
812		    ++curwin->w_cursor.col;
813	    }
814	    else
815	    {
816		if (curwin->w_cursor.col)
817		    while ((F_isdigit(gchar_cursor())
818			    || (gchar_cursor() == F_PERIOD
819				|| gchar_cursor() == F_PLUS
820				|| gchar_cursor() == F_MINUS
821				|| gchar_cursor() == F_MUL
822				|| gchar_cursor() == F_DIVIDE
823				|| gchar_cursor() == F_PERCENT
824				|| gchar_cursor() == F_EQUALS))
825			    && --curwin->w_cursor.col)
826			;
827
828		if (!F_isdigit(gchar_cursor()))
829		    ++curwin->w_cursor.col;
830	    }
831	}
832    }
833
834    if (!revins)
835    {
836	if (curwin->w_p_rl)
837	    p_ri=0;
838	if (!curwin->w_p_rl)
839	    p_ri=1;
840    }
841
842    if ((c < 0x100) && (isalpha(c) || c == '&' ||   c == '^' ||	c == ';' ||
843			    c == '\''||	c == ',' || c == '[' ||
844			    c == ']' ||	c == '{' || c == '}'	))
845	chg_r_to_Xor_X_();
846
847    tempc = 0;
848
849    switch (c)
850    {
851	case '`':
852	case ' ':
853	case '.':
854	case '!':
855	case '"':
856	case '$':
857	case '%':
858	case '^':
859	case '&':
860	case '/':
861	case '(':
862	case ')':
863	case '=':
864	case '\\':
865	case '?':
866	case '+':
867	case '-':
868	case '_':
869	case '*':
870	case ':':
871	case '#':
872	case '~':
873	case '@':
874	case '<':
875	case '>':
876	case '{':
877	case '}':
878	case '|':
879	case '0':
880	case '1':
881	case '2':
882	case '3':
883	case '4':
884	case '5':
885	case '6':
886	case '7':
887	case '8':
888	case '9':
889	case 'B':
890	case 'E':
891	case 'F':
892	case 'H':
893	case 'I':
894	case 'K':
895	case 'L':
896	case 'M':
897	case 'O':
898	case 'P':
899	case 'Q':
900	case 'R':
901	case 'T':
902	case 'U':
903	case 'W':
904	case 'Y':
905	case  NL:
906	case  TAB:
907
908	    if (p_ri && c == NL && curwin->w_cursor.col)
909	    {
910		/*
911		** If the char before the cursor is _X_ or X_ do not change
912		** the one under the cursor with X type.
913		*/
914
915		dec_cursor();
916
917		if (F_isalpha(gchar_cursor()))
918		{
919		    inc_cursor();
920		    return NL;
921		}
922
923		inc_cursor();
924	    }
925
926	    if (!p_ri)
927	    if (!curwin->w_cursor.col)
928	    {
929		switch (c)
930		{
931		    case '0':	return FARSI_0;
932		    case '1':	return FARSI_1;
933		    case '2':	return FARSI_2;
934		    case '3':	return FARSI_3;
935		    case '4':	return FARSI_4;
936		    case '5':	return FARSI_5;
937		    case '6':	return FARSI_6;
938		    case '7':	return FARSI_7;
939		    case '8':	return FARSI_8;
940		    case '9':	return FARSI_9;
941		    case 'B':	return F_PSP;
942		    case 'E':	return JAZR_N;
943		    case 'F':	return ALEF_D_H;
944		    case 'H':	return ALEF_A;
945		    case 'I':	return TASH;
946		    case 'K':	return F_LQUOT;
947		    case 'L':	return F_RQUOT;
948		    case 'M':	return HAMZE;
949		    case 'O':	return '[';
950		    case 'P':	return ']';
951		    case 'Q':	return OO;
952		    case 'R':	return MAD_N;
953		    case 'T':	return OW;
954		    case 'U':	return MAD;
955		    case 'W':	return OW_OW;
956		    case 'Y':	return JAZR;
957		    case '`':	return F_PCN;
958		    case '!':	return F_EXCL;
959		    case '@':	return F_COMMA;
960		    case '#':	return F_DIVIDE;
961		    case '$':	return F_CURRENCY;
962		    case '%':	return F_PERCENT;
963		    case '^':	return F_MUL;
964		    case '&':	return F_BCOMMA;
965		    case '*':	return F_STAR;
966		    case '(':	return F_LPARENT;
967		    case ')':	return F_RPARENT;
968		    case '-':	return F_MINUS;
969		    case '_':	return F_UNDERLINE;
970		    case '=':	return F_EQUALS;
971		    case '+':	return F_PLUS;
972		    case '\\':	return F_BSLASH;
973		    case '|':	return F_PIPE;
974		    case ':':	return F_DCOLON;
975		    case '"':	return F_SEMICOLON;
976		    case '.':	return F_PERIOD;
977		    case '/':	return F_SLASH;
978		    case '<':	return F_LESS;
979		    case '>':	return F_GREATER;
980		    case '?':	return F_QUESTION;
981		    case ' ':	return F_BLANK;
982		}
983		break;
984	    }
985	    if (!p_ri)
986		dec_cursor();
987
988	    switch ((tempc = gchar_cursor()))
989	    {
990		case _BE:
991		case _PE:
992		case _TE:
993		case _SE:
994		case _JIM:
995		case _CHE:
996		case _HE_J:
997		case _XE:
998		case _SIN:
999		case _SHIN:
1000		case _SAD:
1001		case _ZAD:
1002		case _FE:
1003		case _GHAF:
1004		case _KAF:
1005		case _KAF_H:
1006		case _GAF:
1007		case _LAM:
1008		case _MIM:
1009		case _NOON:
1010		case _HE:
1011		case _HE_:
1012		case _TA:
1013		case _ZA:
1014			put_curr_and_l_to_X(toF_TyA(tempc));
1015			break;
1016		case _AYN:
1017		case _AYN_:
1018
1019			if (!p_ri)
1020			    if (!curwin->w_cursor.col)
1021			    {
1022				put_curr_and_l_to_X(AYN);
1023				break;
1024			    }
1025
1026			if (p_ri)
1027			    inc_cursor();
1028			else
1029			    dec_cursor();
1030
1031			if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
1032			    tempc = AYN_;
1033			else
1034			    tempc = AYN;
1035
1036			if (p_ri)
1037			    dec_cursor();
1038			else
1039			    inc_cursor();
1040
1041			put_curr_and_l_to_X(tempc);
1042
1043			break;
1044		case _GHAYN:
1045		case _GHAYN_:
1046
1047			if (!p_ri)
1048			    if (!curwin->w_cursor.col)
1049			    {
1050				put_curr_and_l_to_X(GHAYN);
1051				break;
1052			    }
1053
1054			if (p_ri)
1055			    inc_cursor();
1056			else
1057			    dec_cursor();
1058
1059			if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
1060			    tempc = GHAYN_;
1061			else
1062			    tempc = GHAYN;
1063
1064			if (p_ri)
1065			    dec_cursor();
1066			else
1067			    inc_cursor();
1068
1069			put_curr_and_l_to_X(tempc);
1070			break;
1071		case _YE:
1072		case _IE:
1073		case _YEE:
1074			if (!p_ri)
1075			    if (!curwin->w_cursor.col)
1076			    {
1077				put_curr_and_l_to_X((tempc == _YE ? YE :
1078					    (tempc == _IE ? IE : YEE)));
1079				break;
1080			    }
1081
1082			if (p_ri)
1083			    inc_cursor();
1084			else
1085			    dec_cursor();
1086
1087			if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
1088				tempc = (tempc == _YE ? YE_ :
1089				    (tempc == _IE ? IE_ : YEE_));
1090			else
1091				tempc = (tempc == _YE ? YE :
1092				    (tempc == _IE ? IE : YEE));
1093
1094			if (p_ri)
1095			    dec_cursor();
1096			else
1097			    inc_cursor();
1098
1099			put_curr_and_l_to_X(tempc);
1100			break;
1101		}
1102
1103		if (!p_ri)
1104		    inc_cursor();
1105
1106		tempc = 0;
1107
1108		switch (c)
1109		{
1110		    case '0':	return FARSI_0;
1111		    case '1':	return FARSI_1;
1112		    case '2':	return FARSI_2;
1113		    case '3':	return FARSI_3;
1114		    case '4':	return FARSI_4;
1115		    case '5':	return FARSI_5;
1116		    case '6':	return FARSI_6;
1117		    case '7':	return FARSI_7;
1118		    case '8':	return FARSI_8;
1119		    case '9':	return FARSI_9;
1120		    case 'B':	return F_PSP;
1121		    case 'E':	return JAZR_N;
1122		    case 'F':	return ALEF_D_H;
1123		    case 'H':	return ALEF_A;
1124		    case 'I':	return TASH;
1125		    case 'K':	return F_LQUOT;
1126		    case 'L':	return F_RQUOT;
1127		    case 'M':	return HAMZE;
1128		    case 'O':	return '[';
1129		    case 'P':	return ']';
1130		    case 'Q':	return OO;
1131		    case 'R':	return MAD_N;
1132		    case 'T':	return OW;
1133		    case 'U':	return MAD;
1134		    case 'W':	return OW_OW;
1135		    case 'Y':	return JAZR;
1136		    case '`':	return F_PCN;
1137		    case '!':	return F_EXCL;
1138		    case '@':	return F_COMMA;
1139		    case '#':	return F_DIVIDE;
1140		    case '$':	return F_CURRENCY;
1141		    case '%':	return F_PERCENT;
1142		    case '^':	return F_MUL;
1143		    case '&':	return F_BCOMMA;
1144		    case '*':	return F_STAR;
1145		    case '(':	return F_LPARENT;
1146		    case ')':	return F_RPARENT;
1147		    case '-':	return F_MINUS;
1148		    case '_':	return F_UNDERLINE;
1149		    case '=':	return F_EQUALS;
1150		    case '+':	return F_PLUS;
1151		    case '\\':	return F_BSLASH;
1152		    case '|':	return F_PIPE;
1153		    case ':':	return F_DCOLON;
1154		    case '"':	return F_SEMICOLON;
1155		    case '.':	return F_PERIOD;
1156		    case '/':	return F_SLASH;
1157		    case '<':	return F_LESS;
1158		    case '>':	return F_GREATER;
1159		    case '?':	return F_QUESTION;
1160		    case ' ':	return F_BLANK;
1161		}
1162		break;
1163
1164	case 'a':
1165		tempc = _SHIN;
1166	    break;
1167	case 'A':
1168		tempc = WAW_H;
1169	    break;
1170	case 'b':
1171		tempc = ZAL;
1172	    break;
1173	case 'c':
1174		tempc = ZE;
1175	    break;
1176	case 'C':
1177		tempc = JE;
1178	    break;
1179	case 'd':
1180		tempc = _YE;
1181	    break;
1182	case 'D':
1183		tempc = _YEE;
1184	    break;
1185	case 'e':
1186		tempc = _SE;
1187	    break;
1188	case 'f':
1189		tempc = _BE;
1190	    break;
1191	case 'g':
1192		tempc = _LAM;
1193	    break;
1194	case 'G':
1195	    if (!curwin->w_cursor.col  &&  STRLEN(ml_get_curline()))
1196		{
1197
1198		if (gchar_cursor() == _LAM)
1199		    chg_c_toX_orX ();
1200		else
1201		    if (p_ri)
1202			chg_c_to_X_or_X ();
1203	    }
1204
1205	    if (!p_ri)
1206		if (!curwin->w_cursor.col)
1207		    return ALEF_U_H;
1208
1209	    if (!p_ri)
1210		dec_cursor();
1211
1212	    if (gchar_cursor() == _LAM)
1213	    {
1214		chg_c_toX_orX ();
1215		chg_l_toXor_X ();
1216		    tempc = ALEF_U_H;
1217	    }
1218	    else
1219		if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
1220		{
1221			tempc = ALEF_U_H_;
1222		    chg_l_toXor_X ();
1223		}
1224		else
1225			tempc = ALEF_U_H;
1226
1227	    if (!p_ri)
1228		inc_cursor();
1229
1230	    return tempc;
1231	case 'h':
1232	    if (!curwin->w_cursor.col  &&  STRLEN(ml_get_curline()))
1233		{
1234		if (p_ri)
1235		    chg_c_to_X_or_X ();
1236
1237	    }
1238
1239	    if (!p_ri)
1240		if (!curwin->w_cursor.col)
1241		    return ALEF;
1242
1243	    if (!p_ri)
1244		dec_cursor();
1245
1246	    if (gchar_cursor() == _LAM)
1247	    {
1248		chg_l_toXor_X();
1249		del_char(FALSE);
1250		AppendCharToRedobuff(K_BS);
1251
1252		if (!p_ri)
1253		    dec_cursor();
1254
1255		    tempc = LA;
1256	    }
1257	    else
1258	    {
1259		if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
1260		{
1261			tempc = ALEF_;
1262		    chg_l_toXor_X ();
1263		}
1264		else
1265			tempc = ALEF;
1266	    }
1267
1268	    if (!p_ri)
1269		inc_cursor();
1270
1271	    return tempc;
1272	case 'i':
1273	    if (!curwin->w_cursor.col  &&  STRLEN(ml_get_curline()))
1274		{
1275		if (!p_ri && !F_is_TyE(tempc))
1276		    chg_c_to_X_orX_ ();
1277		if (p_ri)
1278		    chg_c_to_X_or_X ();
1279
1280	    }
1281
1282	    if (!p_ri && !curwin->w_cursor.col)
1283		return _HE;
1284
1285	    if (!p_ri)
1286		dec_cursor();
1287
1288	    if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
1289		    tempc = _HE_;
1290	    else
1291		    tempc = _HE;
1292
1293	    if (!p_ri)
1294		inc_cursor();
1295	    break;
1296	case 'j':
1297		tempc = _TE;
1298	    break;
1299	case 'J':
1300	    if (!curwin->w_cursor.col  &&  STRLEN(ml_get_curline()))
1301		{
1302		if (p_ri)
1303		    chg_c_to_X_or_X ();
1304
1305	    }
1306
1307	    if (!p_ri)
1308		if (!curwin->w_cursor.col)
1309		    return TEE;
1310
1311	    if (!p_ri)
1312		dec_cursor();
1313
1314	    if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
1315	    {
1316		    tempc = TEE_;
1317		chg_l_toXor_X ();
1318	    }
1319	    else
1320			tempc = TEE;
1321
1322	    if (!p_ri)
1323		inc_cursor();
1324
1325	    return tempc;
1326	case 'k':
1327		tempc = _NOON;
1328	    break;
1329	case 'l':
1330		tempc = _MIM;
1331	    break;
1332	case 'm':
1333		tempc = _PE;
1334	    break;
1335	case 'n':
1336	case 'N':
1337		tempc = DAL;
1338	    break;
1339	case 'o':
1340		tempc = _XE;
1341	    break;
1342	case 'p':
1343		tempc = _HE_J;
1344	    break;
1345	case 'q':
1346		tempc = _ZAD;
1347	    break;
1348	case 'r':
1349		tempc = _GHAF;
1350	    break;
1351	case 's':
1352		tempc = _SIN;
1353	    break;
1354	case 'S':
1355		tempc = _IE;
1356	    break;
1357	case 't':
1358		tempc = _FE;
1359	    break;
1360	case 'u':
1361		if (!curwin->w_cursor.col  &&  STRLEN(ml_get_curline()))
1362		{
1363		    if (!p_ri && !F_is_TyE(tempc))
1364			chg_c_to_X_orX_ ();
1365		    if (p_ri)
1366			chg_c_to_X_or_X ();
1367
1368		}
1369
1370		if (!p_ri && !curwin->w_cursor.col)
1371		    return _AYN;
1372
1373		if (!p_ri)
1374		    dec_cursor();
1375
1376		if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
1377		    tempc = _AYN_;
1378		else
1379		    tempc = _AYN;
1380
1381		if (!p_ri)
1382		    inc_cursor();
1383	    break;
1384	case 'v':
1385	case 'V':
1386		tempc = RE;
1387	    break;
1388	case 'w':
1389		tempc = _SAD;
1390	    break;
1391	case 'x':
1392	case 'X':
1393		tempc = _TA;
1394	    break;
1395	case 'y':
1396	    if (!curwin->w_cursor.col  &&  STRLEN(ml_get_curline()))
1397		{
1398		if (!p_ri && !F_is_TyE(tempc))
1399		    chg_c_to_X_orX_ ();
1400		if (p_ri)
1401		    chg_c_to_X_or_X ();
1402
1403	    }
1404
1405	    if (!p_ri && !curwin->w_cursor.col)
1406		return _GHAYN;
1407
1408	    if (!p_ri)
1409		dec_cursor();
1410
1411	    if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
1412		tempc = _GHAYN_;
1413	    else
1414		tempc = _GHAYN;
1415
1416	    if (!p_ri)
1417		inc_cursor();
1418
1419	    break;
1420	case 'z':
1421		tempc = _ZA;
1422	    break;
1423	case 'Z':
1424		tempc = _KAF_H;
1425	    break;
1426	case ';':
1427		tempc = _KAF;
1428	    break;
1429	case '\'':
1430		tempc = _GAF;
1431	    break;
1432	case ',':
1433		tempc = WAW;
1434	    break;
1435	case '[':
1436		tempc = _JIM;
1437	    break;
1438	case ']':
1439		tempc = _CHE;
1440	    break;
1441    }
1442
1443    if ((F_isalpha(tempc) || F_isdigit(tempc)))
1444    {
1445	if (!curwin->w_cursor.col  &&  STRLEN(ml_get_curline()))
1446	    {
1447	    if (!p_ri && !F_is_TyE(tempc))
1448		chg_c_to_X_orX_ ();
1449	    if (p_ri)
1450		chg_c_to_X_or_X ();
1451	}
1452
1453	if (curwin->w_cursor.col)
1454	{
1455	    if (!p_ri)
1456		dec_cursor();
1457
1458	    if (F_is_TyE(tempc))
1459		chg_l_toXor_X ();
1460	    else
1461		chg_l_to_X_orX_ ();
1462
1463	    if (!p_ri)
1464		inc_cursor();
1465	}
1466    }
1467    if (tempc)
1468	return tempc;
1469    return c;
1470}
1471
1472/*
1473** Convert a none leading Farsi char into a leading type.
1474*/
1475    static int
1476toF_leading(c)
1477    int	    c;
1478{
1479    switch (c)
1480    {
1481	case ALEF_:	return ALEF;
1482	case ALEF_U_H_:	    return ALEF_U_H;
1483	case BE:    return _BE;
1484	case PE:    return _PE;
1485	case TE:    return _TE;
1486	case SE:    return _SE;
1487	case JIM:   return _JIM;
1488	case CHE:   return _CHE;
1489	case HE_J:  return _HE_J;
1490	case XE:    return _XE;
1491	case SIN:   return _SIN;
1492	case SHIN:  return _SHIN;
1493	case SAD:   return _SAD;
1494	case ZAD:   return _ZAD;
1495
1496	case AYN:
1497	case AYN_:
1498	case _AYN_: return _AYN;
1499
1500	case GHAYN:
1501	case GHAYN_:
1502	case _GHAYN_:	return _GHAYN;
1503
1504	case FE:    return _FE;
1505	case GHAF:  return _GHAF;
1506	case KAF:   return _KAF;
1507	case GAF:   return _GAF;
1508	case LAM:   return _LAM;
1509	case MIM:   return _MIM;
1510	case NOON:  return _NOON;
1511
1512	case _HE_:
1513	case F_HE:	return _HE;
1514
1515	case YE:
1516	case YE_:	return _YE;
1517
1518	case IE_:
1519	case IE:	return _IE;
1520
1521	case YEE:
1522	case YEE_:	return _YEE;
1523    }
1524    return c;
1525}
1526
1527/*
1528** Convert a given Farsi char into right joining type.
1529*/
1530    static int
1531toF_Rjoin(c)
1532    int	    c;
1533{
1534    switch (c)
1535    {
1536	case ALEF:  return ALEF_;
1537	case ALEF_U_H:	return ALEF_U_H_;
1538	case BE:    return _BE;
1539	case PE:    return _PE;
1540	case TE:    return _TE;
1541	case SE:    return _SE;
1542	case JIM:   return _JIM;
1543	case CHE:   return _CHE;
1544	case HE_J:  return _HE_J;
1545	case XE:    return _XE;
1546	case SIN:   return _SIN;
1547	case SHIN:  return _SHIN;
1548	case SAD:   return _SAD;
1549	case ZAD:   return _ZAD;
1550
1551	case AYN:
1552	case AYN_:
1553	case _AYN:  return _AYN_;
1554
1555	case GHAYN:
1556	case GHAYN_:
1557	case _GHAYN_:	return _GHAYN_;
1558
1559	case FE:    return _FE;
1560	case GHAF:  return _GHAF;
1561	case KAF:   return _KAF;
1562	case GAF:   return _GAF;
1563	case LAM:   return _LAM;
1564	case MIM:   return _MIM;
1565	case NOON:  return _NOON;
1566
1567	case _HE:
1568	case F_HE:	return _HE_;
1569
1570	case YE:
1571	case YE_:	return _YE;
1572
1573	case IE_:
1574	case IE:	return _IE;
1575
1576	case TEE:	return TEE_;
1577
1578	case YEE:
1579	case YEE_:	return _YEE;
1580    }
1581    return c;
1582}
1583
1584/*
1585** Can a given Farsi character join via its left edj.
1586*/
1587    static int
1588canF_Ljoin(c)
1589    int	c;
1590{
1591    switch (c)
1592    {
1593	case _BE:
1594	case BE:
1595	case PE:
1596	case _PE:
1597	case TE:
1598	case _TE:
1599	case SE:
1600	case _SE:
1601	case JIM:
1602	case _JIM:
1603	case CHE:
1604	case _CHE:
1605	case HE_J:
1606	case _HE_J:
1607	case XE:
1608	case _XE:
1609	case SIN:
1610	case _SIN:
1611	case SHIN:
1612	case _SHIN:
1613	case SAD:
1614	case _SAD:
1615	case ZAD:
1616	case _ZAD:
1617	case _TA:
1618	case _ZA:
1619	case AYN:
1620	case _AYN:
1621	case _AYN_:
1622	case AYN_:
1623	case GHAYN:
1624	case GHAYN_:
1625	case _GHAYN_:
1626	case _GHAYN:
1627	case FE:
1628	case _FE:
1629	case GHAF:
1630	case _GHAF:
1631	case _KAF_H:
1632	case KAF:
1633	case _KAF:
1634	case GAF:
1635	case _GAF:
1636	case LAM:
1637	case _LAM:
1638	case MIM:
1639	case _MIM:
1640	case NOON:
1641	case _NOON:
1642	case IE:
1643	case _IE:
1644	case IE_:
1645	case YE:
1646	case _YE:
1647	case YE_:
1648	case YEE:
1649	case _YEE:
1650	case YEE_:
1651	case F_HE:
1652	case _HE:
1653	case _HE_:
1654	    return TRUE;
1655    }
1656    return FALSE;
1657}
1658
1659/*
1660** Can a given Farsi character join via its right edj.
1661*/
1662    static int
1663canF_Rjoin(c)
1664    int	    c;
1665{
1666    switch (c)
1667    {
1668	case ALEF:
1669	case ALEF_:
1670	case ALEF_U_H:
1671	case ALEF_U_H_:
1672	case DAL:
1673	case ZAL:
1674	case RE:
1675	case JE:
1676	case ZE:
1677	case TEE:
1678	case TEE_:
1679	case WAW:
1680	case WAW_H:
1681	    return TRUE;
1682    }
1683
1684    return canF_Ljoin(c);
1685
1686}
1687
1688/*
1689** is a given Farsi character a terminating type.
1690*/
1691    static int
1692F_isterm(c)
1693    int	    c;
1694{
1695    switch (c)
1696    {
1697	case ALEF:
1698	case ALEF_:
1699	case ALEF_U_H:
1700	case ALEF_U_H_:
1701	case DAL:
1702	case ZAL:
1703	case RE:
1704	case JE:
1705	case ZE:
1706	case WAW:
1707	case WAW_H:
1708	case TEE:
1709	case TEE_:
1710	    return TRUE;
1711    }
1712
1713    return FALSE;
1714}
1715
1716/*
1717** Convert the given Farsi character into a ending type .
1718*/
1719    static int
1720toF_ending(c)
1721    int	    c;
1722{
1723
1724    switch (c)
1725    {
1726	case _BE:
1727		return BE;
1728	case _PE:
1729		return PE;
1730	case _TE:
1731		return TE;
1732	case _SE:
1733		return SE;
1734	case _JIM:
1735		return JIM;
1736	case _CHE:
1737		return CHE;
1738	case _HE_J:
1739		return HE_J;
1740	case _XE:
1741		return XE;
1742	case _SIN:
1743		return SIN;
1744	case _SHIN:
1745		return SHIN;
1746	case _SAD:
1747		return SAD;
1748	case _ZAD:
1749		return ZAD;
1750	case _AYN:
1751		return AYN;
1752	case _AYN_:
1753		return AYN_;
1754	case _GHAYN:
1755		return GHAYN;
1756	case _GHAYN_:
1757		return GHAYN_;
1758	case _FE:
1759		return FE;
1760	case _GHAF:
1761		return GHAF;
1762	case _KAF_H:
1763	case _KAF:
1764		return KAF;
1765	case _GAF:
1766		return GAF;
1767	case _LAM:
1768		return LAM;
1769	case _MIM:
1770		return MIM;
1771	case _NOON:
1772		return NOON;
1773	case _YE:
1774		return YE_;
1775	case YE_:
1776		return YE;
1777	case _YEE:
1778		return YEE_;
1779	case YEE_:
1780		return YEE;
1781	case TEE:
1782		return TEE_;
1783	case _IE:
1784		return IE_;
1785	case IE_:
1786		return IE;
1787	case _HE:
1788	case _HE_:
1789		return F_HE;
1790    }
1791    return c;
1792}
1793
1794/*
1795** Convert the Farsi 3342 standard into Farsi VIM.
1796*/
1797    void
1798conv_to_pvim()
1799{
1800    char_u	*ptr;
1801    int		lnum, llen, i;
1802
1803    for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
1804    {
1805	ptr = ml_get((linenr_T)lnum);
1806
1807	llen = (int)STRLEN(ptr);
1808
1809	for ( i = 0; i < llen-1; i++)
1810	{
1811	    if (canF_Ljoin(ptr[i]) && canF_Rjoin(ptr[i+1]))
1812	    {
1813		ptr[i] = toF_leading(ptr[i]);
1814		++i;
1815
1816		while(canF_Rjoin(ptr[i]) && (i < llen))
1817		{
1818		    ptr[i] = toF_Rjoin(ptr[i]);
1819		    if (F_isterm(ptr[i]) || !F_isalpha(ptr[i]))
1820			break;
1821		    ++i;
1822		}
1823		if (!F_isalpha(ptr[i]) || !canF_Rjoin(ptr[i]))
1824		    ptr[i-1] = toF_ending(ptr[i-1]);
1825	    }
1826	    else
1827		ptr[i] = toF_TyA(ptr[i]);
1828	}
1829    }
1830
1831    /*
1832     * Following lines contains Farsi encoded character.
1833     */
1834
1835    do_cmdline_cmd((char_u *)"%s/\202\231/\232/g");
1836    do_cmdline_cmd((char_u *)"%s/\201\231/\370\334/g");
1837
1838    /* Assume the screen has been messed up: clear it and redraw. */
1839    redraw_later(CLEAR);
1840    MSG_ATTR(farsi_text_1, hl_attr(HLF_S));
1841}
1842
1843/*
1844 * Convert the Farsi VIM into Farsi 3342 standad.
1845 */
1846    void
1847conv_to_pstd()
1848{
1849    char_u	*ptr;
1850    int		lnum, llen, i;
1851
1852    /*
1853     * Following line contains Farsi encoded character.
1854     */
1855
1856    do_cmdline_cmd((char_u *)"%s/\232/\202\231/g");
1857
1858    for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
1859    {
1860	ptr = ml_get((linenr_T)lnum);
1861
1862	llen = (int)STRLEN(ptr);
1863
1864	for ( i = 0; i < llen; i++)
1865	{
1866	    ptr[i] = toF_TyA(ptr[i]);
1867
1868	}
1869    }
1870
1871    /* Assume the screen has been messed up: clear it and redraw. */
1872    redraw_later(CLEAR);
1873    MSG_ATTR(farsi_text_2, hl_attr(HLF_S));
1874}
1875
1876/*
1877 * left-right swap the characters in buf[len].
1878 */
1879    static void
1880lrswapbuf(buf, len)
1881    char_u	*buf;
1882    int		len;
1883{
1884    char_u	*s, *e;
1885    int		c;
1886
1887    s = buf;
1888    e = buf + len - 1;
1889
1890    while (e > s)
1891    {
1892	c = *s;
1893	*s = *e;
1894	*e = c;
1895	++s;
1896	--e;
1897    }
1898}
1899
1900/*
1901 * swap all the characters in reverse direction
1902 */
1903    char_u *
1904lrswap(ibuf)
1905    char_u	*ibuf;
1906{
1907    if (ibuf != NULL && *ibuf != NUL)
1908	lrswapbuf(ibuf, (int)STRLEN(ibuf));
1909    return ibuf;
1910}
1911
1912/*
1913 * swap all the Farsi characters in reverse direction
1914 */
1915    char_u *
1916lrFswap(cmdbuf, len)
1917    char_u	*cmdbuf;
1918    int		len;
1919{
1920    int		i, cnt;
1921
1922    if (cmdbuf == NULL)
1923	return cmdbuf;
1924
1925    if (len == 0 && (len = (int)STRLEN(cmdbuf)) == 0)
1926	return cmdbuf;
1927
1928    for (i = 0; i < len; i++)
1929    {
1930	for (cnt = 0; i + cnt < len
1931			&& (F_isalpha(cmdbuf[i + cnt])
1932			    || F_isdigit(cmdbuf[i + cnt])
1933			    || cmdbuf[i + cnt] == ' '); ++cnt)
1934	    ;
1935
1936	lrswapbuf(cmdbuf + i, cnt);
1937	i += cnt;
1938    }
1939    return cmdbuf;
1940}
1941
1942/*
1943 * Reverse the characters in the search path and substitute section
1944 * accordingly.
1945 * TODO: handle different separator characters.  Use skip_regexp().
1946 */
1947    char_u *
1948lrF_sub(ibuf)
1949    char_u	*ibuf;
1950{
1951    char_u	*p, *ep;
1952    int		i, cnt;
1953
1954    p = ibuf;
1955
1956    /* Find the boundary of the search path */
1957    while (((p = vim_strchr(p + 1, '/')) != NULL) && p[-1] == '\\')
1958	;
1959
1960    if (p == NULL)
1961	return ibuf;
1962
1963    /* Reverse the Farsi characters in the search path. */
1964    lrFswap(ibuf, (int)(p-ibuf));
1965
1966    /* Now find the boundary of the substitute section */
1967    if ((ep = (char_u *)strrchr((char *)++p, '/')) != NULL)
1968	cnt = (int)(ep - p);
1969    else
1970	cnt = (int)STRLEN(p);
1971
1972    /* Reverse the characters in the substitute section and take care of '\' */
1973    for (i = 0; i < cnt-1; i++)
1974	if (p[i] == '\\')
1975	{
1976	    p[i] = p[i+1] ;
1977	    p[++i] = '\\';
1978	}
1979
1980    lrswapbuf(p, cnt);
1981
1982    return ibuf;
1983}
1984
1985/*
1986 * Map Farsi keyboard when in cmd_fkmap mode.
1987 */
1988    int
1989cmdl_fkmap(c)
1990    int c;
1991{
1992    int	    tempc;
1993
1994    switch (c)
1995    {
1996	case '0':
1997	case '1':
1998	case '2':
1999	case '3':
2000	case '4':
2001	case '5':
2002	case '6':
2003	case '7':
2004	case '8':
2005	case '9':
2006	case '`':
2007	case ' ':
2008	case '.':
2009	case '!':
2010	case '"':
2011	case '$':
2012	case '%':
2013	case '^':
2014	case '&':
2015	case '/':
2016	case '(':
2017	case ')':
2018	case '=':
2019	case '\\':
2020	case '?':
2021	case '+':
2022	case '-':
2023	case '_':
2024	case '*':
2025	case ':':
2026	case '#':
2027	case '~':
2028	case '@':
2029	case '<':
2030	case '>':
2031	case '{':
2032	case '}':
2033	case '|':
2034	case 'B':
2035	case 'E':
2036	case 'F':
2037	case 'H':
2038	case 'I':
2039	case 'K':
2040	case 'L':
2041	case 'M':
2042	case 'O':
2043	case 'P':
2044	case 'Q':
2045	case 'R':
2046	case 'T':
2047	case 'U':
2048	case 'W':
2049	case 'Y':
2050	case  NL:
2051	case  TAB:
2052
2053	       switch ((tempc = cmd_gchar(AT_CURSOR)))
2054	       {
2055	    case _BE:
2056	    case _PE:
2057	    case _TE:
2058	    case _SE:
2059	    case _JIM:
2060	    case _CHE:
2061	    case _HE_J:
2062	    case _XE:
2063	    case _SIN:
2064	    case _SHIN:
2065	    case _SAD:
2066	    case _ZAD:
2067	    case _AYN:
2068	    case _GHAYN:
2069	    case _FE:
2070	    case _GHAF:
2071	    case _KAF:
2072	    case _GAF:
2073	    case _LAM:
2074	    case _MIM:
2075	    case _NOON:
2076	    case _HE:
2077	    case _HE_:
2078			cmd_pchar(toF_TyA(tempc), AT_CURSOR);
2079		break;
2080	    case _AYN_:
2081			cmd_pchar(AYN_, AT_CURSOR);
2082		break;
2083	    case _GHAYN_:
2084			cmd_pchar(GHAYN_, AT_CURSOR);
2085		break;
2086	    case _IE:
2087		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR+1))
2088			    cmd_pchar(IE_, AT_CURSOR);
2089		else
2090			    cmd_pchar(IE, AT_CURSOR);
2091		break;
2092	    case _YEE:
2093		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR+1))
2094			    cmd_pchar(YEE_, AT_CURSOR);
2095			else
2096			    cmd_pchar(YEE, AT_CURSOR);
2097		break;
2098	    case _YE:
2099		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR+1))
2100			    cmd_pchar(YE_, AT_CURSOR);
2101			else
2102			    cmd_pchar(YE, AT_CURSOR);
2103	    }
2104
2105	    switch (c)
2106	    {
2107		case '0':   return FARSI_0;
2108		case '1':   return FARSI_1;
2109		case '2':   return FARSI_2;
2110		case '3':   return FARSI_3;
2111		case '4':   return FARSI_4;
2112		case '5':   return FARSI_5;
2113		case '6':   return FARSI_6;
2114		case '7':   return FARSI_7;
2115		case '8':   return FARSI_8;
2116		case '9':   return FARSI_9;
2117		case 'B':   return F_PSP;
2118		case 'E':   return JAZR_N;
2119		case 'F':   return ALEF_D_H;
2120		case 'H':   return ALEF_A;
2121		case 'I':   return TASH;
2122		case 'K':   return F_LQUOT;
2123		case 'L':   return F_RQUOT;
2124		case 'M':   return HAMZE;
2125		case 'O':   return '[';
2126		case 'P':   return ']';
2127		case 'Q':   return OO;
2128		case 'R':   return MAD_N;
2129		case 'T':   return OW;
2130		case 'U':   return MAD;
2131		case 'W':   return OW_OW;
2132		case 'Y':   return JAZR;
2133		case '`':   return F_PCN;
2134		case '!':   return F_EXCL;
2135		case '@':   return F_COMMA;
2136		case '#':   return F_DIVIDE;
2137		case '$':   return F_CURRENCY;
2138		case '%':   return F_PERCENT;
2139		case '^':   return F_MUL;
2140		case '&':   return F_BCOMMA;
2141		case '*':   return F_STAR;
2142		case '(':   return F_LPARENT;
2143		case ')':   return F_RPARENT;
2144		case '-':   return F_MINUS;
2145		case '_':   return F_UNDERLINE;
2146		case '=':   return F_EQUALS;
2147		case '+':   return F_PLUS;
2148		case '\\':  return F_BSLASH;
2149		case '|':   return F_PIPE;
2150		case ':':   return F_DCOLON;
2151		case '"':   return F_SEMICOLON;
2152		case '.':   return F_PERIOD;
2153		case '/':   return F_SLASH;
2154		case '<':   return F_LESS;
2155		case '>':   return F_GREATER;
2156		case '?':   return F_QUESTION;
2157		case ' ':   return F_BLANK;
2158	    }
2159
2160	    break;
2161
2162	case 'a':   return _SHIN;
2163	case 'A':   return WAW_H;
2164	case 'b':   return ZAL;
2165	case 'c':   return ZE;
2166	case 'C':   return JE;
2167	case 'd':   return _YE;
2168	case 'D':   return _YEE;
2169	case 'e':   return _SE;
2170	case 'f':   return _BE;
2171	case 'g':   return _LAM;
2172	case 'G':
2173		    if (cmd_gchar(AT_CURSOR) == _LAM )
2174		{
2175		    cmd_pchar(LAM, AT_CURSOR);
2176			    return ALEF_U_H;
2177		}
2178
2179		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
2180			return ALEF_U_H_;
2181		else
2182			return ALEF_U_H;
2183	case 'h':
2184		    if (cmd_gchar(AT_CURSOR) == _LAM )
2185		{
2186		    cmd_pchar(LA, AT_CURSOR);
2187		    redrawcmdline();
2188		    return K_IGNORE;
2189		}
2190
2191		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
2192			return ALEF_;
2193		else
2194			return ALEF;
2195	case 'i':
2196		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
2197			return _HE_;
2198		else
2199			return _HE;
2200	case 'j':   return _TE;
2201	case 'J':
2202		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
2203			return TEE_;
2204		else
2205			return TEE;
2206	case 'k':   return _NOON;
2207	case 'l':   return _MIM;
2208	case 'm':   return _PE;
2209	case 'n':
2210	case 'N':   return DAL;
2211	case 'o':   return _XE;
2212	case 'p':   return _HE_J;
2213	case 'q':   return _ZAD;
2214	case 'r':   return _GHAF;
2215	case 's':   return _SIN;
2216	case 'S':   return _IE;
2217	case 't':   return _FE;
2218	case 'u':
2219		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
2220			return _AYN_;
2221		else
2222			return _AYN;
2223	case 'v':
2224	case 'V':   return RE;
2225	case 'w':   return _SAD;
2226	case 'x':
2227	case 'X':   return _TA;
2228	case 'y':
2229		if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
2230			return _GHAYN_;
2231		else
2232			return _GHAYN;
2233	case 'z':
2234	case 'Z':   return _ZA;
2235	case ';':   return _KAF;
2236	case '\'':  return _GAF;
2237	case ',':   return WAW;
2238	case '[':   return _JIM;
2239	case ']':   return _CHE;
2240	}
2241
2242	return c;
2243}
2244
2245/*
2246 * F_isalpha returns TRUE if 'c' is a Farsi alphabet
2247 */
2248    int
2249F_isalpha(c)
2250    int	c;
2251{
2252    return (( c >= TEE_ && c <= _YE)
2253	    || (c >= ALEF_A && c <= YE)
2254	    || (c >= _IE && c <= YE_));
2255}
2256
2257/*
2258 * F_isdigit returns TRUE if 'c' is a Farsi digit
2259 */
2260    int
2261F_isdigit(c)
2262    int	c;
2263{
2264    return (c >= FARSI_0 && c <= FARSI_9);
2265}
2266
2267/*
2268 * F_ischar returns TRUE if 'c' is a Farsi character.
2269 */
2270    int
2271F_ischar(c)
2272    int	c;
2273{
2274    return (c >= TEE_ && c <= YE_);
2275}
2276
2277    void
2278farsi_fkey(cap)
2279    cmdarg_T	*cap;
2280{
2281    int		c = cap->cmdchar;
2282
2283    if (c == K_F8)
2284    {
2285	if (p_altkeymap)
2286	{
2287	    if (curwin->w_farsi & W_R_L)
2288	    {
2289		p_fkmap = 0;
2290		do_cmdline_cmd((char_u *)"set norl");
2291		MSG("");
2292	    }
2293	    else
2294	    {
2295		p_fkmap = 1;
2296		do_cmdline_cmd((char_u *)"set rl");
2297		MSG("");
2298	    }
2299
2300	    curwin->w_farsi = curwin->w_farsi ^ W_R_L;
2301	}
2302    }
2303
2304    if (c == K_F9)
2305    {
2306	if (p_altkeymap && curwin->w_p_rl)
2307	{
2308	    curwin->w_farsi = curwin->w_farsi ^ W_CONV;
2309	    if (curwin->w_farsi & W_CONV)
2310		conv_to_pvim();
2311	    else
2312		conv_to_pstd();
2313	}
2314    }
2315}
2316