123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543 |
- /*
- * 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);
- int
- runmacro(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;
- }
- void
- popmacro(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;
- void
- runmacro1(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;
- }
- void
- popmacro1(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;
- void
- outtrap(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 */
- void
- r_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);
- }
- }
- void
- r_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);
- }
- }
- void
- r_dt(int argc, Rune **argv)
- {
- USED(argc);
- USED(argv);
- warn("ignoring diversion trap");
- }
- /* define macro - .de, .am, .ig */
- void
- r_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 */
- void
- r_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 */
- void
- r_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 */
- void
- r_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;
- void
- emitdi(void)
- {
- flushdi();
- runefmtstrinit(&difmt);
- difmtinit = 1;
- fmtrune(&difmt, Uformatted);
- }
- void
- flushdi(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);
- }
- void
- outdi(Rune r)
- {
- if(!difmtinit) abort();
- if(r == Uempty)
- return;
- fmtrune(&difmt, r);
- }
- /* .di, .da */
- void
- r_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;
- void
- r_it(int argc, Rune **argv)
- {
- if(argc < 3){
- itrapcount = 0;
- return;
- }
- itrapcount = eval(argv[1]);
- free(itrapname);
- itrapname = erunestrdup(argv[2]);
- }
- void
- itrap(void)
- {
- itrapset();
- if(itrapwaiting){
- itrapwaiting = 0;
- runmacro1(itrapname);
- }
- }
- void
- itrapset(void)
- {
- if(itrapcount > 0 && --itrapcount == 0)
- itrapwaiting = 1;
- }
- /* .em - invoke macro when all input is over */
- void
- r_em(int argc, Rune **argv)
- {
- Rune buf[20];
-
- USED(argc);
- runesnprint(buf, nelem(buf), ".%S\n", argv[1]);
- as(L("eof"), buf);
- }
- int
- e_star(void)
- {
- Rune *p;
-
- p = getds(getname());
- if(p)
- pushinputstring(p);
- return 0;
- }
- int
- e_t(void)
- {
- if(inputmode&CopyMode)
- return '\t';
- return 0;
- }
- int
- e_a(void)
- {
- if(inputmode&CopyMode)
- return '\a';
- return 0;
- }
- int
- e_backslash(void)
- {
- if(inputmode&ArgMode)
- ungetrune('\\');
- return backslash;
- }
- int
- e_dot(void)
- {
- return '.';
- }
- int
- e_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;
- }
- void
- t7init(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(""));
- }
|