6 #define CR2L "ءآأؤإئابةتثجحخدذرزسشصضطظعغـفقكلمنهوىييپچژکگی؛،»«؟"
7 #define CNEUT "-!\"#$%&'()*+,./:;<=>?@^_`{|}~ "
9 /* direction context patterns */
10 static struct dcontext
{
15 {+1, "^[a-zA-Z_0-9]"},
20 int ctx
; /* the direction context for this mark; 0 means any */
21 int dir
; /* the direction of matched text */
22 int grp
; /* the nested subgroup; 0 means no groups */
25 {+0, +1, 0, "$([^$]+)\\$"},
26 {+0, +1, 1, "\\\\\\*\\[([^]]+)\\]"},
27 {+1, -1, 0, "[" CR2L
"][" CNEUT CR2L
"]*[" CR2L
"]"},
28 {-1, +1, 0, "[a-zA-Z0-9_][^" CR2L
"\\\\`$']*[a-zA-Z0-9_]"},
31 static struct rset
*dir_rslr
; /* pattern of marks for left-to-right strings */
32 static struct rset
*dir_rsrl
; /* pattern of marks for right-to-left strings */
33 static struct rset
*dir_rsctx
; /* direction context patterns */
35 static int dir_match(char **chrs
, int beg
, int end
, int ctx
, int *rec
,
36 int *r_beg
, int *r_end
, int *c_beg
, int *c_end
, int *dir
)
39 struct rset
*rs
= ctx
< 0 ? dir_rsrl
: dir_rslr
;
40 struct sbuf
*str
= sbuf_make();
41 int flg
= (beg
? RE_NOTBOL
: 0) | (chrs
[end
][0] ? RE_NOTEOL
: 0);
43 sbuf_mem(str
, chrs
[beg
], chrs
[end
] - chrs
[beg
]);
44 found
= rset_find(rs
, sbuf_buf(str
), LEN(subs
) / 2, subs
, flg
);
45 if (found
>= 0 && r_beg
&& r_end
&& c_beg
&& c_end
) {
46 struct dmark
*dm
= &dmarks
[found
];
47 char *s
= sbuf_buf(str
);
49 *r_beg
= beg
+ uc_off(s
, subs
[0]);
50 *r_end
= beg
+ uc_off(s
, subs
[1]);
51 *c_beg
= subs
[grp
* 2 + 0] >= 0 ?
52 beg
+ uc_off(s
, subs
[grp
* 2 + 0]) : *r_beg
;
53 *c_end
= subs
[grp
* 2 + 1] >= 0 ?
54 beg
+ uc_off(s
, subs
[grp
* 2 + 1]) : *r_end
;
62 static void dir_reverse(int *ord
, int beg
, int end
)
74 /* reorder the characters based on direction marks and characters */
75 static void dir_fix(char **chrs
, int *ord
, int dir
, int beg
, int end
)
77 int r_beg
, r_end
, c_beg
, c_end
;
79 while (beg
< end
&& !dir_match(chrs
, beg
, end
, dir
, &c_rec
,
80 &r_beg
, &r_end
, &c_beg
, &c_end
, &c_dir
)) {
82 dir_reverse(ord
, r_beg
, r_end
);
84 dir_reverse(ord
, c_beg
, c_end
);
88 dir_fix(chrs
, ord
, c_dir
, c_beg
, c_end
);
93 int dir_context(char *s
)
100 found
= rset_find(dir_rsctx
, s
? s
: "", 0, NULL
, 0);
102 return dcontexts
[found
].dir
;
103 return xdir
== 'r' ? -1 : +1;
106 /* reorder the characters in s */
107 void dir_reorder(char *s
, int *ord
)
110 char **chrs
= uc_chop(s
, &n
);
111 int dir
= dir_context(s
);
112 if (n
&& chrs
[n
- 1][0] == '\n') {
116 dir_fix(chrs
, ord
, dir
, 0, n
);
126 for (i
= 0; i
< LEN(dmarks
); i
++) {
127 relr
[i
] = dmarks
[i
].ctx
>= 0 ? dmarks
[i
].pat
: NULL
;
128 rerl
[i
] = dmarks
[i
].ctx
<= 0 ? dmarks
[i
].pat
: NULL
;
130 dir_rslr
= rset_make(LEN(dmarks
), relr
, 0);
131 dir_rsrl
= rset_make(LEN(dmarks
), rerl
, 0);
132 for (i
= 0; i
< LEN(dcontexts
); i
++)
133 ctx
[i
] = dcontexts
[i
].pat
;
134 dir_rsctx
= rset_make(LEN(dcontexts
), ctx
, 0);
141 rset_free(dir_rsctx
);