Annotation of os2sdk/demos/apps/terminal/terminal.c, revision 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.