|
|
Microsoft OS/2 SDK 03-01-1988
/***
*
* TITLE
*
* terminal.c
* Created by Microsoft Corporation 1987
*
* DESCRIPTION
*
* This program emulates an ANSI terminal device.
*
* The device driver COM.SYS must be installed at IPL (Initial Program
* Load) by specifying the following in config.sys:
* device = COM01.SYS
*
* To run this program, type the following to the MS OS/2 prompt:
*
* terminal [filename]
*
* If a filename is specified, the initialisation of the COM port and
* the MODEM will be performed as indicated in the file (creation of this
* file is described in options.c). For more details on setting options
* pertaining to the COM port and the MODEM, see options.c
*
* To exit the terminal emulator, type ALT F1.
*
***/
#define INCL_DOSSIGNALS
#define INCL_SUB
#define INCL_DOSFILEMGR
#define INCL_DOSPROCESS
#define INCL_DOSDEVICES
#include <os2def.h>
#include <bse.h>
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <memory.h>
#include <conio.h>
#include "term.h"
extern void get_options(int, char *[]); /* get com port and modem options */
extern void get_com_options(structComOptions *); /* get com options */
extern make_modem_conn(void); /* make modem connection */
extern modem(void); /* returns TRUE if modem connection was requested */
extern void discon_modem(void); /* disconnect modem */
void init_com_port(void); /* initialise com port */
void far read_com_port(void); /* routine addr for a thread */
void write_com_port(void); /* routine addr for another thread */
void APIENTRY handle_signals(USHORT,USHORT); /* BREAK signals handler */
void close_conn(void); /*close modem connection & com port*/
void far xit(void); /* exit routine for this program */
char *ErrMsg[] = {
"VIOGETCONFIG",
"KBDSETSTATUS",
"OUT OF MEMORY",
"DOSCREATETHREAD",
"DOSCLOSE COMPORT",
"DOSDEVIOCTL SETDCB",
"DOSREAD",
"VIOWRTTTY",
"DOSOPEN: check if COM driver is installed",
"DOSDEVIOCTL SETBAUD",
"DOSDEVIOCTL SETLINECHAR",
"DOSDEVIOCTL GETDCB",
"KBDCHARIN",
"DOSWRITE",
"VIOWRTCHARSTRATT",
"VIOWRTNCELL",
"DOSEXITLIST ADD_ADDR",
"VIOSETCURPOS",
"VIOGETMODE",
"DOSDEVIOCTL FLUSH_XMIT_RECV_QUEUE",
"DOSDEVIOCTL GETCOM",
"DOSSETSIGHANDLER",
"DOSDEVIOCTL SETBREAKON",
"DOSDEVIOCTL SETBREAKOFF",
"INVALID SIGNAL",
"do_option: invalid option type",
"mod_option: invalid option type",
"show_option: invalid option type"
};
HFILE FileHndl = NULL; /* COM port file handle */
static char ExitPgm = FALSE; /* indicate if program should terminate */
static int ErrorNumber = -1, /* used as index to ErrMsg array */
ReturnCode = -1; /* retcode from system/subsystem call */
/*** main - entry point to TERMINAL program
*
* This routine obtains the com port and the modem options from the file
* (specified in the command line) or directly from the user. It opens and
* initialises the com port. It sets up the modem connection (if one was
* requested). It creates a thread which loops continuously waiting to
* receive data from the com port and writing it out to the display. It
* loops continuosly waiting for an input from the keyboard and writing
* it out to the com port. Both the loops terminate when the user presses
* ALT-F1. It closes the modem connection (if one was made), and the com
* port and then terminates.
*
* main(argc, argv)
*
* ENTRY
* argc - number of command line arguments
* argv - pointer to an array of pointers (to command line args)
*
* EXIT
* the program terminates
*
* WARNING
*
* EFFECTS
*
***/
main(argc,argv)
int argc;
char *argv[];
{
UCHAR *Stack1; /* stack for a thread */
TID ThreadID;
unsigned RetCode, /* return code */
Result = TRUE;
USHORT NumBytes; /* number of bytes to be written */
PFNSIGHANDLER PrevAddress;
USHORT PrevAction;
static KBDINFO OurKbdStatus =
{sizeof(OurKbdStatus),KBD_BITMASK,};
/* get COM port and modem options */
get_options(argc, argv);
/* open and initialise COM port */
init_com_port();
/* establish xit() as the exit routine */
if ((RetCode = DosExitList(EXLST_ADD, (void (far *)(USHORT))xit)) != 0)
error(ERR_DOSEXITLIST, RetCode);
/* make modem connection if requested */
if (modem())
Result = make_modem_conn();
if (Result) {
/* allocate memory for separate thread execution */
if (!(Stack1 = (char *) _nmalloc(STACKSIZE)))
error(ERR_OUTOFMEMORY, NO_RETCODE);
/* create a thread that will execute the read_com_port() */
Stack1 += STACKSIZE;
if ((RetCode = DosCreateThread(read_com_port, &ThreadID,
Stack1)) != 0)
error(ERR_DOSCREATETHREAD, RetCode);
/* set the keyboard status */
if ((RetCode = KbdSetStatus(&OurKbdStatus,
RESERVED)) != 0)
error(ERR_KBDSETSTATUS, RetCode);
/* set signal handler for BREAK signal */
if ((RetCode = DosSetSigHandler(handle_signals,
&PrevAddress,
&PrevAction,
RECV_CTRL, BREAK)) != 0)
error(ERR_DOSSETSIGHANDLER, RetCode);
/* display "connected" message */
printf("connected... \n");
/* read chars from the keyboard and write to COM port */
write_com_port();
} /* if (Result) */
}
/*** init_com_port - open the COM port and initialise line characteristics
*
* This routine opens the com port. It sets the com port options
* BaudRate, DataBits, Parity and the StopBits. It sets the read timeout.
* It enables the automatic transmit and receive flow control.
*
* init_com_port()
*
* ENTRY
*
* EXIT
* FileHndl = handle to com port
*
* WARNING
*
* EFFECTS
*
***/
void init_com_port()
{
USHORT ActionTaken; /* action: file existed,created,replaced */
unsigned RetCode;
structLineChar sLineChar; /* line characteristics */
structDCB sDCB; /* device control block information */
structComOptions sComOptions;
get_com_options(&sComOptions);
/* open the com port */
if ((RetCode = DosOpen(sComOptions.pPortName, &FileHndl,
&ActionTaken, 0L, 0, 0x0001, 0x0042, 0L)) != 0)
error(ERR_DOSOPEN, RetCode);
/* set the baud rate */
if ((RetCode = DosDevIOCtl(0L, &(sComOptions.iBaudRate),
SETBAUD, SERIAL, FileHndl)) != 0)
error(ERR_IOCTLSETBAUD, RetCode);
/* set Data Bits, Stop Bits, Parity */
sLineChar.DataBits = sComOptions.chDataBits;
sLineChar.Parity = sComOptions.chParity;
sLineChar.StopBits = sComOptions.chStopBits;
if ((RetCode = DosDevIOCtl(0L, &sLineChar, SETLINECHAR,
SERIAL, FileHndl)) != 0)
error(ERR_IOCTLSETLINECHAR, RetCode);
/* get device control block info */
if ((RetCode = DosDevIOCtl(&sDCB, 0L, GETDCB, SERIAL,
FileHndl)) != 0)
error(ERR_IOCTLGETDCB, RetCode);
sDCB.Flags2 |= 0x03; /* enable auto Xmit and recv flow control */
sDCB.Flags3 &= 0xf9; /* clear read timeout flags */
sDCB.Flags3 |= 0x04; /* set wait for something read timeout */
sDCB.ReadTimeOut = READTIMEOUT; /* set read timout value */
/* set device control block info */
if ((RetCode = DosDevIOCtl(0L, &sDCB, SETDCB, SERIAL,
FileHndl)) != 0)
error(ERR_IOCTLSETDCB, RetCode);
}
/*** write_com_port - read chars from the keyboard and write to COM port
*
* This routine loops continuosly waiting for a keyboard input and
* writing it out to the com port. The loop terminates when the user
* presses the ALT-F1.
*
* write_com_port()
*
* ENTRY
*
* EXIT
*
* WARNING
*
* EFFECTS
*
***/
void write_com_port()
{
USHORT NumBytes; /* number of bytes actually written */
unsigned RetCode;
char OutBuffer; /* output buffer */
KBDKEYINFO OurKeyData; /* struc to read a char from kbd */
while (!ExitPgm) {
/* read input from the keyboard */
if ((RetCode = KbdCharIn(&OurKeyData,
IOWAIT, RESERVED)) != 0)
error(ERR_KBDCHARIN, RetCode);
OutBuffer = OurKeyData.chChar;
if ((OutBuffer == 0) || (OutBuffer == 0xE0)) {
OutBuffer = OurKeyData.chScan;
switch (OutBuffer) {
case DEL_SCAN : OutBuffer = DEL_ASCII;
break;
case ALT_F1 : ExitPgm = TRUE;
break;
default : break;
};
if (OutBuffer != ALT_F1)
/* write the input from the keyboard to the com port */
if ((RetCode = DosWrite(FileHndl, &OutBuffer, 1,
&NumBytes)) != 0)
error(ERR_DOSWRITE, RetCode);
}
else {
/* write the input from the keyboard to the com port */
if ((RetCode = DosWrite(FileHndl, &OutBuffer, 1,
&NumBytes)) != 0)
error(ERR_DOSWRITE, RetCode);
};
};
}
/*** read_com_port - read chars from com port and display on CRT screen
*
* This routine is executed by a thread. It loops continuously waiting
* to receive data from the com port and writing it out to the display.
* The loop terminates when the user presses ALT-F1.
*
* read_com_port()
*
* ENTRY
* FileHndl (handle to com port) setup
*
* EXIT
*
* WARNING
*
* EFFECTS
*
***/
void far read_com_port()
{
USHORT NumBytes; /* number of bytes actually read */
unsigned RetCode;
struct CharsInQue { /*data ret'ned by get num chars in que IOCTL*/
unsigned NumCharsInQue;
unsigned SizeQue;
} sCharsInQue;
char InBuffer[INBUFLENGTH]; /* input buffer */
while (!ExitPgm) {
/* get number of characters in receive queue */
if ((RetCode = DosDevIOCtl(&sCharsInQue, 0L, GETNUMCHARS,
SERIAL, FileHndl)) != 0)
setup_error_msg(ERR_IOCTLSETDCB, RetCode);
if (sCharsInQue.NumCharsInQue == 0)
sCharsInQue.NumCharsInQue++;
if ((RetCode = DosRead(FileHndl, InBuffer, sCharsInQue.NumCharsInQue,
&NumBytes)) != 0)
setup_error_msg(ERR_DOSREAD, RetCode);
if (NumBytes) {
/* write to the tty display */
if ((RetCode = VioWrtTTy(InBuffer, NumBytes, RESERVED)) != 0)
setup_error_msg(ERR_VIOWRTTTY, RetCode);
}
}
}
/*** handle_signals - handle BREAK signal
*
* This routine is the handler for the BREAK signal. When the user presses
* the BREAK key, this routine sends a BREAK on the com line.
*
* handle_signals(SigArg, SigNumber)
*
* ENTRY
* SigArg - not used
* SigNumber - signal number being processed
*
* EXIT
*
* WARNING
*
* EFFECTS
* Since this is a signal handler it must be declared FAR.
*
***/
void APIENTRY handle_signals(SigArg, SigNumber)
USHORT SigArg,
SigNumber;
{
unsigned RetCode,
Status;
char OutBuffer;
switch (SigNumber) {
case BREAK :/* send BREAK to the com port */
if ((RetCode = DosDevIOCtl(&Status, 0L,
SETBREAKON, SERIAL, FileHndl)) != 0)
error(ERR_IOCTLSETBREAKON, RetCode);
DosSleep(1L);
if ((RetCode = DosDevIOCtl(&Status, 0L,
SETBREAKOFF, SERIAL, FileHndl)) != 0)
error(ERR_IOCTLSETBREAKOFF, RetCode);
break;
default :
error(ERR_INVALIDSIGNAL, NO_RETCODE);
break;
}
}
/*** close_conn - close modem connection and the com port
*
* This routine closes the modem connection if one was made and then
* closes the com port.
*
* close_conn()
*
* ENTRY
*
* EXIT
*
* WARNING
*
* EFFECTS
*
***/
void close_conn()
{
int RetCode;
static char CloseMsg[] = "exiting terminal...";
/* send closing message to the display */
if ((RetCode = VioWrtTTy(CloseMsg, sizeof(CloseMsg), RESERVED)) != 0)
print_err_msg(ErrMsg[ERR_VIOWRTTTY], RetCode);
/* if modem connection was made, close it */
if (modem())
discon_modem();
/* close the com port */
if ((RetCode = DosClose(FileHndl)) != 0)
print_err_msg(ErrMsg[ERR_DOSCLOSECOMPORT], RetCode);
}
/*** ERROR HANDLING
*
* There are two error handling routines:
* - error() which is invoked from the main thread
* - setup_err_msg() which is invoked from the thread executing
* the read_com_port() routine
* The two routines perform different functions (described below). This
* is done so that if an error is encountered "simultaneously" in both
* the threads, there will be no race condition in error reporting.
*
* The following routines are also part of the error handling:
* - xit() is a DosExitList routine
* - print_err_msg() does the actual printing of the error message
*
* All the routines discussed above are defined below.
*
***/
/*** error
*
* This routine is invoked when there is an error. It prints an
* an error message and calls DosExit.
*
* error(ErrNum, RetCode)
*
* ENTRY
* ErrNum - error number (used as index to error message array)
* RetCode - return code from a DOS system/subsystem call
*
* EXIT
* global variables ErrorNumber & ReturnCode still contain the
* initial value of -1. At program termination (via DosExit call)
* the DosExitList routine xit() is invoked (described below).
* On return from xit(), this program will terminate.
*
* WARNING
*
* EFFECTS
*
***/
error(ErrNum, RetCode)
int ErrNum;
int RetCode;
{
print_err_msg(ErrMsg[ErrNum], RetCode);
DosExit(EXIT_PROCESS, 1);
}
/*** setup_error_msg - setup error message
*
* Sets up the global ErrorNumber and ReturnCode. It then calls DosExit.
*
* setup_error_msg(ErrNum, RetCode)
*
* ENTRY
* ErrNum - error number (used as index to error message array)
* RetCode - return code from a DOS system/subsystem call
*
* EXIT
* global variables ErrorNumber & ReturnCode are setup. At
* program termination (via DosExit call) the DosExitList
* routine xit() is invoked (described below). xit() will print
* an error message. On return from xit(), this program will
* terminate.
*
* WARNING
*
* EFFECTS
*
***/
setup_error_msg(ErrNum, RetCode)
int ErrNum,
RetCode;
{
ErrorNumber = ErrNum;
ReturnCode = RetCode;
DosExit(EXIT_PROCESS, 1);
}
/*** xit - exit function executed at program termination
*
* This is a DosExitList routine. It prints an error message if
* the global variable ErrorNumber is non-negative.
*
* xit()
*
* ENTRY
*
* EXIT
* If ErrorNumber is non-negative, an error message is printed.
* The program will then terminate.
*
* WARNING
*
* EFFECTS
*
***/
void far xit(void)
{
if (ErrorNumber != -1)
print_err_msg(ErrMsg[ErrorNumber], ReturnCode);
close_conn(); /* close modem connection and the com port */
DosExitList(XFER, 0L);
}
/*** print_err_msg - print error mesage
*
* This routine prints an error message and the returncode.
*
* print_err_msg(Msg, Retcode)
*
* ENTRY
* Msg - error message string
* Retcode - returncode from DOS system/subsystem call
*
* EXIT
*
* WARNING
*
* EFFECTS
*
***/
print_err_msg(Msg, RetCode)
char *Msg;
int RetCode;
{
printf("*** ERROR %s *** ", Msg);
if (RetCode != -1)
printf("ReturnCode = %d ", RetCode);
printf("\n");
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.