|
|
1.1 root 1: /***
2: *
3: * TITLE
4: *
5: * terminal.c
1.1.1.2 ! root 6: * Created by Microsoft Corporation 1987
1.1 root 7: *
8: * DESCRIPTION
9: *
10: * This program emulates an ANSI terminal device.
11: *
12: * The device driver COM.SYS must be installed at IPL (Initial Program
13: * Load) by specifying the following in config.sys:
14: * device = COM01.SYS
15: *
16: * To run this program, type the following to the MS OS/2 prompt:
17: *
18: * terminal [filename]
19: *
20: * If a filename is specified, the initialisation of the COM port and
21: * the MODEM will be performed as indicated in the file (creation of this
22: * file is described in options.c). For more details on setting options
23: * pertaining to the COM port and the MODEM, see options.c
24: *
25: * To exit the terminal emulator, type ALT F1.
26: *
27: ***/
28:
1.1.1.2 ! root 29: #define INCL_DOSSIGNALS
! 30: #define INCL_SUB
! 31: #define INCL_DOSFILEMGR
! 32: #define INCL_DOSPROCESS
! 33: #define INCL_DOSDEVICES
! 34:
! 35: #include <os2def.h>
! 36: #include <bse.h>
1.1 root 37: #include <stdio.h>
38: #include <malloc.h>
39: #include <string.h>
40: #include <memory.h>
41: #include <conio.h>
42: #include "term.h"
43:
44: extern void get_options(int, char *[]); /* get com port and modem options */
45: extern void get_com_options(structComOptions *); /* get com options */
46: extern make_modem_conn(void); /* make modem connection */
47: extern modem(void); /* returns TRUE if modem connection was requested */
48: extern void discon_modem(void); /* disconnect modem */
49:
50: void init_com_port(void); /* initialise com port */
51: void far read_com_port(void); /* routine addr for a thread */
52: void write_com_port(void); /* routine addr for another thread */
1.1.1.2 ! root 53: void APIENTRY handle_signals(USHORT,USHORT); /* BREAK signals handler */
1.1 root 54: void close_conn(void); /*close modem connection & com port*/
1.1.1.2 ! root 55: void far xit(void); /* exit routine for this program */
1.1 root 56:
57: char *ErrMsg[] = {
1.1.1.2 ! root 58: "VIOGETCONFIG",
! 59: "KBDSETSTATUS",
1.1 root 60: "OUT OF MEMORY",
1.1.1.2 ! root 61: "DOSCREATETHREAD",
! 62: "DOSCLOSE COMPORT",
! 63: "DOSDEVIOCTL SETDCB",
! 64: "DOSREAD",
! 65: "VIOWRTTTY",
! 66: "DOSOPEN: check if COM driver is installed",
! 67: "DOSDEVIOCTL SETBAUD",
! 68: "DOSDEVIOCTL SETLINECHAR",
! 69: "DOSDEVIOCTL GETDCB",
! 70: "KBDCHARIN",
! 71: "DOSWRITE",
! 72: "VIOWRTCHARSTRATT",
! 73: "VIOWRTNCELL",
! 74: "DOSEXITLIST ADD_ADDR",
! 75: "VIOSETCURPOS",
! 76: "VIOGETMODE",
! 77: "DOSDEVIOCTL FLUSH_XMIT_RECV_QUEUE",
! 78: "DOSDEVIOCTL GETCOM",
! 79: "DOSSETSIGHANDLER",
! 80: "DOSDEVIOCTL SETBREAKON",
! 81: "DOSDEVIOCTL SETBREAKOFF",
1.1 root 82: "INVALID SIGNAL",
83: "do_option: invalid option type",
84: "mod_option: invalid option type",
85: "show_option: invalid option type"
86: };
1.1.1.2 ! root 87: HFILE FileHndl = NULL; /* COM port file handle */
1.1 root 88:
89: static char ExitPgm = FALSE; /* indicate if program should terminate */
90: static int ErrorNumber = -1, /* used as index to ErrMsg array */
91: ReturnCode = -1; /* retcode from system/subsystem call */
92:
93:
94:
95:
96: /*** main - entry point to TERMINAL program
97: *
98: * This routine obtains the com port and the modem options from the file
99: * (specified in the command line) or directly from the user. It opens and
100: * initialises the com port. It sets up the modem connection (if one was
101: * requested). It creates a thread which loops continuously waiting to
102: * receive data from the com port and writing it out to the display. It
103: * loops continuosly waiting for an input from the keyboard and writing
104: * it out to the com port. Both the loops terminate when the user presses
105: * ALT-F1. It closes the modem connection (if one was made), and the com
106: * port and then terminates.
107: *
108: * main(argc, argv)
109: *
110: * ENTRY
111: * argc - number of command line arguments
112: * argv - pointer to an array of pointers (to command line args)
113: *
114: * EXIT
115: * the program terminates
116: *
117: * WARNING
118: *
119: * EFFECTS
120: *
121: ***/
122:
123: main(argc,argv)
124: int argc;
125: char *argv[];
126: {
1.1.1.2 ! root 127: UCHAR *Stack1; /* stack for a thread */
! 128: TID ThreadID;
! 129: unsigned RetCode, /* return code */
1.1 root 130: Result = TRUE;
1.1.1.2 ! root 131: USHORT NumBytes; /* number of bytes to be written */
! 132: PFNSIGHANDLER PrevAddress;
! 133: USHORT PrevAction;
! 134: static KBDINFO OurKbdStatus =
1.1 root 135: {sizeof(OurKbdStatus),KBD_BITMASK,};
136:
137: /* get COM port and modem options */
138: get_options(argc, argv);
139:
140: /* open and initialise COM port */
141: init_com_port();
142:
143: /* establish xit() as the exit routine */
1.1.1.2 ! root 144: if ((RetCode = DosExitList(EXLST_ADD, (void (far *)(USHORT))xit)) != 0)
1.1 root 145: error(ERR_DOSEXITLIST, RetCode);
146:
147: /* make modem connection if requested */
148: if (modem())
149: Result = make_modem_conn();
150:
151: if (Result) {
152: /* allocate memory for separate thread execution */
153: if (!(Stack1 = (char *) _nmalloc(STACKSIZE)))
154: error(ERR_OUTOFMEMORY, NO_RETCODE);
155:
156: /* create a thread that will execute the read_com_port() */
157: Stack1 += STACKSIZE;
1.1.1.2 ! root 158: if ((RetCode = DosCreateThread(read_com_port, &ThreadID,
1.1 root 159: Stack1)) != 0)
160: error(ERR_DOSCREATETHREAD, RetCode);
161:
162: /* set the keyboard status */
1.1.1.2 ! root 163: if ((RetCode = KbdSetStatus(&OurKbdStatus,
1.1 root 164: RESERVED)) != 0)
165: error(ERR_KBDSETSTATUS, RetCode);
166:
167: /* set signal handler for BREAK signal */
1.1.1.2 ! root 168: if ((RetCode = DosSetSigHandler(handle_signals,
1.1 root 169: &PrevAddress,
170: &PrevAction,
171: RECV_CTRL, BREAK)) != 0)
172: error(ERR_DOSSETSIGHANDLER, RetCode);
173:
174: /* display "connected" message */
175: printf("connected... \n");
176:
177: /* read chars from the keyboard and write to COM port */
178: write_com_port();
179: } /* if (Result) */
180: }
181:
182:
183:
184:
1.1.1.2 ! root 185: /*** init_com_port - open the COM port and initialise line characteristics
1.1 root 186: *
187: * This routine opens the com port. It sets the com port options
188: * BaudRate, DataBits, Parity and the StopBits. It sets the read timeout.
189: * It enables the automatic transmit and receive flow control.
190: *
191: * init_com_port()
192: *
193: * ENTRY
194: *
195: * EXIT
196: * FileHndl = handle to com port
197: *
198: * WARNING
199: *
200: * EFFECTS
201: *
202: ***/
203:
204: void init_com_port()
205: {
1.1.1.2 ! root 206: USHORT ActionTaken; /* action: file existed,created,replaced */
! 207: unsigned RetCode;
1.1 root 208: structLineChar sLineChar; /* line characteristics */
209: structDCB sDCB; /* device control block information */
210: structComOptions sComOptions;
211:
212: get_com_options(&sComOptions);
213:
214: /* open the com port */
1.1.1.2 ! root 215: if ((RetCode = DosOpen(sComOptions.pPortName, &FileHndl,
1.1 root 216: &ActionTaken, 0L, 0, 0x0001, 0x0042, 0L)) != 0)
217: error(ERR_DOSOPEN, RetCode);
218:
219: /* set the baud rate */
1.1.1.2 ! root 220: if ((RetCode = DosDevIOCtl(0L, &(sComOptions.iBaudRate),
1.1 root 221: SETBAUD, SERIAL, FileHndl)) != 0)
222: error(ERR_IOCTLSETBAUD, RetCode);
223:
224: /* set Data Bits, Stop Bits, Parity */
225: sLineChar.DataBits = sComOptions.chDataBits;
226: sLineChar.Parity = sComOptions.chParity;
227: sLineChar.StopBits = sComOptions.chStopBits;
1.1.1.2 ! root 228: if ((RetCode = DosDevIOCtl(0L, &sLineChar, SETLINECHAR,
1.1 root 229: SERIAL, FileHndl)) != 0)
230: error(ERR_IOCTLSETLINECHAR, RetCode);
231:
232: /* get device control block info */
1.1.1.2 ! root 233: if ((RetCode = DosDevIOCtl(&sDCB, 0L, GETDCB, SERIAL,
1.1 root 234: FileHndl)) != 0)
235: error(ERR_IOCTLGETDCB, RetCode);
236:
237: sDCB.Flags2 |= 0x03; /* enable auto Xmit and recv flow control */
238: sDCB.Flags3 &= 0xf9; /* clear read timeout flags */
239: sDCB.Flags3 |= 0x04; /* set wait for something read timeout */
240: sDCB.ReadTimeOut = READTIMEOUT; /* set read timout value */
241:
242: /* set device control block info */
1.1.1.2 ! root 243: if ((RetCode = DosDevIOCtl(0L, &sDCB, SETDCB, SERIAL,
1.1 root 244: FileHndl)) != 0)
245: error(ERR_IOCTLSETDCB, RetCode);
246: }
247:
248:
249:
250:
251: /*** write_com_port - read chars from the keyboard and write to COM port
252: *
253: * This routine loops continuosly waiting for a keyboard input and
254: * writing it out to the com port. The loop terminates when the user
255: * presses the ALT-F1.
256: *
257: * write_com_port()
258: *
259: * ENTRY
260: *
261: * EXIT
262: *
263: * WARNING
264: *
265: * EFFECTS
266: *
267: ***/
268:
269: void write_com_port()
270: {
1.1.1.2 ! root 271: USHORT NumBytes; /* number of bytes actually written */
! 272: unsigned RetCode;
1.1 root 273: char OutBuffer; /* output buffer */
1.1.1.2 ! root 274: KBDKEYINFO OurKeyData; /* struc to read a char from kbd */
1.1 root 275:
276:
277: while (!ExitPgm) {
278: /* read input from the keyboard */
1.1.1.2 ! root 279: if ((RetCode = KbdCharIn(&OurKeyData,
1.1 root 280: IOWAIT, RESERVED)) != 0)
1.1.1.2 ! root 281: error(ERR_KBDCHARIN, RetCode);
! 282: OutBuffer = OurKeyData.chChar;
1.1 root 283: if ((OutBuffer == 0) || (OutBuffer == 0xE0)) {
1.1.1.2 ! root 284: OutBuffer = OurKeyData.chScan;
1.1 root 285: switch (OutBuffer) {
286: case DEL_SCAN : OutBuffer = DEL_ASCII;
287: break;
288: case ALT_F1 : ExitPgm = TRUE;
289: break;
290: default : break;
291: };
292: if (OutBuffer != ALT_F1)
293: /* write the input from the keyboard to the com port */
1.1.1.2 ! root 294: if ((RetCode = DosWrite(FileHndl, &OutBuffer, 1,
1.1 root 295: &NumBytes)) != 0)
1.1.1.2 ! root 296: error(ERR_DOSWRITE, RetCode);
1.1 root 297: }
298: else {
299: /* write the input from the keyboard to the com port */
1.1.1.2 ! root 300: if ((RetCode = DosWrite(FileHndl, &OutBuffer, 1,
1.1 root 301: &NumBytes)) != 0)
302: error(ERR_DOSWRITE, RetCode);
303: };
304: };
305: }
306:
307:
308:
309:
310: /*** read_com_port - read chars from com port and display on CRT screen
311: *
312: * This routine is executed by a thread. It loops continuously waiting
313: * to receive data from the com port and writing it out to the display.
314: * The loop terminates when the user presses ALT-F1.
315: *
316: * read_com_port()
317: *
318: * ENTRY
319: * FileHndl (handle to com port) setup
320: *
321: * EXIT
322: *
323: * WARNING
324: *
325: * EFFECTS
326: *
327: ***/
328:
329: void far read_com_port()
330: {
1.1.1.2 ! root 331: USHORT NumBytes; /* number of bytes actually read */
! 332: unsigned RetCode;
1.1 root 333: struct CharsInQue { /*data ret'ned by get num chars in que IOCTL*/
334: unsigned NumCharsInQue;
335: unsigned SizeQue;
336: } sCharsInQue;
337: char InBuffer[INBUFLENGTH]; /* input buffer */
338:
339: while (!ExitPgm) {
340: /* get number of characters in receive queue */
1.1.1.2 ! root 341: if ((RetCode = DosDevIOCtl(&sCharsInQue, 0L, GETNUMCHARS,
1.1 root 342: SERIAL, FileHndl)) != 0)
343: setup_error_msg(ERR_IOCTLSETDCB, RetCode);
344:
345: if (sCharsInQue.NumCharsInQue == 0)
346: sCharsInQue.NumCharsInQue++;
347:
1.1.1.2 ! root 348: if ((RetCode = DosRead(FileHndl, InBuffer, sCharsInQue.NumCharsInQue,
1.1 root 349: &NumBytes)) != 0)
350: setup_error_msg(ERR_DOSREAD, RetCode);
351:
352: if (NumBytes) {
353: /* write to the tty display */
1.1.1.2 ! root 354: if ((RetCode = VioWrtTTy(InBuffer, NumBytes, RESERVED)) != 0)
1.1 root 355: setup_error_msg(ERR_VIOWRTTTY, RetCode);
356: }
357: }
358: }
359:
360:
361:
362:
363: /*** handle_signals - handle BREAK signal
364: *
365: * This routine is the handler for the BREAK signal. When the user presses
366: * the BREAK key, this routine sends a BREAK on the com line.
367: *
368: * handle_signals(SigArg, SigNumber)
369: *
370: * ENTRY
371: * SigArg - not used
372: * SigNumber - signal number being processed
373: *
374: * EXIT
375: *
376: * WARNING
377: *
378: * EFFECTS
379: * Since this is a signal handler it must be declared FAR.
380: *
381: ***/
382:
1.1.1.2 ! root 383: void APIENTRY handle_signals(SigArg, SigNumber)
! 384: USHORT SigArg,
1.1 root 385: SigNumber;
386: {
1.1.1.2 ! root 387: unsigned RetCode,
1.1 root 388: Status;
389: char OutBuffer;
390:
391: switch (SigNumber) {
392: case BREAK :/* send BREAK to the com port */
1.1.1.2 ! root 393: if ((RetCode = DosDevIOCtl(&Status, 0L,
1.1 root 394: SETBREAKON, SERIAL, FileHndl)) != 0)
395: error(ERR_IOCTLSETBREAKON, RetCode);
1.1.1.2 ! root 396: DosSleep(1L);
! 397: if ((RetCode = DosDevIOCtl(&Status, 0L,
1.1 root 398: SETBREAKOFF, SERIAL, FileHndl)) != 0)
399: error(ERR_IOCTLSETBREAKOFF, RetCode);
400: break;
401: default :
402: error(ERR_INVALIDSIGNAL, NO_RETCODE);
403: break;
404: }
405: }
406:
407:
408:
409:
410: /*** close_conn - close modem connection and the com port
411: *
412: * This routine closes the modem connection if one was made and then
413: * closes the com port.
414: *
415: * close_conn()
416: *
417: * ENTRY
418: *
419: * EXIT
420: *
421: * WARNING
422: *
423: * EFFECTS
424: *
425: ***/
426:
427: void close_conn()
428: {
429: int RetCode;
430: static char CloseMsg[] = "exiting terminal...";
431:
432: /* send closing message to the display */
1.1.1.2 ! root 433: if ((RetCode = VioWrtTTy(CloseMsg, sizeof(CloseMsg), RESERVED)) != 0)
1.1 root 434: print_err_msg(ErrMsg[ERR_VIOWRTTTY], RetCode);
435:
436: /* if modem connection was made, close it */
437: if (modem())
438: discon_modem();
439:
440: /* close the com port */
1.1.1.2 ! root 441: if ((RetCode = DosClose(FileHndl)) != 0)
1.1 root 442: print_err_msg(ErrMsg[ERR_DOSCLOSECOMPORT], RetCode);
443: }
444:
445:
446:
447:
448: /*** ERROR HANDLING
449: *
450: * There are two error handling routines:
451: * - error() which is invoked from the main thread
452: * - setup_err_msg() which is invoked from the thread executing
453: * the read_com_port() routine
454: * The two routines perform different functions (described below). This
455: * is done so that if an error is encountered "simultaneously" in both
456: * the threads, there will be no race condition in error reporting.
457: *
458: * The following routines are also part of the error handling:
1.1.1.2 ! root 459: * - xit() is a DosExitList routine
1.1 root 460: * - print_err_msg() does the actual printing of the error message
461: *
462: * All the routines discussed above are defined below.
463: *
464: ***/
465:
466:
467:
468: /*** error
469: *
470: * This routine is invoked when there is an error. It prints an
1.1.1.2 ! root 471: * an error message and calls DosExit.
1.1 root 472: *
473: * error(ErrNum, RetCode)
474: *
475: * ENTRY
476: * ErrNum - error number (used as index to error message array)
477: * RetCode - return code from a DOS system/subsystem call
478: *
479: * EXIT
480: * global variables ErrorNumber & ReturnCode still contain the
1.1.1.2 ! root 481: * initial value of -1. At program termination (via DosExit call)
! 482: * the DosExitList routine xit() is invoked (described below).
1.1 root 483: * On return from xit(), this program will terminate.
484: *
485: * WARNING
486: *
487: * EFFECTS
488: *
489: ***/
490:
491: error(ErrNum, RetCode)
492: int ErrNum;
493: int RetCode;
494: {
495: print_err_msg(ErrMsg[ErrNum], RetCode);
1.1.1.2 ! root 496: DosExit(EXIT_PROCESS, 1);
1.1 root 497: }
498:
499:
500:
501:
502: /*** setup_error_msg - setup error message
503: *
1.1.1.2 ! root 504: * Sets up the global ErrorNumber and ReturnCode. It then calls DosExit.
1.1 root 505: *
506: * setup_error_msg(ErrNum, RetCode)
507: *
508: * ENTRY
509: * ErrNum - error number (used as index to error message array)
510: * RetCode - return code from a DOS system/subsystem call
511: *
512: * EXIT
513: * global variables ErrorNumber & ReturnCode are setup. At
1.1.1.2 ! root 514: * program termination (via DosExit call) the DosExitList
1.1 root 515: * routine xit() is invoked (described below). xit() will print
516: * an error message. On return from xit(), this program will
517: * terminate.
518: *
519: * WARNING
520: *
521: * EFFECTS
522: *
523: ***/
524:
525: setup_error_msg(ErrNum, RetCode)
526: int ErrNum,
527: RetCode;
528: {
529: ErrorNumber = ErrNum;
530: ReturnCode = RetCode;
1.1.1.2 ! root 531: DosExit(EXIT_PROCESS, 1);
1.1 root 532: }
533:
534:
535:
536:
537: /*** xit - exit function executed at program termination
538: *
1.1.1.2 ! root 539: * This is a DosExitList routine. It prints an error message if
1.1 root 540: * the global variable ErrorNumber is non-negative.
541: *
542: * xit()
543: *
544: * ENTRY
545: *
546: * EXIT
547: * If ErrorNumber is non-negative, an error message is printed.
548: * The program will then terminate.
549: *
550: * WARNING
551: *
552: * EFFECTS
553: *
554: ***/
555:
1.1.1.2 ! root 556: void far xit(void)
1.1 root 557: {
558: if (ErrorNumber != -1)
559: print_err_msg(ErrMsg[ErrorNumber], ReturnCode);
560: close_conn(); /* close modem connection and the com port */
1.1.1.2 ! root 561: DosExitList(XFER, 0L);
1.1 root 562: }
563:
564:
565:
566:
567: /*** print_err_msg - print error mesage
568: *
569: * This routine prints an error message and the returncode.
570: *
571: * print_err_msg(Msg, Retcode)
572: *
573: * ENTRY
574: * Msg - error message string
575: * Retcode - returncode from DOS system/subsystem call
576: *
577: * EXIT
578: *
579: * WARNING
580: *
581: * EFFECTS
582: *
583: ***/
584:
585: print_err_msg(Msg, RetCode)
586: char *Msg;
587: int RetCode;
588:
589: {
590: printf("*** ERROR %s *** ", Msg);
591: if (RetCode != -1)
592: printf("ReturnCode = %d ", RetCode);
593: printf("\n");
594: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.