Annotation of os2sdk/demos/apps/terminal/terminal.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.