home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d9xx / d902 / less.lha / Less / Source / source.lha / io.c < prev    next >
C/C++ Source or Header  |  1993-02-21  |  15KB  |  555 lines

  1. /*  io.c */
  2.  
  3. /* All of the code in this file is Amiga-specific */
  4.  
  5. #include "less.h"
  6.  
  7. #include <ctype.h>
  8. #include <string.h>
  9. #include <intuition/intuition.h>
  10. #include <dos.h>
  11. #include <devices/conunit.h>
  12.  
  13. #include <intuition/intuitionbase.h>
  14. extern struct IntuitionBase *IntuitionBase;
  15. extern int sigs;
  16.  
  17. static struct FileHandle *ttyHandle;
  18. static struct MsgPort *ttyPort; /* Port to send DOS Packets to */
  19. static struct MsgPort *RdReplyPort; /* When a tty read completes */
  20. static BPTR ConsoleHandle = 0;
  21. static struct StandardPacket *RdPacket = NULL; /* Packet for read requests */
  22. static struct ConUnit *conUnit; /* For resizing information */
  23.  
  24. public BOOL UseCLI = FALSE;    /* Has user requested we use CLI window? */
  25.  
  26. public int     nrow = 0;         /* Terminal size, rows.         */
  27. public int     ncol;             /* Terminal size, columns.      */
  28.  
  29.  
  30. /* Following function is required by MySprintf */
  31. extern __asm void stuffChar
  32.     ( register __d0 char c, register __a3 char *SPFbuffer );
  33.  
  34. int Wind_Spec[4] = { 0, 0, 0, 0 };
  35. /* User-supplied option specifying window size/position:
  36.  *
  37.  * [0]: Left edge X - coord.
  38.  * [1]: Top edge Y - coord.
  39.  * [2]: Right edge X - coord.
  40.  * [3]: Bottom edge Y - coord.
  41.  *
  42.  * If element 2 or 3 is negative, it is taken to be a relative value to be
  43.  * subtracted from the maximum screen size.  If the resulting window
  44.  * would be smaller than the minimum, it is quietly enlarged to the
  45.  * minimum, by expanding to the lower right as far as possible, and then
  46.  * moving the window toward the upper left if necessary.
  47.  */
  48. #define W_MINWIDTH 200
  49. #define W_MINHEIGHT 60
  50.  
  51. /* Prototypes for functions defined in io.c */
  52.  
  53. static void StartConRead __PROTO((void));
  54. static int ConGetC __PROTO((void));
  55. static int ConLookC __PROTO((void));
  56. static void ConWrite __PROTO((char *data, int length));
  57. static LONG findWindow ( void );
  58. static void MySendPkt __PROTO((struct StandardPacket *pkt, struct MsgPort *RPort,
  59.     long action, long PktArg[], long Nargs));
  60. static LONG MyDoPkt __PROTO(( long action, long PktArg[], long Nargs ));
  61.  
  62.  
  63. #include <exec/memory.h>
  64.  
  65. extern struct GfxBase *GfxBase;
  66. extern struct MsgPort *CreatePort();
  67.  
  68. static char buffer; /* buffer for incoming console character */
  69.  
  70. /* asynchronous console read request--must be called once before
  71.    any ConGetC requests
  72. */
  73.  
  74. static void StartConRead ( void )
  75. {
  76.     LONG PktArg[3];
  77.  
  78.     PktArg[0] = (LONG)(ttyHandle->fh_Arg1);
  79.     PktArg[1] = (LONG)&buffer;
  80.     PktArg[2] = 1;
  81.     /* asynchronous posting of a read request */
  82.     MySendPkt( RdPacket, RdReplyPort, ACTION_READ, PktArg, 3 );
  83. }
  84.  
  85. /* Get a character from the console.
  86. */
  87. static int ConGetC ()
  88. {
  89.     struct MsgPort *mp;
  90.     struct StandardPacket *rddata;
  91.     int temp;
  92.     ULONG ReadMsgBit, MsgBits;
  93.  
  94.     mp = RdReplyPort;    /* get the read reply port */
  95.     ReadMsgBit = 1 << mp->mp_SigBit;
  96.     rddata = NULL;
  97.     do /* Wait for a character or ^C */
  98.     {
  99.         MsgBits = Wait(ReadMsgBit | SIGBREAKF_CTRL_C);
  100.         if ( MsgBits & ReadMsgBit )
  101.             rddata = (struct StandardPacket *) GetMsg ( mp );
  102.         else if ( MsgBits & SIGBREAKF_CTRL_C )
  103.         {
  104.             quit();
  105.         }
  106.     } while ( !rddata );
  107.  
  108.     /* We've got a character... */
  109.     temp = buffer;   /* get the character */
  110.     StartConRead ( ); /* set up next read */
  111.     return temp;
  112. }
  113.  
  114. /* See if a character is available at the console.
  115.    If so, get it, else return -1.
  116. */
  117. static int ConLookC ( void )
  118. {
  119.     struct MsgPort *mp;
  120.     struct StandardPacket *rddata;
  121.     int temp;
  122.  
  123.     mp = RdReplyPort;    /* get the read reply port */
  124.     rddata = (struct StandardPacket *) GetMsg ( mp );
  125.     if ( !rddata ) return -1;
  126.  
  127.     /* We've got a character... */
  128.     temp = buffer;   /* get the character */
  129.     StartConRead ( ); /* set up next read */
  130.     return temp;
  131. }
  132.  
  133. /* write a specified number of characters from a buffer to console device
  134. */
  135. static void ConWrite ( char *data, int length )
  136. {
  137.     Write ( ConsoleHandle, data, length );
  138. }
  139.  
  140.  
  141. /*
  142.  * This routine gets called once, to set up the
  143.  * terminal channel.
  144.  *
  145.  * See The AmigaDOS Manual for details of how to derive parameters
  146.  * from an AmigaDOS filehandle and for doing console packet IO.
  147.  * The sample code on Fish Disk 56 is also instructive.
  148.  */
  149. void ttopen (void)
  150. {
  151.         int left, top, width, height;   /* window specification */
  152.         struct Screen *wbsdata;
  153.         long PktArg[1];
  154.         static char LessWindowSpec[132];
  155.  
  156.         if ( ConsoleHandle ) return;
  157.  
  158.         /* Under AmigaDos 1.3, one can't seem to open * with MODE_READWRITE */
  159.         if ( !called_from_WB && UseCLI )
  160.             ConsoleHandle = Open ( "*", MODE_OLDFILE );
  161.         if ( ConsoleHandle == 0 )
  162.         {
  163.             wbsdata = MyFindWB();
  164.             if ( (left = Wind_Spec[0]) < 0 ) left += wbsdata->Width;
  165.             if ( left < 0 ) left = 0;
  166.             if ( left > wbsdata->Width )
  167.                 left = wbsdata->Width - W_MINWIDTH;
  168.             if ( (top = Wind_Spec[1]) < 0 ) top += wbsdata->Height;
  169.             if ( top < 0 ) top = 0;
  170.             if ( top > wbsdata->Height )
  171.                 top = wbsdata->Height - W_MINHEIGHT;
  172.  
  173.             width = Wind_Spec[2];
  174.             if ( width <= 0 )
  175.                 width += wbsdata->Width;
  176.             if ( width <= 0 )
  177.                 width = 0;
  178.             height = Wind_Spec[3];
  179.             if ( height <= 0 )
  180.                 height += wbsdata->Height;
  181.             if ( height <= 0 )
  182.                 height = 0;
  183.  
  184.             if ( width < W_MINWIDTH )
  185.                 width = W_MINWIDTH;
  186.             if ( height < W_MINHEIGHT )
  187.                 height = W_MINHEIGHT;
  188.  
  189.             if ( left + width > wbsdata->Width )
  190.                 width = wbsdata->Width - left;
  191.             if ( top + height > wbsdata->Height )
  192.                 height = wbsdata->Height - top;
  193.             if ( width < W_MINWIDTH )
  194.                 left = wbsdata->Width - W_MINWIDTH;
  195.             if ( height < W_MINHEIGHT )
  196.                 top = wbsdata->Height - W_MINHEIGHT;
  197.             if ( left < 0 || top < 0 )
  198.             {
  199.                 MyFreeWB( wbsdata );
  200.                 error ( "Window won't fit on screen" );
  201.                 quit();
  202.             }
  203.  
  204.             MyFreeWB(wbsdata);
  205.             MySprintf ( LessWindowSpec,
  206.                 "CON:%ld/%ld/%ld/%ld/%s: h for help", left, top,
  207.                 width, height, Ver );
  208.             if ( IsV2 ) strcat ( LessWindowSpec, "/CLOSE" );
  209.             ConsoleHandle = Open ( LessWindowSpec, MODE_OLDFILE );
  210.         }
  211.  
  212.         if ( ConsoleHandle == 0 )
  213.         {
  214.             PrintFault ( IoErr(), "Can't open Less window" );
  215.             quit();
  216.         }
  217.         ttyHandle = (struct FileHandle *)(BADDR(ConsoleHandle));
  218.         ttyPort = ttyHandle->fh_Type;
  219.         if ( !ttyPort )
  220.         {
  221.             error ( "NULL ttyPort" );
  222.             quit();
  223.         }
  224.         RdReplyPort = CreatePort ( NULL, 0 );
  225.         RdPacket = (struct StandardPacket *)
  226.             AllocMem ( sizeof(struct StandardPacket), MEMF_PUBLIC | MEMF_CLEAR );
  227.         if ( !RdReplyPort || !RdPacket )
  228.         {
  229.             error ( "Out of Memory" );
  230.             quit();
  231.         }
  232.         findWindow();
  233.  
  234.         StartConRead ( );
  235.         /* enable report of window resizeing and close gadget */
  236.         PktArg[0] = 1;    /* set raw mode */
  237.         if ( ! MyDoPkt ( ACTION_SCREEN_MODE, PktArg, 1 ) )
  238.         {
  239.             error ( "Can't set raw mode" );
  240.             quit();
  241.         }
  242.         /* Enable reports; translate \n to \n\r for aux: */
  243.         ConWrite( "\x1b[12;11{\x1b[20h", 13);
  244. }
  245.  
  246. struct Screen *MyFindWB ( void )
  247. {
  248.     static struct Screen __aligned WBScreen, *wbsdata;
  249.  
  250.     if ( IsV2 )
  251.         wbsdata = LockPubScreen("Workbench");
  252.     else
  253.     {
  254.         if ( !GetScreenData ( &WBScreen, sizeof(struct Screen),
  255.             WBENCHSCREEN, NULL ) )
  256.             wbsdata = NULL;
  257.         else
  258.             wbsdata = &WBScreen;
  259.     }
  260.     if ( !wbsdata )
  261.     {
  262.         error ( "Can't find Workbench screen" );
  263.         quit();
  264.     }
  265.     return wbsdata;
  266. }
  267.  
  268. void MyFreeWB ( struct Screen *wbsdata )
  269. {
  270.     if (IsV2)
  271.         UnlockPubScreen(NULL, wbsdata);
  272. }
  273.  
  274. /* Request size of window information.
  275.    Modelled after sample code by C. Scheppner et al. on Fish Disk 56.
  276. */
  277. void getrowcol (void)
  278. {
  279.     if ( ConsoleHandle == 0 ) ttopen();
  280.     if ( conUnit )
  281.     {
  282.         /* 1.3 needs something done in the window so cu_* becomes  valid */
  283.         lower_left();
  284.  
  285.         nrow = conUnit->cu_YMax + 1;
  286.         ncol = conUnit->cu_XMax + 1;
  287.     }
  288.     else    /* for instance, if we're running aux: */
  289.     {
  290.         /* make something up... */
  291.         nrow = 24;
  292.         ncol = 80;
  293.     }
  294. }
  295.  
  296.  
  297. /*
  298.  * This function gets called just
  299.  * before we go back home to the command interpreter.
  300.  * On the Amiga it closes up the virtual terminal window.
  301.  */
  302. void ttclose (void)
  303. {
  304.     long PktArg[1];
  305.        char ch;
  306.  
  307.     /* disable raw mode report of window resizeing and close gadget */
  308.     if ( ConsoleHandle )
  309.     {
  310.         lower_left();
  311.         clear_eol();
  312.  
  313.         /* Don't leave the console handing with an unfulfilled async
  314.            read request.  We cancel it by forcing the console to send
  315.            us some more-or-less known characters, and not renewing the
  316.            read request when we've seen the last one.
  317.         */
  318.         ConWrite( "\x1b[6n", 4 ); /* request device status */
  319.         while ( 1 )
  320.         {
  321.             WaitPort ( RdReplyPort );
  322.             while ( ! GetMsg ( RdReplyPort ) ) /* nothing */;
  323.             ch = buffer;
  324.             if ( ch == 'R' ) break;
  325.             StartConRead();
  326.         }
  327.  
  328.         /* Disable window sizing reporting and raw mode.  This only
  329.            matters if we are running in a borrowed CLI window.  We
  330.            leave the close gadget activated, since if there is a close
  331.            gadget is was probably activated before we were called.
  332.         */
  333.         ConWrite( "\x1b[12}", 5);
  334.         PktArg[0] = 0; /* Turn off raw mode */
  335.         MyDoPkt ( ACTION_SCREEN_MODE, PktArg, 1 );
  336.         Close ( ConsoleHandle );
  337.         ConsoleHandle = 0;
  338.         if ( RdReplyPort ) DeletePort ( RdReplyPort );
  339.         RdReplyPort = 0L;
  340.     }
  341.     if ( RdPacket ) FreeMem ( RdPacket, sizeof (struct StandardPacket) );
  342.     RdPacket = NULL;
  343.     nrow = 0;
  344. }
  345.  
  346.  
  347. /*
  348.  * Read a character from the terminal,
  349.  * performing no editing and doing conditional echo
  350.  * but interpretting window resize and close gadget reports
  351.  */
  352. int do_echo = 1; /* echo flag */
  353.  
  354. int ttgetc (void)
  355. {
  356.         unsigned char c;        /* must be unsigned! */
  357.  
  358.  
  359.         while ( (c = ConGetC()) == '\x9b' )
  360.         {
  361.             switch (c = ConGetC())
  362.             {
  363.             case '1': /* raw input event */
  364.                 if ( (c = ConGetC()) == '1' )
  365.                     quit();  /* close gadget */
  366.                 else /*if ( c == '2' )  /* window resize */
  367.                 {
  368.                     while ( (c = ConGetC()) != '|') /* nothing */;
  369.                     winch();
  370.                 }
  371.                 break;
  372.             case '?': /* Help key */
  373.                 if ( (c = ConGetC()) == '~' ) return 'h';
  374.                 break;
  375.             case 'A':
  376.             case 'T': /* Arrow up */
  377.                 c = 'b';
  378.                 break;
  379.             case 'B':
  380.             case 'S': /* Arrow down */
  381.                 c = ' ';
  382.                 break;
  383.             case 'D': /* Arrow left */
  384.                 c = 'k';
  385.                 break;
  386.             case 'C': /* Arrow right */
  387.                 c = '\r';
  388.                 break;
  389.             case ' ': /* Shifted left or right */
  390.                 if ( (c = ConGetC()) == 'A' ) c = 'u';
  391.                 else c = 'd';
  392.                 break;
  393.             default:
  394.                 continue;
  395.             }
  396.             break;
  397.         }
  398.         if ( c == 3 )
  399.         {
  400.             sigs |= S_INTERRUPT;
  401.             psignals();
  402.             /* no return */
  403.         }
  404.         if (do_echo)
  405.                 ttwrite(&c, 1);
  406.  
  407.         return ((int) c);
  408. }
  409.  
  410. /*
  411.  * Check for ^C in the tty window.  This routine will throw
  412.  * away any characters waiting in the tty input buffer.  Returns when
  413.  * there's nothing in the input queue or one of the following has been
  414.  * recognized:
  415.  *
  416.  *  Close gadget    (exits)
  417.  *  Window resize   (resets window and returns)
  418.  *  ^C              (sets sigs and returns)
  419.  */
  420. int chk_sigs (void)
  421. {
  422.     int c;
  423.  
  424.     for (;;)
  425.     {
  426.         if ( (c = ConLookC()) < 0 ) return sigs;
  427.  
  428.         switch ( c )
  429.         {
  430.         case '\x9b': /* raw input event */
  431.             if ( (c = ConGetC()) != '1' ) break; /* unexpected raw input */
  432.             if ( (c = ConGetC()) == '1' )
  433.                 quit();  /* close gadget */
  434.             else if ( c == '2' )  /* window resize */
  435.             {
  436.                 while ( (c = ConGetC()) != '|') /* nothing */;
  437.                 winch();
  438.                 return sigs;
  439.             }
  440.             break;
  441.         case 3:
  442.             sigs |= S_INTERRUPT;
  443.             return sigs;
  444.         }
  445.     }
  446. }
  447.  
  448.  
  449.  
  450. /*
  451.  * Write a buffer of characters to the display.
  452.  */
  453. void ttwrite (char *buffer, int length)
  454. {
  455.         ConWrite ( buffer, length );
  456. }
  457.  
  458. /*
  459.  * Write a string to the terminal
  460.  */
  461. void ttputs (char *s)
  462. {
  463.         ConWrite ( s, strlen(s) );
  464. }
  465.  
  466. /* fake termcap output */
  467. /* This takes the place of the original tputs(x,y,z), using only the
  468.    first parameter
  469.  */
  470. void Tputs (char *s)
  471. {
  472.         flush();
  473.         if ( s ) ConWrite ( s, strlen(s) );
  474. }
  475.  
  476.  
  477. /* An sprintf replacement that uses exec.library, so is much smaller that
  478.    including the more general SAS link library routine.
  479. */
  480. __stdargs void MySprintf ( char *buffer, char *fmt, ... )
  481. {
  482.     RawDoFmt ( fmt, (APTR)(&fmt + 1), stuffChar, (APTR)buffer );
  483. }
  484.  
  485. /* The following code is adapted from C. Schepner's sample code on
  486.    Fish Disk 56.
  487.    Inits conUnit (global var), assuming ttyPort has been
  488.    set to the message port of a console.
  489. */
  490. static LONG findWindow ( void )
  491. {
  492.     struct InfoData *id;
  493.     LONG myargs[1] ,nargs, res1;
  494.  
  495.     /* Alloc to insure longword alignment */
  496.     id = (struct InfoData *)AllocMem(sizeof(struct InfoData),
  497.         MEMF_PUBLIC|MEMF_CLEAR);
  498.     if(! id) return(0);
  499.  
  500.     nargs = 0;
  501.     (void) MyDoPkt ( ACTION_FLUSH, myargs, nargs );
  502.  
  503.     myargs[0] = MKBADDR(id);
  504.     nargs = 1;
  505.     res1 = MyDoPkt ( ACTION_DISK_INFO, myargs, nargs );
  506.     conUnit = (struct ConUnit *)
  507.         ((struct IOStdReq *)id->id_InUse)->io_Unit;
  508.     FreeMem ( id, sizeof(struct InfoData) );
  509.     return res1;
  510. }
  511.  
  512. static void MySendPkt ( struct StandardPacket *pkt, struct MsgPort *RPort,
  513.     long action, long PktArg[], long Nargs )
  514. {
  515.     int count;
  516.     long *pargs;
  517.  
  518.     if ( !ttyPort ) quit();
  519.     pkt->sp_Msg.mn_Node.ln_Name = (char *)&(pkt->sp_Pkt);
  520.     pkt->sp_Pkt.dp_Link = &(pkt->sp_Msg);
  521.     pkt->sp_Pkt.dp_Port = RPort;
  522.     pkt->sp_Pkt.dp_Type = action;
  523.     pargs = &(pkt->sp_Pkt.dp_Arg1);
  524.     for ( count = 0; count < Nargs; count++ )
  525.     {
  526.         pargs[count] = PktArg[count];
  527.     }
  528.     PutMsg ( ttyPort, (struct Message *)pkt );
  529. }
  530.  
  531. static LONG MyDoPkt ( long action, long PktArg[], long Nargs )
  532. {
  533.     struct MsgPort *ReplyPort;
  534.     struct StandardPacket *packet;
  535.     LONG result;
  536.  
  537.     if ( !ttyPort ) quit();
  538.     if ( !(ReplyPort = CreatePort ( NULL, 0 )) )
  539.         quit();
  540.     packet = (struct StandardPacket *)AllocMem ( sizeof (struct StandardPacket),
  541.         MEMF_PUBLIC | MEMF_CLEAR );
  542.     if ( !packet )
  543.     {
  544.         DeletePort ( ReplyPort );
  545.         quit ();
  546.     }
  547.     MySendPkt ( packet, ReplyPort, action, PktArg, Nargs );
  548.     WaitPort ( ReplyPort );
  549.     GetMsg ( ReplyPort );
  550.     result = packet->sp_Pkt.dp_Res1;
  551.     FreeMem ( packet, sizeof(struct StandardPacket) );
  552.     DeletePort ( ReplyPort );
  553.     return result;
  554. }
  555.