Commit | Line | Data |
---|---|---|
b346cbec C |
1 | /************************************************************************* |
2 | * This program is copyright (C) 1985, 1986 by Jonathan Payne. It is * | |
3 | * provided to you without charge for use only on a licensed Unix * | |
4 | * system. You may copy JOVE provided that this notice is included with * | |
5 | * the copy. You may not sell copies of this program or versions * | |
6 | * modified for use on microcomputer systems, unless the copies are * | |
7 | * included with a Unix system distribution and the source is provided. * | |
8 | *************************************************************************/ | |
9 | ||
10 | #include "jove.h" | |
11 | ||
12 | struct macro *macros = 0; /* Macros */ | |
13 | data_obj *LastCmd; | |
14 | ||
15 | static | |
16 | add_mac(new) | |
17 | struct macro *new; | |
18 | { | |
19 | register struct macro *mp, | |
20 | *prev = 0; | |
21 | ||
22 | for (mp = macros; mp != 0; prev = mp, mp = mp->m_nextm) | |
23 | if (mp == new) | |
24 | return; | |
25 | ||
26 | if (prev) | |
27 | prev->m_nextm = new; | |
28 | else | |
29 | macros = new; | |
30 | new->m_nextm = 0; | |
31 | new->Type = MACRO; | |
32 | } | |
33 | ||
34 | static | |
35 | del_mac(mac) | |
36 | struct macro *mac; | |
37 | { | |
38 | register struct macro *m; | |
39 | ||
40 | for (m = macros; m != 0; m = m->m_nextm) | |
41 | if (m->m_nextm == mac) { | |
42 | m->m_nextm = mac->m_nextm; | |
43 | break; | |
44 | } | |
45 | free(mac->Name); | |
46 | free(mac->m_body); | |
47 | free((char *) mac); | |
48 | } | |
49 | ||
50 | struct macro KeyMacro; /* Macro used for defining */ | |
51 | ||
52 | #define NMACROS 40 /* This is bad, bad, BAD! */ | |
53 | ||
54 | struct macro *macstack[NMACROS]; | |
55 | static int stackp = 0; | |
56 | ||
57 | fix_macros() | |
58 | { | |
59 | register int i; | |
60 | register struct macro *mp; | |
61 | ||
62 | for (i = 0; macstack[i]; i++) { | |
63 | mp = macstack[i]; | |
64 | macstack[i] = 0; | |
65 | mp->m_flags = mp->m_offset = 0; | |
66 | } | |
67 | stackp = -1; | |
68 | KeyMacro.m_flags = KeyMacro.m_offset = 0; | |
69 | } | |
70 | ||
71 | static | |
72 | mac_err(err) | |
73 | char *err; | |
74 | { | |
75 | KeyMacro.m_flags = 0; | |
76 | MacNolen(&KeyMacro); | |
77 | complain(err); | |
78 | } | |
79 | ||
80 | do_macro(mac) | |
81 | struct macro *mac; | |
82 | { | |
83 | if (mac->m_flags & EXECUTE) | |
84 | mac_err("[Attempt to execute macro recursively!]"); | |
85 | if (++stackp >= NMACROS) | |
86 | complain("[Too many macros at once!]"); | |
87 | macstack[stackp] = mac; | |
88 | mac->m_offset = 0; | |
89 | mac->m_ntimes = exp; | |
90 | mac->m_flags |= EXECUTE; | |
91 | } | |
92 | ||
93 | static | |
94 | MacNolen(m) | |
95 | struct macro *m; | |
96 | { | |
97 | m->m_len = m->m_offset = 0; | |
98 | } | |
99 | ||
100 | static struct macro * | |
101 | mac_exists(name) | |
102 | char *name; | |
103 | { | |
104 | register struct macro *mp; | |
105 | ||
106 | for (mp = macros; mp; mp = mp->m_nextm) | |
107 | if (strcmp(mp->Name, name) == 0) | |
108 | return mp; | |
109 | return 0; | |
110 | } | |
111 | ||
112 | mac_init() | |
113 | { | |
114 | add_mac(&KeyMacro); | |
115 | MacNolen(&KeyMacro); | |
116 | KeyMacro.Name = "keyboard-macro"; | |
117 | KeyMacro.m_buflen = 16; | |
118 | KeyMacro.m_body = emalloc(KeyMacro.m_buflen); | |
119 | KeyMacro.m_ntimes = KeyMacro.m_flags = 0; | |
120 | fix_macros(); | |
121 | } | |
122 | ||
123 | mac_putc(c) | |
124 | int c; | |
125 | { | |
126 | if (KeyMacro.m_len >= KeyMacro.m_buflen) { | |
127 | KeyMacro.m_buflen += 16; | |
128 | KeyMacro.m_body = realloc(KeyMacro.m_body, (unsigned) KeyMacro.m_buflen); | |
129 | if (KeyMacro.m_body == 0) | |
130 | mac_err("[Can't allocate storage for keyboard macro]"); | |
131 | } | |
132 | KeyMacro.m_body[KeyMacro.m_offset++] = c; | |
133 | KeyMacro.m_len++; | |
134 | } | |
135 | ||
136 | in_macro() | |
137 | { | |
138 | return ((stackp >= 0) && ((macstack[stackp])->m_flags & EXECUTE)); | |
139 | } | |
140 | ||
141 | mac_getc() | |
142 | { | |
143 | struct macro *m; | |
144 | ||
145 | if (stackp < 0 || ((m = macstack[stackp])->m_flags & EXECUTE) == 0) | |
146 | return -1; | |
147 | if (m->m_offset == m->m_len) { | |
148 | m->m_offset = 0; | |
149 | if (--m->m_ntimes == 0) { | |
150 | m->m_flags &= ~EXECUTE; | |
151 | stackp--; | |
152 | } | |
153 | return mac_getc(); | |
154 | } | |
155 | return m->m_body[m->m_offset++]; | |
156 | } | |
157 | ||
158 | NameMac() | |
159 | { | |
160 | char *name; | |
161 | struct macro *m; | |
162 | ||
163 | if (KeyMacro.m_len == 0) | |
164 | complain("[No keyboard macro to name!]"); | |
165 | if (KeyMacro.m_flags & (DEFINE | EXECUTE)) | |
166 | complain("[Can't name while defining/executing]"); | |
167 | if ((m = mac_exists(name = ask((char *) 0, ProcFmt))) == 0) | |
168 | m = (struct macro *) emalloc(sizeof *m); | |
169 | else { | |
170 | if (strcmp(name, KeyMacro.Name) == 0) | |
171 | complain("[Can't name it that!]"); | |
172 | free(m->Name); | |
173 | free(m->m_body); | |
174 | } | |
175 | name = copystr(name); | |
176 | m->Type = KeyMacro.Type; | |
177 | m->m_len = KeyMacro.m_len; | |
178 | m->m_buflen = KeyMacro.m_buflen; | |
179 | m->m_body = emalloc(m->m_buflen); | |
180 | byte_copy(KeyMacro.m_body, m->m_body, m->m_len); | |
181 | m->m_ntimes = m->m_offset = 0; /* At the beginning */ | |
182 | m->m_flags = SAVE; | |
183 | m->Name = name; | |
184 | add_mac(m); | |
185 | } | |
186 | ||
187 | RunMacro() | |
188 | { | |
189 | struct macro *m; | |
190 | ||
191 | if (m = (struct macro *) findmac(ProcFmt)) | |
192 | do_macro(m); | |
193 | } | |
194 | ||
195 | static int mac_fd; | |
196 | ||
197 | static | |
198 | mac_io(fcn, ptr, nbytes) | |
199 | int (*fcn)(); | |
200 | char *ptr; | |
201 | { | |
202 | int nio; | |
203 | ||
204 | if ((nio = (*fcn)(mac_fd, ptr, nbytes)) != nbytes) | |
205 | complain("[Macro %s error: %d got %d]", | |
206 | (fcn == read) ? "read" : "write", | |
207 | nbytes, | |
208 | nio); | |
209 | } | |
210 | ||
211 | WriteMacs() | |
212 | { | |
213 | struct macro *m; | |
214 | int namelen, | |
215 | netl, | |
216 | nmacs = 0; | |
217 | char *file, | |
218 | filebuf[FILESIZE]; | |
219 | ||
220 | file = ask_file((char *) 0, filebuf); | |
221 | if ((mac_fd = creat(file, 0666)) == -1) | |
222 | complain(IOerr("create", file)); | |
223 | f_mess("\"%s\"", file); | |
224 | ||
225 | /* Don't write the keyboard macro which is always the first */ | |
226 | for (m = macros->m_nextm; m != 0; m = m->m_nextm) { | |
227 | if (m->m_len == 0) | |
228 | continue; | |
229 | nmacs++; | |
230 | netl = htonl(m->m_len); | |
231 | mac_io(write, (char *) &netl, sizeof m->m_len); | |
232 | namelen = strlen(m->Name) + 1; /* Including the null */ | |
233 | netl = htonl(namelen); | |
234 | mac_io(write, (char *) &netl, sizeof namelen); | |
235 | mac_io(write, m->Name, namelen); | |
236 | mac_io(write, m->m_body, m->m_len); | |
237 | m->m_flags &= ~SAVE; | |
238 | } | |
239 | (void) close(mac_fd); | |
240 | add_mess(" %d macro%n saved.", nmacs, nmacs); | |
241 | } | |
242 | ||
243 | #define NEWWAY 1 | |
244 | #define OLDWAY 0 | |
245 | ||
246 | static int int_how = NEWWAY; | |
247 | ||
248 | /* Formatting int's the old way or the new "improved" way? */ | |
249 | ||
250 | #ifndef BSD4_2 | |
251 | ||
252 | /* 4.2 (at least) has these functions defined. */ | |
253 | ||
254 | #if vax || pdp11 | |
255 | long htonl(x) | |
256 | register long x; | |
257 | { | |
258 | return( (((x >> 0) & 0377) << 24) | | |
259 | (((x >> 8) & 0377) << 16) | | |
260 | (((x >> 16) & 0377) << 8) | | |
261 | (((x >> 24) & 0377) << 0) ); | |
262 | } | |
263 | ||
264 | short htons(x) | |
265 | register short x; | |
266 | { | |
267 | return( (((x >> 0) & 0377) << 8) | | |
268 | (((x >> 8) & 0377) << 0) ); | |
269 | } | |
270 | ||
271 | long ntohl(x) | |
272 | register long x; | |
273 | { | |
274 | return( (((x >> 0) & 0377) << 24) | | |
275 | (((x >> 8) & 0377) << 16) | | |
276 | (((x >> 16) & 0377) << 8) | | |
277 | (((x >> 24) & 0377) << 0) ); | |
278 | } | |
279 | ||
280 | short ntohs(x) | |
281 | register short x; | |
282 | { | |
283 | return( (((x >> 0) & 0377) << 8) | | |
284 | (((x >> 8) & 0377) << 0) ); | |
285 | } | |
286 | #else | |
287 | long htonl(x) | |
288 | register long x; | |
289 | { | |
290 | return(x); | |
291 | } | |
292 | ||
293 | short htons(x) | |
294 | register short x; | |
295 | { | |
296 | return(x); | |
297 | } | |
298 | ||
299 | long ntohl(x) | |
300 | register long x; | |
301 | { | |
302 | return(x); | |
303 | } | |
304 | ||
305 | short ntohs(x) | |
306 | register short x; | |
307 | { | |
308 | return(x); | |
309 | } | |
310 | #endif | |
311 | #endif BSD4_2 | |
312 | ||
313 | int_fmt(i) | |
314 | { | |
315 | if (int_how == NEWWAY) | |
316 | return ntohl(i); | |
317 | return i; | |
318 | } | |
319 | ||
320 | ReadMacs() | |
321 | { | |
322 | char *file, | |
323 | filebuf[FILESIZE]; | |
324 | struct macro *m; | |
325 | int nmacs = 0, | |
326 | namelen, | |
327 | bodylen, | |
328 | tmp, | |
329 | he_is_sure = 0, | |
330 | save_em = FALSE; | |
331 | ||
332 | file = ask_file((char *) 0, filebuf); | |
333 | if ((mac_fd = open(file, 0)) == -1) | |
334 | complain(IOerr("open", file)); | |
335 | ||
336 | f_mess("\"%s\"", file); | |
337 | while (read(mac_fd, (char *) &tmp, sizeof tmp) == (sizeof tmp)) { | |
338 | retry: bodylen = int_fmt(tmp); | |
339 | if (!he_is_sure && (bodylen <= 0 || bodylen > 10000)) { | |
340 | if (int_how == NEWWAY) { | |
341 | int_how = OLDWAY; | |
342 | save_em = TRUE; | |
343 | goto retry; | |
344 | } else { | |
345 | confirm("Are you sure \"%s\" is a JOVE macro file? ", filebuf); | |
346 | he_is_sure = 1; | |
347 | } | |
348 | } | |
349 | nmacs++; | |
350 | m = (struct macro *) emalloc (sizeof *m); | |
351 | m->m_flags = 0; | |
352 | m->m_len = bodylen; | |
353 | m->m_buflen = m->m_len; | |
354 | mac_io(read, (char *) &namelen, sizeof namelen); | |
355 | namelen = int_fmt(namelen); | |
356 | m->Name = emalloc(namelen); | |
357 | mac_io(read, m->Name, namelen); | |
358 | m->m_body = emalloc(m->m_buflen); | |
359 | mac_io(read, m->m_body, m->m_len); | |
360 | add_mac(m); | |
361 | } | |
362 | (void) close(mac_fd); | |
363 | add_mess(" %d macro%n defined.", nmacs, nmacs); | |
364 | if (save_em) { | |
365 | char *msg = "OK to convert to the new format? ", | |
366 | ibuf[FILESIZE + 1]; | |
367 | ||
368 | if (!InJoverc) { | |
369 | TOstart("Warning", TRUE); | |
370 | Typeout("Warning: your macros file is in the old format."); | |
371 | Typeout("Do you want me to convert \"%s\" to the new", pr_name(file)); | |
372 | Typeout("format?"); | |
373 | f_mess(msg); | |
374 | TOstop(); | |
375 | confirm(msg); | |
376 | } | |
377 | /* WriteMacs requests a file name. This is what it'll get. */ | |
378 | sprintf(ibuf, "%s\n", file); | |
379 | Inputp = ibuf; | |
380 | WriteMacs(); | |
381 | } | |
382 | } | |
383 | ||
384 | Remember() | |
385 | { | |
386 | if (KeyMacro.m_flags & EXECUTE) | |
387 | /* We're already executing the macro; ignore any attempts | |
388 | to define the keyboard macro while we are executing. */ | |
389 | return; | |
390 | if (KeyMacro.m_flags & DEFINE) | |
391 | message("[Already remembering ... continue with definition]"); | |
392 | else { | |
393 | UpdModLine++; | |
394 | KeyMacro.m_flags |= DEFINE; | |
395 | MacNolen(&KeyMacro); | |
396 | message("Remembering..."); | |
397 | } | |
398 | } | |
399 | ||
400 | /* Is `c' a prefix character */ | |
401 | ||
402 | static | |
403 | PrefChar(c) | |
404 | { | |
405 | return (int) IsPrefix(mainmap[c]); | |
406 | } | |
407 | ||
408 | Forget() | |
409 | { | |
410 | char *cp; | |
411 | struct macro *m = &KeyMacro; | |
412 | ||
413 | UpdModLine++; | |
414 | if (m->m_flags & DEFINE) { | |
415 | message("Keyboard macro defined."); | |
416 | m->m_flags &= ~DEFINE; | |
417 | cp = &m->m_body[m->m_len - 2]; | |
418 | if (PrefChar(*cp)) | |
419 | m->m_len -= 2; | |
420 | else if (commands[*++cp].c_proc == Forget) | |
421 | m->m_len--; | |
422 | } | |
423 | } | |
424 | ||
425 | ExecMacro() | |
426 | { | |
427 | do_macro(&KeyMacro); | |
428 | } | |
429 | ||
430 | MacInter() | |
431 | { | |
432 | extern int Interactive; | |
433 | ||
434 | if (!Asking) | |
435 | return; | |
436 | Interactive = 1; | |
437 | } | |
438 | ||
439 | ModMacs() | |
440 | { | |
441 | register struct macro *m; | |
442 | ||
443 | for (m = macros->m_nextm; m != 0; m = m->m_nextm) | |
444 | if (m->m_flags & SAVE) | |
445 | return 1; | |
446 | return 0; | |
447 | } | |
448 | ||
449 | data_obj * | |
450 | findmac(prompt) | |
451 | char *prompt; | |
452 | { | |
453 | char *strings[100]; | |
454 | register char **strs = strings; | |
455 | register int com; | |
456 | register struct macro *m = macros; | |
457 | ||
458 | for (; m != 0; m = m->m_nextm) | |
459 | *strs++ = m->Name; | |
460 | *strs = 0; | |
461 | ||
462 | if ((com = complete(strings, prompt, NOTHING)) < 0) | |
463 | return 0; | |
464 | m = macros; | |
465 | while (--com >= 0) | |
466 | m = m->m_nextm; | |
467 | return (data_obj *) m; | |
468 | } | |
469 | ||
470 | DelMacro() | |
471 | { | |
472 | struct macro *m; | |
473 | ||
474 | if ((m = (struct macro *) findmac(ProcFmt)) == 0) | |
475 | return; | |
476 | if (m == &KeyMacro) | |
477 | complain("[It's illegal to delete the keyboard-macro!]"); | |
478 | del_mac(m); | |
479 | } |