home *** CD-ROM | disk | FTP | other *** search
/ Nebula / nebula.bin / SourceCode / Classes / FindManager / FindManager.m < prev    next >
Text File  |  1992-01-09  |  10KB  |  523 lines

  1. /* Generated by Interface Builder */
  2.  
  3. #import "FindManager.h"
  4. #import <objc/Object.h>
  5. #import <appkit/Application.h>
  6. #import <appkit/Panel.h>
  7. #import <appkit/Form.h>
  8. #import <appkit/Text.h>
  9. #import <appkit/Control.h>
  10. #import <appkit/Button.h>
  11. #import <streams/streams.h>
  12.  
  13. #import <string.h>
  14. #import <stdlib.h>
  15. #import <ctype.h>
  16. #import "regex.h"
  17.  
  18. static id instance = nil;
  19.  
  20. static char upcase[0400] =
  21. {000, 001, 002, 003, 004, 005, 006, 007,
  22.  010, 011, 012, 013, 014, 015, 016, 017,
  23.  020, 021, 022, 023, 024, 025, 026, 027,
  24.  030, 031, 032, 033, 034, 035, 036, 037,
  25.  040, 041, 042, 043, 044, 045, 046, 047,
  26.  050, 051, 052, 053, 054, 055, 056, 057,
  27.  060, 061, 062, 063, 064, 065, 066, 067,
  28.  070, 071, 072, 073, 074, 075, 076, 077,
  29.  0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
  30.  0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
  31.  0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
  32.  0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
  33.  0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
  34.  0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
  35.  0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
  36.  0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177,
  37.  0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
  38.  0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
  39.  0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
  40.  0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
  41.  0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
  42.  0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
  43.  0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
  44.  0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
  45.  0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
  46.  0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
  47.  0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
  48.  0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
  49.  0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
  50.  0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
  51.  0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
  52.  0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
  53. };
  54.  
  55. int search(const char *match, char *text, int start, int most, int matchCase);
  56.  
  57. @implementation FindManager
  58.  
  59. + new
  60. {
  61.     if((instance != nil) && [instance isKindOf:[FindManager class]])
  62.         return instance;
  63.     else
  64.          return (instance = [[FindManager alloc] init]);
  65. }
  66.  
  67. - init
  68. {
  69.     if(instance != nil)
  70.         return nil;
  71.     self = [super init];
  72.     instance = self;    
  73.     [NXApp loadNibSection:"FindManager.nib" owner:self withNames:NO];
  74.     
  75.     countType = line;
  76.     extent = all;
  77.     regex = NO;
  78.     matchCase = NO;
  79.     re_set_syntax(RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_CONTEXT_INDEP_OPS);
  80.     return self;
  81. }
  82.  
  83. - textDidEnd:textObject endChar:(unsigned short)whyEnd
  84. {
  85.     free(currentText);
  86.     currentText = NXCopyStringBuffer([findView stringValue]);
  87.  
  88.     return self;
  89. }
  90.  
  91. - (char *)currentText
  92. {
  93.     return currentText;
  94. }
  95.  
  96. - checkResponder
  97. {
  98.     id fr = [[NXApp mainWindow] firstResponder];
  99.     
  100.     if([fr isKindOf:[Text class]])
  101.         return fr;
  102.     else
  103.         return nil;
  104. }
  105.  
  106. - orderFrontFindPanel:sender
  107. {
  108.     [findPanel makeKeyAndOrderFront:self];
  109.     [findView setStringValue:currentText];
  110.     [findView selectTextAt:0];
  111.     return self;
  112. }
  113.  
  114. - orderFrontCountPanel:sender
  115. {
  116.     id text;
  117.     [countPanel makeKeyAndOrderFront:self];
  118.     
  119.     if((text =[self checkResponder]) == nil)
  120.         return self;
  121.     else
  122.     {    
  123.         NXSelPt start, end;
  124.         char buf[20];
  125.         
  126.         [text getSel:&start :&end];
  127.         
  128.         switch(countType)
  129.         {
  130.             case line :
  131.             {
  132.                 sprintf(buf, "%d", [text lineFromPosition:start.c1st]);
  133.                 if(start.c1st != end.c1st)
  134.                 {
  135.                     sprintf((buf + strlen(buf)), ":%d",
  136.                         [text lineFromPosition:end.c1st]);
  137.                 }
  138.                 break;
  139.             }
  140.             case character :
  141.             {
  142.                 sprintf(buf, "%d", start.cp);
  143.                 if(start.cp != end.cp)
  144.                 {
  145.                     sprintf((buf + strlen(buf)), ":%d", end.cp);
  146.                 }
  147.                 break;
  148.             }
  149.         }
  150.         [countView setStringValue:buf];
  151.         [countView selectText:self];
  152.     }
  153.  
  154.     return self;
  155. }
  156.  
  157. - enterSelection:sender
  158. {
  159.     id text;
  160.     NXSelPt start, end;
  161.     
  162.     if((text = [self checkResponder]) == nil)
  163.         return self;
  164.  
  165.     [text getSel:&start :&end];
  166.     if(start.cp != end.cp)
  167.     {
  168.         currentText = (char *)realloc(currentText, end.cp - start.cp + 1);
  169.         [text getSubstring:currentText start:start.cp length:end.cp - start.cp];
  170.         *(currentText + end.cp - start.cp) = '\0';
  171.         [findView setStringValue:currentText];
  172.     }
  173.     [findView selectText:self];
  174.  
  175.     return self;
  176. }
  177.  
  178. - replace:sender
  179. {    
  180.     return [self find:replace];
  181. }
  182.  
  183. - replaceAll:sender
  184. {
  185.     return [self find:rall];
  186. }
  187.  
  188. - setOptions:sender
  189. {
  190.     switch([sender selectedTag])
  191.     {
  192.         case 0 :
  193.             matchCase = ![sender state];
  194.             break;
  195.         case 1:
  196.             regex = [sender state];
  197.             break;
  198.         default:
  199.             break;
  200.     }
  201.     return self;
  202. }
  203.  
  204. - findNext:sender
  205. {
  206.     return [self find:next];
  207. }
  208.  
  209. - jumpToSelection:sender
  210. {
  211.     id text;
  212.     if((text =[self checkResponder]) == nil)
  213.         return self;
  214.     [text scrollSelToVisible];
  215.     return self;
  216. }
  217.  
  218. - findPrevious:sender
  219. {
  220.     return [self find:previous];
  221. }
  222.  
  223. - replaceAndFind:sender
  224. {
  225.     return [self find:(replace | next)];
  226. }
  227.  
  228. - find:(find_type)findTag
  229. {
  230.     id textO;
  231.     NXStream *stream;
  232.     
  233.     if((textO =[self checkResponder]) == nil)
  234.         return self;
  235.     else
  236.     {
  237.     
  238.     const char *replaceBuf;
  239.     NXSelPt start, end;
  240.     int len;
  241.     struct re_pattern_buffer buf;
  242.     char fastmap[(1 << BYTEWIDTH)];
  243.  
  244.  
  245.     currentText = (char *)[findView stringValueAt:0];
  246.     replaceBuf = [findView stringValueAt:1];
  247.     
  248.     if(findTag & replace)
  249.     {
  250.         [textO replaceSel:replaceBuf];
  251.     }
  252.     if(!(findTag & ~replace))
  253.         return self;
  254.         
  255.     if(regex)
  256.     {
  257.         buf.allocated = 40;
  258.         buf.buffer = (char *)malloc(buf.allocated);
  259.         buf.fastmap = fastmap;
  260.         if(!matchCase)
  261.             buf.translate = upcase;
  262.         else buf.translate = NULL;
  263.         re_compile_pattern(currentText, strlen(currentText), &buf);
  264.         re_compile_fastmap(&buf);
  265.     }
  266.     
  267.     len = [textO textLength];
  268.     if(len == 0)
  269.         return self;
  270.     [textO getSel:&start :&end];
  271.     stream = [textO stream];
  272.  
  273.  
  274.     
  275.     if(findTag & (next|previous))
  276.     {
  277.         int i, flen, wrapped = NO, found = NO;
  278.         int begin;
  279.         int most;
  280.         textStart = (char *)realloc(textStart, len);
  281.         NXRead(stream, textStart, len);
  282.         if(findTag & next)
  283.         {
  284.             begin = end.cp;
  285.             most = len - end.cp;
  286.         }
  287.         else
  288.         {
  289.             begin = start.cp - 1;
  290.             most = -start.cp + 1;
  291.             if(begin < 0)
  292.             {
  293.                 begin = len - 1;
  294.                 most = start.cp - len + 1;
  295.                 wrapped = YES;
  296.             }
  297.         }
  298.         
  299.         do
  300.         {
  301.             if(regex)
  302.             {
  303.                 i = re_search(&buf, textStart, len, begin, most, 0, &flen);
  304.             }
  305.             else
  306.             {
  307.                 i = search(currentText, textStart, begin, most, matchCase);
  308.                 flen = strlen(currentText);
  309.             }
  310.             if(i < 0)
  311.             {
  312.                 if(!wrapped)
  313.                 {    
  314.                     wrapped = YES;
  315.                     if(findTag & next)
  316.                     {
  317.                         begin = 0;
  318.                         most = end.cp;
  319.                     }
  320.                     else
  321.                     {
  322.                         begin = len - 1;
  323.                         most = start.cp - len + 1;
  324.                     }
  325.                 }
  326.                 else
  327.                 {
  328.                     if(!found)
  329.                     {
  330.                         [warningText setStringValue:"Not\nFound"];
  331.                     }
  332.                     return self;
  333.                 }
  334.             }
  335.             else
  336.             {
  337.                 if(!found)
  338.                     [warningText setStringValue:""];
  339.                 found = YES;
  340.                 [textO setSel:i:i + flen];
  341.                 [textO scrollSelToVisible];
  342.             }
  343.         } while(!found);
  344.     
  345.     }
  346.     
  347.     if(findTag & rall)
  348.     {
  349.         int begin = 0, most, i, flen, found = NO, offset;
  350.         int rlen = strlen(replaceBuf);
  351.  
  352.         if(extent != all)
  353.         {
  354.             offset = start.cp;
  355.             most = end.cp - start.cp - 1;
  356.             len = most;
  357.         }
  358.         else
  359.         {
  360.             offset = 0;
  361.             most = len;
  362.         }
  363.         if(most < 1)
  364.             return self;
  365.             
  366.         NXSeek(stream, offset, NX_FROMSTART);
  367.         textStart = (char *)realloc(textStart, most);
  368.         NXRead(stream, textStart, most);
  369.         
  370.         flen = strlen(currentText);
  371.         for(;;)
  372.         {
  373.             if(regex)
  374.             {
  375.                 i = re_search(&buf, textStart, len, begin, most, 0, &flen);
  376.             }
  377.             else
  378.             {
  379.                 i = search(currentText, textStart, begin, most, matchCase);
  380.             }
  381.             if((i < 0) || (i + flen) > len)
  382.             {
  383.                 if(!found)
  384.                     [warningText setStringValue:"Not\nFound"];
  385.                 return self;
  386.             }
  387.             else
  388.             {
  389.                 if(!found)
  390.                 {
  391.                     [warningText setStringValue:""];
  392.                     found = YES;
  393.                 }
  394.                 [textO setSel:i + offset :i + offset + flen];
  395.                 [textO replaceSel:replaceBuf];
  396.                 
  397.                 offset += rlen - flen;
  398.                 begin = i + flen;
  399.                 most = len - begin;
  400.                 if(most < 0)
  401.                 {
  402.                     if(!found)
  403.                     [warningText setStringValue:"Not\nFound"];
  404.                     return self;
  405.                 }
  406.             }
  407.         }
  408.     }
  409.             
  410.     return self;
  411.     }
  412. }
  413.  
  414. - jumpToCount:sender
  415. {
  416.     id text;
  417.     
  418.     if((text =[self checkResponder]) == nil)
  419.         return self;
  420.     else
  421.     {
  422.         char *test;
  423.         int end;
  424.         const char *buf = [countView stringValue];
  425.         int start = atoi(buf);
  426.         if((test = strchr(buf, ':')) != NULL)
  427.             end = atoi(test + 1);
  428.         else
  429.             end = start;
  430.         
  431.         switch(countType)
  432.         {
  433.         
  434.             case line :
  435.             {
  436.                 [text setSel:[text positionFromLine:start]
  437.                     :[text positionFromLine:end + 1]];
  438.                 break;
  439.             }
  440.             case character :
  441.             {
  442.                 [text setSel:start :end];
  443.                 break;
  444.             }
  445.         }
  446.     }
  447.     [countPanel orderOut:self];
  448.     [text scrollSelToVisible];
  449.     
  450.     return self;
  451. }
  452.  
  453. - setCountType:sender
  454. {
  455.     countType = [sender selectedTag];
  456.     return self;
  457. }
  458.  
  459. - setSearchExtent:sender
  460. {
  461.     extent = [sender selectedTag];
  462.     return self;
  463. }
  464.  
  465. int search(const char *match, char *text, int start, int most, int matchCase)
  466. {
  467.     int len, offset = 0;
  468.     int c, dir;
  469.     len = strlen(match);
  470.     if(most < 0)
  471.     {
  472.         c = len - 1;
  473.         dir = -1;
  474.     }
  475.     else
  476.     {
  477.         c = 0;
  478.         dir = 1;
  479.     }
  480.     offset = 0;
  481.  
  482.     if(abs(offset) > abs(most))
  483.         return -1;
  484.         
  485.     if(matchCase)
  486.     {
  487.         for(;;)
  488.         {
  489.             while(*(text + start + offset) != *(match + c))
  490.             {
  491.                 offset += dir;
  492.                 if(abs(offset) > abs(most))
  493.                     return -1;
  494.             }
  495.             if(!strncmp(text + start + offset - c, match, abs(len)))
  496.             {
  497.                 return start + offset - c;
  498.             }
  499.             offset += dir;
  500.         }
  501.     }
  502.     else
  503.     {
  504.         for(;;)
  505.         {
  506.             while(tolower(*(text + start + offset)) != tolower(*(match + c)))
  507.             {
  508.                 offset += dir;
  509.                 if(abs(offset) > abs(most))
  510.                     return -1;
  511.             }
  512.             if(!strncasecmp(text + start + offset - c, match, abs(len)))
  513.             {
  514.                 return start + offset - c;
  515.             }
  516.             offset += dir;
  517.         }
  518.     }
  519.     return -1;
  520. }
  521.  
  522. @end
  523.