📄 t7.c
字号:
/* * 7. Macros, strings, diversion, and position traps. * * macros can override builtins * builtins can be renamed or removed! */#include "a.h"enum{ MAXARG = 10, MAXMSTACK = 40};/* macro invocation frame */typedef struct Mac Mac;struct Mac{ int argc; Rune *argv[MAXARG];};Mac mstack[MAXMSTACK];int nmstack;void emitdi(void);void flushdi(void);/* * Run a user-defined macro. */void popmacro(void);intrunmacro(int dot, int argc, Rune **argv){ Rune *p; int i; Mac *m; if(verbose && isupperrune(argv[0][0])) fprint(2, "run: %S\n", argv[0]); p = getds(argv[0]); if(p == nil){ if(verbose) warn("ignoring unknown request %C%S", dot, argv[0]); if(verbose > 1){ for(i=0; i<argc; i++) fprint(2, " %S", argv[i]); fprint(2, "\n"); } return -1; } if(nmstack >= nelem(mstack)){ fprint(2, "%L: macro stack overflow:"); for(i=0; i<nmstack; i++) fprint(2, " %S", mstack[i].argv[0]); fprint(2, "\n"); return -1; } m = &mstack[nmstack++]; m->argc = argc; for(i=0; i<argc; i++) m->argv[i] = erunestrdup(argv[i]); pushinputstring(p); nr(L(".$"), argc-1); inputnotify(popmacro); return 0;}voidpopmacro(void){ int i; Mac *m; if(--nmstack < 0){ fprint(2, "%L: macro stack underflow\n"); return; } m = &mstack[nmstack]; for(i=0; i<m->argc; i++) free(m->argv[i]); if(nmstack > 0) nr(L(".$"), mstack[nmstack-1].argc-1); else nr(L(".$"), 0);}void popmacro1(void);jmp_buf runjb[10];int nrunjb;voidrunmacro1(Rune *name){ Rune *argv[2]; int obol; if(verbose) fprint(2, "outcb %p\n", outcb); obol = bol; argv[0] = name; argv[1] = nil; bol = 1; if(runmacro('.', 1, argv) >= 0){ inputnotify(popmacro1); if(!setjmp(runjb[nrunjb++])) runinput(); else if(verbose) fprint(2, "finished %S\n", name); } bol = obol;}voidpopmacro1(void){ popmacro(); if(nrunjb >= 0) longjmp(runjb[--nrunjb], 1);}/* * macro arguments * * "" means " inside " " * "" empty string * \newline can be done * argument separator is space (not tab) * number register .$ = number of arguments * no arguments outside macros or in strings * * arguments copied in copy mode *//* * diversions * * processed output diverted * dn dl registers vertical and horizontal size of last diversion * .z - current diversion name *//* * traps * * skip most * .t register - distance to next trap */static Rune *trap0;voidouttrap(void){ Rune *t; if(outcb) return; if(trap0){if(verbose) fprint(2, "trap: %S\n", trap0); t = trap0; trap0 = nil; runmacro1(t); free(t); }}/* .wh - install trap */voidr_wh(int argc, Rune **argv){ int i; if(argc < 2) return; i = eval(argv[1]); if(argc == 2){ if(i == 0){ free(trap0); trap0 = nil; }else if(verbose) warn("not removing trap at %d", i); } if(argc > 2){ if(i == 0){ free(trap0); trap0 = erunestrdup(argv[2]); }else if(verbose) warn("not installing %S trap at %d", argv[2], i); }}voidr_ch(int argc, Rune **argv){ int i; if(argc == 2){ if(trap0 && runestrcmp(argv[1], trap0) == 0){ free(trap0); trap0 = nil; }else if(verbose) warn("not removing %S trap", argv[1]); return; } if(argc >= 3){ i = eval(argv[2]); if(i == 0){ free(trap0); trap0 = erunestrdup(argv[1]); }else if(verbose) warn("not moving %S trap to %d", argv[1], i); }}voidr_dt(int argc, Rune **argv){ USED(argc); USED(argv); warn("ignoring diversion trap");}/* define macro - .de, .am, .ig */voidr_de(int argc, Rune **argv){ Rune *end, *p; Fmt fmt; int ignore, len; delreq(argv[1]); delraw(argv[1]); ignore = runestrcmp(argv[0], L("ig")) == 0; if(!ignore) runefmtstrinit(&fmt); end = L(".."); if(argc >= 3) end = argv[2]; if(runestrcmp(argv[0], L("am")) == 0 && (p=getds(argv[1])) != nil) fmtrunestrcpy(&fmt, p); len = runestrlen(end); while((p = readline(CopyMode)) != nil){ if(runestrncmp(p, end, len) == 0 && (p[len]==' ' || p[len]==0 || p[len]=='\t' || (p[len]=='\\' && p[len+1]=='}'))){ free(p); goto done; } if(!ignore) fmtprint(&fmt, "%S\n", p); free(p); } warn("eof in %C%S %S - looking for %#Q", dot, argv[0], argv[1], end);done: if(ignore) return; p = runefmtstrflush(&fmt); if(p == nil) sysfatal("out of memory"); ds(argv[1], p); free(p);}/* define string .ds .as */voidr_ds(Rune *cmd){ Rune *name, *line, *p; name = copyarg(); line = readline(CopyMode); if(name == nil || line == nil){ free(name); return; } p = line; if(*p == '"') p++; if(cmd[0] == 'd') ds(name, p); else as(name, p); free(name); free(line);}/* remove request, macro, or string */voidr_rm(int argc, Rune **argv){ int i; emitdi(); for(i=1; i<argc; i++){ delreq(argv[i]); delraw(argv[i]); ds(argv[i], nil); }}/* .rn - rename request, macro, or string */voidr_rn(int argc, Rune **argv){ USED(argc); renreq(argv[1], argv[2]); renraw(argv[1], argv[2]); ds(argv[2], getds(argv[1])); ds(argv[1], nil);}/* .di - divert output to macro xx *//* .da - divert, appending to macro *//* page offsetting is not done! */Fmt difmt;int difmtinit;Rune di[20][100];int ndi;voidemitdi(void){ flushdi(); runefmtstrinit(&difmt); difmtinit = 1; fmtrune(&difmt, Uformatted);}voidflushdi(void){ int n; Rune *p; if(ndi == 0 || difmtinit == 0) return; fmtrune(&difmt, Uunformatted); p = runefmtstrflush(&difmt); memset(&difmt, 0, sizeof difmt); difmtinit = 0; if(p == nil) warn("out of memory in diversion %C%S", dot, di[ndi-1]); else{ n = runestrlen(p); if(n > 0 && p[n-1] != '\n'){ p = runerealloc(p, n+2); p[n] = '\n'; p[n+1] = 0; } } as(di[ndi-1], p); free(p);}voidoutdi(Rune r){if(!difmtinit) abort(); if(r == Uempty) return; fmtrune(&difmt, r);}/* .di, .da */voidr_di(int argc, Rune **argv){ br(); if(argc > 2) warn("extra arguments to %C%S", dot, argv[0]); if(argc == 1){ /* end diversion */ if(ndi <= 0){ // warn("unmatched %C%S", dot, argv[0]); return; } flushdi(); if(--ndi == 0){ _nr(L(".z"), nil); outcb = nil; }else{ _nr(L(".z"), di[ndi-1]); runefmtstrinit(&difmt); fmtrune(&difmt, Uformatted); difmtinit = 1; } return; } /* start diversion */ /* various register state should be saved, but it's all useless to us */ flushdi(); if(ndi >= nelem(di)) sysfatal("%Cdi overflow", dot); if(argv[0][1] == 'i') ds(argv[1], nil); _nr(L(".z"), argv[1]); runestrcpy(di[ndi++], argv[1]); runefmtstrinit(&difmt); fmtrune(&difmt, Uformatted); difmtinit = 1; outcb = outdi;}/* .wh - install trap *//* .ch - change trap *//* .dt - install diversion trap *//* set input-line count trap */int itrapcount;int itrapwaiting;Rune *itrapname;voidr_it(int argc, Rune **argv){ if(argc < 3){ itrapcount = 0; return; } itrapcount = eval(argv[1]); free(itrapname); itrapname = erunestrdup(argv[2]);}voiditrap(void){ itrapset(); if(itrapwaiting){ itrapwaiting = 0; runmacro1(itrapname); }}voiditrapset(void){ if(itrapcount > 0 && --itrapcount == 0) itrapwaiting = 1;}/* .em - invoke macro when all input is over */voidr_em(int argc, Rune **argv){ Rune buf[20]; USED(argc); runesnprint(buf, nelem(buf), ".%S\n", argv[1]); as(L("eof"), buf);}inte_star(void){ Rune *p; p = getds(getname()); if(p) pushinputstring(p); return 0;}inte_t(void){ if(inputmode&CopyMode) return '\t'; return 0;}inte_a(void){ if(inputmode&CopyMode) return '\a'; return 0;}inte_backslash(void){ if(inputmode&ArgMode) ungetrune('\\'); return backslash;}inte_dot(void){ return '.';}inte_dollar(void){ int c; c = getnext(); if(c < '1' || c > '9'){ ungetnext(c); return 0; } c -= '0'; if(nmstack <= 0 || mstack[nmstack-1].argc <= c) return 0; pushinputstring(mstack[nmstack-1].argv[c]); return 0;}voidt7init(void){ addreq(L("de"), r_de, -1); addreq(L("am"), r_de, -1); addreq(L("ig"), r_de, -1); addraw(L("ds"), r_ds); addraw(L("as"), r_ds); addreq(L("rm"), r_rm, -1); addreq(L("rn"), r_rn, -1); addreq(L("di"), r_di, -1); addreq(L("da"), r_di, -1); addreq(L("it"), r_it, -1); addreq(L("em"), r_em, 1); addreq(L("wh"), r_wh, -1); addreq(L("ch"), r_ch, -1); addreq(L("dt"), r_dt, -1); addesc('$', e_dollar, CopyMode|ArgMode|HtmlMode); addesc('*', e_star, CopyMode|ArgMode|HtmlMode); addesc('t', e_t, CopyMode|ArgMode); addesc('a', e_a, CopyMode|ArgMode); addesc('\\', e_backslash, ArgMode|CopyMode); addesc('.', e_dot, CopyMode|ArgMode); ds(L("eof"), L(".sp 0.5i\n")); ds(L(".."), L(""));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -