/* * Console.c * * Example of opening a window and using the console device * to send text and control sequences to it. The example can be * easily modified to do additional control sequences. * * Compile with SAS C 5.10: LC -b1 -cfistq -v -y -L * * Run from CLI only. */ #include <exec/types.h> #include <exec/io.h> #include <exec/memory.h> #include <intuition/intuition.h> #include <libraries/dos.h> #include <devices/console.h> #include <clib/exec_protos.h> #include <clib/alib_protos.h> #include <clib/dos_protos.h> #include <clib/intuition_protos.h> #include <stdio.h> #ifdef LATTICE int CXBRK(void) { return(0); } /* Disable Lattice CTRL/C handling */ int chkabort(void) { return(0); } /* really */ #endif /* Note - using two character <CSI> ESC[. Hex 9B could be used instead */ #define RESETCON "\033c" #define CURSOFF "\033[0 p" #define CURSON "\033[ p" #define DELCHAR "\033[P" * SGR (set graphic rendition) */ #define COLOR02 "\033[32m" #define COLOR03 "\033[33m" #define ITALICS "\033[3m" #define BOLD "\033[1m" #define UNDERLINE "\033[4m" #define NORMAL "\033[0m" /* our functions */ void cleanexit(UBYTE *,LONG); void cleanup(void); BYTE OpenConsole(struct IOStdReq *,struct IOStdReq *, struct Window *); void CloseConsole(struct IOStdReq *); void QueueRead(struct IOStdReq *, UBYTE *); UBYTE ConGetChar(struct MsgPort *, UBYTE *); LONG ConMayGetChar(struct MsgPort *, UBYTE *); void ConPuts(struct IOStdReq *, UBYTE *); void ConWrite(struct IOStdReq *, UBYTE *, LONG); void ConPutChar(struct IOStdReq *, UBYTE); void main(int argc, char **argv); struct NewWindow nw = { 10, 10, /* starting position (left,top) */ 620,180, /* width, height */ -1,-1, /* detailpen, blockpen */ CLOSEWINDOW, /* flags for idcmp */ WINDOWDEPTH|WINDOWSIZING| WINDOWDRAG|WINDOWCLOSE| SMART_REFRESH|ACTIVATE, /* window flags */ NULL, /* no user gadgets */ NULL, /* no user checkmark */ "Console Test", /* title */ NULL, /* pointer to window screen */ NULL, /* pointer to super bitmap */ 100,45, /* min width, height */ 640,200, /* max width, height */ WBENCHSCREEN /* open on workbench screen */ }; /* Opens/allocations we'll need to clean up */ struct Library *IntuitionBase = NULL; struct Window *win = NULL; struct IOStdReq *writeReq = NULL; /* IORequest block pointer */ struct MsgPort *writePort = NULL; /* replyport for writes */ struct IOStdReq *readReq = NULL; /* IORequest block pointer */ struct MsgPort *readPort = NULL; /* replyport for reads */ BOOL OpenedConsole = FALSE; BOOL FromWb; void main(argc, argv) int argc; char **argv; { struct IntuiMessage *winmsg; ULONG signals, conreadsig, windowsig; LONG lch; SHORT InControl = 0; BOOL Done = FALSE; UBYTE ch, ibuf; UBYTE obuf[200]; BYTE error; FromWb = (argc==0L) ? TRUE : FALSE; if(!(IntuitionBase=OpenLibrary("intuition.library",0))) cleanexit("Can't open intuition\n",RETURN_FAIL); /* Create reply port and io block for writing to console */ if(!(writePort = CreatePort("RKM.console.write",0))) cleanexit("Can't create write port\n",RETURN_FAIL); if(!(writeReq = (struct IOStdReq *) CreateExtIO(writePort,(LONG)sizeof(struct IOStdReq)))) cleanexit("Can't create write request\n",RETURN_FAIL); /* Create reply port and io block for reading from console */ if(!(readPort = CreatePort("RKM.console.read",0))) cleanexit("Can't create read port\n",RETURN_FAIL); if(!(readReq = (struct IOStdReq *) CreateExtIO(readPort,(LONG)sizeof(struct IOStdReq)))) cleanexit("Can't create read request\n",RETURN_FAIL); /* Open a window */ if(!(win = OpenWindow(&nw))) cleanexit("Can't open window\n",RETURN_FAIL); /* Now, attach a console to the window */ if(error = OpenConsole(writeReq,readReq,win)) cleanexit("Can't open console.device\n",RETURN_FAIL); else OpenedConsole = TRUE; /* Demonstrate some console escape sequences */ ConPuts(writeReq,"Here's some normal text\n"); sprintf(obuf,"%s%sHere's text in color 3 & italics\n",COLOR03,ITALICS); ConPuts(writeReq,obuf); ConPuts(writeReq,NORMAL); Delay(50); /* Delay for dramatic demo effect */ ConPuts(writeReq,"We will now delete this asterisk =*="); Delay(50); ConPuts(writeReq,"\b\b"); /* backspace twice */ Delay(50); ConPuts(writeReq,DELCHAR); /* delete the character */ Delay(50); QueueRead(readReq,&ibuf); /* send the first console read request */ ConPuts(writeReq,"\n\nNow reading console\n"); ConPuts(writeReq,"Type some keys. Close window when done.\n\n"); conreadsig = 1 << readPort->mp_SigBit; windowsig = 1 << win->UserPort->mp_SigBit; while(!Done) { /* A character, or an IDCMP msg, or both could wake us up */ signals = Wait(conreadsig|windowsig); /* If a console signal was received, get the character */ if (signals & conreadsig) { if((lch = ConMayGetChar(readPort,&ibuf)) != -1) { ch = lch; /* Show hex and ascii (if printable) for char we got. * If you want to parse received control sequences, such as * function or Help keys,you would buffer control sequences * as you receive them, starting to buffer whenever you * receive 0x9B (or 0x1B[ for user-typed sequences) and * ending when you receive a valid terminating character * for the type of control sequence you are receiving. * For CSI sequences, valid terminating characters * are generally 0x40 through 0x7E. * In our example, InControl has the following values: * 0 = no, 1 = have 0x1B, 2 = have 0x9B OR 0x1B and [, * 3 = now inside control sequence, -1 = normal end esc, * -2 = non-CSI(no [) 0x1B end esc * NOTE - a more complex parser is required to recognize * other types of control sequences. */ /* 0x1B ESC not followed by '[', is not CSI seq */ if (InControl==1) { if(ch=='[') InControl = 2; else InControl = -2; } if ((ch==0x9B)||(ch==0x1B)) /* Control seq starting */ { InControl = (ch==0x1B) ? 1 : 2; ConPuts(writeReq,"=== Control Seq ===\n"); } /* We'll show value of this char we received */ if (((ch >= 0x1F)&&(ch <= 0x7E))||(ch >= 0xA0)) sprintf(obuf,"Received: hex %02x = %c\n",ch,ch); else sprintf(obuf,"Received: hex %02x\n",ch); ConPuts(writeReq,obuf); /* Valid ESC sequence terminator ends an ESC seq */ if ((InControl==3)&&((ch >= 0x40) && (ch <= 0x7E))) { InControl = -1; } if (InControl==2) InControl = 3; /* ESC sequence finished (-1 if OK, -2 if bogus) */ if (InControl < 0) { InControl = 0; ConPuts(writeReq,"=== End Control ===\n"); } } } /* If IDCMP messages received, handle them */ if (signals & windowsig) { /* We have to ReplyMsg these when done with them */ while (winmsg = (struct IntuiMessage *)GetMsg(win->UserPort)) { switch(winmsg->Class) { case CLOSEWINDOW: Done = TRUE; break; default: break; } ReplyMsg((struct Message *)winmsg); } } } /* We always have an outstanding queued read request * so we must abort it if it hasn't completed, * and we must remove it. */ if(!(CheckIO(readReq))) AbortIO(readReq); WaitIO(readReq); /* clear it from our replyport */ cleanup(); exit(RETURN_OK); } void cleanexit(UBYTE *s,LONG n) { if(*s & (!FromWb)) printf(s); cleanup(); exit(n); } void cleanup() { if(OpenedConsole) CloseConsole(writeReq); if(readReq) DeleteExtIO(readReq); if(readPort) DeletePort(readPort); if(writeReq) DeleteExtIO(writeReq); if(writePort) DeletePort(writePort); if(win) CloseWindow(win); if(IntuitionBase) CloseLibrary(IntuitionBase); } /* Attach console device to an open Intuition window. * This function returns a value of 0 if the console * device opened correctly and a nonzero value (the error * returned from OpenDevice) if there was an error. */ BYTE OpenConsole(writereq, readreq, window) struct IOStdReq *writereq; struct IOStdReq *readreq; struct Window *window; { BYTE error; writereq->io_Data = (APTR) window; writereq->io_Length = sizeof(struct Window); error = OpenDevice("console.device", 0, writereq, 0); readreq->io_Device = writereq->io_Device; /* clone required parts */ readreq->io_Unit = writereq->io_Unit; return(error); } void CloseConsole(struct IOStdReq *writereq) { CloseDevice(writereq); } /* Output a single character to a specified console */ void ConPutChar(struct IOStdReq *writereq, UBYTE character) { writereq->io_Command = CMD_WRITE; writereq->io_Data = (APTR)&character; writereq->io_Length = 1; DoIO(writereq); /* command works because DoIO blocks until command is done * (otherwise ptr to the character could become invalid) */ } /* Output a stream of known length to a console */ void ConWrite(struct IOStdReq *writereq, UBYTE *string, LONG length) { writereq->io_Command = CMD_WRITE; writereq->io_Data = (APTR)string; writereq->io_Length = length; DoIO(writereq); /* command works because DoIO blocks until command is done * (otherwise ptr to string could become invalid in the meantime) */ } /* Output a NULL-terminated string of characters to a console */ void ConPuts(struct IOStdReq *writereq,UBYTE *string) { writereq->io_Command = CMD_WRITE; writereq->io_Data = (APTR)string; writereq->io_Length = -1; /* means print till terminating null */ DoIO(writereq); } /* Queue up a read request to console, passing it pointer * to a buffer into which it can read the character */ void QueueRead(struct IOStdReq *readreq, UBYTE *whereto) { readreq->io_Command = CMD_READ; readreq->io_Data = (APTR)whereto; readreq->io_Length = 1; SendIO(readreq); } /* Check if a character has been received. * If none, return -1 */ LONG ConMayGetChar(struct MsgPort *msgport, UBYTE *whereto) { register temp; struct IOStdReq *readreq; if (!(readreq = (struct IOStdReq *)GetMsg(msgport))) return(-1); temp = *whereto; /* get the character */ QueueRead(readreq,whereto); /* then re-use the request block */ return(temp); } /* Wait for a character */ UBYTE ConGetChar(struct MsgPort *msgport, UBYTE *whereto) { register temp; struct IOStdReq *readreq; WaitPort(msgport); readreq = (struct IOStdReq *)GetMsg(msgport); temp = *whereto; /* get the character */ QueueRead(readreq,whereto); /* then re-use the request block*/ return((UBYTE)temp); }