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 >
Wrap
C/C++ Source or Header
|
1993-02-21
|
15KB
|
555 lines
/* io.c */
/* All of the code in this file is Amiga-specific */
#include "less.h"
#include <ctype.h>
#include <string.h>
#include <intuition/intuition.h>
#include <dos.h>
#include <devices/conunit.h>
#include <intuition/intuitionbase.h>
extern struct IntuitionBase *IntuitionBase;
extern int sigs;
static struct FileHandle *ttyHandle;
static struct MsgPort *ttyPort; /* Port to send DOS Packets to */
static struct MsgPort *RdReplyPort; /* When a tty read completes */
static BPTR ConsoleHandle = 0;
static struct StandardPacket *RdPacket = NULL; /* Packet for read requests */
static struct ConUnit *conUnit; /* For resizing information */
public BOOL UseCLI = FALSE; /* Has user requested we use CLI window? */
public int nrow = 0; /* Terminal size, rows. */
public int ncol; /* Terminal size, columns. */
/* Following function is required by MySprintf */
extern __asm void stuffChar
( register __d0 char c, register __a3 char *SPFbuffer );
int Wind_Spec[4] = { 0, 0, 0, 0 };
/* User-supplied option specifying window size/position:
*
* [0]: Left edge X - coord.
* [1]: Top edge Y - coord.
* [2]: Right edge X - coord.
* [3]: Bottom edge Y - coord.
*
* If element 2 or 3 is negative, it is taken to be a relative value to be
* subtracted from the maximum screen size. If the resulting window
* would be smaller than the minimum, it is quietly enlarged to the
* minimum, by expanding to the lower right as far as possible, and then
* moving the window toward the upper left if necessary.
*/
#define W_MINWIDTH 200
#define W_MINHEIGHT 60
/* Prototypes for functions defined in io.c */
static void StartConRead __PROTO((void));
static int ConGetC __PROTO((void));
static int ConLookC __PROTO((void));
static void ConWrite __PROTO((char *data, int length));
static LONG findWindow ( void );
static void MySendPkt __PROTO((struct StandardPacket *pkt, struct MsgPort *RPort,
long action, long PktArg[], long Nargs));
static LONG MyDoPkt __PROTO(( long action, long PktArg[], long Nargs ));
#include <exec/memory.h>
extern struct GfxBase *GfxBase;
extern struct MsgPort *CreatePort();
static char buffer; /* buffer for incoming console character */
/* asynchronous console read request--must be called once before
any ConGetC requests
*/
static void StartConRead ( void )
{
LONG PktArg[3];
PktArg[0] = (LONG)(ttyHandle->fh_Arg1);
PktArg[1] = (LONG)&buffer;
PktArg[2] = 1;
/* asynchronous posting of a read request */
MySendPkt( RdPacket, RdReplyPort, ACTION_READ, PktArg, 3 );
}
/* Get a character from the console.
*/
static int ConGetC ()
{
struct MsgPort *mp;
struct StandardPacket *rddata;
int temp;
ULONG ReadMsgBit, MsgBits;
mp = RdReplyPort; /* get the read reply port */
ReadMsgBit = 1 << mp->mp_SigBit;
rddata = NULL;
do /* Wait for a character or ^C */
{
MsgBits = Wait(ReadMsgBit | SIGBREAKF_CTRL_C);
if ( MsgBits & ReadMsgBit )
rddata = (struct StandardPacket *) GetMsg ( mp );
else if ( MsgBits & SIGBREAKF_CTRL_C )
{
quit();
}
} while ( !rddata );
/* We've got a character... */
temp = buffer; /* get the character */
StartConRead ( ); /* set up next read */
return temp;
}
/* See if a character is available at the console.
If so, get it, else return -1.
*/
static int ConLookC ( void )
{
struct MsgPort *mp;
struct StandardPacket *rddata;
int temp;
mp = RdReplyPort; /* get the read reply port */
rddata = (struct StandardPacket *) GetMsg ( mp );
if ( !rddata ) return -1;
/* We've got a character... */
temp = buffer; /* get the character */
StartConRead ( ); /* set up next read */
return temp;
}
/* write a specified number of characters from a buffer to console device
*/
static void ConWrite ( char *data, int length )
{
Write ( ConsoleHandle, data, length );
}
/*
* This routine gets called once, to set up the
* terminal channel.
*
* See The AmigaDOS Manual for details of how to derive parameters
* from an AmigaDOS filehandle and for doing console packet IO.
* The sample code on Fish Disk 56 is also instructive.
*/
void ttopen (void)
{
int left, top, width, height; /* window specification */
struct Screen *wbsdata;
long PktArg[1];
static char LessWindowSpec[132];
if ( ConsoleHandle ) return;
/* Under AmigaDos 1.3, one can't seem to open * with MODE_READWRITE */
if ( !called_from_WB && UseCLI )
ConsoleHandle = Open ( "*", MODE_OLDFILE );
if ( ConsoleHandle == 0 )
{
wbsdata = MyFindWB();
if ( (left = Wind_Spec[0]) < 0 ) left += wbsdata->Width;
if ( left < 0 ) left = 0;
if ( left > wbsdata->Width )
left = wbsdata->Width - W_MINWIDTH;
if ( (top = Wind_Spec[1]) < 0 ) top += wbsdata->Height;
if ( top < 0 ) top = 0;
if ( top > wbsdata->Height )
top = wbsdata->Height - W_MINHEIGHT;
width = Wind_Spec[2];
if ( width <= 0 )
width += wbsdata->Width;
if ( width <= 0 )
width = 0;
height = Wind_Spec[3];
if ( height <= 0 )
height += wbsdata->Height;
if ( height <= 0 )
height = 0;
if ( width < W_MINWIDTH )
width = W_MINWIDTH;
if ( height < W_MINHEIGHT )
height = W_MINHEIGHT;
if ( left + width > wbsdata->Width )
width = wbsdata->Width - left;
if ( top + height > wbsdata->Height )
height = wbsdata->Height - top;
if ( width < W_MINWIDTH )
left = wbsdata->Width - W_MINWIDTH;
if ( height < W_MINHEIGHT )
top = wbsdata->Height - W_MINHEIGHT;
if ( left < 0 || top < 0 )
{
MyFreeWB( wbsdata );
error ( "Window won't fit on screen" );
quit();
}
MyFreeWB(wbsdata);
MySprintf ( LessWindowSpec,
"CON:%ld/%ld/%ld/%ld/%s: h for help", left, top,
width, height, Ver );
if ( IsV2 ) strcat ( LessWindowSpec, "/CLOSE" );
ConsoleHandle = Open ( LessWindowSpec, MODE_OLDFILE );
}
if ( ConsoleHandle == 0 )
{
PrintFault ( IoErr(), "Can't open Less window" );
quit();
}
ttyHandle = (struct FileHandle *)(BADDR(ConsoleHandle));
ttyPort = ttyHandle->fh_Type;
if ( !ttyPort )
{
error ( "NULL ttyPort" );
quit();
}
RdReplyPort = CreatePort ( NULL, 0 );
RdPacket = (struct StandardPacket *)
AllocMem ( sizeof(struct StandardPacket), MEMF_PUBLIC | MEMF_CLEAR );
if ( !RdReplyPort || !RdPacket )
{
error ( "Out of Memory" );
quit();
}
findWindow();
StartConRead ( );
/* enable report of window resizeing and close gadget */
PktArg[0] = 1; /* set raw mode */
if ( ! MyDoPkt ( ACTION_SCREEN_MODE, PktArg, 1 ) )
{
error ( "Can't set raw mode" );
quit();
}
/* Enable reports; translate \n to \n\r for aux: */
ConWrite( "\x1b[12;11{\x1b[20h", 13);
}
struct Screen *MyFindWB ( void )
{
static struct Screen __aligned WBScreen, *wbsdata;
if ( IsV2 )
wbsdata = LockPubScreen("Workbench");
else
{
if ( !GetScreenData ( &WBScreen, sizeof(struct Screen),
WBENCHSCREEN, NULL ) )
wbsdata = NULL;
else
wbsdata = &WBScreen;
}
if ( !wbsdata )
{
error ( "Can't find Workbench screen" );
quit();
}
return wbsdata;
}
void MyFreeWB ( struct Screen *wbsdata )
{
if (IsV2)
UnlockPubScreen(NULL, wbsdata);
}
/* Request size of window information.
Modelled after sample code by C. Scheppner et al. on Fish Disk 56.
*/
void getrowcol (void)
{
if ( ConsoleHandle == 0 ) ttopen();
if ( conUnit )
{
/* 1.3 needs something done in the window so cu_* becomes valid */
lower_left();
nrow = conUnit->cu_YMax + 1;
ncol = conUnit->cu_XMax + 1;
}
else /* for instance, if we're running aux: */
{
/* make something up... */
nrow = 24;
ncol = 80;
}
}
/*
* This function gets called just
* before we go back home to the command interpreter.
* On the Amiga it closes up the virtual terminal window.
*/
void ttclose (void)
{
long PktArg[1];
char ch;
/* disable raw mode report of window resizeing and close gadget */
if ( ConsoleHandle )
{
lower_left();
clear_eol();
/* Don't leave the console handing with an unfulfilled async
read request. We cancel it by forcing the console to send
us some more-or-less known characters, and not renewing the
read request when we've seen the last one.
*/
ConWrite( "\x1b[6n", 4 ); /* request device status */
while ( 1 )
{
WaitPort ( RdReplyPort );
while ( ! GetMsg ( RdReplyPort ) ) /* nothing */;
ch = buffer;
if ( ch == 'R' ) break;
StartConRead();
}
/* Disable window sizing reporting and raw mode. This only
matters if we are running in a borrowed CLI window. We
leave the close gadget activated, since if there is a close
gadget is was probably activated before we were called.
*/
ConWrite( "\x1b[12}", 5);
PktArg[0] = 0; /* Turn off raw mode */
MyDoPkt ( ACTION_SCREEN_MODE, PktArg, 1 );
Close ( ConsoleHandle );
ConsoleHandle = 0;
if ( RdReplyPort ) DeletePort ( RdReplyPort );
RdReplyPort = 0L;
}
if ( RdPacket ) FreeMem ( RdPacket, sizeof (struct StandardPacket) );
RdPacket = NULL;
nrow = 0;
}
/*
* Read a character from the terminal,
* performing no editing and doing conditional echo
* but interpretting window resize and close gadget reports
*/
int do_echo = 1; /* echo flag */
int ttgetc (void)
{
unsigned char c; /* must be unsigned! */
while ( (c = ConGetC()) == '\x9b' )
{
switch (c = ConGetC())
{
case '1': /* raw input event */
if ( (c = ConGetC()) == '1' )
quit(); /* close gadget */
else /*if ( c == '2' ) /* window resize */
{
while ( (c = ConGetC()) != '|') /* nothing */;
winch();
}
break;
case '?': /* Help key */
if ( (c = ConGetC()) == '~' ) return 'h';
break;
case 'A':
case 'T': /* Arrow up */
c = 'b';
break;
case 'B':
case 'S': /* Arrow down */
c = ' ';
break;
case 'D': /* Arrow left */
c = 'k';
break;
case 'C': /* Arrow right */
c = '\r';
break;
case ' ': /* Shifted left or right */
if ( (c = ConGetC()) == 'A' ) c = 'u';
else c = 'd';
break;
default:
continue;
}
break;
}
if ( c == 3 )
{
sigs |= S_INTERRUPT;
psignals();
/* no return */
}
if (do_echo)
ttwrite(&c, 1);
return ((int) c);
}
/*
* Check for ^C in the tty window. This routine will throw
* away any characters waiting in the tty input buffer. Returns when
* there's nothing in the input queue or one of the following has been
* recognized:
*
* Close gadget (exits)
* Window resize (resets window and returns)
* ^C (sets sigs and returns)
*/
int chk_sigs (void)
{
int c;
for (;;)
{
if ( (c = ConLookC()) < 0 ) return sigs;
switch ( c )
{
case '\x9b': /* raw input event */
if ( (c = ConGetC()) != '1' ) break; /* unexpected raw input */
if ( (c = ConGetC()) == '1' )
quit(); /* close gadget */
else if ( c == '2' ) /* window resize */
{
while ( (c = ConGetC()) != '|') /* nothing */;
winch();
return sigs;
}
break;
case 3:
sigs |= S_INTERRUPT;
return sigs;
}
}
}
/*
* Write a buffer of characters to the display.
*/
void ttwrite (char *buffer, int length)
{
ConWrite ( buffer, length );
}
/*
* Write a string to the terminal
*/
void ttputs (char *s)
{
ConWrite ( s, strlen(s) );
}
/* fake termcap output */
/* This takes the place of the original tputs(x,y,z), using only the
first parameter
*/
void Tputs (char *s)
{
flush();
if ( s ) ConWrite ( s, strlen(s) );
}
/* An sprintf replacement that uses exec.library, so is much smaller that
including the more general SAS link library routine.
*/
__stdargs void MySprintf ( char *buffer, char *fmt, ... )
{
RawDoFmt ( fmt, (APTR)(&fmt + 1), stuffChar, (APTR)buffer );
}
/* The following code is adapted from C. Schepner's sample code on
Fish Disk 56.
Inits conUnit (global var), assuming ttyPort has been
set to the message port of a console.
*/
static LONG findWindow ( void )
{
struct InfoData *id;
LONG myargs[1] ,nargs, res1;
/* Alloc to insure longword alignment */
id = (struct InfoData *)AllocMem(sizeof(struct InfoData),
MEMF_PUBLIC|MEMF_CLEAR);
if(! id) return(0);
nargs = 0;
(void) MyDoPkt ( ACTION_FLUSH, myargs, nargs );
myargs[0] = MKBADDR(id);
nargs = 1;
res1 = MyDoPkt ( ACTION_DISK_INFO, myargs, nargs );
conUnit = (struct ConUnit *)
((struct IOStdReq *)id->id_InUse)->io_Unit;
FreeMem ( id, sizeof(struct InfoData) );
return res1;
}
static void MySendPkt ( struct StandardPacket *pkt, struct MsgPort *RPort,
long action, long PktArg[], long Nargs )
{
int count;
long *pargs;
if ( !ttyPort ) quit();
pkt->sp_Msg.mn_Node.ln_Name = (char *)&(pkt->sp_Pkt);
pkt->sp_Pkt.dp_Link = &(pkt->sp_Msg);
pkt->sp_Pkt.dp_Port = RPort;
pkt->sp_Pkt.dp_Type = action;
pargs = &(pkt->sp_Pkt.dp_Arg1);
for ( count = 0; count < Nargs; count++ )
{
pargs[count] = PktArg[count];
}
PutMsg ( ttyPort, (struct Message *)pkt );
}
static LONG MyDoPkt ( long action, long PktArg[], long Nargs )
{
struct MsgPort *ReplyPort;
struct StandardPacket *packet;
LONG result;
if ( !ttyPort ) quit();
if ( !(ReplyPort = CreatePort ( NULL, 0 )) )
quit();
packet = (struct StandardPacket *)AllocMem ( sizeof (struct StandardPacket),
MEMF_PUBLIC | MEMF_CLEAR );
if ( !packet )
{
DeletePort ( ReplyPort );
quit ();
}
MySendPkt ( packet, ReplyPort, action, PktArg, Nargs );
WaitPort ( ReplyPort );
GetMsg ( ReplyPort );
result = packet->sp_Pkt.dp_Res1;
FreeMem ( packet, sizeof(struct StandardPacket) );
DeletePort ( ReplyPort );
return result;
}