lbuf: useq should always be nonzero
[neatvi.git] / dir.c
blob3f43bc3da766d8a446a2a7b66fa0ab2d992eb165
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "vi.h"
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 */
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)
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;
19 sbuf_mem(str, chrs[beg], chrs[end] - chrs[beg]);
20 found = rset_find(rs, sbuf_buf(str), LEN(subs) / 2, subs, flg);
21 if (found >= 0 && r_beg && r_end && c_beg && c_end) {
22 char *s = sbuf_buf(str);
23 conf_dirmark(found, NULL, NULL, dir, &grp);
24 *r_beg = beg + uc_off(s, subs[0]);
25 *r_end = beg + uc_off(s, subs[1]);
26 *c_beg = subs[grp * 2 + 0] >= 0 ?
27 beg + uc_off(s, subs[grp * 2 + 0]) : *r_beg;
28 *c_end = subs[grp * 2 + 1] >= 0 ?
29 beg + uc_off(s, subs[grp * 2 + 1]) : *r_end;
30 *rec = grp > 0;
32 sbuf_free(str);
33 return found < 0;
36 static void dir_reverse(int *ord, int beg, int end)
38 end--;
39 while (beg < end) {
40 int tmp = ord[beg];
41 ord[beg] = ord[end];
42 ord[end] = tmp;
43 beg++;
44 end--;
48 /* reorder the characters based on direction marks and characters */
49 static void dir_fix(char **chrs, int *ord, int dir, int beg, int end)
51 int r_beg, r_end, c_beg, c_end;
52 int c_dir, c_rec;
53 while (beg < end && !dir_match(chrs, beg, end, dir, &c_rec,
54 &r_beg, &r_end, &c_beg, &c_end, &c_dir)) {
55 if (dir < 0)
56 dir_reverse(ord, r_beg, r_end);
57 if (c_dir < 0)
58 dir_reverse(ord, c_beg, c_end);
59 if (c_beg == r_beg)
60 c_beg++;
61 if (c_rec)
62 dir_fix(chrs, ord, c_dir, c_beg, c_end);
63 beg = r_end;
67 int dir_context(char *s)
69 int found;
70 int dir;
71 if (xdir > +1)
72 return +1;
73 if (xdir < -1)
74 return -1;
75 found = rset_find(dir_rsctx, s ? s : "", 0, NULL, 0);
76 if (!conf_dircontext(found, NULL, &dir))
77 return dir;
78 return xdir < 0 ? -1 : +1;
81 /* reorder the characters in s */
82 void dir_reorder(char *s, int *ord)
84 int n;
85 char **chrs = uc_chop(s, &n);
86 int dir = dir_context(s);
87 if (n && chrs[n - 1][0] == '\n') {
88 ord[n - 1] = n - 1;
89 n--;
91 dir_fix(chrs, ord, dir, 0, n);
92 free(chrs);
95 void dir_init(void)
97 char *relr[128];
98 char *rerl[128];
99 char *ctx[128];
100 int curctx, i;
101 char *pat;
102 for (i = 0; !conf_dirmark(i, &pat, &curctx, NULL, NULL); i++) {
103 relr[i] = curctx >= 0 ? pat : NULL;
104 rerl[i] = curctx <= 0 ? pat : NULL;
106 dir_rslr = rset_make(i, relr, 0);
107 dir_rsrl = rset_make(i, rerl, 0);
108 for (i = 0; !conf_dircontext(i, &pat, NULL); i++)
109 ctx[i] = pat;
110 dir_rsctx = rset_make(i, ctx, 0);
113 void dir_done(void)
115 rset_free(dir_rslr);
116 rset_free(dir_rsrl);
117 rset_free(dir_rsctx);