1 /************************************************************************ 2 * This program is Copyright (C) 1986-1996 by Jonathan Payne. JOVE is * 3 * provided to you without charge, and with no warranty. You may give * 4 * away copies of JOVE, including sources, provided that this notice is * 5 * included in all the files. * 6 ************************************************************************/ 7 8 #include "jove.h" 9 #include "jctype.h" 10 #include "fp.h" 11 #include "chars.h" 12 #include "disp.h" 13 #include "ask.h" 14 #include "commands.h" 15 #include "macros.h" 16 #include "extend.h" 17 #include "fmt.h" 18 /* #include "util.h" */ 19 20 private void 21 pop_macro_stack proto((void)); 22 23 private struct macro 24 *ask_macname proto((const char *, int)); 25 26 private bool UnsavedMacros = NO; /* are there any macros that need saving to a file? */ 27 28 struct macro *macros = NULL; /* macros */ 29 bool InMacDefine = NO; 30 31 private void 32 add_mac(new) 33 struct macro *new; 34 { 35 register struct macro *mp, 36 *prev = NULL; 37 38 for (mp = macros; mp != NULL; prev = mp, mp = mp->m_nextm) 39 if (mp == new) 40 return; 41 42 if (prev) 43 prev->m_nextm = new; 44 else 45 macros = new; 46 new->m_nextm = NULL; 47 new->Type = MACRO; 48 } 49 50 /* To execute a macro, we have a "stack" of running macros. Whenever 51 we execute a macro, we push it on the stack, run it, then pop it 52 from the stack. */ 53 struct m_thread { 54 struct m_thread *mt_prev; 55 struct macro *mt_mp; 56 int mt_offset, 57 mt_count; 58 }; 59 60 private struct m_thread *mac_stack = NULL; 61 62 private struct m_thread * 63 alloc_mthread() 64 { 65 return (struct m_thread *) emalloc(sizeof (struct m_thread)); 66 } 67 68 private void 69 free_mthread(t) 70 struct m_thread *t; 71 { 72 free((UnivPtr) t); 73 } 74 75 void 76 unwind_macro_stack() 77 { 78 while (mac_stack != NULL) 79 pop_macro_stack(); 80 } 81 82 private void 83 pop_macro_stack() 84 { 85 register struct m_thread *m; 86 87 if ((m = mac_stack) == NULL) 88 return; 89 mac_stack = m->mt_prev; 90 free_mthread(m); 91 } 92 93 private void 94 push_macro_stack(m, count) 95 register struct macro *m; 96 int count; 97 { 98 register struct m_thread *t; 99 100 for (t = mac_stack; t != NULL; t = t->mt_prev) 101 if (t->mt_mp == m) 102 complain("[Cannot execute macro recusively]"); 103 if (count <= 0) 104 complain("[Cannot execute macro a negative number of times]"); 105 t = alloc_mthread(); 106 t->mt_prev = mac_stack; 107 mac_stack = t; 108 t->mt_offset = 0; 109 t->mt_mp = m; 110 t->mt_count = count; 111 } 112 113 void 114 do_macro(mac) 115 struct macro *mac; 116 { 117 push_macro_stack(mac, arg_value()); 118 } 119 120 private struct macro KeyMacro = { /* Macro used for defining */ 121 MACRO, "keyboard-macro", 0, NULL, NULL 122 }; 123 124 private int kmac_len; 125 private int kmac_buflen = 0; 126 127 void 128 mac_init() 129 { 130 add_mac(&KeyMacro); 131 } 132 133 void 134 mac_putc(c) 135 char c; 136 { 137 if (kmac_len >= kmac_buflen) { 138 KeyMacro.m_body = erealloc((UnivPtr) KeyMacro.m_body, (size_t) kmac_buflen + 16); 139 kmac_buflen += 16; 140 } 141 KeyMacro.m_body[kmac_len++] = c; 142 } 143 144 void 145 note_dispatch() 146 { 147 if (kmac_len > 0) 148 KeyMacro.m_len = kmac_len - 1; 149 } 150 151 bool 152 in_macro() 153 { 154 return (mac_stack != NULL); 155 } 156 157 ZXchar 158 mac_getc() 159 { 160 struct m_thread *mthread; 161 struct macro *m; 162 163 if ((mthread = mac_stack) == NULL) 164 return EOF; 165 m = mthread->mt_mp; 166 if (mthread->mt_offset == m->m_len) { 167 mthread->mt_offset = 0; 168 if (--mthread->mt_count == 0) 169 pop_macro_stack(); 170 return mac_getc(); 171 } 172 return ZXC(m->m_body[mthread->mt_offset++]); 173 } 174 175 private void 176 MacDef(m, name, len, body) 177 struct macro *m; /* NULL, or def to overwrite */ 178 char *name; /* must be stable if m isn't NULL */ 179 int len; 180 char *body; 181 { 182 if (m == NULL) { 183 m = (struct macro *) emalloc(sizeof *m); 184 m->Name = name; 185 } else { 186 if (m->m_body != NULL) 187 free((UnivPtr) m->m_body); 188 } 189 m->m_len = len; 190 if (len == 0) { 191 m->m_body = NULL; 192 } else { 193 m->m_body = emalloc((size_t) len); 194 byte_copy(body, m->m_body, (size_t) len); 195 } 196 add_mac(m); 197 if (!InJoverc) 198 UnsavedMacros = YES; 199 } 200 201 void 202 NameMac() 203 { 204 char *name = NULL; 205 struct macro *m; 206 207 if (KeyMacro.m_len == 0) 208 complain("[No keyboard macro to name!]"); 209 if (in_macro() || InMacDefine) 210 complain("[Can't name while defining/executing]"); 211 if ((m = ask_macname(ProcFmt, ALLOW_OLD | ALLOW_INDEX | ALLOW_NEW)) == NULL) 212 name = copystr(Minibuf); 213 if (m == &KeyMacro) 214 complain("[Can't name it that!]"); 215 MacDef(m, name, KeyMacro.m_len, KeyMacro.m_body); 216 } 217 218 void 219 RunMacro() 220 { 221 do_macro((struct macro *) findmac(ProcFmt)); 222 } 223 224 private void 225 pr_putc(c, fp) 226 ZXchar c; 227 File *fp; 228 { 229 if (c == '\\' || c == '^') { 230 f_putc('\\', fp); 231 f_putc(c, fp); 232 } else { 233 char buf[PPWIDTH]; 234 char *p; 235 236 PPchar(c, buf); 237 for (p = buf; *p != '\0'; p++) 238 f_putc(*p, fp); 239 } 240 } 241 242 void 243 WriteMacs() 244 { 245 struct macro *m; 246 char 247 fnamebuf[FILESIZE]; 248 File *fp; 249 int i; 250 251 (void) ask_file((char *)NULL, (char *)NULL, fnamebuf); 252 fp = open_file(fnamebuf, iobuff, F_WRITE, YES); 253 254 /* Don't write the keyboard macro which is always the first */ 255 for (m = macros->m_nextm; m != NULL; m = m->m_nextm) { 256 fwritef(fp, "define-macro %s ", m->Name); 257 for (i = 0; i < m->m_len; i++) 258 pr_putc(ZXC(m->m_body[i]), fp); 259 #ifdef USE_CRLF 260 f_putc('\r', fp); 261 #endif /* USE_CRLF */ 262 f_putc(EOL, fp); 263 } 264 close_file(fp); 265 UnsavedMacros = NO; 266 } 267 268 void 269 DefKBDMac() 270 { 271 struct macro *m = ask_macname(ProcFmt, 272 ALLOW_OLD | ALLOW_INDEX | ALLOW_NEW); 273 ZXchar c; 274 char 275 *macro_name = m == NULL? copystr(Minibuf) : m->Name, 276 *macro_body, 277 macro_buffer[LBSIZE]; 278 int len; 279 280 if (m == &KeyMacro) 281 complain("[Can't name it that!]"); 282 /* ??? I hope that this ask doesn't change *m! */ 283 macro_body = ask(NullStr, ": %f %s enter body: ", macro_name); 284 len = 0; 285 while ((c = ZXC(*macro_body++)) != '\0') { 286 if (c == '\\' || c == '^') 287 c = DecodePair(c, ZXC(*macro_body++)); 288 if (len >= LBSIZE) 289 complain("Macro to large"); 290 macro_buffer[len++] = c; 291 } 292 MacDef(m, macro_name, len, macro_buffer); 293 } 294 295 void 296 Remember() 297 { 298 /* We're already executing the macro; ignore any attempts 299 to define the keyboard macro while we are executing. */ 300 if (in_macro()) 301 return; 302 if (InMacDefine) 303 message("[Already defining ... continue with definition]"); 304 else { 305 UpdModLine = YES; 306 InMacDefine = YES; 307 kmac_len = KeyMacro.m_len = 0; 308 message("Defining..."); 309 } 310 } 311 312 void 313 Forget() 314 { 315 UpdModLine = YES; 316 if (InMacDefine) { 317 message("Keyboard macro defined."); 318 InMacDefine = NO; 319 } else 320 complain("[end-kbd-macro: not currently defining macro!]"); 321 } 322 323 void 324 ExecMacro() 325 { 326 do_macro(&KeyMacro); 327 } 328 329 void 330 MacInter() 331 { 332 if (Asking) 333 Interactive = YES; 334 } 335 336 bool 337 ModMacs() 338 { 339 return UnsavedMacros; 340 } 341 342 /* Ask for macro name, with completion. 343 * Flags is passed directly to complete. If ALLOW_NEW is on, 344 * the name might be new, in which case NULL is returned and the 345 * actual name in in Minibuf. 346 */ 347 348 private struct macro * 349 ask_macname(prompt, flags) 350 const char *prompt; 351 int flags; 352 { 353 char *strings[100]; 354 register char **strs = strings; 355 register int com; 356 register struct macro *m; 357 358 for (m = macros; m != NULL; m = m->m_nextm) { 359 if (strs == &strings[elemsof(strings)-1]) 360 complain("[too many macros]"); 361 *strs++ = m->Name; 362 } 363 *strs = NULL; 364 365 if ((com = complete(strings, (char *)NULL, prompt, flags)) < 0) 366 return NULL; 367 m = macros; 368 while (--com >= 0) 369 m = m->m_nextm; 370 return m; 371 } 372 373 data_obj * 374 findmac(prompt) 375 const char *prompt; 376 { 377 return (data_obj *)ask_macname(prompt, ALLOW_OLD | ALLOW_INDEX); 378 } 379