dir.c (3005B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include "vi.h" 5 6 static struct rset *dir_rslr; /* pattern of marks for left-to-right strings */ 7 static struct rset *dir_rsrl; /* pattern of marks for right-to-left strings */ 8 static struct rset *dir_rsctx; /* direction context patterns */ 9 10 static int dir_match(char **chrs, int beg, int end, int ctx, int *rec, 11 int *r_beg, int *r_end, int *c_beg, int *c_end, int *dir) 12 { 13 int subs[16 * 2]; 14 struct rset *rs = ctx < 0 ? dir_rsrl : dir_rslr; 15 struct sbuf *str = sbuf_make(); 16 int grp; 17 int flg = (beg ? RE_NOTBOL : 0) | (chrs[end][0] ? RE_NOTEOL : 0); 18 int found = -1; 19 sbuf_mem(str, chrs[beg], chrs[end] - chrs[beg]); 20 if (rs) 21 found = rset_find(rs, sbuf_buf(str), LEN(subs) / 2, subs, flg); 22 if (found >= 0 && r_beg && r_end && c_beg && c_end) { 23 char *s = sbuf_buf(str); 24 conf_dirmark(found, NULL, NULL, dir, &grp); 25 *r_beg = beg + uc_off(s, subs[0]); 26 *r_end = beg + uc_off(s, subs[1]); 27 *c_beg = subs[grp * 2 + 0] >= 0 ? 28 beg + uc_off(s, subs[grp * 2 + 0]) : *r_beg; 29 *c_end = subs[grp * 2 + 1] >= 0 ? 30 beg + uc_off(s, subs[grp * 2 + 1]) : *r_end; 31 *rec = grp > 0; 32 } 33 sbuf_free(str); 34 return found < 0; 35 } 36 37 static void dir_reverse(int *ord, int beg, int end) 38 { 39 end--; 40 while (beg < end) { 41 int tmp = ord[beg]; 42 ord[beg] = ord[end]; 43 ord[end] = tmp; 44 beg++; 45 end--; 46 } 47 } 48 49 /* reorder the characters based on direction marks and characters */ 50 static void dir_fix(char **chrs, int *ord, int dir, int beg, int end) 51 { 52 int r_beg, r_end, c_beg, c_end; 53 int c_dir, c_rec; 54 while (beg < end && !dir_match(chrs, beg, end, dir, &c_rec, 55 &r_beg, &r_end, &c_beg, &c_end, &c_dir)) { 56 if (dir < 0) 57 dir_reverse(ord, r_beg, r_end); 58 if (c_dir < 0) 59 dir_reverse(ord, c_beg, c_end); 60 if (c_beg == r_beg) 61 c_beg++; 62 if (c_rec) 63 dir_fix(chrs, ord, c_dir, c_beg, c_end); 64 beg = r_end; 65 } 66 } 67 68 /* return the direction context of the given line */ 69 int dir_context(char *s) 70 { 71 int found = -1; 72 int dir; 73 if (xtd > +1) 74 return +1; 75 if (xtd < -1) 76 return -1; 77 if (dir_rsctx) 78 found = rset_find(dir_rsctx, s ? s : "", 0, NULL, 0); 79 if (!conf_dircontext(found, NULL, &dir)) 80 return dir; 81 return xtd < 0 ? -1 : +1; 82 } 83 84 /* reorder the characters in s */ 85 void dir_reorder(char *s, int *ord) 86 { 87 int n; 88 char **chrs = uc_chop(s, &n); 89 int dir = dir_context(s); 90 if (n && chrs[n - 1][0] == '\n') { 91 ord[n - 1] = n - 1; 92 n--; 93 } 94 dir_fix(chrs, ord, dir, 0, n); 95 free(chrs); 96 } 97 98 void dir_init(void) 99 { 100 char *relr[128]; 101 char *rerl[128]; 102 char *ctx[128]; 103 int curctx, i; 104 char *pat; 105 for (i = 0; !conf_dirmark(i, &pat, &curctx, NULL, NULL); i++) { 106 relr[i] = curctx >= 0 ? pat : NULL; 107 rerl[i] = curctx <= 0 ? pat : NULL; 108 } 109 dir_rslr = rset_make(i, relr, 0); 110 dir_rsrl = rset_make(i, rerl, 0); 111 for (i = 0; !conf_dircontext(i, &pat, NULL); i++) 112 ctx[i] = pat; 113 dir_rsctx = rset_make(i, ctx, 0); 114 } 115 116 void dir_done(void) 117 { 118 if (dir_rslr) 119 rset_free(dir_rslr); 120 if (dir_rsrl) 121 rset_free(dir_rsrl); 122 if (dir_rsctx) 123 rset_free(dir_rsctx); 124 }