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", |
114 | "bind goto-position ^XG", |
115 | "bind goto-position ^Xg", |
116 | "bind screen-recentre ^L", |
117 | "", |
118 | "# Standard screen size parameters, plus keybindings to alter them", |
119 | "width 16", |
120 | "offset 0", |
121 | "bind new-width ^XW", |
122 | "bind new-width ^Xw", |
123 | "bind new-offset ^XO", |
124 | "bind new-offset ^Xo", |
125 | "", |
126 | "# Key bindings: overall program/file control", |
127 | "bind suspend ^Z", |
128 | "bind exit ^X^C", |
129 | "bind save-file ^X^S", |
130 | "# unbound by default: exit-and-save", |
131 | "", |
132 | #ifdef TEST_BUFFER |
133 | "bind diagnostics ^X^D", |
134 | "", |
135 | #endif |
136 | "# End of default "RCNAME, |
137 | NULL |
138 | }; |
139 | |
140 | extern char *pname; |
141 | |
142 | void read_rc (void) { |
143 | FILE *fp; |
144 | char **p, *q, *r, *s, *keyseq; |
145 | char rcbuffer[256]; |
146 | char rcname[FILENAME_MAX]; |
147 | int lineno = 0; |
148 | int errors = FALSE, errors_here; |
149 | |
150 | #if defined(unix) && !defined(GO32) |
151 | rcname[0] = '\0'; |
152 | if (getenv("HOME")) |
153 | strcpy (rcname, getenv("HOME")); |
154 | strcat (rcname, "/.tweakrc"); |
155 | #elif defined(MSDOS) |
156 | /* |
157 | * Use environment variable TWEAKRC if set. Otherwise, look for |
158 | * TWEAK.RC in the same directory as TWEAK.EXE, if _that_ exists, |
159 | * and failing everything else, try C:\TWEAK\TWEAK.RC. |
160 | */ |
161 | if (getenv("TWEAKRC")) |
162 | strcpy (rcname, getenv("TWEAKRC")); |
163 | else { |
164 | if ( (q = strrchr(pname, '\\')) != NULL) { |
165 | FILE *tempfp; |
166 | |
167 | strncpy (rcname, pname, q+1-pname); |
168 | strcpy (rcname+(q+1-pname), "TWEAK.RC"); |
169 | if ( (tempfp = fopen(rcname, "r")) != NULL) |
170 | fclose (tempfp); |
171 | else |
172 | strcpy (rcname, "C:\\TWEAK\\TWEAK.RC"); |
173 | } else |
174 | strcpy (rcname, "C:\\TWEAK\\TWEAK.RC"); |
175 | } |
176 | #endif |
177 | |
178 | { /* easy keybindings: self inserts */ |
179 | int i; |
180 | char c; |
181 | for (i=32; i<127; i++) { |
182 | c = i; |
183 | bind_key (&c, 1, act_self_ins); |
184 | } |
185 | } |
186 | |
187 | fp = fopen(rcname, "r"); |
188 | p = default_rc; |
189 | for (EVER) { |
190 | if (fp) { |
191 | if (!fgets(rcbuffer, sizeof(rcbuffer), fp)) { |
192 | fclose (fp); |
193 | break; |
194 | } |
195 | rcbuffer[strcspn(rcbuffer, "\r\n")] = '\0'; |
196 | } else { |
197 | if (!*p) |
198 | break; |
199 | strcpy (rcbuffer, *p++); |
200 | } |
201 | lineno++; |
202 | errors_here = FALSE; |
203 | |
204 | /* |
205 | * Now we have a line from the .rc file, wherever it's |
206 | * really come from. Process it. |
207 | */ |
208 | q = rcbuffer; |
209 | while (*q && isspace(*q)) |
210 | q++; |
211 | |
212 | if (!*q || *q == '#') |
213 | continue; /* comment or blank line */ |
214 | |
215 | r = q; |
216 | while (*r && !isspace(*r)) |
217 | r++; |
218 | if (*r) |
219 | *r++ = '\0'; |
220 | |
221 | /* |
222 | * Now "q" points to the command word, "r" to the rest of |
223 | * the line. |
224 | */ |
225 | if (!strcmp(q, "bind")) { |
226 | /* |
227 | * It's a "bind" directive. The rest of the line should |
228 | * consist of an action name, then a single whitespace |
229 | * character, then a key sequence. |
230 | */ |
231 | keyact action; |
232 | |
233 | while (*r && isspace(*r)) |
234 | r++; |
235 | |
236 | q = r; |
237 | while (*q && !isspace(*q)) |
238 | q++; |
239 | if (*q) |
240 | *q++ = '\0'; |
241 | else { |
242 | fprintf(stderr, "%s: no key sequence after \"bind\" command" |
243 | " on line %d of "RCNAME, pname, lineno); |
244 | errors = TRUE; |
245 | continue; |
246 | } |
247 | |
248 | /* |
249 | * "r" points to the action name; "q" to the key sequence. |
250 | */ |
251 | keyseq = s = q; |
252 | while (*q) { |
253 | if (*q == '^') { |
254 | if (!*++q) { |
255 | fprintf(stderr, "%s: nothing follows `^' on line %d" |
256 | " of "RCNAME, pname, lineno); |
257 | errors = TRUE; |
258 | errors_here = TRUE; |
259 | } else { |
260 | *s++ = *q++ ^ 0x40; |
261 | } |
262 | } else if (*q == '\\') { |
263 | if (!*++q) { |
264 | fprintf(stderr, "%s: nothing follows `\\' on line %d" |
265 | " of "RCNAME, pname, lineno); |
266 | errors = TRUE; |
267 | errors_here = TRUE; |
268 | } else if (*q == '\\' || *q == '^') { |
269 | *s++ = *q++; |
270 | } else if (isxdigit(*q) && q[1] && isxdigit(q[1])) { |
271 | char buf[3]; |
272 | buf[0] = *q++; |
273 | buf[1] = *q++; |
274 | buf[2] = '\0'; |
275 | *s++ = strtol (buf, NULL, 16); |
276 | } else { |
277 | fprintf(stderr, "%s: badly formed `\\' sequence on" |
278 | " line %d of "RCNAME, pname, lineno); |
279 | errors = TRUE; |
280 | errors_here = TRUE; |
281 | } |
282 | } else |
283 | *s++ = *q++; |
284 | } |
285 | if (errors_here) |
286 | continue; |
287 | |
288 | if (!strcmp(r, "quote-next")) { |
289 | /* |
290 | * The "quote next" sequence requires special |
291 | * treatment. |
292 | */ |
293 | int i; |
294 | |
295 | for (i=0; i<256; i++) { |
296 | *s = i; |
297 | bind_key (keyseq, s-keyseq+1, act_self_ins); |
298 | } |
299 | } else if ( (action = parse_action (r)) ) { |
300 | /* |
301 | * An ordinary action, requiring ordinary treatment. |
302 | */ |
303 | bind_key (keyseq, s-keyseq, action); |
304 | } else { |
305 | fprintf(stderr, "%s: unrecognised key action \"%s\"" |
306 | " at line %d of "RCNAME"\n", |
307 | pname, r, lineno); |
308 | errors = TRUE; |
309 | } |
310 | } else if (!strcmp(q, "width")) { |
311 | width = atoi(r); |
312 | } else if (!strcmp(q, "offset")) { |
313 | realoffset = atoi(r); |
314 | } else { |
315 | fprintf(stderr, "%s: unrecognised "RCNAME" directive \"%s\"" |
316 | " at line %d of "RCNAME"\n", |
317 | pname, q, lineno); |
318 | errors = TRUE; |
319 | } |
320 | } |
321 | if (errors) |
322 | exit(1); |
323 | } |
324 | |
325 | void write_default_rc (void) { |
326 | char **p; |
327 | |
328 | for (p = default_rc; *p; p++) |
329 | puts (*p); |
330 | } |