home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckc072.zip / ckitio.c < prev    next >
C/C++ Source or Header  |  1989-06-19  |  27KB  |  1,166 lines

  1. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  2. /* |_o_o|\\ Copyright (c) 1986 The Software Distillery.  All Rights Reserved */
  3. /* |. o.| || This program may not be distributed without the permission of   */
  4. /* | .  | || the authors.                                                    */
  5. /* | o  | ||    Dave Baker     Ed Burnette  Stan Chow    Jay Denebeim        */
  6. /* |  . |//     Gordon Keener  Jack Rouse   John Toebes  Doug Walker         */
  7. /* ======          BBS:(919)-471-6436      VOICE:(919)-469-4210              */
  8. /*                                                                           */
  9. /* Contributed to Columbia University for inclusion in C-Kermit.             */
  10. /* Permission is granted to any individual or institution to use, copy, or   */
  11. /* redistribute this software so long as it is not sold for profit, provided */
  12. /* this copyright notice is retained.                                        */
  13. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  14.  
  15. char *ckxv = "Amiga tty I/O, 4D(005), 31 Jul 87";
  16.  
  17. /*  C K I T I O  --  Serial and Console I/O support for the Amiga */
  18.  
  19. /*
  20.  Author: Jack Rouse, The Software Distillery
  21.  Based on the CKUTIO.C module for Unix
  22. */
  23.  
  24. #include <stdio.h>        /* standard I/O stuff */
  25. #undef NULL
  26. #include "exec/types.h"
  27. #include "exec/exec.h"
  28. #include "devices/serial.h"
  29. #include "devices/timer.h"
  30. #include "libraries/dos.h"
  31. #include "libraries/dosextens.h"
  32. #define fh_Interact fh_Port
  33. #define fh_Process fh_Type
  34. #include "intuition/intuition.h"
  35. #include "intuition/intuitionbase.h"
  36. #define BREAKSIGS (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)
  37. #ifdef LAT310
  38. #include "fcntl.h"
  39. #include "signal.h"
  40. #include "ios1.h"        /* defines ufbs structure */
  41. #else
  42. #include "lattice/ios1.h"    /* defines ufbs structure */
  43. #endif
  44.  
  45. char *ckxsys = " Commodore Amiga";    /* system name */
  46.  
  47. /* external declarations */
  48. extern int speed, mdmtyp, parity, flow;
  49.  
  50. /* external definitions */
  51. char *dftty = SERIALNAME;        /* serial device name */
  52. int dfloc = 1;                /* serial line is external */
  53. int dfprty = 0;                /* default parity is none */
  54. int ttprty = 0;                /* parity in use */
  55. int dfflow = 1;                /* default flow control is on */
  56. int backgrd = 0;            /* default to foreground */
  57. int ckxech = 0;                /* echo in case redirected stdin */
  58.  
  59. struct Process *CurProc;        /* current process */
  60. struct CommandLineInterface *CurCLI;    /* current CLI info */
  61. extern struct IntuitionBase *IntuitionBase;    /* ptr to Intuition lib */
  62.  
  63. /* static definitions */
  64. static struct MsgPort *serport;        /* message port for serial comm */
  65. static struct MsgPort *conport;        /* console packet port */
  66. static struct timerequest *TimerIOB;    /* timer request */
  67. static struct IOExtSer *ReadIOB;    /* serial input request */
  68. static struct IOExtSer *WriteIOB;    /* serial output request */
  69. static struct DosPacket *conpkt;    /* console I/O packet */
  70. static WORD serialopen;            /* true iff serial device open */
  71. static WORD timeropen;            /* true iff timer device open */
  72. static WORD pendwrite;            /* true iff WriteIOB in use */
  73. static WORD pendread;            /* true iff ReadIOB in use */
  74. static WORD pendconsole;        /* true when console read pending */
  75. static int queuedser;            /* serial pushback char or -1 */
  76. static UBYTE serbufc;            /* char buffer for read ahead I/O */
  77. #define NTTOQ 64            /* connect output queue size */
  78. static char ttoq[NTTOQ];        /* connect output queue */
  79. static int nttoq;            /* number of chars in ttoq */
  80. static int pttoq;            /* next char to output in ttoq */
  81. static int queuedcon;            /* contti pushback char or -1 */
  82. static LONG intsigs;            /* signals for aborting serial I/O */
  83. static int (*inthdlr)();        /* function to signal break to */
  84. static BPTR rawcon;            /* file handle for RAW: window */
  85. static BPTR saverr;                     /* saved stderr file handle */
  86. static APTR savewindow;            /* saved process WindowPtr */
  87. static APTR pushwindow;            /* pushed process WindowPtr */
  88. static struct DateStamp prevtime;    /* saved time value */
  89.  
  90. /* Exec routines */
  91. APTR AllocMem();
  92. LONG AllocSignal();
  93. struct IORequest *CheckIO();
  94. VOID CloseDevice(), CloseLibrary();
  95. LONG DoIO();
  96. struct MsgPort *FindPort();
  97. struct Task *FindTask();
  98. VOID FreeMem(), FreeSignal();
  99. struct Message *GetMsg();
  100. LONG OpenDevice();
  101. struct Library *OpenLibrary();
  102. VOID PutMsg(), ReplyMsg();
  103. VOID SendIO();
  104. LONG SetSignal();
  105. VOID Signal();
  106. LONG Wait();
  107. LONG WaitIO();
  108. struct Message *WaitPort();
  109.  
  110. /* Exec support */
  111. struct IORequest *CreateExtIO();
  112. VOID DeleteExtIO();
  113. struct MsgPort *CreatePort();
  114. VOID DeletePort();
  115. struct Task *CreateTask();
  116. VOID DeleteTask();
  117.  
  118. /* AmigaDOS routines */
  119. VOID Delay();
  120. BPTR Open();
  121. VOID Close();
  122. BPTR Input(), Output();
  123. LONG Read();
  124. LONG WaitForChar();
  125. struct DateStamp *DateStamp();
  126.  
  127. /* AmigaDOS support (from ckiutl.c) */
  128. struct DosPacket *CreatePacket();
  129. VOID DeletePacket();
  130.  
  131. #ifdef LAT310
  132. /* translate Unix file handle (0, 1, or 2) to AmigaDOS file handle */
  133. #define DOSFH(n) fileno(&_iob[n])
  134. /* translate Unix file handle (0, 1, or 2) to Lattice file handle */
  135. #define FILENO(n) fileno(&_iob[n])
  136. #else
  137. /* Lattice runtime externals */
  138. extern struct UFB _ufbs[];
  139. extern int Enable_Abort;
  140. #define DOSFH(n) (_ufbs[n].ufbfh)
  141. #define FILENO(n) (n)
  142. #endif
  143.  
  144. /*
  145.  * make note of a serial error and quit
  146.  */
  147. static Fail(msg)
  148. char *msg;
  149. {
  150.     syscleanup();
  151.     fprintf(stderr, msg);
  152.     fprintf(stderr, "\n");
  153.     exit(2);
  154. }
  155. /*
  156.  * default interrupt handler
  157.  */
  158. static int defhdlr()
  159. {
  160.     printf("*** BREAK ***\n");
  161.     doexit(1);
  162. }
  163.  
  164. /*
  165.  *  sysinit -- Amiga specific initialization
  166.  */
  167. sysinit()
  168. {
  169.     register struct IOExtSer *iob;
  170.  
  171.     /* set current process info */
  172.     CurProc = (struct Process *)FindTask((char *)NULL);
  173.     CurCLI = (struct CommandLineInterface *)BADDR(CurProc->pr_CLI);
  174.     backgrd = (CurCLI == NULL || CurCLI->cli_Background);
  175.     savewindow = CurProc->pr_WindowPtr;
  176.  
  177.     /* default interrupts to exit handler */
  178.     intsigs = BREAKSIGS;
  179.     inthdlr = defhdlr;
  180. #ifdef LAT310
  181.     signal(SIGINT, SIG_IGN);
  182. #else
  183.     Enable_Abort = 0;
  184. #endif
  185.  
  186.     /* allocate console ports and IO blocks */
  187.     if ((conport = CreatePort((char *)NULL, 0L)) == NULL)
  188.         Fail("no console MsgPort");
  189.     if ((conpkt = CreatePacket()) == NULL)
  190.         Fail("no console packet");
  191.  
  192.     /* allocate serial ports and IO blocks */
  193.     if ((serport = CreatePort((char *)NULL, 0L)) == NULL)
  194.         Fail("no serial MsgPort");
  195.     iob = (struct IOExtSer *)CreateExtIO(serport,(LONG)sizeof(*iob));
  196.     if ((WriteIOB = iob) == NULL) Fail("no WriteIOB");
  197.     iob = (struct IOExtSer *)CreateExtIO(serport,(LONG)sizeof(*iob));
  198.     if ((ReadIOB = iob) == NULL) Fail("no ReadIOB");
  199.  
  200.     /* open the timer device */
  201.     TimerIOB = (struct timerequest *)
  202.            CreateExtIO(serport,(LONG)sizeof(*TimerIOB));
  203.     if (TimerIOB == NULL) Fail("no TimerIOB");
  204.     if (OpenDevice(TIMERNAME, (LONG)UNIT_VBLANK, TimerIOB, 0L) != 0)
  205.         Fail("no timer device");
  206.     timeropen = TRUE;
  207.  
  208.     /* open the Intuition library */
  209.     if (!IntuitionBase &&
  210.         (IntuitionBase = (struct IntuitionBase *)
  211.                  OpenLibrary("intuition.library", 0L) ) == NULL )
  212.         Fail("can't open Intuition");
  213.  
  214.     /* open the serial device to get configuration */
  215.     iob->io_SerFlags = SERF_SHARED;
  216.     if (OpenDevice(SERIALNAME, 0L, iob, 0L) != 0)
  217.         Fail("can't open serial.device");
  218.     /* set parameters from system defaults */
  219.     flow   = !(iob->io_SerFlags & SERF_XDISABLED);
  220.     parity = !(iob->io_SerFlags & SERF_PARTY_ON) ? 0 :
  221.          (iob->io_SerFlags & SERF_PARTY_ODD) ? 'o' : 'e';
  222.     speed  = iob->io_Baud;
  223.     mdmtyp = (iob->io_SerFlags & SERF_7WIRE) != 0;
  224.  
  225.     CloseDevice(iob);
  226.     serialopen = FALSE;
  227.     return(0);
  228. }
  229.  
  230. /*
  231.  * syscleanup -- Amiga specific cleanup
  232.  */
  233. syscleanup()
  234. {
  235.     /* close everything */
  236.     if (serialopen) CloseDevice(ReadIOB);
  237.     if (timeropen) CloseDevice(TimerIOB);
  238.     if (TimerIOB) DeleteExtIO(TimerIOB, (LONG)sizeof(*TimerIOB));
  239.     if (WriteIOB) DeleteExtIO(WriteIOB, (LONG)sizeof(*WriteIOB));
  240.     if (ReadIOB) DeleteExtIO(ReadIOB, (LONG)sizeof(*ReadIOB));
  241.     if (serport) DeletePort(serport);
  242.     if (conpkt) DeletePacket(conpkt);
  243.     if (conport) DeletePort(conport);
  244.     reqres();
  245.     if (IntuitionBase)
  246.     {
  247.         CloseLibrary(IntuitionBase);
  248.         IntuitionBase = NULL;
  249.     }
  250.  
  251.     /* reset standard I/O */
  252.     if (rawcon > 0)
  253.     {
  254.         /* restore Lattice AmigaDOS file handles */
  255.         DOSFH(0) = Input();
  256.         DOSFH(1) = Output();
  257.         DOSFH(2) = saverr;
  258. #ifdef LAT310
  259.         close(rawcon);
  260. #else
  261.         Close(rawcon);
  262. #endif
  263.     }
  264. }
  265.  
  266. /*
  267.  * reqoff -- turn requestors off
  268.  *    When AmigaDOS encounters an error that user intervention can fix
  269.  *    (like inserting the correct disk), it normally puts up a requestor.
  270.  *    The following code disables requestors, causing an error to be
  271.  *    returned instead.
  272.  */
  273. reqoff()
  274. {
  275.     pushwindow = CurProc->pr_WindowPtr;
  276.     CurProc->pr_WindowPtr = (APTR)-1;
  277. }
  278. /*
  279.  * reqpop -- restore requesters to action at last reqoff
  280.  */
  281. reqpop()
  282. {
  283.     CurProc->pr_WindowPtr = pushwindow;
  284. }
  285.  
  286. /*
  287.  * reqres -- restore requestors to startup action
  288.  */
  289. reqres()
  290. {
  291.     CurProc->pr_WindowPtr = savewindow;
  292. }
  293.  
  294. /*
  295.  * KillIO -- terminate an I/O request
  296.  */
  297. static int KillIO(iob)
  298. struct IORequest *iob;
  299. {
  300.     AbortIO(iob);
  301.     return(WaitIO(iob));
  302. }
  303.  
  304. /*
  305.  * DoIOQuick -- DoIO with quick IO
  306.  * This should not be used where waiting is expected since
  307.  *    it cannot be interrupted.
  308.  */
  309. static int DoIOQuick(iob)
  310. register struct IORequest *iob;
  311. {
  312.     register int D7Save;    /* V1.1 bug. IO sometimes trashes D7 */
  313.  
  314.     /* do I/O with quick option, wait around if necessary */
  315.     iob->io_Flags = IOF_QUICK;
  316.     if (BeginIO(iob) == 0 && !(iob->io_Flags & IOF_QUICK))
  317.         WaitIO(iob);
  318.  
  319.     /* return the error, if any */
  320.     return((int)iob->io_Error);
  321. }
  322.  
  323. /*
  324.  * ttopen -- open the serial device
  325.  *    If already open, returns 0 immediately.
  326.  *    Otherwise, the ttname is compare to SERIALNAME and used to
  327.  *    open the serial device, and, if the value of *lcl is < 0, it is
  328.  *    reset to 1 indicating local mode.  Returns -1 on error.
  329.  */
  330. ttopen(ttname, lcl, modem)
  331. char *ttname;
  332. int *lcl;
  333. int modem;
  334. {
  335.     register struct IOExtSer *iob = ReadIOB;
  336.  
  337.     if (serialopen) return(0);    /* ignore if already open */
  338.  
  339.     /* verify the serial name */
  340.     if (strcmp(ttname, SERIALNAME) != 0) return(-1);
  341.  
  342.     /* set open modes */
  343.     iob->io_SerFlags = (modem) ? (SERF_SHARED|SERF_7WIRE) : SERF_SHARED;
  344.  
  345.     /* open the serial device */
  346.     if (OpenDevice(ttname, 0L, iob, 0L) != 0) return(-1);
  347.     serialopen = TRUE;
  348.     pendread = pendwrite = pendconsole = FALSE;
  349.     queuedser = -1;
  350.  
  351.     /* fill in the fields of the other IO blocks */
  352.     *WriteIOB = *iob;
  353.  
  354.     /* set local mode */
  355.     if (*lcl == -1)    *lcl = 1; /* always local */
  356.     return(0);
  357. }
  358.  
  359. /*
  360.  * StartTimer -- start a timeout
  361.  */
  362. static VOID StartTimer(secs, micro)
  363. LONG secs, micro;
  364. {
  365.     TimerIOB->tr_node.io_Command = TR_ADDREQUEST;
  366.     TimerIOB->tr_time.tv_secs  = secs;
  367.     TimerIOB->tr_time.tv_micro = micro;
  368.     SendIO(TimerIOB);
  369. }
  370.  
  371. /*
  372.  * SerialWait -- wait for serial I/O to terminate
  373.  *    return I/O error
  374.  */
  375. static int SerialWait(iob, timeout)
  376. register struct IOExtSer *iob;
  377. int timeout;
  378. {
  379.     register int D7Save;        /* save register D7 */
  380.     register LONG sigs;
  381.     register struct timerequest *timer = TimerIOB;
  382.     register LONG waitsigs;
  383.  
  384.     /* set up timeout if necessary */
  385.     if (timeout > 0) StartTimer((LONG)timeout, 0L);
  386.  
  387.     /* wait for completion, timeout, or interrupt */
  388.     sigs = 0;
  389.     waitsigs = (1L << serport->mp_SigBit) | intsigs;
  390.     for (;;)
  391.     {
  392.         if (sigs & intsigs)
  393.         {    /* interrupted */
  394.             if (timeout > 0) KillIO(timer);
  395.             KillIO(iob);
  396.             testint(sigs);
  397.             return(-1);
  398.         }
  399.         if (CheckIO(iob))
  400.         {
  401.             if (timeout > 0) KillIO(timer);
  402.             return(WaitIO(iob));
  403.         }
  404.         if (timeout > 0 && CheckIO(timer))
  405.         {
  406.             KillIO(iob);
  407.             WaitIO(timer);
  408.             /* restart if XOFF'ed */
  409.             iob->IOSer.io_Command = CMD_START;
  410.             DoIOQuick(iob);
  411.             return(-1);
  412.         }
  413.         sigs = Wait(waitsigs);
  414.     }
  415. }
  416.  
  417. /*
  418.  * TerminateRead -- wait for queued read to finish
  419.  */
  420. static int TerminateRead()
  421. {
  422.     if (!pendread) return(0);
  423.     if (WaitIO(ReadIOB) == 0) queuedser = serbufc;
  424.     pendread = FALSE;
  425.     return((int)ReadIOB->IOSer.io_Error);
  426. }
  427.  
  428. /*
  429.  * TerminateWrite -- ensure WriteIOB is ready for reuse
  430.  */
  431. static int TerminateWrite(timeout)
  432. int timeout;
  433. {
  434.     testint(0L);
  435.     if (!pendwrite) return(0);
  436.     pendwrite = FALSE;
  437.     return(SerialWait(WriteIOB, timeout));
  438. }
  439.  
  440. /*
  441.  * SerialReset -- terminate pending serial and console I/O
  442.  */ 
  443. static VOID SerialReset()
  444. {
  445.     if (pendread)
  446.     {
  447.         AbortIO(ReadIOB); /* should work even if read finished */
  448.         TerminateRead();
  449.     }
  450.  
  451.     if (pendconsole)
  452.     {    /* this does not happen normally */
  453.         WaitPort(conport);
  454.         GetMsg(conport);
  455.         pendconsole = FALSE;
  456.     }
  457.  
  458.     if (pendwrite)
  459.         TerminateWrite(1);
  460. }
  461.  
  462. /*
  463.  * ttres -- reset serial device
  464.  */
  465. ttres()
  466. {
  467.     if (!serialopen) return(-1);
  468.  
  469.     /* reset everything */
  470.     SerialReset();
  471.     ReadIOB->IOSer.io_Command = CMD_RESET;
  472.     return(DoIOQuick(ReadIOB) ? -1 : 0);
  473. }
  474.  
  475. /*
  476.  * ttclos -- close the serial device
  477.  */
  478. ttclos()
  479. {
  480.     if (!serialopen) return(0);
  481.     if (ttres() < 0) return(-1);
  482.     CloseDevice(ReadIOB);
  483.     serialopen = FALSE;
  484.     return(0);
  485. }
  486.  
  487. /*
  488.  * tthang -- hang up phone line
  489.  *    Drops DTR by closing serial.device
  490.  */
  491. tthang()
  492. {    return((serialopen) ? ttclos() : -1); }
  493.  
  494. /*
  495.  * ttpkt -- set serial device up for packet transmission
  496.  *    sets serial parameters
  497.  */
  498. ttpkt(baud, flow)
  499. int baud, flow;
  500. {
  501.     extern UBYTE eol;
  502.     register struct IOExtSer *iob = ReadIOB;
  503.     int speed;
  504.  
  505.     if (!serialopen || pendread) return(-1);
  506.  
  507.     /* terminate any pending writes */
  508.     TerminateWrite(1);
  509.  
  510.     /* fill in parameters */
  511.     iob->io_CtlChar = 0x11130000;
  512.     if (baud >= 0 && (speed = ttsspd(baud)) >= 0) iob->io_Baud = speed;
  513.     setmem(&iob->io_TermArray, sizeof(struct IOTArray), eol);
  514.     iob->io_ReadLen = iob->io_WriteLen = 8;
  515.     iob->io_StopBits = 1;
  516.     if (flow)
  517.         iob->io_SerFlags &= ~SERF_XDISABLED;
  518.     else
  519.         iob->io_SerFlags |= SERF_XDISABLED;
  520.     /* if no flow and high baud rate, RAD_BOOGIE is appropriate */
  521.     if (!flow && iob->io_Baud > 19200)
  522.         iob->io_SerFlags |= SERF_RAD_BOOGIE;
  523.     else
  524.         iob->io_SerFlags &= ~SERF_RAD_BOOGIE;
  525.     iob->io_SerFlags &= ~(SERF_EOFMODE|SERF_PARTY_ON|SERF_PARTY_ODD);
  526.  
  527.     /* set the parameters */
  528.     iob->IOSer.io_Command = SDCMD_SETPARAMS;
  529.     if (DoIOQuick(iob) != 0) return(-1);
  530.     return(ttflui());
  531. }
  532.  
  533. /*
  534.  * ttvt -- set up serial device for connect mode
  535.  */
  536. ttvt(baud, flow)
  537. int baud, flow;
  538. {    return(ttpkt(baud, flow)); }
  539.  
  540. /*
  541.  * ttsspd -- verify baud rate
  542.  */
  543. int ttsspd(speed)
  544. {
  545.     if (speed < 110 || speed > 292000) return(-1);
  546.     return(max(112, speed));
  547. }
  548.  
  549. /*
  550.  * ttflui -- flush serial device input buffer
  551.  */
  552. ttflui()
  553. {
  554.     if (!serialopen || pendread) return(-1);
  555.     queuedser = -1;
  556.     ReadIOB->IOSer.io_Command = CMD_CLEAR;
  557.     return(DoIOQuick(ReadIOB) ? -1 : 0);
  558. }
  559.  
  560.  
  561. static struct IntuiText BodyText = {
  562.     -1, -1, 0, 4, 4, NULL, "Interrupt Requested", NULL
  563. };
  564.  
  565. static struct IntuiText ContinueText = {
  566.     -1, -1, 0, 4, 4, NULL, "Continue", NULL
  567. };
  568.  
  569. static struct IntuiText AbortText = {
  570.     -1, -1, 0, 4, 4, NULL, "Exit C-Kermit", NULL
  571. };
  572.  
  573. /*
  574.  * test for and catch interrupt
  575.  */
  576. testint(sigs)
  577. LONG sigs;
  578. {
  579.     int (*catch)();
  580.  
  581.     /* test for and reset caught interrupt signals */
  582.     if (((sigs | SetSignal(0L, (LONG)BREAKSIGS)) & intsigs) && inthdlr)
  583.     {
  584.         if (AutoRequest((struct Window *)NULL,
  585.                 &BodyText,
  586.                 &ContinueText,
  587.                 &AbortText,
  588.                 0L, 0L, 260L, 55L) )
  589.             return;
  590.         catch = inthdlr;
  591.         inthdlr = NULL;
  592.         intsigs = 0;
  593.         (*catch)();
  594.     }
  595. }
  596.  
  597. /*
  598.  * conint -- set console interrupt handler
  599.  */
  600. conint(newhdlr)
  601. int (*newhdlr)();
  602. {
  603.     testint(0L);            /* handle any pending interrupts */
  604.     inthdlr = newhdlr;        /* set the new handler */
  605.     intsigs = BREAKSIGS;        /* note signal caught */
  606. }
  607.  
  608. /*
  609.  * connoi -- disable interrupt trapping
  610.  */
  611. connoi()
  612. {
  613.     inthdlr = NULL;            /* disable interrupts */
  614.     intsigs = 0;            /* note signal ignored */
  615.     testint(0L);            /* ignore pending interrupts */
  616. }
  617.  
  618. /*
  619.  * ttchk -- return number of chars immediately available from serial device
  620.  */ 
  621. ttchk()
  622. {
  623.     register struct IOExtSer *read = ReadIOB;
  624.  
  625.     if (!serialopen) return(-1);
  626.     testint(0L);
  627.     if (pendread && !CheckIO(read)) return(0);
  628.     if (TerminateRead() != 0) return(-1);
  629.     read->IOSer.io_Command = SDCMD_QUERY;
  630.     return((DoIOQuick(read) == 0)
  631.             ? ((queuedser >= 0) + (int)read->IOSer.io_Actual)
  632.             : -1);
  633. }
  634.  
  635. /*
  636.  * ttxin -- get n characters from serial device
  637.  */
  638. ttxin(n, buf)
  639. int n;
  640. char *buf;
  641. {    return(ttinl(buf, n, 0, -1)); }
  642.  
  643. /*
  644.  * ttinc -- read character from serial line
  645.  */
  646. ttinc(timeout)
  647. int timeout;
  648. {
  649.     UBYTE ch;
  650.  
  651.     return((ttinl(&ch, 1, timeout, -1) > 0) ? (int)ch : -1);
  652. }
  653.  
  654. /*
  655.  * ttol -- write n chars to serial device, assumes <= 256 characters
  656.  */
  657. ttol(buf, n)
  658. char *buf;
  659. int n;
  660. {
  661.     register int D7Save;
  662.     register struct IOExtSer *write = WriteIOB;
  663.     static char outbuf[256];    /* safe place for output characters */
  664.  
  665.     if (!serialopen) return(-1);
  666.     if (TerminateWrite(0) != 0) return(-1);
  667.     pendwrite = TRUE;
  668.     movmem(buf, outbuf, n);
  669.     write->IOSer.io_Command = CMD_WRITE;
  670.     write->IOSer.io_Data    = (APTR)outbuf;
  671.     write->IOSer.io_Length  = n;
  672.     SendIO(write);
  673.     return(n);
  674. }
  675.  
  676. /*
  677.  * ttoc -- output single character to serial device
  678.  */
  679. ttoc(c)
  680. char c;
  681. {    return(ttol(&c, 1)); }
  682.  
  683. /*
  684.  * ttinl -- read from serial device, possibly with timeout and eol character
  685.  *    reads up to n characters, returning the number of characters read
  686.  *    if eol >= 0, reading the eol character will terminate read
  687.  *    if timeout > 0, terminates read if timeout elapses
  688.  *    returns -1 on error, such as timeout or interrupt
  689.  */
  690. ttinl(buf, n, timeout, eol)
  691. register char *buf;
  692. int n;
  693. int timeout;                /* timeout in seconds or <= 0 */
  694. int eol;                /* end of line character */
  695. {
  696.         int m;
  697.     register int D7Save;
  698.     register struct IOExtSer *read = ReadIOB;
  699.     register int count;
  700.  
  701.     testint(0L);
  702.      if (!serialopen || pendread || n <= 0) return(-1);
  703.  
  704.     m = (ttprty ? 0177 : 0377);    /* parity stripping mask */
  705.  
  706.     /* handle pushback */
  707.     if (queuedser >= 0)
  708.     {
  709.         *buf = queuedser;
  710.         queuedser = -1;
  711.         if ((*buf & 0177) == eol || n == 1) return(1);
  712.         ++buf;
  713.         --n;
  714.         count = 1;
  715.     }
  716.     else
  717.         count = 0;
  718.  
  719.     /* set up line terminator */
  720.     if (eol >= 0)
  721.     {
  722.         /* set up line terminator */
  723. /*** Watch out -- need to recognize 7-bit eol, even if it comes in with ***/
  724. /*** parity bit on.  It's not obvious to me how to change this code to  ***/
  725. /*** do that!   - Frank, C-Kermit 4E ***/
  726.  
  727.         if (eol != *(UBYTE *)&read->io_TermArray)
  728.         {
  729.             setmem(&read->io_TermArray,
  730.                    sizeof(struct IOTArray), eol);
  731.             read->IOSer.io_Command = SDCMD_SETPARAMS;
  732.             DoIOQuick(read);
  733.         }
  734.         read->io_SerFlags |= SERF_EOFMODE;
  735.     }
  736.     else
  737.         read->io_SerFlags &= ~SERF_EOFMODE;
  738.  
  739.     /* set up the read */
  740.     read->IOSer.io_Command = CMD_READ;
  741.     read->IOSer.io_Data    = (APTR)buf;
  742.     read->IOSer.io_Length  = n;
  743.  
  744.     /* perform read quickly if possible */
  745.     read->IOSer.io_Flags = IOF_QUICK;
  746.     BeginIO(read);
  747.     if (read->IOSer.io_Flags & IOF_QUICK)
  748.     {
  749.         read->IOSer.io_Flags = 0;
  750.         return ((read->IOSer.io_Error == 0)
  751.             ? (count + (int)read->IOSer.io_Actual)
  752.             : -1);
  753.     }
  754.  
  755. /*** Need code somewhere here to strip parity if ttprty != 0 ***/
  756.  
  757.     /* wait for read to complete */
  758.     return ((SerialWait(read, timeout) != 0)
  759.         ? -1
  760.         : count + (int)read->IOSer.io_Actual );
  761. }
  762.  
  763. /*
  764.  * Sleeper -- perform an interruptible timeout
  765.  */
  766. static Sleeper(secs, micro)
  767. LONG secs, micro;
  768. {
  769.     register int D7Save;
  770.     register LONG sigs;
  771.     register LONG waitsigs;
  772.     register struct timerequest *timer = TimerIOB;
  773.  
  774.     if (!timeropen) return(-1);
  775.     StartTimer(secs, micro);
  776.     sigs = 0;
  777.     waitsigs = (1L << serport->mp_SigBit) | intsigs;
  778.     for (;;)
  779.     {
  780.         if (CheckIO(timer))
  781.         {
  782.             WaitIO(timer);
  783.             return(0);
  784.         }
  785.         if (sigs & intsigs)
  786.         {
  787.             KillIO(timer);
  788.             testint(sigs);
  789.             return(-1);
  790.         }
  791.         sigs = Wait(waitsigs);
  792.     }
  793. }
  794.  
  795. /*
  796.  * sleep -- wait n seconds
  797.  */
  798. sleep(n)
  799. int n;
  800. {    return(Sleeper((LONG)n, 0L)); }
  801.  
  802. /*
  803.  * msleep -- wait n milliseconds
  804.  */
  805. msleep(m)
  806. int m;
  807. {    return(Sleeper((LONG)(m / 1000), (m % 1000) * 1000L)); } 
  808.  
  809.  
  810. /*
  811.  * rtimer -- reset elapsed time
  812.  */
  813. rtimer()
  814. {    DateStamp(&prevtime); }
  815.  
  816. /*
  817.  * gtimer -- get currently elapsed time in seconds
  818.  */
  819. gtimer()
  820. {
  821.     int x;
  822.     struct DateStamp curtime;
  823.  
  824.     DateStamp(&curtime);
  825.     x = ((curtime.ds_Days   - prevtime.ds_Days  ) * 1440 +
  826.          (curtime.ds_Minute - prevtime.ds_Minute) ) * 60 +
  827.          (curtime.ds_Tick   - prevtime.ds_Tick  ) / 50;
  828.     return((x < 0) ? 0 : x );
  829. }
  830.  
  831. /*
  832.  * ztime -- format current date and time into string
  833.  */
  834. ztime(s)
  835. char **s;
  836. {
  837.    /*
  838.     * The following date code taken from a USENET article by
  839.     *    Tomas Rokicki(rokicki@Navajo.ARPA)
  840.     */
  841.    static char *months[] = { NULL,
  842.       "January","February","March","April","May","June",
  843.       "July","August","September","October","November","December"};
  844.    static char buf[32];
  845.  
  846.    long n ;
  847.    int m, d, y ;
  848.    struct DateStamp datetime;
  849.  
  850.    DateStamp(&datetime);
  851.  
  852.    n = datetime.ds_Days - 2251 ;
  853.    y = (4 * n + 3) / 1461 ;
  854.    n -= 1461 * y / 4 ;
  855.    y += 1984 ;
  856.    m = (5 * n + 2) / 153 ;
  857.    d = n - (153 * m + 2) / 5 + 1 ;
  858.    m += 3 ;
  859.    if (m > 12) {
  860.       y++ ;
  861.       m -= 12 ;
  862.    }
  863.    sprintf(buf, "%02d:%02d:%02d %s %d, %d",
  864.            datetime.ds_Minute / 60, datetime.ds_Minute % 60,
  865.        datetime.ds_Tick / 50, months[m], d, y) ;
  866.    *s = buf;
  867. }
  868.  
  869. /*
  870.  * congm -- save console modes
  871.  */
  872. congm()
  873. {
  874.     if (!saverr) saverr = DOSFH(2);
  875.     return(0);
  876. }
  877.  
  878. /*
  879.  * CreateWindow -- create window and jam it into standard I/O
  880.  */
  881. int CreateWindow(esc)
  882. {
  883.     if (rawcon > 0) return(0);
  884.     congm();
  885.  
  886. #ifdef LAT310
  887.     if ((rawcon = open("RAW:0/0/640/200/Kermit", O_RDWR)) <= 0)
  888.         return(-1);
  889. #else
  890.     if ((rawcon = Open("RAW:0/0/640/200/Kermit", (LONG)MODE_NEWFILE)) == 0)
  891.         return(-1);
  892. #endif
  893.     DOSFH(0) = DOSFH(1) = DOSFH(2) = rawcon;
  894.  
  895.     /* if we create a window, don't abort on errors or echo */
  896.     backgrd = FALSE;
  897.     ckxech = 1;
  898.     return(0);
  899. }
  900.  
  901. /*
  902.  * concb -- put console in single character wakeup mode
  903.  */
  904. concb(esc)
  905. {
  906.     if (rawcon) return(0);
  907.     if (CurCLI && CurProc->pr_CIS != CurCLI->cli_StandardInput)
  908.         return(0);
  909.     return(CreateWindow(esc));
  910. }
  911.  
  912. /*
  913.  * conbin -- put console in raw mode
  914.  */
  915. conbin(esc)
  916. {
  917.     if (rawcon) return(0);
  918.     if (CurCLI && CurProc->pr_CIS != CurCLI->cli_StandardInput)
  919.         return(isatty(0) ? 0 : -1);
  920.     return(CreateWindow(esc));
  921. }
  922.  
  923. /*
  924.  * conres -- restore console
  925.  *    we actually restore in syscleanup()
  926.  */
  927. conres()
  928. {    return(0); }
  929.  
  930. /*
  931.  * conoc -- output character to console
  932.  */
  933. conoc(c)
  934. {
  935.     putchar(c);
  936.     fflush(stdout);
  937.     testint(0L);
  938. }
  939.  
  940. /*
  941.  * conxo -- output x chars to console
  942.  */ 
  943. conxo(n, buf)
  944. char *buf;
  945. int n;
  946. {
  947.     fflush(stdout);
  948.     write(FILENO(1), buf, n);
  949.     testint(0L);
  950. }
  951.  
  952. /*
  953.  * conol -- output line to console
  954.  */
  955. conol(l)
  956. char *l;
  957. {
  958.     fputs(l, stdout);
  959.     fflush(stdout);
  960.     testint(0L);
  961. }
  962.  
  963. /*
  964.  * conola -- output line array to console
  965.  */
  966. conola(l)
  967. char **l;
  968. {
  969.     for (; **l; ++l) conol(*l);
  970. }
  971.  
  972. /*
  973.  * conoll -- output line with CRLF
  974.  */
  975. conoll(l) char *l;
  976. {
  977.     conol(l);
  978.     conxo(2, "\r\n");
  979. }
  980.  
  981. /*
  982.  * conchk -- returns nonzero if characters available from console
  983.  */
  984. conchk()
  985. {
  986.     fflush(stdout);
  987.     testint(0L);
  988.     return(WaitForChar(DOSFH(0), 0L) != 0);
  989. }
  990.  
  991. /*
  992.  * coninc -- get input character from console
  993.  */
  994. coninc(timeout)
  995. int timeout;
  996. {
  997.     UBYTE ch;
  998.  
  999.     fflush(stdout);
  1000.     testint(0L);
  1001.     if (timeout > 0 && !WaitForChar(DOSFH(0), timeout * 1000000L))
  1002.         return(-1);
  1003.     if (read(FILENO(0), &ch, 1) < 1) return(-1);
  1004.     testint(0L);
  1005.     return((int)ch);
  1006. }
  1007.  
  1008. /*
  1009.  * ttsndb -- send a BREAK
  1010.  *    flushes queued and active output
  1011.  */
  1012. ttsndb()
  1013. {
  1014.     register int D7Save;
  1015.  
  1016.     if (!serialopen) return(-1);
  1017.     /* flush queued output */
  1018.     TerminateWrite(1);
  1019.     nttoq = 0;
  1020.     pendwrite = TRUE;
  1021.     WriteIOB->IOSer.io_Command = SDCMD_BREAK;
  1022.     WriteIOB->io_SerFlags &= ~SERF_QUEUEDBRK;
  1023.     SendIO(WriteIOB);
  1024.     return(0);
  1025. }
  1026.  
  1027. /*
  1028.  * ttocq -- write char to serial device, queueing if necessary
  1029.  *    returns -2 on overrun, -1 on serial error
  1030.  *    use only in connect mode
  1031.  */
  1032. ttocq(c)
  1033. char c;
  1034. {
  1035.     register int i;
  1036.  
  1037.     if (!serialopen) return(-1);
  1038.     if (pendwrite && CheckIO(WriteIOB))
  1039.     {
  1040.         pendwrite = FALSE;
  1041.         if (WaitIO(WriteIOB) != 0) return(-1);
  1042.     }
  1043.     if (pendwrite)
  1044.     {
  1045.         if (nttoq >= NTTOQ) return(-2);        /* overrun */
  1046.         ttoq[(pttoq + nttoq++) % NTTOQ] = c;
  1047.     }
  1048.     else if (nttoq == 0)
  1049.         return(ttoc(c));
  1050.     else
  1051.     {
  1052.         i = ttoc(ttoq[pttoq]);
  1053.         ttoq[(pttoq + nttoq) % NTTOQ] = c;
  1054.         pttoq = (pttoq + 1) % NTTOQ;
  1055.         if (i < 0) return(-1);
  1056.     }
  1057.     return(1);
  1058. }
  1059.  
  1060. /*
  1061.  * ttonq -- returns number of characters in serial output queue
  1062.  */
  1063. int ttonq()
  1064. {    return(nttoq); }
  1065.  
  1066. /*
  1067.  * conttb -- prepare for contti() usage
  1068.  */
  1069. conttb()
  1070. {
  1071.     /* flush queued input and output */
  1072.     queuedcon = -1;
  1073.     pttoq = nttoq = 0;
  1074. }
  1075.  
  1076. /*
  1077.  * contte -- end contti() usage
  1078.  *    this can be called after a tthang, it which case ttres will already
  1079.  *    have done this cleanup
  1080.  */
  1081. contte()
  1082. {
  1083.     /* clear any pending ^C, ^D interrupts */
  1084.     testint(0L);
  1085.  
  1086.     /* terminate any pending I/O */
  1087.     if (serialopen) SerialReset();
  1088. }
  1089.  
  1090. /*
  1091.  * contti -- wait for console or tty input
  1092.  *    returns next console input or -1 when serial input available
  1093.  */
  1094. int contti()
  1095. {
  1096.     register int D7Save;
  1097.     register int i;
  1098.     register LONG waitsigs;
  1099.     register struct DosPacket *pkt = conpkt;
  1100.     register struct IOExtSer *read = ReadIOB;
  1101.     static UBYTE conchar;
  1102.     BPTR dosfh = DOSFH(0);
  1103.     struct FileHandle *fh = (struct FileHandle *)BADDR(dosfh);
  1104.  
  1105.     if (queuedcon >= 0)
  1106.     {
  1107.         conchar = queuedcon;
  1108.         queuedcon = -1;
  1109.         return((int)conchar);
  1110.     }
  1111.  
  1112.     if (!pendconsole)
  1113.     {    /* start a console read */
  1114.         pkt->dp_Port = conport;
  1115.         pkt->dp_Type = ACTION_READ;
  1116.         pkt->dp_Arg1 = (LONG)dosfh;
  1117.         pkt->dp_Arg2 = (LONG)&conchar;
  1118.         pkt->dp_Arg3 = 1;
  1119.         PutMsg(fh->fh_Process, pkt->dp_Link);
  1120.         pendconsole = TRUE;
  1121.     }
  1122.  
  1123.     if (queuedser < 0 && !pendread)
  1124.     {    /* start a serial read */
  1125.         read->IOSer.io_Command = CMD_READ;
  1126.         read->IOSer.io_Data    = (APTR)&serbufc;
  1127.         read->IOSer.io_Length  = 1;
  1128.         SendIO(read);
  1129.         pendread = TRUE;
  1130.     }
  1131.  
  1132.     waitsigs = (1L << serport->mp_SigBit) | (1L << conport->mp_SigBit);
  1133.     for (;;)
  1134.     {
  1135.         if (pendwrite && CheckIO(WriteIOB))
  1136.         {
  1137.             pendwrite = FALSE;
  1138.             if (nttoq > 0)
  1139.             {
  1140.                 i = ttoc(ttoq[pttoq]);
  1141.                 pttoq = (pttoq + 1) % NTTOQ;
  1142.                 --nttoq;
  1143.                 if (i < 0) return(-1);
  1144.             }
  1145.         }
  1146.  
  1147.         /* give the console first chance */
  1148.         if (GetMsg(conport))
  1149.         {
  1150.             pendconsole = FALSE;
  1151.             if (pkt->dp_Res1 != 1) return(-1);
  1152.             /* translate CSI to ESC [ */
  1153.             if (conchar == 0x9B)
  1154.             {    conchar = 0x1B; queuedcon = '['; }
  1155.             return((int)conchar);
  1156.         }
  1157.  
  1158.         if (queuedser >= 0) return(-2);
  1159.  
  1160.         if (CheckIO(read))
  1161.             return((TerminateRead() == 0) ? -2 : -1);
  1162.  
  1163.         Wait(waitsigs);
  1164.     }
  1165. }
  1166.