|
|
1.1 ! root 1: /*************************************************************************** ! 2: * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE * ! 3: * is 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 "ctype.h" ! 10: #include "fp.h" ! 11: #include "chars.h" ! 12: #include "disp.h" ! 13: ! 14: private void ! 15: add_mac proto((struct macro *)), ! 16: del_mac proto((struct macro *)), ! 17: pop_macro_stack proto((void)), ! 18: push_macro_stack proto((struct macro *, int)); ! 19: ! 20: private struct macro *mac_exists proto((char *)); ! 21: ! 22: #define SAVE 01 /* this macro needs saving to a file */ ! 23: ! 24: struct macro *macros = 0; /* macros */ ! 25: int InMacDefine = NO; ! 26: ! 27: private void ! 28: add_mac(new) ! 29: struct macro *new; ! 30: { ! 31: register struct macro *mp, ! 32: *prev = 0; ! 33: ! 34: for (mp = macros; mp != 0; prev = mp, mp = mp->m_nextm) ! 35: if (mp == new) ! 36: return; ! 37: ! 38: if (prev) ! 39: prev->m_nextm = new; ! 40: else ! 41: macros = new; ! 42: new->m_nextm = 0; ! 43: new->Type = MACRO; ! 44: } ! 45: ! 46: private void ! 47: del_mac(mac) ! 48: struct macro *mac; ! 49: { ! 50: register struct macro *m; ! 51: ! 52: for (m = macros; m != 0; m = m->m_nextm) ! 53: if (m->m_nextm == mac) { ! 54: m->m_nextm = mac->m_nextm; ! 55: break; ! 56: } ! 57: free(mac->Name); ! 58: free(mac->m_body); ! 59: free((char *) mac); ! 60: } ! 61: ! 62: struct macro KeyMacro; /* Macro used for defining */ ! 63: ! 64: /* To execute a macro, we have a "stack" of running macros. Whenever ! 65: we execute a macro, we push it on the stack, run it, then pop it ! 66: from the stack. */ ! 67: struct m_thread { ! 68: struct m_thread *mt_prev; ! 69: struct macro *mt_mp; ! 70: int mt_offset, ! 71: mt_count; ! 72: }; ! 73: ! 74: private struct m_thread *mac_stack = 0; ! 75: ! 76: private struct m_thread * ! 77: alloc_mthread() ! 78: { ! 79: return (struct m_thread *) emalloc(sizeof (struct m_thread)); ! 80: } ! 81: ! 82: private void ! 83: free_mthread(t) ! 84: struct m_thread *t; ! 85: { ! 86: free((char *) t); ! 87: } ! 88: ! 89: void ! 90: unwind_macro_stack() ! 91: { ! 92: while (mac_stack != 0) ! 93: pop_macro_stack(); ! 94: } ! 95: ! 96: private void ! 97: pop_macro_stack() ! 98: { ! 99: register struct m_thread *m; ! 100: ! 101: if ((m = mac_stack) == 0) ! 102: return; ! 103: mac_stack = m->mt_prev; ! 104: free_mthread(m); ! 105: } ! 106: ! 107: private void ! 108: push_macro_stack(m, count) ! 109: register struct macro *m; ! 110: int count; ! 111: { ! 112: register struct m_thread *t; ! 113: ! 114: for (t = mac_stack; t != 0; t = t->mt_prev) ! 115: if (t->mt_mp == m) ! 116: complain("[Cannot execute macro recusively]"); ! 117: if (count <= 0) ! 118: complain("[Cannot execute macro a negative number of times]"); ! 119: t = alloc_mthread(); ! 120: t->mt_prev = mac_stack; ! 121: mac_stack = t; ! 122: t->mt_offset = 0; ! 123: t->mt_mp = m; ! 124: t->mt_count = count; ! 125: } ! 126: ! 127: void ! 128: do_macro(mac) ! 129: struct macro *mac; ! 130: { ! 131: push_macro_stack(mac, arg_value()); ! 132: } ! 133: ! 134: private struct macro * ! 135: mac_exists(name) ! 136: char *name; ! 137: { ! 138: register struct macro *mp; ! 139: ! 140: for (mp = macros; mp; mp = mp->m_nextm) ! 141: if (strcmp(mp->Name, name) == 0) ! 142: return mp; ! 143: return 0; ! 144: } ! 145: ! 146: void ! 147: mac_init() ! 148: { ! 149: add_mac(&KeyMacro); ! 150: KeyMacro.Name = "keyboard-macro"; ! 151: KeyMacro.m_len = 0; ! 152: KeyMacro.m_buflen = 16; ! 153: KeyMacro.m_body = emalloc((size_t) KeyMacro.m_buflen); ! 154: } ! 155: ! 156: void ! 157: mac_putc(c) ! 158: int c; ! 159: { ! 160: if (KeyMacro.m_len >= KeyMacro.m_buflen) { ! 161: KeyMacro.m_buflen += 16; ! 162: KeyMacro.m_body = realloc(KeyMacro.m_body, (size_t) KeyMacro.m_buflen); ! 163: if (KeyMacro.m_body == 0) { ! 164: KeyMacro.m_buflen = KeyMacro.m_len = 0; ! 165: complain("[Can't allocate storage for keyboard macro]"); ! 166: } ! 167: } ! 168: KeyMacro.m_body[KeyMacro.m_len++] = c; ! 169: } ! 170: ! 171: int ! 172: in_macro() ! 173: { ! 174: return (mac_stack != NULL); ! 175: } ! 176: ! 177: int ! 178: mac_getc() ! 179: { ! 180: struct m_thread *mthread; ! 181: struct macro *m; ! 182: ! 183: if ((mthread = mac_stack) == NULL) ! 184: return EOF; ! 185: m = mthread->mt_mp; ! 186: if (mthread->mt_offset == m->m_len) { ! 187: mthread->mt_offset = 0; ! 188: if (--mthread->mt_count == 0) ! 189: pop_macro_stack(); ! 190: return mac_getc(); ! 191: } ! 192: return m->m_body[mthread->mt_offset++]; ! 193: } ! 194: ! 195: void ! 196: NameMac() ! 197: { ! 198: char *name; ! 199: struct macro *m; ! 200: ! 201: if (KeyMacro.m_len == 0) ! 202: complain("[No keyboard macro to name!]"); ! 203: if (in_macro() || InMacDefine) ! 204: complain("[Can't name while defining/executing]"); ! 205: if ((m = mac_exists(name = ask((char *) 0, ProcFmt))) == 0) ! 206: m = (struct macro *) emalloc(sizeof *m); ! 207: else { ! 208: if (strcmp(name, KeyMacro.Name) == 0) ! 209: complain("[Can't name it that!]"); ! 210: free(m->Name); ! 211: free(m->m_body); ! 212: } ! 213: name = copystr(name); ! 214: m->Type = KeyMacro.Type; ! 215: m->m_len = KeyMacro.m_len; ! 216: m->m_buflen = KeyMacro.m_buflen; ! 217: m->m_body = emalloc((size_t) m->m_buflen); ! 218: byte_copy(KeyMacro.m_body, m->m_body, (size_t) m->m_len); ! 219: m->m_flags = SAVE; ! 220: m->Name = name; ! 221: add_mac(m); ! 222: } ! 223: ! 224: void ! 225: RunMacro() ! 226: { ! 227: struct macro *m; ! 228: ! 229: if ((m = (struct macro *) findmac(ProcFmt)) != NULL) ! 230: do_macro(m); ! 231: } ! 232: ! 233: private void ! 234: pr_putc(c, fp) ! 235: int c; ! 236: File *fp; ! 237: { ! 238: if (c == '\\' || c == '^') ! 239: jputc('\\', fp); ! 240: else if (isctrl(c)) { ! 241: jputc('^', fp); ! 242: c = (c == RUBOUT) ? '?' : (c + '@'); ! 243: } ! 244: jputc(c, fp); ! 245: } ! 246: ! 247: void ! 248: WriteMacs() ! 249: { ! 250: struct macro *m; ! 251: char *file, ! 252: filebuf[FILESIZE]; ! 253: File *fp; ! 254: int i; ! 255: ! 256: file = ask_file((char *) 0, (char *) 0, filebuf); ! 257: fp = open_file(file, iobuff, F_WRITE, YES, YES); ! 258: ! 259: /* Don't write the keyboard macro which is always the first */ ! 260: for (m = macros->m_nextm; m != 0; m = m->m_nextm) { ! 261: fwritef(fp, "define-macro %s ", m->Name); ! 262: for (i = 0; i < m->m_len; i++) ! 263: pr_putc(m->m_body[i], fp); ! 264: jputc('\n', fp); ! 265: m->m_flags &= ~SAVE; ! 266: } ! 267: close_file(fp); ! 268: } ! 269: ! 270: void ! 271: DefKBDMac() ! 272: { ! 273: char *macro_name, ! 274: *macro_body, ! 275: nextc, ! 276: c, ! 277: macro_buffer[LBSIZE]; ! 278: int i; ! 279: struct macro *m; ! 280: ! 281: macro_name = do_ask(" \r\n", (int (*) proto((int))) 0, (char *) 0, ! 282: ProcFmt); ! 283: if (macro_name == 0) ! 284: complain("[No default]"); ! 285: macro_name = copystr(macro_name); ! 286: if ((m = mac_exists(macro_name)) != NULL) ! 287: del_mac(m); ! 288: macro_body = ask((char *) 0, ": %f %s enter body: ", macro_name); ! 289: i = 0; ! 290: while ((c = *macro_body++) != '\0') { ! 291: if (c == '\\') { ! 292: if ((nextc = *macro_body++) == LF) ! 293: complain("[Premature end of line]"); ! 294: c = nextc; ! 295: } else if (c == '^') { ! 296: if ((nextc = *macro_body++) == '?') ! 297: c = RUBOUT; ! 298: else if (isalpha(nextc) || strchr("@[\\]^_", nextc)) ! 299: c = CTL(nextc); ! 300: else ! 301: complain("Bad control-character: '%c'", nextc); ! 302: } ! 303: macro_buffer[i++] = c; ! 304: } ! 305: m = (struct macro *) emalloc(sizeof (*m)); ! 306: m->Name = macro_name; ! 307: m->m_len = m->m_buflen = i; ! 308: m->m_body = emalloc((size_t) i); ! 309: m->m_flags = InJoverc ? 0 : SAVE; ! 310: byte_copy(macro_buffer, m->m_body, (size_t) i); ! 311: add_mac(m); ! 312: } ! 313: ! 314: void ! 315: Remember() ! 316: { ! 317: /* We're already executing the macro; ignore any attempts ! 318: to define the keyboard macro while we are executing. */ ! 319: if (in_macro()) ! 320: return; ! 321: if (InMacDefine) ! 322: message("[Already defining ... continue with definition]"); ! 323: else { ! 324: UpdModLine = YES; ! 325: InMacDefine = YES; ! 326: KeyMacro.m_len = 0; ! 327: message("Defining..."); ! 328: } ! 329: } ! 330: ! 331: void ! 332: Forget() ! 333: { ! 334: char *cp; ! 335: struct macro *m = &KeyMacro; ! 336: ! 337: UpdModLine = YES; ! 338: if (InMacDefine) { ! 339: message("Keyboard macro defined."); ! 340: InMacDefine = NO; ! 341: ! 342: /* try and strip off the key sequence that invoked us */ ! 343: cp = &m->m_body[m->m_len - 2]; ! 344: if (PrefChar(*cp)) ! 345: m->m_len -= 2; ! 346: else if (commands[cp[1]].c_proc == Forget) ! 347: m->m_len -= 1; ! 348: } else ! 349: complain("[end-kbd-macro: not currently defining macro!]"); ! 350: } ! 351: ! 352: void ! 353: ExecMacro() ! 354: { ! 355: do_macro(&KeyMacro); ! 356: } ! 357: ! 358: void ! 359: MacInter() ! 360: { ! 361: if (!Asking) ! 362: return; ! 363: Interactive = 1; ! 364: } ! 365: ! 366: int ! 367: ModMacs() ! 368: { ! 369: register struct macro *m; ! 370: ! 371: for (m = macros->m_nextm; m != 0; m = m->m_nextm) ! 372: if (m->m_flags & SAVE) ! 373: return YES; ! 374: return NO; ! 375: } ! 376: ! 377: data_obj * ! 378: findmac(prompt) ! 379: char *prompt; ! 380: { ! 381: char *strings[100]; ! 382: register char **strs = strings; ! 383: register int com; ! 384: register struct macro *m = macros; ! 385: ! 386: for (; m != 0; m = m->m_nextm) ! 387: *strs++ = m->Name; ! 388: *strs = 0; ! 389: ! 390: if ((com = complete(strings, prompt, NOTHING)) < 0) ! 391: return 0; ! 392: m = macros; ! 393: while (--com >= 0) ! 394: m = m->m_nextm; ! 395: return (data_obj *) m; ! 396: } ! 397: ! 398: void ! 399: DelMacro() ! 400: { ! 401: struct macro *m; ! 402: ! 403: if ((m = (struct macro *) findmac(ProcFmt)) == 0) ! 404: return; ! 405: if (m == &KeyMacro) ! 406: complain("[It's illegal to delete the keyboard-macro!]"); ! 407: del_mac(m); ! 408: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.