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 }