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

  1. #define ABOUT    "usage: grep([flags],regular expression,input)\rgrep XFCN v3.1 by Greg Anderson 14 Sept 1989"
  2. /*
  3. | | grep 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 search string and the contents of a card/background
  12. | | field, grep returns every line from the input field that
  13. | | contains the search string.
  14. | |
  15. | | Standard regular expressions are supported.  See the file 'regexp.c'.
  16. | |
  17. | | Flags:
  18. | |
  19. | |        -i : ignore case while searching
  20. | |        -n : number each output line w/ its position in the input
  21. | |             If the 'n' is followed immediately by a number (e.g. '-n3'),
  22. | |             then each line number will be padded to that many
  23. | |             characters.  Padding is usually done with spaces, although
  24. | |             zeros may be specified printf-style (i.e., '-n03').
  25. | |        -c : display number of matches instead of output
  26. | |        -v : inverted search: lines that DON'T match are returned
  27. | |
  28. | | Non-UNIX flags:
  29. | |
  30. | |        -m : multiline match: indented lines are considered to be
  31. | |             part of the preceeding line.
  32. | |        -f : folded line match: lines that end with a backslash ("\")
  33. | |             are considered to be continued on the next line.
  34. | |
  35. | | Example:  Extracting a long, folded Cc: line from a mail message:
  36. | |
  37. | |        put grep("-fi","^Cc:",theMail) into cc
  38. | |
  39. | | or:          Removing all blank lines:
  40. | |
  41. | |        put grep("-v","^$",foo) into foo
  42. | |
  43. | |
  44. |*/
  45.  
  46. #include <MacTypes.h>
  47. #include <FileMgr.h>
  48. #include <SetUpA4.h>
  49. #include "HyperXCmd.h"
  50. #include "XCmdUtil.h"
  51. #include "regexp.h"
  52.  
  53. /*-----------------------------------------------------------------
  54. |  Global variables:
  55. -----------------------------------------------------------------*/
  56. char        padchar;
  57. int            spaces,
  58.             grep_line,
  59.             grep_matches;
  60.  
  61. /*-----------------------------------------------------------------
  62. |  Function types
  63. -----------------------------------------------------------------*/
  64.  pascal    void main();
  65.  void    grep();
  66.  char    searchline();
  67.  char    endsearch();
  68.  char    copyline();
  69.  void    copynumber();
  70.  char    advanceline();
  71.   
  72. /*-----------------------------------------------------------------
  73. |  This is the entry point to grep
  74. -----------------------------------------------------------------*/
  75. pascal void main (paramPtr)
  76.     XCmdBlockPtr paramPtr;
  77. {
  78.     char        *list;
  79.     int         i;
  80.     
  81.     /*
  82.     | |  Fix up LSC
  83.      */
  84.     RememberA0();
  85.     SetUpA4();
  86.     /*
  87.     | | Check for the propper number of parameters
  88.      */
  89.     if( paramPtr->paramCount == 0 )
  90.     {
  91.         ReturnMsg(paramPtr,ABOUT);
  92.         return;
  93.     }
  94.     if( (paramPtr->paramCount < 2) || (paramPtr->paramCount > 3) )
  95.     {
  96.         ReturnMsg(paramPtr,"Error in number of parameters.");
  97.         return;
  98.     }
  99.     /* 
  100.     | | Move all parameters to top of heap and protect them
  101.      */
  102.     for (i=0;i<paramPtr->paramCount;i++)
  103.     {
  104.         MoveHHi(paramPtr->params[i]);
  105.         HLock(paramPtr->params[i]);
  106.     }
  107.     /* 
  108.     | | Initialize global variables
  109.      */
  110.     padchar            = ' ';
  111.     spaces            = 0;
  112.     grep_line        = 0;
  113.     grep_matches    = 0;
  114.     regexp_flags    = 0;                /* From regexp.c        */
  115.     /*
  116.     | | Search through flags, if any were specified
  117.      */
  118.     list            = *(paramPtr->params[0]);
  119.     if( (paramPtr->paramCount == 3) )
  120.     {
  121.         while( *list )
  122.         {
  123.             switch( *list++ )
  124.             {
  125.             case 'v':    regexp_flags |= INVERT;
  126.                         break;
  127.             case 'i':    regexp_flags |= IGNORE;
  128.                         break;
  129.             case 'n':    regexp_flags |= NUMBER;
  130.                         while( (*list >= '0') && (*list <= '9') )
  131.                         {
  132.                             if( !spaces && (*list == '0') )
  133.                                 padchar = '0';
  134.                             spaces = spaces * 10 + (*list - '0');
  135.                             ++list;
  136.                         }
  137.                         break;
  138.             case 'c':    regexp_flags |= COUNT;
  139.                         break;
  140.             case 'm':    regexp_flags |= MULTILINE;
  141.                         break;
  142.             case 'f':
  143.             case 'M':    regexp_flags |= FOLDEDLINE;
  144.                         break;
  145.             }
  146.         }
  147.     }
  148.     /*
  149.     | | Do the xcmd
  150.      */
  151.     grep(paramPtr);
  152.     /*
  153.     | | Unprotect the parameters so they can be freed by HyperCard
  154.      */
  155.     for (i=0;i<paramPtr->paramCount;i++)
  156.         HUnlock(paramPtr->params[i]);
  157.     /*
  158.     | |  The last thing to do before exiting:
  159.      */
  160.     RestoreA4();
  161. }
  162.  
  163. /*-----------------------------------------------------------------
  164. |  Search for the specified pattern
  165. -----------------------------------------------------------------*/
  166. void grep(paramPtr)
  167.     XCmdBlockPtr paramPtr;
  168. {
  169.     Handle        tempBuf;
  170.     char        *searchstring,
  171.                 *end,
  172.                 *str,
  173.                 *in,
  174.                 *out;
  175.     int            i,
  176.                 regexpparam,
  177.                 textparam,
  178.                 searchlen;
  179.     long        handLen;
  180.     
  181.     regexpparam = (paramPtr->paramCount == 3);
  182.     textparam = regexpparam + 1;
  183.     /*
  184.     | |Create a temporary buffer the same size as the text buffer.
  185.      */
  186.     handLen = GetHandleSize(paramPtr->params[textparam]) + 100L;
  187.     tempBuf = NewHandle((long)handLen);
  188.     if( !tempBuf )
  189.     {
  190.         ReturnMsg(paramPtr,"Error allocating memory.");
  191.         return;
  192.     }
  193.     MoveHHi(tempBuf);
  194.     HLock(tempBuf);
  195.  
  196.     searchstring     = *(paramPtr->params[regexpparam]);
  197.     searchlen        = greplen(&searchstring);
  198.     in                = *(paramPtr->params[textparam]);
  199.     out                = *tempBuf;
  200.     
  201.     if( searchlen < 0 )
  202.     {
  203.         DisposHandle(tempBuf);
  204.         ReturnMsg(paramPtr,"Error in search string.");
  205.         return;
  206.     }
  207.         
  208.     while( searchline(searchstring,&in,&out) );
  209.     /*
  210.     | |  If the COUNT flag is set, then overwrite the output
  211.     | |  with the number of matches
  212.      */
  213.     if( regexp_flags & COUNT )
  214.     {
  215.         out = *tempBuf;
  216.         copynumber(grep_matches,&out);
  217.     }
  218.     *out = 0;
  219.     paramPtr->returnValue = tempBuf;
  220. }
  221.  
  222. /*-----------------------------------------------------------------
  223. |  Check if the current line contains the search pattern
  224. -----------------------------------------------------------------*/
  225. char searchline(searchstring,in,out)
  226.     char        *searchstring,
  227.                 **in,
  228.                 **out;
  229. {
  230.     char        *start,
  231.                 *end,
  232.                 **start_p    = &start,
  233.                 **end_p        = &end;
  234.     int            found;
  235.     
  236.     /*
  237.     | |  If there is nothing on the last line, then it is not a line.
  238.      */
  239.     if( **in == 0 ) return(0);
  240.     
  241.     ++grep_line;
  242.     if( regexp_flags & BEGINFLAG )    start_p    = 0;
  243.     if( regexp_flags & ENDFLAG )    end_p    = 0;
  244.     
  245.     found = find_regexp(searchstring,*in,start_p,end_p);
  246.  
  247.     return( endsearch(in,out,found) );
  248. }
  249.  
  250. /*-----------------------------------------------------------------
  251. | The search has ended:  if match == 1, then the current line has
  252. | a match on it.
  253. -----------------------------------------------------------------*/
  254. char endsearch(in,out,match)
  255.     char        **in,
  256.                 **out;
  257.     int            match;
  258. {
  259.     if( regexp_flags & INVERT )
  260.         match = !match;
  261.     
  262.     if( match )
  263.     {
  264.         ++grep_matches;
  265.         if( regexp_flags & NUMBER )
  266.         {
  267.             copynumber(grep_line,out);
  268.             *(*out-1) = ':';
  269.             *(*out)++ = ' ';
  270.         }
  271.         return( copyline(in,out) );
  272.     }
  273.     else
  274.         return( advanceline(in) );
  275. }
  276.  
  277. /*-----------------------------------------------------------------
  278. |  The pattern was not found on this line; advance pointer
  279. -----------------------------------------------------------------*/
  280. char advanceline(fieldptr)
  281.     char        **fieldptr;
  282. {
  283.     while( !end_of_line(*fieldptr) )
  284.         (*fieldptr)++;
  285.     
  286.     return( *(*fieldptr)++ );
  287. }
  288.  
  289. /*-----------------------------------------------------------------
  290. |  If a pattern is found, copy the line to the output buffer
  291. -----------------------------------------------------------------*/
  292. char copyline(fieldptr,outputptr)
  293.     char        **fieldptr,
  294.                 **outputptr;
  295. {
  296.     while( !end_of_line(*fieldptr) )
  297.     {
  298.         *(*outputptr)++ = *(*fieldptr)++;
  299.     }
  300.     *(*outputptr)++ = '\r';
  301.     return( *(*fieldptr)++ );
  302. }
  303.  
  304. /*-----------------------------------------------------------------
  305. |  Pad spaces before a number, if necessary.
  306. -----------------------------------------------------------------*/
  307. padspaces(number,n_spaces,out)
  308.     char        **out;
  309. {
  310.     int            n = 10,
  311.                 m = 1;
  312.     
  313.     while( m < n_spaces )
  314.     {
  315.         if( (number < n) || (m > 4) )
  316.             *(*out)++ = padchar;
  317.         n *= 10;
  318.         ++m;
  319.     }
  320. }
  321.  
  322. /*-----------------------------------------------------------------
  323. | Copy a number into the output buffer
  324. -----------------------------------------------------------------*/
  325. void copynumber(n,out)
  326.     int            n;
  327.     char        **out;
  328. {
  329.     char        temp[80],
  330.                 *ptr;
  331.     
  332.     padspaces(n,spaces,out);
  333.     
  334.     ptr = temp;
  335.     itoa(ptr,n);
  336.     copyline(&ptr,out);
  337. }
  338.  
  339. /*-----------------------------------------------------------------
  340. |  Count the number of characters on this line
  341. -----------------------------------------------------------------*/
  342. int lineLen(line)
  343.     char        *line;
  344. {
  345.     int            len = 0;
  346.     
  347.     while( !end_of_line(line) )
  348.     {
  349.         ++len;
  350.         ++line;
  351.     }
  352.     return(len);
  353. }
  354.