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