samrc.c - sam - An updated version of the sam text editor. | |
git clone git://vernunftzentrum.de/sam.git | |
Log | |
Files | |
Refs | |
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 ena… | |
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->… | |
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 cha… | |
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 … | |
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,… | |
265 { | |
266 return installchord(buttontomask(s1), buttontomask(s2), nametocomman… | |
267 } | |
268 | |
269 static int | |
270 dirraw(const char *s1, const char *s2, const char *s3, const char *s4, c… | |
271 { | |
272 return installbinding(modtomask(s1), nametokeysym(s2), Kraw, strtol(… | |
273 } | |
274 | |
275 static int | |
276 dirrawliteral(const char *s1, const char *s2, const char *s3, const char… | |
277 { | |
278 if (strlen(s3) != 1) | |
279 return -1; | |
280 return installbinding(modtomask(s1), nametokeysym(s2), Kraw, s3[0], … | |
281 } | |
282 | |
283 static int | |
284 dirbind(const char *s1, const char *s2, const char *s3, const char *s4, … | |
285 { | |
286 return installbinding(modtomask(s1), nametokeysym(s2), Kcommand, nam… | |
287 } | |
288 | |
289 static int | |
290 dirunbind(const char *s1, const char *s2, const char *s3, const char *s4… | |
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 *s… | |
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… | |
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… | |
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… | |
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, … | |
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, … | |
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… | |
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… | |
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 *s… | |
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 *… | |
383 }; | |
384 | |
385 Directive directives[] ={ | |
386 {" chord %5[Nn12345] %5[Nn12345] %99s %99s %1023[^\n]", 5, d… | |
387 {" chord %5[Nn12345] %5[Nn12345] %99s %99s", 4, d… | |
388 {" unchord %5[Nn12345] %5[Nn12345]", 2, d… | |
389 {" bind %5[*camshNCAMSH12345] %99s raw 0x%4[0-9a-fA-F]", 3, d… | |
390 {" bind %5[*camshNCAMSH12345] %99s raw %1s", 3, d… | |
391 {" bind %5[*camshNCAMSH12345] %99s command %99s %1023[^\n]", 4, d… | |
392 {" bind %5[*camshNCAMSH12345] %99s command %99s", 3, d… | |
393 {" unbind %5[*camshNCAMSH12345] %99s", 2, d… | |
394 {" foreground %1023s", 1, d… | |
395 {" background %1023s", 1, d… | |
396 {" border %1023s", 1, d… | |
397 {" font %1023[^\n]", 1, d… | |
398 {" tabs %2[0-9]", 1, d… | |
399 {" expandtabs %99s", 1, d… | |
400 {" autoindent %99s", 1, d… | |
401 {" snarfselection %99s", 1, d… | |
402 {" followfocus %99s", 1, d… | |
403 {" %1[#]", 1, d… | |
404 {" %1[^ ]", EOF, d… | |
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 } |