home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / communication / bbs / termv4.6 / extras / source / term-source.lha / Buffer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-18  |  27.9 KB  |  1,407 lines

  1. /*
  2. **    Buffer.c
  3. **
  4. **    Auxilary routines for text buffer/capture management.
  5. **
  6. **    Copyright © 1990-1996 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #ifndef _GLOBAL_H
  11. #include "Global.h"
  12. #endif
  13.  
  14.     /* Search string window gadgets. */
  15.  
  16. enum    {    GAD_STRING=1000,GAD_OK,GAD_CANCEL };
  17.  
  18.     /* Maximum size of an allocated line string. */
  19.  
  20. #define STRING_SIZE    (1 + 255 + 1)
  21.  
  22.     /* How many strings to include in a single puddle. */
  23.  
  24. #define STRING_COUNT    10
  25.  
  26.     /* The number of lines the buffer will grow. */
  27.  
  28. #define BUFFER_GROW    100
  29.  
  30.     /* Memory pool header. */
  31.  
  32. STATIC APTR        BufferPoolHeader;
  33.  
  34.     /* Word separator characters. */
  35.  
  36. STATIC BYTE WordSeparators[256] =
  37. {
  38.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  39.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  40.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  41.     0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,
  42.     1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  43.     0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,
  44.     1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  45.     0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,
  46.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  47.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  48.     0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  49.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  50.     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  51.     0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
  52.     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  53.     0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0
  54. };
  55.  
  56.     /* AllocString(STRPTR String,LONG Len):
  57.      *
  58.      *    Allocate space for a string, new pooled version.
  59.      */
  60.  
  61. STATIC STRPTR
  62. AllocString(STRPTR String,LONG Len)
  63. {
  64.     STRPTR Mem;
  65.  
  66.     if(Len > 255)
  67.         Len = 255;
  68.  
  69.     if(Mem = (STRPTR)AsmAllocPooled(BufferPoolHeader,1 + Len + 1,SysBase))
  70.     {
  71.         *Mem++ = Len;
  72.  
  73.         if(Len)
  74.             CopyMem(String,Mem,Len);
  75.  
  76.         Mem[Len] = 0;
  77.  
  78.         return((STRPTR)Mem);
  79.     }
  80.     else
  81.         return(NULL);
  82. }
  83.  
  84.     /* FreeString(STRPTR String):
  85.      *
  86.      *    Free the space occupied by a string, new pooled version.
  87.      */
  88.  
  89. STATIC VOID
  90. FreeString(STRPTR String)
  91. {
  92.     AsmFreePooled(BufferPoolHeader,&String[-1],1 + String[-1] + 1,SysBase);
  93. }
  94.  
  95.     /* AddLine(STRPTR Line,LONG Size):
  96.      *
  97.      *    Add a line to the display buffer.
  98.      */
  99.  
  100. VOID
  101. AddLine(register STRPTR Line,register LONG Size)
  102. {
  103.         /* Are we still to update the buffer contents? */
  104.  
  105.     if(!BufferClosed)
  106.     {
  107.             /* Is the buffer array initialized? */
  108.  
  109.         if(BufferLines)
  110.         {
  111.             ULONG Signals = 0;
  112.  
  113.                 /* Pick up the global access semaphore
  114.                  * (two tasks are sharing the data).
  115.                  */
  116.  
  117.             ObtainSemaphore(BufferSemaphore);
  118.  
  119.                 /* Check for limit. */
  120.  
  121.             if(Config -> CaptureConfig -> MaxBufferSize && BufferSpace >= Config -> CaptureConfig -> MaxBufferSize)
  122.             {
  123.                 register LONG i;
  124.  
  125.                 BufferSpace -= BufferLines[0][-1];
  126.  
  127.                 FreeString(BufferLines[0]);
  128.  
  129.                 for(i = 1 ; i < MaxLines ; i++)
  130.                     BufferLines[i - 1] = BufferLines[i];
  131.  
  132.                 Lines--;
  133.  
  134.                     /* Tell the buffer task to
  135.                      * refresh the display.
  136.                      */
  137.  
  138.                 Signals = SIG_MOVEUP;
  139.             }
  140.             else
  141.             {
  142.                     /* We've reached the last line in the buffer. */
  143.  
  144.                 if(Lines == MaxLines)
  145.                 {
  146.                     STRPTR *MoreBuffer;
  147.  
  148.                         /* Allocate space for some more lines. */
  149.  
  150.                     if(MoreBuffer = (STRPTR *)AllocVecPooled((MaxLines + BUFFER_GROW) * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR))
  151.                     {
  152.                         register LONG i;
  153.  
  154.                         BufferChanged = TRUE;
  155.  
  156.                             /* Copy the old lines to the new
  157.                              * buffer.
  158.                              */
  159.  
  160.                         for(i = 0 ; i < Lines ; i++)
  161.                             MoreBuffer[i] = BufferLines[i];
  162.  
  163.                             /* Free the old lines. */
  164.  
  165.                         FreeVecPooled(BufferLines);
  166.  
  167.                             /* Set the new buffer. */
  168.  
  169.                         MaxLines += BUFFER_GROW;
  170.  
  171.                         BufferLines = MoreBuffer;
  172.                     }
  173.                     else
  174.                     {
  175.                         BufferChanged = TRUE;
  176.  
  177.                             /* We couldn't get enough memory
  178.                              * to extend the number of lines
  179.                              * in the buffer, so we'll have
  180.                              * to wrap the contents of the
  181.                              * buffer around.
  182.                              */
  183.  
  184.                         if(Lines)
  185.                         {
  186.                             register LONG i;
  187.  
  188.                             BufferSpace -= BufferLines[0][-1];
  189.  
  190.                             FreeString(BufferLines[0]);
  191.  
  192.                             for(i = 1 ; i < MaxLines ; i++)
  193.                                 BufferLines[i - 1] = BufferLines[i];
  194.  
  195.                             Lines--;
  196.  
  197.                                 /* Tell the buffer task to
  198.                                  * refresh the display.
  199.                                  */
  200.  
  201.                             Signals = SIG_MOVEUP;
  202.                         }
  203.                     }
  204.                 }
  205.             }
  206.  
  207.                 /* Allocate a new line and copy the buffer contents
  208.                  * into it.
  209.                  */
  210.  
  211.             if(BufferLines[Lines] = AllocString(Line,Size))
  212.             {
  213.                 BufferChanged = TRUE;
  214.  
  215.                 Lines++;
  216.  
  217.                 BufferSpace += Size;
  218.             }
  219.  
  220.             ReleaseSemaphore(BufferSemaphore);
  221.  
  222.                 /* Tell the buffer tasks to update the displays. */
  223.  
  224.             if(!Signals)
  225.                 Signals = SIG_UPDATE;
  226.  
  227.             NotifyBuffer(&BufferTaskSemaphore,&BufferInfoData,Signals);
  228.             NotifyBuffer(&ReviewTaskSemaphore,&ReviewInfoData,Signals);
  229.         }
  230.     }
  231. }
  232.  
  233.     /* DeleteBuffer():
  234.      *
  235.      *    Delete buffer resources.
  236.      */
  237.  
  238. VOID
  239. DeleteBuffer()
  240. {
  241.     FreeVecPooled(BufferLines);
  242.     BufferLines = NULL;
  243.  
  244.     if(BufferPoolHeader)
  245.     {
  246.         AsmDeletePool(BufferPoolHeader,SysBase);
  247.  
  248.         BufferPoolHeader = NULL;
  249.     }
  250.  
  251.     FreeVecPooled(BufferSemaphore);
  252.     BufferSemaphore = NULL;
  253. }
  254.  
  255.     /* CreateBuffer():
  256.      *
  257.      *    Allocate buffer resources.
  258.      */
  259.  
  260. BOOL
  261. CreateBuffer()
  262. {
  263.     if(BufferLines = (STRPTR *)AllocVecPooled(MaxLines * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC))
  264.     {
  265.         if(BufferSemaphore = (struct SignalSemaphore *)AllocVecPooled(sizeof(struct SignalSemaphore),MEMF_ANY | MEMF_PUBLIC))
  266.         {
  267.             InitSemaphore(BufferSemaphore);
  268.  
  269.                 /* Create a memory pool header if possible. */
  270.  
  271.             if(BufferPoolHeader = AsmCreatePool(MEMF_ANY | MEMF_PUBLIC,STRING_SIZE * STRING_COUNT,STRING_SIZE * STRING_COUNT,SysBase))
  272.                 return(TRUE);
  273.         }
  274.  
  275.         FreeVecPooled(BufferLines);
  276.  
  277.         BufferLines = NULL;
  278.     }
  279.  
  280.     return(FALSE);
  281. }
  282.  
  283.     /* FreeBuffer():
  284.      *
  285.      *    Release the contents of the text buffer.
  286.      */
  287.  
  288. VOID
  289. FreeBuffer()
  290. {
  291.         /* Free the contents of the display buffer. */
  292.  
  293.     if(BufferLines)
  294.     {
  295.         APTR NewPoolHeader;
  296.  
  297.         ObtainSemaphore(BufferSemaphore);
  298.  
  299.             /* If a new pool header is available, free the old
  300.              * pool and replace it with the new pool.
  301.              */
  302.  
  303.         if(NewPoolHeader = AsmCreatePool(MEMF_ANY | MEMF_PUBLIC,STRING_SIZE * STRING_COUNT,STRING_SIZE * STRING_COUNT,SysBase))
  304.         {
  305.             AsmDeletePool(BufferPoolHeader,SysBase);
  306.  
  307.             BufferPoolHeader = NewPoolHeader;
  308.         }
  309.         else
  310.         {
  311.             LONG i;
  312.  
  313.             for(i = 0 ; i < Lines ; i++)
  314.             {
  315.                 if(BufferLines[i])
  316.                     FreeString(BufferLines[i]);
  317.             }
  318.         }
  319.  
  320.         FreeVecPooled(BufferLines);
  321.  
  322.         Lines = 0;
  323.  
  324.         MaxLines = BUFFER_GROW;
  325.  
  326.         BufferLines = (STRPTR *)AllocVecPooled(MaxLines * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR);
  327.  
  328.         ReleaseSemaphore(BufferSemaphore);
  329.  
  330.         NotifyBuffer(&BufferTaskSemaphore,&BufferInfoData,SIG_UPDATE);
  331.         NotifyBuffer(&ReviewTaskSemaphore,&ReviewInfoData,SIG_UPDATE);
  332.     }
  333.  
  334.     BufferSpace = 0;
  335.  
  336.     BufferChanged = FALSE;
  337. }
  338.  
  339.     /* DeleteSearchInfo(struct SearchInfo *Info):
  340.      *
  341.      *    Free buffer allocated by CreateSearchInfo().
  342.      */
  343.  
  344. VOID
  345. DeleteSearchInfo(struct SearchInfo *Info)
  346. {
  347.     FreeVecPooled(Info);
  348. }
  349.  
  350.     /* CreateSearchInfo(STRPTR Pattern):
  351.      *
  352.      *    Create auxilary data required by SearchTextBuffer().
  353.      */
  354.  
  355. struct SearchInfo *
  356. CreateSearchInfo(STRPTR Pattern,BOOL Forward,BOOL IgnoreCase,BOOL WholeWords)
  357. {
  358.     struct SearchInfo *Info;
  359.  
  360.         /* Allocate the buffer. */
  361.  
  362.     if(Info = (struct SearchInfo *)AllocVecPooled(sizeof(struct SearchInfo),MEMF_ANY | MEMF_PUBLIC))
  363.     {
  364.         LONG i;
  365.  
  366.             /* Determine pattern width. */
  367.  
  368.         Info -> PatternWidth    = strlen(Pattern);
  369.         Info -> IgnoreCase    = IgnoreCase;
  370.  
  371.         if(Info -> PatternWidth == 1)
  372.         {
  373.             if(WordSeparators[Pattern[0]])
  374.                 WholeWords = FALSE;
  375.         }
  376.  
  377.         Info -> WholeWords = WholeWords;
  378.  
  379.             /* Turn the pattern into upper case characters. */
  380.  
  381.         if(IgnoreCase)
  382.         {
  383.             for(i = 0 ; i <= Info -> PatternWidth ; i++)
  384.                 Info -> Pattern[i] = ToUpper(Pattern[i]);
  385.         }
  386.         else
  387.         {
  388.             for(i = 0 ; i <= Info -> PatternWidth ; i++)
  389.                 Info -> Pattern[i] = Pattern[i];
  390.         }
  391.  
  392.             /* Fill the entire range with the maximum pattern width. */
  393.  
  394.         for(i = 0 ; i < 256 ; i++)
  395.             Info -> Distance[i] = Info -> PatternWidth;
  396.  
  397.             /* Fill in the matching distances. */
  398.  
  399.         if(Forward)
  400.         {
  401.             for(i = 0 ; i < Info -> PatternWidth - 1 ; i++)
  402.                 Info -> Distance[Info -> Pattern[i]] = Info -> PatternWidth - 1 - i;
  403.         }
  404.         else
  405.         {
  406.             for(i = Info -> PatternWidth - 1 ; i > 0 ; i--)
  407.                 Info -> Distance[Info -> Pattern[i]] = i;
  408.         }
  409.  
  410.             /* Restart from scratch. */
  411.  
  412.         Info -> FoundY    = -1;
  413.         Info -> Forward    = Forward;
  414.     }
  415.  
  416.     return(Info);
  417. }
  418.  
  419.     /* SearchTextBuffer():
  420.      *
  421.      *    String search function, based on the Boyer-Moore search
  422.      *    algorithm.
  423.      */
  424.  
  425. LONG
  426. SearchTextBuffer(struct SearchInfo *Info)
  427. {
  428.     if(BufferLines)
  429.     {
  430.         UBYTE    *Distance,
  431.             *Pattern;
  432.         LONG    LineWidth,
  433.             PatternWidth;
  434.         STRPTR    Line;
  435.  
  436.         LONG    i;
  437.         LONG    SearchPosition,PatternIndex,LineIndex,LastSearchPosition;
  438.  
  439.             /* Extract the relevant data. */
  440.  
  441.         Distance    = Info -> Distance;
  442.         Pattern        = Info -> Pattern;
  443.         PatternWidth    = Info -> PatternWidth;
  444.  
  445.         if(Info -> WholeWords)
  446.         {
  447.                 /* Which direction are we to search? */
  448.  
  449.             if(Info -> IgnoreCase)
  450.             {
  451.                 if(Info -> Forward)
  452.                 {
  453.                         /* Update the search positions. */
  454.  
  455.                     if(Info -> FoundY == -1)
  456.                     {
  457.                         Info -> FoundX        = 0;
  458.                         Info -> FoundY        = 0;
  459.                         LastSearchPosition    = 0;
  460.                     }
  461.                     else
  462.                     {
  463.                             /* Proceed to the next line. */
  464.  
  465.                         if(!(LastSearchPosition = Info -> Index))
  466.                             Info -> FoundY = (Info -> FoundY + 1) % Lines;
  467.                     }
  468.  
  469.                         /* Run down the buffer. */
  470.  
  471.                     for(i = Info -> FoundY ; i < Lines ; i++)
  472.                     {
  473.                         Line = BufferLines[i];
  474.  
  475.                             /* Is there anything to search for? */
  476.  
  477.                         if((LineWidth = Line[-1]) >= PatternWidth)
  478.                         {
  479.                                 /* Where are we to start searching? */
  480.  
  481.                             if(LastSearchPosition)
  482.                                 SearchPosition = LastSearchPosition;
  483.                             else
  484.                                 SearchPosition = PatternWidth;
  485.  
  486.                             do
  487.                             {
  488.                                     /* How many line characters
  489.                                      * match the pattern?
  490.                                      */
  491.  
  492.                                 PatternIndex    = PatternWidth - 1;
  493.                                 LineIndex    = SearchPosition - 1;
  494.  
  495.                                 while(PatternIndex >= 0 && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  496.                                 {
  497.                                     LineIndex--;
  498.                                     PatternIndex--;
  499.                                 }
  500.  
  501.                                     /* Update the line search index
  502.                                      * for subsequent searches.
  503.                                      */
  504.  
  505.                                 SearchPosition += Distance[ToUpper(Line[SearchPosition - 1])];
  506.  
  507.                                     /* Found the pattern? */
  508.  
  509.                                 if(PatternIndex < 0)
  510.                                 {
  511.                                     LONG X = LineIndex + 1;
  512.  
  513.                                     if(X)
  514.                                     {
  515.                                         if(!WordSeparators[Line[X - 1]])
  516.                                             continue;
  517.                                         else
  518.                                         {
  519.                                             if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  520.                                                 continue;
  521.                                         }
  522.                                     }
  523.                                     else
  524.                                     {
  525.                                         if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  526.                                             continue;
  527.                                     }
  528.  
  529.                                         /* Store the position. */
  530.  
  531.                                     Info -> FoundX    = LineIndex + 1;
  532.                                     Info -> FoundY    = i;
  533.  
  534.                                         /* Remember column to start
  535.                                          * next search attempt at.
  536.                                          */
  537.  
  538.                                     if(SearchPosition <= LineWidth)
  539.                                         Info -> Index = SearchPosition;
  540.                                     else
  541.                                         Info -> Index = 0;
  542.  
  543.                                     return(i);
  544.                                 }
  545.                             }
  546.                             while(SearchPosition <= LineWidth);
  547.                         }
  548.  
  549.                             /* Reset search column. */
  550.  
  551.                         LastSearchPosition = 0;
  552.                     }
  553.                 }
  554.                 else
  555.                 {
  556.                         /* Update the search positions. */
  557.  
  558.                     if(Info -> FoundY == -1)
  559.                     {
  560.                         Info -> FoundX        = 0;
  561.                         Info -> FoundY        = Lines - 1;
  562.                         LastSearchPosition    = 0;
  563.                     }
  564.                     else
  565.                     {
  566.                         if((LastSearchPosition = Info -> Index) < 1)
  567.                         {
  568.                             if(Info -> FoundY)
  569.                                 Info -> FoundY--;
  570.                             else
  571.                                 Info -> FoundY = Lines - 1;
  572.                         }
  573.                     }
  574.  
  575.                         /* Run down the buffer. */
  576.  
  577.                     for(i = Info -> FoundY ; i >= 0 ; i--)
  578.                     {
  579.                         Line = BufferLines[i];
  580.  
  581.                             /* Is there anything to search for? */
  582.  
  583.                         if((LineWidth = Line[-1]) >= PatternWidth)
  584.                         {
  585.                                 /* Cast the magic spell of Boyer-Moore... */
  586.  
  587.                             if(LastSearchPosition < 1)
  588.                                 SearchPosition = LineWidth - (PatternWidth - 1);
  589.                             else
  590.                                 SearchPosition = LastSearchPosition;
  591.  
  592.                             do
  593.                             {
  594.                                 PatternIndex = 0;
  595.                                 LineIndex = SearchPosition - 1;
  596.  
  597.                                 while(PatternIndex < PatternWidth && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  598.                                 {
  599.                                     LineIndex++;
  600.                                     PatternIndex++;
  601.                                 }
  602.  
  603.                                 SearchPosition -= Distance[ToUpper(Line[SearchPosition - 1])];
  604.  
  605.                                 if(PatternIndex == PatternWidth)
  606.                                 {
  607.                                     LONG X = LineIndex - PatternWidth;
  608.  
  609.                                     if(X)
  610.                                     {
  611.                                         if(!WordSeparators[Line[X - 1]])
  612.                                             continue;
  613.                                         else
  614.                                         {
  615.                                             if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  616.                                                 continue;
  617.                                         }
  618.                                     }
  619.                                     else
  620.                                     {
  621.                                         if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  622.                                             continue;
  623.                                     }
  624.  
  625.                                     Info -> FoundX    = LineIndex - PatternWidth;
  626.                                     Info -> FoundY    = i;
  627.                                     Info -> Index    = SearchPosition;
  628.  
  629.                                     return(i);
  630.                                 }
  631.                             }
  632.                             while(SearchPosition > 0);
  633.                         }
  634.  
  635.                         LastSearchPosition = 0;
  636.                     }
  637.                 }
  638.             }
  639.             else
  640.             {
  641.                 if(Info -> Forward)
  642.                 {
  643.                         /* Update the search positions. */
  644.  
  645.                     if(Info -> FoundY == -1)
  646.                     {
  647.                         Info -> FoundX        = 0;
  648.                         Info -> FoundY        = 0;
  649.                         LastSearchPosition    = 0;
  650.                     }
  651.                     else
  652.                     {
  653.                             /* Proceed to the next line. */
  654.  
  655.                         if(!(LastSearchPosition = Info -> Index))
  656.                             Info -> FoundY = (Info -> FoundY + 1) % Lines;
  657.                     }
  658.  
  659.                         /* Run down the buffer. */
  660.  
  661.                     for(i = Info -> FoundY ; i < Lines ; i++)
  662.                     {
  663.                         Line = BufferLines[i];
  664.  
  665.                             /* Is there anything to search for? */
  666.  
  667.                         if((LineWidth = Line[-1]) >= PatternWidth)
  668.                         {
  669.                                 /* Where are we to start searching? */
  670.  
  671.                             if(LastSearchPosition)
  672.                                 SearchPosition = LastSearchPosition;
  673.                             else
  674.                                 SearchPosition = PatternWidth;
  675.  
  676.                             do
  677.                             {
  678.                                     /* How many line characters
  679.                                      * match the pattern?
  680.                                      */
  681.  
  682.                                 PatternIndex    = PatternWidth - 1;
  683.                                 LineIndex    = SearchPosition - 1;
  684.  
  685.                                 while(PatternIndex >= 0 && Pattern[PatternIndex] == Line[LineIndex])
  686.                                 {
  687.                                     LineIndex--;
  688.                                     PatternIndex--;
  689.                                 }
  690.  
  691.                                     /* Update the line search index
  692.                                      * for subsequent searches.
  693.                                      */
  694.  
  695.                                 SearchPosition += Distance[Line[SearchPosition - 1]];
  696.  
  697.                                     /* Found the pattern? */
  698.  
  699.                                 if(PatternIndex < 0)
  700.                                 {
  701.                                     LONG X = LineIndex + 1;
  702.  
  703.                                     if(X)
  704.                                     {
  705.                                         if(!WordSeparators[Line[X - 1]])
  706.                                             continue;
  707.                                         else
  708.                                         {
  709.                                             if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  710.                                                 continue;
  711.                                         }
  712.                                     }
  713.                                     else
  714.                                     {
  715.                                         if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  716.                                             continue;
  717.                                     }
  718.  
  719.                                         /* Store the position. */
  720.  
  721.                                     Info -> FoundX    = LineIndex + 1;
  722.                                     Info -> FoundY    = i;
  723.  
  724.                                         /* Remember column to start
  725.                                          * next search attempt at.
  726.                                          */
  727.  
  728.                                     if(SearchPosition <= LineWidth)
  729.                                         Info -> Index = SearchPosition;
  730.                                     else
  731.                                         Info -> Index = 0;
  732.  
  733.                                     return(i);
  734.                                 }
  735.                             }
  736.                             while(SearchPosition <= LineWidth);
  737.                         }
  738.  
  739.                             /* Reset search column. */
  740.  
  741.                         LastSearchPosition = 0;
  742.                     }
  743.                 }
  744.                 else
  745.                 {
  746.                         /* Update the search positions. */
  747.  
  748.                     if(Info -> FoundY == -1)
  749.                     {
  750.                         Info -> FoundX        = 0;
  751.                         Info -> FoundY        = Lines - 1;
  752.                         LastSearchPosition    = 0;
  753.                     }
  754.                     else
  755.                     {
  756.                         if((LastSearchPosition = Info -> Index) < 1)
  757.                         {
  758.                             if(Info -> FoundY)
  759.                                 Info -> FoundY--;
  760.                             else
  761.                                 Info -> FoundY = Lines - 1;
  762.                         }
  763.                     }
  764.  
  765.                         /* Run down the buffer. */
  766.  
  767.                     for(i = Info -> FoundY ; i >= 0 ; i--)
  768.                     {
  769.                         Line = BufferLines[i];
  770.  
  771.                             /* Is there anything to search for? */
  772.  
  773.                         if((LineWidth = Line[-1]) >= PatternWidth)
  774.                         {
  775.                                 /* Cast the magic spell of Boyer-Moore... */
  776.  
  777.                             if(LastSearchPosition < 1)
  778.                                 SearchPosition = LineWidth - (PatternWidth - 1);
  779.                             else
  780.                                 SearchPosition = LastSearchPosition;
  781.  
  782.                             do
  783.                             {
  784.                                 PatternIndex = 0;
  785.                                 LineIndex = SearchPosition - 1;
  786.  
  787.                                 while(PatternIndex < PatternWidth && Pattern[PatternIndex] == Line[LineIndex])
  788.                                 {
  789.                                     LineIndex++;
  790.                                     PatternIndex++;
  791.                                 }
  792.  
  793.                                 SearchPosition -= Distance[Line[SearchPosition - 1]];
  794.  
  795.                                 if(PatternIndex == PatternWidth)
  796.                                 {
  797.                                     LONG X = LineIndex - PatternWidth;
  798.  
  799.                                     if(X)
  800.                                     {
  801.                                         if(!WordSeparators[Line[X - 1]])
  802.                                             continue;
  803.                                         else
  804.                                         {
  805.                                             if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  806.                                                 continue;
  807.                                         }
  808.                                     }
  809.                                     else
  810.                                     {
  811.                                         if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  812.                                             continue;
  813.                                     }
  814.  
  815.                                     Info -> FoundX    = LineIndex - PatternWidth;
  816.                                     Info -> FoundY    = i;
  817.                                     Info -> Index    = SearchPosition;
  818.  
  819.                                     return(i);
  820.                                 }
  821.                             }
  822.                             while(SearchPosition > 0);
  823.                         }
  824.  
  825.                         LastSearchPosition = 0;
  826.                     }
  827.                 }
  828.             }
  829.         }
  830.         else
  831.         {
  832.                 /* Which direction are we to search? */
  833.  
  834.             if(Info -> IgnoreCase)
  835.             {
  836.                 if(Info -> Forward)
  837.                 {
  838.                         /* Update the search positions. */
  839.  
  840.                     if(Info -> FoundY == -1)
  841.                     {
  842.                         Info -> FoundX        = 0;
  843.                         Info -> FoundY        = 0;
  844.                         LastSearchPosition    = 0;
  845.                     }
  846.                     else
  847.                     {
  848.                             /* Proceed to the next line. */
  849.  
  850.                         if(!(LastSearchPosition = Info -> Index))
  851.                             Info -> FoundY = (Info -> FoundY + 1) % Lines;
  852.                     }
  853.  
  854.                         /* Run down the buffer. */
  855.  
  856.                     for(i = Info -> FoundY ; i < Lines ; i++)
  857.                     {
  858.                         Line = BufferLines[i];
  859.  
  860.                             /* Is there anything to search for? */
  861.  
  862.                         if((LineWidth = Line[-1]) >= PatternWidth)
  863.                         {
  864.                                 /* Where are we to start searching? */
  865.  
  866.                             if(LastSearchPosition)
  867.                                 SearchPosition = LastSearchPosition;
  868.                             else
  869.                                 SearchPosition = PatternWidth;
  870.  
  871.                             do
  872.                             {
  873.                                     /* How many line characters
  874.                                      * match the pattern?
  875.                                      */
  876.  
  877.                                 PatternIndex    = PatternWidth - 1;
  878.                                 LineIndex    = SearchPosition - 1;
  879.  
  880.                                 while(PatternIndex >= 0 && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  881.                                 {
  882.                                     LineIndex--;
  883.                                     PatternIndex--;
  884.                                 }
  885.  
  886.                                     /* Update the line search index
  887.                                      * for subsequent searches.
  888.                                      */
  889.  
  890.                                 SearchPosition += Distance[ToUpper(Line[SearchPosition - 1])];
  891.  
  892.                                     /* Found the pattern? */
  893.  
  894.                                 if(PatternIndex < 0)
  895.                                 {
  896.                                         /* Store the position. */
  897.  
  898.                                     Info -> FoundX    = LineIndex + 1;
  899.                                     Info -> FoundY    = i;
  900.  
  901.                                         /* Remember column to start
  902.                                          * next search attempt at.
  903.                                          */
  904.  
  905.                                     if(SearchPosition <= LineWidth)
  906.                                         Info -> Index = SearchPosition;
  907.                                     else
  908.                                         Info -> Index = 0;
  909.  
  910.                                     return(i);
  911.                                 }
  912.                             }
  913.                             while(SearchPosition <= LineWidth);
  914.                         }
  915.  
  916.                             /* Reset search column. */
  917.  
  918.                         LastSearchPosition = 0;
  919.                     }
  920.                 }
  921.                 else
  922.                 {
  923.                         /* Update the search positions. */
  924.  
  925.                     if(Info -> FoundY == -1)
  926.                     {
  927.                         Info -> FoundX        = 0;
  928.                         Info -> FoundY        = Lines - 1;
  929.                         LastSearchPosition    = 0;
  930.                     }
  931.                     else
  932.                     {
  933.                         if((LastSearchPosition = Info -> Index) < 1)
  934.                         {
  935.                             if(Info -> FoundY)
  936.                                 Info -> FoundY--;
  937.                             else
  938.                                 Info -> FoundY = Lines - 1;
  939.                         }
  940.                     }
  941.  
  942.                         /* Run down the buffer. */
  943.  
  944.                     for(i = Info -> FoundY ; i >= 0 ; i--)
  945.                     {
  946.                         Line = BufferLines[i];
  947.  
  948.                             /* Is there anything to search for? */
  949.  
  950.                         if((LineWidth = Line[-1]) >= PatternWidth)
  951.                         {
  952.                                 /* Cast the magic spell of Boyer-Moore... */
  953.  
  954.                             if(LastSearchPosition < 1)
  955.                                 SearchPosition = LineWidth - (PatternWidth - 1);
  956.                             else
  957.                                 SearchPosition = LastSearchPosition;
  958.  
  959.                             do
  960.                             {
  961.                                 PatternIndex = 0;
  962.                                 LineIndex = SearchPosition - 1;
  963.  
  964.                                 while(PatternIndex < PatternWidth && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  965.                                 {
  966.                                     LineIndex++;
  967.                                     PatternIndex++;
  968.                                 }
  969.  
  970.                                 SearchPosition -= Distance[ToUpper(Line[SearchPosition - 1])];
  971.  
  972.                                 if(PatternIndex == PatternWidth)
  973.                                 {
  974.                                     Info -> FoundX    = LineIndex - PatternWidth;
  975.                                     Info -> FoundY    = i;
  976.                                     Info -> Index    = SearchPosition;
  977.  
  978.                                     return(i);
  979.                                 }
  980.                             }
  981.                             while(SearchPosition > 0);
  982.                         }
  983.  
  984.                         LastSearchPosition = 0;
  985.                     }
  986.                 }
  987.             }
  988.             else
  989.             {
  990.                 if(Info -> Forward)
  991.                 {
  992.                         /* Update the search positions. */
  993.  
  994.                     if(Info -> FoundY == -1)
  995.                     {
  996.                         Info -> FoundX        = 0;
  997.                         Info -> FoundY        = 0;
  998.                         LastSearchPosition    = 0;
  999.                     }
  1000.                     else
  1001.                     {
  1002.                             /* Proceed to the next line. */
  1003.  
  1004.                         if(!(LastSearchPosition = Info -> Index))
  1005.                             Info -> FoundY = (Info -> FoundY + 1) % Lines;
  1006.                     }
  1007.  
  1008.                         /* Run down the buffer. */
  1009.  
  1010.                     for(i = Info -> FoundY ; i < Lines ; i++)
  1011.                     {
  1012.                         Line = BufferLines[i];
  1013.  
  1014.                             /* Is there anything to search for? */
  1015.  
  1016.                         if((LineWidth = Line[-1]) >= PatternWidth)
  1017.                         {
  1018.                                 /* Where are we to start searching? */
  1019.  
  1020.                             if(LastSearchPosition)
  1021.                                 SearchPosition = LastSearchPosition;
  1022.                             else
  1023.                                 SearchPosition = PatternWidth;
  1024.  
  1025.                             do
  1026.                             {
  1027.                                     /* How many line characters
  1028.                                      * match the pattern?
  1029.                                      */
  1030.  
  1031.                                 PatternIndex    = PatternWidth - 1;
  1032.                                 LineIndex    = SearchPosition - 1;
  1033.  
  1034.                                 while(PatternIndex >= 0 && Pattern[PatternIndex] == Line[LineIndex])
  1035.                                 {
  1036.                                     LineIndex--;
  1037.                                     PatternIndex--;
  1038.                                 }
  1039.  
  1040.                                     /* Update the line search index
  1041.                                      * for subsequent searches.
  1042.                                      */
  1043.  
  1044.                                 SearchPosition += Distance[Line[SearchPosition - 1]];
  1045.  
  1046.                                     /* Found the pattern? */
  1047.  
  1048.                                 if(PatternIndex < 0)
  1049.                                 {
  1050.                                         /* Store the position. */
  1051.  
  1052.                                     Info -> FoundX    = LineIndex + 1;
  1053.                                     Info -> FoundY    = i;
  1054.  
  1055.                                         /* Remember column to start
  1056.                                          * next search attempt at.
  1057.                                          */
  1058.  
  1059.                                     if(SearchPosition <= LineWidth)
  1060.                                         Info -> Index = SearchPosition;
  1061.                                     else
  1062.                                         Info -> Index = 0;
  1063.  
  1064.                                     return(i);
  1065.                                 }
  1066.                             }
  1067.                             while(SearchPosition <= LineWidth);
  1068.                         }
  1069.  
  1070.                             /* Reset search column. */
  1071.  
  1072.                         LastSearchPosition = 0;
  1073.                     }
  1074.                 }
  1075.                 else
  1076.                 {
  1077.                         /* Update the search positions. */
  1078.  
  1079.                     if(Info -> FoundY == -1)
  1080.                     {
  1081.                         Info -> FoundX        = 0;
  1082.                         Info -> FoundY        = Lines - 1;
  1083.                         LastSearchPosition    = 0;
  1084.                     }
  1085.                     else
  1086.                     {
  1087.                         if((LastSearchPosition = Info -> Index) < 1)
  1088.                         {
  1089.                             if(Info -> FoundY)
  1090.                                 Info -> FoundY--;
  1091.                             else
  1092.                                 Info -> FoundY = Lines - 1;
  1093.                         }
  1094.                     }
  1095.  
  1096.                         /* Run down the buffer. */
  1097.  
  1098.                     for(i = Info -> FoundY ; i >= 0 ; i--)
  1099.                     {
  1100.                         Line = BufferLines[i];
  1101.  
  1102.                             /* Is there anything to search for? */
  1103.  
  1104.                         if((LineWidth = Line[-1]) >= PatternWidth)
  1105.                         {
  1106.                                 /* Cast the magic spell of Boyer-Moore... */
  1107.  
  1108.                             if(LastSearchPosition < 1)
  1109.                                 SearchPosition = LineWidth - (PatternWidth - 1);
  1110.                             else
  1111.                                 SearchPosition = LastSearchPosition;
  1112.  
  1113.                             do
  1114.                             {
  1115.                                 PatternIndex = 0;
  1116.                                 LineIndex = SearchPosition - 1;
  1117.  
  1118.                                 while(PatternIndex < PatternWidth && Pattern[PatternIndex] == Line[LineIndex])
  1119.                                 {
  1120.                                     LineIndex++;
  1121.                                     PatternIndex++;
  1122.                                 }
  1123.  
  1124.                                 SearchPosition -= Distance[Line[SearchPosition - 1]];
  1125.  
  1126.                                 if(PatternIndex == PatternWidth)
  1127.                                 {
  1128.                                     Info -> FoundX    = LineIndex - PatternWidth;
  1129.                                     Info -> FoundY    = i;
  1130.                                     Info -> Index    = SearchPosition;
  1131.  
  1132.                                     return(i);
  1133.                                 }
  1134.                             }
  1135.                             while(SearchPosition > 0);
  1136.                         }
  1137.  
  1138.                         LastSearchPosition = 0;
  1139.                     }
  1140.                 }
  1141.             }
  1142.         }
  1143.     }
  1144.  
  1145.     return(-1);
  1146. }
  1147.  
  1148. STATIC ULONG __saveds __asm
  1149. HistoryFunc(REG(a0) struct Hook *Hook,REG(a1) STRPTR NewString)
  1150. {
  1151.     struct List *List = (struct List *)Hook -> h_Data;
  1152.  
  1153.     if(NewString)
  1154.     {
  1155.         struct Node *Node = CreateNode(NewString);
  1156.  
  1157.         if(Node)
  1158.             AddTail(List,Node);
  1159.         else
  1160.             return(FALSE);
  1161.     }
  1162.     else
  1163.     {
  1164.         struct Node *Node = RemHead(List);
  1165.  
  1166.         FreeVecPooled(Node);
  1167.     }
  1168.  
  1169.     return(TRUE);
  1170. }
  1171.  
  1172. BOOL
  1173. HandleSearchMessage(struct SearchContext *Context,struct IntuiMessage **MessagePtr)
  1174. {
  1175.     struct IntuiMessage    *Message;
  1176.     BOOL             Done = FALSE;
  1177.  
  1178.     if(Message = GT_FilterIMsg(*MessagePtr))
  1179.     {
  1180.         ULONG         MsgClass    = Message -> Class,
  1181.                  MsgQualifier    = Message -> Qualifier;
  1182.         struct Gadget    *MsgGadget    = (struct Gadget *)Message -> IAddress;
  1183.         UWORD         MsgCode    = Message -> Code;
  1184.  
  1185.         LT_HandleInput(Context -> SearchHandle,MsgQualifier,&MsgClass,&MsgCode,&MsgGadget);
  1186.  
  1187.         if(MsgClass == IDCMP_CLOSEWINDOW)
  1188.             Done = TRUE;
  1189.  
  1190.         if(MsgClass == IDCMP_GADGETUP)
  1191.         {
  1192.             switch(MsgGadget -> GadgetID)
  1193.             {
  1194.                 case GAD_STRING:
  1195.  
  1196.                     if(MsgCode == '\r')
  1197.                     {
  1198.                         if(Context -> LocalBuffer[0])
  1199.                         {
  1200.                             strcpy(Context -> Buffer,Context -> LocalBuffer);
  1201.  
  1202.                             Context -> Ok = TRUE;
  1203.  
  1204.                             LT_PressButton(Context -> SearchHandle,GAD_OK);
  1205.                         }
  1206.                         else
  1207.                             LT_PressButton(Context -> SearchHandle,GAD_CANCEL);
  1208.  
  1209.                         Done = TRUE;
  1210.                     }
  1211.  
  1212.                     break;
  1213.  
  1214.                 case GAD_OK:
  1215.  
  1216.                     LT_UpdateStrings(Context -> SearchHandle);
  1217.  
  1218.                     if(Context -> LocalBuffer[0])
  1219.                     {
  1220.                         strcpy(Context -> Buffer,Context -> LocalBuffer);
  1221.  
  1222.                         Context -> Ok = TRUE;
  1223.                     }
  1224.  
  1225.                     Done = TRUE;
  1226.  
  1227.                     break;
  1228.  
  1229.                 case GAD_CANCEL:
  1230.  
  1231.                     Done = TRUE;
  1232.  
  1233.                     break;
  1234.             }
  1235.         }
  1236.  
  1237.         GT_PostFilterIMsg(Message);
  1238.     }
  1239.  
  1240.     ReplyMsg(*MessagePtr);
  1241.  
  1242.     *MessagePtr = NULL;
  1243.  
  1244.     return(Done);
  1245. }
  1246.  
  1247. VOID
  1248. DeleteSearchContext(struct SearchContext *Context)
  1249. {
  1250.     if(Context)
  1251.     {
  1252.         LT_DeleteHandle(Context -> SearchHandle);
  1253.  
  1254.         FreeVecPooled(Context);
  1255.     }
  1256. }
  1257.  
  1258. struct SearchContext *
  1259. CreateSearchContext(struct Window *ParentWindow,STRPTR Buffer,struct Hook *HistoryHook,BOOLEAN *Forward,BOOLEAN *IgnoreCase,BOOLEAN *WholeWords)
  1260. {
  1261.     struct SearchContext *Context;
  1262.  
  1263.     if(Context = (struct SearchContext *)AllocVecPooled(sizeof(struct SearchContext),MEMF_ANY | MEMF_CLEAR))
  1264.     {
  1265.         struct LayoutHandle *Handle;
  1266.  
  1267.         Context -> Buffer = Buffer;
  1268.  
  1269.         if(HistoryHook)
  1270.             HistoryHook -> h_Entry = (HOOKFUNC)HistoryFunc;
  1271.  
  1272.         if(Handle = LT_CreateHandleTags(ParentWindow -> WScreen,
  1273.             LH_LocaleHook,    &LocaleHook,
  1274.         TAG_DONE))
  1275.         {
  1276.             struct Window *Window;
  1277.  
  1278.             LT_New(Handle,
  1279.                 LA_Type,    VERTICAL_KIND,
  1280.             TAG_DONE);
  1281.             {
  1282.                 LT_New(Handle,
  1283.                     LA_Type,    HORIZONTAL_KIND,
  1284.                 TAG_DONE);
  1285.                 {
  1286.                     LT_New(Handle,
  1287.                         LA_Type,    VERTICAL_KIND,
  1288.                     TAG_DONE);
  1289.                     {
  1290.                         LT_New(Handle,
  1291.                             LA_Type,        STRING_KIND,
  1292.                             LA_LabelID,        MSG_V36_0788,
  1293.                             LA_STRPTR,        Context -> LocalBuffer,
  1294.                             LA_Chars,        30,
  1295.                             LA_ID,            GAD_STRING,
  1296.                             LAST_HistoryLines,    MAX(Config -> CaptureConfig -> SearchHistory,1),
  1297.                             LAST_HistoryHook,    HistoryHook,
  1298.                             GTST_MaxChars,        255,
  1299.                         TAG_DONE);
  1300.  
  1301.                         LT_EndGroup(Handle);
  1302.                     }
  1303.  
  1304.                     LT_New(Handle,
  1305.                         LA_Type,    VERTICAL_KIND,
  1306.                     TAG_DONE);
  1307.                     {
  1308.                         LT_New(Handle,
  1309.                             LA_Type,YBAR_KIND,
  1310.                         TAG_DONE);
  1311.  
  1312.                         LT_EndGroup(Handle);
  1313.                     }
  1314.  
  1315.                     LT_New(Handle,
  1316.                         LA_Type,    VERTICAL_KIND,
  1317.                     TAG_DONE);
  1318.                     {
  1319.                         LT_New(Handle,
  1320.                             LA_Type,    CHECKBOX_KIND,
  1321.                             LA_LabelID,    MSG_TERMBUFFER_SEARCH_FORWARD_TXT,
  1322.                             LA_BYTE,    Forward,
  1323.                         TAG_DONE);
  1324.  
  1325.                         LT_New(Handle,
  1326.                             LA_Type,    CHECKBOX_KIND,
  1327.                             LA_LabelID,    MSG_TEXTBUFFER_IGNORE_CASE_GAD,
  1328.                             LA_BYTE,    IgnoreCase,
  1329.                         TAG_DONE);
  1330.  
  1331.                         LT_New(Handle,
  1332.                             LA_Type,    CHECKBOX_KIND,
  1333.                             LA_LabelID,    MSG_SEARCH_ONLY_WHOLE_WORDS_TXT,
  1334.                             LA_BYTE,    WholeWords,
  1335.                         TAG_DONE);
  1336.  
  1337.                         LT_EndGroup(Handle);
  1338.                     }
  1339.  
  1340.                     LT_EndGroup(Handle);
  1341.                 }
  1342.  
  1343.                 LT_New(Handle,
  1344.                     LA_Type,    VERTICAL_KIND,
  1345.                 TAG_DONE);
  1346.                 {
  1347.                     LT_New(Handle,LA_Type,XBAR_KIND,LAXB_FullSize,TRUE,TAG_DONE);
  1348.  
  1349.                     LT_EndGroup(Handle);
  1350.                 }
  1351.  
  1352.                 LT_New(Handle,LA_Type,HORIZONTAL_KIND,
  1353.                     LAGR_SameSize,    TRUE,
  1354.                     LAGR_Spread,    TRUE,
  1355.                 TAG_DONE);
  1356.                 {
  1357.                     LT_New(Handle,
  1358.                         LA_Type,    BUTTON_KIND,
  1359.                         LA_LabelID,    MSG_TERMXPR_OKAY_GAD,
  1360.                         LA_ID,        GAD_OK,
  1361.                         LABT_ReturnKey,    TRUE,
  1362.                         LABT_ExtraFat,    TRUE,
  1363.                     TAG_DONE);
  1364.  
  1365.                     LT_New(Handle,
  1366.                         LA_Type,    BUTTON_KIND,
  1367.                         LA_LabelID,    MSG_GLOBAL_CANCEL_GAD,
  1368.                         LA_ID,        GAD_CANCEL,
  1369.                         LABT_EscKey,    TRUE,
  1370.                         LABT_ExtraFat,    TRUE,
  1371.                     TAG_DONE);
  1372.  
  1373.                     LT_EndGroup(Handle);
  1374.                 }
  1375.  
  1376.                 LT_EndGroup(Handle);
  1377.             }
  1378.  
  1379.             if(Window = LT_Build(Handle,
  1380.                 LAWN_TitleID,        MSG_TERMBUFFER_ENTER_SEARCH_STRING_TXT,
  1381.                 LAWN_IDCMP,        IDCMP_CLOSEWINDOW,
  1382.                 LAWN_HelpHook,        &GuideHook,
  1383.                 LAWN_Parent,        ParentWindow,
  1384.                 LAWN_UserPort,        ParentWindow -> UserPort,
  1385.                 WA_DepthGadget,        TRUE,
  1386.                 WA_CloseGadget,        TRUE,
  1387.                 WA_DragBar,        TRUE,
  1388.                 WA_RMBTrap,        TRUE,
  1389.                 WA_Activate,        TRUE,
  1390.                 WA_SimpleRefresh,    TRUE,
  1391.             TAG_DONE))
  1392.             {
  1393.                 LT_Activate(Handle,GAD_STRING);
  1394.  
  1395.                 Context -> SearchHandle    = Handle;
  1396.                 Context -> SearchWindow = Window;
  1397.  
  1398.                 return(Context);
  1399.             }
  1400.         }
  1401.  
  1402.         FreeVecPooled(Context);
  1403.     }
  1404.  
  1405.     return(NULL);
  1406. }
  1407.