home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / SED.ZIP / SEDEXEC.C < prev    next >
C/C++ Source or Header  |  1989-01-02  |  29KB  |  743 lines

  1. /*
  2. sedexec.c -- execute compiled form of stream editor commands
  3.  
  4.    The single entry point of this module is the function execute(). It
  5. may take a string argument (the name of a file to be used as text)  or
  6. the argument NULL which tells it to filter standard input. It executes
  7. the compiled commands in cmds[] on each line in turn.
  8.    The function command() does most of the work. Match() and advance()
  9. are used for matching text against precompiled regular expressions and
  10. dosub() does right-hand-side substitution.  Getline() does text input;
  11. readout() and memcmp() are output and string-comparison utilities.
  12.  
  13. ==== Written for the GNU operating system by Eric S. Raymond ====
  14. */
  15.  
  16. #include <stdio.h>      /* {f}puts, {f}printf, getc/putc, f{re}open, fclose */
  17. #include <ctype.h>      /* for isprint(), isdigit(), toascii() macros */
  18. #include "sed.h"        /* command type structures & miscellaneous constants */
  19. #include "sed.dcl"
  20.  
  21. extern char     *strcpy();      /* used in dosub */
  22.  
  23. /***** shared variables imported from the main ******/
  24.  
  25. /* main data areas */
  26. extern char     linebuf[];      /* current-line buffer */
  27. extern sedcmd   cmds[];         /* hold compiled commands */
  28. extern long     linenum[];      /* numeric-addresses table */
  29.  
  30. /* miscellaneous shared variables */
  31. extern int      nflag;          /* -n option flag */
  32. extern int      eargc;          /* scratch copy of argument count */
  33. extern sedcmd   *pending;       /* ptr to command waiting to be executed */
  34. extern char     bits[];         /* the bits table */
  35.  
  36. /***** end of imported stuff *****/
  37.  
  38. #define MAXHOLD         MAXBUF  /* size of the hold space */
  39. #define GENSIZ          MAXBUF  /* maximum genbuf size */
  40.  
  41. #define TRUE            1
  42. #define FALSE           0
  43.  
  44. static char LTLMSG[]    = "sed: line too long\n";
  45.  
  46. static char     *spend;         /* current end-of-line-buffer pointer */
  47. static long     lnum = 0L;      /* current source line number */
  48.  
  49. /* append buffer maintenance */
  50. static sedcmd   *appends[MAXAPPENDS];   /* array of ptrs to a,i,c commands */
  51. static sedcmd   **aptr = appends;       /* ptr to current append */
  52.  
  53. /* genbuf and its pointers */
  54. static char     genbuf[GENSIZ];
  55. static char     *lcomend = genbuf + GENSIZ;
  56. static char     *loc1;
  57. static char     *loc2;
  58. static char     *locs;
  59.  
  60. /* command-logic flags */
  61. static int      lastline;               /* do-line flag */
  62. static int      jump;                   /* jump to cmd's link address if set */
  63. static int      delete;                 /* delete command flag */
  64.  
  65. /* tagged-pattern tracking */
  66. static char     *bracend[MAXTAGS];      /* tagged pattern start pointers */
  67. static char     *brastart[MAXTAGS];     /* tagged pattern end pointers */
  68.  
  69.  
  70. void execute(file)
  71. /* execute the compiled commands in cmds[] on a file */
  72. char *file;             /* name of text source file to be filtered */
  73. {
  74.         register char           *p1, *p2;       /* dummy copy ptrs */
  75.         register sedcmd         *ipc;           /* ptr to current command */
  76.         char                    *execp;         /* ptr to source */
  77.         char                    *getline();     /* input-getting functions */
  78.         void                    command(), readout();
  79.  
  80. PASS("execute(): entry");
  81.  
  82.         if (file != NULL)       /* filter text from a named file */
  83.                 if (freopen(file, "r", stdin) == NULL)
  84.                         fprintf(stderr, "sed: can't open %s\n", file);
  85. PASS("execute(): reopen");
  86.  
  87.         if (pending)            /* there's a command waiting */
  88.         {
  89.                 ipc = pending;          /* it will be first executed */
  90.                 pending = FALSE;        /*   turn off the waiting flag */
  91.                 goto doit;              /*   go to execute it immediately */
  92.         }
  93.  
  94.         /* here's the main command-execution loop */
  95.         for(;;)
  96.         {
  97. PASS("execute(): main loop entry");
  98.  
  99.                 /* get next line to filter */
  100.                 if ((execp = getline(linebuf)) == BAD)
  101.                         return;
  102. PASS("execute(): getline");
  103.                 spend = execp;
  104.  
  105.                 /* loop through compiled commands, executing them */
  106.                 for(ipc = cmds; ipc->command; )
  107.                 {
  108. PASS("execute(): command loop entry");
  109.                         /* all no-address commands are selected */
  110.                         if (ipc->addr1 && !selected(ipc))
  111.                         {
  112.                                 ipc++;
  113.                                 continue;
  114.                         }
  115.         doit:
  116. PASS("execute(): doit");
  117.                         command(ipc);   /* execute the command pointed at */
  118. PASS("execute(): command");
  119.  
  120.                         if (delete)     /* if delete flag is set */
  121.                                 break;  /* don't exec rest of compiled cmds */
  122.  
  123.                         if (jump)       /* if jump set, follow cmd's link */
  124.                         {
  125.                                 jump = FALSE;
  126.                                 if ((ipc = ipc->u.link) == 0)
  127.                                 {
  128.                                         ipc = cmds;
  129.                                         break;
  130.                                 }
  131.                         }
  132.                         else            /* normal goto next command */
  133.                                 ipc++;
  134. PASS("execute(): end command loop");
  135.                 }
  136.                 /* we've now done all modification commands on the line */
  137.  
  138.                 /* here's where the transformed line is output */
  139. PASS("execute(): output");
  140.                 if (!nflag && !delete)
  141.                 {
  142.                         for(p1 = linebuf; p1 < spend; p1++)
  143.                                 putc(*p1, stdout);
  144.                         putc('\n', stdout);
  145.                 }
  146.  
  147.                 /* if we've been set up for append, emit the text from it */
  148.                 if (aptr > appends)
  149.                         readout();
  150.  
  151.                 delete = FALSE; /* clear delete flag; about to get next cmd */
  152. PASS("execute(): end main loop");
  153.         }
  154. PASS("execute(): end execute");
  155. }
  156.  
  157. static int selected(ipc)
  158. /* is current command selected */
  159. sedcmd  *ipc;
  160. {
  161.         register char   *p1 = ipc->addr1;       /* point p1 at first address */
  162.         register char   *p2 = ipc->addr2;       /*   and p2 at second */
  163.         char            c;
  164.  
  165.         if (ipc->flags.inrange)
  166.         {
  167.                 if (*p2 == CEND)
  168.                         p1 = NULL;
  169.                 else if (*p2 == CLNUM)
  170.                 {
  171.                         c = p2[1];
  172.                         if (lnum > linenum[c])
  173.                         {
  174.                                 ipc->flags.inrange = FALSE;
  175.                                 if (ipc->flags.allbut)
  176.                                         return(TRUE);
  177.                                 ipc++;
  178.                                 return(FALSE);
  179.                         }
  180.                         if (lnum == linenum[c])
  181.                                 ipc->flags.inrange = FALSE;
  182.                 }
  183.                 else if (match(p2, 0))
  184.                         ipc->flags.inrange = FALSE;
  185.         }
  186.         else if (*p1 == CEND)
  187.         {
  188.                 if (!lastline)
  189.                 {
  190.                         if (ipc->flags.allbut)
  191.                                 return(TRUE);
  192.                         ipc++;
  193.                         return(FALSE);
  194.                 }
  195.         }
  196.         else if (*p1 == CLNUM)
  197.         {
  198.                 c = p1[1];
  199.                 if (lnum != linenum[c])
  200.                 {
  201.                         if (ipc->flags.allbut)
  202.                                 return(TRUE);
  203.                         ipc++;
  204.                         return(FALSE);
  205.                 }
  206.                 if (p2)
  207.                         ipc->flags.inrange = TRUE;
  208.         }
  209.         else if (match(p1, 0))
  210.         {
  211.                 if (p2)
  212.                         ipc->flags.inrange = TRUE;
  213.         }
  214.         else
  215.         {
  216.                 if (ipc->flags.allbut)
  217.                         return(TRUE);
  218.                 ipc++;
  219.                 return(FALSE);
  220.         }
  221. }
  222.  
  223. static int match(expbuf, gf)    /* uses genbuf */
  224. /* match RE at expbuf against linebuf; if gf set, copy linebuf from genbuf */
  225. char    *expbuf;
  226. {
  227.         register char   *p1, *p2, c;
  228.  
  229.         if (gf)
  230.         {
  231.                 if (*expbuf)
  232.                         return(FALSE);
  233.                 p1 = linebuf; p2 = genbuf;
  234.                 while (*p1++ = *p2++);
  235.                 locs = p1 = loc2;
  236.         }
  237.         else
  238.         {
  239.                 p1 = linebuf;
  240.                 locs = FALSE;
  241.         }
  242.  
  243.         p2 = expbuf;
  244.         if (*p2++)
  245.         {
  246.                 loc1 = p1;
  247.                 if(*p2 == CCHR && p2[1] != *p1) /* 1st char is wrong */
  248.                         return(FALSE);          /*   so fail */
  249.                 return(advance(p1, p2));        /* else try to match rest */
  250.         }
  251.  
  252.         /* quick check for 1st character if it's literal */
  253.         if (*p2 == CCHR)
  254.         {
  255.                 c = p2[1];              /* pull out character to search for */
  256.                 do {
  257.                         if (*p1 != c)
  258.                                 continue;       /* scan the source string */
  259.                         if (advance(p1, p2))    /* found it, match the rest */
  260.                                 return(loc1 = p1, 1);
  261.                 } while
  262.                         (*p1++);
  263.                 return(FALSE);          /* didn't find that first char */
  264.         }
  265.  
  266.         /* else try for unanchored match of the pattern */
  267.         do {
  268.                 if (advance(p1, p2))
  269.                         return(loc1 = p1, 1);
  270.         } while
  271.                 (*p1++);
  272.  
  273.         /* if got here, didn't match either way */
  274.         return(FALSE);
  275. }
  276.  
  277. static int advance(lp, ep)
  278. /* attempt to advance match pointer by one pattern element */
  279. register char   *lp;            /* source (linebuf) ptr */
  280. register char   *ep;            /* regular expression element ptr */
  281. {
  282.         register char   *curlp;         /* save ptr for closures */
  283.         char            c;              /* scratch character holder */
  284.         char            *bbeg;
  285.         int             ct;
  286.  
  287.         for (;;)
  288.                 switch (*ep++)
  289.                 {
  290.                 case CCHR:              /* literal character */
  291.                         if (*ep++ == *lp++)     /* if chars are equal */
  292.                                 continue;       /* matched */
  293.                         return(FALSE);          /* else return false */
  294.  
  295.                 case CDOT:              /* anything but newline */
  296.                         if (*lp++)              /* first NUL is at EOL */
  297.                                 continue;       /* keep going if didn't find */
  298.                         return(FALSE);          /* else return false */
  299.  
  300.                 case CNL:               /* start-of-line */
  301.                 case CDOL:              /* end-of-line */
  302.                         if (*lp == 0)           /* found that first NUL? */
  303.                                 continue;       /* yes, keep going */
  304.                         return(FALSE);          /* else return false */
  305.  
  306.                 case CEOF:              /* end-of-address mark */
  307.                         loc2 = lp;              /* set second loc */
  308.                         return(TRUE);           /* return true */
  309.  
  310.                 case CCL:               /* a closure */
  311.                         c = *lp++ & 0177;
  312.                         if (ep[c>>3] & bits[c & 07])    /* is char in set? */
  313.                         {
  314.                                 ep += 16;       /* then skip rest of bitmask */
  315.                                 continue;       /*   and keep going */
  316.                         }
  317.                         return(FALSE);          /* else return false */
  318.  
  319.                 case CBRA:              /* start of tagged pattern */
  320.                         brastart[*ep++] = lp;   /* mark it */
  321.                         continue;               /* and go */
  322.  
  323.                 case CKET:              /* end of tagged pattern */
  324.                         bracend[*ep++] = lp;    /* mark it */
  325.                         continue;               /* and go */
  326.  
  327.                 case CBACK:
  328.                         bbeg = brastart[*ep];
  329.                         ct = bracend[*ep++] - bbeg;
  330.  
  331.                         if (memcmp(bbeg, lp, ct))
  332.                         {
  333.                                 lp += ct;
  334.                                 continue;
  335.                         }
  336.                         return(FALSE);
  337.  
  338.                 case CBACK|STAR:
  339.                         bbeg = brastart[*ep];
  340.                         ct = bracend[*ep++] - bbeg;
  341.                         curlp = lp;
  342.                         while(memcmp(bbeg, lp, ct))
  343.                                 lp += ct;
  344.  
  345.                         while(lp >= curlp)
  346.                         {
  347.                                 if (advance(lp, ep))
  348.                                         return(TRUE);
  349.                                 lp -= ct;
  350.                         }
  351.                         return(FALSE);
  352.  
  353.  
  354.                 case CDOT|STAR:         /* match .* */
  355.                         curlp = lp;             /* save closure start loc */
  356.                         while (*lp++);          /* match anything */
  357.                         goto star;              /* now look for followers */
  358.  
  359.                 case CCHR|STAR:         /* match <literal char>* */
  360.                         curlp = lp;             /* save closure start loc */
  361.                         while (*lp++ == *ep);   /* match many of that char */
  362.                         ep++;                   /* to start of next element */
  363.                         goto star;              /* match it and followers */
  364.  
  365.                 case CCL|STAR:          /* match [...]* */
  366.                         curlp = lp;             /* save closure start loc */
  367.                         do {
  368.                                 c = *lp++ & 0x7F;       /* match any in set */
  369.                         } while
  370.                                 (ep[c>>3] & bits[c & 07]);
  371.                         ep += 16;               /* skip past the set */
  372.                         goto star;              /* match followers */
  373.  
  374.                 star:           /* the recursion part of a * or + match */
  375.                         if (--lp == curlp)      /* 0 matches */
  376.                                 continue;
  377.  
  378.                         if (*ep == CCHR)
  379.                         {
  380.                                 c = ep[1];
  381.                                 do {
  382.                                         if (*lp != c)
  383.                                                 continue;
  384.                                         if (advance(lp, ep))
  385.                                                 return(TRUE);
  386.                                 } while
  387.                                         (lp-- > curlp);
  388.                                 return(FALSE);
  389.                         }
  390.  
  391.                         if (*ep == CBACK)
  392.                         {
  393.                                 c = *(brastart[ep[1]]);
  394.                                 do {
  395.                                         if (*lp != c)
  396.                                                 continue;
  397.                                         if (advance(lp, ep))
  398.                                                 return(TRUE);
  399.                                 } while
  400.                                         (lp-- > curlp);
  401.                                 return(FALSE);
  402.                         }
  403.  
  404.                         do {
  405.                                 if (lp == locs)
  406.                                         break;
  407.                                 if (advance(lp, ep))
  408.                                         return(TRUE);
  409.                         } while
  410.                                 (lp-- > curlp);
  411.                         return(FALSE);
  412.  
  413.                 default:
  414.                         fprintf(stderr, "sed: RE error, %o\n", *--ep);
  415.                 }
  416. }
  417.  
  418. static int substitute(ipc)
  419. /* perform s command */
  420. sedcmd  *ipc;                           /* ptr to s command struct */
  421. {
  422.         void dosub();                   /* for if we find a match */
  423.  
  424.         if (match(ipc->u.lhs, 0))               /* if no match */
  425.                 dosub(ipc->rhs);                /* perform it once */
  426.         else
  427.                 return(FALSE);                  /* command fails */
  428.  
  429.         if (ipc->flags.global)                  /* if global flag enabled */
  430.                 while(*loc2)                    /* cycle through possibles */
  431.                         if (match(ipc->u.lhs, 1))       /* found another */
  432.                                 dosub(ipc->rhs);        /* so substitute */
  433.                         else                            /* otherwise, */
  434.                                 break;                  /* we're done */
  435.         return(TRUE);                           /* we succeeded */
  436. }
  437.  
  438. static void dosub(rhsbuf)               /* uses linebuf, genbuf, spend */
  439. /* generate substituted right-hand side (of s command) */
  440. char    *rhsbuf;        /* where to put the result */
  441. {
  442.         register char   *lp, *sp, *rp;
  443.         int             c;
  444.         char            *place();
  445.  
  446.         /* copy linebuf to genbuf up to location  1 */
  447.         lp = linebuf; sp = genbuf;
  448.         while (lp < loc1) *sp++ = *lp++;
  449.  
  450.         for (rp = rhsbuf; c = *rp++; )
  451.         {
  452.                 if (c == '&')
  453.                 {
  454.                         sp = place(sp, loc1, loc2);
  455.                         continue;
  456.                 }
  457.                 else if (c & 0200 && (c &= 0177) >= '1' && c < MAXTAGS+'1')
  458.                 {
  459.                         sp = place(sp, brastart[c-'1'], bracend[c-'1']);
  460.                         continue;
  461.                 }
  462.                 *sp++ = c & 0177;
  463.                 if (sp >= genbuf + MAXBUF)
  464.                         fprintf(stderr, LTLMSG);
  465.         }
  466.         lp = loc2;
  467. /* MRY  loc2 = sp - genbuf + linebuf; */
  468.         loc2 = sp - (genbuf - linebuf);
  469.         while (*sp++ = *lp++)
  470.                 if (sp >= genbuf + MAXBUF)
  471.                         fprintf(stderr, LTLMSG);
  472.         lp = linebuf; sp = genbuf;
  473.         while (*lp++ = *sp++);
  474.         spend = lp-1;
  475. }
  476.  
  477. static char *place(asp, al1, al2)               /* uses genbuf */
  478. /* place chars at *al1...*(al1 - 1) at asp... in genbuf[] */
  479. register char   *asp, *al1, *al2;
  480. {
  481.         while (al1 < al2)
  482.         {
  483.                 *asp++ = *al1++;
  484.                 if (asp >= genbuf + MAXBUF)
  485.                         fprintf(stderr, LTLMSG);
  486.         }
  487.         return(asp);
  488. }
  489.  
  490. static void listto(p1, fp)
  491. /* write a hex dump expansion of *p1... to fp */
  492. register char   *p1;            /* the source */
  493. FILE            *fp;            /* output stream to write to */
  494. {
  495.         p1--;
  496.         while(*p1++)
  497.                 if (isprint(*p1))
  498.                         putc(*p1, fp);          /* pass it through */
  499.                 else
  500.                 {
  501.                         putc('\134', fp);               /* emit a backslash */
  502.                         switch(*p1)
  503.                         {
  504.                         case '\10':     putc('b', fp); break;   /* BS */
  505.                         case '\11':     putc('t', fp); break;   /* TAB */
  506. /* \11 was \9 --MRY */
  507.                         case '\12':     putc('n', fp); break;   /* NL */
  508.                         case '\15':     putc('r', fp); break;   /* CR */
  509.                         case '\33':     putc('e', fp); break;   /* ESC */
  510.                         default:        fprintf(fp, "%02x", *p1 & 0xFF);
  511.                         }
  512.                 }
  513.         putc('\n', fp);
  514. }
  515.  
  516. static void command(ipc)
  517. /* execute compiled command pointed at by ipc */
  518. sedcmd  *ipc;
  519. {
  520.         static int      didsub;                 /* true if last s succeeded */
  521.         static char     holdsp[MAXHOLD];        /* the hold space */
  522.         static char     *hspend = holdsp;       /* hold space end pointer */
  523.         register char   *p1, *p2, *p3;
  524.         register int    i;
  525.         char            *execp;
  526.  
  527.         switch(ipc->command)
  528.         {
  529.         case ACMD:              /* append */
  530.                 *aptr++ = ipc;
  531.                 if (aptr >= appends + MAXAPPENDS)
  532.                         fprintf(stderr,
  533.                                 "sed: too many appends after line %ld\n",
  534.                                 lnum);
  535.                 *aptr = 0;
  536.                 break;
  537.  
  538.         case CCMD:              /* change pattern space */
  539.                 delete = TRUE;
  540.                 if (!ipc->flags.inrange || lastline)
  541.                         printf("%s\n", ipc->u.lhs);
  542.                 break;
  543.  
  544.         case DCMD:              /* delete pattern space */
  545.                 delete++;
  546.                 break;
  547.  
  548.         case CDCMD:             /* delete a line in hold space */
  549.                 p1 = p2 = linebuf;
  550.                 while(*p1 != '\n')
  551.                         if (delete = (*p1++ == 0))
  552.                                 return;
  553.                 p1++;
  554.                 while(*p2++ = *p1++) continue;
  555.                 spend = p2-1;
  556.                 jump++;
  557.                 break;
  558.  
  559.         case EQCMD:             /* show current line number */
  560.                 fprintf(stdout, "%ld\n", lnum);
  561.                 break;
  562.  
  563.         case GCMD:              /* copy hold space to pattern space */
  564.                 p1 = linebuf;   p2 = holdsp;    while(*p1++ = *p2++);
  565.                 spend = p1-1;
  566.                 break;
  567.  
  568.         case CGCMD:             /* append hold space to pattern space */
  569.                 *spend++ = '\n';
  570.                 p1 = spend;     p2 = holdsp;
  571.                 while(*p1++ = *p2++)
  572.                         if (p1 >= linebuf + MAXBUF)
  573.                                 break;
  574.                 spend = p1-1;
  575.                 break;
  576.  
  577.         case HCMD:              /* copy pattern space to hold space */
  578.                 p1 = holdsp;    p2 = linebuf;   while(*p1++ = *p2++);
  579.                 hspend = p1-1;
  580.                 break;
  581.  
  582.         case CHCMD:             /* append pattern space to hold space */
  583.                 *hspend++ = '\n';
  584.                 p1 = hspend;    p2 = linebuf;
  585.                 while(*p1++ = *p2++)
  586.                         if (p1 >= holdsp + MAXBUF)
  587.                                 break;
  588.                 hspend = p1-1;
  589.                 break;
  590.  
  591.         case ICMD:              /* insert text */
  592.                 printf("%s\n", ipc->u.lhs);
  593.                 break;
  594.  
  595.         case BCMD:              /* branch to label */
  596.                 jump = TRUE;
  597.                 break;
  598.  
  599.         case LCMD:              /* list text */
  600.                 listto(linebuf, (ipc->fout != NULL)?ipc->fout:stdout); break;
  601.  
  602.         case NCMD:      /* read next line into pattern space */
  603.                 if (!nflag)
  604.                         puts(linebuf);  /* flush out the current line */
  605.                 if (aptr > appends)
  606.                         readout();      /* do pending a, r commands */
  607.                 if ((execp = getline(linebuf)) == BAD)
  608.                 {
  609.                         pending = ipc;
  610.                         delete = TRUE;
  611.                         break;
  612.                 }
  613.                 spend = execp;
  614.                 break;
  615.  
  616.         case CNCMD:     /* append next line to pattern space */
  617.                 if (aptr > appends)
  618.                         readout();
  619.                 *spend++ = '\n';
  620.                 if ((execp = getline(spend)) == BAD)
  621.                 {
  622.                         pending = ipc;
  623.                         delete = TRUE;
  624.                         break;
  625.                 }
  626.                 spend = execp;
  627.                 break;
  628.  
  629.         case PCMD:              /* print pattern space */
  630.                 puts(linebuf);
  631.                 break;
  632.  
  633.         case CPCMD:             /* print one line from pattern space */
  634.                 cpcom:          /* so s command can jump here */
  635.                 for(p1 = linebuf; *p1 != '\n' && *p1 != '\0'; )
  636.                         putc(*p1++, stdout);
  637.                 putc('\n', stdout);
  638.                 break;
  639.  
  640.         case QCMD:              /* quit the stream editor */
  641.                 if (!nflag)
  642.                         puts(linebuf);  /* flush out the current line */
  643.                 if (aptr > appends)
  644.                         readout();      /* do any pending a and r commands */
  645.                 exit(0);
  646.  
  647.         case RCMD:              /* read a file into the stream */
  648.                 *aptr++ = ipc;
  649.                 if (aptr >= appends + MAXAPPENDS)
  650.                         fprintf(stderr,
  651.                                 "sed: too many reads after line %ld\n",
  652.                                 lnum);
  653.                 *aptr = 0;
  654.                 break;
  655.  
  656.         case SCMD:              /* substitute RE */
  657.                 didsub = substitute(ipc);
  658.                 if (ipc->flags.print && didsub)
  659.                         if (ipc->flags.print == TRUE)
  660.                                 puts(linebuf);
  661.                         else
  662.                                 goto cpcom;
  663.                 if (didsub && ipc->fout)
  664.                         fprintf(ipc->fout, "%s\n", linebuf);
  665.                 break;
  666.  
  667.         case TCMD:              /* branch on last s successful */
  668.         case CTCMD:             /* branch on last s failed */
  669.                 if (didsub == (ipc->command == CTCMD))
  670.                         break;          /* no branch if last s failed, else */
  671.                 didsub = FALSE;
  672.                 jump = TRUE;            /*  set up to jump to assoc'd label */
  673.                 break;
  674.  
  675.         case CWCMD:             /* write one line from pattern space */
  676.                 for(p1 = linebuf; *p1 != '\n' && *p1 != '\0'; )
  677.                         putc(*p1++, ipc->fout);
  678.                 putc('\n', ipc->fout);
  679.                 break;
  680.  
  681.         case WCMD:              /* write pattern space to file */
  682.                 fprintf(ipc->fout, "%s\n", linebuf);
  683.                 break;
  684.  
  685.         case XCMD:              /* exchange pattern and hold spaces */
  686.                 p1 = linebuf;   p2 = genbuf;    while(*p2++ = *p1++) continue;
  687.                 p1 = holdsp;    p2 = linebuf;   while(*p2++ = *p1++) continue;
  688.                 spend = p2 - 1;
  689.                 p1 = genbuf;    p2 = holdsp;    while(*p2++ = *p1++) continue;
  690.                 hspend = p2 - 1;
  691.                 break;
  692.  
  693.         case YCMD:
  694.                 p1 = linebuf;   p2 = ipc->u.lhs;
  695.                 while(*p1 = p2[*p1])
  696.                         p1++;
  697.                 break;
  698.         }
  699. }
  700.  
  701. static char *getline(buf)
  702. /* get next line of text to be filtered */
  703. register char   *buf;           /* where to send the input */
  704. {
  705.         if (gets(buf) != NULL)
  706.         {
  707.                 lnum++;                 /* note that we got another line */
  708.                 while(*buf++);          /* find the end of the input */
  709.                 return(--buf);          /* return ptr to terminating null */
  710.         }
  711.         else
  712.         {
  713.                 if (eargc == 0)                 /* if no more args */
  714.                         lastline = TRUE;        /*    set a flag */
  715.                 return(BAD);
  716.         }
  717. }
  718.  
  719. static void readout()
  720. /* write file indicated by r command to output */
  721. {
  722.         register char   *p1;    /* character-fetching dummy */
  723.         register int    t;      /* hold input char or EOF */
  724.         FILE            *fi;    /* ptr to file to be read */
  725.  
  726.         aptr = appends - 1;     /* arrange for pre-increment to work right */
  727.         while(*++aptr)
  728.                 if ((*aptr)->command == ACMD)           /* process "a" cmd */
  729.                         printf("%s\n", (*aptr)->u.lhs);
  730.                 else                                    /* process "r" cmd */
  731.                 {
  732.                         if ((fi = fopen((*aptr)->u.lhs, "r")) == NULL)
  733.                                 continue;
  734.                         while((t = getc(fi)) != EOF)
  735.                                 putc((char) t, stdout);
  736.                         fclose(fi);
  737.                 }
  738.         aptr = appends;         /* reset the append ptr */
  739.         *aptr = 0;
  740. }
  741.  
  742. /* sedexec.c ends here */
  743.