📄 macro.c
字号:
/* * Keyboard macros * Copyright * (C) 1992 Joseph H. Allen * * This file is part of JOE (Joe's Own Editor) */#include "types.h"MACRO *freemacros = NULL;/* Create a macro */MACRO *mkmacro(int k, int flg, int n, CMD *cmd){ MACRO *macro; if (!freemacros) { int x; macro = (MACRO *) joe_malloc(sizeof(MACRO) * 64); for (x = 0; x != 64; ++x) { macro[x].steps = (MACRO **) freemacros; freemacros = macro + x; } } macro = freemacros; freemacros = (MACRO *) macro->steps; macro->steps = NULL; macro->size = 0; macro->flg = flg; macro->n = n; macro->cmd = cmd; macro->k = k; return macro;}/* Eliminate a macro */void rmmacro(MACRO *macro){ if (macro) { if (macro->steps) { int x; for (x = 0; x != macro->n; ++x) rmmacro(macro->steps[x]); joe_free(macro->steps); } macro->steps = (MACRO **) freemacros; freemacros = macro; }}/* Add a step to block macro */void addmacro(MACRO *macro, MACRO *m){ if (macro->n == macro->size) { if (macro->steps) macro->steps = (MACRO **) joe_realloc(macro->steps, (macro->size += 8) * sizeof(MACRO *)); else macro->steps = (MACRO **) joe_malloc((macro->size = 8) * sizeof(MACRO *)); } macro->steps[macro->n++] = m;}/* Duplicate a macro */MACRO *dupmacro(MACRO *mac){ MACRO *m = mkmacro(mac->k, mac->flg, mac->n, mac->cmd); if (mac->steps) { int x; m->steps = (MACRO **) joe_malloc((m->size = mac->n) * sizeof(MACRO *)); for (x = 0; x != m->n; ++x) m->steps[x] = dupmacro(mac->steps[x]); } return m;}/* Set key part of macro */MACRO *macstk(MACRO *m, int k){ m->k = k; return m;}/* Set flg part of macro */MACRO *macsta(MACRO *m, int a){ m->flg = a; return m;}/* Parse text into a macro * sta is set to: ending position in buffer for no error. * -1 for syntax error * -2 for need more input */MACRO *mparse(MACRO *m, unsigned char *buf, int *sta){ int y, c, x = 0; macroloop: /* Skip whitespace */ while (joe_isblank(locale_map,buf[x])) ++x; /* Do we have a string? */ if (buf[x] == '\"') { ++x; while (buf[x] && buf[x] != '\"') { if (buf[x] == '\\' && buf[x + 1]) { ++x; switch (buf[x]) { case 'n': buf[x] = 10; break; case 'r': buf[x] = 13; break; case 'b': buf[x] = 8; break; case 'f': buf[x] = 12; break; case 'a': buf[x] = 7; break; case 't': buf[x] = 9; break; case 'x': c = 0; if (buf[x + 1] >= '0' && buf[x + 1] <= '9') c = c * 16 + buf[++x] - '0'; else if ((buf[x + 1] >= 'a' && buf[x + 1] <= 'f') || (buf[x + 1] >= 'A' && buf[x + 1] <= 'F')) c = c * 16 + (buf[++x] & 0xF) + 9; if (buf[x + 1] >= '0' && buf[x + 1] <= '9') c = c * 16 + buf[++x] - '0'; else if ((buf[x + 1] >= 'a' && buf[x + 1] <= 'f') || (buf[x + 1] >= 'A' && buf[x + 1] <= 'F')) c = c * 16 + (buf[++x] & 0xF) + 9; buf[x] = c; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': c = buf[x] - '0'; if (buf[x + 1] >= '0' && buf[x + 1] <= '7') c = c * 8 + buf[++x] - '0'; if (buf[x + 1] >= '0' && buf[x + 1] <= '7') c = c * 8 + buf[++x] - '0'; buf[x] = c; break; } } if (m) { if (!m->steps) { MACRO *macro = m; m = mkmacro(-1, 0, 0, NULL); addmacro(m, macro); } } else m = mkmacro(-1, 0, 0, NULL); addmacro(m, mkmacro(buf[x], 0, 0, findcmd(USTR "type"))); ++x; } if (buf[x] == '\"') ++x; } /* Do we have a command? */ else { for (y = x; buf[y] && buf[y]!='#' && buf[y] != '!' && buf[y] != '~' && buf[y] !='-' && buf[y] != ',' && buf[y] != ' ' && buf[y] != '\t' && buf[y] != '\n' && buf[x] != '\r'; ++y) ; if (y != x) { CMD *cmd; int flg = 0; c = buf[y]; buf[y] = 0; cmd = findcmd(buf + x); buf[x = y] = c; /* Parse flags */ while (buf[x]=='-' || buf[x]=='!' || buf[x]=='#' || buf[x]=='~') { if (buf[x]=='-') flg |= 1; if (buf[x]=='!') flg |= 2; if (buf[x]=='#') flg |= 4; if (buf[x]=='~') flg |= 8; ++x; } if (!cmd) { *sta = -1; return NULL; } else if (m) { if (!m->steps) { MACRO *macro = m; m = mkmacro(-1, 0, 0, NULL); addmacro(m, macro); } addmacro(m, mkmacro(-1, flg, 0, cmd)); } else m = mkmacro(-1, flg, 0, cmd); } } /* Skip whitespace */ while (joe_isblank(locale_map,buf[x])) ++x; /* Do we have a comma? */ if (buf[x] == ',') { ++x; while (joe_isblank(locale_map,buf[x])) ++x; if (buf[x] && buf[x] != '\r' && buf[x] != '\n') goto macroloop; *sta = -2; return m; } /* Done */ *sta = x; return m;}/* Convert macro to text */static unsigned char *ptr;static int first;static int instr;unsigned char *unescape(unsigned char *ptr, int c){ if (c == '"') { *ptr++ = '\\'; *ptr++ = '"'; } else if (c == '\\') { *ptr++ = '\\'; *ptr++ = '\\'; } else if (c == '\'') { *ptr++ = '\\'; *ptr++ = '\''; } else if (c < 32 || c > 126) { /* FIXME: what if c > 256 or c < 0 ? */ *ptr++ = '\\'; *ptr++ = 'x'; *ptr++ = "0123456789ABCDEF"[c >> 4]; *ptr++ = "0123456789ABCDEF"[c & 15]; } else *ptr++ = c; return ptr;}static void domtext(MACRO *m){ int x; if (!m) return; if (m->steps) for (x = 0; x != m->n; ++x) domtext(m->steps[x]); else { if (instr && zcmp(m->cmd->name, USTR "type")) { *ptr++ = '\"'; instr = 0; } if (first) first = 0; else if (!instr) *ptr++ = ','; if (!zcmp(m->cmd->name, USTR "type")) { if (!instr) { *ptr++ = '\"'; instr = 1; } ptr = unescape(ptr, m->k); } else { for (x = 0; m->cmd->name[x]; ++x) *ptr++ = m->cmd->name[x]; if (!zcmp(m->cmd->name, USTR "play") || !zcmp(m->cmd->name, USTR "gomark") || !zcmp(m->cmd->name, USTR "setmark") || !zcmp(m->cmd->name, USTR "record") || !zcmp(m->cmd->name, USTR "uarg")) { *ptr++ = ','; *ptr++ = '"'; ptr = unescape(ptr, m->k); *ptr++ = '"'; } } }}unsigned char *mtext(unsigned char *s, MACRO *m){ ptr = s; first = 1; instr = 0; domtext(m); if (instr) *ptr++ = '\"'; *ptr = 0; return s;}/* Keyboard macro recorder */static MACRO *kbdmacro[10];static int playmode[10];struct recmac *recmac = NULL;static void unmac(void){ if (recmac) rmmacro(recmac->m->steps[--recmac->m->n]);}void chmac(void){ if (recmac && recmac->m->n) recmac->m->steps[recmac->m->n - 1]->k = 3;}static void record(MACRO *m){ if (recmac) addmacro(recmac->m, dupmacro(m));}static int ifdepth=0; /* JM: Nesting level of if cmds */static int ifflag=1; /* JM: Truth flag for if */static int iffail=0; /* JM: Depth where ifflag became 0 *//* Suspend macro record/play to allow for user input. * * Stop recording current macro, make recursive call to edit loop, which * runs until dialog is complete, then continue with macro recording. * * When the macro is played, edit loop is run as a subroutine until dialog * is complete, then uquery returns, which continues macro execution. * * Completion of a dialog is indicated with 'notify' flag
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -