home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 3 / CDPDIII.bin / fish / 831-840 / ff833 / zip / zip-1.00.lha / amigaio.c next >
C/C++ Source or Header  |  1992-10-25  |  79KB  |  3,992 lines

  1. /* amigaio.c ******************************************************************
  2.  *
  3.  *    Minimal  Amiga  interface  for Mark Howell's `ZIP' Infocom Interpreter
  4.  *    Program.  This is public-domain, no distribution restrictions apply.
  5.  *
  6.  *    Written by Olaf `Olsen' Barthel, 4 October 1992
  7.  *
  8.  *       This  minimal  interface is guaranteed to work both unter Kickstart
  9.  *    1.2/1.3 and Kickstart 2.0 (or higher if you can afford it).
  10.  *
  11.  *    The  screen drag bar is left intact, it is reduced to four lines.  The
  12.  *    input  procedure  uses the following keys:
  13.  *
  14.  *    Return.............. Terminates input
  15.  *    Control-X........... Erases the input line
  16.  *    Backspace........... Deletes the character to the left of the cursor
  17.  *    Delete.............. Deletes the character under the cursor
  18.  *    Cursor left......... Moves the cursor to the left
  19.  *    Shift cursor left... Moves the cursor to the beginning of the line
  20.  *    Cursor right........ Moves the cursor to the right
  21.  *    Shift cursor right.. Moves the cursor to the end of the line
  22.  *    Cursor up........... Moves up in history list
  23.  *    Shift cursor up..... Moves to first history line
  24.  *    Cursor down......... Moves down in history list
  25.  *    Shift cursor down... Moves to end of history list
  26.  *    Help................ Define function key
  27.  *    F1-F10.............. Function keys
  28.  *    Numeric keypad...... Movement
  29.  *
  30.  *    An  ANSI  `C'  compatible  compiler is required to compile this source
  31.  *    code  (e.g.  SAS/C 5.x, Aztec C 5.x, DICE, GCC).
  32.  *
  33.  *****************************************************************************/
  34.  
  35. #include <intuition/intuitionbase.h>
  36. #include <libraries/dosextens.h>
  37. #include <workbench/workbench.h>
  38. #include <workbench/startup.h>
  39. #include <graphics/gfxbase.h>
  40. #include <devices/conunit.h>
  41. #include <devices/audio.h>
  42. #include <devices/timer.h>
  43. #include <exec/memory.h>
  44.  
  45. #ifdef __GNUC__
  46. #include <inline/stubs.h>
  47.  
  48. #include <inline/intuition.h>
  49. #include <inline/graphics.h>
  50. #include <inline/exec.h>
  51. #include <inline/dos.h>
  52.  
  53. #include <signal.h>
  54.  
  55.     /* Signals to trap while running. */
  56.  
  57. #define TRAPPED_SIGNALS (sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGILL)|sigmask(SIGTRAP)|sigmask(SIGABRT)|sigmask(SIGEMT)|sigmask(SIGFPE)|sigmask(SIGBUS)|sigmask(SIGSEGV)|sigmask(SIGSYS)|sigmask(SIGALRM)|sigmask(SIGTERM)|sigmask(SIGTSTP))
  58.  
  59. #endif    /* __GNUC__ */
  60.  
  61. #include <clib/intuition_protos.h>
  62. #include <clib/graphics_protos.h>
  63. #include <clib/console_protos.h>
  64. #include <clib/icon_protos.h>
  65. #include <clib/alib_protos.h>
  66. #include <clib/exec_protos.h>
  67. #include <clib/dos_protos.h>
  68.  
  69.     /* Some help to keep the code size down. */
  70.  
  71. #ifdef AZTEC_C
  72. extern struct ExecBase *SysBase;
  73.  
  74. #include <pragmas/exec_lib.h>
  75. #endif    /* AZTEC_C */
  76.  
  77. #ifdef LATTICE
  78. extern struct ExecBase *SysBase;
  79.  
  80. #include <pragmas/exec_pragmas.h>
  81. #endif    /* LATTICE */
  82.  
  83. #include <stdarg.h>
  84.  
  85. #include "ztypes.h"
  86.  
  87.     /* Disable ^C trapping for several Amiga `C' compilers. */
  88.  
  89. #ifdef LATTICE
  90. ULONG CXBRK(VOID) { return(0); }
  91. #endif    /* LATTICE */
  92.  
  93. #ifdef AZTEC_C
  94. LONG Chk_Abort(VOID) { return(0); }
  95. VOID _wb_parse(VOID) {}
  96. #endif    /* AZTEC_C */
  97.  
  98.     /* Text rendering colours. */
  99.  
  100. enum    {    COLOUR_INPUT, COLOUR_TEXT, COLOUR_RESET };
  101.  
  102.     /* Version identifier tag. */
  103.  
  104. STATIC char            *VersionTag = "\0$VER: AmigaZIP 2.2 (9.10.92)";
  105.  
  106.     /* Control sequence introducer. */
  107.  
  108. #define TERM_CSI        0x9B
  109.  
  110.     /* Backspace character. */
  111.  
  112. #define TERM_BS            '\b'
  113.  
  114.     /* Delete character. */
  115.  
  116. #define TERM_DEL        0x7F
  117.  
  118.     /* Return character. */
  119.  
  120. #define TERM_CR            '\r'
  121.  
  122.     /* Control-X */
  123.  
  124. #define TERM_X            0x18
  125.  
  126.     /* Margin between screen top and window top. */
  127.  
  128. #define SCREEN_MARGIN        4
  129.  
  130.     /* How many history lines to keep. */
  131.  
  132. #ifndef HISTORY_LINES
  133. #define HISTORY_LINES        20
  134. #endif    /* !HISTORY_LINES */
  135.  
  136.     /* Number of function keys. */
  137.  
  138. #define NUM_FKEYS        20
  139.  
  140.     /* Length of `fake' input string. */
  141.  
  142. #define INPUT_LENGTH        1024
  143.  
  144.     /* Minimum system software release version. */
  145.  
  146. #define LIB_VERSION        33
  147.  
  148.     /* A second measured in microseconds. */
  149.  
  150. #define SECOND            1000000
  151.  
  152.     /* Two signals to wait for. */
  153.  
  154. #define SIG_WINDOW        (1 << Window -> UserPort -> mp_SigBit)
  155. #define SIG_TIMER        (1 << TimePort -> mp_SigBit)
  156.  
  157.     /* Audio channel bits. */
  158.  
  159. #define LEFT0F  1
  160. #define RIGHT0F  2
  161. #define RIGHT1F  4
  162. #define LEFT1F  8
  163.  
  164.     /* The two windows. */
  165.  
  166. enum    {    WINDOW_TEXT,WINDOW_STATUS };
  167.  
  168.     /* Cursor widths. */
  169.  
  170. enum    {    CURSOR_AVERAGE = -1,CURSOR_NOCHANGE = 0 };
  171.  
  172.     /* History structure. */
  173.  
  174. struct StringEntry
  175. {
  176.     int    Len;        /* Length of the string. */
  177.     STRPTR    Buffer;        /* The string itself. */
  178. };
  179.  
  180.     /* Global libraries (don't touch!) */
  181.  
  182. struct IntuitionBase        *IntuitionBase;
  183. struct GfxBase            *GfxBase;
  184. struct Library            *IconBase;
  185. struct Device            *ConsoleDevice;
  186.  
  187.     /* Workbench startup message. */
  188.  
  189. STATIC struct WBStartup        *WBenchMsg;
  190.  
  191.     /* Screen and window data. */
  192.  
  193. STATIC struct Screen        *Screen;
  194. STATIC struct Window        *Window;
  195. STATIC struct RastPort        *RPort;
  196. STATIC UBYTE             Depth;
  197.  
  198.     /* Console IO data. */
  199.  
  200. STATIC struct IOStdReq        *ConRequest;
  201. STATIC struct InputEvent    *InputEvent;
  202. STATIC STRPTR             InputEventBuffer;
  203.  
  204. STATIC LONG             CursorX,
  205.                  CursorY,
  206.                  LastX,
  207.                  LastY,
  208.                  OldWidth,
  209.                  NewWidth,
  210.                  WindowWidth;
  211. STATIC BOOL             CursorState,
  212.                  Redraw;
  213.  
  214. STATIC LONG             SavedX,SavedY;
  215. STATIC BOOL             SavedCursor = FALSE;
  216.  
  217.     /* Two different fonts. */
  218.  
  219. STATIC struct TextFont        *PropFont,
  220.                 *FixedFont,
  221.                 *ThisFont;
  222.  
  223.     /* Text font dimensions. */
  224.  
  225. STATIC UWORD             TextFontWidth,
  226.                  TextFontHeight,
  227.                  TextFontAverage;
  228.  
  229.     /* Console data. */
  230.  
  231. STATIC UBYTE             ConChar;
  232. STATIC char            *ConLine;
  233. STATIC int             ConLineLength,
  234.                  ConLineMaxLength,
  235.                  ConLineMinLength;
  236.  
  237. STATIC UBYTE             ConFgPen,
  238.                  ConBgPen,
  239.                  ConStyle;
  240.  
  241.     /* Timer data. */
  242.  
  243. STATIC struct MsgPort        *TimePort;
  244. STATIC struct timerequest    *TimeRequest;
  245.  
  246.     /* Process and DOS tricks. */
  247.  
  248. STATIC struct Process        *ThisProcess;
  249. STATIC APTR             WindowPtr;
  250.  
  251.     /* History management. */
  252.  
  253. STATIC struct StringEntry     HistoryBuffer[HISTORY_LINES];
  254. STATIC int             LastHistory = -1;
  255.  
  256.     /* Function key support. */
  257.  
  258. STATIC struct StringEntry     FunctionKeys[NUM_FKEYS];
  259.  
  260.     /* Fake input buffer. */
  261.  
  262. STATIC UBYTE             InputBuffer[INPUT_LENGTH];
  263. STATIC STRPTR             InputIndex;
  264.  
  265.     /* The currently active text window. */
  266.  
  267. STATIC int             CurrentWindow = WINDOW_TEXT;
  268.  
  269.     /* Current game file name and interpreter program name. */
  270.  
  271. STATIC STRPTR             StoryName,
  272.                  InterpreterName;
  273.  
  274.     /* Current text attribute. */
  275.  
  276. STATIC int             CurrentAttribute = NORMAL;
  277.  
  278.     /* Sound support. */
  279.  
  280. STATIC struct IOAudio        *SoundRequestLeft,
  281.                 *SoundRequestRight,
  282.                 *SoundControlRequest;
  283. STATIC struct MsgPort        *SoundPort;
  284.  
  285.     /* Sound file search path. */
  286.  
  287. STATIC char            *SoundName,
  288.                 *SoundPath;
  289.  
  290.     /* Sound data storage. */
  291.  
  292. STATIC int             SoundNumber = -1;
  293. STATIC APTR             SoundData;
  294. STATIC LONG             SoundLength;
  295.  
  296.     /* Custom routines, local. */
  297.  
  298. STATIC BYTE            SoundInit(VOID);
  299. STATIC VOID            SoundExit(VOID);
  300. STATIC VOID            SoundAbort(VOID);
  301. STATIC VOID            SoundStop(VOID);
  302. STATIC VOID            SoundStart(VOID);
  303.  
  304. STATIC WORD            ConCharWidth(const UBYTE Char);
  305. STATIC VOID            ConCursorOff(VOID);
  306. STATIC VOID            ConCursorOn(const int New);
  307. STATIC VOID            ConMove(const int Delta,const int New);
  308. STATIC VOID            ConSet(const int X,const int Y,const int New);
  309. STATIC VOID            ConClearEOL(VOID);
  310. STATIC VOID            ConCharBackspace(const int Delta,const int New);
  311. STATIC VOID            ConCharDelete(const int New);
  312. STATIC VOID            ConCharInsert(const UBYTE Char);
  313. STATIC VOID            ConScrollUp(VOID);
  314. STATIC VOID            ConWrite(char *Line,int Len);
  315. STATIC VOID            ConRedraw(const int X,const int Y,const STRPTR String,const int Len);
  316. STATIC VOID            ConSetKey(int Key,STRPTR String,int Len);
  317. STATIC VOID            ConFlush(VOID);
  318. STATIC UBYTE            ConGetChar(BOOL SingleKey);
  319. STATIC VOID            ConPrintf(char *Format,...);
  320. STATIC int            ConInput(char *Prompt,char *Input,int MaxLen,BOOL DoHistory);
  321.  
  322.     /* SoundInit():
  323.      *
  324.      *    Allocate resources for sound routine.
  325.      */
  326.  
  327. STATIC BYTE
  328. SoundInit()
  329. {
  330.         /* Create io reply port. */
  331.  
  332.     if(SoundPort = (struct MsgPort *)CreatePort(NULL,0))
  333.     {
  334.             /* Create io control request. We will use it
  335.              * later to change the volume of a sound.
  336.              */
  337.  
  338.         if(SoundControlRequest = (struct IOAudio *)CreateExtIO(SoundPort,sizeof(struct IOAudio)))
  339.         {
  340.                 /* Create io request for left channel. */
  341.  
  342.             if(SoundRequestLeft = (struct IOAudio *)CreateExtIO(SoundPort,sizeof(struct IOAudio)))
  343.             {
  344.                     /* Create io request for right channel. */
  345.  
  346.                 if(SoundRequestRight = (struct IOAudio *)CreateExtIO(SoundPort,sizeof(struct IOAudio)))
  347.                 {
  348.                         /* Channel allocation map,
  349.                          * we want any two stereo
  350.                          * channels.
  351.                          */
  352.  
  353.                     STATIC UBYTE AllocationMap[] =
  354.                     {
  355.                         LEFT0F | RIGHT0F,
  356.                         LEFT0F | RIGHT1F,
  357.                         LEFT1F | RIGHT0F,
  358.                         LEFT1F | RIGHT1F
  359.                     };
  360.  
  361.                         /* Set it up for channel allocation,
  362.                          * any two stereo channels will do.
  363.                          */
  364.  
  365.                     SoundControlRequest -> ioa_Request . io_Message . mn_Node . ln_Pri    = 127;
  366.                     SoundControlRequest -> ioa_Request . io_Command                = ADCMD_ALLOCATE;
  367.                     SoundControlRequest -> ioa_Request . io_Flags                = ADIOF_NOWAIT | ADIOF_PERVOL;
  368.                     SoundControlRequest -> ioa_Data                        = AllocationMap;
  369.                     SoundControlRequest -> ioa_Length                    = sizeof(AllocationMap);
  370.  
  371.                         /* Open the device, allocating the channel on the way. */
  372.  
  373.                     if(!OpenDevice(AUDIONAME,NULL,(struct IORequest *)SoundControlRequest,NULL))
  374.                     {
  375.                             /* Copy the initial data to the
  376.                              * other audio io requests.
  377.                              */
  378.  
  379.                         CopyMem((BYTE *)SoundControlRequest,(BYTE *)SoundRequestLeft, sizeof(struct IOAudio));
  380.                         CopyMem((BYTE *)SoundControlRequest,(BYTE *)SoundRequestRight,sizeof(struct IOAudio));
  381.  
  382.                             /* Divide the channels. */
  383.  
  384.                         SoundRequestLeft  -> ioa_Request . io_Unit = (struct Unit *)((ULONG)SoundRequestLeft  -> ioa_Request . io_Unit & (LEFT0F  | LEFT1F));
  385.                         SoundRequestRight -> ioa_Request . io_Unit = (struct Unit *)((ULONG)SoundRequestRight -> ioa_Request . io_Unit & (RIGHT0F | RIGHT1F));
  386.  
  387.                             /* Return success. */
  388.  
  389.                         return(TRUE);
  390.                     }
  391.                 }
  392.             }
  393.         }
  394.     }
  395.  
  396.         /* Clean up... */
  397.  
  398.     SoundExit();
  399.  
  400.         /* ...and return failure. */
  401.  
  402.     return(FALSE);
  403. }
  404.  
  405.     /* SoundExit():
  406.      *
  407.      *    Free resources allocated by SoundInit().
  408.      */
  409.  
  410. STATIC VOID
  411. SoundExit()
  412. {
  413.         /* Free the left channel data. */
  414.  
  415.     if(SoundRequestLeft)
  416.     {
  417.             /* Did we open the device? */
  418.  
  419.         if(SoundRequestLeft -> ioa_Request . io_Device)
  420.         {
  421.                 /* Check if the sound is still playing. */
  422.  
  423.             if(!CheckIO((struct IORequest *)SoundRequestLeft))
  424.             {
  425.                     /* Abort the request. */
  426.  
  427.                 AbortIO((struct IORequest *)SoundRequestLeft);
  428.  
  429.                     /* Wait for it to return. */
  430.  
  431.                 WaitIO((struct IORequest *)SoundRequestLeft);
  432.             }
  433.             else
  434.                 GetMsg(SoundPort);
  435.         }
  436.  
  437.             /* Free the memory allocated. */
  438.  
  439.         DeleteExtIO((struct IORequest *)SoundRequestLeft);
  440.  
  441.             /* Leave no traces. */
  442.  
  443.         SoundRequestLeft = NULL;
  444.     }
  445.  
  446.         /* Free the right channel data. */
  447.  
  448.     if(SoundRequestRight)
  449.     {
  450.             /* Did we open the device? */
  451.  
  452.         if(SoundRequestRight -> ioa_Request . io_Device)
  453.         {
  454.                 /* Check if the sound is still playing. */
  455.  
  456.             if(!CheckIO((struct IORequest *)SoundRequestRight))
  457.             {
  458.                     /* Abort the request. */
  459.  
  460.                 AbortIO((struct IORequest *)SoundRequestRight);
  461.  
  462.                     /* Wait for it to return. */
  463.  
  464.                 WaitIO((struct IORequest *)SoundRequestRight);
  465.             }
  466.             else
  467.                 GetMsg(SoundPort);
  468.         }
  469.  
  470.             /* Free the memory allocated. */
  471.  
  472.         DeleteExtIO((struct IORequest *)SoundRequestRight);
  473.  
  474.             /* Leave no traces. */
  475.  
  476.         SoundRequestRight = NULL;
  477.     }
  478.  
  479.         /* Free sound control request. */
  480.  
  481.     if(SoundControlRequest)
  482.     {
  483.             /* Close the device, free any allocated channels. */
  484.  
  485.         if(SoundControlRequest -> ioa_Request . io_Device)
  486.             CloseDevice((struct IORequest *)SoundControlRequest);
  487.  
  488.             /* Free the memory allocated. */
  489.  
  490.         DeleteExtIO((struct IORequest *)SoundControlRequest);
  491.  
  492.             /* Leave no traces. */
  493.  
  494.         SoundControlRequest = NULL;
  495.     }
  496.  
  497.         /* Free sound io reply port. */
  498.  
  499.     if(SoundPort)
  500.     {
  501.             /* Delete it. */
  502.  
  503.         DeletePort(SoundPort);
  504.  
  505.             /* Leave no traces. */
  506.  
  507.         SoundPort = NULL;
  508.     }
  509.  
  510.         /* Free sound data. */
  511.  
  512.     if(SoundData && SoundLength)
  513.     {
  514.             /* Free it. */
  515.  
  516.         FreeMem(SoundData,SoundLength);
  517.  
  518.             /* Leave no traces. */
  519.  
  520.         SoundData    = NULL;
  521.         SoundLength    = 0;
  522.     }
  523.  
  524.         /* Clear current sound number. */
  525.  
  526.     SoundNumber = -1;
  527. }
  528.  
  529.     /* SoundAbort():
  530.      *
  531.      *    Abort any currently playing sound and wait for
  532.      *    both IORequests to return.
  533.      */
  534.  
  535. STATIC VOID
  536. SoundAbort()
  537. {
  538.         /* Abort sound playing on the left channel. */
  539.  
  540.     if(!CheckIO((struct IORequest *)SoundRequestLeft))
  541.         AbortIO((struct IORequest *)SoundRequestLeft);
  542.  
  543.         /* Wait for the request to return. */
  544.  
  545.     WaitIO((struct IORequest *)SoundRequestLeft);
  546.  
  547.         /* Abort sound playing on the right channel. */
  548.  
  549.     if(!CheckIO((struct IORequest *)SoundRequestRight))
  550.         AbortIO((struct IORequest *)SoundRequestRight);
  551.  
  552.         /* Wait for the request to return. */
  553.  
  554.     WaitIO((struct IORequest *)SoundRequestRight);
  555. }
  556.  
  557.     /* SoundStop():
  558.      *
  559.      *    Stop sound from getting played (somewhat equivalent to ^S).
  560.      */
  561.  
  562. STATIC VOID
  563. SoundStop()
  564. {
  565.         /* Fill in the command. */
  566.  
  567.     SoundControlRequest -> ioa_Request . io_Command = CMD_STOP;
  568.  
  569.         /* Send it off. */
  570.  
  571.     SendIO((struct IORequest *)SoundControlRequest);
  572.     WaitIO((struct IORequest *)SoundControlRequest);
  573. }
  574.  
  575.     /* SoundStart():
  576.      *
  577.      *    Restart any queued sound.
  578.      */
  579.  
  580. STATIC VOID
  581. SoundStart()
  582. {
  583.         /* Fill in the command. */
  584.  
  585.     SoundControlRequest -> ioa_Request . io_Command = CMD_START;
  586.  
  587.         /* Send it off. */
  588.  
  589.     SendIO((struct IORequest *)SoundControlRequest);
  590.     WaitIO((struct IORequest *)SoundControlRequest);
  591. }
  592.  
  593. VOID
  594. ConSetColour(const int Mode)
  595. {
  596.     switch(Mode)
  597.     {
  598.         case COLOUR_INPUT:    if(ConStyle != FS_NORMAL)
  599.                         SetSoftStyle(RPort,ConStyle = FS_NORMAL,AskSoftStyle(RPort));
  600.  
  601.                     if(Depth > 1)
  602.                     {
  603.                         if(ConFgPen != 2)
  604.                             SetAPen(RPort,ConFgPen = 2);
  605.                     }
  606.                     else
  607.                     {
  608.                         if(ConFgPen != 1)
  609.                             SetAPen(RPort,ConFgPen = 1);
  610.                     }
  611.  
  612.                     break;
  613.  
  614.         case COLOUR_TEXT:    if(ConStyle != FS_NORMAL)
  615.                         SetSoftStyle(RPort,ConStyle = FS_NORMAL,AskSoftStyle(RPort));
  616.  
  617.                     if(ConFgPen != 1)
  618.                         SetAPen(RPort,ConFgPen = 1);
  619.  
  620.                     break;
  621.  
  622.         case COLOUR_RESET:    set_attribute(CurrentAttribute);
  623.                     break;
  624.     }
  625. }
  626.  
  627.     /* ConCharWidth(const UBYTE Char):
  628.      *
  629.      *    Calculate the pixel width of a glyph.
  630.      */
  631.  
  632. STATIC WORD
  633. ConCharWidth(const UBYTE Char)
  634. {
  635.     return(TextLength(RPort,(STRPTR)&Char,1));
  636. }
  637.  
  638.     /* ConCursorOff():
  639.      *
  640.      *    Turn the terminal cursor on.
  641.      */
  642.  
  643. STATIC VOID
  644. ConCursorOff()
  645. {
  646.         /* Is it still enabled? */
  647.  
  648.     if(CursorState)
  649.     {
  650.             /* Remove the cursor. */
  651.  
  652.         SetAPen(RPort,(1 << Depth) - 1);
  653.         SetDrMd(RPort,COMPLEMENT|JAM2);
  654.  
  655.         RectFill(RPort,LastX,LastY,LastX + NewWidth - 1,LastY + TextFontHeight - 1);
  656.  
  657.         SetAPen(RPort,ConFgPen);
  658.         SetDrMd(RPort,JAM2);
  659.  
  660.             /* It's turned off now. */
  661.  
  662.         CursorState = FALSE;
  663.     }
  664. }
  665.  
  666.     /* ConCursorOn(const int New):
  667.      *
  668.      *    Turn the terminal cursor off.
  669.      */
  670.  
  671. STATIC VOID
  672. ConCursorOn(const int New)
  673. {
  674.         /* Is it still disabled? */
  675.  
  676.     if(!CursorState)
  677.     {
  678.             /* Remember new cursor width. */
  679.  
  680.         switch(New)
  681.         {
  682.             case CURSOR_NOCHANGE:    break;
  683.  
  684.             case CURSOR_AVERAGE:    NewWidth = TextFontAverage;
  685.                         break;
  686.  
  687.             default:        NewWidth = New;
  688.                         break;
  689.         }
  690.  
  691.             /* Turn the cursor back on. */
  692.  
  693.         SetAPen(RPort,(1 << Depth) - 1);
  694.         SetDrMd(RPort,COMPLEMENT|JAM2);
  695.  
  696.         RectFill(RPort,CursorX,CursorY,CursorX + NewWidth - 1,CursorY + TextFontHeight - 1);
  697.  
  698.         SetAPen(RPort,ConFgPen);
  699.         SetDrMd(RPort,JAM2);
  700.  
  701.             /* Remember cursor width. */
  702.  
  703.         OldWidth = NewWidth;
  704.  
  705.             /* It's turn on now. */
  706.  
  707.         CursorState = TRUE;
  708.  
  709.             /* Remember cursor position. */
  710.  
  711.         LastX = CursorX;
  712.         LastY = CursorY;
  713.     }
  714. }
  715.  
  716.     /* ConMove(const int Delta,const int New):
  717.      *
  718.      *    Move the cursor.
  719.      */
  720.  
  721. STATIC VOID
  722. ConMove(const int Delta,const int New)
  723. {
  724.         /* If the cursor is still enabled, turn it
  725.          * off before repositioning it.
  726.          */
  727.  
  728.     if(CursorState)
  729.     {
  730.             /* Turn the cursor off. */
  731.  
  732.         ConCursorOff();
  733.  
  734.             /* Move it. */
  735.  
  736.         CursorX += Delta;
  737.  
  738.             /* Turn the cursor back on. */
  739.  
  740.         ConCursorOn(New);
  741.     }
  742.     else
  743.     {
  744.         switch(New)
  745.         {
  746.             case CURSOR_NOCHANGE:    break;
  747.  
  748.             case CURSOR_AVERAGE:    NewWidth = TextFontAverage;
  749.                         break;
  750.  
  751.             default:        NewWidth = New;
  752.                         break;
  753.         }
  754.  
  755.         CursorX += Delta;
  756.     }
  757. }
  758.  
  759.     /* ConSet(const int X,const int Y,const int New):
  760.      *
  761.      *    Place the cursor at a specific position.
  762.      */
  763.  
  764. STATIC VOID
  765. ConSet(const int X,const int Y,const int New)
  766. {
  767.         /* If the cursor is still enabled, turn it
  768.          * off before repositioning it.
  769.          */
  770.  
  771.     if(CursorState)
  772.     {
  773.             /* Turn the cursor off. */
  774.  
  775.         ConCursorOff();
  776.  
  777.             /* Move drawing pen. */
  778.  
  779.         Move(RPort,X,Y + ThisFont -> tf_Baseline);
  780.  
  781.             /* Position the cursor. */
  782.  
  783.         CursorX = X;
  784.         CursorY = Y;
  785.  
  786.             /* Turn the cursor back on. */
  787.  
  788.         ConCursorOn(New);
  789.     }
  790.     else
  791.     {
  792.             /* Remember new cursor width. */
  793.  
  794.         switch(New)
  795.         {
  796.             case CURSOR_NOCHANGE:    break;
  797.  
  798.             case CURSOR_AVERAGE:    NewWidth = OldWidth = TextFontAverage;
  799.                         break;
  800.  
  801.             default:        NewWidth = OldWidth = New;
  802.                         break;
  803.         }
  804.  
  805.             /* Move drawing pen. */
  806.  
  807.         Move(RPort,X,Y + ThisFont -> tf_Baseline);
  808.  
  809.             /* Position the cursor. */
  810.  
  811.         CursorX = X;
  812.         CursorY = Y;
  813.     }
  814. }
  815.  
  816.     /* ConClearEOL():
  817.      *
  818.      *    Clear to end of current line.
  819.      */
  820.  
  821. STATIC VOID
  822. ConClearEOL()
  823. {
  824.         /* Is there anything to clear? */
  825.  
  826.     if(CursorX < WindowWidth)
  827.     {
  828.             /* Turn the cursor off before the line is cleared. */
  829.  
  830.         if(CursorState)
  831.         {
  832.                 /* Turn the cursor off. */
  833.  
  834.             ConCursorOff();
  835.  
  836.                 /* Clear the remaining line. */
  837.  
  838.             SetAPen(RPort,ConBgPen);
  839.             RectFill(RPort,CursorX,CursorY,Window -> Width - 1,CursorY + TextFontHeight - 1);
  840.             SetAPen(RPort,ConFgPen);
  841.  
  842.                 /* Turn the cursor back on. */
  843.  
  844.             ConCursorOn(CURSOR_NOCHANGE);
  845.         }
  846.         else
  847.         {
  848.             SetAPen(RPort,ConBgPen);
  849.             RectFill(RPort,CursorX,CursorY,Window -> Width - 1,CursorY + TextFontHeight - 1);
  850.             SetAPen(RPort,ConFgPen);
  851.         }
  852.     }
  853. }
  854.  
  855.     /* ConCharBackspace(const int Delta,const int New):
  856.      *
  857.      *    Move the cursor one glyph back.
  858.      */
  859.  
  860. STATIC VOID
  861. ConCharBackspace(const int Delta,const int New)
  862. {
  863.     Redraw = TRUE;
  864.  
  865.     CursorX -= Delta;
  866.  
  867.     switch(New)
  868.     {
  869.         case CURSOR_NOCHANGE:    break;
  870.  
  871.         case CURSOR_AVERAGE:    NewWidth = TextFontAverage;
  872.                     break;
  873.  
  874.         default:        NewWidth = New;
  875.                     break;
  876.     }
  877. }
  878.  
  879.     /* ConCharDelete(const int New):
  880.      *
  881.      *    Delete the character under the cursor.
  882.      */
  883.  
  884. STATIC VOID
  885. ConCharDelete(const int New)
  886. {
  887.     Redraw = TRUE;
  888.  
  889.     switch(New)
  890.     {
  891.         case CURSOR_NOCHANGE:    break;
  892.  
  893.         case CURSOR_AVERAGE:    NewWidth = TextFontAverage;
  894.                     break;
  895.  
  896.         default:        NewWidth = New;
  897.                     break;
  898.     }
  899. }
  900.  
  901.     /* ConCharInsert(const UBYTE Char):
  902.      *
  903.      *    Insert a character at the current cursor position.
  904.      */
  905.  
  906. STATIC VOID
  907. ConCharInsert(const UBYTE Char)
  908. {
  909.     Redraw = TRUE;
  910.  
  911.     CursorX += ConCharWidth(Char);
  912. }
  913.  
  914.     /* ConScrollUp():
  915.      *
  916.      *    Scroll the terminal contents one line up.
  917.      */
  918.  
  919. STATIC VOID
  920. ConScrollUp()
  921. {
  922.     UWORD Top = status_size * TextFontHeight;
  923.  
  924.         /* Is the cursor enabled? */
  925.  
  926.     if(CursorState)
  927.     {
  928.             /* Turn the cursor off. */
  929.  
  930.         ConCursorOff();
  931.  
  932.             /* Scroll the terminal contents up. */
  933.  
  934.         ScrollRaster(RPort,0,TextFontHeight,0,Top,Window -> Width - 1,Window -> Height - 1);
  935.  
  936.             /* Reposition the cursor. */
  937.  
  938.         CursorX = 0;
  939.         CursorY = TextFontHeight * (screen_rows - 1);
  940.  
  941.             /* Turn it on again. */
  942.  
  943.         ConCursorOn(CURSOR_NOCHANGE);
  944.     }
  945.     else
  946.     {
  947.             /* Scroll the terminal contents up. */
  948.  
  949.         ScrollRaster(RPort,0,TextFontHeight,0,Top,Window -> Width - 1,Window -> Height - 1);
  950.  
  951.             /* Reposition the cursor. */
  952.  
  953.         CursorX = 0;
  954.         CursorY = TextFontHeight * (screen_rows - 1);
  955.     }
  956. }
  957.  
  958.     /* ConWrite(const char *Line,LONG Len):
  959.      *
  960.      *    Output a text on the terminal.
  961.      */
  962.  
  963. STATIC VOID
  964. ConWrite(char *Line,int Len)
  965. {
  966.         /* Just like console.device, determine the
  967.          * text length if -1 is passed in as the
  968.          * length.
  969.          */
  970.  
  971.     if(Len == -1)
  972.         Len = strlen(Line);
  973.  
  974.         /* Is there anything to print? */
  975.  
  976.     if(Len)
  977.     {
  978.             /* Is the cursor still enabled? */
  979.  
  980.         if(CursorState)
  981.         {
  982.                 /* Turn off the cursor. */
  983.  
  984.             ConCursorOff();
  985.  
  986.                 /* Print the text. */
  987.  
  988.             Move(RPort,CursorX,CursorY + ThisFont -> tf_Baseline);
  989.             Text(RPort,(STRPTR)Line,Len);
  990.  
  991.                 /* Move up. */
  992.  
  993.             CursorX += TextLength(RPort,(STRPTR)Line,Len);
  994.  
  995.                 /* Turn the cursor back on. */
  996.  
  997.             ConCursorOn(CURSOR_NOCHANGE);
  998.         }
  999.         else
  1000.         {
  1001.                 /* Print the text. */
  1002.  
  1003.             Move(RPort,CursorX,CursorY + ThisFont -> tf_Baseline);
  1004.             Text(RPort,(STRPTR)Line,Len);
  1005.  
  1006.                 /* Move up. */
  1007.  
  1008.             CursorX += TextLength(RPort,(STRPTR)Line,Len);
  1009.         }
  1010.     }
  1011. }
  1012.  
  1013.     /* ConRedraw(const int X,const int Y,const STRPTR String,const int Len):
  1014.      *
  1015.      *    Redraw the input string.
  1016.      */
  1017.  
  1018. STATIC VOID
  1019. ConRedraw(const int X,const int Y,const STRPTR String,const int Len)
  1020. {
  1021.     LONG Width = TextLength(RPort,(STRPTR)String,Len);
  1022.  
  1023.         /* Turn the cursor off. */
  1024.  
  1025.     ConCursorOff();
  1026.  
  1027.         /* Redraw the input string. */
  1028.  
  1029.     Move(RPort,X,Y + ThisFont -> tf_Baseline);
  1030.     Text(RPort,(STRPTR)String,Len);
  1031.  
  1032.         /* Clear to end of line. */
  1033.  
  1034.     if(Width < WindowWidth)
  1035.     {
  1036.         SetAPen(RPort,ConBgPen);
  1037.         RectFill(RPort,X + Width,Y,Window -> Width - 1,Y + TextFontHeight - 1);
  1038.         SetAPen(RPort,ConFgPen);
  1039.     }
  1040.  
  1041.         /* Turn the cursor back on. */
  1042.  
  1043.     ConCursorOn(CURSOR_NOCHANGE);
  1044. }
  1045.  
  1046.     /* ConSetKey(int Key,STRPTR String,int Len):
  1047.      *
  1048.      *    Set a specific function key.
  1049.      */
  1050.  
  1051. STATIC VOID
  1052. ConSetKey(int Key,STRPTR String,int Len)
  1053. {
  1054.         /* Is the new string longer than the old one? */
  1055.  
  1056.     if(FunctionKeys[Key] . Len < Len)
  1057.     {
  1058.             /* Free previous key assignment. */
  1059.  
  1060.         free(FunctionKeys[Key] . Buffer);
  1061.  
  1062.             /* Create new string buffer. */
  1063.  
  1064.         if(FunctionKeys[Key] . Buffer = (STRPTR)malloc(Len + 1))
  1065.         {
  1066.                 /* Copy the key string. */
  1067.  
  1068.             memcpy(FunctionKeys[Key] . Buffer,String,Len);
  1069.  
  1070.                 /* Provide null-termination. */
  1071.  
  1072.             FunctionKeys[Key] . Buffer[Len] = 0;
  1073.  
  1074.                 /* Set string length. */
  1075.  
  1076.             FunctionKeys[Key] . Len = Len;
  1077.         }
  1078.         else
  1079.             FunctionKeys[Key] . Len = 0;
  1080.     }
  1081.     else
  1082.     {
  1083.             /* Install new string. */
  1084.  
  1085.         if(Len)
  1086.         {
  1087.                 /* Copy the key string. */
  1088.  
  1089.             memcpy(FunctionKeys[Key] . Buffer,String,Len);
  1090.  
  1091.                 /* Provide null-termination. */
  1092.  
  1093.             FunctionKeys[Key] . Buffer[Len] = 0;
  1094.         }
  1095.         else
  1096.         {
  1097.                 /* Zero length, free previous buffer
  1098.                  * assignment.
  1099.                  */
  1100.  
  1101.             if(FunctionKeys[Key] . Buffer)
  1102.             {
  1103.                     /* Free the buffer. */
  1104.  
  1105.                 free(FunctionKeys[Key] . Buffer);
  1106.  
  1107.                     /* Clear address pointer. */
  1108.  
  1109.                 FunctionKeys[Key] . Buffer = NULL;
  1110.             }
  1111.         }
  1112.  
  1113.             /* Install new length. */
  1114.  
  1115.         FunctionKeys[Key] . Len = Len;
  1116.     }
  1117. }
  1118.  
  1119.     /* ConFlush():
  1120.      *
  1121.      *    Flush the text cache.
  1122.      */
  1123.  
  1124. STATIC VOID
  1125. ConFlush()
  1126. {
  1127.         /* Are there any characters in the cache? */
  1128.  
  1129.     if(ConLineLength)
  1130.     {
  1131.         register BYTE HasMore = FALSE;
  1132.  
  1133.             /* Did we get exactly six character? */
  1134.  
  1135.         if(ConLineLength == 6)
  1136.         {
  1137.                 /* Is it the `[MORE]' prompt? */
  1138.  
  1139.             if(!memcmp(ConLine,"[MORE]",6))
  1140.             {
  1141.                     /* Reset text attribute. */
  1142.  
  1143.                 ConSetColour(COLOUR_INPUT);
  1144.  
  1145.                 if(ThisFont != PropFont)
  1146.                     SetFont(RPort,ThisFont = PropFont);
  1147.  
  1148.                 HasMore = TRUE;
  1149.             }
  1150.         }
  1151.  
  1152.         if(HasMore)
  1153.         {
  1154.                 /* Flush the cache. */
  1155.  
  1156.             ConWrite(ConLine,ConLineLength);
  1157.  
  1158.                 /* Reset index. */
  1159.  
  1160.             ConLineLength = 0;
  1161.  
  1162.                 /* Turn on original text attributes. */
  1163.  
  1164.             ConSetColour(COLOUR_RESET);
  1165.         }
  1166.         else
  1167.         {
  1168.                 /* Flush the cache. */
  1169.  
  1170.             ConWrite(ConLine,ConLineLength);
  1171.  
  1172.                 /* Reset index. */
  1173.  
  1174.             ConLineLength = 0;
  1175.         }
  1176.     }
  1177. }
  1178.  
  1179.     /* ConGetChar():
  1180.      *
  1181.      *    Read a single character from the console window.
  1182.      */
  1183.  
  1184. STATIC UBYTE
  1185. ConGetChar(BOOL SingleKey)
  1186. {
  1187.     struct IntuiMessage    *IntuiMessage;
  1188.     ULONG             Qualifier,
  1189.                  Class,
  1190.                  Code,
  1191.                  Signals;
  1192.     LONG             Len;
  1193.  
  1194.         /* Provide `fake' input in case we are
  1195.          * returning the result of a function keypress
  1196.          * or a menu event.
  1197.          */
  1198.  
  1199.     if(InputIndex)
  1200.     {
  1201.             /* Did we reach the end of the string?
  1202.              * If so, clear the index pointer and
  1203.              * fall through to the input routine.
  1204.              * If not, return the next character
  1205.              * in the buffer.
  1206.              */
  1207.  
  1208.         if(*InputIndex)
  1209.             return(*InputIndex++);
  1210.         else
  1211.             InputIndex = NULL;
  1212.     }
  1213.  
  1214.         /* Wait for input... */
  1215.  
  1216.     FOREVER
  1217.     {
  1218.             /* Process all incoming messages. */
  1219.  
  1220.         while(IntuiMessage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
  1221.         {
  1222.                 /* Remember the menu code. */
  1223.  
  1224.             Qualifier    = IntuiMessage -> Qualifier;
  1225.             Class        = IntuiMessage -> Class;
  1226.             Code        = IntuiMessage -> Code;
  1227.  
  1228.                 /* Conver key code to ANSI character or control sequence. */
  1229.  
  1230.             if(Class == IDCMP_RAWKEY)
  1231.             {
  1232.                 InputEvent -> ie_Class            = IECLASS_RAWKEY;
  1233.                 InputEvent -> ie_Code            = Code;
  1234.                 InputEvent -> ie_Qualifier        = Qualifier;
  1235.                 InputEvent -> ie_position . ie_addr    = *((APTR *)IntuiMessage -> IAddress);
  1236.  
  1237.                 InputEventBuffer[0] = 0;
  1238.  
  1239.                 Len = RawKeyConvert(InputEvent,InputEventBuffer,INPUT_LENGTH - 1,NULL);
  1240.             }
  1241.             else
  1242.                 Len = 0;
  1243.  
  1244.                 /* Reply the message. */
  1245.  
  1246.             ReplyMsg((struct Message *)IntuiMessage);
  1247.  
  1248.                 /* Did the user press a key? */
  1249.  
  1250.             if(Class == IDCMP_RAWKEY && Len > 0)
  1251.             {
  1252.                     /* Provide null-termination. */
  1253.  
  1254.                 InputEventBuffer[Len] = 0;
  1255.  
  1256.                     /* Is this a numeric pad key
  1257.                      * and was no shift key pressed?
  1258.                      */
  1259.  
  1260.                 if(Qualifier & IEQUALIFIER_NUMERICPAD)
  1261.                 {
  1262.                     if(!(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)))
  1263.                     {
  1264.                         if(SingleKey)
  1265.                             return(InputEventBuffer[0]);
  1266.                         else
  1267.                         {
  1268.                                 /* Numbers and associated directions. */
  1269.  
  1270.                             STATIC STRPTR Directions[][2] =
  1271.                             {
  1272.                                 "8",    "n\r",
  1273.                                 "9",    "ne\r",
  1274.                                 "6",    "e\r",
  1275.                                 "3",    "se\r",
  1276.                                 "2",    "s\r",
  1277.                                 "1",    "sw\r",
  1278.                                 "4",    "w\r",
  1279.                                 "7",    "nw\r",
  1280.  
  1281.                                 "[",    "in\r",
  1282.                                 "]",    "out\r",
  1283.  
  1284.                                 "+",    "u\r",
  1285.                                 "-",    "d\r"
  1286.                             };
  1287.  
  1288.                             int i;
  1289.  
  1290.                                 /* Run down the list of directions. */
  1291.  
  1292.                             for(i = 0 ; i < sizeof(Directions) / (2 * sizeof(STRPTR)) ; i++)
  1293.                             {
  1294.                                     /* Does it match the input? */
  1295.  
  1296.                                 if(!strcmp(Directions[i][0],InputEventBuffer))
  1297.                                 {
  1298.                                         /* Use it as fake input. */
  1299.  
  1300.                                     InputIndex = Directions[i][1];
  1301.  
  1302.                                         /* Return ^X. */
  1303.  
  1304.                                     return(TERM_X);
  1305.                                 }
  1306.                             }
  1307.                         }
  1308.                     }
  1309.                 }
  1310.                 else
  1311.                 {
  1312.                     if(SingleKey)
  1313.                     {
  1314.                         if(InputEventBuffer[0] != TERM_CSI)
  1315.                             return(InputEventBuffer[0]);
  1316.                     }
  1317.                     else
  1318.                     {
  1319.                             /* Take over the input. */
  1320.  
  1321.                         InputIndex = InputEventBuffer;
  1322.  
  1323.                             /* Return the first character. */
  1324.  
  1325.                         return(*InputIndex++);
  1326.                     }
  1327.                 }
  1328.             }
  1329.         }
  1330.  
  1331.         do
  1332.         {
  1333.             Signals = Wait(SIG_TIMER | SIG_WINDOW);
  1334.  
  1335.             if(Signals & SIG_TIMER)
  1336.             {
  1337.                 if(CursorState)
  1338.                     ConCursorOff();
  1339.                 else
  1340.                     ConCursorOn(CURSOR_NOCHANGE);
  1341.  
  1342.                     /* Remove timer request. */
  1343.  
  1344.                 WaitIO(TimeRequest);
  1345.  
  1346.                     /* Send new timer request. */
  1347.  
  1348.                 TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  1349.                 TimeRequest -> tr_time . tv_secs    = 0;
  1350.                 TimeRequest -> tr_time . tv_micro    = SECOND / 2;
  1351.  
  1352.                 BeginIO(TimeRequest);
  1353.             }
  1354.         }
  1355.         while(!(Signals & SIG_WINDOW));
  1356.     }
  1357. }
  1358.  
  1359.     /* ConPrintf(char *Format,...):
  1360.      *
  1361.      *    Print a text in the console window, including formatting
  1362.      *    control codes.
  1363.      */
  1364.  
  1365. STATIC VOID
  1366. ConPrintf(char *Format,...)
  1367. {
  1368.     STATIC char    ConBuffer[256];
  1369.     va_list        VarArgs;
  1370.  
  1371.     va_start(VarArgs,Format);
  1372.     vsprintf(ConBuffer,Format,VarArgs);
  1373.     va_end(VarArgs);
  1374.  
  1375.     ConWrite(ConBuffer,-1);
  1376. }
  1377.  
  1378.     /* ConInput(char *Input,int MaxLen):
  1379.      *
  1380.      *    Read a line of input from the console window.
  1381.      */
  1382.  
  1383. STATIC int
  1384. ConInput(char *Prompt,char *Input,int MaxLen,BOOL DoHistory)
  1385. {
  1386.         /* Control sequence buffer and length of control sequence. */
  1387.  
  1388.     UBYTE        SequenceBuffer[81];
  1389.     int        SequenceLen;
  1390.  
  1391.         /* Input length, current cursor position index, last history buffer. */
  1392.  
  1393.     register int    Len        = 0,
  1394.             Index        = 0,
  1395.             HistoryIndex    = LastHistory + 1,
  1396.             i;
  1397.  
  1398.         /* The character to read. */
  1399.  
  1400.     register UBYTE    Char;
  1401.  
  1402.         /* Loop flag. */
  1403.  
  1404.     BOOL        Done    = FALSE;
  1405.  
  1406.     UWORD        OldX    = CursorX;
  1407.  
  1408.     ConSetColour(COLOUR_INPUT);
  1409.  
  1410.     if(ThisFont != PropFont)
  1411.         SetFont(RPort,ThisFont = PropFont);
  1412.  
  1413.     ConCursorOn(CURSOR_AVERAGE);
  1414.  
  1415.         /* Read until done. */
  1416.  
  1417.     do
  1418.     {
  1419.             /* Get a character. */
  1420.  
  1421.         switch(Char = ConGetChar(FALSE))
  1422.         {
  1423.                 /* A function key, a cursor key or the help key. */
  1424.  
  1425.             case TERM_CSI:    SequenceLen = 0;
  1426.  
  1427.                         /* Read the whole sequence if possible,
  1428.                          * up to 80 characters will be accepted.
  1429.                          */
  1430.  
  1431.                     do
  1432.                         SequenceBuffer[SequenceLen++] = Char = ConGetChar(FALSE);
  1433.                     while(SequenceLen < 80 && (Char == ' ' || Char == ';' || Char == '?' || (Char >= '0' && Char <= '9')));
  1434.  
  1435.                         /* Provide null-termination. */
  1436.  
  1437.                     SequenceBuffer[SequenceLen] = 0;
  1438.  
  1439.                         /* Function key. */
  1440.  
  1441.                     if(SequenceBuffer[0] != '?' && SequenceBuffer[SequenceLen - 1] == '~')
  1442.                     {
  1443.                         int Key;
  1444.  
  1445.                             /* Remove the terminating tilde. */
  1446.  
  1447.                         SequenceBuffer[SequenceLen - 1] = 0;
  1448.  
  1449.                             /* Make sure that the function
  1450.                              * key code is in reasonable
  1451.                              * dimensions, some custom
  1452.                              * keyboards have more than
  1453.                              * 20 function keys.
  1454.                              */
  1455.  
  1456.                         if((Key = atoi(SequenceBuffer)) < NUM_FKEYS)
  1457.                         {
  1458.                                 /* Is a string assigned to
  1459.                                  * this function key?
  1460.                                  */
  1461.  
  1462.                             if(FunctionKeys[Key] . Len)
  1463.                             {
  1464.                                 BOOL    GotIt = FALSE;
  1465.                                 int    i;
  1466.  
  1467.                                     /* Examine the string and look
  1468.                                      * for a bar or exclamation mark
  1469.                                      * which will terminate the
  1470.                                      * string and produce a carriage-
  1471.                                      * return.
  1472.                                      */
  1473.  
  1474.                                 for(i = 0 ; i < FunctionKeys[Key] . Len ; i++)
  1475.                                 {
  1476.                                         /* Is this the character we are looking for? */
  1477.  
  1478.                                     if(FunctionKeys[Key] . Buffer[i] == '|' || FunctionKeys[Key] . Buffer[i] == '!')
  1479.                                     {
  1480.                                             /* Copy the string. */
  1481.  
  1482.                                         memcpy(InputBuffer,FunctionKeys[Key] . Buffer,i);
  1483.  
  1484.                                             /* Add the carriage-return. */
  1485.  
  1486.                                         InputBuffer[i++] = '\r';
  1487.                                         InputBuffer[i]   = 0;
  1488.  
  1489.                                             /* Stop the search and
  1490.                                              * remember that we got
  1491.                                              * a fitting string.
  1492.                                              */
  1493.  
  1494.                                         GotIt = TRUE;
  1495.  
  1496.                                         break;
  1497.                                     }
  1498.                                 }
  1499.  
  1500.                                     /* Provide new input. */
  1501.  
  1502.                                 if(GotIt)
  1503.                                     InputIndex = InputBuffer;
  1504.                                 else
  1505.                                     InputIndex = FunctionKeys[Key] . Buffer;
  1506.                             }
  1507.                             else
  1508.                                 DisplayBeep(Window -> WScreen);
  1509.                         }
  1510.  
  1511.                         break;
  1512.                     }
  1513.  
  1514.                         /* Help key. */
  1515.  
  1516.                     if(DoHistory && !strcmp(SequenceBuffer,"?~"))
  1517.                     {
  1518.                             /* Which function key is pressed? */
  1519.  
  1520.                         int WhichKey = -1;
  1521.  
  1522.                             /* Do not produce any `fake' input. */
  1523.  
  1524.                         InputIndex = NULL;
  1525.  
  1526.                         ConCursorOff();
  1527.  
  1528.                             /* Clear the input line. */
  1529.  
  1530.                         ConSet(0,TextFontHeight * (screen_rows - 1),CURSOR_AVERAGE);
  1531.  
  1532.                         ConSetColour(COLOUR_TEXT);
  1533.  
  1534.                             /* Ask for the function key to
  1535.                              * assign a string to.
  1536.                              */
  1537.  
  1538.                         ConPrintf("Function key to define: ");
  1539.                         ConClearEOL();
  1540.  
  1541.                         ConCursorOn(CURSOR_NOCHANGE);
  1542.  
  1543.                             /* Is the first character we get
  1544.                              * a control-sequence introducer?
  1545.                              */
  1546.  
  1547.                         if(ConGetChar(FALSE) == TERM_CSI)
  1548.                         {
  1549.                             SequenceLen = 0;
  1550.  
  1551.                                 /* Read the whole sequence if possible,
  1552.                                  * up to 80 characters will be accepted.
  1553.                                  */
  1554.  
  1555.                             do
  1556.                                 SequenceBuffer[SequenceLen++] = Char = ConGetChar(FALSE);
  1557.                             while(SequenceLen < 80 && (Char == ' ' || Char == ';' || Char == '?' || (Char >= '0' && Char <= '9')));
  1558.  
  1559.                                 /* Provide null-termination. */
  1560.  
  1561.                             SequenceBuffer[SequenceLen] = 0;
  1562.  
  1563.                                 /* Did we get a function key code? */
  1564.  
  1565.                             if(SequenceBuffer[0] != '?' && SequenceBuffer[SequenceLen - 1] == '~')
  1566.                             {
  1567.                                     /* The function key we got. */
  1568.  
  1569.                                 int Key;
  1570.  
  1571.                                     /* Remove the terminating tilde. */
  1572.  
  1573.                                 SequenceBuffer[SequenceLen - 1] = 0;
  1574.  
  1575.                                     /* Get the number of the key. */
  1576.  
  1577.                                 if((Key = atoi(SequenceBuffer)) < NUM_FKEYS)
  1578.                                     WhichKey = Key;
  1579.                             }
  1580.                         }
  1581.  
  1582.                         ConCursorOff();
  1583.  
  1584.                         ConSetColour(COLOUR_INPUT);
  1585.  
  1586.                             /* Did we get any key? */
  1587.  
  1588.                         if(WhichKey == -1)
  1589.                             ConPrintf("none.");
  1590.                         else
  1591.                         {
  1592.                             int Len;
  1593.  
  1594.                                 /* Print the key name. */
  1595.  
  1596.                             ConPrintf("%sF%d",(WhichKey > 9) ? "Shift " : "",(WhichKey % 10) + 1);
  1597.  
  1598.                                 /* Provide new line. */
  1599.  
  1600.                             ConScrollUp();
  1601.  
  1602.                             ConSetColour(COLOUR_TEXT);
  1603.  
  1604.                                 /* Show new prompt. */
  1605.  
  1606.                             ConPrintf("Key text >");
  1607.  
  1608.                             ConCursorOn(CURSOR_NOCHANGE);
  1609.  
  1610.                             InputIndex = NULL;
  1611.  
  1612.                                 /* Read key assignment. */
  1613.  
  1614.                             Len = ConInput("",InputBuffer,0,FALSE);
  1615.  
  1616.                                 /* Set new key string. */
  1617.  
  1618.                             ConSetKey(WhichKey,InputBuffer,Len);
  1619.  
  1620.                             ConCursorOff();
  1621.                         }
  1622.  
  1623.                             /* Provide new line. */
  1624.  
  1625.                         ConScrollUp();
  1626.  
  1627.                         ConSetColour(COLOUR_TEXT);
  1628.  
  1629.                             /* Print the prompt string. */
  1630.  
  1631.                         ConPrintf(Prompt);
  1632.  
  1633.                         ConSetColour(COLOUR_INPUT);
  1634.  
  1635.                             /* Write the entire input line. */
  1636.  
  1637.                         ConWrite(Input,Len);
  1638.  
  1639.                             /* Make sure that the
  1640.                              * cursor is placed at
  1641.                              * the end of the input
  1642.                              * line.
  1643.                              */
  1644.  
  1645.                         Index = Len;
  1646.  
  1647.                         InputIndex = NULL;
  1648.  
  1649.                         ConCursorOn(CURSOR_AVERAGE);
  1650.  
  1651.                         break;
  1652.                     }
  1653.  
  1654.                         /* Cursor up: recall previous line in history buffer. */
  1655.  
  1656.                     if(!strcmp(SequenceBuffer,"A"))
  1657.                     {
  1658.                             /* Are any history lines available? */
  1659.  
  1660.                         if(LastHistory != -1)
  1661.                         {
  1662.                             ConCursorOff();
  1663.  
  1664.                                 /* Move cursor back
  1665.                                  * to beginning of
  1666.                                  * line.
  1667.                                  */
  1668.  
  1669.                             if(Index)
  1670.                                 ConSet(OldX,TextFontHeight * (screen_rows - 1),CURSOR_AVERAGE);
  1671.  
  1672.                                 /* Clear line. */
  1673.  
  1674.                             ConClearEOL();
  1675.  
  1676.                                 /* Go to previous history line. */
  1677.  
  1678.                             if(HistoryIndex)
  1679.                                 HistoryIndex--;
  1680.  
  1681.                                 /* Determine history line length. */
  1682.  
  1683.                             if(MaxLen)
  1684.                                 Index = Len = (HistoryBuffer[HistoryIndex] . Len > MaxLen) ? MaxLen : HistoryBuffer[HistoryIndex] . Len;
  1685.                             else
  1686.                                 Index = Len = HistoryBuffer[HistoryIndex] . Len;
  1687.  
  1688.                                 /* Copy the history line over. */
  1689.  
  1690.                             memcpy(Input,HistoryBuffer[HistoryIndex] . Buffer,Len);
  1691.  
  1692.                                 /* Write the line. */
  1693.  
  1694.                             ConWrite(Input,Len);
  1695.  
  1696.                             ConCursorOn(CURSOR_NOCHANGE);
  1697.                         }
  1698.  
  1699.                         break;
  1700.                     }
  1701.  
  1702.                         /* Cursor down: recall next line in history buffer. */
  1703.  
  1704.                     if(!strcmp(SequenceBuffer,"B"))
  1705.                     {
  1706.                             /* Are any history lines available? */
  1707.  
  1708.                         if(LastHistory != -1)
  1709.                         {
  1710.                             ConCursorOff();
  1711.  
  1712.                                 /* Are we at the end
  1713.                                  * of the list?
  1714.                                  */
  1715.  
  1716.                             if(HistoryIndex < LastHistory)
  1717.                             {
  1718.                                     /* Move cursor back
  1719.                                      * to beginning of
  1720.                                      * line.
  1721.                                      */
  1722.  
  1723.                                 if(Index)
  1724.                                     ConSet(OldX,TextFontHeight * (screen_rows - 1),CURSOR_AVERAGE);
  1725.  
  1726.                                     /* Clear line. */
  1727.  
  1728.                                 ConClearEOL();
  1729.  
  1730.                                     /* Get next history line. */
  1731.  
  1732.                                 HistoryIndex++;
  1733.  
  1734.                                     /* Determine history line length. */
  1735.  
  1736.                                 if(MaxLen)
  1737.                                     Index = Len = (HistoryBuffer[HistoryIndex] . Len > MaxLen) ? MaxLen : HistoryBuffer[HistoryIndex] . Len;
  1738.                                 else
  1739.                                     Index = Len = HistoryBuffer[HistoryIndex] . Len;
  1740.  
  1741.                                     /* Copy the history line over. */
  1742.  
  1743.                                 memcpy(Input,HistoryBuffer[HistoryIndex] . Buffer,Len);
  1744.  
  1745.                                     /* Write the line. */
  1746.  
  1747.                                 ConWrite(Input,Len);
  1748.                             }
  1749.                             else
  1750.                             {
  1751.                                     /* Move cursor back
  1752.                                      * to beginning of
  1753.                                      * line.
  1754.                                      */
  1755.  
  1756.                                 if(Index)
  1757.                                     ConSet(OldX,TextFontHeight * (screen_rows - 1),CURSOR_AVERAGE);
  1758.  
  1759.                                     /* Clear line. */
  1760.  
  1761.                                 ConClearEOL();
  1762.  
  1763.                                     /* Nothing in the line buffer right now. */
  1764.  
  1765.                                 Index = Len = 0;
  1766.  
  1767.                                     /* Make sure that `cursor up'
  1768.                                      * will recall the last history
  1769.                                      * line.
  1770.                                      */
  1771.  
  1772.                                 HistoryIndex = LastHistory + 1;
  1773.                             }
  1774.  
  1775.                             ConCursorOn(CURSOR_NOCHANGE);
  1776.                         }
  1777.  
  1778.                         break;
  1779.                     }
  1780.  
  1781.                         /* Shift+cursor up: recall first history line in buffer. */
  1782.  
  1783.                     if(!strcmp(SequenceBuffer,"T"))
  1784.                     {
  1785.                             /* Are any history lines available? */
  1786.  
  1787.                         if(LastHistory != -1)
  1788.                         {
  1789.                             ConCursorOff();
  1790.  
  1791.                                 /* Move cursor back
  1792.                                  * to beginning of
  1793.                                  * line.
  1794.                                  */
  1795.  
  1796.                             if(Index)
  1797.                                 ConSet(OldX,TextFontHeight * (screen_rows - 1),CURSOR_AVERAGE);
  1798.  
  1799.                                 /* Clear line. */
  1800.  
  1801.                             ConClearEOL();
  1802.  
  1803.                                 /* Use the first history line. */
  1804.  
  1805.                             HistoryIndex = 0;
  1806.  
  1807.                                 /* Determine history line length. */
  1808.  
  1809.                             if(MaxLen)
  1810.                                 Index = Len = (HistoryBuffer[HistoryIndex] . Len > MaxLen) ? MaxLen : HistoryBuffer[HistoryIndex] . Len;
  1811.                             else
  1812.                                 Index = Len = HistoryBuffer[HistoryIndex] . Len;
  1813.  
  1814.                                 /* Copy the history line over. */
  1815.  
  1816.                             memcpy(Input,HistoryBuffer[HistoryIndex] . Buffer,Len);
  1817.  
  1818.                                 /* Write the line. */
  1819.  
  1820.                             ConWrite(Input,Len);
  1821.  
  1822.                             ConCursorOn(CURSOR_NOCHANGE);
  1823.                         }
  1824.  
  1825.                         break;
  1826.                     }
  1827.  
  1828.                         /* Shift+cursor down: recall last history line. */
  1829.  
  1830.                     if(!strcmp(SequenceBuffer,"S"))
  1831.                     {
  1832.                             /* Are any history lines available? */
  1833.  
  1834.                         if(LastHistory != -1)
  1835.                         {
  1836.                             ConCursorOff();
  1837.  
  1838.                                 /* Move cursor back
  1839.                                  * to beginning of
  1840.                                  * line.
  1841.                                  */
  1842.  
  1843.                             if(Index)
  1844.                                 ConSet(OldX,TextFontHeight * (screen_rows - 1),CURSOR_AVERAGE);
  1845.  
  1846.                                 /* Clear line. */
  1847.  
  1848.                             ConClearEOL();
  1849.  
  1850.                                 /* Go to last line in history buffer. */
  1851.  
  1852.                             HistoryIndex = LastHistory;
  1853.  
  1854.                                 /* Determine history line length. */
  1855.  
  1856.                             if(MaxLen)
  1857.                                 Index = Len = (HistoryBuffer[HistoryIndex] . Len > MaxLen) ? MaxLen : HistoryBuffer[HistoryIndex] . Len;
  1858.                             else
  1859.                                 Index = Len = HistoryBuffer[HistoryIndex] . Len;
  1860.  
  1861.                                 /* Copy the history line over. */
  1862.  
  1863.                             memcpy(Input,HistoryBuffer[HistoryIndex] . Buffer,Len);
  1864.  
  1865.                                 /* Write the line. */
  1866.  
  1867.                             ConWrite(Input,Len);
  1868.  
  1869.                             ConCursorOn(CURSOR_NOCHANGE);
  1870.                         }
  1871.  
  1872.                         break;
  1873.                     }
  1874.  
  1875.                         /* Cursor right: move cursor to the right. */
  1876.  
  1877.                     if(!strcmp(SequenceBuffer,"C"))
  1878.                     {
  1879.                             /* Are we at the end of the line? */
  1880.  
  1881.                         if(Index < Len)
  1882.                         {
  1883.                             if(Index == Len - 1)
  1884.                                 ConMove(ConCharWidth(Input[Index]),CURSOR_AVERAGE);
  1885.                             else
  1886.                                 ConMove(ConCharWidth(Input[Index]),ConCharWidth(Input[Index + 1]));
  1887.  
  1888.                             Index++;
  1889.                         }
  1890.  
  1891.                         break;
  1892.                     }
  1893.  
  1894.                         /* Cursor left: move cursor to the left. */
  1895.  
  1896.                     if(!strcmp(SequenceBuffer,"D"))
  1897.                     {
  1898.                             /* Are we at the beginning of the line? */
  1899.  
  1900.                         if(Index > 0)
  1901.                         {
  1902.                                 /* Update internal cursor position. */
  1903.  
  1904.                             Index--;
  1905.  
  1906.                                 /* Move cursor to the left. */
  1907.  
  1908.                             ConMove(-ConCharWidth(Input[Index]),ConCharWidth(Input[Index]));
  1909.                         }
  1910.  
  1911.                         break;
  1912.                     }
  1913.  
  1914.                         /* Shift+cursor right: move cursor to end of line. */
  1915.  
  1916.                     if(!strcmp(SequenceBuffer," @"))
  1917.                     {
  1918.                             /* Are we at the end of the line? */
  1919.  
  1920.                         if(Index < Len)
  1921.                         {
  1922.                                 /* Move cursor to end of line. */
  1923.  
  1924.                             ConMove(TextLength(RPort,&Input[Index],Len - Index),CURSOR_AVERAGE);
  1925.  
  1926.                                 /* Update internal cursor position. */
  1927.  
  1928.                             Index = Len;
  1929.                         }
  1930.  
  1931.                         break;
  1932.                     }
  1933.  
  1934.                         /* Shift+cursor left: move cursor to beginning of line. */
  1935.  
  1936.                     if(!strcmp(SequenceBuffer," A"))
  1937.                     {
  1938.                             /* Are we at the beginning of the line? */
  1939.  
  1940.                         if(Index > 0)
  1941.                         {
  1942.                                 /* Move cursor to beginning of line. */
  1943.  
  1944.                             if(Len)
  1945.                                 ConSet(OldX,TextFontHeight * (screen_rows - 1),ConCharWidth(Input[0]));
  1946.                             else
  1947.                                 ConSet(OldX,TextFontHeight * (screen_rows - 1),CURSOR_AVERAGE);
  1948.  
  1949.                                 /* Update internal cursor position. */
  1950.  
  1951.                             Index = 0;
  1952.                         }
  1953.                     }
  1954.  
  1955.                     break;
  1956.  
  1957.                 /* Backspace: delete the character to the left
  1958.                  * of the cursor.
  1959.                  */
  1960.  
  1961.             case TERM_BS:    if(Index > 0)
  1962.                     {
  1963.                             /* Delete the character. */
  1964.  
  1965.                         if(Index == Len)
  1966.                             ConCharBackspace(ConCharWidth(Input[Index - 1]),CURSOR_AVERAGE);
  1967.                         else
  1968.                             ConCharBackspace(ConCharWidth(Input[Index - 1]),ConCharWidth(Input[Index]));
  1969.  
  1970.                             /* Move line contents. */
  1971.  
  1972.                         for(i = Index - 1 ; i < Len - 1 ; i++)
  1973.                             Input[i] = Input[i + 1];
  1974.  
  1975.                             /* Update internal cursor position. */
  1976.  
  1977.                         Index--;
  1978.  
  1979.                             /* Update line length. */
  1980.  
  1981.                         Len--;
  1982.                     }
  1983.  
  1984.                     break;
  1985.  
  1986.                 /* Delete: delete the character under the cursor. */
  1987.  
  1988.             case TERM_DEL:    if(Index < Len)
  1989.                     {
  1990.                             /* Delete the character. */
  1991.  
  1992.                         if(Index == Len - 1)
  1993.                             ConCharDelete(CURSOR_AVERAGE);
  1994.                         else
  1995.                             ConCharDelete(ConCharWidth(Input[Index + 1]));
  1996.  
  1997.                             /* Move line contents. */
  1998.  
  1999.                         for(i = Index ; i < Len - 1 ; i++)
  2000.                             Input[i] = Input[i + 1];
  2001.  
  2002.                             /* Update line length. */
  2003.  
  2004.                         Len--;
  2005.                     }
  2006.  
  2007.                     break;
  2008.  
  2009.                 /* Control-X: delete the entire line contents. */
  2010.  
  2011.             case TERM_X:    if(Len > 0)
  2012.                     {
  2013.                             /* Move to beginning of line. */
  2014.  
  2015.                         if(Index)
  2016.                             ConSet(OldX,TextFontHeight * (screen_rows - 1),CURSOR_AVERAGE);
  2017.  
  2018.                             /* Clear line contents. */
  2019.  
  2020.                         ConClearEOL();
  2021.  
  2022.                             /* Nothing in the line buffer right now. */
  2023.  
  2024.                         Index = Len = 0;
  2025.                     }
  2026.  
  2027.                     break;
  2028.  
  2029.                 /* Carriage return: terminate input. */
  2030.  
  2031.             case TERM_CR:    Done = TRUE;
  2032.  
  2033.                     break;
  2034.  
  2035.                 /* If suitable, store the character entered. */
  2036.  
  2037.             default:    if(Char >= 32 && Char < 127)
  2038.                     {
  2039.                             /* Is there a length limit? */
  2040.  
  2041.                         if(MaxLen)
  2042.                         {
  2043.                                 /* If the string is large
  2044.                                  * enough already, don't
  2045.                                  * store the new character.
  2046.                                  */
  2047.  
  2048.                             if(Len >= MaxLen)
  2049.                                 break;
  2050.                         }
  2051.  
  2052.                             /* Is the resulting string too long
  2053.                              * to fit in the window, don't store
  2054.                              * the new character.
  2055.                              */
  2056.  
  2057.                         if(OldX + TextLength(RPort,Input,Len) + TextFontWidth + ConCharWidth(Char) >= WindowWidth)
  2058.                             break;
  2059.  
  2060.                             /* Print the character. */
  2061.  
  2062.                         ConCharInsert(Char);
  2063.  
  2064.                             /* Move line contents up if
  2065.                              * necessary.
  2066.                              */
  2067.  
  2068.                         if(Index < Len)
  2069.                         {
  2070.                             for(i = Len ; i > Index ; i--)
  2071.                                 Input[i] = Input[i - 1];
  2072.                         }
  2073.  
  2074.                             /* Store the character. */
  2075.  
  2076.                         Input[Index++] = Char;
  2077.  
  2078.                             /* Update line length. */
  2079.  
  2080.                         Len++;
  2081.                     }
  2082.  
  2083.                     break;
  2084.         }
  2085.  
  2086.             /* Are we to redraw the input line? */
  2087.  
  2088.         if(Redraw)
  2089.         {
  2090.             ConRedraw(OldX,TextFontHeight * (screen_rows - 1),Input,Len);
  2091.  
  2092.             Redraw = FALSE;
  2093.         }
  2094.     }
  2095.     while(!Done);
  2096.  
  2097.         /* Did the user enter anything? */
  2098.  
  2099.     if(Len && DoHistory)
  2100.     {
  2101.             /* Move up if space is exhausted. */
  2102.  
  2103.         if(LastHistory == HISTORY_LINES - 1)
  2104.         {
  2105.                 /* Free first line in history buffer. */
  2106.  
  2107.             free(HistoryBuffer[0] . Buffer);
  2108.  
  2109.                 /* Move previous contents up. */
  2110.  
  2111.             for(i = 1 ; i < HISTORY_LINES ; i++)
  2112.                 HistoryBuffer[i - 1] = HistoryBuffer[i];
  2113.         }
  2114.         else
  2115.             LastHistory++;
  2116.  
  2117.             /* Add next history line. */
  2118.  
  2119.         if(HistoryBuffer[LastHistory] . Buffer = (char *)malloc(Len))
  2120.         {
  2121.                 /* Copy the input line. */
  2122.  
  2123.             memcpy(HistoryBuffer[LastHistory] . Buffer,Input,Len);
  2124.  
  2125.                 /* Save the line length. */
  2126.  
  2127.             HistoryBuffer[LastHistory] . Len = Len;
  2128.         }
  2129.         else
  2130.             LastHistory--;
  2131.     }
  2132.  
  2133.     ConSetColour(COLOUR_RESET);
  2134.  
  2135.         /* Return number of characters entered. */
  2136.  
  2137.     return(Len);
  2138. }
  2139.  
  2140.     /* initialize_screen():
  2141.      *
  2142.      *    Set up the screen to display the text.
  2143.      */
  2144.  
  2145. VOID
  2146. initialize_screen()
  2147. {
  2148.         /* Default and system font definitions. */
  2149.  
  2150.     STATIC struct TextAttr     DefaultFont = { (STRPTR)"topaz.font", 8, FS_NORMAL, FPF_ROMFONT | FPF_DESIGNED };
  2151.  
  2152.         /* The buffer to receive a copy of the Workbench screen. */
  2153.  
  2154.     struct Screen         WorkbenchScreen;
  2155.  
  2156.         /* New screen structure. */
  2157.  
  2158.     struct NewScreen     NewScreen;
  2159.  
  2160.         /* New window structure. */
  2161.  
  2162.     struct NewWindow     NewWindow;
  2163.  
  2164.         /* System font dimensions. */
  2165.  
  2166.     UWORD             SystemFontWidth,
  2167.                  SystemFontHeight;
  2168.  
  2169.         /* Auxilary data. */
  2170.  
  2171.     UWORD             Width,Len;
  2172.     UBYTE             Char;
  2173.  
  2174.         /* The famous `The story is loading...' (as seen on television). */
  2175.  
  2176.     const char        *TheStory = "The story is loading...";
  2177.  
  2178. #ifdef __GNUC__
  2179.  
  2180.     sigset_t trapped = TRAPPED_SIGNALS;
  2181.  
  2182.     if(sigprocmask(SIG_BLOCK,&trapped,NULL) != 0)
  2183.         fatal("Could not block signals");
  2184.  
  2185. #endif    /* __GNUC__ */
  2186.  
  2187.         /* Get current process identifier. */
  2188.  
  2189.     ThisProcess = (struct Process *)FindTask(NULL);
  2190.  
  2191.         /* Remember old window pointer. */
  2192.  
  2193.     WindowPtr = ThisProcess -> pr_WindowPtr;
  2194.  
  2195.         /* Open libraries... */
  2196.  
  2197.     if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",LIB_VERSION)))
  2198.         fatal("Could not open intuition.library");
  2199.  
  2200.     if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",LIB_VERSION)))
  2201.         fatal("Could not open graphics.library");
  2202.  
  2203.     IconBase = OpenLibrary("icon.library",LIB_VERSION);
  2204.  
  2205.         /* Create timer reply port. */
  2206.  
  2207.     if(!(TimePort = (struct MsgPort *)CreatePort(NULL,0)))
  2208.         fatal("Could not create timer port");
  2209.  
  2210.         /* Create timer IORequest. */
  2211.  
  2212.     if(!(TimeRequest = (struct timerequest *)CreateExtIO(TimePort,sizeof(struct timerequest))))
  2213.         fatal("Could not create timer request");
  2214.  
  2215.         /* Open timer.device. */
  2216.  
  2217.     if(OpenDevice("timer.device",UNIT_VBLANK,(struct IORequest *)TimeRequest,0))
  2218.         fatal("Could not open timer.device");
  2219.  
  2220.         /* Remember current system font. */
  2221.  
  2222.     Forbid();
  2223.  
  2224.         /* Remember system font dimensions. */
  2225.  
  2226.     SystemFontWidth        = GfxBase -> DefaultFont -> tf_XSize;
  2227.     SystemFontHeight    = GfxBase -> DefaultFont -> tf_YSize;
  2228.  
  2229.     Permit();
  2230.  
  2231.         /* Clear new screen definition. */
  2232.  
  2233.     memset(&NewScreen,0,sizeof(struct NewScreen));
  2234.  
  2235.         /* Fill in the common screen data. */
  2236.  
  2237.     NewScreen . Depth    = 2;
  2238.     NewScreen . DetailPen    = 0;
  2239.     NewScreen . BlockPen    = 1;
  2240.     NewScreen . Type    = CUSTOMSCREEN | SCREENBEHIND | SCREENQUIET;
  2241.     NewScreen . Font    = NULL;
  2242.  
  2243.     Forbid();
  2244.  
  2245.         /* Try to get some information on the Workbench screen. */
  2246.  
  2247.     if(GetScreenData(&WorkbenchScreen,sizeof(struct Screen),WBENCHSCREEN,NULL))
  2248.     {
  2249.         UWORD    Height    = WorkbenchScreen . Height,
  2250.             Width    = WorkbenchScreen . Width;
  2251.  
  2252.             /* Pick up the screen display mode ID. */
  2253.  
  2254.         NewScreen . ViewModes = WorkbenchScreen . ViewPort . Modes;
  2255.  
  2256.             /* Check for illegal dimension. */
  2257.  
  2258.         if(Width > 2 * GfxBase -> MaxDisplayColumn)
  2259.             Width = GfxBase -> NormalDisplayColumns;
  2260.  
  2261.         if(NewScreen . ViewModes & LACE)
  2262.         {
  2263.             if(Height > 2 * GfxBase -> MaxDisplayRow)
  2264.                 Height = 2 * GfxBase -> NormalDisplayRows;
  2265.         }
  2266.         else
  2267.         {
  2268.             if(Height > GfxBase -> MaxDisplayRow)
  2269.                 Height = GfxBase -> NormalDisplayRows;
  2270.         }
  2271.  
  2272.         NewScreen . Height = (((Height - SCREEN_MARGIN) / SystemFontHeight) * SystemFontHeight) + SCREEN_MARGIN;
  2273.  
  2274.             /* `A mind forever voyaging' requires a fixed screen
  2275.              * width of eighty characters per line.
  2276.              */
  2277.  
  2278.         if(h_type == 4 && (h_version == 79 || h_version == 77))
  2279.         {
  2280.             if(SystemFontWidth * 80 > Width)
  2281.             {
  2282.                 NewScreen . Width    = 640;
  2283.                 NewScreen . Height    = (((Height - SCREEN_MARGIN) / 8) * 8) + SCREEN_MARGIN;
  2284.                 NewScreen . Font    = &DefaultFont;
  2285.             }
  2286.             else
  2287.                 NewScreen . Width = SystemFontWidth * 80;
  2288.         }
  2289.         else
  2290.         {
  2291.                 /* The current interpreter release does not
  2292.                  * support more than 128 columns.
  2293.                  */
  2294.  
  2295.             if(Width / SystemFontWidth > 128)
  2296.             {
  2297.                 NewScreen . Width    = 640;
  2298.                 NewScreen . Height    = (((Height - SCREEN_MARGIN) / 8) * 8) + SCREEN_MARGIN;
  2299.                 NewScreen . Font    = &DefaultFont;
  2300.             }
  2301.             else
  2302.                 NewScreen . Width = Width;
  2303.         }
  2304.     }
  2305.     else
  2306.     {
  2307.             /* Seems that it went wrong, anyway: let's assume
  2308.              * default values then.
  2309.              */
  2310.  
  2311.         NewScreen . ViewModes = HIRES;
  2312.  
  2313.             /* If the desired screen width is larger
  2314.              * than 640 pixels, use the default font.
  2315.              */
  2316.  
  2317.         if(SystemFontWidth * 80 > 640)
  2318.         {
  2319.             NewScreen . Width    = 640;
  2320.             NewScreen . Font    = &DefaultFont;
  2321.         }
  2322.         else
  2323.             NewScreen . Width = SystemFontWidth * 80;
  2324.  
  2325.             /* Adjust screen height accordingly. */
  2326.  
  2327.         if((GfxBase -> DisplayFlags & (PAL|NTSC)) == PAL)
  2328.             NewScreen . Height = (((256 - SCREEN_MARGIN) / SystemFontHeight) * SystemFontHeight) + SCREEN_MARGIN;
  2329.         else
  2330.             NewScreen . Height = (((200 - SCREEN_MARGIN) / SystemFontHeight) * SystemFontHeight) + SCREEN_MARGIN;
  2331.     }
  2332.  
  2333.     Permit();
  2334.  
  2335.         /* Open the screen. */
  2336.  
  2337.     if(IntuitionBase -> LibNode . lib_Version < 36)
  2338.     {
  2339.         if(!(Screen = (struct Screen *)OpenScreen(&NewScreen)))
  2340.             fatal("Could not open screen");
  2341.  
  2342.             /* Turn off the screen title. */
  2343.  
  2344.         ShowTitle(Screen,FALSE);
  2345.     }
  2346.     else
  2347.     {
  2348.         struct Rectangle     DisplayClip;
  2349.         ULONG             DisplayID;
  2350.         struct Screen        *DefaultScreen;
  2351.  
  2352.         if(DefaultScreen = LockPubScreen(NULL))
  2353.         {
  2354.             DisplayID = GetVPModeID(&DefaultScreen -> ViewPort);
  2355.  
  2356.             if((DisplayID & MONITOR_ID_MASK) == A2024_MONITOR_ID)
  2357.                 DisplayID = DEFAULT_MONITOR_ID | HIRESLACE_KEY;
  2358.  
  2359.             UnlockPubScreen(NULL,DefaultScreen);
  2360.         }
  2361.         else
  2362.         {
  2363.             if(NewScreen . ViewModes & LACE)
  2364.                 DisplayID = HIRESLACE_KEY;
  2365.             else
  2366.                 DisplayID = HIRES_KEY;
  2367.         }
  2368.  
  2369.         if(QueryOverscan(DisplayID,&DisplayClip,OSCAN_TEXT))
  2370.         {
  2371.             LONG Width = DisplayClip . MaxX - DisplayClip . MinX + 1;
  2372.  
  2373.             if(NewScreen . Width < Width)
  2374.             {
  2375.                 DisplayClip . MinX += (Width - NewScreen . Width) / 2;
  2376.                 DisplayClip . MaxX -= (Width - NewScreen . Width) / 2;
  2377.             }
  2378.  
  2379.             if(!(Screen = (struct Screen *)OpenScreenTags(&NewScreen,
  2380.                 SA_Behind,    TRUE,
  2381.                 SA_Quiet,    TRUE,
  2382.                 SA_ShowTitle,    FALSE,
  2383.                 SA_Depth,    2,
  2384.                 SA_DClip,    &DisplayClip,
  2385.                 SA_DisplayID,    DisplayID,
  2386.                 SA_SysFont,    NewScreen . Font ? 0 : 1,
  2387.             TAG_DONE)))
  2388.                 fatal("Could not open screen");
  2389.         }
  2390.         else
  2391.         {
  2392.             if(!(Screen = (struct Screen *)OpenScreenTags(&NewScreen,
  2393.                 SA_Behind,    TRUE,
  2394.                 SA_Quiet,    TRUE,
  2395.                 SA_ShowTitle,    FALSE,
  2396.                 SA_Depth,    2,
  2397.                 SA_Width,    NewScreen . Width,
  2398.                 SA_Height,    NewScreen . Height,
  2399.                 SA_DisplayID,    DisplayID,
  2400.                 SA_SysFont,    NewScreen . Font ? 0 : 1,
  2401.             TAG_DONE)))
  2402.                 fatal("Could not open screen");
  2403.         }
  2404.     }
  2405.  
  2406. /*    SetRGB4(&Screen -> ViewPort,0,0x0,0x0,0x0);*/
  2407. /*    SetRGB4(&Screen -> ViewPort,1,0xD,0xD,0xD);*/
  2408.  
  2409.         /* Clear new window defition. */
  2410.  
  2411.     memset(&NewWindow,0,sizeof(struct NewWindow));
  2412.  
  2413.         /* Fill in the new window definition. */
  2414.  
  2415.     NewWindow . Width    = Screen -> Width;
  2416.     NewWindow . Height    = Screen -> Height - SCREEN_MARGIN;
  2417.     NewWindow . LeftEdge    = 0;
  2418.     NewWindow . TopEdge    = SCREEN_MARGIN;
  2419.     NewWindow . DetailPen    = 1;
  2420.     NewWindow . BlockPen    = 0;
  2421.     NewWindow . IDCMPFlags    = IDCMP_RAWKEY | IDCMP_NEWSIZE;
  2422.     NewWindow . Flags    = WFLG_RMBTRAP | WFLG_ACTIVATE | WFLG_BORDERLESS | WFLG_BACKDROP;
  2423.     NewWindow . MinWidth    = NewWindow . Width;
  2424.     NewWindow . MinHeight    = NewWindow . Height;
  2425.     NewWindow . MaxWidth    = NewWindow . Width;
  2426.     NewWindow . MaxHeight    = NewWindow . Height;
  2427.     NewWindow . Screen    = Screen;
  2428.     NewWindow . Type    = CUSTOMSCREEN;
  2429.  
  2430.         /* Open the window. */
  2431.  
  2432.     if(!(Window = (struct Window *)OpenWindow(&NewWindow)))
  2433.         fatal("Could not open window");
  2434.  
  2435.     Depth = Window -> WScreen -> RastPort . BitMap -> Depth;
  2436.  
  2437.         /* Create the console write request. */
  2438.  
  2439.     if(!(ConRequest = (struct IOStdReq *)AllocMem(sizeof(struct IOStdReq),MEMF_ANY|MEMF_CLEAR)))
  2440.         fatal("No console request");
  2441.  
  2442.     if(!(InputEventBuffer = (STRPTR)AllocMem(INPUT_LENGTH,MEMF_ANY)))
  2443.         fatal("No input event buffer");
  2444.  
  2445.     if(!(InputEvent = (struct InputEvent *)AllocMem(sizeof(struct InputEvent),MEMF_ANY|MEMF_CLEAR)))
  2446.         fatal("No input event");
  2447.  
  2448.     if(OpenDevice("console.device",CONU_LIBRARY,ConRequest,NULL))
  2449.         fatal("No console.device");
  2450.  
  2451.     ConsoleDevice = ConRequest -> io_Device;
  2452.  
  2453.     WindowWidth = Window -> Width;
  2454.  
  2455.         /* Obtain rastport pointer. */
  2456.  
  2457.     RPort = Window -> RPort;
  2458.  
  2459.         /* Set text rendering mode. */
  2460.  
  2461.     SetAPen(RPort,ConFgPen = 1);
  2462.     SetBPen(RPort,ConBgPen = 0);
  2463.  
  2464.     ConStyle = FS_NORMAL;
  2465.  
  2466.     SetDrMd(RPort,JAM2);
  2467.  
  2468.     PropFont    = Window -> WScreen -> RastPort . Font;
  2469.     FixedFont    = Window -> IFont;
  2470.  
  2471.     if(FixedFont -> tf_YSize != PropFont -> tf_YSize || h_type > 3)
  2472.         PropFont = FixedFont;
  2473.  
  2474.         /* Obtain the system default font dimensions. */
  2475.  
  2476.     TextFontHeight = FixedFont -> tf_YSize;
  2477.  
  2478.     SetFont(RPort,FixedFont);
  2479.  
  2480.         /* Look for the widest glyph. */
  2481.  
  2482.     for(Char = ' ' ; Char <= '~' ; Char++)
  2483.     {
  2484.         if((Width = ConCharWidth(Char)) > TextFontWidth)
  2485.             TextFontWidth = Width;
  2486.  
  2487.         TextFontAverage += Width;
  2488.     }
  2489.  
  2490.     SetFont(RPort,ThisFont = PropFont);
  2491.  
  2492.         /* Look for the widest glyph. */
  2493.  
  2494.     for(Char = ' ' ; Char <= '~' ; Char++)
  2495.     {
  2496.         if((Width = ConCharWidth(Char)) > TextFontWidth)
  2497.             TextFontWidth = Width;
  2498.  
  2499.         TextFontAverage += Width;
  2500.     }
  2501.  
  2502.     TextFontAverage /= (2 * ('~' - ' ' + 1));
  2503.  
  2504.         /* Determine screen dimensions. */
  2505.  
  2506.     if(h_type > 3)
  2507.         screen_cols = Window -> Width / TextFontWidth;
  2508.     else
  2509.         screen_cols = Window -> Width;
  2510.  
  2511.     screen_rows = Window -> Height / TextFontHeight;
  2512.  
  2513.         /* Determine maximum cached line length. */
  2514.  
  2515.     ConLineMaxLength = screen_cols * TextFontWidth;
  2516.  
  2517.         /* Determine minimum number of characters to fit into a single line. */
  2518.  
  2519.     ConLineMinLength = Window -> Width / TextFontWidth;
  2520.  
  2521.         /* Allocate memory for line cache. */
  2522.  
  2523.     if(!(ConLine = (char *)AllocMem(ConLineMaxLength,NULL)))
  2524.         fatal("Not enough memory for line cache");
  2525.  
  2526.         /* Clear the screen and turn off the cursor. */
  2527.  
  2528.     clear_screen();
  2529.  
  2530.         /* Display startup message. */
  2531.  
  2532.     Len = strlen(TheStory);
  2533.  
  2534.     Move(RPort,(Window -> Width - TextLength(RPort,(STRPTR)TheStory,Len)) / 2,(Window -> Height - ThisFont -> tf_YSize) / 2 + ThisFont -> tf_Baseline);
  2535.     Text(RPort,(STRPTR)TheStory,Len);
  2536.  
  2537.     NewWidth = OldWidth = TextFontAverage;
  2538.  
  2539.         /* Start the timer. */
  2540.  
  2541.     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  2542.     TimeRequest -> tr_time . tv_secs    = 0;
  2543.     TimeRequest -> tr_time . tv_micro    = SECOND / 2;
  2544.  
  2545.     BeginIO(TimeRequest);
  2546.  
  2547.         /* Fill in new default window pointer. */
  2548.  
  2549.     ThisProcess -> pr_WindowPtr = (APTR)Window;
  2550.  
  2551.         /* Bring the new screen to the front. */
  2552.  
  2553.     ScreenToFront(Screen);
  2554. }
  2555.  
  2556.     /* restart_screen():
  2557.      *
  2558.      *    Reset the screen status to defaults.
  2559.      */
  2560.  
  2561. VOID
  2562. restart_screen()
  2563. {
  2564.     set_attribute(NORMAL);
  2565.  
  2566.     clear_screen();
  2567. }
  2568.  
  2569.     /* reset_screen():
  2570.      *
  2571.      *    Restore original screen contents, in our case we will have to
  2572.      *    free all the resources allocated by initialize_screen.
  2573.      */
  2574.  
  2575. VOID
  2576. reset_screen()
  2577. {
  2578.         /* Wait for key to be pressed. */
  2579.  
  2580.     if(Window)
  2581.     {
  2582.         ConPrintf("Press any key to exit.");
  2583.  
  2584.         input_character();
  2585.     }
  2586.  
  2587.         /* Free the console request. */
  2588.  
  2589.     if(ConRequest)
  2590.     {
  2591.             /* Did we open the device? If so, close it. */
  2592.  
  2593.         if(ConRequest -> io_Device)
  2594.             CloseDevice(ConRequest);
  2595.  
  2596.             /* Free the memory. */
  2597.  
  2598.         FreeMem(ConRequest,sizeof(struct IOStdReq));
  2599.     }
  2600.  
  2601.         /* Free the input conversion buffer. */
  2602.  
  2603.     if(InputEventBuffer)
  2604.         FreeMem(InputEventBuffer,INPUT_LENGTH);
  2605.  
  2606.         /* Free the fake inputevent. */
  2607.  
  2608.     if(InputEvent)
  2609.         FreeMem(InputEvent,sizeof(struct InputEvent));
  2610.  
  2611.         /* Free timer data. */
  2612.  
  2613.     if(TimeRequest)
  2614.     {
  2615.         if(TimeRequest -> tr_node . io_Device)
  2616.         {
  2617.             if(!CheckIO(TimeRequest))
  2618.                 AbortIO(TimeRequest);
  2619.  
  2620.             WaitIO(TimeRequest);
  2621.  
  2622.             CloseDevice(TimeRequest);
  2623.         }
  2624.  
  2625.         DeleteExtIO(TimeRequest);
  2626.     }
  2627.  
  2628.     if(TimePort)
  2629.         DeletePort(TimePort);
  2630.  
  2631.         /* Free line cache. */
  2632.  
  2633.     if(ConLine)
  2634.         FreeMem(ConLine,ConLineMaxLength);
  2635.  
  2636.         /* Close the window. */
  2637.  
  2638.     if(Window)
  2639.     {
  2640.         ScreenToBack(Screen);
  2641.  
  2642.         CloseWindow(Window);
  2643.     }
  2644.  
  2645.         /* Close the screen. */
  2646.  
  2647.     if(Screen)
  2648.     {
  2649.         ScreenToBack(Screen);
  2650.  
  2651.         CloseScreen(Screen);
  2652.     }
  2653.  
  2654.         /* Close libraries. */
  2655.  
  2656.     if(IconBase)
  2657.         CloseLibrary(IconBase);
  2658.  
  2659.     if(GfxBase)
  2660.         CloseLibrary(GfxBase);
  2661.  
  2662.     if(IntuitionBase)
  2663.         CloseLibrary(IntuitionBase);
  2664.  
  2665.         /* Free sound resources. */
  2666.  
  2667.     SoundExit();
  2668.  
  2669.         /* Restore window pointer. */
  2670.  
  2671.     if(ThisProcess)
  2672.         ThisProcess -> pr_WindowPtr = WindowPtr;
  2673.  
  2674. #ifdef __GNUC__
  2675.  
  2676.     {
  2677.         sigset_t trapped = TRAPPED_SIGNALS;
  2678.  
  2679.         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  2680.     }
  2681.  
  2682. #endif    /* __GNUC__ */
  2683. }
  2684.  
  2685.     /* clear_screen():
  2686.      *
  2687.      *    Clear the entire screen.
  2688.      */
  2689.  
  2690. VOID
  2691. clear_screen()
  2692. {
  2693.         /* Clear character cache. */
  2694.  
  2695.     ConLineLength = 0;
  2696.  
  2697.     if(CursorState)
  2698.     {
  2699.         ConCursorOff();
  2700.  
  2701.         SetAPen(RPort,ConBgPen);
  2702.         RectFill(RPort,0,0,Window -> Width - 1,Window -> Height - 1);
  2703.         SetAPen(RPort,ConFgPen);
  2704.  
  2705.         ConCursorOn(CURSOR_NOCHANGE);
  2706.     }
  2707.     else
  2708.     {
  2709.         SetAPen(RPort,ConBgPen);
  2710.         RectFill(RPort,0,0,Window -> Width - 1,Window -> Height - 1);
  2711.         SetAPen(RPort,ConFgPen);
  2712.     }
  2713.  
  2714.         /* Move to bottom line. */
  2715.  
  2716.     ConSet(0,(screen_rows - 1) * TextFontHeight,CURSOR_NOCHANGE);
  2717. }
  2718.  
  2719.     /* print_status(int argc,char **argv):
  2720.      *
  2721.      *    Print the status line (type 3 games only).
  2722.      *
  2723.      *    argv[0] : Location name
  2724.      *    argv[1] : Moves/Time
  2725.      *    argv[2] : Score
  2726.      *
  2727.      *    Depending on how many arguments are passed to this routine
  2728.      *    it is to print the status line. The rendering attributes
  2729.      *    and the status line window will be have been activated
  2730.      *    when this routine is called. It is to return FALSE if it
  2731.      *    cannot render the status line in which case the interpreter
  2732.      *    will use display_char() to render it on its own.
  2733.      *
  2734.      *    This routine has been provided in order to support
  2735.      *    proportional-spaced fonts.
  2736.      */
  2737.  
  2738. int
  2739. print_status(int argc,char *argv[])
  2740. {
  2741.     STATIC UBYTE    RightBuffer[170];
  2742.  
  2743.     STRPTR        Left,
  2744.             Right;
  2745.     LONG        LeftWidth,
  2746.             RightWidth;
  2747.     WORD        LeftLen,
  2748.             RightLen;
  2749.  
  2750.         /* Are we to change the font? */
  2751.  
  2752.     if(get_word(H_FLAGS) & FIXED_FONT_FLAG)
  2753.     {
  2754.         if(ThisFont != FixedFont)
  2755.             SetFont(RPort,ThisFont = FixedFont);
  2756.     }
  2757.     else
  2758.     {
  2759.         if(ThisFont != PropFont)
  2760.             SetFont(RPort,ThisFont = PropFont);
  2761.     }
  2762.  
  2763.         /* Set up the status bar, we will put both the
  2764.          * score and the moves on the left hand side
  2765.          * if present.
  2766.          */
  2767.  
  2768.     switch(argc)
  2769.     {
  2770.         case 0:    Left    = "";
  2771.             Right    = "";
  2772.             break;
  2773.  
  2774.         case 1:    Left    = argv[0];
  2775.             Right    = "";
  2776.             break;
  2777.  
  2778.         case 2:    Left    = argv[0];
  2779.             Right    = argv[1];
  2780.  
  2781.             break;
  2782.  
  2783.         case 3:    strcpy(RightBuffer,argv[1]);
  2784.             strcat(RightBuffer,"  ");
  2785.             strcat(RightBuffer,argv[2]);
  2786.  
  2787.             Left    = argv[0];
  2788.             Right    = RightBuffer;
  2789.  
  2790.             break;
  2791.     }
  2792.  
  2793.         /* Determine lengths of both strings. */
  2794.  
  2795.     LeftLen        = strlen(Left);
  2796.     RightLen    = strlen(Right);
  2797.  
  2798.         /* Determine pixel widths of both strings. */
  2799.  
  2800.     LeftWidth    = TextLength(RPort,Left,LeftLen);
  2801.     RightWidth    = TextLength(RPort,Right,RightLen);
  2802.  
  2803.         /* Fill in the space in between. */
  2804.  
  2805.     SetAPen(RPort,ConBgPen);
  2806.     RectFill(RPort,LeftWidth,0,Window -> Width - RightWidth - 1,ThisFont -> tf_YSize - 1);
  2807.     SetAPen(RPort,ConFgPen);
  2808.  
  2809.         /* Print the left hand side text. */
  2810.  
  2811.     Move(RPort,0,ThisFont -> tf_Baseline);
  2812.     Text(RPort,Left,LeftLen);
  2813.  
  2814.         /* Print the right hand side text. */
  2815.  
  2816.     Move(RPort,Window -> Width - RightWidth,ThisFont -> tf_Baseline);
  2817.     Text(RPort,Right,RightLen);
  2818.  
  2819.         /* Return success. */
  2820.  
  2821.     return(TRUE);
  2822. }
  2823.  
  2824.     /* select_status_window():
  2825.      *
  2826.      *    Move the cursor into the status bar area.
  2827.      */
  2828.  
  2829. VOID
  2830. select_status_window()
  2831. {
  2832.     ConFlush();
  2833.  
  2834.     save_cursor_position();
  2835.  
  2836.     ConSet(0,0,CURSOR_NOCHANGE);
  2837.  
  2838.     CurrentWindow = WINDOW_STATUS;
  2839. }
  2840.  
  2841.     /* select_text_window():
  2842.      *
  2843.      *    Move the cursor into the text window area.
  2844.      */
  2845.  
  2846. VOID
  2847. select_text_window()
  2848. {
  2849.     ConFlush();
  2850.  
  2851.     restore_cursor_position();
  2852.  
  2853.     CurrentWindow = WINDOW_TEXT;
  2854. }
  2855.  
  2856.     /* create_status_window():
  2857.      *
  2858.      *    Create the status window (not required by the Amiga
  2859.      *    implementation).
  2860.      */
  2861.  
  2862. VOID
  2863. create_status_window()
  2864. {
  2865. }
  2866.  
  2867.     /* delete_status_window():
  2868.      *
  2869.      *    Delete the status window (not required by the Amiga
  2870.      *    implementation).
  2871.      */
  2872.  
  2873. VOID
  2874. delete_status_window()
  2875. {
  2876. }
  2877.  
  2878.     /* clear_line():
  2879.      *
  2880.      *    Clear the contents of the current cursor line.
  2881.      */
  2882.  
  2883. VOID
  2884. clear_line()
  2885. {
  2886.     ConFlush();
  2887.  
  2888.     ConSet(0,CursorY,CURSOR_NOCHANGE);
  2889.  
  2890.     ConClearEOL();
  2891. }
  2892.  
  2893.     /* clear_text_window():
  2894.      *
  2895.      *    Clear the entire text window, don't touch the status
  2896.      *    bar area.
  2897.      */
  2898.  
  2899. VOID
  2900. clear_text_window()
  2901. {
  2902.     ConFlush();
  2903.  
  2904.     if(CursorState)
  2905.     {
  2906.         ConCursorOff();
  2907.  
  2908.         SetAPen(RPort,ConBgPen);
  2909.         RectFill(RPort,0,status_size * TextFontHeight,Window -> Width - 1,(screen_rows - status_size) * TextFontHeight - 1);
  2910.         SetAPen(RPort,ConFgPen);
  2911.  
  2912.         ConCursorOn(CURSOR_NOCHANGE);
  2913.     }
  2914.     else
  2915.     {
  2916.         SetAPen(RPort,ConBgPen);
  2917.         RectFill(RPort,0,status_size * TextFontHeight,Window -> Width - 1,(screen_rows - status_size) * TextFontHeight - 1);
  2918.         SetAPen(RPort,ConFgPen);
  2919.     }
  2920. }
  2921.  
  2922.     /* clear_status_window():
  2923.      *
  2924.      *    Clear the status bar area.
  2925.      */
  2926.  
  2927. VOID
  2928. clear_status_window()
  2929. {
  2930.     ConFlush();
  2931.  
  2932.     if(CursorState)
  2933.     {
  2934.         ConCursorOff();
  2935.  
  2936.         SetAPen(RPort,ConBgPen);
  2937.         RectFill(RPort,0,0,Window -> Width - 1,status_size * TextFontHeight - 1);
  2938.         SetAPen(RPort,ConFgPen);
  2939.  
  2940.         ConCursorOn(CURSOR_NOCHANGE);
  2941.     }
  2942.     else
  2943.     {
  2944.         SetAPen(RPort,ConBgPen);
  2945.         RectFill(RPort,0,0,Window -> Width - 1,status_size * TextFontHeight - 1);
  2946.         SetAPen(RPort,ConFgPen);
  2947.     }
  2948. }
  2949.  
  2950.     /* save_cursor_position():
  2951.      *
  2952.      *    Save the current cursor position.
  2953.      */
  2954.  
  2955. VOID
  2956. save_cursor_position()
  2957. {
  2958.     if(!SavedCursor)
  2959.     {
  2960.         SavedX        = CursorX;
  2961.         SavedY        = CursorY;
  2962.         SavedCursor    = TRUE;
  2963.     }
  2964. }
  2965.  
  2966.     /* restore_cursor_position():
  2967.      *
  2968.      *    Restore the previously saved cursor position.
  2969.      */
  2970.  
  2971. VOID
  2972. restore_cursor_position()
  2973. {
  2974.     if(SavedCursor)
  2975.     {
  2976.         ConSet(SavedX,SavedY,CURSOR_NOCHANGE);
  2977.  
  2978.         SavedCursor = FALSE;
  2979.     }
  2980. }
  2981.  
  2982.     /* move_cursor(int row,int col):
  2983.      *
  2984.      *    Move the cursor to a given position.
  2985.      */
  2986.  
  2987. VOID
  2988. move_cursor(int row,int col)
  2989. {
  2990.     ConFlush();
  2991.  
  2992.     ConSet((col - 1) * TextFontWidth,(row - 1) * TextFontHeight,CURSOR_NOCHANGE);
  2993. }
  2994.  
  2995.     /* set_attribute(int attribute):
  2996.      *
  2997.      *    Set a text rendering attribute.
  2998.      */
  2999.  
  3000. VOID
  3001. set_attribute(int attribute)
  3002. {
  3003.     UBYTE    FgPen    = ConFgPen,
  3004.         BgPen    = ConBgPen,
  3005.         Style    = ConStyle;
  3006.  
  3007.     ConFlush();
  3008.  
  3009.     switch(attribute)
  3010.     {
  3011.             /* Reversed character/cell colours */
  3012.  
  3013.         case REVERSE:        if(Depth > 1)
  3014.                         BgPen = 3;
  3015.                     else
  3016.                     {
  3017.                         FgPen = 0;
  3018.                         BgPen = 1;
  3019.                     }
  3020.  
  3021.                     break;
  3022.  
  3023.             /* Boldface */
  3024.  
  3025.         case BOLD:        if(Depth > 1)
  3026.                         FgPen = 2;
  3027.                     else
  3028.                         Style = FSF_BOLD;
  3029.  
  3030.                     break;
  3031.  
  3032.             /* Italics */
  3033.  
  3034.         case BLINK:        Style = FSF_ITALIC;
  3035.                     break;
  3036.  
  3037.             /* Underlined */
  3038.  
  3039.         case UNDERSCORE:    Style = FSF_UNDERLINED;
  3040.                     break;
  3041.  
  3042.             /* Default (= Reset) */
  3043.  
  3044.         default:        FgPen = 1;
  3045.                     BgPen = 0;
  3046.                     Style = FS_NORMAL;
  3047.  
  3048.                     break;
  3049.     }
  3050.  
  3051.     if(FgPen != ConFgPen)
  3052.         SetAPen(RPort,ConFgPen = FgPen);
  3053.  
  3054.     if(BgPen != ConBgPen)
  3055.         SetBPen(RPort,ConBgPen = BgPen);
  3056.  
  3057.     if(Style != ConStyle)
  3058.         SetSoftStyle(RPort,ConStyle = Style,AskSoftStyle(RPort));
  3059.  
  3060.         /* Remember current attribute. */
  3061.  
  3062.     CurrentAttribute = attribute;
  3063. }
  3064.  
  3065.     /* fit_line(const char *line,int pos,int max):
  3066.      *
  3067.      *    This routine determines whether a line of text will still fit
  3068.      *    on the screen.
  3069.      *
  3070.      *    line : Line of text to test.
  3071.      *    pos  : Length of text line (in characters).
  3072.      *    max  : Maximum number of characters to fit on the screen.
  3073.      */
  3074.  
  3075. int
  3076. fit_line(const char *line,int pos,int max)
  3077. {
  3078.         /* For type 4 games just compare the current and maximum line width. */
  3079.  
  3080.     if(h_type > 3)
  3081.         return(pos < max);
  3082.     else
  3083.     {
  3084.         if(pos > ConLineMinLength)
  3085.         {
  3086.             if(get_word(H_FLAGS) & FIXED_FONT_FLAG)
  3087.             {
  3088.                 if(ThisFont != FixedFont)
  3089.                 {
  3090.                     ConFlush();
  3091.  
  3092.                     SetFont(RPort,ThisFont = FixedFont);
  3093.                 }
  3094.             }
  3095.             else
  3096.             {
  3097.                 if(ThisFont != PropFont)
  3098.                 {
  3099.                     ConFlush();
  3100.  
  3101.                     SetFont(RPort,ThisFont = PropFont);
  3102.                 }
  3103.             }
  3104.  
  3105.             return(TextLength(RPort,(STRPTR)line,pos) + TextFontWidth < Window -> Width);
  3106.                 }
  3107.         else
  3108.             return(TRUE);
  3109.     }
  3110. }
  3111.  
  3112.     /* display_char(int c):
  3113.      *
  3114.      *    Display a single character (characters are cached in
  3115.      *    order to speed up text display).
  3116.      */
  3117.  
  3118. VOID
  3119. display_char(int c)
  3120. {
  3121.     if(get_word(H_FLAGS) & FIXED_FONT_FLAG)
  3122.     {
  3123.         if(ThisFont != FixedFont)
  3124.         {
  3125.             ConFlush();
  3126.  
  3127.             SetFont(RPort,ThisFont = FixedFont);
  3128.         }
  3129.     }
  3130.     else
  3131.     {
  3132.         if(ThisFont != PropFont)
  3133.         {
  3134.             ConFlush();
  3135.  
  3136.             SetFont(RPort,ThisFont = PropFont);
  3137.         }
  3138.     }
  3139.  
  3140.     if(c >= ' ')
  3141.     {
  3142.             /* Cache the character. */
  3143.  
  3144.         ConLine[ConLineLength] = c;
  3145.  
  3146.             /* If the line cache is full, flush it. */
  3147.  
  3148.         if(ConLineLength++ == ConLineMaxLength)
  3149.             ConFlush();
  3150.     }
  3151.     else
  3152.     {
  3153.         ConFlush();
  3154.  
  3155.         switch(c)
  3156.         {
  3157.             case '\n':    ConSet(0,CursorY + TextFontHeight,CURSOR_NOCHANGE);
  3158.                     break;
  3159.  
  3160.             case '\r':    ConSet(0,CursorY,CURSOR_NOCHANGE);
  3161.                     break;
  3162.  
  3163.             case '\a':    DisplayBeep(Window -> WScreen);
  3164.                     break;
  3165.  
  3166.             default:    break;
  3167.         }
  3168.     }
  3169. }
  3170.  
  3171.     /* fatal(const char *s):
  3172.      *
  3173.      *    Display a fatal error message.
  3174.      */
  3175.  
  3176. VOID
  3177. fatal(const char *s)
  3178. {
  3179.     ConFlush();
  3180.  
  3181.         /* If the console window is available, print the message
  3182.          * into it, else send it to the shell window.
  3183.          */
  3184.  
  3185.     if(Window)
  3186.         ConPrintf("Fatal error: %s",s);
  3187.     else
  3188.     {
  3189.         if(!WBenchMsg)
  3190.             printf("\nFatal error: %s\a\n",s);
  3191.     }
  3192.  
  3193.     reset_screen();
  3194.  
  3195.     exit(RETURN_ERROR);
  3196. }
  3197.  
  3198.     /* input_character():
  3199.      *
  3200.      *    Input a single character.
  3201.      */
  3202.  
  3203. char
  3204. input_character()
  3205. {
  3206.     register UBYTE    Char;
  3207.     register BYTE    Done = FALSE;
  3208.  
  3209.     ConFlush();
  3210.  
  3211.     ConCursorOn(CURSOR_AVERAGE);
  3212.  
  3213.     do
  3214.     {
  3215.         switch(Char = ConGetChar(TRUE))
  3216.         {
  3217.                 /* If it's a suitable character, terminate input. */
  3218.  
  3219.             case '\b':
  3220.             case '\r':    Done = TRUE;
  3221.                     break;
  3222.  
  3223.             default:    if(Char >= 32 && Char < 127)
  3224.                         Done = TRUE;
  3225.  
  3226.                     break;
  3227.         }
  3228.     }
  3229.     while(!Done);
  3230.  
  3231.         /* Turn off the cursor. */
  3232.  
  3233.     ConCursorOff();
  3234.  
  3235.     return((char)Char);
  3236. }
  3237.  
  3238.     /* input_line():
  3239.      *
  3240.      *    Input a single line.
  3241.      */
  3242.  
  3243. VOID
  3244. input_line()
  3245. {
  3246.     STATIC char Prompt[140];
  3247.  
  3248.     if(ConLineLength)
  3249.     {
  3250.         memcpy(Prompt,ConLine,ConLineLength);
  3251.  
  3252.         Prompt[ConLineLength] = 0;
  3253.     }
  3254.     else
  3255.         Prompt[0] = 0;
  3256.  
  3257.     ConFlush();
  3258.  
  3259.         /* Read a line of text, input[0] = maximum length,
  3260.          * input[1] = number of characters read.
  3261.          */
  3262.  
  3263.     input[1] = ConInput(Prompt,&input[2],input[0],TRUE);
  3264.  
  3265.         /* Turn off the cursor. */
  3266.  
  3267.     ConCursorOff();
  3268.  
  3269.     scroll_line();
  3270. }
  3271.  
  3272.     /* scroll_line():
  3273.      *
  3274.      *    Scroll the text area one line up.
  3275.      */
  3276.  
  3277. VOID
  3278. scroll_line()
  3279. {
  3280.     ConFlush();
  3281.  
  3282.     ConScrollUp();
  3283. }
  3284.  
  3285.     /* process_arguments(int argc, char *argv[]):
  3286.      *
  3287.      *    Do any argument preprocessing necessary before the game is
  3288.      *    started. This may include selecting a specific game file or
  3289.      *    setting interface-specific options.
  3290.      */
  3291.  
  3292. void
  3293. process_arguments(int argc, char *argv[])
  3294. {
  3295.     int Len;
  3296.  
  3297.     if(argc > 1)
  3298.     {
  3299.         if(!strcmp(argv[1],"?"))
  3300.         {
  3301.             printf("Usage: %s [Story file name] [Saved game file name]\n",argv[0]);
  3302.  
  3303.             exit(RETURN_WARN);
  3304.         }
  3305.         else
  3306.             StoryName = argv[1];
  3307.  
  3308.         if(argc > 2)
  3309.             restore_name = argv[2];
  3310.     }
  3311.     else
  3312.         StoryName = "Story.Data";
  3313.  
  3314.     if(argc)
  3315.         InterpreterName = argv[0];
  3316.     else
  3317.     {
  3318.         WBenchMsg = (struct WBStartup *)argv;
  3319.  
  3320.         InterpreterName = WBenchMsg -> sm_ArgList[0] . wa_Name;
  3321.  
  3322.         if(IconBase = OpenLibrary("icon.library",LIB_VERSION))
  3323.         {
  3324.             struct DiskObject *Icon;
  3325.  
  3326.             if(Icon = GetDiskObject(InterpreterName))
  3327.             {
  3328.                 char     Buffer[5],
  3329.                     *Type;
  3330.                 int     i;
  3331.  
  3332.                     /* Does it have a filetype info attached? */
  3333.  
  3334.                 if(Type = FindToolType((STRPTR *)Icon -> do_ToolTypes,"STORY"))
  3335.                 {
  3336.                     if(StoryName = (STRPTR)malloc(strlen(Type) + 1))
  3337.                         strcpy(StoryName,Type);
  3338.                     else
  3339.                         StoryName = "Story.Data";
  3340.                 }
  3341.  
  3342.                     /* Check for function key
  3343.                      * defintions and set them
  3344.                      * if approriate.
  3345.                      */
  3346.  
  3347.                 for(i = 0 ; i < NUM_FKEYS ; i++)
  3348.                 {
  3349.                         /* Build fkey string. */
  3350.  
  3351.                     sprintf(Buffer,"F0%2d",i + 1);
  3352.  
  3353.                         /* See if we can find it. */
  3354.  
  3355.                     if(Type = FindToolType((STRPTR *)Icon -> do_ToolTypes,Buffer))
  3356.                         ConSetKey(i,Type,strlen(Type));
  3357.                     else
  3358.                         ConSetKey(i,"",0);
  3359.                 }
  3360.  
  3361.                     /* Free the icon. */
  3362.  
  3363.                 FreeDiskObject(Icon);
  3364.             }
  3365.  
  3366.             if(WBenchMsg -> sm_NumArgs > 1)
  3367.             {
  3368.                 char    *Type;
  3369.                 int     i;
  3370.  
  3371.                 for(i = 0 ; i < WBenchMsg -> sm_NumArgs ; i++)
  3372.                 {
  3373.                     CurrentDir(WBenchMsg -> sm_ArgList[i] . wa_Lock);
  3374.  
  3375.                     if(Icon = GetDiskObject(WBenchMsg -> sm_ArgList[i] . wa_Name))
  3376.                     {
  3377.                         /* Does it have a filetype info attached? */
  3378.  
  3379.                         if(Type = FindToolType((STRPTR *)Icon -> do_ToolTypes,"FILETYPE"))
  3380.                         {
  3381.                             /* Is it a bookmark file? */
  3382.  
  3383.                             if(MatchToolValue(Type,"BOOKMARK") && MatchToolValue(Type,"ZIP"))
  3384.                             {
  3385.                                 restore_name = WBenchMsg -> sm_ArgList[i] . wa_Name;
  3386.  
  3387.                                 if(Type = FindToolType((STRPTR *)Icon -> do_ToolTypes,"STORY"))
  3388.                                 {
  3389.                                     BPTR File;
  3390.  
  3391.                                         /* Try to open the file, this is
  3392.                                          * easier than locking it, allocating
  3393.                                          * a fileinfo, reading it and then
  3394.                                          * to clean up again.
  3395.                                          */
  3396.  
  3397.                                     if(File = Open(Type,MODE_OLDFILE))
  3398.                                     {
  3399.                                         char *NewName;
  3400.  
  3401.                                         Close(File);
  3402.  
  3403.                                         if(NewName = (STRPTR)malloc(strlen(Type) + 1))
  3404.                                         {
  3405.                                             strcpy(NewName,Type);
  3406.  
  3407.                                             StoryName = NewName;
  3408.                                         }
  3409.                                     }
  3410.                                 }
  3411.  
  3412.                                 FreeDiskObject(Icon);
  3413.                                 break;
  3414.                             }
  3415.  
  3416.                             if(MatchToolValue(Type,"STORY"))
  3417.                             {
  3418.                                 BPTR File;
  3419.  
  3420.                                     /* Try to open the file, this is
  3421.                                      * easier than locking it, allocating
  3422.                                      * a fileinfo, reading it and then
  3423.                                      * to clean up again.
  3424.                                      */
  3425.  
  3426.                                 if(File = Open(WBenchMsg -> sm_ArgList[i] . wa_Name,MODE_OLDFILE))
  3427.                                 {
  3428.                                     char *NewName;
  3429.  
  3430.                                     Close(File);
  3431.  
  3432.                                     if(NewName = (STRPTR)malloc(strlen(WBenchMsg -> sm_ArgList[i] . wa_Name) + 1))
  3433.                                     {
  3434.                                         strcpy(NewName,WBenchMsg -> sm_ArgList[i] . wa_Name);
  3435.  
  3436.                                         StoryName = NewName;
  3437.                                     }
  3438.                                 }
  3439.  
  3440.                                 FreeDiskObject(Icon);
  3441.                                 break;
  3442.                             }
  3443.                         }
  3444.  
  3445.                             /* Free the icon. */
  3446.  
  3447.                         FreeDiskObject(Icon);
  3448.                     }
  3449.                 }
  3450.             }
  3451.  
  3452.             CloseLibrary(IconBase);
  3453.  
  3454.             IconBase = NULL;
  3455.         }
  3456.     }
  3457.  
  3458.     open_story(StoryName);
  3459.  
  3460.     Len = strlen(StoryName);
  3461.  
  3462.         /* Make a copy of the game name. */
  3463.  
  3464.     if(SoundName = malloc(Len + 40))
  3465.     {
  3466.         strcpy(SoundName,StoryName);
  3467.  
  3468.             /* Does the sound file name have any
  3469.              * length, i.e. is it a real name?
  3470.              */
  3471.  
  3472.         if(Len)
  3473.         {
  3474.             int i;
  3475.  
  3476.                 /* Starting from the end of the
  3477.                  * file name look for the first
  3478.                  * path character.
  3479.                  */
  3480.  
  3481.             for(i = Len - 1 ; i >= 0 ; i--)
  3482.             {
  3483.                     /* Is it a path name seperation
  3484.                      * character?
  3485.                      */
  3486.  
  3487.                 if(SoundName[i] == '/' || SoundName[i] == ':')
  3488.                 {
  3489.                         /* Append the sound directory
  3490.                          * name to the string.
  3491.                          */
  3492.  
  3493.                     SoundPath = &SoundName[i + 1];
  3494.  
  3495.                         /* We're finished. */
  3496.  
  3497.                     break;
  3498.                 }
  3499.             }
  3500.         }
  3501.  
  3502.             /* If no proper subdirectory name was
  3503.              * to be found, override the entire
  3504.              * string.
  3505.              */
  3506.  
  3507.         if(!SoundPath)
  3508.             SoundPath = SoundName;
  3509.     }
  3510. }
  3511.  
  3512.     /* file_cleanup(const char *file_name, int flag):
  3513.      *
  3514.      *    Perform certain actions after a game file is saved (flag = 1)
  3515.      *    or restored (flag = 0).
  3516.      */
  3517.  
  3518. void
  3519. file_cleanup(const char *file_name, int flag)
  3520. {
  3521.         /* Was the file saved or restored? */
  3522.  
  3523.     if(flag == GAME_SAVE)
  3524.     {
  3525.             /* Clear the `executable' bit. */
  3526.  
  3527.         SetProtection((char *)file_name,FIBF_EXECUTE);
  3528.  
  3529.         if(IconBase)
  3530.         {
  3531.             struct DiskObject *Icon;
  3532.  
  3533.                 /* Get the default icon. */
  3534.  
  3535.             if(Icon = GetDiskObject("Icon.Data"))
  3536.             {
  3537.                 char **ToolTypes;
  3538.  
  3539.                     /* Create the tool type array. */
  3540.  
  3541.                 if(ToolTypes = (char **)malloc(sizeof(char *) * (NUM_FKEYS + 3)))
  3542.                 {
  3543.                     int i,j = 0;
  3544.  
  3545.                         /* Fill in the file type. */
  3546.  
  3547.                     ToolTypes[j++] = "FILETYPE=BOOKMARK|ZIP";
  3548.  
  3549.                         /* Add the story file name. */
  3550.  
  3551.                     if(ToolTypes[j] = malloc(strlen(StoryName) + 7))
  3552.                         sprintf(ToolTypes[j++],"STORY=%s",StoryName);
  3553.  
  3554.                         /* Add the function key definitions if any. */
  3555.  
  3556.                     for(i = 0 ; i < NUM_FKEYS ; i++)
  3557.                     {
  3558.                         if(FunctionKeys[i] . Len)
  3559.                         {
  3560.                             if(ToolTypes[j] = malloc(FunctionKeys[i] . Len + 5))
  3561.                                 sprintf(ToolTypes[j++],"F%02d=%s",i + 1,FunctionKeys[i] . Buffer);
  3562.                         }
  3563.                     }
  3564.  
  3565.                         /* Terminat the tool type array. */
  3566.  
  3567.                     ToolTypes[j] = NULL;
  3568.  
  3569.                         /* Fill in the icon data. */
  3570.  
  3571.                     Icon -> do_DefaultTool    = InterpreterName;
  3572.                     Icon -> do_ToolTypes    = ToolTypes;
  3573.                     Icon -> do_StackSize    = ThisProcess -> pr_StackSize;
  3574.                     Icon -> do_CurrentX    = NO_ICON_POSITION;
  3575.                     Icon -> do_CurrentY    = NO_ICON_POSITION;
  3576.  
  3577.                         /* Create the icon. */
  3578.  
  3579.                     if(!PutDiskObject((char *)file_name,Icon))
  3580.                         output_stringnl("[Error creating icon file]");
  3581.  
  3582.                         /* Free the tool type entries. */
  3583.  
  3584.                     for(i = 1 ; i < j ; i++)
  3585.                         free(ToolTypes[i]);
  3586.  
  3587.                         /* Free the tool type array. */
  3588.  
  3589.                     free(ToolTypes);
  3590.                 }
  3591.  
  3592.                     /* Free the icon. */
  3593.  
  3594.                 FreeDiskObject(Icon);
  3595.             }
  3596.             else
  3597.                 output_stringnl("[No icon]");
  3598.         }
  3599.         else
  3600.             output_stringnl("[No icon]");
  3601.     }
  3602.  
  3603.     if(flag == GAME_RESTORE)
  3604.     {
  3605.         if(IconBase)
  3606.         {
  3607.             struct DiskObject *Icon;
  3608.  
  3609.                 /* Get the file icon. */
  3610.  
  3611.             if(Icon = GetDiskObject((char *)file_name))
  3612.             {
  3613.                 char     Buffer[5],
  3614.                     *Type;
  3615.                 int     i;
  3616.  
  3617.                     /* Does it have a filetype info attached? */
  3618.  
  3619.                 if(Type = FindToolType((STRPTR *)Icon -> do_ToolTypes,"FILETYPE"))
  3620.                 {
  3621.                         /* Is it a bookmark file? */
  3622.  
  3623.                     if(MatchToolValue(Type,"BOOKMARK") && MatchToolValue(Type,"ZIP"))
  3624.                     {
  3625.                             /* Check for function key
  3626.                              * defintions and set them
  3627.                              * if approriate.
  3628.                              */
  3629.  
  3630.                         for(i = 0 ; i < NUM_FKEYS ; i++)
  3631.                         {
  3632.                                 /* Build fkey string. */
  3633.  
  3634.                             sprintf(Buffer,"F%02d",i + 1);
  3635.  
  3636.                                 /* See if we can find it. */
  3637.  
  3638.                             if(Type = FindToolType((STRPTR *)Icon -> do_ToolTypes,Buffer))
  3639.                                 ConSetKey(i,Type,strlen(Type));
  3640.                             else
  3641.                                 ConSetKey(i,"",0);
  3642.                         }
  3643.                     }
  3644.                 }
  3645.  
  3646.                     /* Free the icon. */
  3647.  
  3648.                 FreeDiskObject(Icon);
  3649.             }
  3650.             else
  3651.                 output_stringnl("[No icon]");
  3652.         }
  3653.         else
  3654.             output_stringnl("[No icon]");
  3655.     }
  3656. }
  3657.  
  3658.     /* sound(int argc, zword_t * argv):
  3659.      *
  3660.      *    Replay a sound file or just a bell (^G) signal:
  3661.      *
  3662.      *    argc = 1: Play bell signal.
  3663.      *
  3664.      *    argc = 2: argv[0] = 0
  3665.      *              argv[1] = 3
  3666.      *
  3667.      *              Stop playing current sound.
  3668.      *
  3669.      *    argc = 2: argv[0] = 0
  3670.      *              argv[1] = 4
  3671.      *
  3672.      *              Free allocated resources.
  3673.      *
  3674.      *    argc = 3: argv[0] = ID# of sound file to replay.
  3675.      *              argv[1] = 2
  3676.      *              argv[2] = Volume to replay sound with, this value
  3677.      *                        can range between 1 and 8.
  3678.      */
  3679.  
  3680. void
  3681. sound(int argc, zword_t * argv)
  3682. {
  3683.     if(argc == 1)
  3684.     {
  3685.         int Count = argv[0];
  3686.  
  3687.         while(Count--)
  3688.         {
  3689.             DisplayBeep(Window -> WScreen);
  3690.  
  3691.             if(Count)
  3692.                 Delay(TICKS_PER_SECOND / 2);
  3693.         }
  3694.     }
  3695.     else
  3696.     {
  3697.             /* Is the sound name buffer available? */
  3698.  
  3699.         if(SoundName)
  3700.         {
  3701.             register BOOL GotSound;
  3702.  
  3703.                 /* What are we to do next? */
  3704.  
  3705.             switch(argv[1])
  3706.             {
  3707.                     /* If a new sound is to be replayed, stop
  3708.                      * the current sound.
  3709.                      */
  3710.  
  3711.                 case 2:    if(argv[0] != SoundNumber && SoundNumber != -1 && SoundControlRequest)
  3712.                     {
  3713.                         SoundAbort();
  3714.  
  3715.                             /* Free previously allocated sound data. */
  3716.  
  3717.                         if(SoundData && SoundLength)
  3718.                         {
  3719.                                 /* Free it. */
  3720.  
  3721.                             FreeMem(SoundData,SoundLength);
  3722.  
  3723.                                 /* Leave no traces. */
  3724.  
  3725.                             SoundData    = NULL;
  3726.                             SoundLength    = 0;
  3727.                         }
  3728.  
  3729.                         SoundNumber = -1;
  3730.                     }
  3731.  
  3732.                         /* Make sure that we have the resources we need,
  3733.                          * either allocate them or rely on the fact that
  3734.                          * the previous call to this routine had already
  3735.                          * triggered the allocation.
  3736.                          */
  3737.  
  3738.                     if(!SoundControlRequest)
  3739.                         GotSound = SoundInit();
  3740.                     else
  3741.                         GotSound = TRUE;
  3742.  
  3743.                         /* Do we have the resources or not? */
  3744.  
  3745.                     if(GotSound)
  3746.                     {
  3747.                             /* If we are to replay the same sound as we
  3748.                              * did before, we are probably to change the
  3749.                              * replay volume.
  3750.                              */
  3751.  
  3752.                         if(SoundNumber == argv[0] && SoundNumber != -1)
  3753.                         {
  3754.                                 /* Is the sound still playing? If so,
  3755.                                  * change the volume, else restart
  3756.                                  * it with the new volume.
  3757.                                  */
  3758.  
  3759.                             if(!CheckIO((struct IORequest *)SoundRequestLeft))
  3760.                             {
  3761.                                     /* Set up new volume. */
  3762.  
  3763.                                 SoundControlRequest -> ioa_Request . io_Command    = ADCMD_PERVOL;
  3764.                                 SoundControlRequest -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  3765.                                 SoundControlRequest -> ioa_Volume        = argv[2] * 8;
  3766.  
  3767.                                     /* Tell the device to make the change. */
  3768.  
  3769.                                 SendIO((struct IORequest *)SoundControlRequest);
  3770.                                 WaitIO((struct IORequest *)SoundControlRequest);
  3771.                             }
  3772.                             else
  3773.                             {
  3774.                                     /* Wait for requests to return. */
  3775.  
  3776.                                 SoundAbort();
  3777.  
  3778.                                     /* Set up new volume. */
  3779.  
  3780.                                 SoundRequestLeft  -> ioa_Volume = argv[2] * 8;
  3781.                                 SoundRequestRight -> ioa_Volume = argv[2] * 8;
  3782.  
  3783.                                     /* Stop the sound. */
  3784.  
  3785.                                 SoundStop();
  3786.  
  3787.                                     /* Queue the sound. */
  3788.  
  3789.                                 BeginIO((struct IORequest *)SoundRequestLeft);
  3790.                                 BeginIO((struct IORequest *)SoundRequestRight);
  3791.  
  3792.                                     /* Start the sound. */
  3793.  
  3794.                                 SoundStart();
  3795.                             }
  3796.                         }
  3797.                         else
  3798.                         {
  3799.                                 /* The sound file header. */
  3800.  
  3801.                             struct
  3802.                             {
  3803.                                 UBYTE    Reserved1[2];
  3804.                                 BYTE    Times;        /* How many times to play (0 = continuously). */
  3805.                                 UBYTE    Rate[2];    /* Replay rate (note: little endian). */
  3806.                                 UBYTE    Reserved2[3];
  3807.                                 UWORD    PlayLength;    /* Length of sound to replay. */
  3808.                             } SoundHeader;
  3809.  
  3810.                                 /* Sound file handle and name buffer. */
  3811.  
  3812.                             FILE *SoundFile;
  3813.  
  3814.                                 /* Cancel the argv[0] of the previously loaded
  3815.                                  * sound in case the load fails.
  3816.                                  */
  3817.  
  3818.                             SoundNumber = -1;
  3819.  
  3820.                                 /* Set up the sound file name. */
  3821.  
  3822.                             sprintf(SoundPath,"sound/s%d.dat",argv[0]);
  3823.  
  3824.                                 /* Open the file for reading. */
  3825.  
  3826.                             if(SoundFile = fopen(SoundName,"rb"))
  3827.                             {
  3828.                                     /* Read the file header. */
  3829.  
  3830.                                 if(fread(&SoundHeader,sizeof(SoundHeader),1,SoundFile) == 1)
  3831.                                 {
  3832.                                         /* Remember the sound file length. */
  3833.  
  3834.                                     SoundLength = SoundHeader . PlayLength;
  3835.  
  3836.                                         /* Allocate chip ram for the sound data. */
  3837.  
  3838.                                     if(SoundData = (APTR)AllocMem(SoundLength,MEMF_CHIP))
  3839.                                     {
  3840.                                             /* Read the sound data. */
  3841.  
  3842.                                         if(fread(SoundData,SoundLength,1,SoundFile) == 1)
  3843.                                         {
  3844.                                                 /* Turn the replay rate into a
  3845.                                                  * sensible argv[0].
  3846.                                                  */
  3847.  
  3848.                                             ULONG Rate = (GfxBase -> DisplayFlags & PAL ? 3546895 : 3579545) / ((((UWORD)SoundHeader . Rate[1]) << 8) | SoundHeader . Rate[0]);
  3849.  
  3850.                                                 /* Set up the left channel. */
  3851.  
  3852.                                             SoundRequestLeft -> ioa_Request . io_Command    = CMD_WRITE;
  3853.                                             SoundRequestLeft -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  3854.                                             SoundRequestLeft -> ioa_Period            = Rate;
  3855.                                             SoundRequestLeft -> ioa_Volume            = argv[2] * 8;
  3856.                                             SoundRequestLeft -> ioa_Cycles            = SoundHeader . Times;
  3857.                                             SoundRequestLeft -> ioa_Data            = SoundData;
  3858.                                             SoundRequestLeft -> ioa_Length            = SoundLength;
  3859.  
  3860.                                                 /* Set up the right channel. */
  3861.  
  3862.                                             SoundRequestRight -> ioa_Request . io_Command    = CMD_WRITE;
  3863.                                             SoundRequestRight -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  3864.                                             SoundRequestRight -> ioa_Period            = Rate;
  3865.                                             SoundRequestRight -> ioa_Volume            = argv[2] * 8;
  3866.                                             SoundRequestRight -> ioa_Cycles            = SoundHeader . Times;
  3867.                                             SoundRequestRight -> ioa_Data            = SoundData;
  3868.                                             SoundRequestRight -> ioa_Length            = SoundLength;
  3869.  
  3870.                                                 /* Set up the control request. */
  3871.  
  3872.                                             SoundControlRequest -> ioa_Period        = Rate;
  3873.  
  3874.                                                 /* Stop playing any sound. */
  3875.  
  3876.                                             SoundStop();
  3877.  
  3878.                                                 /* Queue the sound. */
  3879.  
  3880.                                             BeginIO((struct IORequest *)SoundRequestLeft);
  3881.                                             BeginIO((struct IORequest *)SoundRequestRight);
  3882.  
  3883.                                                 /* Play the sound. */
  3884.  
  3885.                                             SoundStart();
  3886.  
  3887.                                                 /* Remember the argv[0] of the current sound. */
  3888.  
  3889.                                             SoundNumber = argv[0];
  3890.                                         }
  3891.                                         else
  3892.                                         {
  3893.                                                 /* The load failed, free the audio memory. */
  3894.  
  3895.                                             FreeMem(SoundData,SoundLength);
  3896.  
  3897.                                                 /* Leave no traces. */
  3898.  
  3899.                                             SoundData    = NULL;
  3900.                                             SoundLength    = 0;
  3901.                                         }
  3902.                                     }
  3903.                                 }
  3904.  
  3905.                                     /* Close the sound file. */
  3906.  
  3907.                                 fclose(SoundFile);
  3908.                             }
  3909.                         }
  3910.                     }
  3911.  
  3912.                     break;
  3913.  
  3914.                     /* Free resources. */
  3915.  
  3916.                 case 3:    SoundExit();
  3917.  
  3918.                     break;
  3919.             }
  3920.         }
  3921.     }
  3922. }
  3923.  
  3924.     /* get_file_name(char *file_name, char *default_name, int flag):
  3925.      *
  3926.      *    Return the name of a file. Flag can be one of: GAME_SAVE, GAME_RESTORE or
  3927.      *    GAME_SCRIPT.
  3928.      */
  3929.  
  3930. int
  3931. get_file_name(char *file_name, char *default_name, int flag)
  3932. {
  3933.     int     saved_scripting_disable = scripting_disable,
  3934.          columns = (screen_cols > 127) ? 127 : screen_cols,
  3935.          status = TRUE;
  3936.     FILE    *tfp;
  3937.     char     c;
  3938.  
  3939.     if(!default_name[0])
  3940.     {
  3941.         if(flag == GAME_SCRIPT)
  3942.             strcpy(default_name,"PRT:");
  3943.         else
  3944.             strcpy(default_name,"Story.Save");
  3945.     }
  3946.  
  3947.     scripting_disable = ON;
  3948.  
  3949.     output_stringnl("Enter a file name.");
  3950.     output_string("(Default is \"");
  3951.     output_string(default_name);
  3952.     output_string("\") >");
  3953.  
  3954.     input[0] = (char) (columns - RIGHT_MARGIN - 1 - sizeof("(Default is \"") - strlen(default_name) - sizeof("\"): "));
  3955.  
  3956.     input_line();
  3957.  
  3958.     if(input[1])
  3959.     {
  3960.         input[input[1] + 2] = '\0';
  3961.  
  3962.         strcpy(file_name, &input[2]);
  3963.     }
  3964.     else
  3965.         strcpy(file_name, default_name);
  3966.  
  3967.     if(flag)
  3968.     {
  3969.         if(tfp = fopen(file_name,"r"))
  3970.         {
  3971.             fclose(tfp);
  3972.  
  3973.             output_string("You are about to write over an existing file.  Proceed? (Y/N) >");
  3974.  
  3975.             do
  3976.                 c = input_character();
  3977.             while(toupper(c) != 'Y' && toupper(c) != 'N');
  3978.  
  3979.             display_char(c);
  3980.  
  3981.             scroll_line();
  3982.  
  3983.             if(c == 'N')
  3984.                 status = FALSE;
  3985.         }
  3986.     }
  3987.  
  3988.     scripting_disable = saved_scripting_disable;
  3989.  
  3990.     return(status);
  3991. }
  3992.