home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1994 June / NEBULA_SE.ISO / SourceCode / MiscKit / Projects / MiscFindPanel / SearchCategories / MiscSearchText.m < prev    next >
Encoding:
Text File  |  1994-03-23  |  9.2 KB  |  310 lines

  1. /*
  2.  *  Copyright (c) 1993 Christopher J. Kane.  All rights reserved.
  3.  *
  4.  *  This software is subject to the terms of the MiscKit license
  5.  *  agreement.  Refer to the license document included with the
  6.  *  MiscKit distribution for these terms.
  7.  *
  8.  *  Version: 1.2 (22 March 1994)
  9.  */
  10.  
  11. #import <misckit/MiscSearchText.h>
  12. #import <misckit/MiscTBMK.h>
  13. #import <misckit/regexpr.h>
  14.  
  15. @implementation Text (SearchText)
  16.  
  17. - (oneway void)makeSelectionVisible
  18. {
  19.   [self scrollSelToVisible];
  20. }
  21.  
  22. - (int)replaceAll:(const char *)pattern with:(const char *)replacement mode:(SearchMode)mode regexpr:(BOOL)regexpr cases:(BOOL)cases
  23. {
  24.   unsigned char fm[256], tr[256];
  25.   struct re_pattern_buffer rpat;
  26.   Misc_TBMKpattern lpat=NULL;
  27.   NXStream *in_strm=NULL, *out_strm=NULL;
  28.   int s1=0, e1=0, s2=0, e2=0, ret_val, plen, rlen, pos, searchTextMaxSize;
  29.  
  30.   if (sp0.cp<0 && mode!=TextEdgeToTextEdge)
  31.     return SEARCH_NO_SELECTION;
  32.   if (![self isEditable])
  33.     return SEARCH_CANNOT_WRITE;
  34.   switch (mode)
  35.     {
  36.       case TextEdgeToTextEdge:
  37.       case SelStartToSelStart:
  38.       case SelEndToSelEnd: s1 = 0; e1 = textLength; break;
  39.       case TextEdgeToSelStart: s1 = 0; e1 = sp0.cp; break;
  40.       case TextEdgeToSelEnd: s1 = 0; e1 = spN.cp; break;
  41.       case SelStartToSelEnd: s1 = sp0.cp; e1 = spN.cp-sp0.cp; break;
  42.       case SelStartToTextEdge: s1 = sp0.cp; e1 = textLength-sp0.cp; break;
  43.       case SelEndToTextEdge: s1 = spN.cp; e1 = textLength-spN.cp; break;
  44.       case SelEndToSelStart: s1 = 0; e1 = sp0.cp; s2 = spN.cp; e2 = textLength-spN.cp; break;
  45.       default: return SEARCH_INVALID_ARGUMENT;
  46.     }
  47.   searchTextMaxSize = s1+e1;
  48.   plen = strlen(pattern);
  49.   rlen = strlen(replacement);
  50.   if (regexpr)
  51.     {
  52.       char *str;
  53.       int i;
  54.       memset(&rpat, 0, sizeof(rpat));
  55.       for(i=256; i--;)
  56.         tr[i] = i;
  57.       if (!cases)
  58.         for(i='A'; i<='Z'; i++) tr[i] = i-'A'+'a';
  59.       rpat.translate = tr;
  60.       rpat.fastmap = fm;
  61.       str = re_compile_pattern((char *)pattern, plen, &rpat);
  62.       if (str!=NULL)
  63.         return (strcmp(str, "Out of memory")?SEARCH_INVALID_REGEXPR:SEARCH_INTERNAL_ERROR);
  64.     }
  65.   else
  66.     {
  67.       lpat = Misc_TBMKpattern_alloc(pattern, plen, 0, !cases);
  68.       if (lpat==NULL)
  69.         return SEARCH_INTERNAL_ERROR;
  70.     }
  71.   out_strm = NXOpenMemory(NULL, 0, NX_READWRITE);
  72.   in_strm = NXOpenMemory(NULL, 0, NX_READWRITE);
  73.   if (out_strm==NULL || in_strm==NULL)
  74.     {
  75.       ret_val = SEARCH_INTERNAL_ERROR;
  76.       goto exit;
  77.     }
  78.   [self writeText:in_strm];
  79.   NXSeek(in_strm, 0, NX_FROMSTART);
  80.   ret_val = 0;
  81.   NXWrite(out_strm, in_strm->buf_base, s1); /* get up to start of searching */
  82.   /* invariant for searching: in_strm->buf_base+s1+e1 is the position _after_ the last one searched */
  83.  start_searching:
  84.   if (regexpr)
  85.     {
  86.       while (!NXUserAborted() && e1>0 && (pos = re_search_pattern(&rpat, in_strm->buf_base, searchTextMaxSize, s1, e1, 0))>=0)
  87.         {
  88.           int len = re_match_pattern(&rpat, in_strm->buf_base, searchTextMaxSize, pos, 0);
  89.           if (len<0)
  90.             {
  91.               ret_val = SEARCH_INTERNAL_ERROR;
  92.               goto exit;
  93.             }
  94.           NXWrite(out_strm, in_strm->buf_base+s1, pos-s1);
  95.           NXWrite(out_strm, replacement, rlen);
  96.           e1 -= (pos-s1+len);
  97.           s1 = (pos+len);
  98.           ret_val++;
  99.         }
  100.       if (pos==-2)
  101.         {
  102.           ret_val = SEARCH_INTERNAL_ERROR;
  103.           goto exit;
  104.         }
  105.     }
  106.   else
  107.     {
  108.       while (!NXUserAborted() && e1>0 && Misc_TBMKsearch_memory(lpat, in_strm->buf_base+s1, e1, 0, &pos)>0)
  109.         {
  110.           NXWrite(out_strm, in_strm->buf_base+s1, pos);
  111.           NXWrite(out_strm, replacement, rlen);
  112.           s1 += (pos+plen);
  113.           e1 -= (pos+plen);
  114.           ret_val++;
  115.         }
  116.     }
  117.   if (NXUserAborted())
  118.     {
  119.       ret_val = SEARCH_ABORTED;
  120.       goto exit;
  121.     }
  122.   if (e1>0)
  123.     NXWrite(out_strm, in_strm->buf_base+s1, e1); /* get remainder of searched material */
  124.   if (e2!=0)
  125.     {
  126.       NXWrite(out_strm, in_strm->buf_base+s1+e1, s2-(s1+e1)); /* get gap */
  127.       s1 = s2;
  128.       e1 = e2;
  129.       s2 = e2 = 0;
  130.       goto start_searching;
  131.     }
  132.   NXWrite(out_strm, in_strm->buf_base+s1+e1, textLength-(s1+e1)); /* after searched to end */
  133.   NXSeek(out_strm, 0, NX_FROMSTART);
  134.   [self readText:out_strm];
  135.   [self setSel:0 :0];
  136.  exit:
  137.   Misc_TBMKpattern_free(&lpat);
  138.   if (in_strm!=NULL)
  139.     NXCloseMemory(in_strm, NX_FREEBUFFER);
  140.   if (out_strm!=NULL)
  141.     NXCloseMemory(out_strm, NX_FREEBUFFER);
  142.   return ret_val;
  143. }
  144.  
  145. - (oneway void)replaceSelection:(const char *)replacement
  146. {
  147.   if ([self isEditable])
  148.     [self replaceSel:replacement];
  149. }
  150.  
  151. - (int)searchFor:(const char *)pattern mode:(SearchMode)mode reverse:(BOOL)rev regexpr:(BOOL)regexpr cases:(BOOL)cases position:(out int *)pos size:(out int *)size
  152. {
  153.   unsigned char fm[256], tr[256];
  154.   struct re_pattern_buffer rpat;
  155.   Misc_TBMKpattern lpat=NULL;
  156.   NXStream *in_strm=NULL;
  157.   int s1=0, e1=0, s2=0, e2=0, ret_val, plen, p, position;
  158.  
  159.   if (sp0.cp<0 && mode!=TextEdgeToTextEdge)
  160.     return SEARCH_NO_SELECTION;
  161.   if (rev)
  162.     switch (mode)
  163.       {
  164.         case TextEdgeToSelStart: s1 = textLength-1; e1 = sp0.cp-textLength; break;
  165.         case TextEdgeToSelEnd: s1 = textLength-1; e1 = spN.cp-textLength; break;
  166.         case TextEdgeToTextEdge: s1 = textLength-1; e1 = -textLength; break;
  167.         case SelStartToSelEnd: s1 = sp0.cp-1; e1 = -sp0.cp+1; s2 = textLength-1; e2 = spN.cp-textLength+1; break;
  168.         case SelStartToTextEdge: s1 = sp0.cp-1; e1 = -sp0.cp+1; break;
  169.         case SelStartToSelStart: s1 = sp0.cp-1; e1 = -sp0.cp+1; s2 = textLength-1; e2 = sp0.cp-textLength+1; break;
  170.         case SelEndToTextEdge: s1 = spN.cp-1; e1 = -spN.cp+1; break;
  171.         case SelEndToSelStart: s1 = spN.cp-1; e1 = sp0.cp-spN.cp+1; break;
  172.         case SelEndToSelEnd: s1 = spN.cp-1; e1 = -spN.cp+1; s2 = textLength-1; e2 = spN.cp-textLength+1; break;
  173.         default: return SEARCH_INVALID_ARGUMENT;
  174.       }
  175.   else
  176.     switch (mode)
  177.       {
  178.         case TextEdgeToSelStart: s1 = 0; e1 = sp0.cp; break;
  179.         case TextEdgeToSelEnd: s1 = 0; e1 = spN.cp; break;
  180.         case TextEdgeToTextEdge: s1 = 0; e1 = textLength; break;
  181.         case SelStartToSelEnd: s1 = sp0.cp; e1 = spN.cp-sp0.cp; break;
  182.         case SelStartToTextEdge: s1 = sp0.cp; e1 = textLength-sp0.cp; break;
  183.         case SelStartToSelStart: s1 = sp0.cp; e1 = textLength-sp0.cp; s2 = 0; e2 = sp0.cp; break;
  184.         case SelEndToTextEdge: s1 = spN.cp; e1 = textLength-spN.cp;  break;
  185.         case SelEndToSelStart: s1 = spN.cp; e1 = textLength-spN.cp; s2 = 0; e2 = sp0.cp; break;
  186.         case SelEndToSelEnd: s1 = spN.cp; e1 = textLength-spN.cp; s2 = 0; e2 = spN.cp; break;
  187.         default: return SEARCH_INVALID_ARGUMENT;
  188.       }
  189.   plen = strlen(pattern);
  190.   if (regexpr)
  191.     {
  192.       char *str;
  193.       int i;
  194.       memset(&rpat, 0, sizeof(rpat));
  195.       for(i=256; i--;)
  196.         tr[i] = i;
  197.       if (!cases)
  198.         for(i='A'; i<='Z'; i++) tr[i] = i-'A'+'a';
  199.       rpat.translate = tr;
  200.       rpat.fastmap = fm;
  201.       str = re_compile_pattern((char *)pattern, plen, &rpat);
  202.       if (str!=NULL)
  203.         return (strcmp(str, "Out of memory")?SEARCH_INVALID_REGEXPR:SEARCH_INTERNAL_ERROR);
  204.     }
  205.   else
  206.     {
  207.       lpat = Misc_TBMKpattern_alloc(pattern, plen, rev, !cases);
  208.       if (lpat==NULL)
  209.         return SEARCH_INTERNAL_ERROR;
  210.     }
  211.   in_strm = NXOpenMemory(NULL, 0, NX_READWRITE);
  212.   if (in_strm==NULL)
  213.     {
  214.       ret_val = SEARCH_INTERNAL_ERROR;
  215.       goto exit;
  216.     }
  217.   [self writeText:in_strm];
  218.   NXSeek(in_strm, 0, NX_FROMSTART);
  219.   ret_val = 0;
  220.  start_searching:
  221.   if (NXUserAborted())
  222.     {
  223.       ret_val = SEARCH_ABORTED;
  224.       goto exit;
  225.     }
  226.   if (regexpr)
  227.     {
  228.       p = -1;
  229.       if (s1>=0)
  230.         p = re_search_pattern(&rpat, in_strm->buf_base, textLength, s1, e1, 0);
  231.       if (p==-1 && e2!=0)
  232.         {
  233.           s1 = s2;
  234.           e1 = e2;
  235.           s2 = e2 = 0;
  236.           goto start_searching;
  237.         }
  238.       if (p==-2)
  239.         {
  240.           ret_val = SEARCH_INTERNAL_ERROR;
  241.           goto exit;
  242.         }
  243.       if (p>-1)
  244.         {
  245.           *pos = p;
  246.           *size = re_match_pattern(&rpat, in_strm->buf_base, textLength, p, 0);
  247.           if (*size<0)
  248.             {
  249.               ret_val = SEARCH_INTERNAL_ERROR;
  250.               goto exit;
  251.             }
  252.           ret_val = 1;
  253.         }
  254.     }
  255.   else
  256.     {
  257.       p = 0;
  258.       if (s1>=0)
  259.         p = Misc_TBMKsearch_memory(lpat, in_strm->buf_base+s1, e1, 0, &position);
  260.       if (p<0)
  261.         {
  262.           ret_val = SEARCH_INTERNAL_ERROR;
  263.           goto exit;
  264.         }
  265.       if (p==0 && e2!=0)
  266.         {
  267.           s1 = s2;
  268.           e1 = e2;
  269.           s2 = e2 = 0;
  270.           goto start_searching;
  271.         }
  272.       if (p>0)
  273.         {
  274.           *pos = position+s1;
  275.           *size = plen;
  276.           ret_val = 1;
  277.         }
  278.    }
  279.  exit:
  280.   Misc_TBMKpattern_free(&lpat);
  281.   if (in_strm!=NULL)
  282.     NXCloseMemory(in_strm, NX_FREEBUFFER);
  283.   return ret_val;
  284. }
  285.  
  286. - (oneway void)selectTextFrom:(int)start to:(int)end
  287. {
  288.   if ([self isSelectable] && start<=end && 0<=start)
  289.     [self setSel:start :end];
  290. }
  291.  
  292. - (int)setRegExprSyntax:(int)syntax
  293. {
  294.   return re_set_syntax(syntax);
  295. }
  296.  
  297. - (void)writeSelectionToPasteboard:(in Pasteboard *)pboard asType:(in NXAtom)type
  298. {
  299.   char text[spN.cp-sp0.cp+1];
  300.   [self getSubstring:text start:sp0.cp length:spN.cp-sp0.cp];
  301.   text[spN.cp-sp0.cp] = '\0';
  302.   if (*text!='\0')
  303.     {
  304.       [pboard declareTypes:&type num:1 owner:NULL];
  305.       [pboard writeType:type data:text length:spN.cp-sp0.cp];
  306.     }
  307. }
  308.  
  309. @end
  310.