home *** CD-ROM | disk | FTP | other *** search
- /* io.c */
-
- #ifdef AMIGA
- /* Compile with -HPreHeader.q to get "less.h"! */
- #else
- #include "less.h"
- #endif
-
- #include <ctype.h>
- #include <string.h>
- #include <intuition/intuition.h>
- #include <dos.h>
-
-
- #undef TRUE
- #undef FALSE
-
- extern int sigs;
-
- static struct ConCom *tty = NULL;
-
- public int nrow = 0; /* Terminal size, rows. */
- public int ncol; /* Terminal size, columns. */
-
- static struct Window *LessWindow;
-
- 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
-
- extern char version[];
-
- /* Prototypes for functions defined in io.c */
-
- static struct ConCom *OpenConsole __PROTO((struct Window *window));
- static void CloseConsole __PROTO((struct ConCom *tty));
- static void StartTtyTimer __PROTO((void));
- static void StartConRead __PROTO((struct ConCom *tty));
- static int ConGetC __PROTO((struct ConCom *tty));
- static int ConLookC __PROTO((struct ConCom *tty));
- static void ConWrite __PROTO((struct ConCom *tty,
- char *data,
- int length));
-
-
-
- /****************************************************************/
- /* Code to open a console on an existing Intuition window.
- See RKM Libraries & Devices, pp 277 ff
- */
-
- #include <exec/memory.h>
- #include <devices/timer.h>
-
- extern struct GfxBase *GfxBase;
- extern struct IOStdReq * CreateStdIO();
- extern struct MsgPort *CreatePort();
-
-
- struct ConCom
- {
- struct IOStdReq *ConWriteReq; /* I/O write request */
- struct IOStdReq *ConReadReq; /* I/O read request */
- struct MsgPort *RdReplyPort; /* pointer to ReplyPort for console read */
- struct timerequest *TimerMsg; /* If != NULL, timer is open */
- };
-
-
- static struct ConCom *OpenConsole ( struct Window *window );
- static void CloseConsole ( struct ConCom *tty );
- static void StartConRead ( struct ConCom *tty );
- static int ConGetC ( struct ConCom *tty );
- static int ConLookC ( struct ConCom *tty );
- static void ConWrite ( struct ConCom *c, char *data, int length );
-
- static struct ConCom *OpenConsole (struct Window *window)
- {
- struct ConCom *tty;
- struct MsgPort *WrReplyPort, *TimerPort;
-
- if ( tty = (struct ConCom *)
- AllocMem(sizeof(struct ConCom), MEMF_CLEAR | MEMF_PUBLIC) )
- {
-
- if ( (WrReplyPort = CreatePort(0, 0)) /* reply port for write */
-
- && (tty->RdReplyPort = CreatePort(0, 0)) /* reply port for read */
-
- && (tty->ConWriteReq = CreateStdIO ( WrReplyPort ))
-
- && (tty->ConReadReq = CreateStdIO ( tty->RdReplyPort)) )
- {
- tty->ConWriteReq->io_Data = (APTR) window;
- tty->ConWriteReq->io_Length = sizeof(struct Window);
-
- if ( !(OpenDevice ( "console.device", 0, tty->ConWriteReq, 0 )) )
- {
- tty->ConReadReq->io_Device = tty->ConWriteReq->io_Device;
- tty->ConReadReq->io_Unit = tty->ConWriteReq->io_Unit;
-
- /* Try to set up regular interrupts for ^C check */
- TimerPort = CreatePort(NULL, 0);
- if (
- TimerPort
- && ( tty->TimerMsg = (struct timerequest *)
- CreateExtIO(TimerPort, sizeof(struct timerequest)) )
- && !OpenDevice (TIMERNAME, UNIT_VBLANK,
- (struct IORequest *)(tty->TimerMsg), 0)
- )
- return tty; /* All ok! */
- /* Main console ports ok, but no timer. We'll live
- without it...
- */
- if ( TimerPort ) DeletePort ( TimerPort );
- if ( tty->TimerMsg )
- DeleteExtIO( (struct IORequest *)(tty->TimerMsg),
- (long)sizeof(struct timerequest) );
- tty->TimerMsg = NULL;
- return tty;
- }
- }
-
- /* If get here, something went wrong */
- if ( tty->ConReadReq ) DeleteStdIO(tty->ConReadReq);
- if ( tty->RdReplyPort ) DeletePort(tty->RdReplyPort);
- if ( tty->ConWriteReq ) DeleteStdIO(tty->ConWriteReq);
- if ( WrReplyPort ) DeletePort(WrReplyPort);
- }
- if ( tty )
- FreeMem(tty, sizeof(struct ConCom));
- return NULL;
-
- }
-
- static void CloseConsole (struct ConCom *tty)
- {
- struct MsgPort *mp;
-
- AbortIO(tty->ConReadReq); /* Abort any read in progress */
- CloseDevice(tty->ConWriteReq); /* close console device */
-
- mp = tty->ConWriteReq->io_Message.mn_ReplyPort;
-
- DeleteStdIO(tty->ConWriteReq);
- DeletePort(mp);
-
- mp = tty->ConReadReq->io_Message.mn_ReplyPort;
-
- DeleteStdIO(tty->ConReadReq);
- DeletePort(mp);
-
- if (tty->TimerMsg)
- {
- AbortIO((struct IORequest *)(tty->TimerMsg));
- CloseDevice((struct IORequest *)(tty->TimerMsg));
- DeletePort ( tty->TimerMsg->tr_node.io_Message.mn_ReplyPort );
- DeleteExtIO ( (struct IORequest *)(tty->TimerMsg),
- (long)sizeof(struct timerequest) );
- }
-
- FreeMem(tty, sizeof(struct ConCom));
- return;
- }
-
- /* Request a timer interrupt in 0.25 seconds. Use this to poll for ^C */
-
- static void StartTtyTimer (void)
- {
- if ( !tty->TimerMsg ) return;
- tty->TimerMsg->tr_node.io_Command = TR_ADDREQUEST;
- tty->TimerMsg->tr_time.tv_secs = 0;
- tty->TimerMsg->tr_time.tv_micro = 250000L;
- SendIO ( (struct IORequest *)(tty->TimerMsg) );
- }
-
- static char buffer; /* buffer for incoming console character */
-
- /* asynchronous console read request--must be called once before
- any ConGetC requests
- */
-
- static void StartConRead (struct ConCom *tty)
- {
- struct IOStdReq *conr;
-
- conr = tty->ConReadReq;
- conr->io_Command = CMD_READ;
- conr->io_Length = 1;
- conr->io_Data = (APTR) &buffer;
- SendIO(conr); /* asynchronous posting of a read request */
- }
-
- /* Get a character from the console.
- */
- static int ConGetC (struct ConCom *tty)
- {
- struct MsgPort *mp, *tp;
- struct IOStdReq *rddata;
- int temp;
- ULONG ReadMsgBit, ClockMsgBit, MsgBits;
-
- mp = tty->RdReplyPort; /* get the read reply port */
- ReadMsgBit = 1 << mp->mp_SigBit;
- if ( tty->TimerMsg )
- {
- tp = tty->TimerMsg->tr_node.io_Message.mn_ReplyPort;
- ClockMsgBit = 1 << tp->mp_SigBit;
- }
- else ClockMsgBit = 0;
- rddata = NULL;
- do /* Wait for a character. Wake up periodically so that ^C works */
- {
- MsgBits = Wait(ReadMsgBit | ClockMsgBit);
- if ( MsgBits & ReadMsgBit )
- rddata = (struct IOStdReq *) GetMsg ( mp );
- if ( MsgBits & ClockMsgBit )
- if ( GetMsg (tp) )
- {
- StartTtyTimer();
- chkabort();
- }
- } while ( !rddata );
-
- /* We've got a character... */
- temp = buffer; /* get the character */
- StartConRead ( tty ); /* 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 (struct ConCom *tty)
- {
- struct MsgPort *mp;
- struct IOStdReq *rddata;
- int temp;
-
- mp = tty->RdReplyPort; /* get the read reply port */
- rddata = (struct IOStdReq *) GetMsg ( mp );
- if ( !rddata ) return -1;
-
- /* We've got a character... */
- temp = buffer; /* get the character */
- StartConRead ( tty ); /* set up next read */
- return temp;
- }
-
- /* write a specified number of characters from a buffer to console device
- */
- static void ConWrite (struct ConCom *tty, char *data, int length)
- {
- struct IOStdReq *wrdata;
-
- wrdata = tty->ConWriteReq;
- wrdata->io_Command = CMD_WRITE;
- wrdata->io_Length = length;
- wrdata->io_Data = (APTR) data;
- DoIO(wrdata); /* waits until write completes before continuing */
- }
-
- /****************************************************************/
-
-
-
- /*
- * This routine gets called once, to set up the
- * terminal channel.
- */
- void ttopen (void)
- {
- int wl, wt; /* window upper left corner specification */
- static struct Screen __aligned WBScreen, *wbsdata;
- static int IsV2;
- static struct NewWindow NewLessWindow =
- {
- 0, 0, 640, 200, /* position & size (may be changed) */
- -1, -1, /* pens */
- 0, /* IDCMP */
- WINDOWDEPTH | WINDOWSIZING | WINDOWDRAG | WINDOWCLOSE | ACTIVATE
- | SMART_REFRESH | NOCAREREFRESH,
- NULL, NULL, /* Gadgets, Checkmark */
- "Less 1.4Z: h for help",
- NULL, NULL, /* Use WB screen */
- W_MINWIDTH, W_MINHEIGHT, -1, -1,
- WBENCHSCREEN
- };
-
- if (tty) return;
-
-
- if (GfxBase = /* V2.0 + ? */
- (struct GfxBase *)OpenLibrary("graphics.library", 36) )
- {
- CloseLibrary ( GfxBase );
- IsV2 = 1;
- if ( !(wbsdata = LockPubScreen("Workbench")) )
- {
- error ( "Can't find Workbench screen" );
- quit();
- }
- }
- else
- {
- IsV2 = 0;
- if ( !GetScreenData ( &WBScreen, sizeof(struct Screen),
- WBENCHSCREEN, NULL ) )
- {
- error ( "Can't find Workbench screen" );
- quit();
- }
- wbsdata = &WBScreen;
- }
- if ( (wl = Wind_Spec[0]) < 0 ) wl += wbsdata->Width;
- if ( wl < 0 ) wl = 0;
- if ( wl > wbsdata->Width )
- wl = wbsdata->Width - W_MINWIDTH;
- if ( (wt = Wind_Spec[1]) < 0 ) wt += wbsdata->Height;
- if ( wt < 0 ) wt = 0;
- if ( wt > wbsdata->Height )
- wt = wbsdata->Height - W_MINHEIGHT;
- if ( wl < 0 || wt < 0 )
- {
- error ( "Window won't fit on screen" );
- quit();
- }
- NewLessWindow.LeftEdge = wl;
- NewLessWindow.TopEdge = wt;
-
- NewLessWindow.Width = Wind_Spec[2];
- if ( NewLessWindow.Width <= 0 )
- NewLessWindow.Width += wbsdata->Width;
- if ( NewLessWindow.Width <= 0 )
- NewLessWindow.Width = 0;
- NewLessWindow.Height = Wind_Spec[3];
- if ( NewLessWindow.Height <= 0 )
- NewLessWindow.Height += wbsdata->Height;
- if ( NewLessWindow.Height <= 0 )
- NewLessWindow.Height = 0;
-
- if ( NewLessWindow.Width < W_MINWIDTH )
- NewLessWindow.Width = W_MINWIDTH;
- if ( NewLessWindow.Height < W_MINHEIGHT )
- NewLessWindow.Height = W_MINHEIGHT;
-
- if ( NewLessWindow.LeftEdge + NewLessWindow.Width > wbsdata->Width )
- NewLessWindow.Width = wbsdata->Width - NewLessWindow.LeftEdge;
- if ( NewLessWindow.TopEdge + NewLessWindow.Height > wbsdata->Height )
- NewLessWindow.Height = wbsdata->Height - NewLessWindow.TopEdge;
- if ( NewLessWindow.Width < W_MINWIDTH )
- NewLessWindow.LeftEdge = wbsdata->Width - W_MINWIDTH;
- if ( NewLessWindow.Height < W_MINHEIGHT )
- NewLessWindow.TopEdge = wbsdata->Height - W_MINHEIGHT;
- if ( NewLessWindow.LeftEdge < 0 || NewLessWindow.TopEdge < 0 )
- {
- error ( "Window won't fit on screen" );
- quit();
- }
-
- if (IsV2)
- UnlockPubScreen(NULL, wbsdata);
- if (!(LessWindow = (struct Window *) OpenWindow (&NewLessWindow)) )
- {
- error ( "Can't open Less window" );
- quit();
- }
- if (!(tty = OpenConsole(LessWindow)))
- {
- error ( "Can't open console device" );
- quit();
- }
- StartConRead ( tty );
- if ( tty->TimerMsg ) StartTtyTimer();
- /* enable report of window resizeing and close gadget */
- ConWrite(tty, "\x9b\x31\x32;11{", 7);
- }
-
- /* Request size of window information
- */
- void getrowcol (void)
- {
- static unsigned char buf[16], *p;
-
- if ( !tty) ttopen();
- ConWrite(tty, "\x9b\x30\x20\x71", 4); /* request current window size */
- p = buf;
- while ( (*p = ConGetC(tty)) != 0x9b ) /* nothing */;
- p++;
- do
- {
- *p = ConGetC(tty);
- } while ( p < &(buf[15]) && *p++ != '\x72' );
- *p = '\0';
- /* buf has "En;n;n;n|", where E is 0x9b, n is a decimal number */
-
- p = buf+1;
- do
- {
- if ( p = strchr ( p, ';' ) ) p++; /* skip window position */
- else break;
- if ( p = strchr ( p, ';' ) ) p++;
- else break;
- nrow = atoi ( p ); /* window height */
- if ( p = strchr ( p, ';' ) ) p++;
- else break;
- ncol = atoi ( p ); /* window width */
- } while (0); /* just once! */
-
- /* arbitrary data integrity checks: */
- if ( nrow < 2 || nrow > 99 || ncol < 10 || ncol > 200 )
- {
- /* Window probably too small for the font chosen. We may not
- be able to even write an error message in the window! */
- MyRequester ( "Screen/Font mismatch" );
- quit();
- }
- }
-
-
-
- /*
- * 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)
- {
- if (tty != (struct ConCom *) 0L) {
- CloseConsole(tty);
- CloseWindow(LessWindow);
- }
- tty = 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(tty)) == '\x9b' )
- {
- switch (c = ConGetC(tty))
- {
- case '1': /* raw input event */
- if ( (c = ConGetC(tty)) == '1' )
- quit(); /* close gadget */
- else if ( c == '2' ) /* window resize */
- {
- while ( (c = ConGetC(tty)) != '|') /* nothing */;
- winch();
- }
- break;
- case '?': /* Help key */
- if ( (c = ConGetC(tty)) == '~' ) 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(tty)) == 'A' ) c = 'u';
- else c = 'd';
- break;
- default:
- continue;
- }
- break;
- }
- if ( c == 3 )
- {
- sigs |= 01;
- 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(tty)) < 0 ) return sigs;
-
- switch ( c )
- {
- case '\x9b': /* raw input event */
- if ( (c = ConGetC(tty)) != '1' ) break; /* unexpected raw input */
- if ( (c = ConGetC(tty)) == '1' )
- quit(); /* close gadget */
- else if ( c == '2' ) /* window resize */
- {
- while ( (c = ConGetC(tty)) != '|') /* nothing */;
- winch();
- return sigs;
- }
- break;
- case 3:
- sigs |= 01;
- return sigs;
- }
- }
- }
-
-
-
- /*
- * Write a buffer of characters to the display.
- */
- void ttwrite (char *buffer, int length)
- {
- ConWrite ( tty, buffer, length );
- }
-
- /*
- * Write a string to the terminal
- */
- void ttputs (char *s)
- {
- ConWrite ( tty, 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 ( tty, s, strlen(s) );
- }
-
- /*
- * We may not have a window: display a message in a requester
- */
- int MyRequester (char *s)
- {
- static struct IntuiText __aligned
- Ok =
- {
- AUTOFRONTPEN, AUTOBACKPEN, AUTODRAWMODE,
- AUTOLEFTEDGE, AUTOTOPEDGE,
- AUTOITEXTFONT,
- "Ok!",
- AUTONEXTTEXT
- },
- IMsg =
- {
- AUTOFRONTPEN, AUTOBACKPEN, AUTODRAWMODE,
- AUTOLEFTEDGE, AUTOTOPEDGE + 20, /* Hope this is enough for default font */
- AUTOITEXTFONT,
- "",
- AUTONEXTTEXT
- },
- LessMsg =
- {
- AUTOFRONTPEN, AUTOBACKPEN, AUTODRAWMODE,
- AUTOLEFTEDGE, AUTOTOPEDGE,
- AUTOITEXTFONT,
- "Less 1.4Z:",
- &IMsg
- };
-
- IMsg.IText = s;
- return (int)AutoRequest(NULL, &LessMsg, &Ok, &Ok, NULL, NULL, 250, 80);
- }
-