home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / amiga / comms / comprgs / term232.lha / Source_Code / termSource / termBuffer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-22  |  42.8 KB  |  1,805 lines

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