6e182d98 |
1 | #include <stdio.h> |
2 | #include <stdlib.h> |
3 | #include <string.h> |
4 | #include <ctype.h> |
5 | |
6 | #include "tweak.h" |
7 | |
8 | #if defined(unix) && !defined(GO32) |
9 | #define RCNAME ".tweakrc" |
10 | #elif defined(MSDOS) |
11 | #define RCNAME "tweak.rc" |
12 | #endif |
13 | |
14 | static char *default_rc[] = { |
15 | "# Default "RCNAME" generated by `tweak -D'.", |
16 | "#", |
17 | "# Key bindings: movement keys", |
18 | "bind top-of-file ^[<", |
19 | #if defined(unix) && !defined(GO32) |
20 | "bind page-up ^[[5~", |
21 | #elif defined(MSDOS) |
22 | "bind page-up ^@I", |
23 | "bind page-up ^@/", |
24 | #endif |
25 | "bind page-up ^[V", |
26 | "bind page-up ^[v", |
27 | "bind move-up ^P", |
28 | #if defined(unix) && !defined(GO32) |
29 | "bind move-up ^[[A", |
30 | #elif defined(MSDOS) |
31 | "bind move-up ^@H", |
32 | #endif |
33 | "bind begin-line ^A", |
34 | #if defined(unix) && !defined(GO32) |
35 | "bind begin-line ^[[H", |
36 | "bind begin-line ^[[1~", |
37 | #elif defined(MSDOS) |
38 | "bind begin-line ^@G", |
39 | #endif |
40 | "bind move-left ^B", |
41 | #if defined(unix) && !defined(GO32) |
42 | "bind move-left ^[[D", |
43 | #elif defined(MSDOS) |
44 | "bind move-left ^@K", |
45 | #endif |
46 | "bind move-right ^F", |
47 | #if defined(unix) && !defined(GO32) |
48 | "bind move-right ^[[C", |
49 | #elif defined(MSDOS) |
50 | "bind move-right ^@M", |
51 | #endif |
52 | "bind end-line ^E", |
53 | #if defined(unix) && !defined(GO32) |
54 | "bind end-line ^[Ow", |
55 | "bind end-line ^[[4~", |
56 | #elif defined(MSDOS) |
57 | "bind end-line ^@O", |
58 | #endif |
59 | "bind move-down ^N", |
60 | #if defined(unix) && !defined(GO32) |
61 | "bind move-down ^[[B", |
62 | #elif defined(MSDOS) |
63 | "bind move-down ^@P", |
64 | #endif |
65 | "bind page-down ^V", |
66 | #if defined(unix) && !defined(GO32) |
67 | "bind page-down ^[[6~", |
68 | #elif defined(MSDOS) |
69 | "bind page-down ^@Q", |
70 | #endif |
71 | "bind bottom-of-file ^[>", |
72 | "", |
73 | "# Key bindings: miscellaneous editing keys", |
74 | "bind toggle-insert ^X^I", |
75 | #if defined(unix) && !defined(GO32) |
76 | "bind toggle-insert ^[[2~", |
77 | #elif defined(MSDOS) |
78 | "bind toggle-insert ^@R", |
79 | #endif |
80 | "bind change-mode ^M", |
81 | "bind change-mode ^J", |
82 | "bind quote-next ^Q", |
83 | "bind toggle-status ^XH", |
84 | "bind toggle-status ^Xh", |
85 | "bind toggle-status ^XX", |
86 | "bind toggle-status ^Xx", |
87 | "", |
88 | "# Key bindings: deletion keys", |
89 | "bind delete-left ^?", |
90 | "bind delete-left ^H", |
91 | "bind delete-right ^D", |
92 | #if defined(unix) && !defined(GO32) |
93 | "bind delete-right ^[[3~", |
94 | #elif defined(MSDOS) |
95 | "bind delete-right ^@S", |
96 | #endif |
97 | "", |
98 | "# Key bindings: cut and paste keys", |
99 | #if defined(unix) && !defined(GO32) |
100 | "bind mark-place ^@", |
101 | #elif defined(MSDOS) |
102 | "bind mark-place ^@^C", |
103 | #endif |
104 | "bind cut ^W", |
105 | "bind copy ^[W", |
106 | "bind copy ^[w", |
107 | #ifdef MSDOS |
108 | "bind copy ^@^Q", |
109 | #endif |
110 | "bind paste ^Y", |
111 | "", |
112 | "# Key bindings: additional movement keys", |
113 | "bind search ^S", |
a63728c7 |
114 | "bind search-back ^R", |
6e182d98 |
115 | "bind goto-position ^XG", |
116 | "bind goto-position ^Xg", |
117 | "bind screen-recentre ^L", |
118 | "", |
119 | "# Standard screen size parameters, plus keybindings to alter them", |
120 | "width 16", |
121 | "offset 0", |
122 | "bind new-width ^XW", |
123 | "bind new-width ^Xw", |
124 | "bind new-offset ^XO", |
125 | "bind new-offset ^Xo", |
126 | "", |
127 | "# Key bindings: overall program/file control", |
128 | "bind suspend ^Z", |
129 | "bind exit ^X^C", |
130 | "bind save-file ^X^S", |
131 | "# unbound by default: exit-and-save", |
132 | "", |
133 | #ifdef TEST_BUFFER |
134 | "bind diagnostics ^X^D", |
135 | "", |
136 | #endif |
137 | "# End of default "RCNAME, |
138 | NULL |
139 | }; |
140 | |
141 | extern char *pname; |
142 | |
143 | void read_rc (void) { |
144 | FILE *fp; |
145 | char **p, *q, *r, *s, *keyseq; |
146 | char rcbuffer[256]; |
147 | char rcname[FILENAME_MAX]; |
148 | int lineno = 0; |
149 | int errors = FALSE, errors_here; |
150 | |
151 | #if defined(unix) && !defined(GO32) |
152 | rcname[0] = '\0'; |
153 | if (getenv("HOME")) |
154 | strcpy (rcname, getenv("HOME")); |
155 | strcat (rcname, "/.tweakrc"); |
156 | #elif defined(MSDOS) |
157 | /* |
158 | * Use environment variable TWEAKRC if set. Otherwise, look for |
159 | * TWEAK.RC in the same directory as TWEAK.EXE, if _that_ exists, |
160 | * and failing everything else, try C:\TWEAK\TWEAK.RC. |
161 | */ |
162 | if (getenv("TWEAKRC")) |
163 | strcpy (rcname, getenv("TWEAKRC")); |
164 | else { |
165 | if ( (q = strrchr(pname, '\\')) != NULL) { |
166 | FILE *tempfp; |
167 | |
168 | strncpy (rcname, pname, q+1-pname); |
169 | strcpy (rcname+(q+1-pname), "TWEAK.RC"); |
170 | if ( (tempfp = fopen(rcname, "r")) != NULL) |
171 | fclose (tempfp); |
172 | else |
173 | strcpy (rcname, "C:\\TWEAK\\TWEAK.RC"); |
174 | } else |
175 | strcpy (rcname, "C:\\TWEAK\\TWEAK.RC"); |
176 | } |
177 | #endif |
178 | |
179 | { /* easy keybindings: self inserts */ |
180 | int i; |
181 | char c; |
182 | for (i=32; i<127; i++) { |
183 | c = i; |
184 | bind_key (&c, 1, act_self_ins); |
185 | } |
186 | } |
187 | |
188 | fp = fopen(rcname, "r"); |
189 | p = default_rc; |
190 | for (EVER) { |
191 | if (fp) { |
192 | if (!fgets(rcbuffer, sizeof(rcbuffer), fp)) { |
193 | fclose (fp); |
194 | break; |
195 | } |
196 | rcbuffer[strcspn(rcbuffer, "\r\n")] = '\0'; |
197 | } else { |
198 | if (!*p) |
199 | break; |
200 | strcpy (rcbuffer, *p++); |
201 | } |
202 | lineno++; |
203 | errors_here = FALSE; |
204 | |
205 | /* |
206 | * Now we have a line from the .rc file, wherever it's |
207 | * really come from. Process it. |
208 | */ |
209 | q = rcbuffer; |
210 | while (*q && isspace(*q)) |
211 | q++; |
212 | |
213 | if (!*q || *q == '#') |
214 | continue; /* comment or blank line */ |
215 | |
216 | r = q; |
217 | while (*r && !isspace(*r)) |
218 | r++; |
219 | if (*r) |
220 | *r++ = '\0'; |
221 | |
222 | /* |
223 | * Now "q" points to the command word, "r" to the rest of |
224 | * the line. |
225 | */ |
226 | if (!strcmp(q, "bind")) { |
227 | /* |
228 | * It's a "bind" directive. The rest of the line should |
229 | * consist of an action name, then a single whitespace |
230 | * character, then a key sequence. |
231 | */ |
232 | keyact action; |
233 | |
234 | while (*r && isspace(*r)) |
235 | r++; |
236 | |
237 | q = r; |
238 | while (*q && !isspace(*q)) |
239 | q++; |
240 | if (*q) |
241 | *q++ = '\0'; |
242 | else { |
243 | fprintf(stderr, "%s: no key sequence after \"bind\" command" |
244 | " on line %d of "RCNAME, pname, lineno); |
245 | errors = TRUE; |
246 | continue; |
247 | } |
248 | |
249 | /* |
250 | * "r" points to the action name; "q" to the key sequence. |
251 | */ |
252 | keyseq = s = q; |
253 | while (*q) { |
254 | if (*q == '^') { |
255 | if (!*++q) { |
256 | fprintf(stderr, "%s: nothing follows `^' on line %d" |
257 | " of "RCNAME, pname, lineno); |
258 | errors = TRUE; |
259 | errors_here = TRUE; |
260 | } else { |
261 | *s++ = *q++ ^ 0x40; |
262 | } |
263 | } else if (*q == '\\') { |
264 | if (!*++q) { |
265 | fprintf(stderr, "%s: nothing follows `\\' on line %d" |
266 | " of "RCNAME, pname, lineno); |
267 | errors = TRUE; |
268 | errors_here = TRUE; |
269 | } else if (*q == '\\' || *q == '^') { |
270 | *s++ = *q++; |
271 | } else if (isxdigit(*q) && q[1] && isxdigit(q[1])) { |
272 | char buf[3]; |
273 | buf[0] = *q++; |
274 | buf[1] = *q++; |
275 | buf[2] = '\0'; |
276 | *s++ = strtol (buf, NULL, 16); |
277 | } else { |
278 | fprintf(stderr, "%s: badly formed `\\' sequence on" |
279 | " line %d of "RCNAME, pname, lineno); |
280 | errors = TRUE; |
281 | errors_here = TRUE; |
282 | } |
283 | } else |
284 | *s++ = *q++; |
285 | } |
286 | if (errors_here) |
287 | continue; |
288 | |
289 | if (!strcmp(r, "quote-next")) { |
290 | /* |
291 | * The "quote next" sequence requires special |
292 | * treatment. |
293 | */ |
294 | int i; |
295 | |
296 | for (i=0; i<256; i++) { |
297 | *s = i; |
298 | bind_key (keyseq, s-keyseq+1, act_self_ins); |
299 | } |
300 | } else if ( (action = parse_action (r)) ) { |
301 | /* |
302 | * An ordinary action, requiring ordinary treatment. |
303 | */ |
304 | bind_key (keyseq, s-keyseq, action); |
305 | } else { |
306 | fprintf(stderr, "%s: unrecognised key action \"%s\"" |
307 | " at line %d of "RCNAME"\n", |
308 | pname, r, lineno); |
309 | errors = TRUE; |
310 | } |
311 | } else if (!strcmp(q, "width")) { |
312 | width = atoi(r); |
313 | } else if (!strcmp(q, "offset")) { |
314 | realoffset = atoi(r); |
315 | } else { |
316 | fprintf(stderr, "%s: unrecognised "RCNAME" directive \"%s\"" |
317 | " at line %d of "RCNAME"\n", |
318 | pname, q, lineno); |
319 | errors = TRUE; |
320 | } |
321 | } |
322 | if (errors) |
323 | exit(1); |
324 | } |
325 | |
326 | void write_default_rc (void) { |
327 | char **p; |
328 | |
329 | for (p = default_rc; *p; p++) |
330 | puts (*p); |
331 | } |