URI:
       tt7.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tt7.c (8615B)
       ---
            1 /*
            2  * 7.  Macros, strings, diversion, and position traps.
            3  *
            4  *         macros can override builtins
            5  *        builtins can be renamed or removed!
            6  */
            7 
            8 #include "a.h"
            9 
           10 enum
           11 {
           12         MAXARG = 10,
           13         MAXMSTACK = 40
           14 };
           15 
           16 /* macro invocation frame */
           17 typedef struct Mac Mac;
           18 struct Mac
           19 {
           20         int argc;
           21         Rune *argv[MAXARG];
           22 };
           23 
           24 Mac                mstack[MAXMSTACK];
           25 int                nmstack;
           26 void                emitdi(void);
           27 void                flushdi(void);
           28 
           29 /*
           30  * Run a user-defined macro.
           31  */
           32 void popmacro(void);
           33 int
           34 runmacro(int dot, int argc, Rune **argv)
           35 {
           36         Rune *p;
           37         int i;
           38         Mac *m;
           39 
           40 if(verbose && isupperrune(argv[0][0])) fprint(2, "run: %S\n", argv[0]);
           41         p = getds(argv[0]);
           42         if(p == nil){
           43                 if(verbose)
           44                         warn("ignoring unknown request %C%S", dot, argv[0]);
           45                 if(verbose > 1){
           46                         for(i=0; i<argc; i++)
           47                                 fprint(2, " %S", argv[i]);
           48                         fprint(2, "\n");
           49                 }
           50                 return -1;
           51         }
           52         if(nmstack >= nelem(mstack)){
           53                 fprint(2, "%L: macro stack overflow:");
           54                 for(i=0; i<nmstack; i++)
           55                         fprint(2, " %S", mstack[i].argv[0]);
           56                 fprint(2, "\n");
           57                 return -1;
           58         }
           59         m = &mstack[nmstack++];
           60         m->argc = argc;
           61         for(i=0; i<argc; i++)
           62                 m->argv[i] = erunestrdup(argv[i]);
           63         pushinputstring(p);
           64         nr(L(".$"), argc-1);
           65         inputnotify(popmacro);
           66         return 0;
           67 }
           68 
           69 void
           70 popmacro(void)
           71 {
           72         int i;
           73         Mac *m;
           74 
           75         if(--nmstack < 0){
           76                 fprint(2, "%L: macro stack underflow\n");
           77                 return;
           78         }
           79         m = &mstack[nmstack];
           80         for(i=0; i<m->argc; i++)
           81                 free(m->argv[i]);
           82         if(nmstack > 0)
           83                 nr(L(".$"), mstack[nmstack-1].argc-1);
           84         else
           85                 nr(L(".$"), 0);
           86 }
           87 
           88 void popmacro1(void);
           89 jmp_buf runjb[10];
           90 int nrunjb;
           91 
           92 void
           93 runmacro1(Rune *name)
           94 {
           95         Rune *argv[2];
           96         int obol;
           97 
           98 if(verbose) fprint(2, "outcb %p\n", outcb);
           99         obol = bol;
          100         argv[0] = name;
          101         argv[1] = nil;
          102         bol = 1;
          103         if(runmacro('.', 1, argv) >= 0){
          104                 inputnotify(popmacro1);
          105                 if(!setjmp(runjb[nrunjb++]))
          106                         runinput();
          107                 else
          108                         if(verbose) fprint(2, "finished %S\n", name);
          109         }
          110         bol = obol;
          111 }
          112 
          113 void
          114 popmacro1(void)
          115 {
          116         popmacro();
          117         if(nrunjb >= 0)
          118                 longjmp(runjb[--nrunjb], 1);
          119 }
          120 
          121 /*
          122  * macro arguments
          123  *
          124  *        "" means " inside " "
          125  *        "" empty string
          126  *        \newline can be done
          127  *        argument separator is space (not tab)
          128  *        number register .$ = number of arguments
          129  *        no arguments outside macros or in strings
          130  *
          131  *        arguments copied in copy mode
          132  */
          133 
          134 /*
          135  * diversions
          136  *
          137  *        processed output diverted
          138  *        dn dl registers vertical and horizontal size of last diversion
          139  *        .z - current diversion name
          140  */
          141 
          142 /*
          143  * traps
          144  *
          145  *        skip most
          146  *        .t register - distance to next trap
          147  */
          148 static Rune *trap0;
          149 
          150 void
          151 outtrap(void)
          152 {
          153         Rune *t;
          154 
          155         if(outcb)
          156                 return;
          157         if(trap0){
          158 if(verbose) fprint(2, "trap: %S\n", trap0);
          159                 t = trap0;
          160                 trap0 = nil;
          161                 runmacro1(t);
          162                 free(t);
          163         }
          164 }
          165 
          166 /* .wh - install trap */
          167 void
          168 r_wh(int argc, Rune **argv)
          169 {
          170         int i;
          171 
          172         if(argc < 2)
          173                 return;
          174 
          175         i = eval(argv[1]);
          176         if(argc == 2){
          177                 if(i == 0){
          178                         free(trap0);
          179                         trap0 = nil;
          180                 }else
          181                         if(verbose)
          182                                 warn("not removing trap at %d", i);
          183         }
          184         if(argc > 2){
          185                 if(i == 0){
          186                         free(trap0);
          187                         trap0 = erunestrdup(argv[2]);
          188                 }else
          189                         if(verbose)
          190                                 warn("not installing %S trap at %d", argv[2], i);
          191         }
          192 }
          193 
          194 void
          195 r_ch(int argc, Rune **argv)
          196 {
          197         int i;
          198 
          199         if(argc == 2){
          200                 if(trap0 && runestrcmp(argv[1], trap0) == 0){
          201                         free(trap0);
          202                         trap0 = nil;
          203                 }else
          204                         if(verbose)
          205                                 warn("not removing %S trap", argv[1]);
          206                 return;
          207         }
          208         if(argc >= 3){
          209                 i = eval(argv[2]);
          210                 if(i == 0){
          211                         free(trap0);
          212                         trap0 = erunestrdup(argv[1]);
          213                 }else
          214                         if(verbose)
          215                                 warn("not moving %S trap to %d", argv[1], i);
          216         }
          217 }
          218 
          219 void
          220 r_dt(int argc, Rune **argv)
          221 {
          222         USED(argc);
          223         USED(argv);
          224         warn("ignoring diversion trap");
          225 }
          226 
          227 /* define macro - .de, .am, .ig */
          228 void
          229 r_de(int argc, Rune **argv)
          230 {
          231         Rune *end, *p;
          232         Fmt fmt;
          233         int ignore, len;
          234 
          235         delreq(argv[1]);
          236         delraw(argv[1]);
          237         ignore = runestrcmp(argv[0], L("ig")) == 0;
          238         if(!ignore)
          239                 runefmtstrinit(&fmt);
          240         end = L("..");
          241         if(argc >= 3)
          242                 end = argv[2];
          243         if(runestrcmp(argv[0], L("am")) == 0 && (p=getds(argv[1])) != nil)
          244                 fmtrunestrcpy(&fmt, p);
          245         len = runestrlen(end);
          246         while((p = readline(CopyMode)) != nil){
          247                 if(runestrncmp(p, end, len) == 0
          248                 && (p[len]==' ' || p[len]==0 || p[len]=='\t'
          249                         || (p[len]=='\\' && p[len+1]=='}'))){
          250                         free(p);
          251                         goto done;
          252                 }
          253                 if(!ignore)
          254                         fmtprint(&fmt, "%S\n", p);
          255                 free(p);
          256         }
          257         warn("eof in %C%S %S - looking for %#Q", dot, argv[0], argv[1], end);
          258 done:
          259         if(ignore)
          260                 return;
          261         p = runefmtstrflush(&fmt);
          262         if(p == nil)
          263                 sysfatal("out of memory");
          264         ds(argv[1], p);
          265         free(p);
          266 }
          267 
          268 /* define string .ds .as */
          269 void
          270 r_ds(Rune *cmd)
          271 {
          272         Rune *name, *line, *p;
          273 
          274         name = copyarg();
          275         line = readline(CopyMode);
          276         if(name == nil || line == nil){
          277                 free(name);
          278                 return;
          279         }
          280         p = line;
          281         if(*p == '"')
          282                 p++;
          283         if(cmd[0] == 'd')
          284                 ds(name, p);
          285         else
          286                 as(name, p);
          287         free(name);
          288         free(line);
          289 }
          290 
          291 /* remove request, macro, or string */
          292 void
          293 r_rm(int argc, Rune **argv)
          294 {
          295         int i;
          296 
          297         emitdi();
          298         for(i=1; i<argc; i++){
          299                 delreq(argv[i]);
          300                 delraw(argv[i]);
          301                 ds(argv[i], nil);
          302         }
          303 }
          304 
          305 /* .rn - rename request, macro, or string */
          306 void
          307 r_rn(int argc, Rune **argv)
          308 {
          309         USED(argc);
          310         renreq(argv[1], argv[2]);
          311         renraw(argv[1], argv[2]);
          312         ds(argv[2], getds(argv[1]));
          313         ds(argv[1], nil);
          314 }
          315 
          316 /* .di - divert output to macro xx */
          317 /* .da - divert, appending to macro */
          318 /* page offsetting is not done! */
          319 Fmt difmt;
          320 int difmtinit;
          321 Rune di[20][100];
          322 int ndi;
          323 
          324 void
          325 emitdi(void)
          326 {
          327         flushdi();
          328         runefmtstrinit(&difmt);
          329         difmtinit = 1;
          330         fmtrune(&difmt, Uformatted);
          331 }
          332 
          333 void
          334 flushdi(void)
          335 {
          336         int n;
          337         Rune *p;
          338 
          339         if(ndi == 0 || difmtinit == 0)
          340                 return;
          341         fmtrune(&difmt, Uunformatted);
          342         p = runefmtstrflush(&difmt);
          343         memset(&difmt, 0, sizeof difmt);
          344         difmtinit = 0;
          345         if(p == nil)
          346                 warn("out of memory in diversion %C%S", dot, di[ndi-1]);
          347         else{
          348                 n = runestrlen(p);
          349                 if(n > 0 && p[n-1] != '\n'){
          350                         p = runerealloc(p, n+2);
          351                         p[n] = '\n';
          352                         p[n+1] = 0;
          353                 }
          354         }
          355         as(di[ndi-1], p);
          356         free(p);
          357 }
          358 
          359 void
          360 outdi(Rune r)
          361 {
          362 if(!difmtinit) abort();
          363         if(r == Uempty)
          364                 return;
          365         fmtrune(&difmt, r);
          366 }
          367 
          368 /* .di, .da */
          369 void
          370 r_di(int argc, Rune **argv)
          371 {
          372         br();
          373         if(argc > 2)
          374                 warn("extra arguments to %C%S", dot, argv[0]);
          375         if(argc == 1){
          376                 /* end diversion */
          377                 if(ndi <= 0){
          378                         /* warn("unmatched %C%S", dot, argv[0]); */
          379                         return;
          380                 }
          381                 flushdi();
          382                 if(--ndi == 0){
          383                         _nr(L(".z"), nil);
          384                         outcb = nil;
          385                 }else{
          386                         _nr(L(".z"), di[ndi-1]);
          387                         runefmtstrinit(&difmt);
          388                         fmtrune(&difmt, Uformatted);
          389                         difmtinit = 1;
          390                 }
          391                 return;
          392         }
          393         /* start diversion */
          394         /* various register state should be saved, but it's all useless to us */
          395         flushdi();
          396         if(ndi >= nelem(di))
          397                 sysfatal("%Cdi overflow", dot);
          398         if(argv[0][1] == 'i')
          399                 ds(argv[1], nil);
          400         _nr(L(".z"), argv[1]);
          401         runestrcpy(di[ndi++], argv[1]);
          402         runefmtstrinit(&difmt);
          403         fmtrune(&difmt, Uformatted);
          404         difmtinit = 1;
          405         outcb = outdi;
          406 }
          407 
          408 /* .wh - install trap */
          409 /* .ch - change trap */
          410 /* .dt - install diversion trap */
          411 
          412 /* set input-line count trap */
          413 int itrapcount;
          414 int itrapwaiting;
          415 Rune *itrapname;
          416 
          417 void
          418 r_it(int argc, Rune **argv)
          419 {
          420         if(argc < 3){
          421                 itrapcount = 0;
          422                 return;
          423         }
          424         itrapcount = eval(argv[1]);
          425         free(itrapname);
          426         itrapname = erunestrdup(argv[2]);
          427 }
          428 
          429 void
          430 itrap(void)
          431 {
          432         itrapset();
          433         if(itrapwaiting){
          434                 itrapwaiting = 0;
          435                 runmacro1(itrapname);
          436         }
          437 }
          438 
          439 void
          440 itrapset(void)
          441 {
          442         if(itrapcount > 0 && --itrapcount == 0)
          443                 itrapwaiting = 1;
          444 }
          445 
          446 /* .em - invoke macro when all input is over */
          447 void
          448 r_em(int argc, Rune **argv)
          449 {
          450         Rune buf[20];
          451 
          452         USED(argc);
          453         runesnprint(buf, nelem(buf), ".%S\n", argv[1]);
          454         as(L("eof"), buf);
          455 }
          456 
          457 int
          458 e_star(void)
          459 {
          460         Rune *p;
          461 
          462         p = getds(getname());
          463         if(p)
          464                 pushinputstring(p);
          465         return 0;
          466 }
          467 
          468 int
          469 e_t(void)
          470 {
          471         if(inputmode&CopyMode)
          472                 return '\t';
          473         return 0;
          474 }
          475 
          476 int
          477 e_a(void)
          478 {
          479         if(inputmode&CopyMode)
          480                 return '\a';
          481         return 0;
          482 }
          483 
          484 int
          485 e_backslash(void)
          486 {
          487         if(inputmode&ArgMode)
          488                 ungetrune('\\');
          489         return backslash;
          490 }
          491 
          492 int
          493 e_dot(void)
          494 {
          495         return '.';
          496 }
          497 
          498 int
          499 e_dollar(void)
          500 {
          501         int c;
          502 
          503         c = getnext();
          504         if(c < '1' || c > '9'){
          505                 ungetnext(c);
          506                 return 0;
          507         }
          508         c -= '0';
          509         if(nmstack <= 0 || mstack[nmstack-1].argc <= c)
          510                 return 0;
          511         pushinputstring(mstack[nmstack-1].argv[c]);
          512         return 0;
          513 }
          514 
          515 void
          516 t7init(void)
          517 {
          518         addreq(L("de"), r_de, -1);
          519         addreq(L("am"), r_de, -1);
          520         addreq(L("ig"), r_de, -1);
          521         addraw(L("ds"), r_ds);
          522         addraw(L("as"), r_ds);
          523         addreq(L("rm"), r_rm, -1);
          524         addreq(L("rn"), r_rn, -1);
          525         addreq(L("di"), r_di, -1);
          526         addreq(L("da"), r_di, -1);
          527         addreq(L("it"), r_it, -1);
          528         addreq(L("em"), r_em, 1);
          529         addreq(L("wh"), r_wh, -1);
          530         addreq(L("ch"), r_ch, -1);
          531         addreq(L("dt"), r_dt, -1);
          532 
          533         addesc('$', e_dollar, CopyMode|ArgMode|HtmlMode);
          534         addesc('*', e_star, CopyMode|ArgMode|HtmlMode);
          535         addesc('t', e_t, CopyMode|ArgMode);
          536         addesc('a', e_a, CopyMode|ArgMode);
          537         addesc('\\', e_backslash, ArgMode|CopyMode);
          538         addesc('.', e_dot, CopyMode|ArgMode);
          539 
          540         ds(L("eof"), L(".sp 0.5i\n"));
          541         ds(L(".."), L(""));
          542 }