home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d8xx / d834 / pinfocom.lha / PInfoCom / pinfocom-3.0.lha / amiga_console.c < prev    next >
C/C++ Source or Header  |  1993-02-21  |  100KB  |  4,934 lines

  1. /* amiga_console.c
  2.  *
  3.  *  ``pinfocom'' -- a portable Infocom Inc. data file interpreter.
  4.  *  Copyright (C) 1987-1992  InfoTaskForce
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; see the file COPYING.  If not, write to the
  18.  *  Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. /*
  22.  * $Header$
  23.  */
  24.  
  25. #ifndef _AMIGA_GLOBAL_H
  26. #include "amiga_global.h"
  27. #endif    /* !_AMIGA_GLOBAL_H */
  28.  
  29.     /* ConLayerSetup(LONG Width,LONG Height):
  30.      *
  31.      *    Set up hidden drawing area.
  32.      */
  33.  
  34. Bool
  35. ConLayerSetup(LONG Width,LONG Height)
  36. {
  37.     if(!(PadBitMap = (struct BitMap *)AllocMem(sizeof(struct BitMap),MEMF_ANY)))
  38.         return(FALSE);
  39.  
  40.     InitBitMap(PadBitMap,1,PadBitMapWidth = Width,PadBitMapHeight = Height);
  41.  
  42.     if(!(PadBitMap -> Planes[0] = AllocRaster(PadBitMapWidth,PadBitMapHeight)))
  43.         return(FALSE);
  44.  
  45.     if(!(PadLayerInfo = NewLayerInfo()))
  46.         return(FALSE);
  47.  
  48.     if(!(PadLayer = CreateBehindLayer(PadLayerInfo,PadBitMap,0,0,PadBitMapWidth - 1,PadBitMapHeight - 1,LAYERSIMPLE,NULL)))
  49.         return(FALSE);
  50.  
  51.     PadRPort = PadLayer -> rp;
  52.  
  53.     SetDrMd(PadRPort,JAM1);
  54.     SetAPen(PadRPort,1);
  55.     SetBPen(PadRPort,0);
  56.  
  57.     return(TRUE);
  58. }
  59.  
  60.     /* ConLayerCleanup():
  61.      *
  62.      *    Dispose hidden drawing area.
  63.      */
  64.  
  65. VOID
  66. ConLayerCleanup()
  67. {
  68.     if(PadLayer)
  69.     {
  70.         DeleteLayer(NULL,PadLayer);
  71.  
  72.         PadLayer = NULL;
  73.     }
  74.  
  75.     if(PadLayerInfo)
  76.     {
  77.         DisposeLayerInfo(PadLayerInfo);
  78.  
  79.         PadLayerInfo = NULL;
  80.     }
  81.  
  82.     if(PadBitMap)
  83.     {
  84.         if(PadBitMap -> Planes[0])
  85.             FreeRaster(PadBitMap -> Planes[0],PadBitMapWidth,PadBitMapHeight);
  86.  
  87.         FreeMem(PadBitMap,sizeof(struct BitMap));
  88.  
  89.         PadBitMap = NULL;
  90.     }
  91. }
  92.  
  93.     /* ConUnblockWindow(struct Window *Window):
  94.      *
  95.      *    Remove blocking requester and mouse pointer.
  96.      */
  97.  
  98. VOID
  99. ConUnblockWindow(struct Window *Window)
  100. {
  101.     struct BlockedWindow     *Blocker    =  BlockedWindows,
  102.                 **LastBlocker    = &BlockedWindows;
  103.  
  104.     while(Blocker)
  105.     {
  106.         if(Blocker -> bw_Window == Window)
  107.         {
  108.             if(Blocker -> bw_Requester)
  109.                 EndRequest(Blocker -> bw_Requester,Window);
  110.  
  111. #ifdef WA_BusyPointer
  112.             if(IntuitionBase -> LibNode . lib_Version >= 39)
  113.                 SetWindowPointer(Window,TAG_DONE);
  114.             else
  115. #endif    /* WA_BusyPointer */
  116.                 ClearPointer(Window);
  117.  
  118.             *LastBlocker = Blocker -> bw_Next;
  119.  
  120.             FreeVec(Blocker);
  121.  
  122.             break;
  123.         }
  124.         else
  125.         {
  126.             LastBlocker = &Blocker -> bw_Next;
  127.  
  128.             Blocker = Blocker -> bw_Next;
  129.         }
  130.     }
  131. }
  132.  
  133.     /* ConBlockWindow(struct Window *Window):
  134.      *
  135.      *    Block window input, attach a `Wait...' mouse pointer.
  136.      */
  137.  
  138. VOID
  139. ConBlockWindow(struct Window *Window)
  140. {
  141.     struct BlockedWindow *Blocker;
  142.  
  143.     if(Blocker = (struct BlockedWindow *)AllocVec(sizeof(struct BlockedWindow) + sizeof(struct Requester),MEMF_PUBLIC | MEMF_CLEAR))
  144.     {
  145.         Blocker -> bw_Next    = BlockedWindows;
  146.         Blocker -> bw_Window    = Window;
  147.         Blocker -> bw_Requester    = (struct Requester *)(Blocker + 1);
  148.  
  149.         BlockedWindows = Blocker;
  150.  
  151.         if(!Request(Blocker -> bw_Requester,Window))
  152.             Blocker -> bw_Requester = NULL;
  153.  
  154. #ifdef WA_BusyPointer
  155.         if(IntuitionBase -> LibNode . lib_Version >= 39)
  156.         {
  157.             SetWindowPointer(Window,
  158.                 WA_BusyPointer,TRUE,
  159.             TAG_DONE);
  160.         }
  161.         else
  162. #endif    /* WA_BusyPointer */
  163.         {
  164.             if(ChipData)
  165.                 SetPointer(Window,&ChipData[CHIPDATA_POINTER],STOPWATCH_HEIGHT,STOPWATCH_WIDTH,STOPWATCH_LEFT_OFFSET,STOPWATCH_TOP_OFFSET);
  166.         }
  167.     }
  168. }
  169.  
  170.     /* ConCharWidth(const UBYTE Char):
  171.      *
  172.      *    Calculate the pixel width of a glyph.
  173.      */
  174.  
  175. WORD
  176. ConCharWidth(const UBYTE Char)
  177. {
  178.     return(TextLength(RPort,(STRPTR)&Char,1));
  179. }
  180.  
  181.     /* ConCursorOff():
  182.      *
  183.      *    Turn the terminal cursor on.
  184.      */
  185.  
  186. VOID
  187. ConCursorOff()
  188. {
  189.         /* Is it still enabled? */
  190.  
  191.     if(CursorEnabled)
  192.     {
  193.         LONG    Left    = LastCursorX + WindowBorderLeft,
  194.             Top    = LastCursorY + WindowBorderTop;
  195.  
  196.             /* Turn on xor operation. */
  197.  
  198.         SetDrMd(RPort,JAM1 | COMPLEMENT);
  199.  
  200.             /* Complement all planes. */
  201.  
  202.         SetAPen(RPort,DepthMask);
  203.  
  204.             /* Is the window inactive? */
  205.  
  206.         if(!WindowIsActive)
  207.         {
  208.                 /* Set the cross-hatch pattern. */
  209.  
  210.             SetAfPt(RPort,&ChipData[CHIPDATA_PATTERN],1);
  211.  
  212.                 /* Render the cursor data. */
  213.  
  214.             RectFill(RPort,Left,Top,Left + NewCursorWidth - 1,Top + TextFontHeight - 1);
  215.  
  216.                 /* Reset the pattern. */
  217.  
  218.             SetAfPt(RPort,NULL,0);
  219.         }
  220.         else
  221.             RectFill(RPort,Left,Top,Left + NewCursorWidth - 1,Top + TextFontHeight - 1);
  222.  
  223.             /* Reset the drawing mode. */
  224.  
  225.         SetDrMd(RPort,JAM2);
  226.  
  227.             /* Reset the drawing pen. */
  228.  
  229.         SetAPen(RPort,ConTextPen);
  230.  
  231.             /* It's turned off now. */
  232.  
  233.         CursorEnabled = FALSE;
  234.     }
  235. }
  236.  
  237.     /* ConCursorOn(const int New):
  238.      *
  239.      *    Turn the terminal cursor off.
  240.      */
  241.  
  242. VOID
  243. ConCursorOn(const int New)
  244. {
  245.         /* Is it still disabled? */
  246.  
  247.     if(!CursorEnabled)
  248.     {
  249.         LONG    Left    = CursorX + WindowBorderLeft,
  250.             Top    = CursorY + WindowBorderTop;
  251.  
  252.             /* Remember new cursor width. */
  253.  
  254.         switch(New)
  255.         {
  256.             case CURSOR_NOCHANGE:    break;
  257.  
  258.             case CURSOR_AVERAGE:    NewCursorWidth = DefaultCursorWidth;
  259.                         break;
  260.  
  261.             default:        NewCursorWidth = New;
  262.                         break;
  263.         }
  264.  
  265.             /* Turn on xor operation. */
  266.  
  267.         SetDrMd(RPort,JAM1 | COMPLEMENT);
  268.  
  269.             /* Complement all planes. */
  270.  
  271.         SetAPen(RPort,DepthMask);
  272.  
  273.             /* Is the window inactive? */
  274.  
  275.         if(!WindowIsActive)
  276.         {
  277.                 /* Set the cross-hatch pattern. */
  278.  
  279.             SetAfPt(RPort,&ChipData[CHIPDATA_PATTERN],1);
  280.  
  281.                 /* Render the cursor data. */
  282.  
  283.             RectFill(RPort,Left,Top,Left + NewCursorWidth - 1,Top + TextFontHeight - 1);
  284.  
  285.                 /* Reset the pattern. */
  286.  
  287.             SetAfPt(RPort,NULL,0);
  288.         }
  289.         else
  290.             RectFill(RPort,Left,Top,Left + NewCursorWidth - 1,Top + TextFontHeight - 1);
  291.  
  292.             /* Reset the drawing mode. */
  293.  
  294.         SetDrMd(RPort,JAM2);
  295.  
  296.             /* Reset the drawing pen. */
  297.  
  298.         SetAPen(RPort,ConTextPen);
  299.  
  300.             /* Remember cursor width. */
  301.  
  302.         OldCursorWidth = NewCursorWidth;
  303.  
  304.             /* It's turn on now. */
  305.  
  306.         CursorEnabled = TRUE;
  307.  
  308.             /* Remember cursor position. */
  309.  
  310.         LastCursorX = CursorX;
  311.         LastCursorY = CursorY;
  312.     }
  313. }
  314.  
  315.     /* ConMove(const int Delta,const int New):
  316.      *
  317.      *    Move the cursor.
  318.      */
  319.  
  320. VOID
  321. ConMove(const int Delta,const int New)
  322. {
  323.         /* If the cursor is still enabled, turn it
  324.          * off before repositioning it.
  325.          */
  326.  
  327.     if(CursorEnabled)
  328.     {
  329.             /* Turn the cursor off. */
  330.  
  331.         ConCursorOff();
  332.  
  333.             /* Move it. */
  334.  
  335.         CursorX += Delta;
  336.  
  337.             /* Turn the cursor back on. */
  338.  
  339.         ConCursorOn(New);
  340.     }
  341.     else
  342.     {
  343.         CursorX += Delta;
  344.  
  345.         switch(New)
  346.         {
  347.             case CURSOR_NOCHANGE:    NewCursorWidth = OldCursorWidth;
  348.                         break;
  349.  
  350.             case CURSOR_AVERAGE:    NewCursorWidth = OldCursorWidth = DefaultCursorWidth;
  351.                         break;
  352.  
  353.             default:        NewCursorWidth = OldCursorWidth = New;
  354.                         break;
  355.         }
  356.     }
  357. }
  358.  
  359.     /* ConSet(const int X,const int Y,const int New):
  360.      *
  361.      *    Place the cursor at a specific position.
  362.      */
  363.  
  364. VOID
  365. ConSet(const int X,const int Y,const int New)
  366. {
  367.         /* If the cursor is still enabled, turn it
  368.          * off before repositioning it.
  369.          */
  370.  
  371.     if(CursorEnabled)
  372.     {
  373.             /* Turn the cursor off. */
  374.  
  375.         ConCursorOff();
  376.  
  377.             /* Move drawing pen. */
  378.  
  379.         Move(RPort,X + WindowBorderLeft,Y + ThisFont -> tf_Baseline + WindowBorderTop);
  380.  
  381.             /* Position the cursor. */
  382.  
  383.         CursorX = X;
  384.         CursorY = Y;
  385.  
  386.             /* Turn the cursor back on. */
  387.  
  388.         ConCursorOn(New);
  389.     }
  390.     else
  391.     {
  392.             /* Remember new cursor width. */
  393.  
  394.         switch(New)
  395.         {
  396.             case CURSOR_NOCHANGE:    NewCursorWidth = OldCursorWidth;
  397.                         break;
  398.  
  399.             case CURSOR_AVERAGE:    NewCursorWidth = OldCursorWidth = DefaultCursorWidth;
  400.                         break;
  401.  
  402.             default:        NewCursorWidth = OldCursorWidth = New;
  403.                         break;
  404.         }
  405.  
  406.             /* Move drawing pen. */
  407.  
  408.         Move(RPort,X + WindowBorderLeft,Y + ThisFont -> tf_Baseline + WindowBorderTop);
  409.  
  410.             /* Position the cursor. */
  411.  
  412.         CursorX = X;
  413.         CursorY = Y;
  414.     }
  415. }
  416.  
  417.     /* ConClearEOL():
  418.      *
  419.      *    Clear to end of current line.
  420.      */
  421.  
  422. VOID
  423. ConClearEOL()
  424. {
  425.         /* Is there anything to clear? */
  426.  
  427.     if(CursorX < WindowWidth)
  428.     {
  429.             /* Turn the cursor off before the line is cleared. */
  430.  
  431.         if(CursorEnabled)
  432.         {
  433.                 /* Turn the cursor off. */
  434.  
  435.             ConCursorOff();
  436.  
  437.                 /* Clear the remaining line. */
  438.  
  439.             SetAPen(RPort,ConBackPen);
  440.             RectFill(RPort,CursorX + WindowBorderLeft,CursorY + WindowBorderTop,Window -> Width - (WindowBorderRight + 1),CursorY + WindowBorderTop + TextFontHeight - 1);
  441.             SetAPen(RPort,ConTextPen);
  442.  
  443.                 /* Turn the cursor back on. */
  444.  
  445.             ConCursorOn(CURSOR_NOCHANGE);
  446.         }
  447.         else
  448.         {
  449.             SetAPen(RPort,ConBackPen);
  450.             RectFill(RPort,CursorX + WindowBorderLeft,CursorY + WindowBorderTop,Window -> Width - (WindowBorderRight + 1),CursorY + WindowBorderTop + TextFontHeight - 1);
  451.             SetAPen(RPort,ConTextPen);
  452.         }
  453.     }
  454. }
  455.  
  456.     /* ConCharBackspace(const int Delta,const int New):
  457.      *
  458.      *    Move the cursor one glyph back.
  459.      */
  460.  
  461. VOID
  462. ConCharBackspace(const int Delta,const int New)
  463. {
  464.     RedrawInputLine = TRUE;
  465.  
  466.     CursorX -= Delta;
  467.  
  468.     switch(New)
  469.     {
  470.         case CURSOR_NOCHANGE:    NewCursorWidth = OldCursorWidth;
  471.                     break;
  472.  
  473.         case CURSOR_AVERAGE:    NewCursorWidth = OldCursorWidth = DefaultCursorWidth;
  474.                     break;
  475.  
  476.         default:        NewCursorWidth = OldCursorWidth = New;
  477.                     break;
  478.     }
  479. }
  480.  
  481.     /* ConCharDelete(const int New):
  482.      *
  483.      *    Delete the character under the cursor.
  484.      */
  485.  
  486. VOID
  487. ConCharDelete(const int New)
  488. {
  489.     RedrawInputLine = TRUE;
  490.  
  491.     switch(New)
  492.     {
  493.         case CURSOR_NOCHANGE:    NewCursorWidth = OldCursorWidth;
  494.                     break;
  495.  
  496.         case CURSOR_AVERAGE:    NewCursorWidth = OldCursorWidth = DefaultCursorWidth;
  497.                     break;
  498.  
  499.         default:        NewCursorWidth = OldCursorWidth = New;
  500.                     break;
  501.     }
  502. }
  503.  
  504.     /* ConCharInsert(const UBYTE Char):
  505.      *
  506.      *    Insert a character at the current cursor position.
  507.      */
  508.  
  509. VOID
  510. ConCharInsert(const UBYTE Char)
  511. {
  512.     RedrawInputLine = TRUE;
  513.  
  514.     CursorX += ConCharWidth(Char);
  515. }
  516.  
  517.     /* ConScrollUp():
  518.      *
  519.      *    Scroll the terminal contents one line up.
  520.      */
  521.  
  522. VOID
  523. ConScrollUp()
  524. {
  525.         /* Inside the status line the cursor is always
  526.          * disabled.
  527.          */
  528.  
  529.     if(ConOutputWindow)
  530.         ScrollRaster(RPort,0,TextFontHeight,WindowBorderLeft,WindowBorderTop,Window -> Width - (WindowBorderRight + 1),ConNumStatusLines * TextFontHeight);
  531.     else
  532.     {
  533.             /* Is the cursor enabled? */
  534.  
  535.         if(CursorEnabled)
  536.         {
  537.                 /* Turn the cursor off. */
  538.  
  539.             ConCursorOff();
  540.  
  541.                 /* Scroll the terminal contents up. */
  542.  
  543.             if(gflags . pr_status || ConNumStatusLines > 1)
  544.                 ScrollRaster(RPort,0,TextFontHeight,WindowBorderLeft,ConNumStatusLines * TextFontHeight + WindowBorderTop,Window -> Width - (WindowBorderRight + 1),Window -> Height - (WindowBorderBottom + 1));
  545.             else
  546.                 ScrollRaster(RPort,0,TextFontHeight,WindowBorderLeft,WindowBorderTop,Window -> Width - (WindowBorderRight + 1),Window -> Height - (WindowBorderBottom + 1));
  547.  
  548.                 /* Reposition the cursor. */
  549.  
  550.             CursorX = 0;
  551.             CursorY = TextFontHeight * (ConNumLines - 1);
  552.  
  553.                 /* Turn it on again. */
  554.  
  555.             ConCursorOn(CURSOR_NOCHANGE);
  556.         }
  557.         else
  558.         {
  559.                 /* Scroll the terminal contents up. */
  560.  
  561.             if(gflags . pr_status || ConNumStatusLines > 1)
  562.                 ScrollRaster(RPort,0,TextFontHeight,WindowBorderLeft,ConNumStatusLines * TextFontHeight + WindowBorderTop,Window -> Width - (WindowBorderRight + 1),Window -> Height - (WindowBorderBottom + 1));
  563.             else
  564.                 ScrollRaster(RPort,0,TextFontHeight,WindowBorderLeft,WindowBorderTop,Window -> Width - (WindowBorderRight + 1),Window -> Height - (WindowBorderBottom + 1));
  565.  
  566.                 /* Reposition the cursor. */
  567.  
  568.             CursorX = 0;
  569.             CursorY = TextFontHeight * (ConNumLines - 1);
  570.         }
  571.     }
  572. }
  573.  
  574.     /* ConPad(const char *Line,LONG Len,LONG Indent):
  575.      *
  576.      *    Similar to ConWrite(), but pads the line contents
  577.      *    in order to make it fill the entire window width.
  578.      */
  579.  
  580. VOID
  581. ConPad(const char *Line,LONG Len,LONG Indent)
  582. {
  583.     int    Index        = 0,
  584.         Size        = 0,
  585.         Start        = 0,
  586.         i        = 0,
  587.         MaxWidth    = PadWidth;
  588.     Bool    Cursor        = CursorEnabled;
  589.  
  590.         /* Skip leading spaces. */
  591.  
  592.     while(i < Len && Line[i] == ' ')
  593.     {
  594.         Size++;
  595.  
  596.         i++;
  597.     }
  598.  
  599.         /* Run down the string... */
  600.  
  601.     while(i < Len)
  602.     {
  603.             /* Count the number of characters. */
  604.  
  605.         while(i < Len && Line[i] != ' ')
  606.         {
  607.             Size++;
  608.             i++;
  609.         }
  610.  
  611.             /* Store width and position. */
  612.  
  613.         PadLen[Index]    = Size;
  614.         PadSkip[Index]    = Start;
  615.  
  616.             /* Skip the spaces. */
  617.  
  618.         while(i < Len && Line[i] == ' ')
  619.             i++;
  620.  
  621.             /* Proceed to the next word. */
  622.  
  623.         Index++;
  624.  
  625.         Start = i;
  626.  
  627.         Size = 0;
  628.     }
  629.  
  630.         /* Turn the cursor off if still enabled. */
  631.  
  632.     if(CursorEnabled)
  633.         ConCursorOff();
  634.  
  635.         /* Are there any words to output? */
  636.  
  637.     if(Index > 1)
  638.     {
  639.         LONG    Count    = Index - 1,
  640.             Left    = 0,
  641.             Top    = ThisFont -> tf_Baseline;
  642.  
  643.             /* Determine the remaining space in between the words. */
  644.  
  645.         for(i = 0 ; i < Index ; i++)
  646.             MaxWidth -= TextLength(RPort,(STRPTR)&Line[PadSkip[i]],PadLen[i]);
  647.  
  648.             /* Clear the drawing area. */
  649.  
  650.         SetRast(PadRPort,0);
  651.  
  652.  
  653.         i = 0;
  654.  
  655.             /* Output the single words. */
  656.  
  657.         do
  658.         {
  659.                 /* This is where the magic takes place. The space
  660.                  * between the words is evenly distributed. I spent
  661.                  * a sleepless night trying to find the best possible
  662.                  * solution. Basically the magic number is simply
  663.                  * MaxWidth / Count, but as we are using integers for
  664.                  * calculation we have to take fractions into account.
  665.                  */
  666.  
  667.             if(i)
  668.                 Left = PadRPort -> cp_x + (MaxWidth * i) / Count - (MaxWidth * (i - 1)) / Count;
  669.  
  670.                 /* Print the text. */
  671.  
  672.             Move(PadRPort,Left,Top);
  673.             Text(PadRPort,(STRPTR)&Line[PadSkip[i]],PadLen[i]);
  674.  
  675.                 /* Skip to the next word. */
  676.  
  677.             i++;
  678.         }
  679.         while(--Index);
  680.  
  681.             /* Transfer the printed text. */
  682.  
  683.         ClipBlit(PadRPort,0,0,RPort,Indent + WindowBorderLeft,CursorY + WindowBorderTop,PadWidth,PadBitMapHeight,0xC0);
  684.     }
  685.     else
  686.     {
  687.         Move(RPort,Indent + CursorX + WindowBorderLeft,CursorY + ThisFont -> tf_Baseline + WindowBorderTop);
  688.         Text(RPort,(STRPTR)Line,Len);
  689.     }
  690.  
  691.         /* Turn the cursor back on. */
  692.  
  693.     if(Cursor)
  694.         ConCursorOn(CURSOR_NOCHANGE);
  695. }
  696.  
  697.     /* ConWrite(const char *Line,LONG Len,LONG Indent):
  698.      *
  699.      *    Output a text on the terminal.
  700.      */
  701.  
  702. VOID
  703. ConWrite(const char *Line,LONG Len,LONG Indent)
  704. {
  705.         /* Just like console.device, determine the
  706.          * text length if -1 is passed in as the
  707.          * length.
  708.          */
  709.  
  710.     if(Len == -1)
  711.         Len = strlen(Line);
  712.  
  713.         /* Is there anything to print? */
  714.  
  715.     if(Len)
  716.     {
  717.             /* Is the cursor still enabled? */
  718.  
  719.         if(CursorEnabled)
  720.         {
  721.                 /* Turn off the cursor. */
  722.  
  723.             ConCursorOff();
  724.  
  725.                 /* Print the text. */
  726.  
  727.             Move(RPort,Indent + CursorX + WindowBorderLeft,CursorY + ThisFont -> tf_Baseline + WindowBorderTop);
  728.             Text(RPort,(STRPTR)Line,Len);
  729.  
  730.                 /* Move up. */
  731.  
  732.             CursorX += TextLength(RPort,(STRPTR)Line,Len);
  733.  
  734.                 /* Turn the cursor back on. */
  735.  
  736.             ConCursorOn(CURSOR_NOCHANGE);
  737.         }
  738.         else
  739.         {
  740.                 /* Print the text. */
  741.  
  742.             Move(RPort,Indent + CursorX + WindowBorderLeft,CursorY + ThisFont -> tf_Baseline + WindowBorderTop);
  743.             Text(RPort,(STRPTR)Line,Len);
  744.  
  745.                 /* Move up. */
  746.  
  747.             CursorX += TextLength(RPort,(STRPTR)Line,Len);
  748.         }
  749.     }
  750. }
  751.  
  752.     /* ConRedraw(const int X,const int Y,const STRPTR String,const int Len):
  753.      *
  754.      *    Redraw the input string.
  755.      */
  756.  
  757. VOID
  758. ConRedraw(const int X,const int Y,const STRPTR String,const int Len)
  759. {
  760.         /* Determine width in pixels. */
  761.  
  762.     int Width = TextLength(RPort,(STRPTR)String,Len);
  763.  
  764.         /* Turn the cursor off. */
  765.  
  766.     ConCursorOff();
  767.  
  768.         /* Redraw the input string. */
  769.  
  770.     Move(RPort,X + WindowBorderLeft,Y + ThisFont -> tf_Baseline + WindowBorderTop);
  771.     Text(RPort,(STRPTR)String,Len);
  772.  
  773.         /* Clear to end of line. */
  774.  
  775.     if(Width < WindowWidth)
  776.     {
  777.         SetAPen(RPort,ConBackPen);
  778.         RectFill(RPort,X + Width + WindowBorderLeft,Y + WindowBorderTop,Window -> Width - (WindowBorderRight + 1),Y + WindowBorderTop + TextFontHeight - 1);
  779.         SetAPen(RPort,ConTextPen);
  780.     }
  781.  
  782.         /* Turn the cursor back on. */
  783.  
  784.     ConCursorOn(CURSOR_NOCHANGE);
  785. }
  786.  
  787.     /* ConSetColour(const int Colour):
  788.      *
  789.      *    Set the text rendering colours. If running on a monochrome
  790.      *    display, the colours will be mapped to text style attributes.
  791.      */
  792.  
  793. VOID
  794. ConSetColour(const int Colour)
  795. {
  796.         /* Are we running on a monochrome display? */
  797.  
  798.     Bool IsMono = (Depth == 1 || !NewOS);
  799.  
  800.         /* The following code decides which text rendering colour
  801.          * to set.
  802.          */
  803.  
  804.     switch(Colour)
  805.     {
  806.             /* Text input colour. */
  807.  
  808.         case COLOUR_INPUT:    if(IsMono)
  809.                     {
  810.                         SetAPen(RPort,ConTextPen = 1);
  811.                         SetBPen(RPort,ConBackPen = 0);
  812.  
  813.                         SetSoftStyle(RPort,FS_NORMAL,AskSoftStyle(RPort));
  814.                     }
  815.                     else
  816.                     {
  817.                         SetAPen(RPort,ConTextPen = 2);
  818.                         SetBPen(RPort,ConBackPen = 0);
  819.                     }
  820.  
  821.                     break;
  822.  
  823.             /* Status line colour. */
  824.  
  825.         case COLOUR_STATUS:    if(IsMono)
  826.                     {
  827.                         SetAPen(RPort,ConTextPen = 0);
  828.                         SetBPen(RPort,ConBackPen = 1);
  829.  
  830.                         SetSoftStyle(RPort,FS_NORMAL,AskSoftStyle(RPort));
  831.                     }
  832.                     else
  833.                     {
  834.                         SetAPen(RPort,ConTextPen = 2);
  835.                         SetBPen(RPort,ConBackPen = 3);
  836.                     }
  837.  
  838.                     break;
  839.  
  840.             /* Error message colour. */
  841.  
  842.         case COLOUR_ERROR:    if(IsMono)
  843.                     {
  844.                         SetAPen(RPort,ConTextPen = 1);
  845.                         SetBPen(RPort,ConBackPen = 0);
  846.  
  847.                         SetSoftStyle(RPort,FSF_UNDERLINED,AskSoftStyle(RPort));
  848.                     }
  849.                     else
  850.                     {
  851.                         SetAPen(RPort,ConTextPen = 3);
  852.                         SetBPen(RPort,ConBackPen = 0);
  853.                     }
  854.  
  855.                     break;
  856.  
  857.             /* Special emphasis colour. */
  858.  
  859.         case COLOUR_SPECIAL:    if(IsMono)
  860.                     {
  861.                         SetAPen(RPort,ConTextPen = 1);
  862.                         SetBPen(RPort,ConBackPen = 0);
  863.  
  864.                         SetSoftStyle(RPort,FSF_BOLD,AskSoftStyle(RPort));
  865.                     }
  866.                     else
  867.                     {
  868.                         SetAPen(RPort,ConTextPen = 2);
  869.                         SetBPen(RPort,ConBackPen = 0);
  870.                     }
  871.  
  872.                     break;
  873.  
  874.             /* Standard text colour. */
  875.  
  876.         default:        SetAPen(RPort,ConTextPen = 1);
  877.                     SetBPen(RPort,ConBackPen = 0);
  878.  
  879.                     if(IsMono)
  880.                         SetSoftStyle(RPort,FS_NORMAL,AskSoftStyle(RPort));
  881.  
  882.                     break;
  883.     }
  884. }
  885.  
  886.     /* ConSetFont(const int Font):
  887.      *
  888.      *    Change the current text rendering font.
  889.      */
  890.  
  891. VOID
  892. ConSetFont(const int Font)
  893. {
  894.         /* Which font type are we to set? */
  895.  
  896.     switch(Font)
  897.     {
  898.             /* Use the fixed-width font. */
  899.  
  900.         case FONT_FIXED:
  901.  
  902.             if(ThisFont != FixedFont)
  903.             {
  904.                 SetFont(RPort,ThisFont = FixedFont);
  905.                 SetFont(PadRPort,ThisFont);
  906.             }
  907.  
  908.             break;
  909.  
  910.             /* Use the proportional-spaced font. */
  911.  
  912.         case FONT_PROP:
  913.  
  914.             if(ThisFont != PropFont)
  915.             {
  916.                 SetFont(RPort,ThisFont = PropFont);
  917.                 SetFont(PadRPort,ThisFont);
  918.             }
  919.  
  920.             break;
  921.     }
  922. }
  923.  
  924.     /* ConSetKey(const int Key,const STRPTR String,const int Len):
  925.      *
  926.      *    Set a specific function key.
  927.      */
  928.  
  929. VOID
  930. ConSetKey(const int Key,const STRPTR String,const int Len)
  931. {
  932.         /* Is the new string longer than the old one? */
  933.  
  934.     if(FunctionKeys[Key] . sb_Len < Len)
  935.     {
  936.             /* Free previous key assignment. */
  937.  
  938.         free(FunctionKeys[Key] . sb_Buffer);
  939.  
  940.             /* Create new string buffer. */
  941.  
  942.         if(FunctionKeys[Key] . sb_Buffer = (char *)malloc(Len + 1))
  943.         {
  944.                 /* Copy the key string. */
  945.  
  946.             memcpy(FunctionKeys[Key] . sb_Buffer,String,Len);
  947.  
  948.                 /* Provide null-termination. */
  949.  
  950.             FunctionKeys[Key] . sb_Buffer[Len] = 0;
  951.  
  952.                 /* Set string length. */
  953.  
  954.             FunctionKeys[Key] . sb_Len = Len;
  955.         }
  956.         else
  957.             FunctionKeys[Key] . sb_Len = 0;
  958.     }
  959.     else
  960.     {
  961.             /* Install new string. */
  962.  
  963.         if(Len)
  964.         {
  965.                 /* Copy the key string. */
  966.  
  967.             memcpy(FunctionKeys[Key] . sb_Buffer,String,Len);
  968.  
  969.                 /* Provide null-termination. */
  970.  
  971.             FunctionKeys[Key] . sb_Buffer[Len] = 0;
  972.         }
  973.         else
  974.         {
  975.                 /* Zero length, free previous buffer
  976.                  * assignment.
  977.                  */
  978.  
  979.             if(FunctionKeys[Key] . sb_Buffer)
  980.             {
  981.                     /* Free the buffer. */
  982.  
  983.                 free(FunctionKeys[Key] . sb_Buffer);
  984.  
  985.                     /* Clear address pointer. */
  986.  
  987.                 FunctionKeys[Key] . sb_Buffer = NULL;
  988.             }
  989.         }
  990.  
  991.             /* Install new length. */
  992.  
  993.         FunctionKeys[Key] . sb_Len = Len;
  994.     }
  995. }
  996.  
  997.     /* ConOpenLibs():
  998.      *
  999.      *    Open required system libraries.
  1000.      */
  1001.  
  1002. Bool
  1003. ConOpenLibs()
  1004. {
  1005.     if(!LibsOpened)
  1006.     {
  1007.             /* Remember default window pointer. */
  1008.  
  1009.         WindowPtr = ThisProcess -> pr_WindowPtr;
  1010.  
  1011.             /* Make sure that the cleanup routine gets called on exit. */
  1012.  
  1013.         if(AT_EXIT(ConCleanup))
  1014.             return(FALSE);
  1015.  
  1016.             /* Open intuition.library. */
  1017.  
  1018.         if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",LIB_MINIMUM)))
  1019.             return(FALSE);
  1020.  
  1021.             /* Open graphics.library. */
  1022.  
  1023.         if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",LIB_MINIMUM)))
  1024.             return(FALSE);
  1025.  
  1026.             /* Open layers.library. */
  1027.  
  1028.         if(!(LayersBase = OpenLibrary("layers.library",LIB_MINIMUM)))
  1029.             return(FALSE);
  1030.  
  1031.             /* Open diskfont.library, don't worry if it fails. */
  1032.  
  1033.         DiskfontBase = OpenLibrary("diskfont.library",LIB_MINIMUM);
  1034.  
  1035.             /* Which operating system revision is this
  1036.              * machine currently running?
  1037.              */
  1038.  
  1039.         if(NewOS = (IntuitionBase -> LibNode . lib_Version >= LIB_VERSION))
  1040.         {
  1041.                 /* Open asl.library (file requester routines). */
  1042.  
  1043.             if(!(AslBase = OpenLibrary("asl.library",LIB_VERSION)))
  1044.                 return(FALSE);
  1045.  
  1046.                 /* Open icon.library (icon file routines). */
  1047.  
  1048.             if(!(IconBase = OpenLibrary("icon.library",LIB_VERSION)))
  1049.                 return(FALSE);
  1050.  
  1051.                 /* Open utility.library (string comparison routines). */
  1052.  
  1053.             if(!(UtilityBase = OpenLibrary("utility.library",LIB_VERSION)))
  1054.                 return(FALSE);
  1055.  
  1056.                 /* Open gadtools.library (menu and gadget creation routines). */
  1057.  
  1058.             if(!(GadToolsBase = OpenLibrary("gadtools.library",LIB_VERSION)))
  1059.                 return(FALSE);
  1060.  
  1061.                 /* Open iffparse.library (iff file parsing routines). */
  1062.  
  1063.             if(!(IFFParseBase = OpenLibrary("iffparse.library",LIB_VERSION)))
  1064.                 return(FALSE);
  1065.  
  1066.                 /* Open workbench.library (appwindow routines). */
  1067.  
  1068.             WorkbenchBase = OpenLibrary("workbench.library",LIB_VERSION);
  1069.         }
  1070.         else
  1071.             IconBase = OpenLibrary("icon.library",LIB_MINIMUM);
  1072.     }
  1073.  
  1074.     return(LibsOpened = TRUE);
  1075. }
  1076.  
  1077.     /* ConCleanup():
  1078.      *
  1079.      *    Free all resources.
  1080.      */
  1081.  
  1082. VOID
  1083. ConCleanup()
  1084. {
  1085.         /* Free the sound data. */
  1086.  
  1087.     SoundExit();
  1088.  
  1089.         /* Close the clipboard. */
  1090.  
  1091.     ClipClose();
  1092.  
  1093.         /* Free the script padding buffers. */
  1094.  
  1095.     ScriptPadCleanup();
  1096.  
  1097.         /* Free the timer request. */
  1098.  
  1099.     if(TimeRequest)
  1100.     {
  1101.             /* Did we succeed in opening the device? */
  1102.  
  1103.         if(TimeRequest -> tr_node . io_Device)
  1104.         {
  1105.                 /* Is the time request still pending? If so, abort it. */
  1106.  
  1107.             if(!CheckIO((struct IORequest *)TimeRequest))
  1108.                 AbortIO((struct IORequest *)TimeRequest);
  1109.  
  1110.                 /* Remove the request. */
  1111.  
  1112.             WaitIO((struct IORequest *)TimeRequest);
  1113.  
  1114.                 /* Close the device. */
  1115.  
  1116.             CloseDevice((struct IORequest *)TimeRequest);
  1117.         }
  1118.  
  1119.             /* Free the request. */
  1120.  
  1121.         DeleteExtIO((struct IORequest *)TimeRequest);
  1122.  
  1123.         TimeRequest = NULL;
  1124.     }
  1125.  
  1126.         /* Free the timer port. */
  1127.  
  1128.     if(TimePort)
  1129.     {
  1130.         DeletePort(TimePort);
  1131.  
  1132.         TimePort = NULL;
  1133.     }
  1134.  
  1135.         /* Free the console request. */
  1136.  
  1137.     if(ConRequest)
  1138.     {
  1139.             /* Did we open the device? If so, close it. */
  1140.  
  1141.         if(ConRequest -> io_Device)
  1142.             CloseDevice((struct IORequest *)ConRequest);
  1143.  
  1144.             /* Free the memory. */
  1145.  
  1146.         FreeMem(ConRequest,sizeof(struct IOStdReq));
  1147.  
  1148.         ConRequest = NULL;
  1149.     }
  1150.  
  1151.         /* Free the input conversion buffer. */
  1152.  
  1153.     if(InputEventBuffer)
  1154.     {
  1155.         FreeMem(InputEventBuffer,INPUT_LENGTH);
  1156.  
  1157.         InputEventBuffer = NULL;
  1158.     }
  1159.  
  1160.         /* Free the fake inputevent. */
  1161.  
  1162.     if(InputEvent)
  1163.     {
  1164.         FreeMem(InputEvent,sizeof(struct InputEvent));
  1165.  
  1166.         InputEvent = NULL;
  1167.     }
  1168.  
  1169.         /* Remove appwindow link. */
  1170.  
  1171.     if(WorkbenchWindow)
  1172.     {
  1173.         RemoveAppWindow(WorkbenchWindow);
  1174.  
  1175.         WorkbenchWindow = NULL;
  1176.     }
  1177.  
  1178.         /* Remove appwindow msgport and any pending messages. */
  1179.  
  1180.     if(WorkbenchPort)
  1181.     {
  1182.         struct Message *Message;
  1183.  
  1184.         while(Message = GetMsg(WorkbenchPort))
  1185.             ReplyMsg(Message);
  1186.  
  1187.         DeletePort(WorkbenchPort);
  1188.  
  1189.         WorkbenchPort = NULL;
  1190.     }
  1191.  
  1192.     if(PadLen)
  1193.     {
  1194.         FreeMem(PadLen,sizeof(int) * Window -> WScreen -> Width / 2);
  1195.  
  1196.         PadLen = NULL;
  1197.     }
  1198.  
  1199.     if(PadSkip)
  1200.     {
  1201.         FreeMem(PadSkip,sizeof(int) * Window -> WScreen -> Width / 2);
  1202.  
  1203.         PadSkip = NULL;
  1204.     }
  1205.  
  1206.         /* Close the window. */
  1207.  
  1208.     if(Window)
  1209.     {
  1210.             /* Cosmeticism. */
  1211.  
  1212.         if(Screen)
  1213.             ScreenToBack(Screen);
  1214.  
  1215.             /* Remove the pull-down menus. */
  1216.  
  1217.         if(Menu)
  1218.             ClearMenuStrip(Window);
  1219.  
  1220.             /* Really close the window. */
  1221.  
  1222.         CloseWindow(Window);
  1223.  
  1224.         Window = NULL;
  1225.     }
  1226.  
  1227.         /* Free the menu strip. */
  1228.  
  1229.     if(Menu)
  1230.     {
  1231.         FreeMenus(Menu);
  1232.  
  1233.         Menu = NULL;
  1234.     }
  1235.  
  1236.         /* Free the chip memory buffer. */
  1237.  
  1238.     if(ChipData)
  1239.     {
  1240.         FreeMem(ChipData,sizeof(UWORD) * (sizeof(StopwatchData) + 2));
  1241.  
  1242.         ChipData = NULL;
  1243.     }
  1244.  
  1245.         /* Free the visual information buffer. */
  1246.  
  1247.     if(VisualInfo)
  1248.     {
  1249.         FreeVisualInfo(VisualInfo);
  1250.  
  1251.         VisualInfo = NULL;
  1252.     }
  1253.  
  1254.         /* Close the custom screen if any. */
  1255.  
  1256.     if(Screen)
  1257.     {
  1258.         CloseScreen(Screen);
  1259.  
  1260.         Screen = NULL;
  1261.     }
  1262.  
  1263.         /* Close the disk fonts if any. */
  1264.  
  1265.     if(TextFont)
  1266.     {
  1267.         CloseFont(TextFont);
  1268.  
  1269.         TextFont = NULL;
  1270.     }
  1271.  
  1272.     if(ListFont)
  1273.     {
  1274.         CloseFont(ListFont);
  1275.  
  1276.         ListFont = NULL;
  1277.     }
  1278.  
  1279.         /* Free the file requester. */
  1280.  
  1281.     if(GameFileRequest)
  1282.     {
  1283.         FreeAslRequest(GameFileRequest);
  1284.  
  1285.         GameFileRequest = NULL;
  1286.     }
  1287.  
  1288.         /* If not already done, release the lock on the default
  1289.          * public screen.
  1290.          */
  1291.  
  1292.     if(DefaultScreen)
  1293.     {
  1294.         UnlockPubScreen(NULL,DefaultScreen);
  1295.  
  1296.         DefaultScreen = NULL;
  1297.     }
  1298.  
  1299.         /* Reset the DOS requester location. */
  1300.  
  1301.     if(ThisProcess)
  1302.     {
  1303.         ThisProcess -> pr_WindowPtr = WindowPtr;
  1304.  
  1305.         ThisProcess = NULL;
  1306.     }
  1307.  
  1308.         /* Dispose the hidden drawing area. */
  1309.  
  1310.     ConLayerCleanup();
  1311.  
  1312.         /* Close the libraries. */
  1313.  
  1314.     if(IntuitionBase)
  1315.     {
  1316.         CloseLibrary((struct Library *)IntuitionBase);
  1317.  
  1318.         IntuitionBase = NULL;
  1319.     }
  1320.  
  1321.     if(GfxBase)
  1322.     {
  1323.         CloseLibrary((struct Library *)GfxBase);
  1324.  
  1325.         GfxBase = NULL;
  1326.     }
  1327.  
  1328.     if(LayersBase)
  1329.     {
  1330.         CloseLibrary(LayersBase);
  1331.  
  1332.         LayersBase = NULL;
  1333.     }
  1334.  
  1335.     if(DiskfontBase)
  1336.     {
  1337.         CloseLibrary(DiskfontBase);
  1338.  
  1339.         DiskfontBase = NULL;
  1340.     }
  1341.  
  1342.     if(AslBase)
  1343.     {
  1344.         CloseLibrary(AslBase);
  1345.  
  1346.         AslBase = NULL;
  1347.     }
  1348.  
  1349.     if(IconBase)
  1350.     {
  1351.         CloseLibrary(IconBase);
  1352.  
  1353.         IconBase = NULL;
  1354.     }
  1355.  
  1356.     if(IFFParseBase)
  1357.     {
  1358.         CloseLibrary(IFFParseBase);
  1359.  
  1360.         IFFParseBase = NULL;
  1361.     }
  1362.  
  1363.     if(GadToolsBase)
  1364.     {
  1365.         CloseLibrary(GadToolsBase);
  1366.  
  1367.         GadToolsBase = NULL;
  1368.     }
  1369.  
  1370.     if(UtilityBase)
  1371.     {
  1372.         CloseLibrary(UtilityBase);
  1373.  
  1374.         UtilityBase = NULL;
  1375.     }
  1376.  
  1377.     if(WorkbenchBase)
  1378.     {
  1379.         CloseLibrary(WorkbenchBase);
  1380.  
  1381.         WorkbenchBase = NULL;
  1382.     }
  1383. }
  1384.  
  1385.     /* ConSetup():
  1386.      *
  1387.      *    Set up console interface.
  1388.      */
  1389.  
  1390. Bool
  1391. ConSetup()
  1392. {
  1393.     struct IBox    ZoomBox;
  1394.     UWORD        Pen    = (UWORD)~0,
  1395.             Width;
  1396.     WORD        MinHeight,
  1397.             MinWidth;
  1398.     UBYTE        Char;
  1399.     ULONG        Total    = 0,
  1400.             Count    = 0;
  1401.     Bool        UseFont    = FALSE;
  1402.  
  1403.         /* Open system libraries. */
  1404.  
  1405.     if(!ConOpenLibs())
  1406.         return(FALSE);
  1407.  
  1408.         /* Create the console info. */
  1409.  
  1410.     if(!(ConRequest = (struct IOStdReq *)AllocMem(sizeof(struct IOStdReq),MEMF_ANY | MEMF_CLEAR)))
  1411.         return(FALSE);
  1412.  
  1413.         /* Open console.device and extract the device base pointer. */
  1414.  
  1415.     if(OpenDevice("console.device",CONU_LIBRARY,(struct IORequest *)ConRequest,NULL))
  1416.         return(FALSE);
  1417.  
  1418.     ConsoleDevice = ConRequest -> io_Device;
  1419.  
  1420.         /* Create the input event auxilary buffers. */
  1421.  
  1422.     if(!(InputEventBuffer = (STRPTR)AllocMem(INPUT_LENGTH,MEMF_ANY)))
  1423.         return(FALSE);
  1424.  
  1425.     if(!(InputEvent = (struct InputEvent *)AllocMem(sizeof(struct InputEvent),MEMF_ANY | MEMF_CLEAR)))
  1426.         return(FALSE);
  1427.  
  1428.         /* Create timer reply port. */
  1429.  
  1430.     if(!(TimePort = CreatePort(NULL,0)))
  1431.         return(FALSE);
  1432.  
  1433.         /* Create timer request. */
  1434.  
  1435.     if(!(TimeRequest = (struct timerequest *)CreateExtIO(TimePort,sizeof(struct timerequest))))
  1436.         return(FALSE);
  1437.  
  1438.         /* Open timer.device */
  1439.  
  1440.     if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)TimeRequest,0))
  1441.         return(FALSE);
  1442.  
  1443.         /* Allocate and set up chip memory data area. */
  1444.  
  1445.     if(!(ChipData = (UWORD *)AllocMem(sizeof(UWORD) * (sizeof(StopwatchData) + 2),MEMF_CHIP)))
  1446.         return(FALSE);
  1447.  
  1448.         /* Fill in the cross-hatch pattern. */
  1449.  
  1450.     ChipData[CHIPDATA_PATTERN  ] = 0x5555;
  1451.     ChipData[CHIPDATA_PATTERN+1] = 0xAAAA;
  1452.  
  1453.         /* Fill in the mouse pointer data. */
  1454.  
  1455.     CopyMem((BYTE *)StopwatchData,(BYTE *)&ChipData[CHIPDATA_POINTER],sizeof(StopwatchData));
  1456.  
  1457.         /* Are we to use special fonts? */
  1458.  
  1459.     if(ListFontName[0] && TextFontName[0] && FontSize > 0 && DiskfontBase)
  1460.     {
  1461.             /* Tack on the ".font" suffix. */
  1462.  
  1463.         strcat(ListFontName,".font");
  1464.         strcat(TextFontName,".font");
  1465.  
  1466.             /* Set up the fixed width (`list') font. */
  1467.  
  1468.         ListFontAttr . ta_Name    = ListFontName;
  1469.         ListFontAttr . ta_YSize    = FontSize;
  1470.         ListFontAttr . ta_Style    = FS_NORMAL;
  1471.         ListFontAttr . ta_Flags    = NULL;
  1472.  
  1473.             /* Set up the proportional-spaced (`text') font. */
  1474.  
  1475.         TextFontAttr . ta_Name    = TextFontName;
  1476.         TextFontAttr . ta_YSize    = FontSize;
  1477.         TextFontAttr . ta_Style    = FS_NORMAL;
  1478.         TextFontAttr . ta_Flags    = NULL;
  1479.  
  1480.             /* Try to open the fixed-width font. */
  1481.  
  1482.         if(ListFont = OpenDiskFont(&ListFontAttr))
  1483.         {
  1484.                 /* Is it really a fixed-width font? */
  1485.  
  1486.             if(!(ListFont -> tf_Flags & FPF_PROPORTIONAL))
  1487.             {
  1488.                     /* Try to open the other font. It does not
  1489.                      * matter whether it's fixed-width or
  1490.                      * proportional-spaced.
  1491.                      */
  1492.  
  1493.                 if(TextFont = OpenDiskFont(&TextFontAttr))
  1494.                     UseFont = TRUE;
  1495.             }
  1496.  
  1497.                 /* Are we able to use both fonts? */
  1498.  
  1499.             if(!UseFont)
  1500.             {
  1501.                     /* No, let's clean up then. */
  1502.  
  1503.                 CloseFont(ListFont);
  1504.  
  1505.                 ListFont = NULL;
  1506.             }
  1507.         }
  1508.     }
  1509.  
  1510.         /* Are we running under control of Kickstart 2.04 or higher? */
  1511.  
  1512.     if(NewOS)
  1513.     {
  1514.             /* Obtain a lock on the default public screen,
  1515.              * we will try to clone it later.
  1516.              */
  1517.  
  1518.         if(!(DefaultScreen = LockPubScreen(NULL)))
  1519.             return(FALSE);
  1520.  
  1521.             /* Are we to open a custom screen? */
  1522.  
  1523.         if(UseCustomScreen)
  1524.         {
  1525.             struct DrawInfo    *DrawInfo;
  1526.             ULONG         DefaultMode,
  1527.                      Mode;
  1528.  
  1529.                 /* Obtain the default screen display mode. */
  1530.  
  1531.             DefaultMode = GetVPModeID(&DefaultScreen -> ViewPort);
  1532.  
  1533.                 /* Build new display mode ID by looking
  1534.                  * at the default screen display mode
  1535.                  * properties.
  1536.                  */
  1537.  
  1538.             if((DefaultMode & MONITOR_ID_MASK) == A2024_MONITOR_ID)
  1539.                 Mode = DEFAULT_MONITOR_ID | HIRESLACE_KEY;
  1540.             else
  1541.                 Mode = DefaultMode;
  1542.  
  1543.                 /* Determine new screen depth, don't use more
  1544.                  * bit planes than necessary, though.
  1545.                  */
  1546.  
  1547.             if(DrawInfo = GetScreenDrawInfo(DefaultScreen))
  1548.             {
  1549.                 Depth = MIN(2,DrawInfo -> dri_Depth);
  1550.  
  1551.                 FreeScreenDrawInfo(DefaultScreen,DrawInfo);
  1552.             }
  1553.             else
  1554.                 Depth = 1;
  1555.  
  1556.                 /* Open the custom screen. */
  1557.  
  1558.             if(!(Screen = OpenScreenTags(NULL,
  1559.                 SA_Depth,                Depth,
  1560.                 SA_DisplayID,                Mode,
  1561.                 SA_Overscan,                OSCAN_TEXT,
  1562.                 SA_Pens,                &Pen,
  1563.                 SA_Title,                SCREEN_TITLE,
  1564.                 SA_AutoScroll,                TRUE,
  1565.                 SA_Behind,                TRUE,
  1566. #ifdef SA_Interleaved
  1567.                 SA_Interleaved,                TRUE,
  1568. #endif    /* SA_Interleaved */
  1569.  
  1570.                 UseFont ? TAG_IGNORE : SA_SysFont,    1,
  1571.                 UseFont ? SA_Font : TAG_IGNORE,        &TextFontAttr,
  1572.             TAG_DONE)))
  1573.                 return(FALSE);
  1574.  
  1575.                 /* Open the window on the custom screen. */
  1576.  
  1577.             if(!(Window = OpenWindowTags(NULL,
  1578.                 WA_Left,        0,
  1579.                 WA_Top,            Screen -> BarHeight + 2,
  1580.                 WA_Width,        Screen -> Width,
  1581.                 WA_Height,        Screen -> Height - (Screen -> BarHeight + 2),
  1582.                 WA_Borderless,        TRUE,
  1583.                 WA_Backdrop,        TRUE,
  1584.                 WA_RMBTrap,        TRUE,
  1585.                 WA_NoCareRefresh,    TRUE,
  1586. #ifdef WA_NewLookMenus
  1587.                 WA_NewLookMenus,    TRUE,
  1588. #endif    /* WA_NewLookMenus */
  1589.                 WA_CustomScreen,    Screen,
  1590.                 WA_IDCMP,        IDCMP_MENUPICK | IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS | IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW,
  1591.             TAG_DONE)))
  1592.                 return(FALSE);
  1593.         }
  1594.         else
  1595.         {
  1596.             UWORD    Width,Height,
  1597.                 ScreenWidth,ScreenHeight;
  1598.             WORD    i,ExtensionLen,NameLen;
  1599.             Bool    GotIt = FALSE;
  1600.  
  1601.             if(UseFont)
  1602.             {
  1603.                 Width    = DefaultScreen -> WBorLeft + WINDOW_COLUMNS * ListFont -> tf_XSize + DefaultScreen -> WBorRight;
  1604.                 Height    = DefaultScreen -> WBorTop + DefaultScreen -> Font -> ta_YSize + ListFont -> tf_YSize * WINDOW_LINES + DefaultScreen -> WBorBottom;
  1605.             }
  1606.             else
  1607.             {
  1608.                 Width    = DefaultScreen -> WBorLeft + WINDOW_COLUMNS * DefaultScreen -> RastPort . Font -> tf_XSize + DefaultScreen -> WBorRight;
  1609.                 Height    = DefaultScreen -> WBorTop + DefaultScreen -> Font -> ta_YSize * (WINDOW_LINES + 1) + DefaultScreen -> WBorBottom;
  1610.             }
  1611.  
  1612.                 /* Query the visible screen dimensions. */
  1613.  
  1614.             if(DefaultScreen -> ViewPort . ColorMap -> cm_vpe)
  1615.             {
  1616.                 struct ViewPortExtra *Extra;
  1617.  
  1618.                 Extra = DefaultScreen -> ViewPort . ColorMap -> cm_vpe;
  1619.  
  1620.                 ScreenWidth    = Extra -> DisplayClip . MaxX - Extra -> DisplayClip . MinX + 1;
  1621.                 ScreenHeight    = Extra -> DisplayClip . MaxY - Extra -> DisplayClip . MinY + 1;
  1622.             }
  1623.             else
  1624.             {
  1625.                 struct ViewPortExtra *Extra;
  1626.  
  1627.                 if(Extra = (struct ViewPortExtra *)GfxLookUp(&DefaultScreen -> ViewPort))
  1628.                 {
  1629.                     ScreenWidth    = Extra -> DisplayClip . MaxX - Extra -> DisplayClip . MinX + 1;
  1630.                     ScreenHeight    = Extra -> DisplayClip . MaxY - Extra -> DisplayClip . MinY + 1;
  1631.                 }
  1632.                 else
  1633.                 {
  1634.                     ScreenWidth    = DefaultScreen -> Width;
  1635.                     ScreenHeight    = DefaultScreen -> Height;
  1636.                 }
  1637.             }
  1638.  
  1639.                 /* Set up the alternative window coordinates and size. */
  1640.  
  1641.             ZoomBox . Left        = 0;
  1642.             ZoomBox . Top        = DefaultScreen -> BarHeight + 1;
  1643.             ZoomBox . Width        = ScreenWidth;
  1644.             ZoomBox . Height    = ScreenHeight - ZoomBox . Top;
  1645.  
  1646.                 /* Set up the window title. */
  1647.  
  1648.             strcpy(WindowTitle,FilePart((STRPTR)gflags . filenm));
  1649.  
  1650.                 /* Determine name length. */
  1651.  
  1652.             NameLen = strlen(WindowTitle);
  1653.  
  1654.                 /* Try to find a matching game
  1655.                  * file name extension.
  1656.                  */
  1657.  
  1658.             for(i = 0 ; !GotIt && StoryExtensions[i] ; i++)
  1659.             {
  1660.                     /* Is the game file name long enough
  1661.                      * to hold an extension?
  1662.                      */
  1663.  
  1664.                 if((ExtensionLen = strlen(StoryExtensions[i])) > NameLen)
  1665.                 {
  1666.                         /* Does the extension match? */
  1667.  
  1668.                     if(!Stricmp(&WindowTitle[NameLen - ExtensionLen],StoryExtensions[i]))
  1669.                     {
  1670.                             /* Strip the file name extension. */
  1671.  
  1672.                         WindowTitle[NameLen - ExtensionLen] = 0;
  1673.  
  1674.                             /* We're done now. */
  1675.  
  1676.                         GotIt = TRUE;
  1677.                     }
  1678.                 }
  1679.             }
  1680.  
  1681.                 /* Open the window on the Workbench screen. */
  1682.  
  1683.             if(!(Window = OpenWindowTags(NULL,
  1684.                 WA_Title,        WindowTitle,
  1685.                 WA_Width,        Width,
  1686.                 WA_Height,        Height,
  1687.                 WA_MaxWidth,        Width,
  1688.                 WA_MaxHeight,        Height,
  1689.                 WA_MinWidth,        Width,
  1690.                 WA_MinHeight,        Height,
  1691.                 WA_Zoom,        &ZoomBox,
  1692.                 WA_RMBTrap,        TRUE,
  1693.                 WA_DragBar,        TRUE,
  1694.                 WA_DepthGadget,        TRUE,
  1695.                 WA_CloseGadget,        TRUE,
  1696.                 WA_Activate,        TRUE,
  1697.                 WA_SizeGadget,        TRUE,
  1698.                 WA_SizeBBottom,        TRUE,
  1699.                 WA_NoCareRefresh,    TRUE,
  1700. #ifdef WA_NewLookMenus
  1701.                 WA_NewLookMenus,    TRUE,
  1702. #endif    /* WA_NewLookMenus */
  1703.                 WA_CustomScreen,    DefaultScreen,
  1704.                 WA_IDCMP,        IDCMP_CLOSEWINDOW | IDCMP_NEWSIZE | IDCMP_MENUPICK | IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS | IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW,
  1705.             TAG_DONE)))
  1706.                 return(FALSE);
  1707.             else
  1708.             {
  1709.                 struct DrawInfo *DrawInfo;
  1710.  
  1711.                 if(DrawInfo = GetScreenDrawInfo(Window -> WScreen))
  1712.                 {
  1713.                     Depth = DrawInfo -> dri_Depth;
  1714.  
  1715.                     FreeScreenDrawInfo(Window -> WScreen,DrawInfo);
  1716.                 }
  1717.                 else
  1718.                     Depth = 1;
  1719.  
  1720.                 SetWindowTitles(Window,(STRPTR)~0,SCREEN_TITLE);
  1721.  
  1722.                     /* Get the window border limits. */
  1723.  
  1724.                 WindowBorderLeft    = Window -> BorderLeft + 1;
  1725.                 WindowBorderRight    = Window -> BorderRight + 1;
  1726.                 WindowBorderTop        = Window -> BorderTop;
  1727.                 WindowBorderBottom    = Window -> BorderBottom;
  1728.             }
  1729.         }
  1730.  
  1731.             /* Release the lock on the default public screen. */
  1732.  
  1733.         UnlockPubScreen(NULL,DefaultScreen);
  1734.  
  1735.             /* Clear the address pointer. */
  1736.  
  1737.         DefaultScreen = NULL;
  1738.  
  1739.             /* Allocate the file requester. */
  1740.  
  1741.         if(!(GameFileRequest = AllocAslRequestTags(ASL_FileRequest,
  1742.             ASL_LeftEdge,    Window -> LeftEdge + Window -> Width / 4,
  1743.             ASL_TopEdge,    Window -> TopEdge + Window -> Height / 4,
  1744.             ASL_Width,    Window -> Width / 2,
  1745.             ASL_Height,    Window -> Height / 2,
  1746.         TAG_DONE)))
  1747.             return(FALSE);
  1748.  
  1749.             /* Obtain visual info on our custom screen. */
  1750.  
  1751.         if(!(VisualInfo = GetVisualInfo(Window -> WScreen,TAG_DONE)))
  1752.             return(FALSE);
  1753.  
  1754.             /* Create the pull-down menus. */
  1755.  
  1756.         if(!(Menu = CreateMenus(ConMenuConfig,TAG_DONE)))
  1757.             return(FALSE);
  1758.  
  1759.             /* Properly layout the menus. */
  1760.  
  1761.         if(!(LayoutMenus(Menu,VisualInfo,
  1762. #ifdef GTMN_NewLookMenus
  1763.             GTMN_NewLookMenus,    TRUE,
  1764. #endif    /* GTMN_NewLookMenus */
  1765.             GTMN_TextAttr,        Window -> WScreen -> Font,
  1766.         TAG_DONE)))
  1767.             return(FALSE);
  1768.  
  1769.             /* Attach the menus to the window. */
  1770.  
  1771.         SetMenuStrip(Window,Menu);
  1772.  
  1773.             /* Enable the menus. */
  1774.  
  1775.         Window -> Flags &= ~WFLG_RMBTRAP;
  1776.     }
  1777.     else
  1778.     {
  1779.             /* The buffer to hold information on the Workbench screen. */
  1780.  
  1781.         struct Screen        WorkbenchScreen;
  1782.  
  1783.             /* Screen and window allocation data. */
  1784.  
  1785.         struct NewScreen    NewScreen;
  1786.         struct NewWindow    NewWindow;
  1787.  
  1788.             /* Clear the new screen structure. */
  1789.  
  1790.         memset(&NewScreen,0,sizeof(struct NewScreen));
  1791.  
  1792.             /* Fill in the common data. */
  1793.  
  1794.         NewScreen . Depth        = 1;
  1795.         NewScreen . DetailPen        = 0;
  1796.         NewScreen . BlockPen        = 1;
  1797.         NewScreen . DefaultTitle    = SCREEN_TITLE;
  1798.         NewScreen . Type        = CUSTOMSCREEN | SCREENBEHIND;
  1799.  
  1800.         if(UseFont)
  1801.             NewScreen . Font = &TextFontAttr;
  1802.  
  1803.             /* Get the Workbench screen size and display mode. */
  1804.  
  1805.         if(GetScreenData((BYTE *)&WorkbenchScreen,sizeof(struct Screen),WBENCHSCREEN,NULL))
  1806.         {
  1807.             NewScreen . ViewModes    = WorkbenchScreen . ViewPort . Modes;
  1808.             NewScreen . Height    = WorkbenchScreen . Height;
  1809.             NewScreen . Width    = WorkbenchScreen . Width;
  1810.         }
  1811.         else
  1812.             return(FALSE);
  1813.  
  1814.             /* Clear the new window structure. */
  1815.  
  1816.         memset(&NewWindow,0,sizeof(struct NewWindow));
  1817.  
  1818.             /* Fill in the common data. */
  1819.  
  1820.         NewWindow . LeftEdge    = 0;
  1821.         NewWindow . Width    = NewScreen . Width;
  1822.         NewWindow . DetailPen    = (UBYTE)-1;
  1823.         NewWindow . BlockPen    = (UBYTE)-1;
  1824.         NewWindow . IDCMPFlags    = MOUSEBUTTONS | RAWKEY | ACTIVEWINDOW | INACTIVEWINDOW | NEWSIZE | CLOSEWINDOW;
  1825.         NewWindow . MinWidth    = NewWindow . Width;
  1826.         NewWindow . MinHeight    = NewWindow . Height;
  1827.         NewWindow . MaxWidth    = NewWindow . Width;
  1828.         NewWindow . MaxHeight    = NewWindow . Height;
  1829.  
  1830.             /* Are we to open a custom screen? */
  1831.  
  1832.         if(UseCustomScreen)
  1833.         {
  1834.                 /* Default colour palette. */
  1835.  
  1836.             STATIC UWORD Palette[2] = { 0x000,0xEEE };
  1837.  
  1838.                 /* Open the screen. */
  1839.  
  1840.             if(!(Screen = OpenScreen(&NewScreen)))
  1841.                 return(FALSE);
  1842.  
  1843.                 /* Set the screen colours. */
  1844.  
  1845.             LoadRGB4(&Screen -> ViewPort,Palette,2);
  1846.  
  1847.                 /* Set up the remaining window flags. */
  1848.  
  1849.             NewWindow . TopEdge    = Screen -> BarHeight + 1;
  1850.             NewWindow . Height    = Screen -> Height - NewWindow . TopEdge;
  1851.             NewWindow . Flags    = ACTIVATE | RMBTRAP | SMART_REFRESH | NOCAREREFRESH | BORDERLESS | BACKDROP;
  1852.             NewWindow . Screen    = Screen;
  1853.             NewWindow . Type    = CUSTOMSCREEN;
  1854.         }
  1855.         else
  1856.         {
  1857.                 /* Set up the remaining window flags. */
  1858.  
  1859.             NewWindow . TopEdge    = WorkbenchScreen . BarHeight + 1;
  1860.             NewWindow . Height    = NewScreen . Height - NewWindow . TopEdge;
  1861.             NewWindow . Flags    = ACTIVATE | RMBTRAP | SMART_REFRESH | NOCAREREFRESH | WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE;
  1862.             NewWindow . Title    = SCREEN_TITLE;
  1863.             NewWindow . Type    = WBENCHSCREEN;
  1864.         }
  1865.  
  1866.             /* Open the window. */
  1867.  
  1868.         if(!(Window = OpenWindow(&NewWindow)))
  1869.             return(FALSE);
  1870.         else
  1871.             Depth = Window -> RPort -> BitMap -> Depth;
  1872.     }
  1873.  
  1874.         /* Allocate the padding auxilary vectors. */
  1875.  
  1876.     if(!(PadLen = (int *)AllocMem(sizeof(int) * Window -> WScreen -> Width / 2,MEMF_ANY)))
  1877.         return(FALSE);
  1878.  
  1879.     if(!(PadSkip = (int *)AllocMem(sizeof(int) * Window -> WScreen -> Width / 2,MEMF_ANY)))
  1880.         return(FALSE);
  1881.  
  1882.         /* Determine bitmap plane mask. */
  1883.  
  1884.     DepthMask = (1 << Depth) - 1;
  1885.  
  1886.         /* Let's assume that our window is active now. */
  1887.  
  1888.     WindowIsActive = TRUE;
  1889.  
  1890.         /* Did we open a custom screen? */
  1891.  
  1892.     if(!Screen && WorkbenchBase)
  1893.     {
  1894.             /* Create Workbench appwindow msgport. */
  1895.  
  1896.         if(!(WorkbenchPort = CreatePort(NULL,0)))
  1897.             return(FALSE);
  1898.  
  1899.             /* Create Workbench appwindow link. */
  1900.  
  1901.         if(!(WorkbenchWindow = AddAppWindow(0,0,Window,WorkbenchPort,NULL)))
  1902.         {
  1903.                 /* Maybe just Workbench isn't up and running,
  1904.                  * so don't cause any trouble, proceed as usual.
  1905.                  */
  1906.  
  1907.             DeletePort(WorkbenchPort);
  1908.  
  1909.             WorkbenchPort = NULL;
  1910.  
  1911.             CloseLibrary(WorkbenchBase);
  1912.  
  1913.             WorkbenchBase = NULL;
  1914.         }
  1915.     }
  1916.  
  1917.         /* Determine inner window width. */
  1918.  
  1919.     WindowWidth = Window -> Width - (WindowBorderLeft + WindowBorderRight);
  1920.  
  1921.         /* Obtain rastport pointer. */
  1922.  
  1923.     RPort = Window -> RPort;
  1924.  
  1925.         /* Set text rendering mode. */
  1926.  
  1927.     SetDrMd(RPort,JAM2);
  1928.  
  1929.         /* Set text colour. */
  1930.  
  1931.     ConSetColour(COLOUR_TEXT);
  1932.  
  1933.         /* Get both the screen and system default font. The
  1934.          * screen font can be a proportional-spaced font
  1935.          * while the window rastport font is guaranteed
  1936.          * to be a fixed-width font.
  1937.          */
  1938.  
  1939.     if(UseFont)
  1940.     {
  1941.         PropFont    = TextFont;
  1942.         FixedFont    = ListFont;
  1943.     }
  1944.     else
  1945.     {
  1946.         PropFont    = Window -> WScreen -> RastPort . Font;
  1947.         FixedFont    = Window -> IFont;
  1948.     }
  1949.  
  1950.         /* Obtain the system default font dimensions. */
  1951.  
  1952.     TextFontHeight    = FixedFont -> tf_YSize;
  1953.     TextFontWidth    = 0;
  1954.  
  1955.         /* Create the hidden drawing area. */
  1956.  
  1957.     if(!ConLayerSetup(Window -> WScreen -> Width,TextFontHeight))
  1958.         return(FALSE);
  1959.  
  1960.         /* Both the proportional-spaced and the fixed-width
  1961.          * font have to match in height. If this is not the
  1962.          * case, we will use only the fixed-width font.
  1963.          */
  1964.  
  1965.     if(PropFont -> tf_YSize != FixedFont -> tf_YSize)
  1966.         PropFont = FixedFont;
  1967.  
  1968.         /* Set the fixed-width font. */
  1969.  
  1970.     SetFont(RPort,ThisFont = FixedFont);
  1971.  
  1972.         /* Look for the widest glyph. */
  1973.  
  1974.     for(Char = ' ' ; Char <= '~' ; Char++)
  1975.     {
  1976.         if((Width = ConCharWidth(Char)) > TextFontWidth)
  1977.             TextFontWidth = Width;
  1978.  
  1979.             /* Update width. */
  1980.  
  1981.         Total += Width;
  1982.  
  1983.         Count++;
  1984.     }
  1985.  
  1986.         /* Set the proportional-spaced font. */
  1987.  
  1988.     SetFont(RPort,ThisFont = PropFont);
  1989.     SetFont(PadRPort,ThisFont);
  1990.  
  1991.         /* Look for the widest glyph. */
  1992.  
  1993.     for(Char = ' ' ; Char <= '~' ; Char++)
  1994.     {
  1995.         if((Width = ConCharWidth(Char)) > TextFontWidth)
  1996.             TextFontWidth = Width;
  1997.  
  1998.             /* Update width. */
  1999.  
  2000.         Total += Width;
  2001.  
  2002.         Count++;
  2003.     }
  2004.  
  2005.         /* Determine the average glyph width. */
  2006.  
  2007.     DefaultCursorWidth = Total / Count;
  2008.  
  2009.         /* Determine space character width. */
  2010.  
  2011.     SpaceWidth = ConCharWidth(' ');
  2012.  
  2013.         /* Determine window minimum dimensions. */
  2014.  
  2015.     MinWidth    = WindowBorderLeft + MIN_WINDOW_COLUMNS * TextFontWidth + WindowBorderRight;
  2016.     MinHeight    = WindowBorderTop + MIN_WINDOW_LINES * TextFontHeight + WindowBorderBottom;
  2017.  
  2018.         /* Set the minimum dimensions if possible. */
  2019.  
  2020.     if(MinWidth < Window -> Width)
  2021.     {
  2022.         if(MinHeight < Window -> Height)
  2023.             WindowLimits(Window,MinWidth,MinHeight,Window -> WScreen -> Width,Window -> WScreen -> Height);
  2024.         else
  2025.             WindowLimits(Window,MinWidth,0,Window -> WScreen -> Width,Window -> WScreen -> Height);
  2026.     }
  2027.     else
  2028.         WindowLimits(Window,0,0,Window -> WScreen -> Width,Window -> WScreen -> Height);
  2029.  
  2030.         /* Remember initial window width. */
  2031.  
  2032.     OldWindowWidth    = Window -> Width;
  2033.     OldWindowHeight    = Window -> Height;
  2034.  
  2035.         /* Redirect DOS requesters. */
  2036.  
  2037.     ThisProcess -> pr_WindowPtr = (APTR)Window;
  2038.  
  2039.         /* Start the timer. */
  2040.  
  2041.     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  2042.     TimeRequest -> tr_time . tv_secs    = 0;
  2043.     TimeRequest -> tr_time . tv_micro    = SECOND / 2;
  2044.  
  2045.     SendIO((struct IORequest *)TimeRequest);
  2046.  
  2047.         /* Return success. */
  2048.  
  2049.     return(TRUE);
  2050. }
  2051.  
  2052.     /* ConGetChar(Bool SingleKey):
  2053.      *
  2054.      *    Read a single character from the console.
  2055.      */
  2056.  
  2057. UBYTE
  2058. ConGetChar(const Bool SingleKey)
  2059. {
  2060.     struct IntuiMessage    *IntuiMessage;
  2061.     ULONG             Qualifier,
  2062.                  Class,
  2063.                  Code,
  2064.                  Signals;
  2065.     LONG             Len;
  2066.     Bool             GotName = FALSE;
  2067.  
  2068.         /* Provide `fake' input in case we are
  2069.          * returning the result of a function keypress
  2070.          * or a menu event.
  2071.          */
  2072.  
  2073.     if(InputIndex)
  2074.     {
  2075.             /* Did we reach the end of the string?
  2076.              * If so, clear the index pointer and
  2077.              * fall through to the input routine.
  2078.              * If not, return the next character
  2079.              * in the buffer.
  2080.              */
  2081.  
  2082.         if(*InputIndex)
  2083.             return(*InputIndex++);
  2084.         else
  2085.         {
  2086.                 /* Are we to read input from the clipboard? */
  2087.  
  2088.             if(ClipInput)
  2089.             {
  2090.                 LONG Len;
  2091.  
  2092.                     /* Read next data. */
  2093.  
  2094.                 if((Len = ClipRead(InputBuffer,INPUT_LENGTH)) > 0)
  2095.                 {
  2096.                         /* Reset index pointer. */
  2097.  
  2098.                     InputIndex = InputBuffer;
  2099.  
  2100.                         /* Provide terminating NUL character. */
  2101.  
  2102.                     InputIndex[Len] = 0;
  2103.  
  2104.                         /* Return the next byte. */
  2105.  
  2106.                     return(*InputIndex++);
  2107.                 }
  2108.                 else
  2109.                 {
  2110.                         /* Close the clipboard. */
  2111.  
  2112.                     ClipClose();
  2113.                 }
  2114.             }
  2115.  
  2116.                 /* Clear the buffer pointer. */
  2117.  
  2118.             InputIndex = NULL;
  2119.         }
  2120.     }
  2121.  
  2122.         /* Wait for input... */
  2123.  
  2124.     FOREVER
  2125.     {
  2126.             /* Process all incoming messages. */
  2127.  
  2128.         while(IntuiMessage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
  2129.         {
  2130.                 /* Remember the menu code. */
  2131.  
  2132.             Qualifier    = IntuiMessage -> Qualifier;
  2133.             Class        = IntuiMessage -> Class;
  2134.             Code        = IntuiMessage -> Code;
  2135.  
  2136.                 /* Conver key code to ANSI character or control sequence. */
  2137.  
  2138.             if(Class == IDCMP_RAWKEY)
  2139.             {
  2140.                 InputEvent -> ie_Class            = IECLASS_RAWKEY;
  2141.                 InputEvent -> ie_Code            = Code;
  2142.                 InputEvent -> ie_Qualifier        = Qualifier;
  2143.  
  2144.                     /* Not really an APTR, but let's keep
  2145.                      * it for the sake of compatibility.
  2146.                      */
  2147.  
  2148.                 InputEvent -> ie_position . ie_addr    = *((APTR *)IntuiMessage -> IAddress);
  2149.  
  2150.                     /* Clear the conversion buffer, or the
  2151.                      * conversion result will be appended
  2152.                      * after the current contents.
  2153.                      */
  2154.  
  2155.                 InputEventBuffer[0] = 0;
  2156.  
  2157.                     /* Convert the event. */
  2158.  
  2159.                 Len = RawKeyConvert(InputEvent,InputEventBuffer,INPUT_LENGTH - 1,NULL);
  2160.             }
  2161.             else
  2162.                 Len = 0;
  2163.  
  2164.                 /* Reply the message. */
  2165.  
  2166.             ReplyMsg((struct Message *)IntuiMessage);
  2167.  
  2168.                 /* Did the window size change? */
  2169.  
  2170.             if(Class == IDCMP_NEWSIZE)
  2171.                 return(TERM_RESIZE);
  2172.  
  2173.                 /* Did the window become inactive? */
  2174.  
  2175.             if(Class == IDCMP_INACTIVEWINDOW)
  2176.             {
  2177.                     /* Turn the cursor off. */
  2178.  
  2179.                 ConCursorOff();
  2180.  
  2181.                     /* Remember that the window is
  2182.                      * inactive now.
  2183.                      */
  2184.  
  2185.                 WindowIsActive = FALSE;
  2186.  
  2187.                     /* Turn on the (disabled) cursor. */
  2188.  
  2189.                 ConCursorOn(CURSOR_NOCHANGE);
  2190.             }
  2191.  
  2192.                 /* Did the window become active? */
  2193.  
  2194.             if(Class == IDCMP_ACTIVEWINDOW)
  2195.             {
  2196.                     /* Turn the cursor off. */
  2197.  
  2198.                 ConCursorOff();
  2199.  
  2200.                     /* Remember that the window is
  2201.                      * active now.
  2202.                      */
  2203.  
  2204.                 WindowIsActive = TRUE;
  2205.  
  2206.                     /* Turn on the (enabled) cursor. */
  2207.  
  2208.                 ConCursorOn(CURSOR_NOCHANGE);
  2209.             }
  2210.  
  2211.                 /* Did the user press the close gadget? */
  2212.  
  2213.             if(Class == IDCMP_CLOSEWINDOW && !SingleKey)
  2214.                 return(TERM_CLOSE);
  2215.  
  2216.                 /* Did the user press the select button
  2217.                  * and a single keypress is wanted? If so,
  2218.                  * return a blank space.
  2219.                  */
  2220.  
  2221.             if(Class == IDCMP_MOUSEBUTTONS && SingleKey && Code == SELECTDOWN)
  2222.                 return(' ');
  2223.  
  2224.                 /* Did the user press a key? */
  2225.  
  2226.             if(Class == IDCMP_RAWKEY && Len > 0)
  2227.             {
  2228.                     /* Return a blank space if just a
  2229.                      * keypress is wanted.
  2230.                      */
  2231.  
  2232.                 if(SingleKey)
  2233.                     return(' ');
  2234.                 else
  2235.                 {
  2236.                         /* Provide null-termination. */
  2237.  
  2238.                     InputEventBuffer[Len] = 0;
  2239.  
  2240.                         /* Is this a numeric pad key
  2241.                          * and was no shift key pressed?
  2242.                          */
  2243.  
  2244.                     if((Qualifier & IEQUALIFIER_NUMERICPAD) && !(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT | IEQUALIFIER_CAPSLOCK)))
  2245.                     {
  2246.                             /* Key codes and associated cardinal directions. */
  2247.  
  2248.                         STATIC STRPTR Directions[][2] =
  2249.                         {
  2250.                             "8",    "north\r",
  2251.                             "9",    "ne\r",
  2252.                             "6",    "east\r",
  2253.                             "3",    "se\r",
  2254.                             "2",    "south\r",
  2255.                             "1",    "sw\r",
  2256.                             "4",    "west\r",
  2257.                             "7",    "nw\r",
  2258.  
  2259.                             "[",    "in\r",
  2260.                             "]",    "out\r",
  2261.  
  2262.                             "+",    "up\r",
  2263.                             "-",    "down\r"
  2264.                         };
  2265.  
  2266.                         int i;
  2267.  
  2268.                             /* Run down the list of directions. */
  2269.  
  2270.                         for(i = 0 ; i < sizeof(Directions) / (2 * sizeof(STRPTR)) ; i++)
  2271.                         {
  2272.                                 /* Does it match the input? */
  2273.  
  2274.                             if(!strcmp(Directions[i][0],InputEventBuffer))
  2275.                             {
  2276.                                     /* Use it as fake input. */
  2277.  
  2278.                                 InputIndex = Directions[i][1];
  2279.  
  2280.                                     /* Return ^X. */
  2281.  
  2282.                                 return(TERM_CUT);
  2283.                             }
  2284.                         }
  2285.  
  2286.                             /* Get back to the loop. */
  2287.  
  2288.                         continue;
  2289.                     }
  2290.  
  2291.                         /* Check for special codes, such as
  2292.                          * Shift + Del or Shift + Backspace.
  2293.                          */
  2294.  
  2295.                     if(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  2296.                     {
  2297.                             /* Delete to end of line? */
  2298.  
  2299.                         if(InputEventBuffer[0] == TERM_DEL)
  2300.                             return(TERM_DELFWD);
  2301.  
  2302.                             /* Delete to start of line? */
  2303.  
  2304.                         if(InputEventBuffer[0] == TERM_BS)
  2305.                             return(TERM_DELBCK);
  2306.                     }
  2307.  
  2308.                         /* Take over the input. */
  2309.  
  2310.                     InputIndex = InputEventBuffer;
  2311.  
  2312.                         /* Return the first character. */
  2313.  
  2314.                     return(*InputIndex++);
  2315.                 }
  2316.             }
  2317.  
  2318.                 /* Process all menu codes, including
  2319.                  * cases of multiple-selection.
  2320.                  */
  2321.  
  2322.             if(Class == IDCMP_MENUPICK)
  2323.             {
  2324.                 struct MenuItem    *Item;
  2325.                 UBYTE         Char = 0;
  2326.  
  2327.                     /* Process all menu selections. */
  2328.  
  2329.                 while(Code != MENUNULL)
  2330.                 {
  2331.                         /* Obtain the address of
  2332.                          * the menu item to belong
  2333.                          * to this menu code.
  2334.                          */
  2335.  
  2336.                     if(Item = ItemAddress(Menu,Code))
  2337.                     {
  2338.                             /* Did we already get
  2339.                              * a suitable menu
  2340.                              * item?
  2341.                              */
  2342.  
  2343.                         if(!Char)
  2344.                         {
  2345.                                 /* Get the new input string. */
  2346.  
  2347.                             if(!(InputIndex = (STRPTR)GTMENUITEM_USERDATA(Item)))
  2348.                             {
  2349.                                     /* Is it the `About...' item? */
  2350.  
  2351.                                 if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_PROJECT,PROJECTMENU_ABOUT,NOSUB)))
  2352.                                 {
  2353.                                         /* Turn the cursor off. */
  2354.  
  2355.                                     ConCursorOff();
  2356.  
  2357.                                         /* Display the information requester. */
  2358.  
  2359.                                     ConAbout();
  2360.  
  2361.                                         /* Turn the cursor back on. */
  2362.  
  2363.                                     ConCursorOn(CURSOR_NOCHANGE);
  2364.                                 }
  2365.  
  2366.                                     /* Is it the `Script...' item? */
  2367.  
  2368.                                 if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_PROJECT,PROJECTMENU_SCRIPT,NOSUB)))
  2369.                                 {
  2370.                                         /* This is probably the scripting command. */
  2371.  
  2372.                                     if(F2_IS_SET(B_SCRIPTING))
  2373.                                         InputIndex = (STRPTR)"Unscript\r";
  2374.                                     else
  2375.                                         InputIndex = (STRPTR)"Script\r";
  2376.  
  2377.                                         /* `Fake' a Ctrl-X
  2378.                                          * to clear the contents
  2379.                                          * of the input line.
  2380.                                          */
  2381.  
  2382.                                     Char = TERM_CUT;
  2383.                                 }
  2384.  
  2385.                                     /* Is it the `Cut' item? */
  2386.  
  2387.                                 if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_EDIT,EDITMENU_CUT,NOSUB)))
  2388.                                     Char = TERM_CUT;
  2389.  
  2390.                                     /* Is it the `Copy' item? */
  2391.  
  2392.                                 if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_EDIT,EDITMENU_COPY,NOSUB)))
  2393.                                     Char = TERM_COPY;
  2394.  
  2395.                                     /* Is it the `Paste' item? */
  2396.  
  2397.                                 if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_EDIT,EDITMENU_PASTE,NOSUB)))
  2398.                                 {
  2399.                                         /* Open the clipboard for reading. */
  2400.  
  2401.                                     if(ClipOpen())
  2402.                                     {
  2403.                                         LONG Len;
  2404.  
  2405.                                             /* Read next data. */
  2406.  
  2407.                                         if((Len = ClipRead(InputBuffer,INPUT_LENGTH)) > 0)
  2408.                                         {
  2409.                                                 /* Reset index pointer. */
  2410.  
  2411.                                             InputIndex = InputBuffer;
  2412.  
  2413.                                                 /* Provide terminating NUL character. */
  2414.  
  2415.                                             InputIndex[Len] = 0;
  2416.  
  2417.                                                 /* Return the next byte. */
  2418.  
  2419.                                             return(*InputIndex++);
  2420.                                         }
  2421.  
  2422.                                             /* Close the clipboard. */
  2423.  
  2424.                                         ClipClose();
  2425.                                     }
  2426.                                 }
  2427.  
  2428.                                     /* Is it the `Undo' item? */
  2429.  
  2430.                                 if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_EDIT,EDITMENU_UNDO,NOSUB)))
  2431.                                     Char = TERM_UNDO;
  2432.                             }
  2433.                             else
  2434.                             {
  2435.                                     /* `Fake' a Ctrl-X
  2436.                                      * to clear the contents
  2437.                                      * of the input line.
  2438.                                      */
  2439.  
  2440.                                 Char = TERM_CUT;
  2441.                             }
  2442.                         }
  2443.  
  2444.                             /* Proceed to next menu entry. */
  2445.  
  2446.                         Code = Item -> NextSelect;
  2447.                     }
  2448.                 }
  2449.  
  2450.                     /* Did we get anything sensible? If so,
  2451.                      * return immediately.
  2452.                      */
  2453.  
  2454.                 if(Char)
  2455.                     return(Char);
  2456.             }
  2457.         }
  2458.  
  2459.             /* Check the Workbench appwindow. */
  2460.  
  2461.         if(WorkbenchPort)
  2462.         {
  2463.             struct AppMessage *AppMessage;
  2464.  
  2465.             while(AppMessage = (struct AppMessage *)GetMsg(WorkbenchPort))
  2466.             {
  2467.                     /* Do we already have a file name? */
  2468.  
  2469.                 if(!GotName)
  2470.                 {
  2471.                     LONG i;
  2472.  
  2473.                         /* Run down the list of arguments... */
  2474.  
  2475.                     for(i = 0 ; !GotName && i < AppMessage -> am_NumArgs ; i++)
  2476.                     {
  2477.                             /* A correct project icon always has a
  2478.                              * directory lock associated, let's check it.
  2479.                              */
  2480.  
  2481.                         if(AppMessage -> am_ArgList[i] . wa_Lock)
  2482.                         {
  2483.                                 /* Build the project directory name. */
  2484.  
  2485.                             if(NameFromLock(AppMessage -> am_ArgList[i] . wa_Lock,ProjectName,MAX_FILENAME_LENGTH))
  2486.                             {
  2487.                                     /* Add the project name. */
  2488.  
  2489.                                 if(AddPart(ProjectName,AppMessage -> am_ArgList[i] . wa_Name,MAX_FILENAME_LENGTH))
  2490.                                 {
  2491.                                     struct DiskObject *Icon;
  2492.  
  2493.                                         /* Try to read the project icon. */
  2494.  
  2495.                                     if(Icon = GetDiskObject(ProjectName))
  2496.                                     {
  2497.                                             /* Is it really a project icon? */
  2498.  
  2499.                                         if(Icon -> do_Type == WBPROJECT)
  2500.                                         {
  2501.                                             STRPTR Type;
  2502.  
  2503.                                                 /* Find the file type if any. */
  2504.  
  2505.                                             if(Type = FindToolType((STRPTR *)Icon -> do_ToolTypes,"FILETYPE"))
  2506.                                             {
  2507.                                                     /* Is it a bookmark file? */
  2508.  
  2509.                                                 if(MatchToolValue(Type,"BOOKMARK") && MatchToolValue(Type,"ITF"))
  2510.                                                     GotName = TRUE;
  2511.                                             }
  2512.                                         }
  2513.  
  2514.                                             /* Free the icon data. */
  2515.  
  2516.                                         FreeDiskObject(Icon);
  2517.                                     }
  2518.                                 }
  2519.                             }
  2520.                         }
  2521.                     }
  2522.                 }
  2523.  
  2524.                     /* Reply the notification message. */
  2525.  
  2526.                 ReplyMsg((struct Message *)AppMessage);
  2527.             }
  2528.         }
  2529.  
  2530.             /* Did we get a project file name? */
  2531.  
  2532.         if(GotName)
  2533.         {
  2534.                 /* Get the new input string. */
  2535.  
  2536.             InputIndex = (STRPTR)"Restore\r";
  2537.  
  2538.                 /* Return with new input. */
  2539.  
  2540.             return(TERM_CUT);
  2541.         }
  2542.         else
  2543.             ProjectName[0] = 0;
  2544.  
  2545.         do
  2546.         {
  2547.                 /* Wait for input... */
  2548.  
  2549.             Signals = Wait(SIG_WINDOW | SIG_WORKBENCH | SIG_TIME);
  2550.  
  2551.                 /* Did we get a timeout? */
  2552.  
  2553.             if(Signals & SIG_TIME)
  2554.             {
  2555.                     /* Toggle the cursor state
  2556.                      * only if the window is
  2557.                      * really active.
  2558.                      */
  2559.  
  2560.                 if(WindowIsActive)
  2561.                 {
  2562.                         /* Which state is the cursor currently in?
  2563.                          * If it's enabled, turn it off, else
  2564.                          * turn it on.
  2565.                          */
  2566.  
  2567.                     if(CursorEnabled)
  2568.                         ConCursorOff();
  2569.                     else
  2570.                         ConCursorOn(CURSOR_NOCHANGE);
  2571.                 }
  2572.  
  2573.                     /* Wait for timer request to return. */
  2574.  
  2575.                 WaitIO((struct IORequest *)TimeRequest);
  2576.  
  2577.                     /* Restart timer. */
  2578.  
  2579.                 TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  2580.                 TimeRequest -> tr_time . tv_secs    = 0;
  2581.                 TimeRequest -> tr_time . tv_micro    = SECOND / 2;
  2582.  
  2583.                 SendIO((struct IORequest *)TimeRequest);
  2584.             }
  2585.         }
  2586.         while(!(Signals & (SIG_WINDOW | SIG_WORKBENCH)));
  2587.     }
  2588. }
  2589.  
  2590.     /* ConPrintf(const char *Format,...):
  2591.      *
  2592.      *    Print a string on the console, including formatting.
  2593.      */
  2594.  
  2595. VOID
  2596. ConPrintf(const char *Format,...)
  2597. {
  2598.     va_list VarArgs;
  2599.  
  2600.         /* Build the string. */
  2601.  
  2602.     va_start(VarArgs,Format);
  2603.  
  2604.     vsprintf(TempBuffer,Format,VarArgs);
  2605.  
  2606.     va_end(VarArgs);
  2607.  
  2608.         /* Print it. */
  2609.  
  2610.     ConWrite(TempBuffer,-1,0);
  2611. }
  2612.  
  2613.     /* ConSwap(STRPTR a,STRPTR b,int Len):
  2614.      *
  2615.      *    Swap the contents of two string buffers.
  2616.      */
  2617.  
  2618. VOID
  2619. ConSwap(STRPTR a,STRPTR b,int Len)
  2620. {
  2621.     register UBYTE Temp;
  2622.  
  2623.     while(Len--)
  2624.     {
  2625.         Temp    = *a;
  2626.         *a++    = *b;
  2627.         *b++    = Temp;
  2628.     }
  2629. }
  2630.  
  2631.     /* ConInput(char *Prompt,char *Input,const int MaxLen,const Bool DoHistory):
  2632.      *
  2633.      *    Read a line of characters.
  2634.      */
  2635.  
  2636. int
  2637. ConInput(char *Prompt,char *Input,const int MaxLen,const Bool DoHistory)
  2638. {
  2639.         /* Control sequence buffer and length of control sequence. */
  2640.  
  2641.     TEXT         SequenceBuffer[81];
  2642.     int         SequenceLen;
  2643.  
  2644.         /* Input length, current cursor position index, last history buffer. */
  2645.  
  2646.     int         Len        = 0,
  2647.              Index        = 0,
  2648.              HistoryIndex    = LastHistory + 1,
  2649.              i;
  2650.  
  2651.         /* Undo buffer area. */
  2652.  
  2653.     char        *UndoBuffer;
  2654.     int         UndoLen,
  2655.              UndoIndex;
  2656.  
  2657.         /* The character to read. */
  2658.  
  2659.     UBYTE         Char;
  2660.  
  2661.         /* Initial cursor X position. */
  2662.  
  2663.     UWORD         InitialCursorX    = CursorX;
  2664.  
  2665.         /* Loop flag. */
  2666.  
  2667.     Bool         Done        = FALSE;
  2668.  
  2669.         /* Prepare the undo buffer. */
  2670.  
  2671.     UndoBuffer = malloc(MaxLen);
  2672.  
  2673.     UndoLen = UndoIndex = 0;
  2674.  
  2675.         /* Change the font if necessary. */
  2676.  
  2677.     ConSetFont(FONT_PROP);
  2678.  
  2679.         /* Activate the size verify option. */
  2680.  
  2681.     ModifyIDCMP(Window,Window -> IDCMPFlags | IDCMP_SIZEVERIFY);
  2682.  
  2683.         /* Read until done. */
  2684.  
  2685.     do
  2686.     {
  2687.             /* Get a character. */
  2688.  
  2689.         switch(Char = ConGetChar(FALSE))
  2690.         {
  2691.                 /* A function key, a cursor key or the help key. */
  2692.  
  2693.             case TERM_CSI:    SequenceLen = 0;
  2694.  
  2695.                         /* Read the whole sequence if possible,
  2696.                          * up to 80 characters will be accepted.
  2697.                          */
  2698.  
  2699.                     do
  2700.                         SequenceBuffer[SequenceLen++] = Char = ConGetChar(FALSE);
  2701.                     while(SequenceLen < 80 && (Char == ' ' || Char == ';' || Char == '?' || (Char >= '0' && Char <= '9')));
  2702.  
  2703.                         /* Provide null-termination. */
  2704.  
  2705.                     SequenceBuffer[SequenceLen] = 0;
  2706.  
  2707.                         /* Function key. */
  2708.  
  2709.                     if(SequenceBuffer[0] != '?' && SequenceBuffer[SequenceLen - 1] == '~')
  2710.                     {
  2711.                         int Key;
  2712.  
  2713.                             /* Remove the terminating tilde. */
  2714.  
  2715.                         SequenceBuffer[SequenceLen - 1] = 0;
  2716.  
  2717.                             /* Make sure that the function
  2718.                              * key code is in reasonable
  2719.                              * dimensions, some custom
  2720.                              * keyboards have more than
  2721.                              * 20 function keys.
  2722.                              */
  2723.  
  2724.                         if((Key = atoi(SequenceBuffer)) < NUM_FKEYS)
  2725.                         {
  2726.                                 /* Is a string assigned to
  2727.                                  * this function key?
  2728.                                  */
  2729.  
  2730.                             if(FunctionKeys[Key] . sb_Len)
  2731.                             {
  2732.                                 Bool    GotIt = FALSE;
  2733.                                 int    i;
  2734.  
  2735.                                     /* Examine the string and look
  2736.                                      * for a bar or exclamation mark
  2737.                                      * which will terminate the
  2738.                                      * string and produce a carriage-
  2739.                                      * return.
  2740.                                      */
  2741.  
  2742.                                 for(i = 0 ; i < FunctionKeys[Key] . sb_Len ; i++)
  2743.                                 {
  2744.                                         /* Is this the character we are looking for? */
  2745.  
  2746.                                     if(FunctionKeys[Key] . sb_Buffer[i] == '|' || FunctionKeys[Key] . sb_Buffer[i] == '!')
  2747.                                     {
  2748.                                             /* Save the previous input buffer contents. */
  2749.  
  2750.                                         if(Len && UndoBuffer)
  2751.                                             memcpy(UndoBuffer,Input,Len);
  2752.  
  2753.                                         UndoLen        = Len;
  2754.                                         UndoIndex    = Index;
  2755.  
  2756.                                             /* Copy the string. */
  2757.  
  2758.                                         memcpy(InputBuffer,FunctionKeys[Key] . sb_Buffer,i);
  2759.  
  2760.                                             /* Add the carriage-return. */
  2761.  
  2762.                                         InputBuffer[i++] = '\r';
  2763.                                         InputBuffer[i]   = 0;
  2764.  
  2765.                                             /* Stop the search and
  2766.                                              * remember that we got
  2767.                                              * a fitting string.
  2768.                                              */
  2769.  
  2770.                                         GotIt = TRUE;
  2771.  
  2772.                                         break;
  2773.                                     }
  2774.                                 }
  2775.  
  2776.                                     /* Provide new input. */
  2777.  
  2778.                                 if(GotIt)
  2779.                                     InputIndex = InputBuffer;
  2780.                                 else
  2781.                                     InputIndex = FunctionKeys[Key] . sb_Buffer;
  2782.                             }
  2783.                             else
  2784.                                 DisplayBeep(Window -> WScreen);
  2785.                         }
  2786.  
  2787.                         break;
  2788.                     }
  2789.  
  2790.                         /* Help key. */
  2791.  
  2792.                     if(DoHistory && !strcmp(SequenceBuffer,"?~"))
  2793.                     {
  2794.                             /* Which function key is pressed? */
  2795.  
  2796.                         int WhichKey = -1;
  2797.  
  2798.                             /* Do not produce any `fake' input. */
  2799.  
  2800.                         InputIndex = NULL;
  2801.  
  2802.                             /* Reset the text colour. */
  2803.  
  2804.                         ConSetColour(COLOUR_TEXT);
  2805.  
  2806.                         ConCursorOff();
  2807.  
  2808.                             /* Clear the input line. */
  2809.  
  2810.                         ConSet(0,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  2811.  
  2812.                             /* Ask for the function key to
  2813.                              * assign a string to.
  2814.                              */
  2815.  
  2816.                         ConPrintf("Function key to define: ");
  2817.                         ConClearEOL();
  2818.  
  2819.                         ConCursorOn(CURSOR_NOCHANGE);
  2820.  
  2821.                             /* Is the first character we get
  2822.                              * a control-sequence introducer?
  2823.                              */
  2824.  
  2825.                         if(ConGetChar(FALSE) == TERM_CSI)
  2826.                         {
  2827.                             SequenceLen = 0;
  2828.  
  2829.                                 /* Read the whole sequence if possible,
  2830.                                  * up to 80 characters will be accepted.
  2831.                                  */
  2832.  
  2833.                             do
  2834.                                 SequenceBuffer[SequenceLen++] = Char = ConGetChar(FALSE);
  2835.                             while(SequenceLen < 80 && (Char == ' ' || Char == ';' || Char == '?' || (Char >= '0' && Char <= '9')));
  2836.  
  2837.                                 /* Provide null-termination. */
  2838.  
  2839.                             SequenceBuffer[SequenceLen] = 0;
  2840.  
  2841.                                 /* Did we get a function key code? */
  2842.  
  2843.                             if(SequenceBuffer[0] != '?' && SequenceBuffer[SequenceLen - 1] == '~')
  2844.                             {
  2845.                                     /* The function key we got. */
  2846.  
  2847.                                 int Key;
  2848.  
  2849.                                     /* Remove the terminating tilde. */
  2850.  
  2851.                                 SequenceBuffer[SequenceLen - 1] = 0;
  2852.  
  2853.                                     /* Get the number of the key. */
  2854.  
  2855.                                 if((Key = atoi(SequenceBuffer)) < NUM_FKEYS)
  2856.                                     WhichKey = Key;
  2857.                             }
  2858.                         }
  2859.  
  2860.                         ConCursorOff();
  2861.  
  2862.                             /* Return to input colour. */
  2863.  
  2864.                         ConSetColour(COLOUR_INPUT);
  2865.  
  2866.                             /* Did we get any key? */
  2867.  
  2868.                         if(WhichKey == -1)
  2869.                             ConPrintf("None.");
  2870.                         else
  2871.                         {
  2872.                             int Len;
  2873.  
  2874.                                 /* Print the key name. */
  2875.  
  2876.                             ConPrintf("%sF%d",(WhichKey > 9) ? "Shift " : "",(WhichKey % 10) + 1);
  2877.  
  2878.                                 /* Provide new line. */
  2879.  
  2880.                             ConScrollUp();
  2881.  
  2882.                                 /* Set text colour. */
  2883.  
  2884.                             ConSetColour(COLOUR_TEXT);
  2885.  
  2886.                                 /* Show new prompt. */
  2887.  
  2888.                             ConPrintf("Key text >");
  2889.  
  2890.                             ConCursorOn(CURSOR_NOCHANGE);
  2891.  
  2892.                                 /* Return to input colour. */
  2893.  
  2894.                             ConSetColour(COLOUR_INPUT);
  2895.  
  2896.                             InputIndex = NULL;
  2897.  
  2898.                                 /* Read key assignment. */
  2899.  
  2900.                             Len = ConInput("",InputBuffer,0,FALSE);
  2901.  
  2902.                                 /* Set new key string. */
  2903.  
  2904.                             ConSetKey(WhichKey,InputBuffer,Len);
  2905.  
  2906.                             ConCursorOff();
  2907.                         }
  2908.  
  2909.                             /* Provide new line. */
  2910.  
  2911.                         ConScrollUp();
  2912.  
  2913.                             /* Set text colour. */
  2914.  
  2915.                         ConSetColour(COLOUR_TEXT);
  2916.  
  2917.                             /* Print the prompt string. */
  2918.  
  2919.                         ConPrintf(Prompt);
  2920.  
  2921.                             /* Set input colour. */
  2922.  
  2923.                         ConSetColour(COLOUR_INPUT);
  2924.  
  2925.                             /* Write the entire input line. */
  2926.  
  2927.                         ConWrite(Input,Len,0);
  2928.  
  2929.                             /* Make sure that the
  2930.                              * cursor is placed at
  2931.                              * the end of the input
  2932.                              * line.
  2933.                              */
  2934.  
  2935.                         Index = Len;
  2936.  
  2937.                         InputIndex = NULL;
  2938.  
  2939.                         ConCursorOn(CURSOR_AVERAGE);
  2940.  
  2941.                         break;
  2942.                     }
  2943.  
  2944.                         /* Cursor up: recall previous line in history buffer. */
  2945.  
  2946.                     if(!strcmp(SequenceBuffer,"A"))
  2947.                     {
  2948.                             /* Are any history lines available? */
  2949.  
  2950.                         if(LastHistory != -1)
  2951.                         {
  2952.                             ConCursorOff();
  2953.  
  2954.                                 /* Move cursor back
  2955.                                  * to beginning of
  2956.                                  * line.
  2957.                                  */
  2958.  
  2959.                             if(Index)
  2960.                                 ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  2961.  
  2962.                                 /* Clear line. */
  2963.  
  2964.                             ConClearEOL();
  2965.  
  2966.                                 /* Go to previous history line. */
  2967.  
  2968.                             if(HistoryIndex)
  2969.                                 HistoryIndex--;
  2970.  
  2971.                                 /* Save the previous input buffer contents. */
  2972.  
  2973.                             if(Len && UndoBuffer)
  2974.                                 memcpy(UndoBuffer,Input,Len);
  2975.  
  2976.                             UndoLen        = Len;
  2977.                             UndoIndex    = Index;
  2978.  
  2979.                                 /* Determine history line length. */
  2980.  
  2981.                             if(MaxLen)
  2982.                                 Index = Len = MIN(MaxLen,HistoryBuffer[HistoryIndex] . sb_Len);
  2983.                             else
  2984.                                 Index = Len = HistoryBuffer[HistoryIndex] . sb_Len;
  2985.  
  2986.                                 /* Copy the history line over. */
  2987.  
  2988.                             memcpy(Input,HistoryBuffer[HistoryIndex] . sb_Buffer,Len);
  2989.  
  2990.                                 /* Write the line. */
  2991.  
  2992.                             ConWrite(Input,Len,0);
  2993.  
  2994.                             ConCursorOn(CURSOR_NOCHANGE);
  2995.                         }
  2996.  
  2997.                         break;
  2998.                     }
  2999.  
  3000.                         /* Cursor down: recall next line in history buffer. */
  3001.  
  3002.                     if(!strcmp(SequenceBuffer,"B"))
  3003.                     {
  3004.                             /* Are any history lines available? */
  3005.  
  3006.                         if(LastHistory != -1)
  3007.                         {
  3008.                             ConCursorOff();
  3009.  
  3010.                                 /* Are we at the end
  3011.                                  * of the list?
  3012.                                  */
  3013.  
  3014.                             if(HistoryIndex < LastHistory)
  3015.                             {
  3016.                                     /* Move cursor back
  3017.                                      * to beginning of
  3018.                                      * line.
  3019.                                      */
  3020.  
  3021.                                 if(Index)
  3022.                                     ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  3023.  
  3024.                                     /* Clear line. */
  3025.  
  3026.                                 ConClearEOL();
  3027.  
  3028.                                     /* Get next history line. */
  3029.  
  3030.                                 HistoryIndex++;
  3031.  
  3032.                                     /* Save the previous input buffer contents. */
  3033.  
  3034.                                 if(Len && UndoBuffer)
  3035.                                     memcpy(UndoBuffer,Input,Len);
  3036.  
  3037.                                 UndoLen        = Len;
  3038.                                 UndoIndex    = Index;
  3039.  
  3040.                                     /* Determine history line length. */
  3041.  
  3042.                                 if(MaxLen)
  3043.                                     Index = Len = MIN(MaxLen,HistoryBuffer[HistoryIndex] . sb_Len);
  3044.                                 else
  3045.                                     Index = Len = HistoryBuffer[HistoryIndex] . sb_Len;
  3046.  
  3047.                                     /* Copy the history line over. */
  3048.  
  3049.                                 memcpy(Input,HistoryBuffer[HistoryIndex] . sb_Buffer,Len);
  3050.  
  3051.                                     /* Write the line. */
  3052.  
  3053.                                 ConWrite(Input,Len,0);
  3054.                             }
  3055.                             else
  3056.                             {
  3057.                                     /* Move cursor back
  3058.                                      * to beginning of
  3059.                                      * line.
  3060.                                      */
  3061.  
  3062.                                 if(Index)
  3063.                                     ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  3064.  
  3065.                                     /* Clear line. */
  3066.  
  3067.                                 ConClearEOL();
  3068.  
  3069.                                     /* Save the previous input buffer contents. */
  3070.  
  3071.                                 if(Len && UndoBuffer)
  3072.                                     memcpy(UndoBuffer,Input,Len);
  3073.  
  3074.                                 UndoLen        = Len;
  3075.                                 UndoIndex    = Index;
  3076.  
  3077.                                     /* Nothing in the line buffer right now. */
  3078.  
  3079.                                 Index = Len = 0;
  3080.  
  3081.                                     /* Make sure that `cursor up'
  3082.                                      * will recall the last history
  3083.                                      * line.
  3084.                                      */
  3085.  
  3086.                                 HistoryIndex = LastHistory + 1;
  3087.                             }
  3088.  
  3089.                             ConCursorOn(CURSOR_NOCHANGE);
  3090.                         }
  3091.  
  3092.                         break;
  3093.                     }
  3094.  
  3095.                         /* Shift + cursor up: recall first history line in buffer. */
  3096.  
  3097.                     if(!strcmp(SequenceBuffer,"T"))
  3098.                     {
  3099.                             /* Are any history lines available? */
  3100.  
  3101.                         if(LastHistory != -1)
  3102.                         {
  3103.                             ConCursorOff();
  3104.  
  3105.                                 /* Move cursor back
  3106.                                  * to beginning of
  3107.                                  * line.
  3108.                                  */
  3109.  
  3110.                             if(Index)
  3111.                                 ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  3112.  
  3113.                                 /* Clear line. */
  3114.  
  3115.                             ConClearEOL();
  3116.  
  3117.                                 /* Use the first history line. */
  3118.  
  3119.                             HistoryIndex = 0;
  3120.  
  3121.                                 /* Save the previous input buffer contents. */
  3122.  
  3123.                             if(Len && UndoBuffer)
  3124.                                 memcpy(UndoBuffer,Input,Len);
  3125.  
  3126.                             UndoLen        = Len;
  3127.                             UndoIndex    = Index;
  3128.  
  3129.                                 /* Determine history line length. */
  3130.  
  3131.                             if(MaxLen)
  3132.                                 Index = Len = MIN(MaxLen,HistoryBuffer[HistoryIndex] . sb_Len);
  3133.                             else
  3134.                                 Index = Len = HistoryBuffer[HistoryIndex] . sb_Len;
  3135.  
  3136.                                 /* Copy the history line over. */
  3137.  
  3138.                             memcpy(Input,HistoryBuffer[HistoryIndex] . sb_Buffer,Len);
  3139.  
  3140.                                 /* Write the line. */
  3141.  
  3142.                             ConWrite(Input,Len,0);
  3143.  
  3144.                             ConCursorOn(CURSOR_NOCHANGE);
  3145.                         }
  3146.  
  3147.                         break;
  3148.                     }
  3149.  
  3150.                         /* Shift + cursor down: recall last history line. */
  3151.  
  3152.                     if(!strcmp(SequenceBuffer,"S"))
  3153.                     {
  3154.                             /* Are any history lines available? */
  3155.  
  3156.                         if(LastHistory != -1)
  3157.                         {
  3158.                             ConCursorOff();
  3159.  
  3160.                                 /* Move cursor back
  3161.                                  * to beginning of
  3162.                                  * line.
  3163.                                  */
  3164.  
  3165.                             if(Index)
  3166.                                 ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  3167.  
  3168.                                 /* Clear line. */
  3169.  
  3170.                             ConClearEOL();
  3171.  
  3172.                                 /* Go to last line in history buffer. */
  3173.  
  3174.                             HistoryIndex = LastHistory;
  3175.  
  3176.                                 /* Save the previous input buffer contents. */
  3177.  
  3178.                             if(Len && UndoBuffer)
  3179.                                 memcpy(UndoBuffer,Input,Len);
  3180.  
  3181.                             UndoLen        = Len;
  3182.                             UndoIndex    = Index;
  3183.  
  3184.                                 /* Determine history line length. */
  3185.  
  3186.                             if(MaxLen)
  3187.                                 Index = Len = MIN(MaxLen,HistoryBuffer[HistoryIndex] . sb_Len);
  3188.                             else
  3189.                                 Index = Len = HistoryBuffer[HistoryIndex] . sb_Len;
  3190.  
  3191.                                 /* Copy the history line over. */
  3192.  
  3193.                             memcpy(Input,HistoryBuffer[HistoryIndex] . sb_Buffer,Len);
  3194.  
  3195.                                 /* Write the line. */
  3196.  
  3197.                             ConWrite(Input,Len,0);
  3198.  
  3199.                             ConCursorOn(CURSOR_NOCHANGE);
  3200.                         }
  3201.  
  3202.                         break;
  3203.                     }
  3204.  
  3205.                         /* Cursor right: move cursor to the right. */
  3206.  
  3207.                     if(!strcmp(SequenceBuffer,"C"))
  3208.                     {
  3209.                             /* Are we at the end of the line? */
  3210.  
  3211.                         if(Index < Len)
  3212.                         {
  3213.                             if(Index == Len - 1)
  3214.                                 ConMove(ConCharWidth(Input[Index]),-1);
  3215.                             else
  3216.                                 ConMove(ConCharWidth(Input[Index]),ConCharWidth(Input[Index + 1]));
  3217.  
  3218.                             Index++;
  3219.                         }
  3220.  
  3221.                         break;
  3222.                     }
  3223.  
  3224.                         /* Cursor left: move cursor to the left. */
  3225.  
  3226.                     if(!strcmp(SequenceBuffer,"D"))
  3227.                     {
  3228.                             /* Are we at the beginning of the line? */
  3229.  
  3230.                         if(Index > 0)
  3231.                         {
  3232.                                 /* Update internal cursor position. */
  3233.  
  3234.                             Index--;
  3235.  
  3236.                                 /* Move cursor to the left. */
  3237.  
  3238.                             ConMove(-ConCharWidth(Input[Index]),ConCharWidth(Input[Index]));
  3239.                         }
  3240.  
  3241.                         break;
  3242.                     }
  3243.  
  3244.                         /* Shift + cursor right: jump to next word. */
  3245.  
  3246.                     if(!strcmp(SequenceBuffer," @"))
  3247.                     {
  3248.                             /* Are we at the end of the line? */
  3249.  
  3250.                         if(Index < Len)
  3251.                         {
  3252.                             int i = Index;
  3253.  
  3254.                             while(i < Len && Input[i] != ' ')
  3255.                                 i++;
  3256.  
  3257.                             while(i < Len && Input[i] == ' ')
  3258.                                 i++;
  3259.  
  3260.                             if(i != Index)
  3261.                             {
  3262.                                 Index = i;
  3263.  
  3264.                                 if(Index == Len)
  3265.                                     ConSet(InitialCursorX + TextLength(RPort,Input,Index),TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  3266.                                 else
  3267.                                 {
  3268.                                     if(Index)
  3269.                                         ConSet(InitialCursorX + TextLength(RPort,Input,Index),TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
  3270.                                     else
  3271.                                         ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
  3272.                                 }
  3273.                             }
  3274.                         }
  3275.  
  3276.                         break;
  3277.                     }
  3278.  
  3279.                         /* Shift + cursor left: jump to previous word. */
  3280.  
  3281.                     if(!strcmp(SequenceBuffer," A"))
  3282.                     {
  3283.                             /* Are we at the beginning of the line? */
  3284.  
  3285.                         if(Index > 0)
  3286.                         {
  3287.                             int i = Index;
  3288.  
  3289.                             if(i > 0 && Input[i - 1] == ' ' && Input[i] != ' ')
  3290.                                 i--;
  3291.  
  3292.                             while(i > 0 && Input[i] == ' ')
  3293.                                 i--;
  3294.  
  3295.                             while(i > 0 && Input[i] != ' ')
  3296.                             {
  3297.                                 if(Input[i - 1] == ' ')
  3298.                                     break;
  3299.                                 else
  3300.                                     i--;
  3301.                             }
  3302.  
  3303.                             if(i != Index)
  3304.                             {
  3305.                                 Index = i;
  3306.  
  3307.                                 if(Index == Len)
  3308.                                     ConSet(InitialCursorX + TextLength(RPort,Input,Index),TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  3309.                                 else
  3310.                                 {
  3311.                                     if(Index)
  3312.                                         ConSet(InitialCursorX + TextLength(RPort,Input,Index),TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
  3313.                                     else
  3314.                                         ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
  3315.                                 }
  3316.                             }
  3317.                         }
  3318.                     }
  3319.  
  3320.                     break;
  3321.  
  3322.  
  3323.                 /* Form feed: window was resized. */
  3324.  
  3325.             case TERM_RESIZE:
  3326.  
  3327.                     if(Window -> Width != OldWindowWidth || Window -> Height != OldWindowHeight)
  3328.                     {
  3329.                         Bool NewPrompt = FALSE;
  3330.  
  3331.                             /* Has the width changed? */
  3332.  
  3333.                         if(Window -> Width != OldWindowWidth)
  3334.                         {
  3335.                                 /* Determine new window width. */
  3336.  
  3337.                             WindowWidth = Window -> Width - (WindowBorderLeft + WindowBorderRight);
  3338.  
  3339.                                 /* If the input line has become
  3340.                                  * too long for the window to
  3341.                                  * hold, trim it.
  3342.                                  */
  3343.  
  3344.                             if(InitialCursorX + TextLength(RPort,Input,Len) + TextFontWidth + ConCharWidth(Char) >= WindowWidth)
  3345.                             {
  3346.                                 while(Len > 0 && InitialCursorX + TextLength(RPort,Input,Len) + TextFontWidth + ConCharWidth(Char) >= WindowWidth)
  3347.                                     Len--;
  3348.  
  3349.                                     /* Turn off the cursor. */
  3350.  
  3351.                                 ConCursorOff();
  3352.  
  3353.                                     /* Is the prompt too long? If so,
  3354.                                      * use a single character.
  3355.                                      */
  3356.  
  3357.                                 if(Len < 0)
  3358.                                 {
  3359.                                     InitialCursorX = ConCharWidth('>');
  3360.  
  3361.                                     Prompt = ">";
  3362.                                 }
  3363.  
  3364.                                     /* Redraw prompt and input string. */
  3365.  
  3366.                                 NewPrompt = TRUE;
  3367.                             }
  3368.  
  3369.                                 /* Remember new window width. */
  3370.  
  3371.                             OldWindowWidth = Window -> Width;
  3372.  
  3373.                                 /* Print the score line. */
  3374.  
  3375.                             scr_putscore();
  3376.                         }
  3377.  
  3378.                             /* Has the height changed? */
  3379.  
  3380.                         if(Window -> Height != OldWindowHeight)
  3381.                         {
  3382.                             WORD Remainder;
  3383.  
  3384.                                 /* Has the window become less high?
  3385.                                  * If so, clear the area below the
  3386.                                  * input line.
  3387.                                  */
  3388.  
  3389.                             if((Remainder = Window -> Height - (WindowBorderTop + ConNumLines * TextFontHeight + WindowBorderBottom)) > 0)
  3390.                             {
  3391.                                     /* The cursor has probably
  3392.                                      * already been erased,
  3393.                                      * so let's better ignore
  3394.                                      * it.
  3395.                                      */
  3396.  
  3397.                                 CursorEnabled = FALSE;
  3398.  
  3399.                                 SetAPen(RPort,ConBackPen);
  3400.                                 RectFill(RPort,WindowBorderLeft,Window -> Height - (WindowBorderBottom + Remainder),Window -> Width - (WindowBorderRight + 1),Window -> Height - (WindowBorderBottom + 1));
  3401.                                 SetAPen(RPort,ConTextPen);
  3402.                             }
  3403.  
  3404.                                 /* Turn the cursor off. */
  3405.  
  3406.                             ConCursorOff();
  3407.  
  3408.                                 /* If the window has become higher,
  3409.                                  * erase the previous prompt.
  3410.                                  */
  3411.  
  3412.                             if(Window -> Height > OldWindowHeight)
  3413.                             {
  3414.                                 ConSet(0,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  3415.  
  3416.                                 ConClearEOL();
  3417.                             }
  3418.  
  3419.                                 /* Determine new number of lines. */
  3420.  
  3421.                             ConNumLines = (Window -> Height - (WindowBorderTop + WindowBorderBottom)) / TextFontHeight;
  3422.  
  3423.                                 /* Redraw both prompt and input string. */
  3424.  
  3425.                             NewPrompt = TRUE;
  3426.  
  3427.                                 /* Remember new window height. */
  3428.  
  3429.                             OldWindowHeight = Window -> Height;
  3430.  
  3431.                                 /* Clear the area below the input line. */
  3432.  
  3433.                             if((Remainder = Window -> Height - (WindowBorderTop + ConNumLines * TextFontHeight + WindowBorderBottom)) > 0)
  3434.                             {
  3435.                                 SetAPen(RPort,ConBackPen);
  3436.                                 RectFill(RPort,WindowBorderLeft,Window -> Height - (WindowBorderBottom + Remainder),Window -> Width - (WindowBorderRight + 1),Window -> Height - (WindowBorderBottom + 1));
  3437.                                 SetAPen(RPort,ConTextPen);
  3438.                             }
  3439.                         }
  3440.  
  3441.                             /* Are we to redraw prompt and input string? */
  3442.  
  3443.                         if(NewPrompt)
  3444.                         {
  3445.                                 /* Move to bottom of window. */
  3446.  
  3447.                             ConSet(0,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  3448.  
  3449.                                 /* Set text colour. */
  3450.  
  3451.                             ConSetColour(COLOUR_TEXT);
  3452.  
  3453.                                 /* Print the prompt string. */
  3454.  
  3455.                             ConPrintf(Prompt);
  3456.  
  3457.                                 /* Set input colour. */
  3458.  
  3459.                             ConSetColour(COLOUR_INPUT);
  3460.  
  3461.                                 /* Write the entire input line. */
  3462.  
  3463.                             ConWrite(Input,Len,0);
  3464.  
  3465.                                 /* Clear the rest of the line. */
  3466.  
  3467.                             ConClearEOL();
  3468.  
  3469.                                 /* Make sure that the
  3470.                                  * cursor is placed at
  3471.                                  * the end of the input
  3472.                                  * line.
  3473.                                  */
  3474.  
  3475.                             Index = Len;
  3476.  
  3477.                             InputIndex = NULL;
  3478.  
  3479.                             ConCursorOn(CURSOR_AVERAGE);
  3480.                         }
  3481.                     }
  3482.  
  3483.                     break;
  3484.  
  3485.                 /* Control-\: close the window. */
  3486.  
  3487.             case TERM_CLOSE:
  3488.  
  3489.                     if(Len > 0)
  3490.                     {
  3491.                             /* Move to beginning of line. */
  3492.  
  3493.                         if(Index)
  3494.                             ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  3495.  
  3496.                             /* Clear line contents. */
  3497.  
  3498.                         ConClearEOL();
  3499.  
  3500.                             /* Nothing in the line buffer right now. */
  3501.  
  3502.                         Index = Len = 0;
  3503.                     }
  3504.  
  3505.                         /* Drop clipboard processing. */
  3506.  
  3507.                     ClipClose();
  3508.  
  3509.                         /* Provide fake input. */
  3510.  
  3511.                     InputIndex = "Quit\r";
  3512.  
  3513.                     break;
  3514.  
  3515.                 /* Control-A: move cursor to beginning of line. */
  3516.  
  3517.             case TERM_BEGIN:
  3518.  
  3519.                     if(Index > 0)
  3520.                     {
  3521.                             /* Move cursor to beginning of line. */
  3522.  
  3523.                         if(Len)
  3524.                             ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[0]));
  3525.                         else
  3526.                             ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  3527.  
  3528.                             /* Update internal cursor position. */
  3529.  
  3530.                         Index = 0;
  3531.                     }
  3532.  
  3533.                     break;
  3534.  
  3535.                 /* Control-Z: move cursor to end of line. */
  3536.  
  3537.             case TERM_END:    if(Index < Len)
  3538.                     {
  3539.                             /* Move cursor to end of line. */
  3540.  
  3541.                         ConMove(TextLength(RPort,&Input[Index],Len - Index),-1);
  3542.  
  3543.                             /* Update internal cursor position. */
  3544.  
  3545.                         Index = Len;
  3546.                     }
  3547.  
  3548.                     break;
  3549.  
  3550.                 /* Control-C: copy input line. */
  3551.  
  3552.             case TERM_COPY:    if(UndoBuffer)
  3553.                     {
  3554.                         if(Len && UndoBuffer)
  3555.                             memcpy(UndoBuffer,Input,Len);
  3556.  
  3557.                         UndoLen        = Len;
  3558.                         UndoIndex    = Index;
  3559.                     }
  3560.                     else
  3561.                         DisplayBeep(Window -> WScreen);
  3562.  
  3563.                     if(Len)
  3564.                         ClipSave(Input,Len);
  3565.  
  3566.                     break;
  3567.  
  3568.                 /* Control-X: delete the entire line contents. */
  3569.  
  3570.             case TERM_CUT:    if(Len > 0)
  3571.                     {
  3572.                         ClipSave(Input,Len);
  3573.  
  3574.                             /* Save the previous input buffer contents. */
  3575.  
  3576.                         if(UndoBuffer)
  3577.                             memcpy(UndoBuffer,Input,Len);
  3578.  
  3579.                         UndoLen        = Len;
  3580.                         UndoIndex    = Index;
  3581.  
  3582.                             /* Move to beginning of line. */
  3583.  
  3584.                         if(Index)
  3585.                             ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  3586.  
  3587.                             /* Clear line contents. */
  3588.  
  3589.                         ConClearEOL();
  3590.  
  3591.                             /* Nothing in the line buffer right now. */
  3592.  
  3593.                         Index = Len = 0;
  3594.                     }
  3595.  
  3596.                     break;
  3597.  
  3598.                 /* Control-Y: undo previous editing action. */
  3599.  
  3600.             case TERM_UNDO:    if(UndoBuffer)
  3601.                     {
  3602.                         int OldLen,OldIndex;
  3603.  
  3604.                         if(Len > 0)
  3605.                         {
  3606.                                 /* Move to beginning of line. */
  3607.  
  3608.                             if(Index)
  3609.                                 ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  3610.  
  3611.                                 /* Clear line contents. */
  3612.  
  3613.                             ConClearEOL();
  3614.                         }
  3615.  
  3616.                             /* Set new cursor size. */
  3617.  
  3618.                         ConCursorOff();
  3619.                         ConCursorOn(CURSOR_AVERAGE);
  3620.  
  3621.                             /* Copy the input line. */
  3622.  
  3623.                         ConSwap(Input,UndoBuffer,MaxLen);
  3624.  
  3625.                             /* Restore length and index. */
  3626.  
  3627.                         OldLen        = Len;
  3628.                         OldIndex    = Index;
  3629.  
  3630.                         Len        = UndoLen;
  3631.                         Index        = UndoIndex;
  3632.  
  3633.                         UndoLen        = OldLen;
  3634.                         UndoIndex    = OldIndex;
  3635.  
  3636.                             /* Move the cursor. */
  3637.  
  3638.                         if(Index && Len)
  3639.                         {
  3640.                             if(Index == Len)
  3641.                                 ConSet(InitialCursorX + TextLength(RPort,Input,Index),TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  3642.                             else
  3643.                             {
  3644.                                 if(Index)
  3645.                                     ConSet(InitialCursorX + TextLength(RPort,Input,Index),TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
  3646.                                 else
  3647.                                     ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
  3648.                             }
  3649.                         }
  3650.  
  3651.                             /* Redraw the input line. */
  3652.  
  3653.                         RedrawInputLine = TRUE;
  3654.                     }
  3655.                     else
  3656.                         DisplayBeep(Window -> WScreen);
  3657.  
  3658.                     break;
  3659.  
  3660.                 /* Backspace: delete the character to the left
  3661.                  * of the cursor.
  3662.                  */
  3663.  
  3664.             case TERM_BS:    if(Index > 0)
  3665.                     {
  3666.                             /* Save the previous input buffer contents. */
  3667.  
  3668.                         if(Len && UndoBuffer)
  3669.                             memcpy(UndoBuffer,Input,Len);
  3670.  
  3671.                         UndoLen        = Len;
  3672.                         UndoIndex    = Index;
  3673.  
  3674.                             /* Delete the character. */
  3675.  
  3676.                         if(Index == Len)
  3677.                             ConCharBackspace(ConCharWidth(Input[Index - 1]),-1);
  3678.                         else
  3679.                             ConCharBackspace(ConCharWidth(Input[Index - 1]),ConCharWidth(Input[Index]));
  3680.  
  3681.                             /* Move line contents. */
  3682.  
  3683.                         for(i = Index - 1 ; i < Len - 1 ; i++)
  3684.                             Input[i] = Input[i + 1];
  3685.  
  3686.                             /* Update internal cursor position. */
  3687.  
  3688.                         Index--;
  3689.  
  3690.                             /* Update line length. */
  3691.  
  3692.                         Len--;
  3693.                     }
  3694.  
  3695.                     break;
  3696.  
  3697.                 /* Delete: delete the character under the cursor. */
  3698.  
  3699.             case TERM_DEL:    if(Index < Len)
  3700.                     {
  3701.                             /* Save the previous input buffer contents. */
  3702.  
  3703.                         if(Len && UndoBuffer)
  3704.                             memcpy(UndoBuffer,Input,Len);
  3705.  
  3706.                         UndoLen        = Len;
  3707.                         UndoIndex    = Index;
  3708.  
  3709.                             /* Delete the character. */
  3710.  
  3711.                         if(Index == Len - 1)
  3712.                             ConCharDelete(CURSOR_AVERAGE);
  3713.                         else
  3714.                             ConCharDelete(ConCharWidth(Input[Index + 1]));
  3715.  
  3716.                             /* Move line contents. */
  3717.  
  3718.                         for(i = Index ; i < Len - 1 ; i++)
  3719.                             Input[i] = Input[i + 1];
  3720.  
  3721.                             /* Update line length. */
  3722.  
  3723.                         Len--;
  3724.                     }
  3725.  
  3726.                     break;
  3727.  
  3728.                 /* Control-K: delete everything from the cursor forward
  3729.                  * to the end of the line.
  3730.                  */
  3731.  
  3732.             case TERM_DELFWD:
  3733.  
  3734.                         /* Save the previous input buffer contents. */
  3735.  
  3736.                     if(Len && UndoBuffer)
  3737.                         memcpy(UndoBuffer,Input,Len);
  3738.  
  3739.                     UndoLen        = Len;
  3740.                     UndoIndex    = Index;
  3741.  
  3742.                         /* Cut off the remaining line. */
  3743.  
  3744.                     Len = Index;
  3745.  
  3746.                         /* Set new cursor size. */
  3747.  
  3748.                     ConCursorOff();
  3749.                     ConCursorOn(CURSOR_AVERAGE);
  3750.  
  3751.                         /* Redraw the input line. */
  3752.  
  3753.                     RedrawInputLine = TRUE;
  3754.  
  3755.                     break;
  3756.  
  3757.                 /* Control-U: delete everything from the cursor backward
  3758.                  * to the start of the line.
  3759.                  */
  3760.  
  3761.             case TERM_DELBCK:
  3762.  
  3763.                         /* Save the previous input buffer contents. */
  3764.  
  3765.                     if(Len && UndoBuffer)
  3766.                         memcpy(UndoBuffer,Input,Len);
  3767.  
  3768.                     UndoLen        = Len;
  3769.                     UndoIndex    = Index;
  3770.  
  3771.                         /* Is there anything to clear? */
  3772.  
  3773.                     if(Index > 0 && Len > 0)
  3774.                     {
  3775.                             /* Are we to clear the entire line? */
  3776.  
  3777.                         if(Index == Len)
  3778.                         {
  3779.                                 /* Move to beginning of line. */
  3780.  
  3781.                             ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  3782.  
  3783.                                 /* Clear line contents. */
  3784.  
  3785.                             ConClearEOL();
  3786.  
  3787.                                 /* Nothing in the line buffer right now. */
  3788.  
  3789.                             Index = Len = 0;
  3790.                         }
  3791.                         else
  3792.                         {
  3793.                                 /* Move line contents. */
  3794.  
  3795.                             for(i = 0 ; i < Len - Index ; i++)
  3796.                                 Input[i] = Input[Index + i];
  3797.  
  3798.                                 /* Update length and index. */
  3799.  
  3800.                             Len    -= Index;
  3801.                             Index     = 0;
  3802.  
  3803.                                 /* Reposition the cursor. */
  3804.  
  3805.                             if(Len)
  3806.                             {
  3807.                                 if(Index)
  3808.                                     ConSet(InitialCursorX + TextLength(RPort,Input,Index),TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
  3809.                                 else
  3810.                                     ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
  3811.                             }
  3812.                             else
  3813.                                 ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  3814.  
  3815.                                 /* Redraw the input line. */
  3816.  
  3817.                             RedrawInputLine = TRUE;
  3818.                         }
  3819.                     }
  3820.  
  3821.                     break;
  3822.  
  3823.                 /* Control-W: delete the word to the left of the cursor. */
  3824.  
  3825.             case TERM_DELWORD:
  3826.  
  3827.                         /* Anything to delete? */
  3828.  
  3829.                     if(Len > 0 && Index > 0)
  3830.                     {
  3831.                         int Diff,Offset = Index - 1;
  3832.  
  3833.                             /* Save the previous input buffer contents. */
  3834.  
  3835.                         if(Len && UndoBuffer)
  3836.                             memcpy(UndoBuffer,Input,Len);
  3837.  
  3838.                         UndoLen        = Len;
  3839.                         UndoIndex    = Index;
  3840.  
  3841.                             /* Find the start of the previous word. */
  3842.  
  3843.                         for(i = Index - 1 ; i >= 0 ; i--)
  3844.                         {
  3845.                             if(i)
  3846.                             {
  3847.                                 if(Input[i] == ' ')
  3848.                                 {
  3849.                                     Offset = i + 1;
  3850.  
  3851.                                     break;
  3852.                                 }
  3853.                             }
  3854.                             else
  3855.                             {
  3856.                                 Offset = i;
  3857.  
  3858.                                 break;
  3859.                             }
  3860.  
  3861.                         }
  3862.  
  3863.                             /* Too much to move? */
  3864.  
  3865.                         if(!(Diff = Index - Offset))
  3866.                         {
  3867.                             Diff    = 1;
  3868.                             Offset    = Index - 1;
  3869.                         }
  3870.  
  3871.                             /* Move the line over. */
  3872.  
  3873.                         for(i = Offset ; i < Len - Diff ; i++)
  3874.                             Input[i] = Input[i + Diff];
  3875.  
  3876.                         Index    -= Diff;
  3877.                         Len    -= Diff;
  3878.  
  3879.                             /* Move the cursor. */
  3880.  
  3881.                         if(Len)
  3882.                         {
  3883.                             if(Index)
  3884.                                 ConSet(InitialCursorX + TextLength(RPort,Input,Index),TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
  3885.                             else
  3886.                                 ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
  3887.                         }
  3888.                         else
  3889.                             ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  3890.  
  3891.                             /* Redraw the input line. */
  3892.  
  3893.                         RedrawInputLine = TRUE;
  3894.                     }
  3895.  
  3896.                     break;
  3897.  
  3898.                 /* Carriage return: terminate input. */
  3899.  
  3900.             case TERM_CR:    Done = TRUE;
  3901.  
  3902.                     break;
  3903.  
  3904.                 /* If suitable, store the character entered. */
  3905.  
  3906.             default:    if(Char >= ' ' && Char <= '~')
  3907.                     {
  3908.                             /* Is there a length limit? */
  3909.  
  3910.                         if(!MaxLen || Len < MaxLen)
  3911.                         {
  3912.                                 /* If the resulting string will become
  3913.                                  * too long to fit in the window, don't
  3914.                                  * store the new character.
  3915.                                  */
  3916.  
  3917.                             if(InitialCursorX + TextLength(RPort,Input,Len) + TextFontWidth + ConCharWidth(Char) < WindowWidth)
  3918.                             {
  3919.                                     /* Save the previous input buffer contents. */
  3920.  
  3921.                                 if(Len && UndoBuffer)
  3922.                                     memcpy(UndoBuffer,Input,Len);
  3923.  
  3924.                                 UndoLen        = Len;
  3925.                                 UndoIndex    = Index;
  3926.  
  3927.                                     /* Print the character. */
  3928.  
  3929.                                 ConCharInsert(Char);
  3930.  
  3931.                                     /* Move line contents up if
  3932.                                      * necessary.
  3933.                                      */
  3934.  
  3935.                                 if(Index < Len)
  3936.                                 {
  3937.                                     for(i = Len ; i > Index ; i--)
  3938.                                         Input[i] = Input[i - 1];
  3939.                                 }
  3940.  
  3941.                                     /* Store the character. */
  3942.  
  3943.                                 Input[Index++] = Char;
  3944.  
  3945.                                     /* Update line length. */
  3946.  
  3947.                                 Len++;
  3948.                             }
  3949.                         }
  3950.                     }
  3951.  
  3952.                     break;
  3953.         }
  3954.  
  3955.             /* Are we to redraw the input line? */
  3956.  
  3957.         if(RedrawInputLine)
  3958.         {
  3959.             ConRedraw(InitialCursorX,TextFontHeight * (ConNumLines - 1),Input,Len);
  3960.  
  3961.             RedrawInputLine = FALSE;
  3962.         }
  3963.     }
  3964.     while(!Done);
  3965.  
  3966.         /* Turn off the size verify option. */
  3967.  
  3968.     ModifyIDCMP(Window,Window -> IDCMPFlags & ~IDCMP_SIZEVERIFY);
  3969.  
  3970.         /* Did the user enter anything? */
  3971.  
  3972.     if(Len && DoHistory)
  3973.     {
  3974.             /* Move up if space is exhausted. */
  3975.  
  3976.         if(LastHistory == HISTORY_LINES - 1)
  3977.         {
  3978.                 /* Free first line in history buffer. */
  3979.  
  3980.             free(HistoryBuffer[0] . sb_Buffer);
  3981.  
  3982.                 /* Move previous contents up. */
  3983.  
  3984.             for(i = 1 ; i < HISTORY_LINES ; i++)
  3985.                 HistoryBuffer[i - 1] = HistoryBuffer[i];
  3986.         }
  3987.         else
  3988.             LastHistory++;
  3989.  
  3990.             /* Add next history line. */
  3991.  
  3992.         if(HistoryBuffer[LastHistory] . sb_Buffer = (char *)malloc(Len))
  3993.         {
  3994.                 /* Copy the input line. */
  3995.  
  3996.             memcpy(HistoryBuffer[LastHistory] . sb_Buffer,Input,Len);
  3997.  
  3998.                 /* Save the line length. */
  3999.  
  4000.             HistoryBuffer[LastHistory] . sb_Len = Len;
  4001.         }
  4002.         else
  4003.             LastHistory--;
  4004.     }
  4005.  
  4006.         /* Drop the undo buffer. */
  4007.  
  4008.     if(UndoBuffer)
  4009.         free(UndoBuffer);
  4010.  
  4011.         /* Close the clipboard, we don't want multiple
  4012.          * lines to be returned.
  4013.          */
  4014.  
  4015.     ClipClose();
  4016.  
  4017.         /* Return number of characters entered. */
  4018.  
  4019.     return(Len);
  4020. }
  4021.  
  4022.     /* ConPrintStatus(const char *Left,const char *Right):
  4023.      *
  4024.      *    Print the status line.
  4025.      */
  4026.  
  4027. VOID
  4028. ConPrintStatus(const char *Left,const char *Right)
  4029. {
  4030.     int    LeftLen,    RightLen,
  4031.         LeftWidth,    RightWidth,
  4032.         Width;
  4033.  
  4034.         /* Change the font if necessary. */
  4035.  
  4036.     ConSetFont(FONT_PROP);
  4037.  
  4038.         /* Determine lengths of both strings. */
  4039.  
  4040.     LeftLen        = strlen(Left),
  4041.     RightLen    = strlen(Right),
  4042.  
  4043.         /* Determine pixel widths of both strings. */
  4044.  
  4045.     LeftWidth    = TextLength(RPort,(STRPTR)Left,LeftLen);
  4046.     RightWidth    = TextLength(RPort,(STRPTR)Right,RightLen);
  4047.  
  4048.         /* Determine width of the space in between. */
  4049.  
  4050.     Width        = Window -> Width - (Window -> BorderLeft + Window -> BorderRight + LeftWidth + RightWidth);
  4051.  
  4052.         /* Set the status colour. */
  4053.  
  4054.     ConSetColour(COLOUR_STATUS);
  4055.  
  4056.         /* Print the left part if any. */
  4057.  
  4058.     if(LeftLen)
  4059.     {
  4060.         Move(RPort,Window -> BorderLeft,ThisFont -> tf_Baseline + WindowBorderTop);
  4061.         Text(RPort,(STRPTR)Left,LeftLen);
  4062.     }
  4063.  
  4064.         /* Clear the area between left and right part. */
  4065.  
  4066.     if(Width > 0)
  4067.     {
  4068.         SetAPen(RPort,ConBackPen);
  4069.         RectFill(RPort,LeftWidth + Window -> BorderLeft,WindowBorderTop,LeftWidth + Width + Window -> BorderLeft - 1,WindowBorderTop + TextFontHeight - 1);
  4070.         SetAPen(RPort,ConTextPen);
  4071.     }
  4072.  
  4073.         /* Print the right part if any. */
  4074.  
  4075.     if(RightLen)
  4076.     {
  4077.         Move(RPort,Window -> Width - (RightWidth + Window -> BorderRight),WindowBorderTop + ThisFont -> tf_Baseline);
  4078.         Text(RPort,(STRPTR)Right,RightLen);
  4079.     }
  4080.  
  4081.         /* Return to previous cursor position. */
  4082.  
  4083.     ConSetColour(COLOUR_TEXT);
  4084. }
  4085.  
  4086.     /* ConShowRequest():
  4087.      *
  4088.      *    Display a multiple-choice requester.
  4089.      */
  4090.  
  4091. LONG
  4092. ConShowRequest(struct Window *Window,const STRPTR Text,const STRPTR Gadgets,...)
  4093. {
  4094.     struct EasyStruct    Easy;
  4095.     LONG            Result;
  4096.     ULONG            IDCMP = NULL;
  4097.     va_list            VarArgs;
  4098.  
  4099.         /* Block the parent window. */
  4100.  
  4101.     ConBlockWindow(Window);
  4102.  
  4103.         /* Fill in the template. */
  4104.  
  4105.     Easy . es_StructSize    = sizeof(struct EasyStruct);
  4106.     Easy . es_Flags        = NULL;
  4107.     Easy . es_Title        = (STRPTR)"Infocom";
  4108.     Easy . es_TextFormat    = (STRPTR)Text;
  4109.     Easy . es_GadgetFormat    = (STRPTR)Gadgets;
  4110.  
  4111.         /* Display the requester. */
  4112.  
  4113.     va_start(VarArgs,Gadgets);
  4114.  
  4115.     Result = EasyRequestArgs(Window,&Easy,&IDCMP,VarArgs);
  4116.  
  4117.     va_end(VarArgs);
  4118.  
  4119.         /* Unblock the parent window. */
  4120.  
  4121.     ConUnblockWindow(Window);
  4122.  
  4123.         /* Return the result. */
  4124.  
  4125.     return(Result);
  4126. }
  4127.  
  4128.     /* ConQueryOption(int Option):
  4129.      *
  4130.      *    Query the state of an interpreter option.
  4131.      */
  4132.  
  4133. Bool
  4134. ConQueryOption(int Option)
  4135. {
  4136.     switch(Option)
  4137.     {
  4138.         case OPTION_ATTRIBUTE_ASSIGNMENTS:
  4139.  
  4140.             if(gflags . pr_attr)
  4141.                 return(TRUE);
  4142.             else
  4143.                 break;
  4144.  
  4145.         case OPTION_ATTRIBUTE_TESTS:
  4146.  
  4147.             if(gflags . pr_atest)
  4148.                 return(TRUE);
  4149.             else
  4150.                 break;
  4151.  
  4152.         case OPTION_ECHO:
  4153.  
  4154.             if(gflags . echo)
  4155.                 return(TRUE);
  4156.             else
  4157.                 break;
  4158.  
  4159.         case OPTION_PAGING:
  4160.  
  4161.             if(gflags . paged)
  4162.                 return(TRUE);
  4163.             else
  4164.                 break;
  4165.  
  4166.         case OPTION_PROMPT:
  4167.  
  4168.             if(F1_IS_SET(B_ALT_PROMPT))
  4169.                 return(TRUE);
  4170.             else
  4171.                 break;
  4172.  
  4173.         case OPTION_STATUS:
  4174.  
  4175.             if(gflags . pr_status)
  4176.                 return(TRUE);
  4177.             else
  4178.                 break;
  4179.  
  4180.         case OPTION_TANDY:
  4181.  
  4182.             if(F1_IS_SET(B_TANDY))
  4183.                 return(TRUE);
  4184.             else
  4185.                 break;
  4186.  
  4187.         case OPTION_XFERS:
  4188.  
  4189.             if(gflags . pr_xfers)
  4190.                 return(TRUE);
  4191.             else
  4192.                 break;
  4193.  
  4194.         default:
  4195.  
  4196.             break;
  4197.     }
  4198.  
  4199.     return(FALSE);
  4200. }
  4201.  
  4202.     /* ConUpdateMenus():
  4203.      *
  4204.      *    Update the main menu items corresponding
  4205.      *    to the runtime options.
  4206.      */
  4207.  
  4208. VOID
  4209. ConUpdateMenus()
  4210. {
  4211.     struct MenuItem *Item;
  4212.  
  4213.         /* Block the pull-down menu. */
  4214.  
  4215.     ConLockMenus();
  4216.  
  4217.         /* Are object attribute assignments to be printed? */
  4218.  
  4219.     Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_ATTRIBUTE_ASSIGNMENTS,NOSUB));
  4220.  
  4221.     if(ConQueryOption(OPTION_ATTRIBUTE_ASSIGNMENTS))
  4222.         Item -> Flags |= CHECKED;
  4223.     else
  4224.         Item -> Flags &= ~CHECKED;
  4225.  
  4226.         /* Are object attribute tests to be printed? */
  4227.  
  4228.     Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_ATTRIBUTE_TESTS,NOSUB));
  4229.  
  4230.     if(ConQueryOption(OPTION_ATTRIBUTE_TESTS))
  4231.         Item -> Flags |= CHECKED;
  4232.     else
  4233.         Item -> Flags &= ~CHECKED;
  4234.  
  4235.         /* Is input to be echoed? */
  4236.  
  4237.     Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_ECHO,NOSUB));
  4238.  
  4239.     if(ConQueryOption(OPTION_ECHO))
  4240.         Item -> Flags |= CHECKED;
  4241.     else
  4242.         Item -> Flags &= ~CHECKED;
  4243.  
  4244.         /* Is text paging enabled? */
  4245.  
  4246.     Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_PAGING,NOSUB));
  4247.  
  4248.     if(ConQueryOption(OPTION_PAGING))
  4249.         Item -> Flags |= CHECKED;
  4250.     else
  4251.         Item -> Flags &= ~CHECKED;
  4252.  
  4253.         /* Is the alternate prompt to be displayed? */
  4254.  
  4255.     Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_PROMPT,NOSUB));
  4256.  
  4257.     if(ConQueryOption(OPTION_PROMPT))
  4258.         Item -> Flags |= CHECKED;
  4259.     else
  4260.         Item -> Flags &= ~CHECKED;
  4261.  
  4262.         /* Is the status line to be displayed? */
  4263.  
  4264.     Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_STATUS,NOSUB));
  4265.  
  4266.     if(ConQueryOption(OPTION_STATUS))
  4267.         Item -> Flags |= CHECKED;
  4268.     else
  4269.         Item -> Flags &= ~CHECKED;
  4270.  
  4271.         /* Is the Tandy license to be displayed? */
  4272.  
  4273.     Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_TANDY,NOSUB));
  4274.  
  4275.     if(ConQueryOption(OPTION_TANDY))
  4276.         Item -> Flags |= CHECKED;
  4277.     else
  4278.         Item -> Flags &= ~CHECKED;
  4279.  
  4280.         /* Are object transfers to be displayed? */
  4281.  
  4282.     Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_XFERS,NOSUB));
  4283.  
  4284.     if(ConQueryOption(OPTION_XFERS))
  4285.         Item -> Flags |= CHECKED;
  4286.     else
  4287.         Item -> Flags &= ~CHECKED;
  4288.  
  4289.         /* Enable the pull-down menus again. */
  4290.  
  4291.     ConUnlockMenus();
  4292. }
  4293.  
  4294.     /* ConLockMenus():
  4295.      *
  4296.      *    Lock the menu strip.
  4297.      */
  4298.  
  4299. VOID
  4300. ConLockMenus()
  4301. {
  4302.         /* Are we allowed to do what we want? */
  4303.  
  4304.     if(NewOS)
  4305.     {
  4306.         if(!MenuLockCount++)
  4307.         {
  4308.                 /* Remove the menu strip. */
  4309.  
  4310.             ClearMenuStrip(Window);
  4311.         }
  4312.     }
  4313. }
  4314.  
  4315.     /* ConUnlockMenus():
  4316.      *
  4317.      *    Unlock the menu strip.
  4318.      */
  4319.  
  4320. VOID
  4321. ConUnlockMenus()
  4322. {
  4323.         /* Are we allowed to do what we want? */
  4324.  
  4325.     if(NewOS)
  4326.     {
  4327.         if(MenuLockCount > 0)
  4328.         {
  4329.             if(MenuLockCount-- == 1)
  4330.             {
  4331.                     /* Reattach the menu strip. */
  4332.  
  4333.                 ResetMenuStrip(Window,Menu);
  4334.             }
  4335.         }
  4336.     }
  4337. }
  4338.  
  4339.     /* ConSplitLine(char *Line,int Len,Bool ReturnPrompt):
  4340.      *
  4341.      *    Split a hunk of text into neat little pieces.
  4342.      */
  4343.  
  4344. char *
  4345. ConSplitLine(char *Line,int Len,Bool ReturnPrompt)
  4346. {
  4347.     LONG    Width,
  4348.         Indent,
  4349.         Columns;
  4350.  
  4351.     int    Count,
  4352.         Space;
  4353.  
  4354.         /* Make sure that the rendering area is large enough. */
  4355.  
  4356.     if((WindowWidth - (ConLineIndent * SpaceWidth + ConLineMargin * SpaceWidth)) / TextFontWidth < 40)
  4357.     {
  4358.         do
  4359.         {
  4360.             if(ConLineIndent)
  4361.                 ConLineIndent--;
  4362.  
  4363.             if(ConLineMargin)
  4364.                 ConLineMargin--;
  4365.         }
  4366.         while(ConLineIndent && ConLineMargin && (WindowWidth - (ConLineIndent * SpaceWidth + ConLineMargin * SpaceWidth)) / TextFontWidth < 40);
  4367.     }
  4368.  
  4369.         /* Make sure to leave enough space for the user
  4370.          * to type a character.
  4371.          */
  4372.  
  4373.     if(ReturnPrompt)
  4374.     {
  4375.         Width    = WindowWidth - (2 * TextFontWidth + SpaceWidth * ConLineMargin);
  4376.         Indent    = 0;
  4377.     }
  4378.     else
  4379.     {
  4380.         Width    = WindowWidth - SpaceWidth * (ConLineIndent + ConLineMargin);
  4381.         Indent    = SpaceWidth * ConLineIndent;
  4382.     }
  4383.  
  4384.         /* Determine fill width. */
  4385.  
  4386.     PadWidth = WindowWidth - SpaceWidth * (ConLineIndent + ConLineMargin) - Indent;
  4387.  
  4388.         /* Determine number of columns. */
  4389.  
  4390.     Columns = (Width - SpaceWidth * (ConLineIndent + ConLineMargin)) / TextFontWidth;
  4391.  
  4392.         /* Process & chop the text. */
  4393.  
  4394.     do
  4395.     {
  4396.             /* Does the entire line fit? */
  4397.  
  4398.         if(Len <= Columns)
  4399.         {
  4400.                 /* Are we to return the
  4401.                  * rest of the line as
  4402.                  * a buffer suitable for
  4403.                  * printing as a prompt?
  4404.                  */
  4405.  
  4406.             if(ReturnPrompt)
  4407.                 return(Line);
  4408.             else
  4409.                 ConPrintLine(Line,Count = Len,Indent,FALSE);
  4410.         }
  4411.         else
  4412.         {
  4413.                 /* Start with minimum values. */
  4414.  
  4415.             Space = Count = Columns;
  4416.  
  4417.                 /* Try to find the last space in case
  4418.                  * the minimum width is the exact line
  4419.                  * size to fit which would cause the
  4420.                  * line to be broken at the last
  4421.                  * character (generally, not a pretty
  4422.                  * sight at all).
  4423.                  */
  4424.  
  4425.             while(Space > 0 && Line[Space] != ' ')
  4426.                 Space--;
  4427.  
  4428.                 /* Will another character fit? */
  4429.  
  4430.             while(Count < Len && TextLength(RPort,(STRPTR)Line,Count + 1) < Width)
  4431.             {
  4432.                 Count++;
  4433.  
  4434.                     /* Remember last space. */
  4435.  
  4436.                 if(Line[Count] == ' ')
  4437.                     Space = Count;
  4438.             }
  4439.  
  4440.                 /* Print the text. */
  4441.  
  4442.             if(Count == Len)
  4443.             {
  4444.                 if(ReturnPrompt)
  4445.                     return(Line);
  4446.                 else
  4447.                 {
  4448.                     if(Line[Count - 1] == ' ')
  4449.                         ConPrintLine(Line,Count - 1,Indent,FALSE);
  4450.                     else
  4451.                         ConPrintLine(Line,Count,Indent,FALSE);
  4452.                 }
  4453.             }
  4454.             else
  4455.             {
  4456.                 if(Line[Count - 1] == ' ')
  4457.                     ConPrintLine(Line,Count - 1,Indent,FillLines);
  4458.                 else
  4459.                 {
  4460.                     ConPrintLine(Line,Space,Indent,FillLines);
  4461.  
  4462.                     Count = Space + 1;
  4463.                 }
  4464.             }
  4465.  
  4466.                 /* Move up. */
  4467.  
  4468.             Line += Count;
  4469.         }
  4470.  
  4471.             /* Reduce remaining line length. */
  4472.  
  4473.         Len -= Count;
  4474.     }
  4475.     while(Len > 0);
  4476.  
  4477.         /* Return blank prompt. */
  4478.  
  4479.     return("");
  4480. }
  4481.  
  4482.     /* ConPrintLine(const char *Buffer,int Len,int Indent,Bool PadLine):
  4483.      *
  4484.      *    Print a line of text.
  4485.      */
  4486.  
  4487. VOID
  4488. ConPrintLine(const char *Buffer,int Len,int Indent,Bool PadLine)
  4489. {
  4490.         /* Is the plain text window active? */
  4491.  
  4492.     if(!ConOutputWindow)
  4493.     {
  4494.             /* Scroll the screen contents up one line. */
  4495.  
  4496.         ConScrollUp();
  4497.  
  4498.             /* Are we to perform paging? */
  4499.  
  4500.         if(gflags . paged)
  4501.         {
  4502.             int PageLength;
  4503.  
  4504.                 /* Determine current page length. */
  4505.  
  4506.             if(ConNumStatusLines > 1 || gflags . pr_status)
  4507.                 PageLength = ConNumLines - ConNumStatusLines;
  4508.             else
  4509.                 PageLength = ConNumLines;
  4510.  
  4511.                 /* Did we print enough lines already to
  4512.                  * show the `[More]' prompt?
  4513.                  */
  4514.  
  4515.             if(ConLinesPrinted >= PageLength - (ConLineContext + 2))
  4516.             {
  4517.                 Bool SizeVerify;
  4518.  
  4519.                     /* Enable the size verify option? */
  4520.  
  4521.                 if(Window -> IDCMPFlags & IDCMP_SIZEVERIFY)
  4522.                     SizeVerify = FALSE;
  4523.                 else
  4524.                 {
  4525.                     ModifyIDCMP(Window,Window -> IDCMPFlags | IDCMP_SIZEVERIFY);
  4526.  
  4527.                     SizeVerify = TRUE;
  4528.                 }
  4529.  
  4530.                     /* Turn on the text rendering font. */
  4531.  
  4532.                 ConSetFont(FONT_PROP);
  4533.  
  4534.                     /* Set special colour. */
  4535.  
  4536.                 ConSetColour(COLOUR_SPECIAL);
  4537.  
  4538.                     /* Show the prompt. */
  4539.  
  4540.                 ConPrintf("[More]");
  4541.  
  4542.                     /* Set text colour. */
  4543.  
  4544.                 ConSetColour(COLOUR_TEXT);
  4545.  
  4546.                     /* Turn on the cursor. */
  4547.  
  4548.                 ConCursorOn(CURSOR_AVERAGE);
  4549.  
  4550.                     /* Block the pull-down menus. */
  4551.  
  4552.                 if(NewOS)
  4553.                     Window -> Flags |= WFLG_RMBTRAP;
  4554.  
  4555.                     /* Did the window size change? If so,
  4556.                      * go through the same number of
  4557.                      * actions as in the main input
  4558.                      * routine.
  4559.                      */
  4560.  
  4561.                 while(ConGetChar(TRUE) == TERM_RESIZE)
  4562.                 {
  4563.                     if(Window -> Width != OldWindowWidth)
  4564.                     {
  4565.                             /* Remember new window width. */
  4566.  
  4567.                         OldWindowWidth = Window -> Width;
  4568.  
  4569.                             /* Determine new window dimensions. */
  4570.  
  4571.                         WindowWidth = Window -> Width - (WindowBorderLeft + WindowBorderRight);
  4572.  
  4573.                             /* Update score display. */
  4574.  
  4575.                         scr_putscore();
  4576.                     }
  4577.  
  4578.                     if(Window -> Height != OldWindowHeight)
  4579.                     {
  4580.                         WORD Remainder;
  4581.  
  4582.                         ConCursorOff();
  4583.  
  4584.                             /* If the window has become larger than
  4585.                              * before, remove the `[More]' prompt.
  4586.                              */
  4587.  
  4588.                         if(Window -> Height > OldWindowHeight)
  4589.                         {
  4590.                             ConSet(0,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  4591.  
  4592.                             ConClearEOL();
  4593.                         }
  4594.  
  4595.                             /* Calculate new window dimensions. */
  4596.  
  4597.                         ConNumLines = (Window -> Height - (WindowBorderTop + WindowBorderBottom)) / TextFontHeight;
  4598.  
  4599.                         OldWindowHeight = Window -> Height;
  4600.  
  4601.                             /* Set input colour. */
  4602.  
  4603.                         ConSetColour(COLOUR_INPUT);
  4604.  
  4605.                             /* Go to the bottom of the screen. */
  4606.  
  4607.                         ConSet(0,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  4608.  
  4609.                             /* Show the prompt. */
  4610.  
  4611.                         ConPrintf("[More]");
  4612.  
  4613.                         ConClearEOL();
  4614.  
  4615.                             /* Set text colour. */
  4616.  
  4617.                         ConSetColour(COLOUR_TEXT);
  4618.  
  4619.                             /* Turn on the cursor. */
  4620.  
  4621.                         ConCursorOn(CURSOR_AVERAGE);
  4622.  
  4623.                         if((Remainder = Window -> Height - (WindowBorderTop + ConNumLines * TextFontHeight + WindowBorderBottom)) > 0)
  4624.                         {
  4625.                             SetAPen(RPort,ConBackPen);
  4626.                             RectFill(RPort,WindowBorderLeft,Window -> Height - (WindowBorderBottom + Remainder),Window -> Width - (WindowBorderRight + 1),Window -> Height - (WindowBorderBottom + 1));
  4627.                             SetAPen(RPort,ConTextPen);
  4628.                         }
  4629.                     }
  4630.                 }
  4631.  
  4632.                     /* Enable the pull-down menus again. */
  4633.  
  4634.                 if(NewOS)
  4635.                     Window -> Flags &= ~WFLG_RMBTRAP;
  4636.  
  4637.                     /* Erase the `[More]' prompt. */
  4638.  
  4639.                 ConCursorOff();
  4640.  
  4641.                 ConSet(0,TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  4642.  
  4643.                 ConClearEOL();
  4644.  
  4645.                     /* That's all. */
  4646.  
  4647.                 ConLinesPrinted = 0;
  4648.  
  4649.                     /* Turn off the size verify option? */
  4650.  
  4651.                 if(SizeVerify)
  4652.                     ModifyIDCMP(Window,Window -> IDCMPFlags & ~IDCMP_SIZEVERIFY);
  4653.             }
  4654.             else
  4655.                 ConLinesPrinted++;
  4656.         }
  4657.     }
  4658.  
  4659.         /* Is the status window active? */
  4660.  
  4661.     if(ConOutputWindow)
  4662.     {
  4663.             /* Write the string if any. */
  4664.  
  4665.         if(Len)
  4666.         {
  4667.                 /* Are we to change the text rendering font?
  4668.                  * The interpreter may want to change between
  4669.                  * a fixed and a proportional-spaced font.
  4670.                  */
  4671.  
  4672.             if(F2_IS_SET(B_FIXED_FONT))
  4673.                 ConSetFont(FONT_FIXED);
  4674.             else
  4675.                 ConSetFont(FONT_PROP);
  4676.  
  4677.                 /* Write the string. */
  4678.  
  4679.             ConWrite(Buffer,Len,0);
  4680.         }
  4681.  
  4682.             /* Clear to end of line. */
  4683.  
  4684.         ConClearEOL();
  4685.  
  4686.             /* Update current cursor position. */
  4687.  
  4688.         CursorY    += TextFontHeight;
  4689.         CursorX     = 0;
  4690.     }
  4691.     else
  4692.     {
  4693.             /* Write the string if any. */
  4694.  
  4695.         if(Len)
  4696.         {
  4697.                 /* Are we to change the text rendering font?
  4698.                  * The interpreter may want to change between
  4699.                  * a fixed and a proportional-spaced font.
  4700.                  */
  4701.  
  4702.             if(F2_IS_SET(B_FIXED_FONT))
  4703.                 ConSetFont(FONT_FIXED);
  4704.             else
  4705.                 ConSetFont(FONT_PROP);
  4706.  
  4707.                 /* Write the string. */
  4708.  
  4709.             if(PadLine)
  4710.                 ConPad(Buffer,Len,Indent);
  4711.             else
  4712.                 ConWrite(Buffer,Len,Indent);
  4713.         }
  4714.     }
  4715. }
  4716.  
  4717.     /* ConCheckStory(char *Name):
  4718.      *
  4719.      *    Check a file to see if it's a valid type 3
  4720.      *    story game file.
  4721.      */
  4722.  
  4723. Bool
  4724. ConCheckStory(const char *Name)
  4725. {
  4726.     struct FileInfoBlock    *FileInfo;
  4727.     Bool             Result = FALSE;
  4728.  
  4729.         /* Allocate space for fileinfo data. */
  4730.  
  4731.     if(FileInfo = (struct FileInfoBlock *)AllocDosObjectTags(DOS_FIB,TAG_DONE))
  4732.     {
  4733.         BPTR FileLock;
  4734.  
  4735.             /* Try to locate the file. */
  4736.  
  4737.         if(FileLock = Lock((STRPTR)Name,ACCESS_READ))
  4738.         {
  4739.                 /* Get a closer look at it. */
  4740.  
  4741.             if(Examine(FileLock,FileInfo))
  4742.             {
  4743.                     /* Does it look like a valid file? */
  4744.  
  4745.                 if(FileInfo -> fib_DirEntryType < 0 && FileInfo -> fib_Size > 0)
  4746.                 {
  4747.                     FILE *StoryFile;
  4748.  
  4749.                         /* Try to open the file for reading. */
  4750.  
  4751.                     if(StoryFile = fopen(Name,"rb"))
  4752.                     {
  4753.                             /* Does it look like a type 3
  4754.                              * story game file?
  4755.                              */
  4756.  
  4757.                         if(fgetc(StoryFile) == 3)
  4758.                             Result = TRUE;
  4759.  
  4760.                             /* Close the file. */
  4761.  
  4762.                         fclose(StoryFile);
  4763.                     }
  4764.                 }
  4765.             }
  4766.  
  4767.                 /* Release the file lock. */
  4768.  
  4769.             UnLock(FileLock);
  4770.         }
  4771.  
  4772.             /* Free fileinfo data. */
  4773.  
  4774.         FreeDosObject(DOS_FIB,FileInfo);
  4775.     }
  4776.  
  4777.     return(Result);
  4778. }
  4779.  
  4780.     /* ConLocateStory(char *Directory,char *Default):
  4781.      *
  4782.      *    Try to locate a story file in a directory.
  4783.      */
  4784.  
  4785. char *
  4786. ConLocateStory(const char *Directory,const char *Default)
  4787. {
  4788.     char     LocalBuffer[MAX_FILENAME_LENGTH];
  4789.     int     i,j;
  4790.  
  4791.         /* Start with the current default name. */
  4792.  
  4793.     if(Default[0])
  4794.     {
  4795.         for(j = 0 ; StoryExtensions[j] ; j++)
  4796.         {
  4797.                 /* Copy the directory name. */
  4798.  
  4799.             strcpy(TempBuffer,Directory);
  4800.  
  4801.                 /* Build the story file name. */
  4802.  
  4803.             strcpy(LocalBuffer,Default);
  4804.             strcat(LocalBuffer,StoryExtensions[j]);
  4805.  
  4806.                 /* Build the full path name. */
  4807.  
  4808.             if(AddPart(TempBuffer,LocalBuffer,MAX_FILENAME_LENGTH))
  4809.             {
  4810.                     /* Is it a valid story game file? */
  4811.  
  4812.                 if(ConCheckStory(TempBuffer))
  4813.                     return((char *)TempBuffer);
  4814.             }
  4815.         }
  4816.     }
  4817.  
  4818.         /* Run down the number of alternatives. */
  4819.  
  4820.     for(i = 0 ; StoryNames[i] ; i++)
  4821.     {
  4822.             /* Run down the number of file name extensions. */
  4823.  
  4824.         for(j = 0 ; StoryExtensions[j] ; j++)
  4825.         {
  4826.                 /* Copy the directory name. */
  4827.  
  4828.             strcpy(TempBuffer,Directory);
  4829.  
  4830.                 /* Build the story file name. */
  4831.  
  4832.             strcpy(LocalBuffer,StoryNames[i]);
  4833.             strcat(LocalBuffer,StoryExtensions[j]);
  4834.  
  4835.                 /* Build the full path name. */
  4836.  
  4837.             if(AddPart(TempBuffer,LocalBuffer,MAX_FILENAME_LENGTH))
  4838.             {
  4839.                     /* Is it a valid story game file? */
  4840.  
  4841.                 if(ConCheckStory(TempBuffer))
  4842.                     return((char *)TempBuffer);
  4843.             }
  4844.         }
  4845.     }
  4846.  
  4847.     return(NULL);
  4848. }
  4849.  
  4850.     /* ConQueryStoryInformation(const char *Name):
  4851.      *
  4852.      *    Query the story game header for information.
  4853.      */
  4854.  
  4855. VOID
  4856. ConQueryStoryInformation(const char *Name)
  4857. {
  4858.     FILE *GameFile;
  4859.  
  4860.         /* Reset information. */
  4861.  
  4862.     StorySerial = StoryRelease = 0;
  4863.  
  4864.         /* Try to open the file for reading. */
  4865.  
  4866.     if(GameFile = fopen(Name,"rb"))
  4867.     {
  4868.         header_t GameHeader;
  4869.  
  4870.             /* Read the game file header. */
  4871.  
  4872.         if(fread(&GameHeader,sizeof(header_t),1,GameFile) == 1)
  4873.         {
  4874.                 /* Is it a type 3 game? */
  4875.  
  4876.             if(GameHeader . z_version == 3)
  4877.             {
  4878.                 int    Serial = 0,
  4879.                     i;
  4880.  
  4881.                     /* Calculate the serial number. */
  4882.  
  4883.                 for(i = 0 ; i < 6 ; i++)
  4884.                 {
  4885.                     Serial *= 10;
  4886.                     Serial += GameHeader . serial_no[i] - '0';
  4887.                 }
  4888.  
  4889.                     /* Try to find a corresponding
  4890.                      * game in the list.
  4891.                      */
  4892.  
  4893.                 for(i = 0 ; SerialNumbers[i][SERIAL_INDEX] != -1 ; i++)
  4894.                 {
  4895.                         /* Do the serial and release numbers match? */
  4896.  
  4897.                     if(Serial == SerialNumbers[i][SERIAL_NUMBER] && GameHeader . release == SerialNumbers[i][SERIAL_RELEASE])
  4898.                     {
  4899.                         StorySerial    = Serial;
  4900.                         StoryRelease    = GameHeader . release;
  4901.                         StoryIndex    = SerialNumbers[i][SERIAL_INDEX];
  4902.                     }
  4903.                 }
  4904.             }
  4905.         }
  4906.  
  4907.             /* Close the story file. */
  4908.  
  4909.         fclose(GameFile);
  4910.     }
  4911. }
  4912.  
  4913.     /* ConAbout():
  4914.      *
  4915.      *    Display an information requester.
  4916.      */
  4917.  
  4918. VOID
  4919. ConAbout()
  4920. {
  4921.         /* Show the information requester. */
  4922.  
  4923.     if(StorySerial)
  4924.     {
  4925.         ConShowRequest(Window,"\"%s\" (%s)\nRelease %ld / Serial number %ld\nWritten by %s\n\n\"pinfo\" version %ld.%ld, Amiga release %ld.%ld\nCopyright \251 1987-1992 InfoTaskForce",
  4926.             "Continue",Titles[StoryIndex],Levels[GameLevels[StoryIndex]],StoryRelease,StorySerial,Authors[StoryIndex],VERSION,PATCHLEVEL,AMIGA_VERSION,AMIGA_REVISION);
  4927.     }
  4928.     else
  4929.     {
  4930.         ConShowRequest(Window,"\"pinfo\" version %ld.%ld, Amiga release %ld.%ld\nCopyright \251 1987-1992 InfoTaskForce",
  4931.             "Continue",VERSION,PATCHLEVEL,AMIGA_VERSION,AMIGA_REVISION);
  4932.     }
  4933. }
  4934.