tdir.c - neatvi - [fork] simple vi-type editor with UTF-8 support
 (HTM) git clone git://src.adamsgaard.dk/neatvi
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
       tdir.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 }