home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckc190.zip / ckitio.c < prev    next >
C/C++ Source or Header  |  1994-10-08  |  45KB  |  1,739 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 $Id: ckitio.c,v 1.14 94/10/04 22:42:58 swalton Exp Locker: swalton $";
  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.  * srw@csun.edu.  Further mods documented in ckiker.upd.
  26.  *
  27.  
  28.  $Log:    ckitio.c,v $
  29.  * Revision 1.14  94/10/04  22:42:58  swalton
  30.  * Minor mod to flow control:  if flow is not FLO_XONX or FLO_RTSC then
  31.  * we use NONE, without error message;  this is how ck9tio.c does it.
  32.  * 
  33.  * Revision 1.13  94/09/27  05:28:23  swalton
  34.  * ttsspd() was a no-op, somehow.  I think the old code was taking advantage
  35.  * of the fact that pre-5A versions of C Kermit never called ttsspd, but
  36.  * rather always went through either ttpkt() or ttvt().  It works now.
  37.  * 
  38.  * Revision 1.12  94/09/11  09:44:24  swalton
  39.  * Fixed timeout in ttinl.  There was (again) no Wait() on the timer signal
  40.  * bit, so it never really timed out.  Evidence:  try to receive a file
  41.  * with no connection and modem off.  It hangs up.
  42.  *    Deleted ttwmdm() as it is no longer needed.  Wrote ttgmdm() so it works
  43.  * instead of returning 'not implemented.'
  44.  * 
  45.  * Revision 1.11  94/07/29  12:25:35  swalton
  46.  * Changed both timers to use the RKM CreateTimer() and DeleteTimer() routines
  47.  * for cleanliness sake.  In looking at the code, I also realized that
  48.  * Sleeper() should be Wait()'ing on the SigBit in the MsgPort for the
  49.  * timer, not the serial port (as it was).  Not sure how this could have
  50.  * worked at all up until now!
  51.  * 
  52.  * Revision 1.10  94/07/26  16:39:36  swalton
  53.  * Added code for local alarm() function to allow use of C Kermit DIAL and
  54.  * SCRIPT commands.  Now it has a lot of duplicate code for the timer.device,
  55.  * which I plan to clean up before release.
  56.  *    Also added a few strategic debug() calls.  May not be very useful with
  57.  * above, since doing a LOG DEBUG seems to slow things down enough so that
  58.  * DIAL no longer works.
  59.  * 
  60.  * Revision 1.9  93/08/03  08:36:07  swalton
  61.  * Many changes thanks to Olaf Barthel:
  62.  * 1.  Changed include files to Amiga standard.
  63.  * 2.  Changed signal-handling to use ANSI signal() call.  Still can't
  64.  *     call Aztec Chk_Abort(), though, because it ignores signal().
  65.  * 3.  Used GetScreenData() on the Workbench screen to find the window
  66.  *     size to open.
  67.  * 4.  Deleted DoIOQuick() and changed calls to it to DoIO(), which is
  68.  *     identical.
  69.  * 5.. ttol() rewritten to have a static buffer whose size is checked
  70.  *     and to handle the pendwrite flag correctly.
  71.  * 
  72.  * Revision 1.8  92/10/30  16:14:46  swalton
  73.  * Put in code to attempt to open a 1024 by 1024 console, at John Ata's
  74.  * suggestion.  This will make a maximum-size window on most Amigas.
  75.  * 
  76.  * Added code to set a global int "v37" to TRUE or FALSE according to the
  77.  * version of the ROM Kernel.  This is then used in other places to
  78.  * conditionally turn on V37 features.
  79.  * 
  80.  * Revision 1.7  92/03/16  13:50:58  swalton
  81.  * Support added for CTR/RTS flow control, using the new FLO_ manifest
  82.  * constants in version 5A.
  83.  *
  84.  * Revision 1.6  92/01/15  17:12:35  swalton
  85.  * Added Long BREAK support with new ttsndlb() routine.
  86.  *
  87.  * Added support for multiple devices;  the SET LINE command now takes a
  88.  * line of the form "device/unit".
  89.  *
  90.  *  Revision 1.5  91/07/18  16:04:57  swalton
  91.  *  ttinl() now null terminates a received packet correctly.
  92.  *
  93.  *  Revision 1.4  91/05/29  09:08:57  swalton
  94.  *  1.  Changed function definitions to prototype style.  Required adding
  95.  *      a few forward declarations.
  96.  *  2.  Removed includes of stdio.h, stdlib.h, and string.h, as they are
  97.  *      now pulled in by ckcdeb.h, provided we compile with -DCK_ANSILIBS.
  98.  *
  99.  *  Revision 1.3  90/11/19  21:46:54  swalton
  100.  *  Modifications for compiling with SAS/C Version 5.10, courtesy of
  101.  *  Larry Rosenman (ler@erami.lonestar.org, ler on BIX)
  102.  *
  103.  *  Revision 1.2  90/11/07  14:42:07  swalton
  104.  *  Version 1.2--released to world as first beta test version simultaneously
  105.  *  with release of edit 5A(160).
  106.  *
  107.  *  Revision 1.1  90/07/12  22:30:11  swalton
  108.  *  Rather extensive changes were made to ckitio.c, mainly to add new functions
  109.  * required for the proper operation of C Kermit 5A(149).  They are not listed
  110.  * in detail here;  refer to the parts of the C Kermit interface document
  111.  * (file ckasys.doc in the Kermit archive) for the portions labeled *NEW*.
  112.  * These will point you at the code revisions.
  113.  *
  114.  * Revision 1.0  90/04/30  11:54:27  swalton
  115.  * Initial revision
  116.  *
  117.  */
  118.  
  119. #include "ckcdeb.h"
  120. #include "ckcker.h"
  121. #include "ckcnet.h"
  122. #include <exec/types.h>
  123. #include <exec/exec.h>
  124. #include <devices/serial.h>
  125. #include <devices/timer.h>
  126. #include <libraries/dos.h>
  127. #include <libraries/dosextens.h>
  128. #define fh_Interact fh_Port
  129. #define fh_Process fh_Type
  130. #include <intuition/intuition.h>
  131. #include <intuition/intuitionbase.h>
  132. #define BREAKSIGS (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)
  133. #include <string.h>
  134. #include <time.h>
  135.  
  136. #ifdef AZTEC_C
  137. #include <fcntl.h>
  138. #include <signal.h>
  139. char *ckxsys = " Commodore Amiga (Aztec_C)";    /* system name */
  140. #else
  141. #ifdef __SASC
  142. #include <fcntl.h>
  143. #include <signal.h>
  144. #include <ios1.h>        /* defines ufbs structure */
  145. char *ckxsys = " Commodore Amiga (SAS/C)";    /* system name */
  146. #endif
  147. #endif
  148.  
  149. #include <clib/exec_protos.h>
  150. #include <clib/alib_protos.h>
  151. #include <clib/dos_protos.h>
  152. #include <clib/intuition_protos.h>
  153.  
  154. /* external definitions */
  155. UBYTE *dftty = (UBYTE *) SERIALNAME;    /* serial device name */
  156. int dfloc = 1;                /* serial line is external */
  157. int dfprty = 0;                /* default parity is none */
  158. int ttprty = 0;                /* parity in use */
  159. int dfflow = FLO_XONX;            /* default flow control is on */
  160. int backgrd = 0;            /* default to foreground */
  161. int ckxech = 0;                /* echo in case redirected stdin */
  162. int tvtflg = 0;            
  163. int ttcarr = 0;                /* Carrier detection mode */
  164. int ttnproto = NP_NONE;            /* Protocol for network device */
  165.  
  166. struct Process *CurProc;        /* current process */
  167. struct CommandLineInterface *CurCLI;    /* current CLI info */
  168. struct IntuitionBase *IntuitionBase;    /* ptr to Intuition lib */
  169. short v37;                /* Are we version 37? */
  170.  
  171. /* static definitions */
  172. static struct MsgPort *serport;        /* message port for serial comm */
  173. static struct MsgPort *conport;        /* console packet port */
  174. static struct timerequest *TimerIOB;    /* timer request */
  175. static struct IOExtSer *ReadIOB;    /* serial input request */
  176. static struct IOExtSer *WriteIOB;    /* serial output request */
  177. static struct DosPacket *conpkt;    /* console I/O packet */
  178. static WORD serialopen;            /* true iff serial device open */
  179. static WORD pendwrite;            /* true iff WriteIOB in use */
  180. static WORD pendread;            /* true iff ReadIOB in use */
  181. static WORD pendconsole;        /* true when console read pending */
  182. static int queuedser;            /* serial pushback char or -1 */
  183. static UBYTE serbufc;            /* char buffer for read ahead I/O */
  184. #define NTTOQ 64            /* connect output queue size */
  185. static char ttoq[NTTOQ];        /* connect output queue */
  186. static int nttoq;            /* number of chars in ttoq */
  187. static int pttoq;            /* next char to output in ttoq */
  188. static int queuedcon;            /* contti pushback char or -1 */
  189. static LONG intsigs;            /* signals for aborting serial I/O */
  190. static BPTR rawcon;            /* file handle for RAW: window */
  191. static BPTR saverr;                     /* saved stderr file handle */
  192. static APTR savewindow;            /* saved process WindowPtr */
  193. static APTR pushwindow;            /* pushed process WindowPtr */
  194. static struct DateStamp prevtime;    /* saved time value */
  195.  
  196.  
  197. /* AmigaDOS support (from ckiutl.c) */
  198. struct DosPacket *CreatePacket(void);
  199. VOID DeletePacket(struct DosPacket *);
  200.  
  201. #ifdef AZTEC_C
  202. /* translate Unix file handle (0, 1, or 2) to AmigaDOS file handle */
  203. #define DOSFH(n) (_devtab[n].fd)
  204. /* translate Unix file handle (0, 1, or 2) to Aztec file handle */
  205. #define FILENO(n) (n)
  206. extern int Enable_Abort;
  207. #else
  208. /* Lattice runtime externals */
  209. #ifdef __SASC
  210. #define DOSFH(n) (chkufb(n)->ufbfh)
  211. #define FILENO(n) (n)
  212. #endif
  213. #endif
  214.  
  215. /*
  216.  * Under ANSI C, pointer-pointer assignments are illegal without an
  217.  * explicit cast.  So, we define the following to make such casts short.
  218.  */
  219. #define IOR struct IORequest
  220.  
  221. /*
  222.  * Forward declarations
  223.  */
  224. void reqres(void);
  225. static void testint(long);
  226. #ifdef AZTEC_C
  227. #define Chk_Abort() testint(0L)
  228. #else
  229. void Chk_Abort(void);        /* or #define Chk_Abort() testint(0) */
  230. #endif
  231.  
  232. /*
  233.  * make note of a serial error and quit
  234.  */
  235. static void
  236. Fail(char *msg)
  237. {
  238.     syscleanup();
  239.     fprintf(stderr, msg);
  240.     fprintf(stderr, "\n");
  241.     exit(2);
  242. }
  243.  
  244. void
  245. emergency(void) {
  246.     (void) syscleanup();
  247. }
  248.  
  249. /*
  250.  * Timer.device routines from RKM, slightly modified.
  251.  */
  252.  
  253. void
  254. DeleteTimer(struct timerequest *tr) {
  255.    struct MsgPort *tp;
  256.  
  257.    if (tr != 0) {
  258.       tp = tr->tr_node.io_Message.mn_ReplyPort;
  259.       if (tp != 0)
  260.          DeletePort(tp);
  261.       CloseDevice((struct IORequest *) tr);
  262.       DeleteExtIO((struct IORequest *) tr);
  263.    }
  264. }
  265.  
  266. struct timerequest *
  267. CreateTimer(ULONG unit) {
  268.    /* return a pointer to a timer request.  If any problem, return NULL. */
  269.  
  270.    LONG error;
  271.    struct MsgPort *timerport;
  272.    struct timerequest *timermsg;
  273.    
  274.    timerport = CreatePort(0, 0);
  275.    if (timerport == NULL)
  276.       return NULL;
  277.    timermsg = (struct timerequest *)
  278.               CreateExtIO(timerport, sizeof(struct timerequest));
  279.    if (timermsg == NULL) {
  280.       DeletePort(timerport);
  281.       return NULL;
  282.    }
  283.    error = OpenDevice((UBYTE *) TIMERNAME, unit,
  284.                       (struct IORequest *) timermsg, 0L);
  285.    if (error != 0) {
  286.       DeleteTimer(timermsg);
  287.       return NULL;
  288.    }
  289.    return timermsg;
  290. }
  291.  
  292. /*
  293.  *  sysinit -- Amiga specific initialization
  294.  */
  295. int
  296. sysinit(void)
  297. {
  298.     struct IOExtSer *iob;
  299.  
  300.     /* set current process info */
  301.     CurProc = (struct Process *)FindTask((char *)NULL);
  302.     CurCLI = (struct CommandLineInterface *)BADDR(CurProc->pr_CLI);
  303.     backgrd = (CurCLI == NULL || CurCLI->cli_Background);
  304.     savewindow = CurProc->pr_WindowPtr;
  305.  
  306.     signal(SIGINT, SIG_IGN);
  307.  
  308.     /* allocate console ports and IO blocks */
  309.     if ((conport = CreatePort((char *)NULL, 0L)) == NULL)
  310.         Fail("no console MsgPort");
  311.     if ((conpkt = CreatePacket()) == NULL)
  312.         Fail("no console packet");
  313.  
  314.     /* allocate serial ports and IO blocks */
  315.     if ((serport = CreatePort((char *)NULL, 0L)) == NULL)
  316.         Fail("no serial MsgPort");
  317.     iob = (struct IOExtSer *)CreateExtIO(serport,(LONG)sizeof(*iob));
  318.     if ((WriteIOB = iob) == NULL) Fail("no WriteIOB");
  319.     iob = (struct IOExtSer *)CreateExtIO(serport,(LONG)sizeof(*iob));
  320.     if ((ReadIOB = iob) == NULL) Fail("no ReadIOB");
  321.  
  322.     /* open the timer device */
  323.     TimerIOB = CreateTimer(UNIT_VBLANK);
  324.     if (TimerIOB == NULL) Fail("no TimerIOB");
  325.  
  326.     /* open the Intuition library */
  327.     if (!IntuitionBase &&
  328.         (IntuitionBase = (struct IntuitionBase *)
  329.                  OpenLibrary((UBYTE *) "intuition.library", 0L) ) == NULL )
  330.         Fail("can't open Intuition");
  331.  
  332.     if (((struct Library *)IntuitionBase)->lib_Version >= 37)
  333.         v37 = TRUE;
  334.     else
  335.         v37 = FALSE;
  336.     /* open the serial device to get configuration */
  337.     iob->io_SerFlags = SERF_SHARED;
  338.     if (OpenDevice((UBYTE *) SERIALNAME, 0L, (IOR *)iob, 0L) != 0)
  339.         Fail("can't open serial.device");
  340.     /* set parameters from system defaults */
  341.     if (!(iob->io_SerFlags & SERF_XDISABLED))
  342.         dfflow = FLO_XONX;
  343.     else if (iob->io_SerFlags & SERF_7WIRE)
  344.         dfflow = FLO_RTSC;
  345.     else
  346.         dfflow = FLO_NONE;
  347.     /*
  348.      * Set default (startup) parity from Preferences settings.
  349.       */
  350.     if (iob->io_SerFlags & SERF_PARTY_ON)     /* Parity is on */
  351.         if (iob->io_ExtFlags & SEXTF_MSPON)    /* Space or mark */
  352.             if (iob->io_ExtFlags & SEXTF_MARK)
  353.                 dfprty = 'm';        /* Mark parity */
  354.             else
  355.                 dfprty = 's';        /* Space parity */
  356.         else                    /* Even or odd */
  357.             if (iob->io_SerFlags & SERF_PARTY_ODD)
  358.                 dfprty = 'o';        /* Odd parity */
  359.             else
  360.                 dfprty = 'e';        /* Even parity */
  361.     else
  362.         dfprty = 0;                /* No parity. */
  363.     ttprty = dfprty;
  364.     CloseDevice((IOR *)iob);
  365.     serialopen = FALSE;
  366.     atexit(emergency);
  367.     return(0);
  368. }
  369.  
  370. unsigned aalarm(unsigned);    /* forward declaration */
  371.  
  372. /*
  373.  * syscleanup -- Amiga specific cleanup
  374.  */
  375. syscleanup(void)
  376. {
  377.     /* close everything */
  378.     aalarm(0);
  379.     if (serialopen) CloseDevice((IOR *)ReadIOB);
  380.     if (TimerIOB) DeleteTimer(TimerIOB);
  381.     if (WriteIOB) DeleteExtIO((IOR *)WriteIOB);
  382.     if (ReadIOB) DeleteExtIO((IOR *)ReadIOB);
  383.     if (serport) DeletePort(serport);
  384.     if (conpkt) DeletePacket(conpkt);
  385.     if (conport) DeletePort(conport);
  386.     reqres();
  387.     if (IntuitionBase)
  388.     {
  389.         CloseLibrary((struct Library *)IntuitionBase);
  390.         IntuitionBase = NULL;
  391.     }
  392.  
  393.     /* reset standard I/O */
  394.     if (rawcon > 0)
  395.     {
  396.         /* restore Lattice AmigaDOS file handles */
  397.         DOSFH(0) = Input();
  398.         DOSFH(1) = Output();
  399.         DOSFH(2) = saverr;
  400.         Close(rawcon);
  401.         rawcon = 0;
  402.     }
  403.     serialopen = 0;
  404.     TimerIOB = WriteIOB = ReadIOB = serport = conpkt = conport = NULL;
  405.     return 1;
  406. }
  407.  
  408. /*
  409.  * reqoff -- turn requestors off
  410.  *    When AmigaDOS encounters an error that user intervention can fix
  411.  *    (like inserting the correct disk), it normally puts up a requestor.
  412.  *    The following code disables requestors, causing an error to be
  413.  *    returned instead.
  414.  */
  415. void
  416. reqoff(void)
  417. {
  418.     pushwindow = CurProc->pr_WindowPtr;
  419.     CurProc->pr_WindowPtr = (APTR)-1;
  420. }
  421. /*
  422.  * reqpop -- restore requesters to action at last reqoff
  423.  */
  424. void
  425. reqpop(void)
  426. {
  427.     CurProc->pr_WindowPtr = pushwindow;
  428. }
  429.  
  430. /*
  431.  * reqres -- restore requestors to startup action
  432.  */
  433. void
  434. reqres(void)
  435. {
  436.     CurProc->pr_WindowPtr = savewindow;
  437. }
  438.  
  439. /*
  440.  * KillIO -- terminate an I/O request
  441.  */
  442. static int
  443. KillIO(struct IORequest *iob)
  444. {
  445.     AbortIO(iob);
  446.     return((int)WaitIO(iob));
  447. }
  448.  
  449. /*
  450.  * ttopen -- open the serial device
  451.  *    If already open, returns 0 immediately.
  452.  *    Otherwise, the ttname is compare to SERIALNAME and used to
  453.  *    open the serial device, and, if the value of *lcl is < 0, it is
  454.  *    reset to 1 indicating local mode.  Returns -1 on error.
  455.  *    timo is the length of time to wait before flunking open;  we don't
  456.  *    need this feature on the Amiga.
  457.  */
  458. int
  459. ttopen(char * ttname, int *lcl, int modem, int timo)
  460. {
  461.     struct IOExtSer *iob = ReadIOB;
  462.     char *p;
  463.     ULONG unit;
  464.     static  char cttname[50];    /* Current open ttname */
  465.  
  466.     debug(F111,"ttopen entry modem",ttname,modem);
  467.     debug(F101," lcl","",*lcl);
  468.     if (modem < 0) return -1;    /* We don't do networks yet. */
  469.     if (serialopen)            /* Already have serial device open */
  470.             if (strcmp(ttname, cttname) == 0)
  471.                 return(0);        /* Same device - ignore  */
  472.             else ttclos(0);        /* Different device - close */
  473.  
  474.     /* verify the serial name */
  475. #if 0
  476.     if (strcmp(ttname, SERIALNAME) != 0) return(-1);
  477. #endif
  478.  
  479.     /* set open modes.  We no longer open in shared mode. */
  480.     iob->io_SerFlags = (modem > 0 ? SERF_7WIRE : 0);
  481.  
  482.     /* parse device name as device/unit */
  483.     if ((p = strchr(ttname, '/')) == NULL)
  484.         unit = 0;
  485.     else {
  486.         if (*(p + strlen(p) - 1) == 's')    /* Open in shared mode */
  487.             {
  488.                 iob->io_SerFlags |= SERF_SHARED;
  489.                 *(p + strlen(p) - 1) = '\0';
  490.             }
  491.         unit = (ULONG) atoi(p + 1);
  492.         *p = '\0';
  493.     }
  494.     /* open the serial device */
  495.     if (OpenDevice((UBYTE *) ttname, unit, (IOR *)iob, 0L) != 0)
  496.         return(-1);
  497.     serialopen = TRUE;
  498.     tvtflg = 0;
  499.     pendread = pendwrite = pendconsole = FALSE;
  500.     queuedser = -1;
  501.  
  502.     /* fill in the fields of the other IO blocks */
  503.     *WriteIOB = *iob;
  504.  
  505.     /* set local mode */
  506.     if (*lcl == -1)    *lcl = 1; /* always local */
  507.     if (p) *p = '/';        /* restore slash */
  508.         if (iob->io_SerFlags & SERF_SHARED)
  509.             *(p + strlen(p)) = 's';     /* restore suffix if present */
  510.     strcpy(cttname, ttname);
  511.     debug(F110, "ttopen got device", ttname, 0);
  512.     return(0);
  513. }
  514.  
  515. /*
  516.  * StartTimer -- start a timeout
  517.  */
  518. static VOID
  519. StartTimer(LONG secs, LONG micro)
  520. {
  521.     TimerIOB->tr_node.io_Command = TR_ADDREQUEST;
  522.     TimerIOB->tr_time.tv_secs  = secs;
  523.     TimerIOB->tr_time.tv_micro = micro;
  524.     SendIO((IOR *)TimerIOB);
  525. }
  526.  
  527. /*
  528.  * SerialWait -- wait for serial I/O to terminate
  529.  *    return I/O error
  530.  */
  531. static int
  532. SerialWait(struct IOExtSer *iob, int timeout)
  533. {
  534.     LONG sigs;
  535.     struct timerequest *timer = TimerIOB;
  536.     LONG waitsigs;
  537.  
  538.     /* set up timeout if necessary */
  539.     if (timeout > 0) {
  540.         StartTimer((LONG)timeout, 0L);
  541.         waitsigs =
  542.            (1L << timer->tr_node.io_Message.mn_ReplyPort->mp_SigBit);
  543.     } else
  544.         waitsigs = 0;
  545.  
  546.     /* wait for completion, timeout, or interrupt */
  547.     sigs = 0;
  548.     waitsigs |= (1L << serport->mp_SigBit) | 
  549.                    intsigs;
  550.     for (;;)
  551.     {
  552.         if (sigs & intsigs)
  553.         {    /* interrupted */
  554.             if (timeout > 0) KillIO((IOR *)timer);
  555.             KillIO((IOR *)iob);
  556.             testint(sigs);
  557.             return(-1);
  558.         }
  559.         if (CheckIO((IOR *)iob))
  560.         {
  561.             if (timeout > 0) KillIO((IOR *)timer);
  562.             return((int)WaitIO((IOR *)iob));
  563.         }
  564.         if (timeout > 0 && CheckIO((IOR *)timer))
  565.         {
  566.             KillIO((IOR *)iob);
  567.             WaitIO((IOR *)timer);
  568.             /* restart if XOFF'ed */
  569.             iob->IOSer.io_Command = CMD_START;
  570.             DoIO((IOR *)iob);
  571.             return(-1);
  572.         }
  573.         sigs = Wait(waitsigs);
  574.     }
  575. }
  576.  
  577. /*
  578.  * TerminateRead -- wait for queued read to finish
  579.  */
  580. static int
  581. TerminateRead(void)
  582. {
  583.     if (!pendread) return(0);
  584.     if (WaitIO((IOR *)ReadIOB) == 0) queuedser = serbufc;
  585.     pendread = FALSE;
  586.     return((int)ReadIOB->IOSer.io_Error);
  587. }
  588.  
  589. /*
  590.  * TerminateWrite -- ensure WriteIOB is ready for reuse
  591.  */
  592. static int
  593. TerminateWrite(int timeout)
  594. {
  595.     Chk_Abort();
  596.     if (!pendwrite) return(0);
  597.     pendwrite = FALSE;
  598.     if (timeout) {
  599.         timeout = WriteIOB->IOSer.io_Length * 80 / WriteIOB->io_Baud;
  600.     }
  601.     return(SerialWait(WriteIOB, timeout));
  602. }
  603.  
  604. /*
  605.  * SerialReset -- terminate pending serial and console I/O
  606.  */
  607. static void
  608. SerialReset(void)
  609. {
  610.     if (pendread)
  611.     {
  612.         AbortIO((IOR *)ReadIOB); /* should work even if read finished */
  613.         TerminateRead();
  614.     }
  615.  
  616.     if (pendconsole)
  617.     {    /* this does not happen normally */
  618.         WaitPort(conport);
  619.         GetMsg(conport);
  620.         pendconsole = FALSE;
  621.     }
  622.  
  623.     if (pendwrite)
  624.         TerminateWrite(1);
  625. }
  626.  
  627. /*
  628.  * ttres -- reset serial device
  629.  */
  630. ttres()
  631. {
  632.     if (!serialopen) return(-1);
  633.  
  634.     /* reset everything */
  635.     SerialReset();
  636.     ReadIOB->IOSer.io_Command = CMD_RESET;
  637.     tvtflg = 0;
  638.     return(DoIO((IOR *)ReadIOB) ? -1 : 0);
  639. }
  640.  
  641. /*
  642.  * ttclos -- close the serial device
  643.  */
  644. int
  645. ttclos(int unit)
  646. {
  647.     debug(F101, "ttopen ", "", unit);
  648.     if (!serialopen) return(0);
  649.     if (ttres() < 0) return(-1);
  650.     CloseDevice((IOR *)ReadIOB);
  651.     serialopen = FALSE;
  652.     tvtflg = 0;
  653.     return(0);
  654. }
  655.  
  656. /*
  657.  * tthang -- hang up phone line
  658.  *    Drops DTR by closing serial.device
  659.  */
  660. int
  661. tthang(void)
  662. {
  663.         return((serialopen) ? ttclos(0) : -1);
  664. }
  665.  
  666. /*
  667.  * ttpkt -- set serial device up for packet transmission
  668.  *    sets serial parameters
  669.  */
  670. int
  671. ttpkt(long speed, int flow, int parity)
  672. {
  673.     extern UBYTE eol;
  674.     struct IOExtSer *iob = ReadIOB;
  675.  
  676.     debug(F101, "ttpkt speed ", "", speed);
  677.     debug(F101, "ttpkt flow ", "", flow);
  678.     debug(F101, "ttpkt parity ", "", parity);
  679.     if (!serialopen || pendread) return(-1);
  680.  
  681.     /* terminate any pending writes */
  682.     TerminateWrite(1);
  683.  
  684.     /* fill in parameters */
  685.     iob->io_CtlChar = 0x11130000;
  686.     if (speed >= 0 && ttsspd((int) (speed / 10)) >= 0) iob->io_Baud = speed;
  687.     iob->io_RBufLen = speed;    /* 10 seconds worth of data */
  688.     /*
  689.      * Notice the dopar(eol) here to set the EOL character with the
  690.      * appropriate parity.  See also ttinl().
  691.      */
  692.     memset(&iob->io_TermArray, dopar(eol), sizeof(struct IOTArray));
  693.     iob->io_ReadLen = iob->io_WriteLen = 8;
  694.     iob->io_StopBits = 1;
  695.     if (flow == FLO_XONX)
  696.         iob->io_SerFlags &= ~(SERF_XDISABLED | SERF_7WIRE);
  697.     else if (flow == FLO_RTSC)
  698.         iob->io_SerFlags |= (SERF_XDISABLED | SERF_7WIRE);
  699.     else {
  700.         iob->io_SerFlags |= SERF_XDISABLED;
  701.         iob->io_SerFlags &= ~SERF_7WIRE;
  702.     }
  703.     /* if no XON/XOFF flow and high baud rate, RAD_BOOGIE is appropriate */
  704.     if (flow != FLO_XONX && iob->io_Baud >= 19200)
  705.         iob->io_SerFlags |= SERF_RAD_BOOGIE;
  706.     else
  707.         iob->io_SerFlags &= ~SERF_RAD_BOOGIE;
  708.  
  709.     /*
  710.      * Parity setting.  For packet send/receive, we turn off the
  711.      * Amiga's internal parity generation and checking, as this code
  712.      * does it itself (which makes it bigger and slower...).  We
  713.      * save the current parity for ttinl().
  714.      */
  715.  
  716.     ttprty = parity;
  717.     iob->io_SerFlags &= ~(SERF_EOFMODE|SERF_PARTY_ON|SERF_PARTY_ODD);
  718.     iob->io_ExtFlags = 0;        /* MUST BE ZERO unless Mark or Space. */
  719.  
  720.     /* set the parameters */
  721.     iob->IOSer.io_Command = SDCMD_SETPARAMS;
  722.     if (DoIO((IOR *)iob) != 0) return(-1);
  723.     tvtflg = 0;
  724.     return(ttflui());
  725. }
  726.  
  727. /*
  728.  * ttvt -- set up serial device for connect mode.  This is almost the same
  729.  * as ttpkt() on the Amiga, except we save the settings and a flag and return
  730.  * without doing anything if we've already been called with the same
  731.  * values.
  732.  */
  733. int
  734. ttvt(long speed, int flow) {
  735.     static long ospeed = -1;
  736.     static int oflow = -9;
  737.  
  738.     if (tvtflg != 0 && ospeed == speed && oflow == flow)
  739.         return 0;
  740.     if (ttpkt(speed, flow, 0) < 0)
  741.         return -1;
  742.     ospeed = speed;            /* Save speed */
  743.     oflow = flow;            /* and flow control set */
  744.     tvtflg = 1;            /* and flag we've been called */
  745.     return 0;
  746. }
  747.  
  748. /*  T T S S P D  --  Set the transmission of tty to ten times the argument */
  749.  
  750. ttsspd(speed) int speed; {
  751.     int s;
  752.     struct IOExtSer *iob = ReadIOB;
  753.  
  754.     debug (F101,"ttsspd: speed(cps):","",speed);
  755.     if (!serialopen) return(-1);
  756.  
  757.     switch (speed) {
  758.         case 5:         s = 50;        break;
  759.         case 7:         s = 75;        break;
  760.         case 11:        s = 110;       break;
  761.         case 13:        s = 134;       break;
  762.         case 15:        s = 150;       break;
  763.         case 30:        s = 300;       break;
  764.         case 60:        s = 600;       break;
  765.         case 120:       s = 1200;      break;
  766.         case 180:       s = 1800;      break;
  767.         case 200:       s = 2000;      break;
  768.         case 240:       s = 2400;      break;
  769.         case 360:       s = 3600;      break;
  770.         case 480:       s = 4800;      break;
  771.         case 720:       s = 7200;      break;
  772.         case 960:       s = 9600;      break;
  773.         case 1440:    s = 14400;     break;
  774.         case 1920:      s = 19200;     break;
  775.         case 3840:      s = 38400;     break;
  776.         case 888:       return(-1); /* no 75/1200 split speed */
  777.         default:        return -1;
  778.     }
  779.     /* First get a complete copy of current settings. */
  780.     iob->IOSer.io_Command = SDCMD_QUERY;
  781.     if (DoIO((IOR *)iob) != 0) return(-1);
  782.     iob->io_Baud = s;
  783.     iob->io_RBufLen = s;    /* 10 seconds worth of data */
  784.     /* set the parameters */
  785.     iob->IOSer.io_Command = SDCMD_SETPARAMS;
  786.     if (DoIO((IOR *)iob) != 0) return(-1);
  787.  
  788.     return s;
  789.  
  790. }
  791.  
  792. /* T T G S P D  -  Get speed of currently selected tty line  */
  793.  
  794. /*
  795.   Read speed from serial.device, or, if not open, return the value in
  796.   the current ReadIOB.
  797. */
  798. long
  799. ttgspd(void) {                /* Get current tty speed */
  800.     struct IOExtSer *myread = ReadIOB;
  801.  
  802.     if (!serialopen)
  803.         if (myread != NULL) return((long)myread->io_Baud);
  804.         else return -1;
  805.     Chk_Abort();
  806.     if (pendread && !CheckIO((IOR *)myread)) return(0);
  807.     if (TerminateRead() != 0) return(-1);
  808.     myread->IOSer.io_Command = SDCMD_QUERY;
  809.     return((DoIO((IOR *)myread) == 0)
  810.             ? (long)myread->io_Baud
  811.             : -1);
  812. }
  813.  
  814. /*
  815.  * ttflui -- flush serial device input buffer
  816.  */
  817. int
  818. ttflui(void)
  819. {
  820.     if (!serialopen || pendread) return(-1);
  821.     queuedser = -1;
  822.     ReadIOB->IOSer.io_Command = CMD_CLEAR;
  823.     return(DoIO((IOR *)ReadIOB) ? -1 : 0);
  824. }
  825.  
  826. /*
  827.  * ttfluo -- flush serial output buffer
  828.  */
  829. int
  830. ttfluo(void)
  831. {
  832.     if (!serialopen || pendwrite) return -1;
  833.     WriteIOB->IOSer.io_Command = CMD_CLEAR;
  834.     return(DoIO((IOR *)WriteIOB) ? -1 : 0);
  835. }
  836.  
  837.  
  838. /*
  839.  * test for and catch interrupt
  840.  */
  841. static void
  842. testint(LONG sigs)
  843. {
  844.     /* test for and reset caught interrupt signals */
  845.     if ((sigs | SetSignal(0L, (LONG)BREAKSIGS)) & intsigs) {
  846.         raise(SIGINT);
  847.     }
  848. }
  849.  
  850. /*
  851.  * conint -- set console interrupt handler and suspend handler.
  852.  */
  853. void
  854. conint(SIGTYP (*newhdlr)(int), SIGTYP (*stophdlr)(int))
  855. {
  856.     Chk_Abort();            /* handle any pending interrupts */
  857.     signal(SIGINT, newhdlr);    /* set the new handler */
  858.     intsigs = BREAKSIGS;        /* note signal caught */
  859. }
  860.  
  861. /*
  862.  * connoi -- disable interrupt trapping
  863.  */
  864. void
  865. connoi(void)
  866. {
  867.     signal(SIGINT, SIG_IGN);    /* disable interrupts */
  868.     intsigs = 0;            /* note signal ignored */
  869.     Chk_Abort();            /* ignore pending interrupts */
  870. }
  871.  
  872. /*
  873.  * ttchk -- return number of chars immediately available from serial device
  874.  */
  875. int
  876. ttchk(void)
  877. {
  878.     struct IOExtSer *myread = ReadIOB;
  879.  
  880.     if (!serialopen) return(-1);
  881.     Chk_Abort();
  882.     if (pendread && !CheckIO((IOR *)myread)) return(0);
  883.     if (TerminateRead() != 0) return(-1);
  884.     myread->IOSer.io_Command = SDCMD_QUERY;
  885.     return((DoIO((IOR *)myread) == 0)
  886.             ? ((queuedser >= 0 ? 1 : 0) + (int)myread->IOSer.io_Actual)
  887.             : -1);
  888. }
  889.  
  890. /*
  891.  * ttxin -- get n characters from serial device.  This routine should
  892.  * only be called when we know that there are at least n characters
  893.  * ready to be read.
  894.  */
  895. int
  896. ttxin(int n, CHAR *buf)
  897. {
  898.         return(ttinl(buf, n, 0, 0));
  899. }
  900.  
  901. #ifdef PARSENSE
  902.  
  903. extern CHAR partab[];
  904.  
  905. /*  P A R C H K  --  Check if Kermit packet has parity  */
  906.  
  907. /*
  908.   Call with s = pointer to packet, start = packet start character, n = length.
  909.   Returns 0 if packet has no parity, -1 on error, or if packet has parity:
  910.     'e' for even, 'o' for odd, 'm' for mark.  Space parity cannot be sensed.
  911. */
  912. parchk(s,start,n) CHAR *s, start; int n; {
  913.     CHAR s0, s1, s2, s3, sn;
  914.  
  915.     debug(F101,"parchk n","",n);
  916.     debug(F101,"parchk start","",start);
  917.     debug(F110,"parchk s",s,0);
  918.  
  919.     s0 = s[0] & 0x7f;            /* Mark field (usually Ctrl-A) */
  920.  
  921.     if (s0 != start || n < 5) return(-1); /* Not a valid packet */
  922.  
  923. /* Look at packet control fields, which never have 8th bit set */
  924. /* First check for no parity, most common case. */
  925.  
  926.     if (((s[0] | s[1] | s[2] | s[3] | s[n-2]) & 0x80) == 0)
  927.       return(0);            /* No parity */
  928.  
  929. /* Check for mark parity */
  930.  
  931.     if (((s[0] & s[1] & s[2] & s[3] & s[n-2]) & 0x80) == 0x80)
  932.       return('m');            /* Mark parity */
  933.  
  934. /* Packet has some kind of parity */
  935. /* Make 7-bit copies of control fields */
  936.  
  937.     s1 = s[1] & 0x7f;            /* LEN */
  938.     s2 = s[2] & 0x7f;            /* SEQ */
  939.     s3 = s[3] & 0x7f;            /* TYPE */
  940.     sn = s[n-2] & 0x7f;            /* CHECK */
  941.  
  942. /* Check for even parity */
  943.  
  944.     if ((s[0] == partab[s0]) &&
  945.         (s[1] == partab[s1]) &&
  946.         (s[2] == partab[s2]) &&
  947.     (s[3] == partab[s3]) &&
  948.     (s[n-2] == partab[sn]))
  949.       return('e');
  950.  
  951. /* Check for odd parity */
  952.  
  953.     if ((s[0] != partab[s0]) &&
  954.         (s[1] != partab[s1]) &&
  955.         (s[2] != partab[s2]) &&
  956.     (s[3] != partab[s3]) &&
  957.     (s[n-2] != partab[sn]))
  958.       return('o');
  959.  
  960. /* Otherwise it's probably line noise.  Let checksum calculation catch it. */
  961.  
  962.     return(-1);
  963. }
  964. #endif /* PARSENSE */
  965.  
  966. /*
  967.  * ttinc -- read character from serial line
  968.  */
  969. int
  970. ttinc(int timeout)
  971. {
  972.     UBYTE ch;
  973.  
  974.     return((ttinl((CHAR *)&ch, 1, timeout, 0) > 0) ? (int)ch : -1);
  975. }
  976.  
  977. /*
  978.  * The following chunk of code is a primitive (very!) alarm() function
  979.  * for the Amiga.  It is nowhere near general, and it will only work
  980.  * with Kermit, most likely.  It has three parts:
  981.  *
  982.  * asignal() is call-compatible with signal().  If the signal is less
  983.  * than or equal to _NUMSIG (in <signal.h>), then the vendor-supplied
  984.  * signal() is called.  If it is equal to _NUMSIG+1, which I define as
  985.  * SIGALRM, then it is a new alarm signal.  The pointer to the passed
  986.  * function is saved and the old one is returned.
  987.  *
  988.  * aalarm() is the Unix-like call.  It is called with a time in seconds,
  989.  * which is the time after which the routine passed in the
  990.  * signal(SIGALRM, ...) call is to be called.  Here we just start a
  991.  * timer and return.
  992.  *
  993.  * check_alarm() sees if the time specified by aalarm() is up yet, and
  994.  * calls the saved function if it is.
  995.  */
  996.  
  997. static void (*savalarm)(int) = SIG_DFL;
  998. static struct timerequest *alarmIOB;
  999. static unsigned savesecs;
  1000. static short alarmflag = 0;        /* flag that an alarm is pending */
  1001. #define SIGALRM (_NUMSIG+1)
  1002.  
  1003. void (*asignal(int sig, void (*func)(int)))(int) {
  1004.  
  1005.     void (*talarm)(int);
  1006.     debug(F101, "asignal sig", "", sig);
  1007.     debug(F101, "asignal func", "", func);
  1008.     if (sig <= _NUMSIG)
  1009.         return(signal(sig, func));
  1010.     else if (sig == SIGALRM) {
  1011.         talarm = savalarm;
  1012.         savalarm = func;
  1013.         return(talarm);
  1014.     }
  1015.     else {
  1016.         debug(F100, "asignal called with sig too large", "", 0);
  1017.         return(SIG_IGN);
  1018.     }
  1019. }
  1020.  
  1021. unsigned
  1022. aalarm(unsigned secs) {
  1023.     unsigned t;
  1024.  
  1025.     debug(F101, "aalarm", "", secs);
  1026.     t = savesecs;
  1027.     if (secs == 0) {
  1028.         if (alarmIOB) {
  1029.             KillIO((IOR *) alarmIOB);
  1030.             DeleteTimer(alarmIOB);
  1031.             alarmIOB = NULL;
  1032.         }
  1033.         savesecs = 0;
  1034.         alarmflag = 0;
  1035.         return(t);
  1036.     } else {
  1037.         alarmIOB = CreateTimer(UNIT_VBLANK);
  1038.         if (alarmIOB == NULL) {
  1039.             debug(F100, "CreateExtIO failed in alarm", "", 0);
  1040.             return(0);
  1041.         }
  1042.         alarmIOB->tr_time.tv_secs = savesecs = secs;
  1043.         alarmIOB->tr_time.tv_micro = 0;
  1044.         alarmIOB->tr_node.io_Command = TR_ADDREQUEST;
  1045.         SendIO((IOR *) alarmIOB);
  1046.         alarmflag = 1;
  1047.         return(t);
  1048.     }
  1049. }
  1050.  
  1051. static void
  1052. check_alarm(void) {
  1053.  
  1054.     if (alarmflag)
  1055.         if (CheckIO((IOR *) alarmIOB)) {
  1056.             WaitIO((IOR *) alarmIOB);
  1057.             alarmflag = 0;
  1058.             if (savalarm == SIG_IGN)
  1059.                 return;
  1060.             else if (savalarm == SIG_DFL)
  1061.                 Fail("uncaught alarm seen");
  1062.             else
  1063.                 (*savalarm)(SIGALRM);
  1064.         }
  1065. }
  1066.  
  1067. /*
  1068.  * ttol -- write n chars to serial device.  For small writes, we have
  1069.  * a small local buffer which allows them to run asynchronously.  For
  1070.  * large writes, we do them synchronously.  This seems to be the best
  1071.  * compromise between speed and code simplicity and size.
  1072.  *
  1073.  * Stephen Walton, 23 October 1989
  1074.  */
  1075. int
  1076. ttol(CHAR *buf, int n)
  1077. {
  1078.     struct IOExtSer *mywrite = WriteIOB;
  1079.     static char outbuf[1024];    /* safe place for output characters */
  1080.     int s;
  1081.     int oldn = n;
  1082.  
  1083.     if (!serialopen) return(-1);
  1084.     check_alarm();
  1085.     if ((s = n - sizeof(outbuf)) > 0) {
  1086.         if (TerminateWrite(1) != 0) return(-1);
  1087.         mywrite->IOSer.io_Command = CMD_WRITE;
  1088.         mywrite->IOSer.io_Data  = (APTR) buf;
  1089.         mywrite->IOSer.io_Length = s;
  1090.         SendIO((IOR *)mywrite);
  1091.         pendwrite = TRUE;
  1092.         buf += s;
  1093.         n   -= s;
  1094.         memcpy(outbuf, buf, n);
  1095.         if (TerminateWrite(1) != 0) return(-1);
  1096.     } else {
  1097.         if (TerminateWrite(1) != 0) return(-1);
  1098.         memcpy(outbuf, buf, n);
  1099.     }
  1100.     mywrite->IOSer.io_Command = CMD_WRITE;
  1101.     mywrite->IOSer.io_Data    = (APTR)outbuf;
  1102.     mywrite->IOSer.io_Length  = n;
  1103.     SendIO((IOR *)mywrite);
  1104.     pendwrite = TRUE;
  1105.  
  1106.     return oldn;
  1107. }
  1108.  
  1109. /*
  1110.  * ttoc -- output single character to serial device
  1111.  */
  1112. int
  1113. ttoc(char c)
  1114. {
  1115.         return(ttol((CHAR *) &c, 1));
  1116. }
  1117.  
  1118. /*
  1119.  * ttinl -- read from serial device, possibly with timeout and eol character
  1120.  *    reads up to n characters, returning the number of characters read
  1121.  *    if eol > 0, reading the eol character will terminate read
  1122.  *    if timeout > 0, terminates read if timeout elapses
  1123.  *    returns -1 on error, such as timeout or interrupt
  1124.  *
  1125.  *    Note that this is the single routine which does all character reading
  1126.  *    in Amiga C Kermit, and has some added "features" compared to, say,
  1127.  *    the Unix version.  If timeout is 0, this routine waits forever.
  1128.  *    If eol is zero, it is not used.
  1129.  *
  1130.  *    New for 5A(157) is the start parameter, which is the start-of-packet
  1131.  *    character.  Following the Unix example, we just read until eol,
  1132.  *    but return a bad packet if the first character we got doesn't agree
  1133.  *    with start.
  1134.  */
  1135. int
  1136. ttinl(CHAR *buf, int n, int timeout, CHAR eol)
  1137. {
  1138.         unsigned  mask;
  1139.     struct IOExtSer *myread = ReadIOB;
  1140.     int count;
  1141.     int nread, i;
  1142.  
  1143.     Chk_Abort();
  1144.     check_alarm();
  1145.      if (!serialopen || pendread || n <= 0) return(-1);
  1146.  
  1147.     mask = (ttprty ? 0177 : 0377);    /* parity stripping mask */
  1148.  
  1149.     /* handle pushback */
  1150.     if (queuedser >= 0)
  1151.     {
  1152.         *buf = queuedser & mask;    /* Strip queued character. */
  1153.         queuedser = -1;
  1154.         if (*buf == eol || n == 1) return(1);
  1155.         ++buf;
  1156.         --n;
  1157.         count = 1;
  1158.     }
  1159.     else
  1160.         count = 0;
  1161.  
  1162.     /* set up line terminator */
  1163.     if (eol > 0)
  1164.     {
  1165.         /*
  1166.          * For reasons which are obscure to me, this batch of
  1167.          * code generally fails.  Normally, this doesn't matter,
  1168.          * because io_TermArray is set in ttpkt() above, and so
  1169.          * this code is only executed if eol changes as a result
  1170.          * of the initial packet negotiation.  I found the bug
  1171.          * by inadvertently not using dopar(eol) in the setting
  1172.          * of io_TermArray in ttpkt(), which did cause this code
  1173.          * to be called if parity was MARK or EVEN (since in that
  1174.          * case dopar(eol) != eol).
  1175.          */
  1176.  
  1177.         if (dopar(eol) != *(UBYTE *)&myread->io_TermArray)
  1178.         {
  1179.             memset(&myread->io_TermArray, dopar(eol),
  1180.                    sizeof(struct IOTArray));
  1181.             myread->IOSer.io_Command = SDCMD_SETPARAMS;
  1182.             if (DoIO((IOR *)myread) != 0) {
  1183.                 debug(F111, "SETPARAMS fails in ttinl()",
  1184.                       "io_Error", (int) myread->IOSer.io_Error);
  1185.                 myread->io_TermArray.TermArray0 =
  1186.                     myread->io_TermArray.TermArray1 = 0xffffffffu;
  1187.                 return -1;
  1188.             }
  1189.         }
  1190.         myread->io_SerFlags |= SERF_EOFMODE;
  1191.     }
  1192.     else
  1193.         myread->io_SerFlags &= ~SERF_EOFMODE;
  1194.  
  1195.     /* set up the read */
  1196.     myread->IOSer.io_Command = CMD_READ;
  1197.     myread->IOSer.io_Data    = (APTR)buf;
  1198.     myread->IOSer.io_Length  = n;
  1199.  
  1200.     /* perform read quickly if possible */
  1201.     myread->IOSer.io_Flags = IOF_QUICK;
  1202.     BeginIO((IOR *)myread);
  1203.     if (myread->IOSer.io_Flags & IOF_QUICK)
  1204.         myread->IOSer.io_Flags = 0;
  1205.     else
  1206.         /* wait for read to complete if no QUICK. */
  1207.         if (SerialWait(myread, timeout) != 0)
  1208.             return -1;
  1209.  
  1210.     if (myread->IOSer.io_Error != 0)
  1211.         return -1;
  1212. #if COMMENT
  1213.     if (start != 0 && (buf[0] & mask) != start) /* Bad packet */
  1214.         return -1;
  1215. #endif
  1216.     /* Strip parity bits if need be. */
  1217.     nread = (int) myread->IOSer.io_Actual;
  1218.     if (ttprty)
  1219.         for (i = 0; i < nread; i++)
  1220.             buf[i] &= mask;
  1221.     if (nread > 1)
  1222.         buf[nread] = '\0';        /* Null terminate */
  1223.     return(count + nread);
  1224. }
  1225.  
  1226. /*
  1227.  * Sleeper -- perform an interruptible timeout
  1228.  */
  1229. static int
  1230. Sleeper(LONG secs, LONG micro)
  1231. {
  1232.     LONG sigs;
  1233.     LONG waitsigs;
  1234.     struct timerequest *timer = TimerIOB;
  1235.  
  1236.     if (!TimerIOB) return(-1);
  1237.     if (secs == 0 && micro <= 2)
  1238.         return(0);
  1239.     StartTimer(secs, micro);
  1240.     sigs = 0;
  1241.     waitsigs = (1L << timer->tr_node.io_Message.mn_ReplyPort->mp_SigBit) | intsigs;
  1242.     for (;;)
  1243.     {
  1244.         if (CheckIO((IOR *)timer))
  1245.         {
  1246.             WaitIO((IOR *)timer);
  1247.             return(0);
  1248.         }
  1249.         if (sigs & intsigs)
  1250.         {
  1251.             KillIO((IOR *)timer);
  1252.             testint(sigs);
  1253.             return(-1);
  1254.         }
  1255.         sigs = Wait(waitsigs);
  1256.     }
  1257. }
  1258.  
  1259. /*
  1260.  * sleep -- wait n seconds
  1261.  */
  1262. int
  1263. sleep(int n)
  1264. {    return(Sleeper((LONG)n, 0L)); }
  1265.  
  1266. /*
  1267.  * msleep -- wait n milliseconds
  1268.  */
  1269. int
  1270. msleep(int m)
  1271. {    return(Sleeper((LONG)(m / 1000), (m % 1000) * 1000L)); }
  1272.  
  1273.  
  1274. /*
  1275.  * rtimer -- reset elapsed time
  1276.  */
  1277. void
  1278. rtimer(void)
  1279. {    DateStamp(&prevtime); }
  1280.  
  1281. /*
  1282.  * gtimer -- get currently elapsed time in seconds
  1283.  */
  1284. int
  1285. gtimer(void)
  1286. {
  1287.     int x;
  1288.     struct DateStamp curtime;
  1289.  
  1290.     DateStamp(&curtime);
  1291.     x = ((curtime.ds_Days   - prevtime.ds_Days  ) * 1440 +
  1292.          (curtime.ds_Minute - prevtime.ds_Minute) ) * 60 +
  1293.          (curtime.ds_Tick   - prevtime.ds_Tick  ) / 50;
  1294.     return((x < 0) ? 0 : x );
  1295. }
  1296.  
  1297. /*
  1298.  * ztime -- format current date and time into string
  1299.  */
  1300. void
  1301. ztime(char **s)
  1302. {
  1303.     time_t xclock;
  1304.  
  1305.     (void) time(&xclock);
  1306.     *s = asctime(localtime(&xclock));
  1307. }
  1308.  
  1309. /*
  1310.  * congm -- save console modes
  1311.  */
  1312. int
  1313. congm(void)
  1314. {
  1315.     if (!saverr) saverr = DOSFH(2);
  1316.     return(0);
  1317. }
  1318.  
  1319. /*
  1320.  * CreateWindow -- create window and jam it into standard I/O
  1321.  */
  1322. int
  1323. CreateWindow(int esc)
  1324. {
  1325.     char rawname[48];
  1326.     struct Screen s;
  1327.  
  1328.     if (rawcon > 0) return(0);
  1329.     congm();
  1330.  
  1331.     if (GetScreenData(&s, sizeof(s), WBENCHSCREEN, NULL) == 0) {
  1332.         s.Width = 640;
  1333.         s.Height = 200;
  1334.     }
  1335.     sprintf(rawname, "RAW:0/1/%d/%d/Kermit%s", s.Width, s.Height - 1,
  1336.         v37? "/ALT0/1/100/30" : "");
  1337.     rawcon = Open((UBYTE *) rawname, (LONG)MODE_NEWFILE);
  1338.       if (rawcon == 0)
  1339.           return(-1);
  1340.     DOSFH(0) = DOSFH(1) = DOSFH(2) = rawcon;
  1341.  
  1342.     /* if we create a window, don't abort on errors or echo */
  1343.     backgrd = FALSE;
  1344.     ckxech = 1;
  1345.     return(0);
  1346. }
  1347.  
  1348. /*
  1349.  * concb -- put console in single character wakeup mode
  1350.  */
  1351. int
  1352. concb(char esc)
  1353. {
  1354.     if (rawcon) return(0);
  1355.     if (CurCLI && CurProc->pr_CIS != CurCLI->cli_StandardInput)
  1356.         return(0);
  1357.     return(CreateWindow(esc));
  1358. }
  1359.  
  1360. /*
  1361.  * conbin -- put console in raw mode
  1362.  */
  1363. int
  1364. conbin(char esc)
  1365. {
  1366.     if (rawcon) return(0);
  1367.     if (CurCLI && CurProc->pr_CIS != CurCLI->cli_StandardInput)
  1368.         return(isatty(0) ? 0 : -1);
  1369.     return(CreateWindow(esc));
  1370. }
  1371.  
  1372. /*
  1373.  * conres -- restore console
  1374.  *    we actually restore in syscleanup()
  1375.  */
  1376. conres()
  1377. {
  1378.         return(0);
  1379. }
  1380.  
  1381. /*
  1382.  * conoc -- output character to console
  1383.  */
  1384. int
  1385. conoc(char c)
  1386. {
  1387.     putchar(c);
  1388.     fflush(stdout);
  1389.     Chk_Abort();
  1390.     return c;
  1391. }
  1392.  
  1393. /*
  1394.  * conxo -- output x chars to console
  1395.  */
  1396. int
  1397. conxo(int n, char *buf)
  1398. {
  1399.     int retval;
  1400.  
  1401.     fflush(stdout);
  1402.     retval = write(FILENO(1), buf, n);
  1403.     Chk_Abort();
  1404.     return retval;
  1405. }
  1406.  
  1407. /*
  1408.  * conol -- output line to console
  1409.  */
  1410. int
  1411. conol(char *l)
  1412. {
  1413.     int retval;
  1414.     retval = fputs(l, stdout);
  1415.     fflush(stdout);
  1416.     Chk_Abort();
  1417.     return retval;
  1418. }
  1419.  
  1420. /*
  1421.  * conola -- output line array to console
  1422.  */
  1423. int
  1424. conola(char **l)
  1425. {
  1426.     for (; **l; ++l)
  1427.         if (conol(*l) < 0)
  1428.             return(-1);
  1429.     return 0;
  1430. }
  1431.  
  1432. /*
  1433.  * conoll -- output line with CRLF
  1434.  */
  1435. int
  1436. conoll(char *l)
  1437. {
  1438.     if (conol(l) < 0)
  1439.         return -1;
  1440.     if (conxo(2, "\r\n") < 0)
  1441.         return -1;
  1442.     return 0;
  1443. }
  1444.  
  1445. /*
  1446.  * conchk -- returns nonzero if characters available from console
  1447.  */
  1448. int
  1449. conchk(void)
  1450. {
  1451.     fflush(stdout);
  1452.     Chk_Abort();
  1453.     return(WaitForChar(DOSFH(0), 0L) != 0);
  1454. }
  1455.  
  1456. /*
  1457.  * coninc -- get input character from console
  1458.  */
  1459. int
  1460. coninc(int timeout)
  1461. {
  1462.     UBYTE ch;
  1463.  
  1464.     fflush(stdout);
  1465.     Chk_Abort();
  1466.     if (timeout > 0 && !WaitForChar(DOSFH(0), timeout * 1000000L))
  1467.         return(-1);
  1468.     if (read(FILENO(0), &ch, 1) < 1) return(-1);
  1469.     Chk_Abort();
  1470.     return((int)ch);
  1471. }
  1472.  
  1473. /*
  1474.  * T T S C A R R -- Copy desired character mode to global ttcarr for future
  1475.  * and later use.
  1476.  */
  1477. ttscarr(carrier) int carrier; {
  1478.     ttcarr = carrier;
  1479.     debug(F101, "ttscarr","",ttcarr);
  1480.     return(ttcarr);
  1481. }
  1482.  
  1483. static int
  1484. sendbreak(long time) {
  1485.     if (!serialopen) return(-1);
  1486.     /* flush queued output */
  1487.     TerminateWrite(1);
  1488.     nttoq = 0;
  1489.     pendwrite = TRUE;
  1490.     WriteIOB->IOSer.io_Command = SDCMD_SETPARAMS;
  1491.     WriteIOB->io_BrkTime = time;
  1492.     (void) DoIO((IOR *)WriteIOB);
  1493.     pendwrite = TRUE;
  1494.     WriteIOB->IOSer.io_Command = SDCMD_BREAK;
  1495.     WriteIOB->io_SerFlags &= ~SERF_QUEUEDBRK;
  1496.     SendIO((IOR *)WriteIOB);
  1497.     return(0);
  1498. }
  1499.  
  1500. /*
  1501.  * ttsndb -- send a BREAK
  1502.  *    flushes queued and active output
  1503.  */
  1504. int
  1505. ttsndb(void)
  1506. {
  1507.     return(sendbreak(275000L));
  1508. }
  1509.  
  1510. /*
  1511.  * ttsndlb -- send a long BREAK (1.5 sec)
  1512.  */
  1513. int
  1514. ttsndlb(void) {
  1515.     return(sendbreak(1500000L));
  1516. }
  1517.  
  1518. /*  T T G M D M  --  Get modem signals  */
  1519. /*
  1520.  Looks for the modem signals as defined by the BM_??? constants in
  1521.  ckcdeb.h, and returns those that are on as a bit mask.  Returns:
  1522.  -3 Not implemented
  1523.  -2 if the line does not have modem control
  1524.  -1 on error.
  1525.  >= 0 on success, with a bit mask containing the modem signals that are on.
  1526. */
  1527.  
  1528. int
  1529. ttgmdm(void) {
  1530.     struct IOExtSer *myread = ReadIOB;
  1531.     int z;
  1532.     UWORD status;
  1533.  
  1534.     if (!serialopen)
  1535.         return -1;
  1536.     Chk_Abort();
  1537.     if (pendread && !CheckIO((IOR *)myread)) return(0);
  1538.     if (TerminateRead() != 0) return(-1);
  1539.     myread->IOSer.io_Command = SDCMD_QUERY;
  1540.     if (DoIO((IOR *) myread) != 0)
  1541.         return -1;
  1542.     status = myread->io_Status;
  1543.     z = 0;
  1544.     if (status & (1<<2)) z |= BM_RNG;    /* active high */
  1545.     status = ~status;            /* rest are active low */
  1546.     if (status & (1<<3)) z |= BM_DSR;
  1547.     if (status & (1<<4)) z |= BM_CTS;
  1548.     if (status & (1<<5)) z |= BM_DCD;
  1549.     if (status & (1<<6)) z |= BM_RTS;
  1550.     if (status & (1<<7)) z |= BM_DTR;
  1551.     return(z);
  1552. }
  1553.  
  1554.  
  1555. /*
  1556.  * ttocq -- write char to serial device, queueing if necessary
  1557.  *    returns -2 on overrun, -1 on serial error
  1558.  *    use only in connect mode
  1559.  */
  1560. int
  1561. ttocq(char c)
  1562. {
  1563.     int i;
  1564.  
  1565.     if (!serialopen) return(-1);
  1566.     if (pendwrite && CheckIO((IOR *)WriteIOB))
  1567.     {
  1568.         pendwrite = FALSE;
  1569.         if (WaitIO((IOR *)WriteIOB) != 0) return(-1);
  1570.     }
  1571.     if (pendwrite)
  1572.     {
  1573.         if (nttoq >= NTTOQ) return(-2);        /* overrun */
  1574.         ttoq[(pttoq + nttoq++) % NTTOQ] = c;
  1575.     }
  1576.     else if (nttoq == 0)
  1577.         return(ttoc(c));
  1578.     else
  1579.     {
  1580.         i = ttoc(ttoq[pttoq]);
  1581.         ttoq[(pttoq + nttoq) % NTTOQ] = c;
  1582.         pttoq = (pttoq + 1) % NTTOQ;
  1583.         if (i < 0) return(-1);
  1584.     }
  1585.     return(1);
  1586. }
  1587.  
  1588. /*
  1589.  * ttonq -- returns number of characters in serial output queue
  1590.  */
  1591. int
  1592. ttonq(void)
  1593. {
  1594.         return(nttoq);
  1595. }
  1596.  
  1597. /*
  1598.  * conttb -- prepare for contti() usage
  1599.  */
  1600. void
  1601. conttb(void)
  1602. {
  1603.     /* flush queued input and output */
  1604.     queuedcon = -1;
  1605.     pttoq = nttoq = 0;
  1606. }
  1607.  
  1608. /*
  1609.  * contte -- end contti() usage
  1610.  *    this can be called after a tthang, it which case ttres will already
  1611.  *    have done this cleanup
  1612.  */
  1613. void
  1614. contte(void)
  1615. {
  1616.     /* clear any pending ^C, ^D interrupts */
  1617.     Chk_Abort();
  1618.  
  1619.     /* terminate any pending I/O */
  1620.     if (serialopen) SerialReset();
  1621. }
  1622.  
  1623. /*
  1624.  * contti -- wait for console or tty input
  1625.  *    returns next console input or -1 when serial input available
  1626.  */
  1627. int
  1628. contti(void)
  1629. {
  1630.     int i;
  1631.     LONG waitsigs;
  1632.     struct DosPacket *pkt = conpkt;
  1633.     struct IOExtSer *myread = ReadIOB;
  1634.     static UBYTE conchar;
  1635.     BPTR dosfh = DOSFH(0);
  1636.     struct FileHandle *fh = (struct FileHandle *)BADDR(dosfh);
  1637.  
  1638.     if (queuedcon >= 0)
  1639.     {
  1640.         conchar = queuedcon;
  1641.         queuedcon = -1;
  1642.         return((int)conchar);
  1643.     }
  1644.  
  1645.     if (!pendconsole)
  1646.     {    /* start a console read */
  1647.         pkt->dp_Port = conport;
  1648.         pkt->dp_Type = ACTION_READ;
  1649.         pkt->dp_Arg1 = (LONG)dosfh;
  1650.         pkt->dp_Arg2 = (LONG)&conchar;
  1651.         pkt->dp_Arg3 = 1;
  1652.         PutMsg(fh->fh_Process, pkt->dp_Link);
  1653.         pendconsole = TRUE;
  1654.     }
  1655.  
  1656.     if (queuedser < 0 && !pendread)
  1657.     {    /* start a serial read */
  1658.         myread->IOSer.io_Command = CMD_READ;
  1659.         myread->IOSer.io_Data    = (APTR)&serbufc;
  1660.         myread->IOSer.io_Length  = 1;
  1661.         SendIO((IOR *)myread);
  1662.         pendread = TRUE;
  1663.     }
  1664.  
  1665.     waitsigs = (1L << serport->mp_SigBit) | (1L << conport->mp_SigBit);
  1666.     for (;;)
  1667.     {
  1668.         if (pendwrite && CheckIO((IOR *)WriteIOB))
  1669.         {
  1670.             WaitIO((IOR *)WriteIOB);
  1671.             pendwrite = FALSE;
  1672.             if (nttoq > 0)
  1673.             {
  1674.                 i = ttoc(ttoq[pttoq]);
  1675.                 pttoq = (pttoq + 1) % NTTOQ;
  1676.                 --nttoq;
  1677.                 if (i < 0) return(-1);
  1678.             }
  1679.         }
  1680.  
  1681.         /* give the console first chance */
  1682.         if (GetMsg(conport))
  1683.         {
  1684.             pendconsole = FALSE;
  1685.             if (pkt->dp_Res1 != 1) return(-1);
  1686.             /* translate CSI to ESC [ */
  1687.             if (conchar == 0x9B)
  1688.             {
  1689.                     conchar = 0x1B;
  1690.                 queuedcon = '[';
  1691.             }
  1692.             return((int)conchar);
  1693.         }
  1694.  
  1695.         if (queuedser >= 0) return(-2);
  1696.  
  1697.         if (CheckIO((IOR *)myread))
  1698.             return((TerminateRead() == 0) ? -2 : -1);
  1699.  
  1700.         Wait(waitsigs);
  1701.     }
  1702. }
  1703.  
  1704. /* P S U S P E N D -- Put current process in background. */
  1705.  
  1706. /*
  1707.  * Even though this isn't supported on the Amiga, I return success anyway.
  1708.  * After all, the user can pop the window to the back and do something
  1709.  * else any time he wants.
  1710.  */
  1711.  
  1712. int
  1713. psuspend(int foo) {
  1714.     return 0;
  1715. }
  1716.  
  1717. /* P R I V _ functions -- all dummy on the Amiga. */
  1718.  
  1719. int
  1720. priv_ini(void) {
  1721.     return 0;
  1722. }
  1723.  
  1724.  
  1725. int
  1726. priv_on(void) {
  1727.     return 0;
  1728. }
  1729.  
  1730. int
  1731. priv_off(void) {
  1732.     return 0;
  1733. }
  1734.  
  1735. int
  1736. priv_can(void) {
  1737.     return 0;
  1738. }
  1739.