samrc.c - sam - An updated version of the sam text editor.
 (HTM) git clone git://vernunftzentrum.de/sam.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
       samrc.c (13604B)
       ---
            1 #include <stdio.h>
            2 #include <stdlib.h>
            3 #include <string.h>
            4 #include <strings.h>
            5 #include <X11/Xlib.h>
            6 #include <X11/keysym.h>
            7 
            8 #include <u.h>
            9 #include <libg.h>
           10 #include <frame.h>
           11 #include "flayer.h"
           12 #include "samterm.h"
           13 
           14 extern bool expandtabs;
           15 extern int tabwidth;
           16 extern bool autoindent;
           17 
           18 typedef struct Namemapping Namemapping;
           19 struct Namemapping{
           20     const char *name;
           21     int value;
           22 };
           23 
           24 static Namemapping commandmapping[] ={
           25     {"none",            Cnone},
           26     {"default",         Cdefault},
           27     {"escape",          Cescape},
           28     {"scrolldown",      Cscrolldown},
           29     {"scrollup",        Cscrollup},
           30     {"scrolldownline",  Cscrolldownline},
           31     {"scrollupline",    Cscrollupline},
           32     {"jump",            Cjump},
           33     {"charright",       Ccharright},
           34     {"charleft",        Ccharleft},
           35     {"linedown",        Clinedown},
           36     {"lineup",          Clineup},
           37     {"delword",         Cdelword},
           38     {"delbol",          Cdelbol},
           39     {"delbs",           Cdelbs},
           40     {"del",             Cdel},
           41     {"snarf",           Csnarf},
           42     {"cut",             Ccut},
           43     {"paste",           Cpaste},
           44     {"exchange",        Cexchange},
           45     {"eol",             Ceol},
           46     {"bol",             Cbol},
           47     {"tab",             Ctab},
           48     {"send",            Csend},
           49     {"look",            Clook},
           50     {"search",          Csearch},
           51     {"write",           Cwrite},
           52     {NULL, 0}
           53 };
           54 
           55 static Namemapping targetmapping[] ={
           56     {"current",     Tcurrent},
           57     {"mouse",       Tmouse},
           58     {NULL, 0}
           59 };
           60 
           61 static Namemapping buttonmapping[] ={
           62     {"0",  0}, 
           63     {"n",  0}, 
           64 #define B1 1
           65     {"1",  1}, 
           66 #define B2 2
           67     {"2",  2}, 
           68 #define B3 4
           69     {"3",  4}, 
           70 #define B4 8
           71     {"4",  8}, 
           72 #define B5 16
           73     {"5", 16}, 
           74     {NULL, 0}
           75 };
           76 
           77 static Namemapping modmapping[] ={
           78     {"*", 0},
           79     {"c", ControlMask}, 
           80     {"a", Mod1Mask},
           81     {"s", ShiftMask},
           82     {NULL, 0}
           83 };
           84 
           85 static int
           86 lookupmapping(const char *n, Namemapping *m)
           87 {
           88     for (Namemapping *k = m; k->name != NULL; k++){
           89         if (strcasecmp(k->name, n) == 0)
           90             return k->value;
           91     }
           92 
           93     return -1;
           94 }
           95 
           96 #define nametocommand(n) lookupmapping(n, commandmapping)
           97 #define nametotarget(n) lookupmapping(n, targetmapping)
           98 
           99 typedef struct Defaultbinding Defaultbinding;
          100 struct Defaultbinding{
          101     int modifiers;
          102     KeySym keysym;
          103     int kind;
          104     int command;
          105     const char *arg;
          106 };
          107 
          108 static Defaultbinding defaultbindings[] ={    
          109     /* Suppress control key combinations unless explicitly bound. */
          110     {ControlMask, XK_VoidSymbol,    Kcommand, Cnone,        NULL},
          111 
          112     /* Motion commands following the WordStar diamond. */
          113     {ControlMask, XK_e,             Kcommand,  Clineup,     NULL},
          114     {ControlMask, XK_x,             Kcommand,  Clinedown,   NULL},
          115     {ControlMask, XK_d,             Kcommand,  Ccharright,  NULL},
          116     {ControlMask, XK_s,             Kcommand,  Ccharleft,   NULL},
          117     {ControlMask, XK_u,             Kcommand,  Cdelbol,     NULL},
          118     {ControlMask, XK_w,             Kcommand,  Cdelword,    NULL},
          119     {ControlMask, XK_k,             Kcommand,  Cjump,       NULL},
          120     {ControlMask, XK_BackSpace,     Kcommand,  Cdelword,    NULL},
          121     {ControlMask, XK_y,             Kcommand,  Ccut,        NULL},
          122     {ControlMask, XK_c,             Kcommand,  Csnarf,      NULL},
          123     {ControlMask, XK_v,             Kcommand,  Cpaste,      NULL},
          124     {ControlMask, XK_q,             Kcommand,  Cexchange,   NULL},
          125 
          126     /* Handle arrow keys, page up/down, and escape. */
          127     {0,           XK_Up,            Kcommand, Cscrollup,    NULL},
          128     {0,           XK_Prior,         Kcommand, Cscrollup,    NULL},
          129     {0,           XK_Left,          Kcommand, Cscrollup,    NULL},
          130     {0,           XK_Down,          Kcommand, Cscrolldown,  NULL},
          131     {0,           XK_Next,          Kcommand, Cscrolldown,  NULL},
          132     {0,           XK_Right,         Kcommand, Cscrolldown,  NULL},
          133     {0,           XK_Escape,        Kcommand, Cescape,      NULL},
          134     
          135     /* More fundamental stuff: backspace, delete, etc. */
          136     {0,           XK_BackSpace,     Kcommand, Cdelbs,   NULL},
          137     {0,           XK_Delete,        Kcommand, Cdel,     NULL},
          138     {0,           XK_Tab,           Kcommand, Ctab,     NULL},
          139     {0,           XK_Return,        Kraw,     '\n',     NULL},
          140     {0,           XK_KP_Enter,      Kraw,     '\n',     NULL},
          141     {0,           XK_Linefeed,      Kraw,     '\r',     NULL},
          142     {0,           XK_KP_0,          Kraw,     '0',      NULL},
          143     {0,           XK_KP_1,          Kraw,     '1',      NULL},
          144     {0,           XK_KP_2,          Kraw,     '2',      NULL},
          145     {0,           XK_KP_3,          Kraw,     '3',      NULL},
          146     {0,           XK_KP_4,          Kraw,     '4',      NULL},
          147     {0,           XK_KP_5,          Kraw,     '5',      NULL},
          148     {0,           XK_KP_6,          Kraw,     '6',      NULL},
          149     {0,           XK_KP_7,          Kraw,     '7',      NULL},
          150     {0,           XK_KP_8,          Kraw,     '8',      NULL},
          151     {0,           XK_KP_9,          Kraw,     '9',      NULL},
          152     {0,           XK_KP_Divide,     Kraw,     '/',      NULL},
          153     {0,           XK_KP_Multiply,   Kraw,     '*',      NULL},
          154     {0,           XK_KP_Subtract,   Kraw,     '-',      NULL},
          155     {0,           XK_KP_Add,        Kraw,     '+',      NULL},
          156     {0,           XK_KP_Decimal,    Kraw,     '.',      NULL},
          157     {0,           XK_hyphen,        Kraw,     '-',      NULL},
          158 
          159     /* Support traditional control sequences. */
          160     {ControlMask, XK_bracketleft,   Kcommand, Cescape,  NULL},
          161     {ControlMask, XK_h,             Kcommand, Cdelbs,   NULL},
          162     {ControlMask, XK_Delete,        Kcommand, Cdel,     NULL},
          163     {ControlMask, XK_i,             Kcommand, Ctab,     NULL},
          164     {ControlMask, XK_j,             Kraw,     '\n',     NULL},
          165     {ControlMask, XK_m,             Kraw,     '\r',     NULL},
          166 
          167     /* Use Control-Tab to insert a literal tab when tab expansion is enabled. */
          168     {ControlMask, XK_Tab,           Kraw,     '\t',     NULL},
          169 
          170     {0,           0,                Kend,     0,        NULL}
          171 };
          172 
          173 void
          174 installdefaultbindings(void)
          175 {
          176     for (Defaultbinding *b = defaultbindings; b->kind != Kend; b++)
          177         installbinding(b->modifiers, b->keysym, b->kind, b->command, b->arg);
          178 }
          179 
          180 typedef struct Defaultchord Defaultchord;
          181 struct Defaultchord{
          182     int state1;
          183     int state2;
          184     int command;
          185     int target;
          186     const char *arg;
          187 };
          188 
          189 static Defaultchord defaultchords[] ={
          190     {B1, B1|B2,  Ccut,   Tcurrent, NULL},
          191     {B1, B1|B3,  Cpaste, Tcurrent, NULL},
          192     {B1|B2, B1,  Cnone,  Tcurrent, NULL},
          193     {B1|B3, B1,  Cnone,  Tcurrent, NULL},
          194 
          195     {B4, 0,  Cscrollupline,   Tmouse, NULL},
          196     {B5, 0,  Cscrolldownline, Tmouse, NULL},
          197 
          198     {0, 0, Kend, 0, NULL}
          199 };
          200 
          201 void
          202 installdefaultchords(void)
          203 {
          204     for (Defaultchord *c = defaultchords; c->state1 != 0; c++)
          205         installchord(c->state1, c->state2, c->command, c->target, c->arg);
          206 }
          207 
          208 static int
          209 statetomask(const char *n, Namemapping *m)
          210 {
          211     int r = 0;
          212     for (int i = 0; n[i] != 0; i++){
          213         char s[2] = {n[i], 0};
          214         int v = lookupmapping(s, m);
          215         if (v < 0)
          216             return -1;
          217         r |= v;
          218     }
          219 
          220     return r;
          221 }
          222 
          223 #define buttontomask(n) statetomask(n, buttonmapping)
          224 #define modtomask(n) statetomask(n, modmapping)
          225 
          226 static KeySym
          227 nametokeysym(const char *n)
          228 {
          229     KeySym k, l, u;
          230 
          231     k = XStringToKeysym(n);
          232     XConvertCase(k, &l, &u);
          233     return l;
          234 }
          235 
          236 static int
          237 dirfollowfocus(const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
          238 {
          239     if (strcasecmp(s1, "true") != 0 && strcasecmp(s1, "false") != 0)
          240         return -1;
          241 
          242     followfocus = (strcasecmp(s1, "true") == 0);
          243     return 0;
          244 }
          245 
          246 static int
          247 dirsnarfselection(const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
          248 {
          249     extern const char *clipatom;
          250 
          251     if (strcasecmp(s1, "primary") == 0)
          252         clipatom = "PRIMARY";
          253     else if (strcasecmp(s1, "secondary") == 0)
          254         clipatom = "SECONDARY";
          255     else if (strcasecmp(s1, "clipboard") == 0)
          256         clipatom = "CLIPBOARD";
          257     else
          258         return -1;
          259 
          260     return 0;
          261 }
          262 
          263 static int
          264 dirchord(const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
          265 {
          266     return installchord(buttontomask(s1), buttontomask(s2), nametocommand(s3), nametotarget(s4), s5);
          267 }
          268 
          269 static int
          270 dirraw(const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
          271 {
          272     return installbinding(modtomask(s1), nametokeysym(s2), Kraw, strtol(s3, NULL, 16), NULL);
          273 }
          274 
          275 static int
          276 dirrawliteral(const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
          277 {
          278     if (strlen(s3) != 1)
          279         return -1;
          280     return installbinding(modtomask(s1), nametokeysym(s2), Kraw, s3[0], NULL);
          281 }
          282 
          283 static int
          284 dirbind(const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
          285 {
          286     return installbinding(modtomask(s1), nametokeysym(s2), Kcommand, nametocommand(s3), s4);
          287 }
          288 
          289 static int
          290 dirunbind(const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
          291 {
          292     return removebinding(modtomask(s1), nametokeysym(s2));
          293 }
          294 
          295 static int
          296 dirunchord(const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
          297 {
          298     return removechord(buttontomask(s1), buttontomask(s2));
          299 }
          300 
          301 static int
          302 dirforeground(const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
          303 {
          304     if (strlen(s1) == 0)
          305         return -1;
          306 
          307     strncpy(foregroundspec, s1, sizeof(foregroundspec) - 1);
          308     return 0;
          309 }
          310 
          311 static int
          312 dirbackground(const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
          313 {
          314     if (strlen(s1) == 0)
          315         return -1;
          316 
          317     strncpy(backgroundspec, s1, sizeof(backgroundspec) - 1);
          318     return 0;
          319 }
          320 
          321 static int
          322 dirborder(const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
          323 {
          324     if (strlen(s1) == 0)
          325         return -1;
          326 
          327     strncpy(borderspec, s1, sizeof(borderspec) - 1);
          328     return 0;
          329 }
          330 
          331 static int
          332 dirfont(const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
          333 {
          334     if (strlen(s1) == 0)
          335         return -1;
          336 
          337     strncpy(fontspec, s1, sizeof(fontspec) - 1);
          338     return 0;
          339 }
          340 
          341 static int
          342 dirtabs(const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
          343 {
          344     int i = atoi(s1);
          345     if (i <= 0 || i > 12)
          346         return -1;
          347 
          348     tabwidth = i;
          349     return 0;
          350 }
          351 
          352 static int
          353 direxpandtabs(const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
          354 {
          355     if (strcasecmp(s1, "true") != 0 && strcasecmp(s1, "false") != 0)
          356         return -1;
          357 
          358     expandtabs = (strcasecmp(s1, "true") == 0);
          359     return 0;
          360 }
          361 
          362 static int
          363 dirautoindent(const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
          364 {
          365     if (strcasecmp(s1, "true") != 0 && strcasecmp(s1, "false") != 0)
          366         return -1;
          367 
          368     autoindent = (strcasecmp(s1, "true") == 0);
          369     return 0;
          370 }
          371 
          372 static int
          373 dircomment(const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
          374 {
          375     return 0;
          376 }
          377 
          378 typedef struct Directive Directive;
          379 struct Directive{
          380     const char *format;
          381     int result;
          382     int (*action)(const char *, const char *, const char *, const char *, const char *);
          383 };
          384 
          385 Directive directives[] ={
          386     {" chord %5[Nn12345] %5[Nn12345] %99s %99s %1023[^\n]",       5,   dirchord},
          387     {" chord %5[Nn12345] %5[Nn12345] %99s %99s",                  4,   dirchord},
          388     {" unchord %5[Nn12345] %5[Nn12345]",                          2,   dirunchord},
          389     {" bind %5[*camshNCAMSH12345] %99s raw 0x%4[0-9a-fA-F]",      3,   dirraw},
          390     {" bind %5[*camshNCAMSH12345] %99s raw %1s",                  3,   dirrawliteral},
          391     {" bind %5[*camshNCAMSH12345] %99s command %99s %1023[^\n]",  4,   dirbind},
          392     {" bind %5[*camshNCAMSH12345] %99s command %99s",             3,   dirbind},
          393     {" unbind %5[*camshNCAMSH12345] %99s",                        2,   dirunbind},
          394     {" foreground %1023s",                                        1,   dirforeground},
          395     {" background %1023s",                                        1,   dirbackground},
          396     {" border %1023s",                                            1,   dirborder},
          397     {" font %1023[^\n]",                                          1,   dirfont},
          398     {" tabs %2[0-9]",                                             1,   dirtabs},
          399     {" expandtabs %99s",                                          1,   direxpandtabs},
          400     {" autoindent %99s",                                          1,   dirautoindent},
          401     {" snarfselection %99s",                                      1,   dirsnarfselection},
          402     {" followfocus %99s",                                         1,   dirfollowfocus},
          403     {" %1[#]",                                                    1,   dircomment},
          404     {" %1[^ ]",                                                   EOF, dircomment},
          405     {NULL, 0, NULL}
          406 };
          407 
          408 void
          409 loadrcfile(FILE *f)
          410 {
          411     char *l = NULL;
          412     size_t n = 0;
          413     ssize_t r = 0;
          414     size_t ln = 0;
          415 
          416     while ((r = getline(&l, &n, f)) >= 0){
          417         char s1[1024] = {0};
          418         char s2[1024] = {0};
          419         char s3[1024] = {0};
          420         char s4[1024] = {0};
          421         char s5[1024] = {0};
          422         int rc = 0;
          423         bool found = false;
          424 
          425         ln++;
          426         if (r == 0)
          427             continue;
          428 
          429         for (Directive *d = directives; d->format && !found; d++){
          430             if (sscanf(l, d->format, s1, s2, s3, s4, s5) == d->result){
          431                 rc = d->action(s1, s2, s3, s4, s5);
          432                 found = true;
          433             }
          434         }
          435 
          436         if (!found)
          437             fprintf(stderr, "invalid rc line %zd\n", ln);
          438 
          439         if (rc != 0)
          440             fprintf(stderr, "invalid chord/binding on rc line %zd\n", ln);
          441     }
          442 
          443     free(l);
          444 }