home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / c-kermit / ckmtio.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  59KB  |  1,988 lines

  1. char *ckxv = "Communications I/O, 5A(084), 8 Feb 96";
  2.  
  3. /*  C K M T I O  --  interrupt, console, and port functions for Mac Kermit  */
  4. /*
  5. COPYRIGHT NOTICE:
  6.  
  7.   Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
  8.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  9.   sold for profit as a software product itself, nor may it be included in or
  10.   distributed with commercial products or otherwise distributed by commercial
  11.   concerns to their clients or customers without written permission of the
  12.   Office of Kermit Development and Distribution, Columbia University.  This
  13.   copyright notice must not be removed, altered, or obscured.
  14. */
  15. /*
  16.  Variables:
  17.  
  18.    dftty  -- Pointer to default tty name string, like "/dev/tty".
  19.    dfloc  -- 0 if dftty is console, 1 if external line.
  20.    dfprty -- Default parity
  21.    dfflow -- Default flow control
  22.    ckxech -- Flag for who echoes console typein:
  23.      1 - The program (system echo is turned off)
  24.      0 - The system (or front end, or terminal).
  25.    functions that want to do their own echoing should check this flag
  26.    before doing so.
  27.  
  28.  Functions for assigned communication line (either external or console tty):
  29.  
  30.    ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access.
  31.    ttclos()                -- Close & reset the tty, releasing any access lock.
  32.    ttpkt(speed,flow)       -- Put the tty in packet mode and set the speed.
  33.    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
  34.    ttinl(dest,max,timo)    -- Timed read line from the tty.
  35.    ttinc(timo)             -- Timed read character from tty.
  36.    ttchk()                 -- See how many characters in tty input buffer.
  37.    ttxin(n,buf)            -- Read n characters from tty (untimed).
  38.    ttol(string,length)     -- Write a string to the tty.
  39.    ttoc(c)                 -- Write a character to the tty.
  40.    ttflui()                -- Flush tty input buffer.
  41.  
  42. Functions for console terminal:
  43.  
  44.    congm()   -- Get console terminal modes.
  45.    concb()   -- Put the console in single-character wakeup mode with no echo.
  46.    conbin()  -- Put the console in binary (raw) mode.
  47.    conres()  -- Restore the console to mode obtained by congm().
  48.    conoc(c)  -- Unbuffered output, one character to console.
  49.    conol(s)  -- Unbuffered output, null-terminated string to the console.
  50.    conxo(n,s) -- Unbuffered output, n characters to the console.
  51.    conchk()  -- Check if characters available at console.
  52.    coninc()  -- Get a character from the console.
  53.    conint()  -- Enable terminal interrupts on the console.
  54.    connoi()  -- Disable terminal interrupts on the console.
  55.  
  56. Time functions
  57.  
  58.    msleep(m) -- Millisecond sleep
  59.    ztime(&s) -- Return pointer to date/time string
  60. */
  61.  
  62. #include <StdArg.h>
  63. #include <CRMSerialDevices.h>
  64. #include <CommResources.h>
  65.  
  66. #include "ckcdeb.h"        /* Formats for debug() */
  67. #include "ckcker.h"        /* kermit defs */
  68. #include "ckmdef.h"        /* macintosh defs */
  69. #include "ckcasc.h"
  70. #include "ckmwin.h"
  71. #include "ckmcon.h"
  72. #include "ckmptp.h"        /* ckm* Prototypes */
  73. #include "ckuusr.h"
  74. #include "ckmres.h"
  75.  
  76. char default_port_name[256];
  77. char *dftty = default_port_name;
  78.  
  79. /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
  80.  
  81. int dfloc = 1;
  82.  
  83. /* Other defaults */
  84.  
  85. int dfprty = 0;            /* Default parity */
  86. int ttprty = 0;            /* Parity in use. */
  87. long ttspeed = -1;        /* For saving speed */
  88. int dfflow = 1;            /* Xon/Xoff flow control */
  89. int ttflow = -9;        /* For saving flow */
  90. int fDTR = 0;            /* DTR input flow control */
  91. int fCTS = 0;            /* CTS output flow control */
  92. int fInX = 0;            /* send xoff when buffer almost full */
  93.  
  94. int backgrd = 0;        /* a Mac is allways in foreground */
  95.  
  96. /* Local variables */
  97.  
  98. int drop_dtr = 0;        /* drop DTR on Quit */
  99.  
  100. /* buffer and pointer for input processing */
  101. static char *my_input_buf;    /* we give this to the serial driver queue */
  102.  
  103. /* Private buffer for myread() and its companions.  Not for use by anything
  104.  * else.  ttflui() is allowed to reset them to initial values.  ttchk() is
  105.  * allowed to read my_count.
  106.  *
  107.  * my_item is an index into mybuf[].  Increment it *before* reading mybuf[].
  108.  *
  109.  * A global parity mask variable could be useful too.  We could use it to
  110.  * let myread() strip the parity on its own, instead of stripping sign
  111.  * bits as it does now.
  112.  */
  113.  
  114. /* #define MYBUFLEN 256 */
  115. #define MYBUFLEN 2048
  116. static unsigned char *mybufp;        /* Buffer, including push back */
  117. static int my_count = 0;        /* Number of chars still in mybuf */
  118. static int my_item = -1;        /* Last index read from mybuf[] */
  119.  
  120.  
  121. #ifdef COMMENT
  122. #define TTBUFL 200        /* good size (it's RBUFL guys!) */
  123. static unsigned char *ttbuf;
  124. #endif
  125.  
  126. static char *tto_buf;            /* output buffer for ttol() */
  127. static ParamBlockRec iopb;        /* paramater block for ttol() */
  128. static long tto_startticks;        /* when we started the output */
  129. #define XOFFTIMEO 480L            /* a timeout of 8 seconds (in ticks) */
  130.  
  131. short dfltVol;                /* Volume for Take- and Log-File */
  132.  
  133. extern Boolean have_128roms;        /* True if we are a Plus or better */
  134.  
  135. extern char ttname[];
  136.  
  137. extern  SIGTYP (*alarmfunc)();
  138. extern  SIGTYP (*intfunc)();
  139. typedef unsigned long ulong;
  140. extern ulong alarmtime;            /* Global alarm time */
  141.  
  142. extern int pflag;
  143.  
  144. static void ucharout (char c);
  145.  
  146. /****************************************************************************/
  147. /*  S Y S I N I T  --  System-dependent program initialization.  */
  148. /****************************************************************************/
  149. sysinit() {
  150.     ParamBlockRec pb;
  151.  
  152.     mac_init ();            /* Set up the Mac */
  153.  
  154.     /* Get the default volume reference number for Take- and Log-Files */
  155.     pb.volumeParam.ioNamePtr = NIL;
  156.     PBGetVol (&pb, FALSE);
  157.     dfltVol = pb.volumeParam.ioVRefNum;
  158.  
  159.     findfinderfiles();            /* See if file was selected */
  160.     /*
  161.      * If we did not open a port in findfinderfiles(), select the default port
  162.      * and open it now.
  163.      */
  164.     if (innum == 0) {
  165.     default_serial_port(default_port_name);
  166.     dftty = default_port_name;
  167.  
  168.     port_open(dftty);
  169.     parity = DEFPAR;
  170.     if (!setserial (innum, outnum, DSPEED, DEFPAR))    /* set speed parity */
  171.       macfatal("Couldn't set serial port to default speed",0);
  172.     (void) sershake(flow);
  173.     ttres(); /* (PWP) set up flow control for interactive use */
  174.     }
  175.     mac_post_load_init();        /* Show the terminal window etc */
  176.     return(0);
  177. } /* sysinit */
  178.  
  179. /* init terminal I/O buffers */
  180. inittiobufs() {
  181. #ifdef COMMENT
  182.     if ((ttbuf = (unsigned char *) NewPtr(TTBUFL + 1)) == NIL)
  183.         macfatal("Can't allocate ttbuf", 0);
  184. #endif
  185.     if ((mybufp = (unsigned char *) NewPtr(MYBUFLEN + 4)) == NIL)
  186.         macfatal("Can't allocate mybufp", 0);
  187.     my_count = 0;        /* Number of chars still in mybuf */
  188.     my_item = -1;        /* Last index read from mybuf[] */
  189.  
  190.     if ((tto_buf = (char *) NewPtr(MAXSP)) == NIL)
  191.         macfatal("Can't allocate tto_buf", 0);
  192.     if ((my_input_buf = (char *) NewPtr(MYBUFSIZE)) == NIL)
  193.         macfatal("Can't allocate my_input_buf", 0);
  194. }
  195.  
  196. /****************************************************************************/
  197. /* P O R T _ O P E N -- Open and init a serial port.  port is either -6 (for */
  198. /*  the modem port) or -8 (for the printer port)                */
  199. /****************************************************************************/
  200.  
  201. #ifdef MPW
  202. #define RamSDOpen RAMSDOPEN        /* Fix routine name */
  203. #else    /* !MPW (Think C) */
  204. #define RamSDOpen(n)    (noErr)        /* Don't really do anything */
  205. #endif    /* !MPW */
  206.  
  207. port_open (char *port_name) {
  208.     int err;
  209.     char scratch[256];
  210.     Str255 p_port_name, input_driver_name, output_driver_name;
  211.  
  212.     strcpy((char *)p_port_name, port_name);
  213.     c2pstr(p_port_name);
  214.  
  215.     /* Set up IO drivers */
  216.  
  217.     if (!portnameToDriver(p_port_name,input_driver_name, output_driver_name)) {
  218.     sprintf(scratch, "Could not find the serial port \"%s\"", port_name);
  219.     printerr(scratch, 0);
  220.     innum = outnum = 0;
  221.     return;
  222.     }
  223.  
  224.     /*
  225.      * See if the port is already open. If so, warn the user before proceeding.
  226.      */
  227. #if 1
  228.     if (!HaveSerialPortArbitration()) { /* if no arbitrator */
  229.     if (isOpenDriver(output_driver_name)) {
  230.         if (checkPortConflict(port_name)) {
  231.         return;
  232.         }
  233.     }
  234.     }
  235. #else
  236.     if (isOpenDriver(output_driver_name)) {
  237.     if (checkPortConflict(port_name)) {
  238.         return;
  239.     }
  240.     }
  241. #endif
  242.  
  243.     if ((err = OpenDriver(input_driver_name, &innum)) != noErr) {
  244.     if (err == portInUse) {
  245.         sprintf(scratch, "Output port \"%s\" is in use", port_name);
  246.         err = 0;
  247.     } else
  248.         sprintf(scratch, "Could not open output \"%s\": ", port_name);
  249.     printerr(scratch, err);
  250.     innum = outnum = 0;
  251.     return;
  252.     }
  253.     if ((err = OpenDriver(output_driver_name, &outnum)) != noErr) {
  254.     if (err == portInUse) {
  255.         sprintf(scratch, "Input port \"%s\" is in use", port_name);
  256.         err = 0;
  257.     } else
  258.         sprintf(scratch, "Could not open input \"%s\": ", port_name);
  259.     CloseDriver(innum);
  260.     innum = outnum = 0;
  261.     return;
  262.     }
  263.  
  264.     /* Make driver use larger buff */
  265.     err = SerSetBuf (innum, my_input_buf, MYBUFSIZE);
  266.     if (err)
  267.     printerr ("Trouble making IO buffer:", err);
  268.  
  269.     strcpy(ttname, port_name);
  270. }
  271.  
  272. /*****************************************************************************/
  273. /* P O R T _ C L O S E -- Close down the serial port.                 */
  274. /*****************************************************************************/
  275. port_close() {
  276.     int err;
  277.     ParamBlockRec cpb;
  278.  
  279.     if (!innum)
  280.         return;            /* already closed */
  281.  
  282.     err = KillIO(innum);    /* Kill off IO drivers */
  283.     if (err != noErr)
  284.         printerr("trouble KillIO-ing serial input driver:",err);
  285.     err = KillIO(outnum);    /* Kill off IO drivers */
  286.     if (err != noErr)
  287.         printerr("trouble KillIO-ing serial output driver:",err);
  288.  
  289.     err = SerSetBuf (innum, NULL, 0);    /* Make driver default buffer */
  290.     if (err != noErr)
  291.         printerr("trouble resetting serial IO buffer:",err);
  292.  
  293. /*    if (usingRAMdriver) { */
  294.  
  295.     if (!drop_dtr) {
  296.         bzero((char *) &cpb, sizeof(cpb));
  297.         cpb.cntrlParam.ioNamePtr = NULL;    /* IM-IV p226 */
  298.         /* tell the ram driver not to lower DTR on close */
  299.         cpb.cntrlParam.csCode = 16;        /* misc serial control */
  300.         *((unsigned char *) cpb.cntrlParam.csParam) = 0x80;
  301.                 /* don't lower DTR */
  302.         cpb.cntrlParam.ioCRefNum = innum;
  303.         err = PBControl(&cpb, FALSE);
  304.         if ((err != noErr) && (err != -1))
  305.         printerr(
  306.           "trouble telling RAM serial driver (in) not to lower DTR:",
  307.              err);
  308.  
  309.         bzero((char *) &cpb, sizeof(cpb));
  310.         cpb.cntrlParam.ioNamePtr = NULL;    /* IM-IV p226 */
  311.         cpb.cntrlParam.csCode = 16;        /* misc serial control */
  312.         /* don't lower DTR */
  313.         *((unsigned char *) cpb.cntrlParam.csParam) = 0x80;
  314.         cpb.cntrlParam.ioCRefNum = outnum;
  315.         err = PBControl(&cpb, FALSE);
  316.         if ((err != noErr) && (err != -1))
  317.           printerr("\
  318. trouble telling RAM serial driver (out) not to lower DTR:",err);
  319.     }
  320.  
  321. /*    RamSDClose (sPortA); */    /* this "returns" void */
  322. /*    } */
  323.  
  324.     err = CloseDriver (innum);
  325.     if (err != noErr)
  326.     printerr("trouble closing serial input driver:",err);
  327. /*
  328.  * For some reason or other, doing this close on a 64k ROM machine will cause
  329.  * the mouse to freeze.  Since the input driver is the only one that really
  330.  * matters, we just close it.
  331.  */
  332.     if (have_128roms) {
  333.     err = CloseDriver (outnum);
  334.     if (err != noErr)
  335.         printerr("trouble closing serial output driver:",err);
  336.     }
  337.  
  338.     /* mark things as closed */
  339.     innum = outnum = 0;
  340. }
  341.  
  342. /****************************************************************************/
  343. /*  T T O P E N  --  Open a tty for exclusive access.  */
  344. /*                                                       */
  345. /*  ttname = C string, name of communications device     */
  346. /*  lcl    = (doesn't mean anything in Mac Kermit        */
  347. /*  modem  = 0 if no modem, positive if there is a modem */
  348. /*  timeo  = (not used in Mac Kermit)                    */
  349. /*                                                       */
  350. /*  Returns 0 on success, -1 on failure.                 */
  351. /****************************************************************************/
  352. int
  353. ttopen (ttname, lcl, modem, timeo)
  354. char *ttname;
  355. int *lcl;
  356. int modem;
  357. int timeo;
  358. #pragma unused (modem, timeo)
  359. {
  360.     int saved_drop_dtr;
  361.  
  362.     my_count = 0;            /* Initialize myread() stuff */
  363.     my_item = -1;
  364.  
  365.     if (*lcl < 0)
  366.       *lcl = 1;                /* Always in local mode */
  367.  
  368.     if (mybufp == NIL)
  369.       macfatal("No mybufp", 0);
  370.     if (tto_buf == NIL)
  371.       macfatal("No tto_buf", 0);
  372.     if (my_input_buf == NIL)
  373.       macfatal("No my_input_buf", 0);
  374.  
  375.     iopb.ioParam.ioResult = 0;        /* No pending output */
  376.  
  377.     iopb.ioParam.ioActCount = 0;    /* For error checking in ttol() */
  378.     iopb.ioParam.ioReqCount = 0;
  379.  
  380.     /* Re-open the port if it has changed. */
  381.     /* ddddd don't do this if no change in port name ? */
  382.  
  383.     saved_drop_dtr = drop_dtr;
  384.     drop_dtr = 1;            /* So we don't confuse AppleTalk */
  385.     port_close();
  386.     drop_dtr = saved_drop_dtr;
  387.     port_open(ttname);
  388.     if (!setserial (innum, outnum, speed, KPARITY_NONE))
  389.     printfalert("Problem setting port speed");
  390.     (void) sershake(flow);        /* Set flow control */
  391.  
  392.     return (0);
  393. } /* ttopen */
  394.  
  395. /****************************************************************************/
  396. /*  T T C L O S  --  Close the TTY, releasing any lock.  */
  397. /****************************************************************************/
  398. int
  399. ttclos ()
  400. {
  401.     my_count = 0;            /* Initialize myread() stuff */
  402.     my_item = -1;
  403.  
  404.     return 0;
  405. }                /* ttclos */
  406.  
  407. /*
  408.  * sershake
  409.  * Set handshake parameters on serial port.
  410.  */
  411. int sershake (int flow)
  412. {
  413.     int err;
  414.     ParamBlockRec pb;
  415.     SerShk *controlparam;    /* To change serial driver paramaters */
  416.  
  417.     if (!innum)
  418.         return 0;        /* if port closed, do nothing */
  419.  
  420.     bzero((char *)&pb, sizeof(pb));
  421.     controlparam = (SerShk *) &pb.cntrlParam.csParam;
  422.     /*
  423.      * Old code used to issue controls to in and out sides. IM-IV
  424.      * says to use the output driver.
  425.      */
  426.     pb.cntrlParam.ioCRefNum = outnum;
  427.     if (have_128roms)
  428.       pb.cntrlParam.csCode = 14;    /* SerHShake + DTR */
  429.     else
  430.       pb.cntrlParam.csCode = 10;    /* SerHShake */
  431.  
  432.     if (flow)
  433.       controlparam->fXOn = TRUE;    /* obey flow control */
  434.     else
  435.       controlparam->fXOn = FALSE;    /* ignore flow control */
  436.     controlparam->fCTS = fCTS;        /* output flow control */
  437.     controlparam->xOn = 17;
  438.     controlparam->xOff = 19;
  439.     controlparam->errs = FALSE;
  440.     controlparam->evts = FALSE;
  441.     if (flow && fInX)
  442.       controlparam->fInX = TRUE;    /* flow control when almost full */
  443.     else
  444.       controlparam->fInX = FALSE;
  445.     controlparam->fDTR = fDTR;        /* input flow control */
  446.  
  447.     err = PBControl(&pb, FALSE);
  448.     if (err != noErr) {
  449.     printfalert("sershake: problem setting handshake: %d", err);
  450.     return -1;
  451.     }
  452.  
  453.     return 0;
  454. }
  455.  
  456.  
  457.  
  458. /****************************************************************************/
  459. /*  T T P K T  --  Condition the communication line for packets. */
  460. /*  If called with speed > -1, also set the speed.  */
  461. /*  Returns 0 on success, -1 on failure.  */
  462. /****************************************************************************/
  463. int
  464. ttpkt (long spd, int flow, int parity)    /* we only care about flow here */
  465. {
  466. #pragma unused (spd)
  467.  
  468.     ttprty = parity;                    /* Let other tt functions see these. */
  469.     ttspeed = speed;        /* $$$ is this correct? */
  470.     ttflow = flow;            /* Now make this available too. */
  471.  
  472.     fInX = TRUE;
  473.     return(sershake(flow));
  474. }
  475.  
  476.  
  477. /****************************************************************************/
  478. /*  T T V T  --  Condition the communication line for a virtual terminal. */
  479. /*  If called with spd > -1, also set the spd.  */
  480. /*  Returns 0 on success, -1 on failure.  */
  481. /****************************************************************************/
  482. int
  483. ttvt (spd, flow, parity)    /* all ignoreed */
  484. long spd;
  485. int flow;
  486. int parity;
  487. #pragma unused (spd, flow, parity)
  488. {
  489.     (void) ttres();
  490.     return (0);
  491. }                /* ttvt */
  492.  
  493.  
  494. /****************************************************************************/
  495. /*  T T F L U I  --  Flush tty input buffer */
  496. /****************************************************************************/
  497. int
  498. ttflui ()
  499. {
  500.     int err;
  501.  
  502.     my_count = 0;            /* Initialize myread() stuff */
  503.     my_item = -1;
  504.  
  505.     if (!innum)
  506.         return 0;            /* if port closed, do nothing */
  507.  
  508.     err = KillIO (innum);
  509.     if (err)
  510.     printerr ("Bad input clear", err);
  511.  
  512.     return (0);
  513. }                /* ttflui */
  514.  
  515. int
  516. ttfluo()                /* Flush output buffer */
  517. {
  518.     int err;
  519.  
  520.     if (!innum)
  521.         return 0;            /* if port closed, do nothing */
  522.  
  523.     err = KillIO (outnum);
  524.     if (err)
  525.     printerr ("Bad ouput clear", err);
  526.  
  527.     return (0);                /* (dummy for now) */
  528. }
  529.  
  530. /****************************************************************************/
  531. /*  T T S N D B  --  Send a break */
  532. /****************************************************************************/
  533. ttsndb() {
  534.     long finalticks;
  535.  
  536.     if (!innum)
  537.         return 0;            /* if port closed, do nothing */
  538.  
  539.     /* delay wants 1/60th units */
  540.  
  541.     SerSetBrk (outnum);            /* start breaking */
  542.     Delay ((long) 15, &finalticks);    /* delay about 250ms */
  543.     SerClrBrk (outnum);            /* stop breaking */
  544.     return 0;
  545. }
  546.  
  547. /****************************************************************************/
  548. /*
  549.  *   Flushio:
  550.  *      Initialize some communications constants, and clear screen and
  551.  *      character buffers. */
  552. /****************************************************************************/
  553. flushio () {
  554.     int err;
  555.  
  556.     if (!innum)
  557.       return 0;                /* if port closed, do nothing */
  558.  
  559.     err = KillIO (innum);
  560.     if (err)
  561.       printerr ("Bad input clear", err);
  562.     err = KillIO (outnum);
  563.     if (err)
  564.       printerr ("Bad ouput clear", err);
  565.     return 0;
  566. } /* flushio */
  567.  
  568.  
  569.  
  570. /****************************************************************************/
  571. /* sendbreak - sends a break across the communictions line.
  572.  *
  573.  * The argument is in units of approximately 0.05 seconds (or 50
  574.  * milliseconds).  To send a break of duration 250 milliseconds the
  575.  * argument would be 5; a break of duration 3.5 seconds would be (umm,
  576.  * lets see now) 70.
  577.  *
  578.  */
  579. /****************************************************************************/
  580. sendbreak (msunit) int msunit; {
  581.     long finalticks;
  582.  
  583.     if (!innum)
  584.       return 0;                /* if port closed, do nothing */
  585.  
  586. /* delay wants 1/60th units.  We have 3/60 (50 ms.) units, convert */
  587.  
  588.     msunit = msunit * 3;
  589.  
  590.     SerSetBrk (outnum);            /* start breaking */
  591.     Delay ((long) msunit, &finalticks);    /* delay */
  592.     SerClrBrk (outnum);            /* stop breaking */
  593.     return 0;
  594. } /* sendbreak */
  595.  
  596. /****************************************************************************/
  597. /* toggledtr - Turn DTR off, wait a bit, turn it back on.
  598.  *
  599.  * the argument is in the same units as sendbreak (see above).
  600.  */
  601. /****************************************************************************/
  602. toggle_dtr (msunit) int msunit; {
  603.     long finalticks;
  604.     ParamBlockRec pb;
  605.     int err;
  606.  
  607.     if (!innum)
  608.       return 0;                /* if port closed, do nothing */
  609.  
  610.     /* delay wants 1/60th units.  We have 3/60 (50 ms.) units, convert */
  611.  
  612.     msunit = msunit * 3;
  613.  
  614.     pb.cntrlParam.csCode = 18;        /* lower DTR */
  615.     pb.cntrlParam.ioCRefNum = outnum;
  616.     err = PBControl (&pb, FALSE);
  617.     if (err != noErr)
  618.       printerr ("toggle_dtr() trouble lowering DTR: ", err);
  619.  
  620.     Delay ((long) msunit, &finalticks);    /* delay */
  621.  
  622.     pb.cntrlParam.csCode = 17;        /* raise DTR */
  623.     pb.cntrlParam.ioCRefNum = outnum;
  624.     err = PBControl (&pb, FALSE);
  625.     if (err != noErr)
  626.       printerr ("toggle_dtr() trouble raising DTR: ", err);
  627.  
  628.     return 0;
  629. } /* sendbreak */
  630.  
  631. /****************************************************************************/
  632. /* do_xon - xon the output port and send an xon (control-Q) character        */
  633. /****************************************************************************/
  634. do_xon () {
  635.     ParamBlockRec pb;
  636.     int err;
  637.  
  638.     if (!innum)
  639.       return 0;                /* if port closed, do nothing */
  640.     pb.cntrlParam.csCode = 22;        /* clear XOFF for my output */
  641.     pb.cntrlParam.ioCRefNum = outnum;
  642.     err = PBControl (&pb, FALSE);
  643.     if (err != noErr)
  644.       printerr ("do_xon() trouble unblocking output port: ", err);
  645.  
  646.     pb.cntrlParam.csCode = 24;        /* unconditionally send XON */
  647.     pb.cntrlParam.ioCRefNum = outnum;
  648.     err = PBControl (&pb, FALSE);
  649.     if (err != noErr)
  650.       printerr ("do_xon() trouble sending XON: ", err);
  651.     return 0;
  652. } /* do_xon */
  653.  
  654. /****************************************************************************/
  655. /*  T T S S P D  --  Set tty speed */
  656. /****************************************************************************/
  657.  
  658. ttsspd (cps) int cps; {
  659.     if (!innum)
  660.       return 0;                /* if port closed, do nothing */
  661.  
  662.     if (setserial (innum, outnum, cps*10, KPARITY_NONE))
  663.       return(0);
  664.     else
  665.       return (-1);
  666. }
  667.  
  668. /****************************************************************************/
  669. /*  T T G S P D  --  Get tty speed */
  670. /****************************************************************************/
  671.  
  672. long
  673. ttgspd () {
  674.     if (speed <= 0L && innum != 0)
  675.       printerr("Speed got reset, now == ", (int) speed);
  676.     return (speed);
  677. }
  678.  
  679. /* Interrupt Functions */
  680.  
  681. /****************************************************************************/
  682. /* Set up terminal interrupts on console terminal */
  683. /* Set an interrupt trap. */
  684. /****************************************************************************/
  685. VOID conint(SIGTYP (*f)(int), SIGTYP (*s)(int)) {
  686. #pragma unused (f, s)
  687.     return;
  688. } /* conint */
  689.  
  690.  
  691.  
  692. /****************************************************************************/
  693. /* Reset console terminal interrupts */
  694. /****************************************************************************/
  695. VOID connoi () {
  696.     return;
  697. } /* connoi */
  698.  
  699. /****************************************************************************/
  700. /* writeps - write a pascal string to the serial port.
  701.  *
  702.  */
  703. /****************************************************************************/
  704. void
  705. writeps (StringPtr s) {
  706.     long wcnt, w2;
  707.     StringPtr s2;
  708.  
  709.     w2 = wcnt = *s++;            /* get count */
  710.  
  711.     for (s2 = s; w2 > 0; w2--, s2++)    /* add parity */
  712.     *s2 = dopar (*s2);
  713.  
  714.     /* ttol will printerr() if it has a problem */
  715.     (void) ttol((CHAR *) s, wcnt);
  716.  
  717.     return;
  718. } /* writeps */
  719.  
  720. extern Boolean have_multifinder;/* true if running under MF */
  721. extern Boolean in_background;    /* becomes true if running MF and in bg */
  722. extern long mf_sleep_time;    /* number of 60ths between task time */
  723.  
  724. /****************************************************************************/
  725. /*  T T O L  --  Similar to "ttinl", but for writing.  */
  726. /****************************************************************************/
  727. ttol (s, n) CHAR *s; int n; {
  728.     long finalticks;
  729.     int err;
  730.     ParamBlockRec cpb;
  731.  
  732.     if (!innum)
  733.       return (-1);            /* if port closed, do nothing */
  734.  
  735. #ifdef COMMENT
  736.     debug(F101,"ttol n","",n);
  737.     debug(F101," s","",s);
  738.  
  739.     /*
  740.      * the straight-forward way to write out a buffer: synchronously
  741.      */
  742.     finalticks = n;
  743.     err = FSWrite(outnum, &finalticks, s);
  744.     if ((err != noErr) || (finalticks != n)) {
  745.     printerr("ttol FSWrite error: ", err);
  746.     return (-1);
  747.     }
  748.     return (n);
  749. #endif
  750.     /*
  751.      * The fancy way to write out strings: do async writes, waiting for the
  752.      * previous call to finish first (and possibly unsticking the serial
  753.      * driver)
  754.      */
  755.     /* wait for previous call to finish */
  756.     /* while the prev. request is still running */
  757.     while (iopb.ioParam.ioResult == 1) {
  758.     /* if we're running protocol */
  759.     if (have_multifinder && protocmd != 0) {
  760.         miniparser (TRUE);        /* keep mac running */
  761.         finalticks = TickCount ();
  762.     } else {            /* else terminal emulation */
  763.         Delay ((long) 1, &finalticks); /* wait for a bit */
  764.     }
  765.     /* (PWP) If we have waited too long, unblock the output (keep the
  766.        Mac from freezing up) */
  767.     if (finalticks > (tto_startticks + XOFFTIMEO)) {
  768.         cpb.cntrlParam.csCode = 22;    /* clear XOFF for my output */
  769.         cpb.cntrlParam.ioCRefNum = outnum;
  770.         err = PBControl (&cpb, FALSE);
  771.         if (err != noErr)
  772.         printerr ("ttol() trouble unblocking output port: ", err);
  773.         tto_startticks = TickCount (); /* Get starting time */
  774.     }
  775.     }
  776.  
  777.     /* check for errors in previous call */
  778.     if (iopb.ioParam.ioResult) {
  779.     printerr ("Error in previous PBWrite:", iopb.ioParam.ioResult);
  780.     return (-1);
  781.     }
  782.     if (iopb.ioParam.ioActCount != iopb.ioParam.ioReqCount) {
  783.     printerr ("PBWrite to serial didn't write enough: ",
  784.           iopb.ioParam.ioActCount);
  785.     printerr ("(asked for:)", iopb.ioParam.ioReqCount);
  786.     return (-1);
  787.     }
  788.  
  789.     /* the previous call is now done, so we can load in our new information */
  790.  
  791.     if (n > MAXSP) {            /* MAXSP == sizeof(tto_buf) */
  792.         printerr("ttol asked to write too many chars: ", n);
  793.     return (-1);
  794.     }
  795.     bcopy((char *) s, tto_buf, n);    /* in ckmfio.h if nowhere else */
  796.  
  797.     iopb.ioParam.ioCompletion = NULL;
  798.     iopb.ioParam.ioNamePtr = NULL;
  799.     iopb.ioParam.ioVRefNum = 0;
  800.  
  801.     iopb.ioParam.ioRefNum = outnum;
  802.     iopb.ioParam.ioVersNum = 0;
  803.     iopb.ioParam.ioPermssn = 0;
  804.     iopb.ioParam.ioMisc = NULL;
  805.     iopb.ioParam.ioBuffer = tto_buf;
  806.     iopb.ioParam.ioReqCount = (long) n;
  807.     iopb.ioParam.ioPosMode = 0;
  808.     iopb.ioParam.ioPosOffset = 0;
  809.  
  810.     tto_startticks = TickCount ();    /* get starting time */
  811.  
  812.     PBWrite (&iopb, TRUE);        /* request an async. write */
  813.     if (protocmd != 0)
  814.       miniparser (TRUE);        /* allow other tasks to run */
  815.     return (n);                /* fake a good run */
  816. } /* ttol */
  817.  
  818.  
  819. /*  T T O C  --  Output a character to the communication line  */
  820.  
  821. ttoc(char c) {
  822.     char foo[2];
  823.  
  824.     foo[0] = c;
  825.     foo[1] = '\0';
  826.     return (ttol((CHAR *) foo, 1));
  827. }
  828.  
  829. /* myread() -- Efficient read of one character from communications line.
  830.  *
  831.  * Uses a private buffer to minimize the number of expensive read() system
  832.  * calls.  Essentially performs the equivalent of read() of 1 character, which
  833.  * is then returned.  By reading all available input from the system buffers
  834.  * to the private buffer in one chunk, and then working from this buffer, the
  835.  * number of system calls is reduced in any case where more than one character
  836.  * arrives during the processing of the previous chunk, for instance high
  837.  * baud rates or network type connections where input arrives in packets.
  838.  * If the time needed for a read() system call approaches the time for more
  839.  * than one character to arrive, then this mechanism automatically compensates
  840.  * for that by performing bigger read()s less frequently.  If the system load
  841.  * is high, the same mechanism compensates for that too.
  842.  *
  843.  * myread() is a macro that returns the next character from the buffer.  If the
  844.  * buffer is empty, mygetbuf() is called.  See mygetbuf() for possible error
  845.  * returns.
  846.  *
  847.  * This should be efficient enough for any one-character-at-a-time loops.
  848.  * For even better efficiency you might use memcpy()/bcopy() or such between
  849.  * buffers (since they are often better optimized for copying), but it may not
  850.  * be worth it if you have to take an extra pass over the buffer to strip
  851.  * parity and check for CTRL-C anyway.
  852.  *
  853.  * Note that if you have been using myread() from another program module, you
  854.  * may have some trouble accessing this macro version and the private variables
  855.  * it uses.  In that case, just add a function in this module, that invokes the
  856.  * macro.
  857.  */
  858.  
  859. #define mac_myread(timeo_ticks,intim)  (--my_count < 0 \
  860.             ? mac_mygetbuf(timeo_ticks,intim) \
  861.             : (int) (mybufp[++my_item]))
  862.  
  863. /* Specification: Push back up to one character onto myread()'s queue.
  864.  *
  865.  * This implementation: Push back characters into mybuf. At least one character
  866.  * must have been read through myread() before myunrd() may be used.  After
  867.  * EOF or read error, again, myunrd() can not be used.  Sometimes more than
  868.  * one character can be pushed back, but only one character is guaranteed.
  869.  * Since a previous myread() must have read its character out of mybuf[],
  870.  * that guarantees that there is space for at least one character.  If push
  871.  * back was really needed after EOF, a small addition could provide that.
  872.  *
  873.  * myunrd() is currently not called from anywhere inside kermit...
  874.  */
  875. #ifdef NOTUSED
  876. myunrd(ch) CHAR ch; {
  877.     if (my_item >= 0) {
  878.     mybufp[my_item--] = ch;
  879.     ++my_count;
  880.     }
  881. }
  882. #endif
  883.  
  884. /* mygetbuf() -- Fill buffer for myread() and return first character.
  885.  *
  886.  * This function is what myread() uses when it can't get the next character
  887.  * directly from its buffer.  First, it calls a system dependent myfillbuf()
  888.  * to read at least one new character into the buffer, and then it returns
  889.  * the first character just as myread() would have done.  This function also
  890.  * is responsible for all error conditions that myread() can indicate.
  891.  *
  892.  * Returns: When OK    => a positive character, 0 or greater.
  893.  *        When EOF    => -2.
  894.  *        When error    => -3, error code in errno.
  895.  *
  896.  * Older myread()s additionally returned -1 to indicate that there was nothing
  897.  * to read, upon which the caller would call myread() again until it got
  898.  * something.  The new myread()/mygetbuf() always gets something.  If it
  899.  * doesn't, then make it do so!  Any program that actually depends on the old
  900.  * behaviour will break.
  901.  *
  902.  * The older version also used to return -2 both for EOF and other errors,
  903.  * and used to set errno to 9999 on EOF.  The errno stuff is gone, EOF and
  904.  * other errors now return different results, although Kermit currently never
  905.  * checks to see which it was.  It just disconnects in both cases.
  906.  *
  907.  * Kermit lets the user use the quit key to perform some special commands
  908.  * during file transfer.  This causes read(), and thus also mygetbuf(), to
  909.  * finish without reading anything and return the EINTR error.  This should
  910.  * be checked by the caller.  Mygetbuf() could retry the read() on EINTR,
  911.  * but if there is nothing to read, this could delay Kermit's reaction to
  912.  * the command, and make Kermit appear unresponsive.
  913.  *
  914.  * The debug() call should be removed for optimum performance.
  915.  */
  916. /* myfillbuf():
  917.  * System-dependent read() into mybuf[], as many characters as possible.
  918.  *
  919.  * Returns: OK => number of characters read, always more than zero.
  920.  *          EOF => 0
  921.  *          Error => -1, error code in errno.
  922.  *
  923.  * If there is input available in the system's buffers, all of it should be
  924.  * read into mybuf[] and the function return immediately.  If no input is
  925.  * available, it should wait for a character to arrive, and return with that
  926.  * one in mybuf[] as soon as possible.  It may wait somewhat past the first
  927.  * character, but be aware that any such delay lengthens the packet turnaround
  928.  * time during kermit file transfers.  Should never return with zero characters
  929.  * unless EOF or irrecoverable read error.
  930.  *
  931.  * Correct functioning depends on the correct tty parameters being used.
  932.  * Better control of current parameters is required than may have been the
  933.  * case in older Kermit releases.  For instance, O_NDELAY (or equivalent) can
  934.  * no longer be sometimes off and sometimes on like it used to, unless a
  935.  * special myfillbuf() is written to handle that.  Otherwise the ordinary
  936.  * myfillbuf()s may think they have come to EOF.
  937.  *
  938.  * If your system has a facility to directly perform the functioning of
  939.  * myfillbuf(), then use it.  If the system can tell you how many characters
  940.  * are available in its buffers, then read that amount (but not less than 1).
  941.  * If the system can return a special indication when you try to read without
  942.  * anything to read, while allowing you to read all there is when there is
  943.  * something, you may loop until there is something to read, but probably that
  944.  * is not good for the system load.
  945.  */
  946.  
  947. int
  948. mac_mygetbuf(long timeo_tics, long intim) {
  949.     long avail;                /* can't be register */
  950.     long finaltics;            /* can't be register */
  951.     int err;
  952.     extern int tlevel;
  953.  
  954.     if (mybufp == NIL)
  955.       macfatal("No mybufp (in mac_mygetbuf())", 0);
  956.  
  957.     if (!innum)
  958.       return -1;            /* if port closed, do nothing */
  959.  
  960.     for (;;) {
  961.     SerGetBuf (innum, &avail);    /* Get available count */
  962.  
  963.     if (avail > 0)
  964.       break;            /* we can get these chars */
  965.  
  966.     /* no chars availiable yet */
  967.     if ((protocmd != 0) || (tlevel > -1) || intfunc) {
  968.         miniparser (TRUE);        /* keep mac running */
  969.         if (sstate == 'a')    {    /* abort occured? */
  970.         if (intfunc) {
  971.             sstate = '\0';
  972.             (*intfunc)(0);
  973.         } else
  974.             return (-1);    /* ugh, look like timeout */
  975.         }
  976.     }
  977.  
  978.     /*
  979.      * Check alarm() timeouts.
  980.      */
  981.     if (alarmtime && alarmfunc && (((ulong)TickCount() - alarmtime) > 0))
  982.         (*alarmfunc)(0);
  983.  
  984.     finaltics = TickCount ();
  985.     if (timeo_tics > 0) {        /* Want to do timeout? */
  986.         if (intim + timeo_tics < finaltics) {
  987.         return (-1);        /* Too long, give up */
  988.         }
  989.     }
  990.  
  991.     /* go back and try to get more chars */
  992.     }
  993.     if (avail > MYBUFLEN)
  994.       avail = MYBUFLEN;
  995.  
  996.     /*
  997.      * CAREFUL: the Mac FSRead() function gets how much to read,
  998.      * AND PUTS HOW MUCH IT DID READ into avail
  999.      */
  1000.     err = FSRead (innum, &avail, mybufp); /* Into our buffer */
  1001.  
  1002.     if (err != noErr) {
  1003.     screen(SCR_EM,0,(long) err,"Serial input error:");
  1004.     return (-3);    /* return input error */
  1005.     }
  1006.     if (avail <= 0) {
  1007.     screen(SCR_EM, 0, (long) avail,
  1008.            "No serial input error, but didn't read any:");
  1009.     return (-3);    /* return input error */
  1010.     }
  1011.  
  1012.     /* not at end of packet yet, so let other tasks have a chance */
  1013.     if (in_background)
  1014.       miniparser (TRUE);        /* allow other tasks to run */
  1015.  
  1016.     my_count = (int) avail;
  1017.  
  1018.     /* debug(F101, "myfillbuf read", "", my_count); */
  1019.  
  1020.     --my_count;
  1021.     return((int) (mybufp[my_item = 0]));
  1022. }
  1023.  
  1024. /****************************************************************************/
  1025. /*  T T I N L  --  Read a record (up to break character) from comm line.  */
  1026. /*
  1027.   If no break character encountered within "max", return "max" characters,
  1028.   with disposition of any remaining characters undefined.  Otherwise, return
  1029.   the characters that were read, including the break character, in "dest" and
  1030.   the number of characters read as the value of function, or 0 upon end of
  1031.   file, or -1 if an error occurred.  Times out & returns error if not completed
  1032.   within "timo" seconds.
  1033. */
  1034. /*
  1035.   Reads up to "max" characters from the communication line, terminating on
  1036.   the packet-end character (eol), or timing out and returning -1 if the eol
  1037.   character not encountered within "timo" seconds.  The characters that were
  1038.   input are copied into "dest" with their parity bits stripped if parity was
  1039.   selected.  Returns the number of characters read.  Characters after the
  1040.   eol are available upon the next call to this function.
  1041.  
  1042.   The idea is to minimize the number of system calls per packet, and also to
  1043.   minimize timeouts.  This function is the inner loop of the program and must
  1044.   be as efficient as possible.  The current strategy is to use myread().
  1045.  
  1046.   WARNING: this function calls parchk(), which is defined in another module.
  1047.   Normally, ckutio.c does not depend on code from any other module, but there
  1048.   is an exception in this case because all the other ck?tio.c modules also
  1049.   need to call parchk(), so it's better to have it defined in a common place.
  1050. */
  1051. /****************************************************************************/
  1052.  
  1053. #define CTRLC '\03'
  1054.  
  1055. #ifdef PARSENSE
  1056. int
  1057. ttinl(CHAR *dest, int max, int timo, CHAR eol, CHAR start) {
  1058.     int flag;
  1059. #else
  1060. int
  1061. ttinl(CHAR *dest, int max, int timo, CHAR eol) {
  1062. #endif
  1063.     register int i, m, n;        /* local variables */
  1064.     int x;
  1065.     long timeoticks;
  1066.     long intim;            /* when we started */
  1067.  
  1068.     debug(F101,"ttinl max","",max);
  1069.     debug(F101,"ttinl timo","",timo);
  1070.  
  1071. #ifdef PARSENSE
  1072.     debug(F000,"ttinl start","",start);
  1073.     flag = 0;                /* Start of packet flag */
  1074. #endif
  1075.  
  1076.     x = 0;                /* Return code */
  1077.     m = (ttprty) ? 0177 : 0377;         /* Parity stripping mask. */
  1078.     *dest = '\0';                       /* Clear destination buffer */
  1079.  
  1080.     if (timo <= 0) {        /* untimed */
  1081.     timo = 0;        /* Safety */
  1082.     intim = 0;        /* tell mac_myread not to timeout */
  1083.     timeoticks = 0;
  1084.     } else {
  1085.     timeoticks = timo * 60;
  1086.     intim = TickCount ();    /* now */
  1087.     }
  1088.  
  1089.     i = 0;
  1090.     while (i < max-1) {
  1091.     /* debug(F101,"ttinl i","",i); */
  1092.     if ((n = mac_myread(timeoticks,intim)) < 0) {
  1093.         debug(F101,"ttinl myread failure, n","",n);
  1094.         x = -1; break;
  1095.     }
  1096.     /* debug(F101,"ttinl char","",n&m); */
  1097.  
  1098. #ifdef PARSENSE
  1099.     if ((flag == 0) && ((n & 0x7f) == start)) flag = 1;
  1100.     if (flag) dest[i++] = n & m;
  1101. #else
  1102.     dest[i++] = n & m;
  1103. #endif /* PARSENSE */
  1104.  
  1105. #ifdef PARSENSE
  1106.     if (flag == 0) {
  1107.         debug(F101,"ttinl skipping","",n);
  1108.         continue;
  1109.     }
  1110. #endif /* PARSENSE */
  1111.  
  1112.     /* Check for end of packet */
  1113.  
  1114.     if ((n & 0x7f) == eol) {
  1115.         debug(F101,"ttinl got eol","",eol);
  1116.         dest[i] = '\0';        /* Yes, terminate the string, */
  1117.         /* debug(F101,"ttinl i","",i); */
  1118.  
  1119. #ifdef PARSENSE
  1120. /* Here's where we actually check and adjust the parity. */
  1121. /* The major flaw here is if parity is NONE (ttprty = 0) and the packets */
  1122. /* really do have no parity, then parchk() is called for every packet. */
  1123. /* In practice, this doesn't really harm efficiency noticably, but it would */
  1124. /* be better if ttinl() had a way of knowing to stop doing this once a */
  1125. /* particular file transfer had been started and checked. */
  1126.         if (ttprty == 0) {
  1127.         if ((ttprty = parchk(dest,start,i)) > 0) {
  1128.             register int j;
  1129.             debug(F101,"ttinl senses parity","",ttprty);
  1130.             debug(F110,"ttinl packet before",dest,0);
  1131.             for (j = 0; j < i; j++)
  1132.             dest[j] &= 0x7f; /* Strip parity from packet */
  1133.             debug(F110,"ttinl packet after ",dest,0);
  1134.         } else debug(F101,"parchk","",ttprty);
  1135.         }
  1136. #endif
  1137.         debug(F111,"ttinl got", dest,i);
  1138.         return(i);
  1139.     }
  1140.     }        /* end while (i < max-1) */
  1141.     debug(F100,"ttinl timout","",0);    /* Get here on timeout. */
  1142.     debug(F111," with",dest,i);
  1143.     return(x);                          /* and return error code. */
  1144.  
  1145. }                /* ttinl */
  1146.  
  1147.  
  1148. /****************************************************************************/
  1149. /* ttinc(timo) - read a character with timeout.  Return -1 on timeout. */
  1150. /****************************************************************************/
  1151. int
  1152. ttinc (int timo) {
  1153.     register int m, n = 0;
  1154.     long timeoticks;
  1155.     long intim;            /* when we started */
  1156.  
  1157.     if (timo <= 0) {        /* untimed */
  1158.     intim = 0;        /* tell mac_myread not to timeout */
  1159.     timeoticks = 0;
  1160.     } else {
  1161.     timeoticks = timo * 60;
  1162.     intim = TickCount ();    /* now */
  1163.     }
  1164.  
  1165.     m = (ttprty) ? 0177 : 0377;         /* Parity stripping mask. */
  1166.  
  1167.         /* comm line failure returns -1 thru myread, so no &= 0377 */
  1168.     n = mac_myread(timeoticks,intim);    /* Wait for a character... */
  1169.  
  1170.     /* debug(F101,"ttinc n","",n); */
  1171.     return(n < 0 ? n : n & m);
  1172. } /* ttinc */
  1173.  
  1174. /****************************************************************************/
  1175. /* PWP: input as many chars as we can read from the serial line right now   */
  1176. /****************************************************************************/
  1177. int
  1178. ttinm(register char *buf, register int max) {
  1179.     long avil, num;
  1180.     int err, i;
  1181.  
  1182.     if (!innum)
  1183.         return 0;        /* if port closed, do nothing */
  1184.     /*
  1185.      * DANGER WILL ROBINSON: this KNOWS about how mac_myread works
  1186.      * (in an incestuous way), so BE CAREFUL!!!
  1187.      */
  1188.     if (my_count > 0) {        /* do we have chars buffered up? */
  1189.         for (i = 0; (my_count > 0) && (i < max); i++)
  1190.       *buf++ = mac_myread(0L, 0L);
  1191.     return (i);        /* return contents of previous read buffer */
  1192.     }
  1193.  
  1194.     SerGetBuf (innum, &avil);    /* Get available count */
  1195.  
  1196.     if (avil > 0) {            /* Have something? */
  1197.     num = (avil > max) ? max : avil; /* Set max */
  1198.  
  1199.     err = FSRead (innum, &num, buf); /* Into our buffer */
  1200.     if (err != noErr)
  1201.         printerr ("Serial input error: ", err);
  1202.     return (num);            /* return how many */
  1203.     } else {
  1204.         return (0);
  1205.     }
  1206. }
  1207.  
  1208. /****************************************************************************/
  1209. /****************************************************************************/
  1210. int
  1211. ttchk () {
  1212.     long avcnt;                /* pascal long */
  1213.  
  1214.     if (!innum)
  1215.       return 0;                /* if port closed, none available */
  1216.  
  1217.     SerGetBuf (innum, &avcnt);        /* get available */
  1218.  
  1219.     return (avcnt + my_count);        /* return avail plus our own */
  1220. } /* ttchk */
  1221.  
  1222. /****************************************************************************/
  1223. /* T T R E S -- Reset the serial line after doing a protocol things        */
  1224. /****************************************************************************/
  1225. ttres () {
  1226.     fInX = FALSE;
  1227.     return(sershake(flow));
  1228. }
  1229.  
  1230. unsigned long starttime;
  1231. Boolean timerRunning = FALSE;
  1232.  
  1233. /****************************************************************************/
  1234. /*  R T I M E R --  Reset elapsed time counter  */
  1235. /****************************************************************************/
  1236. VOID rtimer () {
  1237.     GetDateTime (&starttime);
  1238.     timerRunning = TRUE;
  1239. }                /* rtimer */
  1240.  
  1241. /****************************************************************************/
  1242. /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
  1243. /****************************************************************************/
  1244. int
  1245. gtimer () {
  1246.     unsigned long secs;
  1247.  
  1248.     if (timerRunning) {
  1249.     GetDateTime (&secs);
  1250.     return (secs - starttime);
  1251.     timerRunning = FALSE;
  1252.     } else
  1253.       return (0);
  1254. } /* gtimer */
  1255.  
  1256. /****************************************************************************/
  1257. /*  Z T I M E  --  Return date/time string  */
  1258. /* Various bits stolen from Unix Kermit assume that ztime() returns */
  1259. /* a asctime() format string, vis: */
  1260. /* "Thu Feb  8 12:00:00 1990" */
  1261. /****************************************************************************/
  1262. VOID ztime (s) char **s; {
  1263. /*
  1264.   ztime() MUST return a string in asctime() format.
  1265. */
  1266.     unsigned long secs;
  1267.     DateTimeRec dtrec;
  1268.     static char dtime[32];    /* really only 25 needed, but be safe */
  1269.     static char *month_names[] = {
  1270.     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1271.     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  1272.     };
  1273.     static char *day_names[] = {
  1274.     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  1275.     };
  1276.     GetDateTime (&secs);
  1277.     Secs2Date (secs, &dtrec);
  1278.     sprintf(dtime, "%3s %3s %2d %2d:%02d:%02d %4d",
  1279.         day_names[dtrec.dayOfWeek - 1],
  1280.         month_names[dtrec.month - 1],
  1281.         dtrec.day, dtrec.hour, dtrec.minute, dtrec.second, dtrec.year);
  1282.  
  1283.     *s = dtime;
  1284.  
  1285. #ifdef COMMENT
  1286. #include <Time.h>
  1287.     time_t time(time_t *timer);
  1288.     char *ctime(const time_t *timer);
  1289.  
  1290.     time_t time_now;
  1291.     time_now = time( (time_t) 0 );
  1292.     *s = ctime( &time_now );
  1293. #endif /* COMMENT */
  1294. }                /* ztime */
  1295.  
  1296. /* Console IO routines.  The console is implemented as a text edit structure.
  1297.  * These routines are supported:
  1298.  *
  1299.  * conoc(c)   -- output one character to TE record at insertion point
  1300.  * conol(s)   -- output null terminated string to TE record " "
  1301.  * conoll(s)  -- same but with CR on the end
  1302.  * conxo(n,s) -- n character to TE record " "
  1303.  *
  1304.  */
  1305.  
  1306. #define NILTE ((TEHandle ) NILPTR)
  1307. #define LF 012
  1308. #define CR 015
  1309.  
  1310. /****************************************************************************/
  1311. /*  C O N X O  --  Output string of length len to console text edit record  */
  1312. /****************************************************************************/
  1313. conxo (len, s)
  1314.     int len;
  1315.     register char *s; {
  1316.     register char *t;
  1317.  
  1318.     /* change NLs to CRs for the Mac */
  1319.     for (t = s; *t && (t - s < len); t++)
  1320.         if (*t == LF)
  1321.         *t = CR;
  1322.  
  1323.     /* debug (F101, "conxo here: ", s, len); */
  1324.     if (rcmdw->teh == NULL)
  1325.     return(0);
  1326.  
  1327.     TEDeactivate(rcmdw->teh);
  1328.     (void) trimcon(rcmdw, len);
  1329.     TEInsert (s, (long) len, rcmdw->teh); /* insert the string */
  1330.     TESetSelect(TE_MAX, TE_MAX, rcmdw->teh);
  1331.     TEActivate(rcmdw->teh);
  1332.     rcdwscroll (rcmdw);            /* possibly scroll it */
  1333.  
  1334.     return (0);
  1335. } /* conxo */
  1336.  
  1337.  
  1338. /****************************************************************************/
  1339. /*  C O N O C  --  Output a character to the console text edit record */
  1340. /****************************************************************************/
  1341. conoc (char c) {
  1342.     (void) conxo (1, &c);
  1343. }                    /* conoc */
  1344.  
  1345. /****************************************************************************/
  1346. /****************************************************************************/
  1347. conopen () {
  1348.     return (1);
  1349. } /* conopen */
  1350.  
  1351. /****************************************************************************/
  1352. /*  C O N O L  --  Write a line to the console text edit record  */
  1353. /****************************************************************************/
  1354. conol (s) register char *s; {
  1355.     return (conxo (strlen (s), s));
  1356. } /* conol */
  1357.  
  1358. /****************************************************************************/
  1359. /*  C O N O L L  --  Output a string followed by CRLF  */
  1360. /****************************************************************************/
  1361. conoll (s) char *s; {
  1362.     (void) conol (s);            /* first the string */
  1363.     (void) conoc (CR);            /* now the return */
  1364.     return (0);
  1365. } /* conoll */
  1366.  
  1367. /*****************************************
  1368.  *    C-Kermit Compatibility routines    *
  1369.  *****************************************/
  1370.  
  1371. /*
  1372.  * dummy routines for MAC
  1373.  */
  1374. #define CINC(v,l)((v+1 == l)? 0 : v+1)
  1375. #define CBL 25                /* console buffer length */
  1376. int cbin = 0;                /* circular buffer pointers */
  1377. int cbout = 0;
  1378. unsigned char cbuf[CBL];        /* console buffer */
  1379.  
  1380. concb (char esc) {
  1381. #pragma unused (esc)
  1382. }
  1383.  
  1384. conres () {
  1385. }
  1386.  
  1387. conchk () {
  1388.     if (sstate == 'a')            /* if cmd-. in miniparser */
  1389.       return 1;
  1390.     else
  1391.       return 0;
  1392. }
  1393.  
  1394. tthang () {
  1395.     toggle_dtr(70);
  1396.     return(1);
  1397. }
  1398.  
  1399. VOID
  1400. setint () {
  1401. }
  1402.  
  1403. /*
  1404.  * ttgmdm
  1405.  * Get modem control signals.
  1406.  * The mac only has one input handshake (CTS) and one output
  1407.  * line (DTR).  DTR may not be present on older MACS with
  1408.  * DB-9 (instead of DIN-8) connectors.
  1409.  */
  1410. ttgmdm() {
  1411.     int err, r;
  1412.     SerStaRec stat;
  1413.  
  1414.     err = SerStatus(outnum, &stat);
  1415.     if (err != noErr) {
  1416.     printfalert("ttgmdm: Error getting serial status: %d", err);
  1417.     return -1;            /* not available */
  1418.     }
  1419.     r = 0;
  1420.     if (!stat.ctsHold)
  1421.     r |= BM_CTS;
  1422.     /*
  1423.      * Always say dtr is on. We may be lying if we've enabled
  1424.      * dtr input flow control.
  1425.      */
  1426.     r |= BM_DTR;
  1427.  
  1428.     return r;
  1429. }
  1430.  
  1431.  
  1432. /*
  1433.  * Things from ckutio.c
  1434.  */
  1435. int ckxech = 1;       /* 0 if system normally echoes console characters, else 1 */
  1436.  
  1437. int ttcarr = CAR_AUT;            /* Carrier handling mode. */
  1438.  
  1439. #include "ckuver.h"            /* Version herald */
  1440. char *ckxsys = HERALD;
  1441.  
  1442. /*  T T S C A R R  --  Set ttcarr variable, controlling carrier handling.
  1443.  *
  1444.  *  0 = Off: Always ignore carrier. E.g. you can connect without carrier.
  1445.  *  1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
  1446.  *  2 = Auto: For "modem direct": The same as "Off".
  1447.  *            For real modem types: Heed carrier during connect, but ignore
  1448.  *                it anytime else.  Compatible with pre-5A C-Kermit versions.
  1449.  *
  1450.  * As you can see, this setting does not affect dialing, which always ignores
  1451.  * carrier (unless there is some special exception for some modem type).  It
  1452.  * does affect ttopen() if it is set before ttopen() is used.  This setting
  1453.  * takes effect on the next call to ttopen()/ttpkt()/ttvt().  And they are
  1454.  * (or should be) always called before any communications is tried, which
  1455.  * means that, practically speaking, the effect is immediate.
  1456.  *
  1457.  * Of course, nothing of this applies to remote mode (xlocal = 0).
  1458.  *
  1459.  * Someone has yet to uncover how to manipulate the carrier in the BSD
  1460.  * environment (or any non-termio using environment).  Until that time, this
  1461.  * will simply be a no-op for BSD.
  1462.  *
  1463.  * Note that in previous versions, the carrier was most often left unchanged
  1464.  * in ttpkt()/ttvt() unless they were called with DIALING or CONNECT.  This
  1465.  * has changed.  Now it is controlled by ttcarr in conjunction with these
  1466.  * modes.
  1467.  */
  1468. int ttscarr (carrier) int carrier; {
  1469.     ttcarr = carrier;
  1470.     debug(F101, "ttscarr","",ttcarr);
  1471.     return(ttcarr);
  1472. }
  1473.  
  1474. VOID bgchk () {  /* Check background status */
  1475. #ifdef notdef
  1476.     if (bgset < 0) pflag = !backgrd;
  1477.     else pflag = (bgset == 0 ? 1 : 0);
  1478. #endif
  1479. }
  1480.  
  1481. /*  T T X I N  --  Get n characters from tty input buffer  */
  1482.  
  1483. /*  Returns number of characters actually gotten, or -1 on failure  */
  1484.  
  1485. /*  Intended for use only when it is known that n characters are actually */
  1486. /*  Available in the input buffer.  */
  1487.  
  1488. int ttxin (n,buf) int n; CHAR *buf; {
  1489.     int i, c;
  1490.  
  1491.     for (i = 0; i < n; i++) {
  1492.     c = ttinc(0);
  1493.     if (c < 0)
  1494.         return -1;
  1495.     *buf++ = ttinc(0);        /* ignore errors */
  1496.     }
  1497.     return n;
  1498. }
  1499.  
  1500.  
  1501. /*  C O N I N C  --  Get a character from the console  */
  1502.  
  1503. int coninc (timo) int timo; {
  1504.     int c;
  1505.  
  1506.     newparser(1, 0, (long) timo);    /* wait till timeout, no menus */
  1507.  
  1508.     if (cbin == cbout)            /* if timeout */
  1509.     return -1;
  1510.  
  1511.     c = cbuf[cbout];
  1512.     cbout = CINC(cbout, CBL);        /* advance pointer */
  1513.  
  1514.     return c;
  1515. }
  1516.  
  1517. /*
  1518.  * puts for mac console
  1519.  */
  1520. int
  1521. mac_puts (const char *string) {
  1522.     const char *cp;
  1523.  
  1524.     if (cmdinterminal)
  1525.     cursor_erase (ttermw);
  1526.  
  1527.     for (cp = string; *cp; cp++)
  1528.     ucharout(*cp);
  1529.  
  1530.     if (cmdinterminal) {
  1531.     if (ttermw->scroll_amount)
  1532.         flushscroll(ctermw);    /* sync the screen */
  1533.     if (ctermw->out_maxcol)        /* KLUDGE */
  1534.         flushbuf(ctermw);
  1535.     cursor_draw(ctermw);
  1536.     }
  1537.  
  1538.     return 1;            /* $$$ what should this be? */
  1539. }
  1540.  
  1541. /*
  1542.  * printf for mac console
  1543.  */
  1544. int
  1545. mac_printf (const char *format, ...) {
  1546.     int i, rc;
  1547.     char string[512];        /* Hope that this is big enough!! */
  1548.     char *cp;
  1549.     va_list ap;
  1550.  
  1551.     va_start(ap, format);
  1552.     rc = vsprintf(string, format, ap);
  1553.     va_end(ap);
  1554.  
  1555.     if ((i = strlen(string)) >= sizeof(string))
  1556.     printerr("Overran allocation for string in printf(), len:", i);
  1557.  
  1558.     if (cmdinterminal)
  1559.     cursor_erase (ttermw);
  1560.  
  1561.     for (cp = string; *cp; cp++)
  1562.     ucharout(*cp);
  1563.  
  1564.     if (cmdinterminal) {
  1565.     if (ctermw->scroll_amount)
  1566.         flushscroll(ctermw);        /* sync the screen */
  1567.     if (ctermw->out_maxcol)        /* KLUDGE */
  1568.         flushbuf(ctermw);
  1569.     cursor_draw(ctermw);
  1570.     }
  1571.     return (rc);
  1572. }
  1573.  
  1574. int
  1575. mac_perror (const char *s) {
  1576.     mac_printf("MacError: %s\n",s);
  1577. }
  1578.  
  1579. /*
  1580.  * putchar for mac console
  1581.  */
  1582. int
  1583. mac_putchar (int c) {
  1584.     if (cmdinterminal)
  1585.     cursor_erase (ttermw);
  1586.  
  1587.     ucharout(c);
  1588.  
  1589.     if (cmdinterminal) {
  1590.     if (ctermw->scroll_amount)
  1591.         flushscroll(ctermw);        /* sync the screen */
  1592.     if (ctermw->out_maxcol)        /* KLUDGE */
  1593.         flushbuf(ctermw);
  1594.     cursor_draw(ctermw);
  1595.     }
  1596.     return 1;                /* $$$ what should this be? */
  1597. }
  1598.  
  1599.  
  1600. /*
  1601.  * outchar
  1602.  * output a character to a termw window.
  1603.  */
  1604. void outchar (struct termw *termw, char c) {
  1605.     unsigned char buf[2];
  1606.  
  1607.     buf[0] = c;
  1608.     buf[1] = 0;
  1609.  
  1610.     printem(termw, buf, 1);
  1611. }
  1612.  
  1613. /*
  1614.  * Send a single character to the console, unix format.
  1615.  * The MPW compiler thinks that '\r' is 0x0a and that
  1616.  * '\n' is 0x0d.  In this routine, we translate things
  1617.  * to the appropriate action.
  1618.  *
  1619.  * This will be broken if we call this routine with chars
  1620.  * that are already correct, e.g.: CR.
  1621.  */
  1622. static void
  1623. ucharout (char c) {
  1624.     switch (c) {
  1625.     case '\n':                /* unix newline -> CR, LF */
  1626.     cmdout(LF);
  1627.     cmdout(CR);
  1628.     return;
  1629.     case '\r':                /* \r -> CR */
  1630.     cmdout(CR);
  1631.     return;
  1632.     default:
  1633.     cmdout(c);
  1634.     return;
  1635.     }
  1636. }
  1637.  
  1638.  
  1639. /*
  1640.  * cmdout
  1641.  * write a character to the command window
  1642.  * (copied from conxo)
  1643.  */
  1644. VOID cmdout (char c) {
  1645.     unsigned char buf[2];
  1646.  
  1647.     buf[0] = c;
  1648.     buf[1] = 0;
  1649.     /*
  1650.      * Output to terminal window if no command window.
  1651.      */
  1652.     if (cmdinterminal) {
  1653.     printem(ttermw, buf, 1);
  1654.     return;
  1655.     }
  1656.     printem(ctermw, buf, 1);
  1657. }
  1658.  
  1659.  
  1660. /*
  1661.  * getchar for mac console
  1662.  */
  1663. int
  1664. mac_getchar () {
  1665.     int c;
  1666.  
  1667.     while (cbin == cbout) {        /* while buffer is empty */
  1668.     if (sstate = newparser(1, 1, 0L)) {
  1669.         if (sstate == 'p')        /* if wakeup flag */
  1670.         sstate = '\0';
  1671.         else if (sstate == 'n') {    /* if null command state */
  1672.         sstate = '\0';
  1673.         return (-3);
  1674.         } else
  1675.         return(-3);            /* NULL command */
  1676.     }
  1677.     }
  1678.     c = cbuf[cbout];
  1679.     cbout = CINC(cbout, CBL);        /* advance pointer */
  1680.  
  1681.     return c;
  1682. }
  1683.  
  1684. #ifdef THINK_C
  1685. /* Just a dummy so that we can use so ckuus*.c */
  1686. char *
  1687. getenv(const char *s) {
  1688.     return (NULL);        /* the Mac doesn't have an "environment" */
  1689. }
  1690. #endif /* THINK_C */
  1691.  
  1692. /*
  1693.  * writecbc
  1694.  * Store a character into the console input buffer.
  1695.  */
  1696. writecbc (c) char c; {
  1697.     int t;
  1698.  
  1699.     cbuf[cbin] = c;
  1700.     t = CINC(cbin, CBL);        /* advance pointer */
  1701.     if (t == cbout)            /* if buffer was full */
  1702.     return;                /* drop character */
  1703.     cbin = t;
  1704. }
  1705.  
  1706. /*
  1707.  * writecb
  1708.  * Store a pascal string into the console input buffer.
  1709.  */
  1710. writecb (string) char *string; {
  1711.     int l, i;
  1712.  
  1713.     l = *string++;            /* length */
  1714.     for (i = 0; i < l; i++)
  1715.     writecbc(*string++);
  1716. }
  1717.  
  1718. /*  C O N B I N  --  Put console in binary mode  */
  1719.  
  1720. /*  Returns 0 if ok, -1 if not  */
  1721.  
  1722. int
  1723. conbin (char esc) {
  1724. #pragma unused (esc)
  1725.     return 0;
  1726. }
  1727.  
  1728.  
  1729. /*
  1730.  * portnameToDriver
  1731.  *
  1732.  * Return false if error
  1733.  */
  1734. Boolean portnameToDriver (unsigned char *port_name,
  1735.               unsigned char *input_driver,
  1736.               unsigned char *output_driver
  1737.               ) {
  1738.     CRMRecPtr crmp;
  1739.     CRMRec dummycrmrec;
  1740.     CRMSerialPtr serp;
  1741.     char hs1, hs2, hs3;
  1742.     Boolean found = false;
  1743.  
  1744.     /* if CTB ... */
  1745.     if (NGetTrapAddress(0x8b, OSTrap) != NGetTrapAddress(0x9f,OSTrap)) {
  1746.     crmp = &dummycrmrec;
  1747.     dummycrmrec.crmDeviceType = crmSerialDevice;
  1748.     dummycrmrec.crmDeviceID = 0;
  1749.     while (crmp = (CRMRecPtr)CRMSearch((QElemPtr)crmp)) {
  1750.         if (serp = (CRMSerialPtr)crmp->crmAttributes) {
  1751.         hs1 = HGetState((Handle)serp->outputDriverName);
  1752.         hs3 = HGetState((Handle)serp->inputDriverName);
  1753.         hs2 = HGetState((Handle)serp->name);
  1754.         HLock((Handle)serp->outputDriverName);
  1755.         HLock((Handle)serp->inputDriverName);
  1756.         HLock((Handle)serp->name);
  1757.         /* if portname match */
  1758.         if (EqualString(port_name, *serp->name, false, false)) {
  1759.             if (input_driver)
  1760.               BlockMove(*(char **)serp->inputDriverName,
  1761.                 input_driver,
  1762.                 256
  1763.                 );
  1764.             if (output_driver)
  1765.               BlockMove(*(char **)serp->outputDriverName,
  1766.                 output_driver,
  1767.                 256
  1768.                 );
  1769.             found = true;
  1770.         }
  1771.         HSetState((Handle)serp->outputDriverName, hs1);
  1772.         HSetState((Handle)serp->inputDriverName, hs3);
  1773.         HSetState((Handle)serp->name, hs2);
  1774.         if (found)
  1775.           return true;
  1776.         }
  1777.     }
  1778.     } else {
  1779.     if (EqualString(port_name, "\pPrinter", false, false)) {
  1780.         if (input_driver)
  1781.           BlockMove("\p.Bin", input_driver, 5);
  1782.         if (output_driver)
  1783.           BlockMove("\p.Bout", output_driver, 6);
  1784.         return true;
  1785.     } else {            /* default to Phone */
  1786.         if (input_driver)
  1787.           BlockMove("\p.Ain", input_driver, 5);
  1788.         if (output_driver)
  1789.           BlockMove("\p.Aout", output_driver, 6);
  1790.         return true;
  1791.     }
  1792.     }
  1793.     if (input_driver)
  1794.       *input_driver = '\0';
  1795.     if (output_driver)
  1796.       *output_driver = '\0';
  1797.     return false;
  1798. }
  1799.  
  1800.  
  1801. /*
  1802.  * Sets the default serial port name.
  1803.  */
  1804. void default_serial_port (char *default_name) {
  1805.     CRMRecPtr crmp;
  1806.     CRMRec dummycrmrec;
  1807.     CRMSerialPtr serp;
  1808.     char hs1, hs2, hs3;
  1809.     Boolean pass2 = false;
  1810.     Boolean found = false;
  1811.     /*
  1812.      * If the CTB is not present, default to the phone port.
  1813.      */
  1814.     if (NGetTrapAddress(0x8b, OSTrap) == NGetTrapAddress(0x9f,OSTrap)) {
  1815.     strcpy(default_name, "Phone");
  1816.     return;
  1817.     }
  1818.     /*
  1819.      * With the CTB, default to the Modem Port, unless it does not exist in
  1820.      * which case we use the first serial port we can find.
  1821.      */
  1822.  retry:
  1823.     crmp = &dummycrmrec;
  1824.     dummycrmrec.crmDeviceType = crmSerialDevice;
  1825.     dummycrmrec.crmDeviceID = 0;
  1826.     while (crmp = (CRMRecPtr)CRMSearch((QElemPtr)crmp)) {
  1827.     if (serp = (CRMSerialPtr)crmp->crmAttributes) {
  1828.         hs1 = HGetState((Handle)serp->outputDriverName);
  1829.         hs3 = HGetState((Handle)serp->inputDriverName);
  1830.         hs2 = HGetState((Handle)serp->name);
  1831.         HLock((Handle)serp->outputDriverName);
  1832.         HLock((Handle)serp->inputDriverName);
  1833.         HLock((Handle)serp->name);
  1834.         if (pass2 ||
  1835.         EqualString("\pModem Port", *serp->name, false, false)
  1836.         ) {
  1837.         BlockMove(*(char **)serp->name, default_name, 256);
  1838.         p2cstr(default_name);
  1839.         found = true;
  1840.         }
  1841.         HSetState((Handle)serp->outputDriverName, hs1);
  1842.         HSetState((Handle)serp->inputDriverName, hs3);
  1843.         HSetState((Handle)serp->name, hs2);
  1844.         if (found)
  1845.           return;
  1846.     }
  1847.     }
  1848.     if (pass2)
  1849.       macfatal("Could not find any serial ports to use", 0);
  1850.     pass2 = true;
  1851.     goto retry;
  1852. }
  1853.  
  1854.  
  1855. /*
  1856.  * Return driver ref if driver is open
  1857.  */
  1858. short
  1859. isOpenDriver (unsigned char *driverName) {
  1860.     short dref = 0;
  1861.     DCtlHandle dceHndl;
  1862.  
  1863.     if (dceHndl = findDriver(driverName))
  1864.       if ((*dceHndl)->dCtlFlags & 0x20) /* if open (bit 5) */
  1865.     dref = (*dceHndl)->dCtlRefNum;
  1866.     return dref;
  1867. }
  1868.  
  1869. /*
  1870.  * findDriver
  1871.  * Return driver dctlhandle if it exists.
  1872.  */
  1873.  
  1874. /* enum { UnitNtryCnt = 0x1D2 }; */
  1875. /* [GLOBAL VAR]  count of entries in unit table [word] */
  1876.  
  1877. #define LMGetUTableBase() (* (Ptr *) 0x011C)
  1878.  
  1879. DCtlHandle
  1880. findDriver (unsigned char *driverName) {
  1881.     short count;
  1882.     DCtlEntry **entry, ***utable;
  1883.     unsigned char *namePtr;
  1884.  
  1885.     count = *(short *)UnitNtryCnt;    /* number of entries in unit table */
  1886.     utable = (DCtlEntry ***)LMGetUTableBase(); /* the unit table */
  1887.  
  1888.     while (count-- > 0) {
  1889.     entry = *utable++;
  1890.  
  1891.     if (entry) {
  1892.         /* see if ram based (test bit 6) */
  1893.         if ((*entry)->dCtlFlags & 0x40) {
  1894.         /* in ram, so we have a handle */
  1895.         namePtr = (CHAR *)(*(Handle)((*entry)->dCtlDriver)) + 18;
  1896.         } else {
  1897.         /* in rom, so we have a pointer */
  1898.         namePtr = (CHAR *)((*entry)->dCtlDriver) + 18;
  1899.         }
  1900.         /* compare name, case insensitive, diacritical sensitive */
  1901.         if (RelString(driverName, namePtr, false, true) == 0) {
  1902.         return entry;
  1903.         }
  1904.     }
  1905.     }
  1906.     return 0;
  1907. }
  1908.  
  1909. /*
  1910.  * HaveSerialPortArbitration
  1911.  * Return true if the serial port arbitrator is present.
  1912.  */
  1913. #define gestaltArbitorAttr 'arb '
  1914. #define gestaltSerialArbitrationExists 0
  1915.  
  1916. #pragma parameter __D0 my_Gestalt(__D0,__A1)
  1917. pascal OSErr my_Gestalt(OSType selector,long *response) = {0xA1AD,0x2288};
  1918.  
  1919. #define _Unimplemented    0xA89F
  1920. #define _GestaltDispatch 0xA0AD
  1921.  
  1922. Boolean
  1923. HaveSerialPortArbitration() {
  1924.     int io;
  1925.     long attribs;
  1926.  
  1927.     /*
  1928.      * My copy of Think has bad glue for Gestalt, so do the
  1929.      * checks here.
  1930.      */
  1931.     if (NGetTrapAddress((short)_GestaltDispatch, OSTrap) ==
  1932.     NGetTrapAddress((short)_Unimplemented, ToolTrap))
  1933.       return false;
  1934.  
  1935.     io = my_Gestalt(gestaltArbitorAttr, &attribs);
  1936.     return ((io == noErr) && (attribs & (1<<gestaltSerialArbitrationExists)));
  1937. }
  1938.  
  1939. /*
  1940.  * checkPortConflict
  1941.  * Return true if we should not mess with open port
  1942.  */
  1943. Boolean
  1944. checkPortConflict (char *port_name) {
  1945.     DialogPtr dlg;
  1946.     short itemhit;
  1947.     char scratch[255];
  1948.     int v = -1;
  1949.     GrafPtr save_port;
  1950.  
  1951.     GetPort(&save_port);
  1952.  
  1953.     sprintf(scratch,
  1954.         "The \"%s\" port appears to be in use. Try to open it anyway?",
  1955.         port_name
  1956.         );
  1957.     c2pstr(scratch);
  1958.     ParamText(scratch, "", "", "");
  1959.     dlg = GetNewDialog (YESNOID, NILPTR, (WindowPtr) - 1);
  1960.     SetPort(dlg);
  1961.     circleOK(dlg);
  1962.  
  1963.     while (v == -1) {
  1964.     ModalDialog ((ModalFilterProcPtr) NILPROC, &itemhit);
  1965.     switch (itemhit) {
  1966.       case YN_YES:
  1967.         v = false;
  1968.         break;
  1969.       case YN_NO:
  1970.         v = true;
  1971.         break;
  1972.     }
  1973.     }
  1974.     DisposDialog(dlg);
  1975.     SetPort(save_port);
  1976.     return v;
  1977. }
  1978.  
  1979. /*
  1980.  * Junk so Emacs will set local variables to be compatible with Mac/MPW.
  1981.  * Should be at end of file.
  1982.  * this module uses 8 char tabs
  1983.  *
  1984.  * Local Variables:
  1985.  * tab-width: 8
  1986.  * End:
  1987.  */
  1988.