This is macro.c in view mode; [Download] [Up]
/* Keyboard macros Copyright (C) 1992 Joseph H. Allen This file is part of JOE (Joe's Own Editor) JOE is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. JOE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with JOE; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "main.h" #include "qw.h" #include "pw.h" #include "bw.h" #include "vs.h" #include "undo.h" #include "cmd.h" #include "ublock.h" #include "umath.h" #include "uedit.h" #include "zstr.h" #include "macro.h" MACRO *freemacros=0; /* Create a macro */ MACRO *mkmacro(k,arg,n,cmd) CMD *cmd; { MACRO *macro; if(!freemacros) { int x; macro=(MACRO *)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=0; macro->size=0; macro->arg=arg; macro->n=n; macro->cmd=cmd; macro->k=k; return macro; } /* Eliminate a macro */ void rmmacro(macro) MACRO *macro; { if(macro) { if(macro->steps) { int x; for(x=0;x!=macro->n;++x) rmmacro(macro->steps[x]); free(macro->steps); } macro->steps=(MACRO **)freemacros; freemacros=macro; } } /* Add a step to block macro */ void addmacro(macro,m) MACRO *macro, *m; { if(macro->n==macro->size) if(macro->steps) macro->steps=(MACRO **)realloc(macro->steps,(macro->size+=8)*sizeof(MACRO *)); else macro->steps=(MACRO **)malloc((macro->size=8)*sizeof(MACRO *)); macro->steps[macro->n++]=m; } /* Duplicate a macro */ MACRO *dupmacro(mac) MACRO *mac; { MACRO *m=mkmacro(mac->k,mac->arg,mac->n,mac->cmd); if(mac->steps) { int x; m->steps=(MACRO **)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(m,k) MACRO *m; { m->k=k; return m; } /* Set arg part of macro */ MACRO *macsta(m,a) MACRO *m; { m->arg=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(m,buf,sta) MACRO *m; char *buf; int *sta; { int y, c, x=0; macroloop: /* Skip whitespace */ while(cwhite(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(MAXINT,1,0,NULL); addmacro(m,macro); } } else m=mkmacro(MAXINT,1,0,NULL); addmacro(m,mkmacro(buf[x],1,0,findcmd("type"))); ++x; } if(buf[x]=='\"') ++x; } /* Do we have a command? */ else { for(y=x; buf[y] && buf[y]!=',' && buf[y]!=' ' && buf[y]!='\t' && buf[y]!='\n' && buf[x]!='\r'; ++y); if(y!=x) { CMD *cmd; c=buf[y]; buf[y]=0; cmd=findcmd(buf+x); if(!cmd) { *sta = -1; return 0; } else if(m) { if(!m->steps) { MACRO *macro=m; m=mkmacro(MAXINT,1,0,NULL); addmacro(m,macro); } addmacro(m,mkmacro(MAXINT,1,0,cmd)); } else m=mkmacro(MAXINT,1,0,cmd); buf[x=y]=c; } } /* Skip whitespace */ while(cwhite(buf[x])) ++x; /* Do we have a comma? */ if(buf[x]==',') { ++x; while(cwhite(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 char *ptr; static int first; static int instr; char *unescape(ptr,c) char *ptr; { if(c=='"') *ptr++='\\', *ptr++='"'; else if(c=='\'') *ptr++='\\', *ptr++='\''; else if(c<32 || c>126) { *ptr++='\\'; *ptr++='x'; *ptr++="0123456789ABCDEF"[c>>4]; *ptr++="0123456789ABCDEF"[c&15]; } else *ptr++=c; return ptr; } void domtext(m) 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,"type")) *ptr++='\"', instr=0; if(first) first=0; else if(!instr) *ptr++=','; if(!zcmp(m->cmd->name,"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,"play") || !zcmp(m->cmd->name,"gomark") || !zcmp(m->cmd->name,"setmark") || !zcmp(m->cmd->name,"record") || !zcmp(m->cmd->name,"uarg")) { *ptr++=','; *ptr++='"'; ptr=unescape(ptr,m->k); *ptr++='"'; } } } } char *mtext(s,m) 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=0; static void unmac() { if(recmac) rmmacro(recmac->m->steps[--recmac->m->n]); } void chmac() { if(recmac && recmac->m->n) recmac->m->steps[recmac->m->n-1]->k=3; } static void record(m) MACRO *m; { if(recmac) addmacro(recmac->m,dupmacro(m)); } /* Query for user input */ int uquery(bw) BW *bw; { int ret; struct recmac *tmp=recmac; recmac=0; ret=edloop(1); recmac=tmp; return ret; } /* Macro execution */ MACRO *curmacro=0; /* Set if we're in a macro */ static int macroptr; static int arg=0; /* Repeat argument */ static int argset=0; /* Set if 'arg' is set */ int exmacro(m,u) MACRO *m; { int larg; int negarg=0; int flg=0; CMD *cmd; int n; int ret=0; if(argset) { larg=arg; arg=0; argset=0; if(larg<0) negarg=1, larg= -larg; if(m->steps) negarg=0; else { cmd=m->cmd; if(!cmd->arg) larg=0; else if(negarg) if(cmd->negarg) cmd=findcmd(cmd->negarg); else larg=0; } } else { cmd=m->cmd; larg=1; } if( m->steps || larg!=1 || !(cmd->flag&EMINOR) || maint->curwin->watom->what==TYPEQW /* Undo work right for s & r */ ) flg=1; if(flg && u) umclear(); while(larg-- && !leave && !ret) if(m->steps) { MACRO *tmpmac=curmacro; int tmpptr=macroptr; int x=0; int stk=nstack; while(m && x!=m->n && !leave && !ret) { MACRO *d; d=m->steps[x++]; curmacro=m; macroptr=x; ret=exmacro(d,0); m=curmacro; x=macroptr; } curmacro=tmpmac; macroptr=tmpptr; while(nstack>stk) upop(NULL); } else ret=execmd(cmd,m->k); if(leave) return ret; if(flg && u) umclear(); if(u) undomark(); return ret; } /* Execute a macro */ int exemac(m) MACRO *m; { record(m); return exmacro(m,1); } /* Keyboard macro user routines */ static int dorecord(bw,c,object,notify) BW *bw; void *object; int *notify; { int n; struct recmac *r; if(notify) *notify=1; if(c>'9' || c<'0') { nungetc(c); return -1; } for(n=0;n!=10;++n) if(playmode[n]) return -1; r=(struct recmac *)malloc(sizeof(struct recmac)); r->m=mkmacro(0,1,0,NULL); r->next=recmac; r->n=c-'0'; recmac=r; return 0; } int urecord(bw,c) BW *bw; { if(c>='0' && c<='9') return dorecord(bw,c,NULL,NULL); else if(mkqw(bw,sc("Macro to record (0-9 or ^C to abort): "),dorecord,NULL,NULL,NULL)) return 0; else return -1; } extern int dostaupd; int ustop() { unmac(); if(recmac) { struct recmac *r=recmac; MACRO *m; dostaupd=1; recmac=r->next; if(kbdmacro[r->n]) rmmacro(kbdmacro[r->n]); kbdmacro[r->n]=r->m; if(recmac) record(m=mkmacro(r->n+'0',1,0,findcmd("play"))), rmmacro(m); free(r); } return 0; } int doplay(bw,c,object,notify) BW *bw; void *object; int *notify; { if(notify) *notify=1; if(c>='0' && c<='9') { int ret; c-='0'; if(playmode[c] || !kbdmacro[c]) return -1; playmode[c]=1; ret=exmacro(kbdmacro[c],0); playmode[c]=0; return ret; } else { nungetc(c); return -1; } } int umacros(bw) BW *bw; { int x; char buf[1024]; peol(bw->cursor); for(x=0;x!=10;++x) if(kbdmacro[x]) { mtext(buf,kbdmacro[x]); binss(bw->cursor,buf); peol(bw->cursor); sprintf(buf,"\t^K %c\tMacro %d",x+'0',x); binss(bw->cursor,buf); peol(bw->cursor); binsc(bw->cursor,'\n'); pgetc(bw->cursor); } return 0; } int uplay(bw,c) BW *bw; { if(c>='0' && c<='9') return doplay(bw,c,NULL,NULL); else if(mkqwna(bw,sc("Play-"),doplay,NULL,NULL,NULL)) return 0; else return -1; } /* Repeat-count setting */ static int doarg(bw,s,object,notify) BW *bw; char *s; void *object; int *notify; { long num; if(notify) *notify=1; num=calc(bw,s); if(merr) { msgnw(bw,merr); return -1; } arg=num; argset=1; vsrm(s); return 0; } int uarg(bw) BW *bw; { if(wmkpw(bw, "No. times to repeat next command (^C to abort): ", NULL,doarg,NULL,NULL,utypebw,NULL,NULL)) return 0; else return -1; } int unaarg; int negarg; int douarg(bw,c,object,notify) BW *bw; void *object; int *notify; { if(c=='-') negarg= !negarg; else if(c>='0' && c<='9') unaarg=unaarg*10+c-'0'; else if(c=='U'-'@') if(unaarg) unaarg*=4; else unaarg=16; else if(c==7 || c==3 || c==32) { if(notify) *notify=1; return -1; } else { nungetc(c); if(unaarg) arg=unaarg; else if(negarg) arg=1; else arg=4; if(negarg) arg= -arg; argset=1; if(notify) *notify=1; return 0; } sprintf(msgbuf,"Repeat %s%d",negarg?"-":"",unaarg); if(mkqwna(bw,sz(msgbuf),douarg,NULL,NULL,notify)) return 0; else return -1; } int uuarg(bw,c) BW *bw; { unaarg=0; negarg=0; if(c>='0' && c<='9' || c=='-') return douarg(bw,c,NULL,NULL); else if(mkqwna(bw,sc("Repeat"),douarg,NULL,NULL,NULL)) return 0; else return -1; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.