home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d534 / term.lha / Term / Source.LZH / termBuffer.c < prev    next >
C/C++ Source or Header  |  1991-07-20  |  39KB  |  1,635 lines

  1. /* $Revision Header * Header built automatically - do not edit! *************
  2.  *
  3.  *    (C) Copyright 1990 by Olaf 'Olsen' Barthel & MXM
  4.  *
  5.  *    Name .....: TermBuffer.c
  6.  *    Created ..: Monday 21-Jan-91 20:12
  7.  *    Revision .: 0
  8.  *
  9.  *    Date            Author          Comment
  10.  *    =========       ========        ====================
  11.  *    21-Jan-91       Olsen           Created this file!
  12.  *
  13.  * $Revision Header ********************************************************/
  14.  
  15. #include "TermGlobal.h"
  16.  
  17.     /* Some private data (render info & window). */
  18.  
  19. STATIC struct Window    *BufferWindow;
  20. STATIC struct Screen    *BufferScreen;
  21.  
  22. struct Gadget        *BufferGadget;
  23.  
  24. STATIC struct RastPort    *BPort;
  25. STATIC APTR         BufferVisualInfo;
  26.  
  27. STATIC LONG         BufLine,BufCols;
  28.  
  29. STATIC BYTE         MarkedArea;
  30.  
  31. STATIC BYTE         BufferTerminated;
  32.  
  33. enum    {    MEN_SEARCH,MEN_REPEAT,MEN_GOTO,MEN_CLEARBUF,MEN_CLOSEBUF,MEN_QUITBUF };
  34. enum    {    MEN_OKAY=1,MEN_CANCEL,MEN_QUITPANEL=4 };
  35.  
  36. STATIC struct NewMenu BufferMenu[] =
  37. {
  38.     { NM_TITLE, "Project",             0 , 0, 0, (APTR)0},
  39.     {  NM_ITEM, "Search...",        "S", 0, 0, (APTR)MEN_SEARCH},
  40.     {  NM_ITEM, "Repeat Search",        "R", 0, 0, (APTR)MEN_REPEAT},
  41.     {  NM_ITEM, NM_BARLABEL,         0 , 0, 0, (APTR)0},
  42.     {  NM_ITEM, "Go To Main Screen",    "B", 0, 0, (APTR)MEN_GOTO},
  43.     {  NM_ITEM, NM_BARLABEL,         0 , 0, 0, (APTR)0},
  44.     {  NM_ITEM, "Clear Buffer",        "K", 0, 0, (APTR)MEN_CLEARBUF},
  45.     {  NM_ITEM, "Close Buffer",        "C", 0, 0, (APTR)MEN_CLOSEBUF},
  46.     {  NM_ITEM, NM_BARLABEL,         0 , 0, 0, (APTR)0},
  47.     {  NM_ITEM, "Quit",            "Q", 0, 0, (APTR)MEN_QUITBUF},
  48.     { NM_END, 0,                 0 , 0, 0, (APTR)0}
  49. };
  50.  
  51.     /* AllocString(UBYTE *String,SHORT Len):
  52.      *
  53.      +    Allocate space for a string.
  54.      */
  55.  
  56. STATIC UBYTE *
  57. AllocString(UBYTE *String,SHORT Len)
  58. {
  59.     ULONG *Mem;
  60.  
  61.     if(Mem = AllocMem(sizeof(ULONG) + Len,MEMF_PUBLIC))
  62.     {
  63.         *Mem++ = Len;
  64.  
  65.         CopyMem(String,Mem,Len);
  66.  
  67.         String = (UBYTE *)Mem;
  68.  
  69.         return(String);
  70.     }
  71.  
  72.     return(NULL);
  73. }
  74.  
  75.     /* FreeString(UBYTE *String):
  76.      *
  77.      *    Free the space occupied by a string.
  78.      */
  79.  
  80. STATIC VOID
  81. FreeString(UBYTE *String)
  82. {
  83.     FreeMem(&((ULONG *)String)[-1],((ULONG *)String)[-1] + sizeof(ULONG));
  84. }
  85.  
  86.     /* AddLine(UBYTE *Line,LONG Size):
  87.      *
  88.      *    Add a line to the display buffer.
  89.      */
  90.  
  91. VOID
  92. AddLine(UBYTE *Line,LONG Size)
  93. {
  94.     ULONG Signals = 0;
  95.  
  96.         /* Is the buffer array initialized? */
  97.  
  98.     if(BufferLines)
  99.     {
  100.             /* Pick up the global access semaphore
  101.              * (two tasks are sharing the data).
  102.              */
  103.  
  104.         ObtainSemaphore(BufferSemaphore);
  105.  
  106.             /* We've reached the last line in the buffer. */
  107.  
  108.         if(Lines == MaxLines)
  109.         {
  110.             UBYTE **MoreBuffer;
  111.             LONG i;
  112.  
  113.                 /* Allocate space for some more lines. */
  114.  
  115.             if(MoreBuffer = (UBYTE **)AllocVec((MaxLines + 100) * sizeof(UBYTE *),MEMF_PUBLIC|MEMF_CLEAR))
  116.             {
  117.                     /* Copy the old lines to the new
  118.                      * buffer.
  119.                      */
  120.  
  121.                 for(i = 0 ; i < Lines ; i++)
  122.                     MoreBuffer[i] = BufferLines[i];
  123.  
  124.                     /* Free the old lines. */
  125.  
  126.                 FreeVec(BufferLines);
  127.  
  128.                     /* Set the new buffer. */
  129.  
  130.                 MaxLines += 100;
  131.  
  132.                 BufferLines = MoreBuffer;
  133.             }
  134.             else
  135.             {
  136.                     /* We couldn't get enough memory
  137.                      * to extend the number of lines
  138.                      * in the buffer, so we'll have
  139.                      * to wrap the contents of the
  140.                      * buffer around.
  141.                      */
  142.  
  143.                 if(Lines)
  144.                 {
  145.                     BufferSpace -= ((ULONG *)BufferLines[0])[-1];
  146.  
  147.                     FreeString(BufferLines[0]);
  148.  
  149.                     for(i = 1 ; i < MaxLines ; i++)
  150.                         BufferLines[i - 1] = BufferLines[i];
  151.  
  152.                     Lines--;
  153.  
  154.                         /* Tell the buffer task to
  155.                          * refresh the display.
  156.                          */
  157.  
  158.                     Signals = SIGBREAKF_CTRL_F;
  159.                 }
  160.             }
  161.         }
  162.  
  163.             /* Allocate a new line and copy the buffer contents
  164.              * into it.
  165.              */
  166.  
  167.         if(BufferLines[Lines++] = AllocString(Line,Size))
  168.             BufferSpace += Size;
  169.  
  170.         ReleaseSemaphore(BufferSemaphore);
  171.  
  172.             /* Tell the buffer task to update the display. */
  173.  
  174.         if(!Signals)
  175.             Signals = SIGBREAKF_CTRL_E;
  176.  
  177.         if(BufferProcess)
  178.             Signal(BufferProcess,Signals);
  179.     }
  180. }
  181.  
  182.     /* ClearBuffer():
  183.      *
  184.      *    Clear the current display buffer and flush the contents
  185.      *    of the buffered capture file handles.
  186.      */
  187.  
  188. VOID
  189. ClearBuffer()
  190. {
  191.     SHORT i;
  192.  
  193.     if(BufferProcess)
  194.     {
  195.         Signal(BufferProcess,SIGBREAKF_CTRL_C);
  196.  
  197.         Wait(SIGBREAKF_CTRL_C);
  198.     }
  199.  
  200.     if(FileCapture)
  201.         Flush(FileCapture);
  202.  
  203.     if(PrinterCapture)
  204.         Flush(PrinterCapture);
  205.  
  206.         /* Free the contents of the display buffer. */
  207.  
  208.     if(BufferLines)
  209.     {
  210.         for(i = 0 ; i < Lines ; i++)
  211.         {
  212.             if(BufferLines[i])
  213.                 FreeString(BufferLines[i]);
  214.         }
  215.  
  216.         FreeVec(BufferLines);
  217.  
  218.         BufferLines = NULL;
  219.  
  220.         Lines = 0;
  221.  
  222.         MaxLines = 100;
  223.  
  224.         BufferLines = (UBYTE **)AllocVec(MaxLines * sizeof(UBYTE *),MEMF_PUBLIC|MEMF_CLEAR);
  225.     }
  226.  
  227.     BufferSpace = 0;
  228. }
  229.  
  230.     /* StoreBuffer(APTR Buffer,LONG Size):
  231.      *
  232.      *    Store data in the display buffer.
  233.      */
  234.  
  235. VOID
  236. StoreBuffer(APTR Buffer,LONG Size)
  237. {
  238.     STATIC UBYTE     LineBuffer[200];
  239.     STATIC LONG      BufferCount = 0;
  240.  
  241.     UBYTE        *CharBuffer = Buffer;
  242.     LONG         i;
  243.  
  244.     for(i = 0 ; i < Size ; i++)
  245.     {
  246.             /* Look which char we are to handle. */
  247.  
  248.         switch(CharBuffer[i])
  249.         {
  250.                 /* Ignore the following characters. */
  251.  
  252.             case FFD:
  253.             case BEL:
  254.             case DEL:
  255.             case VTB:
  256.             case XON:
  257.             case XOF:    continue;
  258.  
  259.                 /* Move the cursor to the next tab
  260.                  * stop.
  261.                  */
  262.  
  263.             case TAB:    if(BufferCount + 8 < LastColumn)
  264.                     {
  265.                         strcpy(&LineBuffer[BufferCount],"        ");
  266.  
  267.                         BufferCount += 8;
  268.  
  269.                         break;
  270.                     }
  271.  
  272.                     continue;
  273.  
  274.                 /* Move the cursor one step back. */
  275.  
  276.             case BKS:    if(BufferCount)
  277.                         BufferCount--;
  278.  
  279.                     continue;
  280.  
  281.                 /* Terminate the current line. */
  282.  
  283.             case ENT:
  284.             case RET:    AddLine(LineBuffer,BufferCount);
  285.  
  286.                     BufferCount = 0;
  287.                     continue;
  288.  
  289.                 /* Stuff the character into the buffer. */
  290.  
  291.             default:    LineBuffer[BufferCount++] = CharBuffer[i];
  292.                     break;
  293.         }
  294.  
  295.             /* The line is full, add it to the display buffer. */
  296.  
  297.         if(BufferCount > LastColumn)
  298.         {
  299.             AddLine(LineBuffer,BufferCount);
  300.  
  301.             BufferCount = 0;
  302.         }
  303.     }
  304. }
  305.  
  306.     /* FlushIMsg(struct Window *Window):
  307.      *
  308.      +    Clear the MsgPort of a window.
  309.      */
  310.  
  311. STATIC VOID
  312. FlushIMsg(struct Window *Window)
  313. {
  314.     struct IntuiMessage *Massage;
  315.  
  316.     while(Massage = GT_GetIMsg(Window -> UserPort))
  317.         GT_ReplyIMsg(Massage);
  318. }
  319.  
  320.     /* CreateAllGadgets():
  321.      *
  322.      *    Create all the gadgets required by the
  323.      *    buffer screen (i.e. the scroller gadget).
  324.      */
  325.  
  326. STATIC struct Gadget *
  327. CreateAllGadgets(struct Gadget **GadgetArray,struct Gadget **GadgetList)
  328. {
  329.     struct Gadget        *Gadget;
  330.     struct NewGadget     NewGadget;
  331.  
  332.     if(Gadget = CreateContext(GadgetList))
  333.     {
  334.         memset(&NewGadget,0,sizeof(struct NewGadget));
  335.  
  336.         NewGadget . ng_Width        = 16;
  337.         NewGadget . ng_Height        = BufferWindow -> Height;
  338.         NewGadget . ng_TextAttr        = &DefaultFont;
  339.         NewGadget . ng_VisualInfo    = BufferVisualInfo;
  340.         NewGadget . ng_GadgetID        = 0;
  341.         NewGadget . ng_LeftEdge        = BufferWindow -> Width - 16;
  342.         NewGadget . ng_TopEdge        = 0;
  343.  
  344.         GadgetArray[0] = Gadget = CreateGadget(SCROLLER_KIND,Gadget,&NewGadget,
  345.             GTSC_Arrows,    (Config . DisplayMode & LACE) ? 16 : 8,
  346.             PGA_Freedom,    LORIENT_VERT,
  347.             GA_Immediate,    TRUE,
  348.             GA_RelVerify,    TRUE,
  349.         TAG_DONE);
  350.     }
  351.  
  352.     return(Gadget);
  353. }
  354.  
  355.     /* GetSearchString(UBYTE *Buffer):
  356.      *
  357.      *    Prompt user for a string to search the buffer for.
  358.      */
  359.  
  360. STATIC BYTE
  361. GetSearchString(UBYTE *Buffer)
  362. {
  363.     struct Gadget    *GadgetList;
  364.     struct Gadget    *GadgetArray[4];
  365.     struct Window    *PanelWindow;
  366.     struct Menu    *PanelMenu;
  367.     LONG         Width;
  368.     UBYTE         OtherBuffer[256];
  369.     BYTE         Success = FALSE;
  370.  
  371.     strcpy(OtherBuffer,Buffer);
  372.  
  373.     if(CreateAllGetsGadgets(FALSE,OtherBuffer,"Enter Search String",&Width,&GadgetArray[0],&GadgetList,BufferVisualInfo,BufferScreen -> WBorTop + BufferScreen -> Font -> ta_YSize + 1))
  374.     {
  375.         if(PanelMenu = CreateMenus(GetsMenu,
  376.             GTMN_FrontPen, 0,
  377.         TAG_DONE))
  378.         {
  379.             if(LayoutMenus(PanelMenu,VisualInfo,
  380.                 GTMN_TextAttr,&DefaultFont,
  381.             TAG_DONE))
  382.             {
  383.                 if(PanelWindow = OpenWindowTags(NULL,
  384.                     WA_Width,    Width,
  385.                     WA_Height,    56,
  386.  
  387.                     WA_Left,    (BufferScreen -> Width - Width) >> 1,
  388.                     WA_Top,        (BufferScreen -> Height - 56) >> 1,
  389.  
  390.                     WA_Activate,    TRUE,
  391.                     WA_DragBar,    TRUE,
  392.                     WA_DepthGadget,    TRUE,
  393.                     WA_CloseGadget,    TRUE,
  394.                     WA_RMBTrap,    TRUE,
  395.                     WA_CustomScreen,BufferScreen,
  396.  
  397.                     WA_IDCMP,    IDCMP_ACTIVEWINDOW | IDCMP_CLOSEWINDOW | IDCMP_GADGETUP | IDCMP_MENUPICK,
  398.  
  399.                     WA_Title,    "Enter Search String",
  400.                 TAG_DONE))
  401.                 {
  402.                     struct IntuiMessage    *Massage;
  403.                     ULONG             Class,Code;
  404.                     struct Gadget        *Gadget;
  405.                     BYTE             Terminated = FALSE;
  406.                     struct StringExtend     PanelExtend;
  407.                     ULONG             SignalSet;
  408.  
  409.                     CopyMem(&CommandExtend,&PanelExtend,sizeof(struct StringExtend));
  410.  
  411.                     PanelExtend . Pens[0]        = 1;
  412.                     PanelExtend . Pens[1]        = 0;
  413.  
  414.                     PanelExtend . Pens[2]        = 1;
  415.                     PanelExtend . Pens[3]        = 0;
  416.  
  417.                     ((struct StringInfo *)GadgetArray[0] -> SpecialInfo) -> Extension = &PanelExtend;
  418.  
  419.                     AddGList(PanelWindow,GadgetList,(UWORD)-1,(UWORD)-1,NULL);
  420.                     RefreshGList(GadgetList,PanelWindow,NULL,(UWORD)-1);
  421.                     GT_RefreshWindow(PanelWindow,NULL);
  422.  
  423.                     SetMenuStrip(PanelWindow,PanelMenu);
  424.  
  425.                     PanelWindow -> Flags &= ~WFLG_RMBTRAP;
  426.  
  427.                     ActiveGadget = GadgetArray[0];
  428.  
  429.                     ActivateGadget(GadgetArray[0],PanelWindow,NULL);
  430.  
  431.                     while(!Terminated)
  432.                     {
  433.                         SignalSet = Wait((1 << PanelWindow -> UserPort -> mp_SigBit) | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_C);
  434.  
  435.                         if(SignalSet & SIGBREAKF_CTRL_D)
  436.                         {
  437.                             BumpWindow(PanelWindow);
  438.  
  439.                             ActivateGadget(GadgetArray[0],PanelWindow,NULL);
  440.                         }
  441.  
  442.                         if(SignalSet & SIGBREAKF_CTRL_C)
  443.                         {
  444.                             BufferTerminated = TRUE;
  445.                             Terminated = TRUE;
  446.                         }
  447.  
  448.                         if(SignalSet & (1 << PanelWindow -> UserPort -> mp_SigBit))
  449.                         {
  450.                             while(!Terminated && (Massage = (struct IntuiMessage *)GT_GetIMsg(PanelWindow -> UserPort)))
  451.                             {
  452.                                 Class    = Massage -> Class;
  453.                                 Code    = Massage -> Code;
  454.                                 Gadget    = (struct Gadget *)Massage -> IAddress;
  455.  
  456.                                 GT_ReplyIMsg(Massage);
  457.  
  458.                                 if(Class == IDCMP_MENUPICK)
  459.                                 {
  460.                                     struct MenuItem *MenuItem;
  461.  
  462.                                     while(Code != MENUNULL)
  463.                                     {
  464.                                         MenuItem = ItemAddress(PanelMenu,Code);
  465.  
  466.                                         switch((ULONG)MENU_USERDATA(MenuItem))
  467.                                         {
  468.                                             case MEN_CANCEL:
  469.                                             case MEN_QUITPANEL:    Class = IDCMP_CLOSEWINDOW;
  470.                                                         break;
  471.  
  472.                                             case MEN_OKAY:        strcpy(Buffer,((struct StringInfo *)GadgetArray[0] -> SpecialInfo) -> Buffer);
  473.  
  474.                                                         Success = TRUE;
  475.  
  476.                                                         Terminated = TRUE;
  477.                                                         break;
  478.                                         }
  479.  
  480.                                         Code = MenuItem -> NextSelect;
  481.                                     }
  482.  
  483.                                     if(ActiveGadget)
  484.                                         ActivateGadget(ActiveGadget,PanelWindow,NULL);
  485.                                 }
  486.  
  487.                                 if(Class == IDCMP_ACTIVEWINDOW)
  488.                                     ActivateGadget(GadgetArray[0],PanelWindow,NULL);
  489.  
  490.                                 if(Class == IDCMP_CLOSEWINDOW)
  491.                                     Terminated = TRUE;
  492.  
  493.                                 if(Class == IDCMP_GADGETUP)
  494.                                 {
  495.                                     switch(Gadget -> GadgetID)
  496.                                     {
  497.                                         case 0:
  498.                                         case 1:    if(((struct StringInfo *)GadgetArray[0] -> SpecialInfo) -> Buffer[0])
  499.                                             {
  500.                                                 strcpy(Buffer,((struct StringInfo *)GadgetArray[0] -> SpecialInfo) -> Buffer);
  501.  
  502.                                                 Success = TRUE;
  503.                                             }
  504.  
  505.                                             Terminated = TRUE;
  506.                                             break;
  507.  
  508.                                         case 3:    Terminated = TRUE;
  509.                                             break;
  510.                                     }
  511.                                 }
  512.                             }
  513.                         }
  514.                     }
  515.  
  516.                     PanelWindow -> Flags |= WFLG_RMBTRAP;
  517.  
  518.                     ClearMenuStrip(PanelWindow);
  519.  
  520.                     RemoveGList(PanelWindow,GadgetList,(UWORD)-1);
  521.  
  522.                     CloseWindow(PanelWindow);
  523.                 }
  524.  
  525.                 FreeGadgets(GadgetList);
  526.             }
  527.  
  528.             FreeMenus(PanelMenu);
  529.         }
  530.     }
  531.  
  532.     return(Success);
  533. }
  534.  
  535.     /* PrintLine(UBYTE *Buffer,LONG LineNumber):
  536.      *
  537.      *    Print a line at a given line number in the displayed area.
  538.      */
  539.  
  540. STATIC VOID
  541. PrintLine(UBYTE *Buffer,LONG LineNumber)
  542. {
  543.     SHORT Length = ((ULONG *)Buffer)[-1];
  544.  
  545.         /* The line doesn't exactly fill the displayed line,
  546.          * so erase the remaining columns.
  547.          */
  548.  
  549.     if(Length < BufCols)
  550.     {
  551.         SetAPen(BPort,0);
  552.  
  553.         RectFill(BPort,Length << 3,LineNumber << 3,(BufCols << 3) - 1,((LineNumber + 1) << 3) - 1);
  554.  
  555.         SetAPen(BPort,1);
  556.     }
  557.  
  558.         /* Print the text. */
  559.  
  560.     if(Length)
  561.     {
  562.         Move(BPort,0,(LineNumber << 3) + 6);
  563.  
  564.         if(Length > BufCols)
  565.             Text(BPort,Buffer,BufCols);
  566.         else
  567.             Text(BPort,Buffer,Length);
  568.     }
  569. }
  570.  
  571.     /* RedrawScreen(LONG FirstLine):
  572.      *
  573.      *    Redraw the contents of the entire screen and return the
  574.      *    number of lines actually drawn.
  575.      */
  576.  
  577. STATIC LONG
  578. RedrawScreen(LONG FirstLine)
  579. {
  580.     LONG i,Last,Line = 0;
  581.  
  582.         /* Determine last line to display. */
  583.  
  584.     if((Last = FirstLine + BufLine) >= Lines)
  585.         Last = Lines;
  586.  
  587.         /* Obtain the access semaphore and display the single
  588.          * lines.
  589.          */
  590.  
  591.     ObtainSemaphore(BufferSemaphore);
  592.  
  593.     for(i = FirstLine ; i < Last ; i++)
  594.         PrintLine(BufferLines[i],Line++);
  595.  
  596.     ReleaseSemaphore(BufferSemaphore);
  597.  
  598.         /* We didn't fill the whole screen, so clear the rest. */
  599.  
  600.     if(Line < BufLine)
  601.     {
  602.         SetAPen(BPort,0);
  603.  
  604.         RectFill(BPort,0,Line << 3,BufferWindow -> Width - (1 + 16),BufferWindow -> Height - 1);
  605.  
  606.         SetAPen(BPort,1);
  607.     }
  608.  
  609.     return(Line);
  610. }
  611.  
  612.     /* MarkArea(SHORT Column,SHORT Line,SHORT Length):
  613.      *
  614.      *    Mark an area in the term Buffer window.
  615.      */
  616.  
  617. STATIC VOID
  618. MarkArea(SHORT Column,SHORT Line,SHORT Length)
  619. {
  620.     STATIC SHORT OldColumn = -1,OldLine = -1,OldLength = -1;
  621.  
  622.     if(OldColumn != Column || OldLine != Line || OldLength != Length)
  623.     {
  624.         if(OldColumn != -1)
  625.             ClipBlit(BPort,0,0,BPort,OldColumn << 3,OldLine << 3,OldLength << 3,8,0x50);
  626.  
  627.         MarkedArea = TRUE;
  628.  
  629.         if(Column != -1)
  630.             ClipBlit(BPort,0,0,BPort,Column << 3,Line << 3,Length << 3,8,0x50);
  631.         else
  632.             MarkedArea = FALSE;
  633.     }
  634.  
  635.     OldColumn    = Column;
  636.     OldLine        = Line;
  637.     OldLength    = Length;
  638. }
  639.  
  640.     /* Search():
  641.      *
  642.      *    String search function, based on the Boyer-Moore search
  643.      *    algorithm.
  644.      */
  645.  
  646. STATIC LONG
  647. Search(UBYTE *Pattern,LONG *FoundX,LONG *FoundY,LONG *SaveX)
  648. {
  649.     UBYTE    Distance[256],NewPattern[256],PatternWidth,SearchWidth;
  650.     LONG    LineNumber = -1,i;
  651.     SHORT    j,k,l;
  652.  
  653.         /* Determine length of search pattern. */
  654.  
  655.     PatternWidth = strlen(Pattern);
  656.  
  657.         /* Convert search pattern to upper cse. */
  658.  
  659.     for(i = 0 ; i <= PatternWidth ; i++)
  660.         NewPattern[i] = ToUpper(Pattern[i]);
  661.  
  662.         /* Create distance table. */
  663.  
  664.     for(i = 0 ; i < 256 ; i++)
  665.         Distance[i] = PatternWidth;
  666.  
  667.     for(i = 0 ; i < PatternWidth - 1 ; i++)
  668.         Distance[NewPattern[i]] = PatternWidth - i - 1;
  669.  
  670.         /* Run down the buffer. */
  671.  
  672.     for(i = *FoundY ; i < Lines ; i++)
  673.     {
  674.             /* Is there anything to search for? */
  675.  
  676.         if(SearchWidth = ((ULONG *)BufferLines[i])[-1])
  677.         {
  678.                 /* Cast the magick spell of
  679.                  * Boyer-Moore...
  680.                  */
  681.  
  682.             j = PatternWidth;
  683.  
  684.             do
  685.             {
  686.                 k = PatternWidth;
  687.                 l = j;
  688.  
  689.                 do
  690.                 {
  691.                     k--;
  692.                     l--;
  693.                 }
  694.                 while(k >= 0 && NewPattern[k] == ToUpper(BufferLines[i][l]));
  695.  
  696.                 j += Distance[ToUpper(BufferLines[i][j - 1])];
  697.             }
  698.             while(k >= 0 && j <= SearchWidth);
  699.  
  700.                 /* Found first occurence, set up the
  701.                  * data and quit.
  702.                  */
  703.  
  704.             if(k < 0)
  705.             {
  706.                 *FoundX    = l + 1;
  707.                 *FoundY    = LineNumber = i;
  708.  
  709.                 *SaveX    = l + 1;
  710.  
  711.                 if(BufferLines[i][*FoundX + 1])
  712.                     *FoundX++;
  713.                 else
  714.                 {
  715.                     if(*FoundY - 1 < Lines)
  716.                     {
  717.                         *FoundX = 0;
  718.                         *FoundY++;
  719.                     }
  720.                 }
  721.  
  722.                 return(LineNumber);
  723.             }
  724.             else
  725.                 *FoundX = 0;
  726.         }
  727.     }
  728.  
  729.     return(LineNumber);
  730. }
  731.  
  732.     /* BufferServer():
  733.      *
  734.      *    Asynchronous task to display the data stored in the
  735.      *    scrollback display buffer.
  736.      */
  737.  
  738. VOID __saveds
  739. BufferServer()
  740. {
  741.     struct ColorSpec     ColorSpec[3];
  742.  
  743.     ULONG             SignalSet;
  744.  
  745.     struct IntuiMessage    *Massage;
  746.     ULONG             Class,Code,Qualifier;
  747.     UBYTE             Char,LastChar = 0;
  748.  
  749.     LONG             CurrentLine,DisplayedLines;
  750.  
  751.     UBYTE             PercentBuffer[80];
  752.  
  753.     struct Menu        *BufferMenuStrip;
  754.  
  755.     STATIC UBYTE         SearchBuffer[256];
  756.     LONG             LineNumber,SaveX,FoundX = 0,FoundY = 0;
  757.     ULONG             DisplayMode;
  758.  
  759.     struct Rectangle     DisplayClip;
  760.  
  761.     UWORD             SomeColour;
  762.  
  763.     struct Gadget        *GadgetList;
  764.     struct Gadget        *GadgetArray[1];
  765.  
  766.     BYTE             Scrolling = FALSE;
  767.  
  768.     BufferTerminated = FALSE;
  769.  
  770.         /* Set up the startup colours for our buffer screen. */
  771.  
  772.     ColorSpec[0] . ColorIndex    = 0;
  773.     ColorSpec[0] . Red        = (Config . Colours[0] >> 8) & 0xF;
  774.     ColorSpec[0] . Green        = (Config . Colours[0] >> 4) & 0xF;
  775.     ColorSpec[0] . Blue        = (Config . Colours[0]     ) & 0xF;
  776.  
  777.     switch(Config . ColourMode)
  778.     {
  779.         case COLOUR_EIGHT:    SomeColour = Config . Colours[7];
  780.                     break;
  781.  
  782.         case COLOUR_SIXTEEN:    SomeColour = Config . Colours[15];
  783.                     break;
  784.  
  785.         case COLOUR_AMIGA:
  786.         default:        SomeColour = Config . Colours[1];
  787.                     break;
  788.     }
  789.  
  790.     ColorSpec[1] . ColorIndex    = 1;
  791.     ColorSpec[1] . Red        = (SomeColour >> 8) & 0xF;
  792.     ColorSpec[1] . Green        = (SomeColour >> 4) & 0xF;
  793.     ColorSpec[1] . Blue        = (SomeColour     ) & 0xF;
  794.  
  795.     ColorSpec[2] . ColorIndex    = -1;
  796.  
  797.         /* We'll use a fixed screen width, only the
  798.          * height is adapted from the main screen.
  799.          */
  800.  
  801.     if(Config . DisplayMode & LACE)
  802.     {
  803.         if(!ModeNotAvailable(VGAPRODUCT_KEY))
  804.             DisplayMode = VGAPRODUCT_KEY;
  805.         else
  806.             DisplayMode = HIRESLACE_KEY;
  807.     }
  808.     else
  809.         DisplayMode = HIRES_KEY;
  810.  
  811.         /* Inquire the text overscan dimensions. */
  812.  
  813.     if(QueryOverscan(DisplayMode,&DisplayClip,OSCAN_TEXT))
  814.     {
  815.             /* Centre the buffer screen. */
  816.  
  817.         if(DisplayClip . MaxX - DisplayClip . MinX + 1 > 640 + 16)
  818.         {
  819.             SHORT Differ = ((DisplayClip . MaxX - DisplayClip . MinX + 1) - (640 + 16)) >> 1;
  820.  
  821.             DisplayClip . MinX += Differ;
  822.             DisplayClip . MaxX -= Differ;
  823.         }
  824.  
  825.             /* Open a single bitplane clone of the main screen. */
  826.  
  827.         if(BufferScreen = (struct Screen *)OpenScreenTags(NULL,
  828.             SA_Title,    "term Buffer",
  829.             SA_Depth,    1,
  830.             SA_DClip,    &DisplayClip,
  831.             SA_DisplayID,    DisplayMode,
  832.             SA_Font,    &DefaultFont,
  833.             SA_Behind,    TRUE,
  834.             SA_AutoScroll,    TRUE,
  835.             SA_Colors,    ColorSpec,
  836.         TAG_END))
  837.         {
  838.             if(BufferVisualInfo = GetVisualInfo(BufferScreen,TAG_DONE))
  839.             {
  840.                 if(BufferMenuStrip = CreateMenus(BufferMenu,
  841.                     GTMN_FrontPen, 0,
  842.                 TAG_DONE))
  843.                 {
  844.                     if(LayoutMenus(BufferMenuStrip,BufferVisualInfo,
  845.                         GTMN_TextAttr,&DefaultFont,
  846.                     TAG_DONE))
  847.                     {
  848.                             /* Open a cute window on our buffer screen. */
  849.  
  850.                         if(BufferWindow = OpenWindowTags(NULL,
  851.                             WA_Top,        BufferScreen -> BarHeight + 2,
  852.                             WA_Left,    0,
  853.                             WA_Width,    BufferScreen -> Width,
  854.                             WA_Height,    BufferScreen -> Height - (Screen -> BarHeight + 2),
  855.                             WA_Backdrop,    TRUE,
  856.                             WA_Borderless,    TRUE,
  857.                             WA_SmartRefresh,FALSE,
  858.                             WA_CustomScreen,BufferScreen,
  859.                             WA_RMBTrap,    TRUE,
  860.                             WA_RptQueue,    1,
  861.                             WA_IDCMP,    ARROWIDCMP | SCROLLERIDCMP | IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE | IDCMP_MENUPICK,
  862.                         TAG_DONE))
  863.                         {
  864.                             if(CreateAllGadgets(&GadgetArray[0],&GadgetList))
  865.                             {
  866.                                     /* Signal our father process that
  867.                                      * we're running.
  868.                                      */
  869.  
  870.                                 Signal(ThisProcess,SIGBREAKF_CTRL_C);
  871.  
  872.                                 SetMenuStrip(BufferWindow,BufferMenuStrip);
  873.  
  874.                                 BufferGadget = GadgetArray[0];
  875.  
  876.                                 AddGList(BufferWindow,GadgetList,(UWORD)-1,(UWORD)-1,NULL);
  877.                                 RefreshGList(GadgetList,BufferWindow,NULL,(UWORD)-1);
  878.                                 GT_RefreshWindow(BufferWindow,NULL);
  879.  
  880. Restart:                                /* Set the IBM font if necessary. */
  881.  
  882.                                 BPort = BufferWindow -> RPort;
  883.  
  884.                                 if(Config . Font == FONT_IBM && IBM)
  885.                                     SetFont(BPort,IBM);
  886.  
  887.                                     /* Determine maximum dimensions of
  888.                                      * the buffer screen (in rows and
  889.                                      * columns).
  890.                                      */
  891.  
  892.                                 BufCols    = (BufferWindow -> Width - 16) >> 3;
  893.                                 BufLine    = BufferWindow -> Height >> 3;
  894.  
  895.                                     /* Bring the screen to the front. */
  896.  
  897.                                 BumpWindow(BufferWindow);
  898.  
  899.                                     /* Set the drawing pens for the window. */
  900.  
  901.                                 SetAPen(BPort,1);
  902.                                 SetBPen(BPort,0);
  903.                                 SetDrMd(BPort,JAM2);
  904.  
  905.                                     /* Initial creation of the buffer display. */
  906.  
  907.                                 DisplayedLines = RedrawScreen(CurrentLine = 0);
  908.  
  909.                                 GT_SetGadgetAttrs(BufferGadget,BufferWindow,NULL,
  910.                                     GTSC_Top,    0,
  911.                                     GTSC_Total,    Lines,
  912.                                     GTSC_Visible,    BufLine,
  913.                                 TAG_DONE);
  914.  
  915.                                 BufferWindow -> Flags &= ~WFLG_RMBTRAP;
  916.  
  917.                                 while(!BufferTerminated)
  918.                                 {
  919.                                         /* Show where we are. */
  920.  
  921.                                     if(Lines)
  922.                                     {
  923.                                         SetAPen(BufferScreen -> BarLayer -> rp,0);
  924.                                         SetBPen(BufferScreen -> BarLayer -> rp,1);
  925.                                         SetDrMd(BufferScreen -> BarLayer -> rp,JAM2);
  926.  
  927.                                         SPrintf(PercentBuffer,"%04ld/%04ld (%3ld%%) %ld Bytes Total        ",CurrentLine,Lines > BufLine ? Lines - BufLine : 0,(100 * (CurrentLine + DisplayedLines)) / Lines,BufferSpace);
  928.  
  929.                                         Move(BufferScreen -> BarLayer -> rp,101,7);
  930.                                         Text(BufferScreen -> BarLayer -> rp,PercentBuffer,strlen(PercentBuffer));
  931.                                     }
  932.  
  933.                                     SignalSet = Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F | (1 << BufferWindow -> UserPort -> mp_SigBit));
  934.  
  935.                                         /* Leave the town? */
  936.  
  937.                                     if(SignalSet & SIGBREAKF_CTRL_C)
  938.                                         BufferTerminated = TRUE;
  939.  
  940.                                         /* Bring our window to the front. */
  941.  
  942.                                     if(SignalSet & SIGBREAKF_CTRL_D)
  943.                                         BumpWindow(BufferWindow);
  944.  
  945.                                         /* We've got one more line in the
  946.                                          * buffer.
  947.                                          */
  948.  
  949.                                     if(SignalSet & SIGBREAKF_CTRL_E)
  950.                                     {
  951.                                         if(Lines - CurrentLine > DisplayedLines && DisplayedLines < BufLine)
  952.                                             PrintLine(BufferLines[CurrentLine + DisplayedLines],DisplayedLines++);
  953.  
  954.                                         GT_SetGadgetAttrs(BufferGadget,BufferWindow,NULL,
  955.                                             GTSC_Total,    Lines,
  956.                                             GTSC_Visible,    BufLine,
  957.                                         TAG_DONE);
  958.                                     }
  959.  
  960.                                         /* The contents of the buffer have moved
  961.                                          * up a line.
  962.                                          */
  963.  
  964.                                     if(SignalSet & SIGBREAKF_CTRL_F)
  965.                                     {
  966.                                         if(DisplayedLines)
  967.                                             ScrollRaster(BPort,0,-8,0,0,(BufCols << 3) - 1,(DisplayedLines << 3) - 1);
  968.  
  969.                                         CurrentLine--;
  970.  
  971.                                         ObtainSemaphore(BufferSemaphore);
  972.  
  973.                                         PrintLine(BufferLines[CurrentLine],0);
  974.  
  975.                                         ReleaseSemaphore(BufferSemaphore);
  976.  
  977.                                         if(DisplayedLines < BufLine)
  978.                                             DisplayedLines++;
  979.  
  980.                                         if(FoundY)
  981.                                             FoundY--;
  982.                                     }
  983.  
  984.                                         /* Process the incoming window
  985.                                          * input.
  986.                                          */
  987.  
  988.                                     while(!BufferTerminated && (Massage = (struct IntuiMessage *)GT_GetIMsg(BufferWindow -> UserPort)))
  989.                                     {
  990.                                         Class        = Massage -> Class;
  991.                                         Code        = Massage -> Code;
  992.                                         Qualifier    = Massage -> Qualifier;
  993.  
  994.                                             /* This hack is necessary to obtain the
  995.                                              * character codes generated for the cursor
  996.                                              * keys. A control or alternate qualifier
  997.                                              * would spoil the result (i.e. we would
  998.                                              * not get a valid key code).
  999.                                              */
  1000.  
  1001.                                         Massage -> Qualifier = NULL;
  1002.  
  1003.                                         Char = KeyConvert(Massage,NULL);
  1004.  
  1005.                                             /* Just in case anybody needs it... */
  1006.  
  1007.                                         Massage -> Qualifier = Qualifier;
  1008.  
  1009.                                         GT_ReplyIMsg(Massage);
  1010.  
  1011.                                         if(Class == IDCMP_GADGETUP)
  1012.                                             Scrolling = FALSE;
  1013.  
  1014.                                         if(Class == IDCMP_GADGETDOWN)
  1015.                                             Scrolling = TRUE;
  1016.  
  1017.                                         if((Class == IDCMP_MOUSEMOVE && Scrolling) || Class == IDCMP_GADGETDOWN)
  1018.                                         {
  1019.                                             if(Code != CurrentLine)
  1020.                                             {
  1021.                                                 if(ABS(CurrentLine - Code) == 1)
  1022.                                                 {
  1023.                                                     Qualifier    = NULL;
  1024.                                                     Class        = IDCMP_RAWKEY;
  1025.  
  1026.                                                     if(Code > CurrentLine)
  1027.                                                         Code = CDN;
  1028.                                                     else
  1029.                                                         Code = CUP;
  1030.  
  1031.                                                     goto UseKey;
  1032.                                                 }
  1033.                                                 else
  1034.                                                 {
  1035.                                                     if(MarkedArea)
  1036.                                                         MarkArea(-1,-1,-1);
  1037.                                             
  1038.                                                     DisplayedLines = RedrawScreen(CurrentLine = Code);
  1039.                                                 }
  1040.                                             }
  1041.                                         }
  1042.  
  1043.                                         if(Class == IDCMP_RAWKEY)
  1044.                                         {
  1045.                                             if(LastChar && (Code & IECODE_UP_PREFIX))
  1046.                                             {
  1047.                                                 GT_SetGadgetAttrs(BufferGadget,BufferWindow,NULL,
  1048.                                                     GTSC_Top,    CurrentLine,
  1049.                                                     GTSC_Total,    Lines,
  1050.                                                     GTSC_Visible,    BufLine,
  1051.                                                 TAG_DONE);
  1052.                                             }
  1053.  
  1054.                                             if(LastChar = Char)
  1055.                                             {
  1056.                                                     /* Use the numeric keypad keys to
  1057.                                                      * move through the buffer.
  1058.                                                      */
  1059.  
  1060. UseKey:                                                if(Qualifier & IEQUALIFIER_NUMERICPAD)
  1061.                                                 {
  1062.                                                         /* Remove the numpad qualifier. */
  1063.  
  1064.                                                     Qualifier &= ~IEQUALIFIER_NUMERICPAD;
  1065.  
  1066.                                                     switch(Char - '0')
  1067.                                                     {
  1068.                                                             /* Jump to bottom. */
  1069.  
  1070.                                                         case 1: Char = CDN;
  1071.                                                             Qualifier |= IEQUALIFIER_CONTROL;
  1072.                                                             break;
  1073.  
  1074.                                                             /* Jump to top. */
  1075.  
  1076.                                                         case 7: Char = CUP;
  1077.                                                             Qualifier |= IEQUALIFIER_CONTROL;
  1078.                                                             break;
  1079.  
  1080.                                                             /* Move one page down. */
  1081.  
  1082.                                                         case 3: Char = CDN;
  1083.                                                             Qualifier |= IEQUALIFIER_LSHIFT;
  1084.                                                             break;
  1085.  
  1086.                                                             /* Move one page up. */
  1087.  
  1088.                                                         case 9: Char = CUP;
  1089.                                                             Qualifier |= IEQUALIFIER_LSHIFT;
  1090.                                                             break;
  1091.  
  1092.                                                             /* Move one line down. */
  1093.  
  1094.                                                         case 2: Char = CDN;
  1095.                                                             break;
  1096.  
  1097.                                                             /* Move one line up. */
  1098.  
  1099.                                                         case 8: Char = CUP;
  1100.                                                             break;
  1101.                                                     }
  1102.                                                 }
  1103.  
  1104.                                                     /* Check cursor keys. */
  1105.  
  1106.                                                 switch(Char)
  1107.                                                 {
  1108.                                                         /* Scroll the buffer up. */
  1109.  
  1110.                                                     case CUP:    if(Qualifier & IEQUALIFIER_CONTROL)
  1111.                                                             {
  1112.                                                                 if(MarkedArea)
  1113.                                                                     MarkArea(-1,-1,-1);
  1114.  
  1115.                                                                 if(CurrentLine)
  1116.                                                                 {
  1117.                                                                     DisplayedLines = RedrawScreen(CurrentLine = 0);
  1118.  
  1119.                                                                     GT_SetGadgetAttrs(BufferGadget,BufferWindow,NULL,
  1120.                                                                         GTSC_Top,    0,
  1121.                                                                         GTSC_Total,    Lines,
  1122.                                                                         GTSC_Visible,    BufLine,
  1123.                                                                     TAG_DONE);
  1124.                                                                 }
  1125.  
  1126.                                                                 break;
  1127.                                                             }
  1128.  
  1129.                                                             if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  1130.                                                             {
  1131.                                                                 LONG NewCurrentLine;
  1132.  
  1133.                                                                 if((NewCurrentLine = CurrentLine - BufLine) < 0)
  1134.                                                                     NewCurrentLine = 0;
  1135.  
  1136.                                                                 if(MarkedArea)
  1137.                                                                     MarkArea(-1,-1,-1);
  1138.  
  1139.                                                                 if(NewCurrentLine != CurrentLine)
  1140.                                                                 {
  1141.                                                                     DisplayedLines = RedrawScreen(CurrentLine = NewCurrentLine);
  1142.  
  1143.                                                                     GT_SetGadgetAttrs(BufferGadget,BufferWindow,NULL,
  1144.                                                                         GTSC_Top,    CurrentLine,
  1145.                                                                         GTSC_Total,    Lines,
  1146.                                                                         GTSC_Visible,    BufLine,
  1147.                                                                     TAG_DONE);
  1148.                                                                 }
  1149.  
  1150.                                                                 break;
  1151.                                                             }
  1152.  
  1153.                                                             if(CurrentLine)
  1154.                                                             {
  1155.                                                                 if(MarkedArea)
  1156.                                                                     MarkArea(-1,-1,-1);
  1157.  
  1158.                                                                 if(DisplayedLines)
  1159.                                                                     ScrollRaster(BPort,0,-8,0,0,(BufCols << 3) - 1,(DisplayedLines << 3) - 1);
  1160.  
  1161.                                                                 CurrentLine--;
  1162.  
  1163.                                                                 ObtainSemaphore(BufferSemaphore);
  1164.  
  1165.                                                                 PrintLine(BufferLines[CurrentLine],0);
  1166.  
  1167.                                                                 ReleaseSemaphore(BufferSemaphore);
  1168.  
  1169.                                                                 if(DisplayedLines < BufLine)
  1170.                                                                     DisplayedLines++;
  1171.                                                             }
  1172.  
  1173.                                                             break;
  1174.  
  1175.                                                         /* Scroll the buffer down. */
  1176.     
  1177.                                                     case CDN:    if(Qualifier & IEQUALIFIER_CONTROL)
  1178.                                                             {
  1179.                                                                 LONG NewCurrentLine;
  1180.  
  1181.                                                                 if((NewCurrentLine = Lines - BufLine) < 0)
  1182.                                                                     NewCurrentLine = 0;
  1183.  
  1184.                                                                 if(MarkedArea)
  1185.                                                                     MarkArea(-1,-1,-1);
  1186.  
  1187.                                                                 if(CurrentLine != NewCurrentLine)
  1188.                                                                 {
  1189.                                                                     DisplayedLines = RedrawScreen(CurrentLine = NewCurrentLine);
  1190.  
  1191.                                                                     GT_SetGadgetAttrs(BufferGadget,BufferWindow,NULL,
  1192.                                                                         GTSC_Top,    CurrentLine,
  1193.                                                                         GTSC_Total,    Lines,
  1194.                                                                         GTSC_Visible,    BufLine,
  1195.                                                                     TAG_DONE);
  1196.                                                                 }
  1197.  
  1198.                                                                 break;
  1199.                                                             }
  1200.  
  1201.                                                             if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  1202.                                                             {
  1203.                                                                 LONG NewCurrentLine;
  1204.  
  1205.                                                                 if((NewCurrentLine = CurrentLine + (2 * BufLine)) > Lines)
  1206.                                                                     NewCurrentLine = Lines;
  1207.  
  1208.                                                                 if((NewCurrentLine = NewCurrentLine - BufLine) < 0)
  1209.                                                                     NewCurrentLine = 0;
  1210.  
  1211.                                                                 if(MarkedArea)
  1212.                                                                     MarkArea(-1,-1,-1);
  1213.  
  1214.                                                                 if(NewCurrentLine != CurrentLine)
  1215.                                                                 {
  1216.                                                                     DisplayedLines = RedrawScreen(CurrentLine = NewCurrentLine);
  1217.  
  1218.                                                                     GT_SetGadgetAttrs(BufferGadget,BufferWindow,NULL,
  1219.                                                                         GTSC_Top,    CurrentLine,
  1220.                                                                         GTSC_Total,    Lines,
  1221.                                                                         GTSC_Visible,    BufLine,
  1222.                                                                     TAG_DONE);
  1223.                                                                 }
  1224.  
  1225.                                                                 break;
  1226.                                                             }
  1227.  
  1228.                                                             if(CurrentLine + BufLine < Lines)
  1229.                                                             {
  1230.                                                                 if(MarkedArea)
  1231.                                                                     MarkArea(-1,-1,-1);
  1232.  
  1233.                                                                 if(DisplayedLines)
  1234.                                                                     ScrollRaster(BPort,0,8,0,0,(BufCols << 3) - 1,(DisplayedLines << 3) - 1);
  1235.  
  1236.                                                                 ObtainSemaphore(BufferSemaphore);
  1237.  
  1238.                                                                 PrintLine(BufferLines[CurrentLine + BufLine],BufLine - 1);
  1239.  
  1240.                                                                 ReleaseSemaphore(BufferSemaphore);
  1241.  
  1242.                                                                 CurrentLine++;
  1243.  
  1244.                                                                 if(DisplayedLines < BufLine)
  1245.                                                                     DisplayedLines++;
  1246.                                                             }
  1247.  
  1248.                                                             break;
  1249.  
  1250.                                                     default:    break;
  1251.                                                 }
  1252.                                             }
  1253.  
  1254.                                             continue;
  1255.                                         }
  1256.  
  1257.                                             /* User hit a mouse button. */
  1258.  
  1259.                                         if(Class == IDCMP_MOUSEBUTTONS)
  1260.                                         {
  1261.                                             BYTE SkipLoop = FALSE;
  1262.                                             LONG ThisLine,ThisColumn,MyColumn,LastColumn,SomeColumn;
  1263.                                             UBYTE *TheLine;
  1264.  
  1265.                                                 /* Remember initial mouse position. */
  1266.  
  1267.                                             ThisColumn    = Massage -> MouseX >> 3;
  1268.                                             ThisLine    = Massage -> MouseY >> 3;
  1269.  
  1270.                                             if(MarkedArea)
  1271.                                                 MarkArea(-1,-1,-1);
  1272.  
  1273.                                                 /* Reasonable dimensions? */
  1274.  
  1275.                                             if(ThisLine < DisplayedLines)
  1276.                                             {
  1277.                                                     /* Find the approriate line and its length. */
  1278.  
  1279.                                                 TheLine        = BufferLines[CurrentLine + ThisLine];
  1280.                                                 LastColumn    = ((ULONG *)BufferLines[CurrentLine + ThisLine])[-1];
  1281.  
  1282.                                                     /* Resonable dimensions? */
  1283.  
  1284.                                                 if(ThisColumn < LastColumn)
  1285.                                                 {
  1286.                                                     MyColumn = ThisColumn;
  1287.  
  1288.                                                     ReportMouse(TRUE,BufferWindow);
  1289.  
  1290.                                                         /* Loop until left mouse button is release. */
  1291.  
  1292.                                                     while(!SkipLoop)
  1293.                                                     {
  1294.                                                         SignalSet = Wait(SIGBREAKF_CTRL_F | (1 << BufferWindow -> UserPort -> mp_SigBit));
  1295.  
  1296.                                                             /* Contents of the buffer has changed! */
  1297.  
  1298.                                                         if(SignalSet & SIGBREAKF_CTRL_F)
  1299.                                                         {
  1300.                                                             if(FoundY)
  1301.                                                                 FoundY--;
  1302.  
  1303.                                                             DisplayBeep(BufferScreen);
  1304.                                                             break;
  1305.                                                         }
  1306.  
  1307.                                                         while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
  1308.                                                         {
  1309.                                                             Class    = Massage -> Class;
  1310.                                                             Code    = Massage -> Code;
  1311.  
  1312.                                                             ReplyMsg(Massage);
  1313.  
  1314.                                                                 /* We're finished! */
  1315.  
  1316.                                                             if(Class == IDCMP_MOUSEBUTTONS && Code == SELECTUP)
  1317.                                                             {
  1318.                                                                 SkipLoop = TRUE;
  1319.  
  1320.                                                                     /* Did we get a reasonable mouse
  1321.                                                                      * position?
  1322.                                                                      */
  1323.  
  1324.                                                                 if(MyColumn != ThisColumn)
  1325.                                                                 {
  1326.                                                                         /* Preserve right order of
  1327.                                                                          * numbers.
  1328.                                                                          */
  1329.  
  1330.                                                                     if(MyColumn < ThisColumn)
  1331.                                                                     {
  1332.                                                                         LONG Help;
  1333.  
  1334.                                                                         Help        = ThisColumn;
  1335.                                                                         ThisColumn    = MyColumn;
  1336.                                                                         MyColumn    = Help;
  1337.                                                                     }
  1338.  
  1339.                                                                         /* Restore the line. */
  1340.  
  1341.                                                                     if(MyColumn < LastColumn)
  1342.                                                                         LastColumn = MyColumn;
  1343.  
  1344.                                                                     MarkArea(-1,-1,-1);
  1345.  
  1346.                                                                         /* Clip the contents of the line to
  1347.                                                                          * the clipboard.
  1348.                                                                          */
  1349.  
  1350.                                                                     SaveClip(&TheLine[ThisColumn],MyColumn - ThisColumn);
  1351.                                                                 }
  1352.  
  1353.                                                                 break;
  1354.                                                             }
  1355.  
  1356.                                                                 /* The mouse has moved. */
  1357.  
  1358.                                                             if(Class == IDCMP_MOUSEMOVE)
  1359.                                                             {
  1360.                                                                 STATIC LONG OldColumn = ~0;
  1361.  
  1362.                                                                     /* Determine new mouse position. */
  1363.  
  1364.                                                                 SomeColumn = MyColumn;
  1365.  
  1366.                                                                 MyColumn = Massage -> MouseX >> 3;
  1367.  
  1368.                                                                 if((Massage -> MouseY >> 3) < ThisLine)
  1369.                                                                     MyColumn = 0;
  1370.  
  1371.                                                                 if((Massage -> MouseY >> 3) > ThisLine)
  1372.                                                                     MyColumn = LastColumn;
  1373.  
  1374.                                                                     /* Don't redraw the line if nothing
  1375.                                                                      * has changed.
  1376.                                                                      */
  1377.  
  1378.                                                                 if(OldColumn != MyColumn)
  1379.                                                                 {
  1380.                                                                     OldColumn = MyColumn;
  1381.  
  1382.                                                                         /* Reasonable position? */
  1383.  
  1384.                                                                     if(MyColumn <= LastColumn)
  1385.                                                                     {
  1386.                                                                         if(MyColumn >= 0)
  1387.                                                                         {
  1388.                                                                                 /* Highlight the selected
  1389.                                                                                  * area (invert).
  1390.                                                                                  */
  1391.  
  1392.                                                                             if(MyColumn != ThisColumn)
  1393.                                                                             {
  1394.                                                                                 if(MyColumn < ThisColumn)
  1395.                                                                                     MarkArea(MyColumn,ThisLine,ThisColumn - MyColumn);
  1396.                                                                                 else
  1397.                                                                                     MarkArea(ThisColumn,ThisLine,MyColumn - ThisColumn);
  1398.                                                                             }
  1399.                                                                         }
  1400.                                                                     }
  1401.                                                                     else
  1402.                                                                         MyColumn = SomeColumn;
  1403.                                                                 }
  1404.                                                             }
  1405.                                                         }
  1406.                                                     }
  1407.  
  1408.                                                     ReportMouse(FALSE,BufferWindow);
  1409.                                                 }
  1410.                                             }
  1411.                                         }
  1412.  
  1413.                                         if(Class == IDCMP_MENUPICK)
  1414.                                         {
  1415.                                             struct MenuItem *MenuItem;
  1416.  
  1417.                                             while(Code != MENUNULL)
  1418.                                             {
  1419.                                                 MenuItem = ItemAddress(BufferMenuStrip,Code);
  1420.  
  1421.                                                 switch((ULONG)MENU_USERDATA(MenuItem))
  1422.                                                 {
  1423.                                                     case MEN_SEARCH:    BufferWindow -> Flags |= WFLG_RMBTRAP;
  1424.                                                                 SetWait(BufferWindow);
  1425.  
  1426. GetTheString:                                                            if(Lines)
  1427.                                                                 {
  1428.                                                                     GT_SetGadgetAttrs(BufferGadget,BufferWindow,NULL,
  1429.                                                                         GA_Disabled,TRUE,
  1430.                                                                     TAG_DONE);
  1431.  
  1432.                                                                     if(GetSearchString(SearchBuffer))
  1433.                                                                     {
  1434.                                                                         FoundX = FoundY = 0;
  1435.  
  1436. SearchForIt:                                                                    LineNumber = -1;
  1437.  
  1438.                                                                         if(FoundY == 0 && CurrentLine != 0)
  1439.                                                                             FoundY = CurrentLine;
  1440.  
  1441.                                                                         ObtainSemaphore(BufferSemaphore);
  1442.  
  1443.                                                                         LineNumber = Search(SearchBuffer,&FoundX,&FoundY,&SaveX);
  1444.  
  1445.                                                                         ReleaseSemaphore(BufferSemaphore);
  1446.  
  1447.                                                                         if(LineNumber == -1)
  1448.                                                                         {
  1449.                                                                             BlockWindows();
  1450.  
  1451.                                                                             MyEasyRequest(BufferWindow,"Didn't find \"%s\".","Continue",SearchBuffer);
  1452.  
  1453.                                                                             ReleaseWindows();
  1454.  
  1455.                                                                             FlushIMsg(BufferWindow);
  1456.  
  1457.                                                                             FoundX = FoundY = 0;
  1458.  
  1459.                                                                             if(MarkedArea)
  1460.                                                                                 MarkArea(-1,-1,-1);
  1461.                                                                         }
  1462.                                                                         else
  1463.                                                                         {
  1464.                                                                             if(LineNumber < CurrentLine)
  1465.                                                                             {
  1466.                                                                                 if(MarkedArea)
  1467.                                                                                     MarkArea(-1,-1,-1);
  1468.  
  1469.                                                                                 DisplayedLines = RedrawScreen(CurrentLine = 0);
  1470.  
  1471.                                                                                 GT_SetGadgetAttrs(BufferGadget,BufferWindow,NULL,
  1472.                                                                                     GTSC_Top,    CurrentLine,
  1473.                                                                                     GTSC_Total,    Lines,
  1474.                                                                                     GTSC_Visible,    BufLine,
  1475.                                                                                 TAG_DONE);
  1476.                                                                             }
  1477.                                                                             else
  1478.                                                                             {
  1479.                                                                                 if(LineNumber > CurrentLine + DisplayedLines - 1)
  1480.                                                                                 {
  1481.                                                                                     if(MarkedArea)
  1482.                                                                                         MarkArea(-1,-1,-1);
  1483.     
  1484.                                                                                     if(LineNumber >= Lines - BufLine)
  1485.                                                                                     {
  1486.                                                                                         LONG NewCurrentLine;
  1487.  
  1488.                                                                                         if((NewCurrentLine = Lines - BufLine) < 0)
  1489.                                                                                             NewCurrentLine = 0;
  1490.  
  1491.                                                                                         if(CurrentLine != NewCurrentLine)
  1492.                                                                                         {
  1493.                                                                                             DisplayedLines = RedrawScreen(CurrentLine = NewCurrentLine);
  1494.  
  1495.                                                                                             GT_SetGadgetAttrs(BufferGadget,BufferWindow,NULL,
  1496.                                                                                                 GTSC_Top,    CurrentLine,
  1497.                                                                                                 GTSC_Total,    Lines,
  1498.                                                                                                 GTSC_Visible,    BufLine,
  1499.                                                                                             TAG_DONE);
  1500.                                                                                         }
  1501.                                                                                     }
  1502.                                                                                     else
  1503.                                                                                     {
  1504.                                                                                         DisplayedLines = RedrawScreen(CurrentLine = LineNumber);
  1505.  
  1506.                                                                                         GT_SetGadgetAttrs(BufferGadget,BufferWindow,NULL,
  1507.                                                                                             GTSC_Top,    CurrentLine,
  1508.                                                                                             GTSC_Total,    Lines,
  1509.                                                                                             GTSC_Visible,    BufLine,
  1510.                                                                                         TAG_DONE);
  1511.                                                                                     }
  1512.                                                                                 }
  1513.                                                                             }
  1514.  
  1515.                                                                             MarkArea(SaveX,LineNumber - CurrentLine,strlen(SearchBuffer));
  1516.                                                                         }
  1517.  
  1518.                                                                         FoundY = (FoundY + 1) % Lines;
  1519.                                                                     }
  1520.  
  1521.                                                                     GT_SetGadgetAttrs(BufferGadget,BufferWindow,NULL,
  1522.                                                                         GA_Disabled,FALSE,
  1523.                                                                     TAG_DONE);
  1524.                                                                 }
  1525.                                                                 else
  1526.                                                                     MyEasyRequest(BufferWindow,"There isn't anything in the\nbuffer right now.","Continue");
  1527.  
  1528.                                                                 BufferWindow -> Flags &= ~WFLG_RMBTRAP;
  1529.                                                                 ClearPointer(BufferWindow);
  1530.                                                                 break;
  1531.  
  1532.                                                     case MEN_REPEAT:    BufferWindow -> Flags |= WFLG_RMBTRAP;
  1533.                                                                 SetWait(BufferWindow);
  1534.  
  1535.                                                                 if(!SearchBuffer[0])
  1536.                                                                     goto GetTheString;
  1537.                                                                 else
  1538.                                                                 {
  1539.                                                                     GT_SetGadgetAttrs(BufferGadget,BufferWindow,NULL,
  1540.                                                                         GA_Disabled,TRUE,
  1541.                                                                     TAG_DONE);
  1542.  
  1543.                                                                     goto SearchForIt;
  1544.                                                                 }
  1545.  
  1546.                                                     case MEN_GOTO:        BumpWindow(TopWindow);
  1547.                                                                 break;
  1548.  
  1549.                                                     case MEN_QUITBUF:
  1550.                                                     case MEN_CLOSEBUF:    BufferTerminated = TRUE;
  1551.                                                                 break;
  1552.  
  1553.                                                     case MEN_CLEARBUF:    if(Lines)
  1554.                                                                 {
  1555.                                                                     BlockWindows();
  1556.  
  1557.                                                                     SetWait(BufferWindow);
  1558.  
  1559.                                                                     BufferWindow -> Flags |= WFLG_RMBTRAP;
  1560.  
  1561.                                                                     if(MyEasyRequest(BufferWindow,"The buffer still holds %ld lines,\ndo you wish to discard them?","Yes|No",Lines))
  1562.                                                                     {
  1563.                                                                         ClearBuffer();
  1564.  
  1565.                                                                         MarkedArea = FALSE;
  1566.  
  1567.                                                                         ClearPointer(BufferWindow);
  1568.  
  1569.                                                                         BufferWindow -> Flags &= ~WFLG_RMBTRAP;
  1570.  
  1571.                                                                         ReleaseWindows();
  1572.  
  1573.                                                                         FlushIMsg(BufferWindow);
  1574.  
  1575.                                                                         goto Restart;
  1576.                                                                     }
  1577.  
  1578.                                                                     ClearPointer(BufferWindow);
  1579.  
  1580.                                                                     BufferWindow -> Flags &= ~WFLG_RMBTRAP;
  1581.  
  1582.                                                                     ReleaseWindows();
  1583.  
  1584.                                                                     FlushIMsg(BufferWindow);
  1585.                                                                 }
  1586.  
  1587.                                                                 break;
  1588.  
  1589.                                                     default:        break;
  1590.                                                 }
  1591.  
  1592.                                                 Code = MenuItem -> NextSelect;
  1593.                                             }
  1594.                                         }
  1595.                                     }
  1596.                                 }
  1597.  
  1598.                                 RemoveGList(BufferWindow,GadgetList,(UWORD)-1);
  1599.  
  1600.                                 FreeGadgets(GadgetList);
  1601.  
  1602.                                 BufferGadget = NULL;
  1603.                             }
  1604.  
  1605.                             BumpWindow(TopWindow);
  1606.  
  1607.                             MarkArea(-1,-1,-1);
  1608.  
  1609.                             ScreenToBack(BufferScreen);
  1610.  
  1611.                             BufferWindow -> Flags |= WFLG_RMBTRAP;
  1612.  
  1613.                             ClearMenuStrip(BufferWindow);
  1614.  
  1615.                             CloseWindow(BufferWindow);
  1616.                         }
  1617.                     }
  1618.  
  1619.                     FreeMenus(BufferMenuStrip);
  1620.                 }
  1621.  
  1622.                 FreeVisualInfo(BufferVisualInfo);
  1623.             }
  1624.  
  1625.             CloseScreen(BufferScreen);
  1626.         }
  1627.     }
  1628.  
  1629.     Forbid();
  1630.  
  1631.     BufferProcess = NULL;
  1632.  
  1633.     Signal(ThisProcess,SIGBREAKF_CTRL_C);
  1634. }
  1635.