home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / HyperCard / reg_exp.XFCN / replace.c < prev    next >
C/C++ Source or Header  |  1989-09-18  |  7KB  |  306 lines

  1. #define ABOUT    "usage: rep([flags],regular expression,replacement string,input text)\rrep XFCN v2.1 by Greg Anderson 14 Sept 1989\r"
  2. /*
  3. | | replace XFCN:
  4. | |
  5. | | Greg Anderson
  6. | | 24 Kerr Hall
  7. | | Social Sciences Computing
  8. | | University of California, Santa Cruz
  9. | | sirkm@ssyx
  10. | |
  11. | | Given a regular expresion and a replacement string, the
  12. | | 'replace' XFCN replaces all strings in the source text
  13. | | that match the regular expression.
  14. | |
  15. | | Example:
  16. | |
  17. | |        put replace(reg exp,"replacement",bg fld "Info") into temp
  18. | |
  19. | |
  20. | | KNOWN BUGS:
  21. | |
  22. | | The resulting string cannot be more than 4K larger than the source
  23. | | string.
  24. |*/
  25.  
  26. #include <MacTypes.h>
  27. #include <FileMgr.h>
  28. #include <SetUpA4.h>
  29. #include "HyperXCmd.h"
  30. #include "XCmdUtil.h"
  31. #include "regexp.h"
  32.  
  33.  
  34. /*-----------------------------------------------------------------
  35. |  Function types
  36. -----------------------------------------------------------------*/
  37.  pascal    void main();
  38.  void    replace();
  39.  void    replacement();
  40.  char    searchline();
  41.  char    copyline();
  42.  char    advanceline();
  43.  
  44. /*-----------------------------------------------------------------
  45. |  This is the entry point to replace
  46. -----------------------------------------------------------------*/
  47. pascal void main(paramPtr)
  48.     XCmdBlockPtr paramPtr;
  49. {
  50.     char    *list;
  51.     int     i;
  52.     
  53.     /*
  54.     | |  Fix up LSC
  55.      */
  56.     RememberA0();
  57.     SetUpA4();
  58.     /*
  59.     | | Check for the propper number of parameters
  60.      */
  61.     if( (paramPtr->paramCount == 0) )
  62.     {
  63.         ReturnMsg(paramPtr,ABOUT);
  64.         return;
  65.     }
  66.     if( (paramPtr->paramCount < 3) || (paramPtr->paramCount > 4) )
  67.     {
  68.         ReturnMsg(paramPtr,"Error in number of parameters.");
  69.         return;
  70.     }
  71.  
  72.     /* 
  73.     | | Move all parameters to top of heap and protect them
  74.      */
  75.     for (i=0;i<paramPtr->paramCount;i++)
  76.     {
  77.         MoveHHi(paramPtr->params[i]);
  78.         HLock(paramPtr->params[i]);
  79.     }
  80.     /*
  81.     | | Search through flags, if any were specified
  82.      */
  83.        regexp_flags    = 0;                    /* From regexp.c        */
  84.     list            = *(paramPtr->params[0]);
  85.     if( (paramPtr->paramCount == 4) )
  86.     {
  87.         while( *list )
  88.         {
  89.             switch( *list++ )
  90.             {
  91.             case 'i':    regexp_flags |= IGNORE;
  92.                         break;
  93.             case 'm':    regexp_flags |= MULTILINE;
  94.                         break;
  95.             case 'f':    regexp_flags |= FOLDEDLINE;
  96.                         break;
  97.             case 'b':    regexp_flags |= NOBREAKS;
  98.                         break;
  99.             }
  100.         }
  101.     }
  102.     /*
  103.     | | Do the xcmd
  104.      */
  105.     replace(paramPtr);
  106.     
  107.     /*
  108.     | | Unprotect the parameters so they can be freed by HyperCard
  109.      */
  110.     for (i=0;i<paramPtr->paramCount;i++)
  111.         HUnlock(paramPtr->params[i]);
  112.     /*
  113.     | |  The last thing to do before exiting:
  114.      */
  115.     RestoreA4();
  116. }
  117.  
  118. /*-----------------------------------------------------------------
  119. |  Main replace loop
  120. -----------------------------------------------------------------*/
  121. void replace(paramPtr)
  122.     XCmdBlockPtr paramPtr;
  123. {
  124.     Handle        tempBuf;
  125.     char        *searchstring,
  126.                 *repstring,
  127.                 *in,
  128.                 *out;
  129.     int            i,
  130.                 regexpparam,
  131.                 replaceparam,
  132.                 textparam,
  133.                 searchlen;
  134.     long        handLen;
  135.     
  136.     regexpparam = (paramPtr->paramCount == 4);
  137.     replaceparam = regexpparam + 1;
  138.     textparam = replaceparam + 1;
  139.     /*
  140.     | |Create a temporary buffer about 4K larger than the input buffer.
  141.      */
  142.     handLen = GetHandleSize(paramPtr->params[textparam]) + 4200L;
  143.     tempBuf = NewHandle((long)handLen);
  144.     if( !tempBuf )
  145.     {
  146.         ReturnMsg(paramPtr,"Error allocating memory.");
  147.         return;
  148.     }
  149.     MoveHHi(tempBuf);
  150.     HLock(tempBuf);
  151.  
  152.     searchstring     = *(paramPtr->params[regexpparam]);
  153.     searchlen        = greplen(&searchstring);
  154.     repstring        = *(paramPtr->params[replaceparam]);
  155.     in                = *(paramPtr->params[textparam]);
  156.     out                = *tempBuf;
  157.  
  158.     if( searchlen < 0 )
  159.     {
  160.         DisposHandle(tempBuf);
  161.         ReturnMsg(paramPtr,"Error in search string.");
  162.         return;
  163.     }
  164.  
  165.     while( searchline(searchstring,repstring,&in,&out) );
  166.     
  167.     *out = 0;
  168.     paramPtr->returnValue = tempBuf;
  169. }
  170.  
  171. /*-----------------------------------------------------------------
  172. |  Check if the current line contains the search pattern
  173. -----------------------------------------------------------------*/
  174. char searchline(searchstring,rep,in,out)
  175.     char        *searchstring,
  176.                 *rep,
  177.                 **in,
  178.                 **out;
  179. {
  180.     char        *initial,
  181.                 *start,
  182.                 *end,
  183.                 **start_p    = &start,
  184.                 **end_p        = &end;
  185.     
  186.     /*
  187.     | |  If there is nothing on the last line, then it is not a line.
  188.      */
  189.     if( **in == 0 ) return(0);
  190.     
  191.     if( regexp_flags & BEGINFLAG )    start_p    = 0;
  192.     if( regexp_flags & ENDFLAG )    end_p    = 0;
  193.     
  194.     for(;;)
  195.     {
  196.         initial = *in;
  197.         start = initial;
  198.         if( find_regexp(searchstring,*in,start_p,end_p) )
  199.         {
  200.             /*
  201.             | |  Copy the beginning portion of the line (before
  202.             | |  the match) to the output buffer
  203.              */
  204.             while( initial < start )
  205.             {
  206.                 *(*out)++ = *(*in)++;
  207.                 ++initial;
  208.             }
  209.             /*
  210.             | |  Insert the replacement string into the output buffer
  211.              */
  212.             replacement(rep,out);
  213.             /*
  214.             | |  If this match was to the end of the line ('$' flag),
  215.             | |  then skip to the end of the input buffer line (which
  216.             | |  must be where the match ended) and copy an end-of-line
  217.             | |  marker to the output buffer.
  218.              */
  219.             if( !end_p )
  220.             {
  221.                 *(*out)++ = '\r';
  222.                 return( advanceline(in) );
  223.             }
  224.             /*
  225.             | |  Skip past the portion of the input that was replaced
  226.              */
  227.             *in = end;
  228.             /*
  229.             | |  If this match was from the beginning of the line
  230.             | |  ('^' flag), then copy everything in the input line
  231.             | |  after the match into the output buffer.
  232.              */
  233.             if( !start_p )
  234.                 return( copyline(in,out) );
  235.             /*
  236.             | |  If neither '^' nor '$' were specified, but the match
  237.             | |  still went to the end of the line, add an end-of-line
  238.             | |  character to the output buffer and exit.
  239.             | |
  240.             | |  If the pointer is not at the end of the line, then
  241.             | |  the rest of the input line will be checked for
  242.             | |  other possible matches.
  243.              */
  244.             if( end_of_line(end) )
  245.             {
  246.                 *(*out)++ = '\r';
  247.                 return( *(*in)++ );
  248.             }
  249.             /*
  250.             | |  Prevent null regular expressions from looping
  251.             | |  infinitely--after every null match, skip over
  252.             | |  one input character (copying it to the output buffer)
  253.              */
  254.             if( !(*searchstring) ) *(*out)++ = *(*in)++;
  255.         }
  256.         else
  257.             /*
  258.             | |  No matches on this line -- just copy the input
  259.             | |  line to the output buffer.
  260.              */
  261.             return( copyline(in,out) );
  262.     }
  263. }
  264.  
  265. /*-----------------------------------------------------------------
  266. |  If a pattern is not found, copy the line to the output buffer
  267. -----------------------------------------------------------------*/
  268. char copyline(fieldptr,outputptr)
  269.     char        **fieldptr,
  270.                 **outputptr;
  271. {
  272.     while( !end_of_line(*fieldptr) )
  273.     {
  274.         *(*outputptr)++ = *(*fieldptr)++;
  275.     }
  276.     *(*outputptr)++ = '\r';
  277.     return( *(*fieldptr)++ );
  278. }
  279.  
  280. /*-----------------------------------------------------------------
  281. |  The pattern was found & replaced to the end of the line; advance
  282. |  the pointer.
  283. -----------------------------------------------------------------*/
  284. char advanceline(fieldptr)
  285.     char        **fieldptr;
  286. {
  287.     while( !end_of_line(*fieldptr) )
  288.         (*fieldptr)++;
  289.     
  290.     return( *(*fieldptr)++ );
  291.  
  292. }
  293.  
  294. /*-----------------------------------------------------------------
  295. |  If a pattern is found, copy the replacement to the output buffer
  296. -----------------------------------------------------------------*/
  297. void replacement(repstring,outputptr)
  298.     char        *repstring,
  299.                 **outputptr;
  300. {
  301.     char        c;
  302.     
  303.     while( (c = *repstring++) )
  304.         *(*outputptr)++ = c;
  305. }
  306.