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