home *** CD-ROM | disk | FTP | other *** search
/ Mega CD-ROM 1 / megacd_rom_1.zip / megacd_rom_1 / MAGAZINE / DDJMAG / DDJ9111.ZIP / PORTUNIX.ASC < prev    next >
Text File  |  1991-10-18  |  21KB  |  796 lines

  1. _PORTING UNIX APPLICATIONS TO DOS_
  2. by David N. Glass
  3.  
  4.  
  5. [LISTING ONE]
  6.  
  7. /* Serial support for target communications. Assumes 8250 serial device */
  8.  
  9. #include <dos.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <i32.h>
  13. #include <process.h>
  14. #include "ttycntl.h"
  15. #include "gnudos.h"
  16.  
  17. static char serial_device[20];
  18. static int  serial_baud;
  19. static int  serial_devtype; /* Device identifier. */
  20. static int  serial_iobase;  /* I/O base value. */
  21. static int  serial_ivec;    /* Host interrupt vector. */
  22. static char serial_opened;  /* Flag set if file is opened */
  23. static char serial_setup;   /* Flag set if setup for port has started */
  24. static char serial_updated; /* Flag set if port values were altered */
  25.  
  26. static struct dupdef {
  27.     int num;
  28.     int max;
  29.     int *fd;
  30. } serial_dup = { 0, 5, NULL };
  31.  
  32. static void (*orig_serial_vec)() = 0;
  33.  
  34. #define IR3        0x0b
  35. #define IR4        0x0c
  36. #define IR5        0x0d
  37.  
  38. #define IMR_8259    0x21        /* int mask reg */
  39.  
  40. #define LOOPERMS    33        /* rough loop count per ms */
  41. #define BREAKMS     1000        /* break length in ms */
  42.  
  43. /*
  44.  * Map bauds onto counter values
  45.  */
  46. static struct baudmap {
  47.     unsigned long baud;
  48.     int code;
  49. } baudmap[] ={
  50.     {   1200, 0x060},
  51.     {   2400, 0x030},
  52.     {   4800, 0x018},
  53.     {   9600, 0x00C},
  54.     {  19200, 6},
  55.     {  38400, 3},
  56.     {  57600, 2},
  57.     { 115200, 1},
  58.     { 166600, -1},
  59.     { 250000, -1},
  60.     { 500000, -1},
  61.     { 750000, -1},
  62.     {1500000, -1},
  63.     {      0, 0}
  64. };
  65.  
  66. /*
  67.  * Input queue
  68.  */
  69. #define QBUFSZ    (3*1024)    /* queue size */
  70.  
  71. static struct queue {
  72.     int        q_cnt;        /* amount in buffer    */
  73.     unsigned    q_ovfl;     /* number of overflows    */
  74.     char *        q_in;        /* next free spot    */
  75.     char *        q_out;        /* next char out    */
  76.     char        q_buf[QBUFSZ];    /* character buffer    */
  77. } siq;        /* chars from remote port */
  78.  
  79.  
  80. static int  get_port(int comwhich);
  81. static void init_8259(unsigned int int_value);
  82. static int  is_dupd(int);
  83. static int  is_serial(int);
  84. static void sendbreak(void);
  85. static void senq(int);
  86. static int  serial_read1(int, char *, int);
  87. static int  set_mode( unsigned long, unsigned);
  88. static void sputch(int);
  89. static void uinit_8259(unsigned int int_value);
  90.  
  91. /* 8250 register addresses */
  92. #define LCNT_REG    (serial_iobase + 0)
  93. #define HCNT_REG    (serial_iobase + 1)
  94. #define IER_REG     (serial_iobase + 1)
  95. #define ISR_REG     (serial_iobase + 2)
  96. #define LCR_REG     (serial_iobase + 3)
  97. #define MCR_REG     (serial_iobase + 4)
  98. #define ST_REG        (serial_iobase + 5)
  99.  
  100. /* 8250 status register bits */
  101. #define GETRDYBIT    0x01
  102. #define PUTRDYBIT    0x20
  103.  
  104. /* 8250 interrupt register bits */
  105. #define ENTXINT     0x02
  106. #define ENRXINT     0x01
  107.  
  108. /* 8250 line control register bits */
  109. #define ENCNTREG    0x80
  110. #define SETBREAK    0x40
  111. #define CHLEN1        0x02
  112. #define CHLEN0        0x01
  113.  
  114. /* 8250 modem control register btis */
  115. #define OUT2        0x08
  116. #define RTS        0x02        /* inverted */    
  117. #define DTR        0x01        /* inverted */
  118.  
  119.  
  120. /*
  121.  * TIMER ROUTINES
  122.  */
  123. #define TKPSEC        17
  124. #define MSECPTK     (1000/TKPSEC)
  125. #define TMRVEC        0x1c
  126.  
  127. static int bad;     /* bad pointer, in case of bad timeout pointer */
  128. static int *timeoutp = &bad;        /* timeout flag pointer */
  129. static unsigned short timecnt = 0;    /* timeout ticks remaining */
  130. static int inited = 0;
  131. static void (*prev_timer_int)() = 0;
  132. static int occurcnt = 0;        /* debug, time out count */
  133.  
  134. /******************************************************************************
  135.  * settimeout()
  136.  *    Set a "background" timer which sets requested flag when alloted 
  137.  *    interval expires.
  138.  *
  139.  *    WARNING: Normal usage would settimeout( > 0 ), process until some event 
  140.  *    occurs OR this flag sets (indicating times up), then settimeout(0)
  141.  *    in order to turn the timer off.
  142.  *    This is VERY important, because if the requester flag is for instance, 
  143.  *    a stack variable, and the caller RETURNs before the timeout; then, when 
  144.  *    the timer does go off, it will set some, now defunct location.
  145.  ******************************************************************************/
  146. static void
  147. settimeout(ms, flagp)
  148.     unsigned ms;
  149.     int *flagp;
  150. {
  151.     int pif;
  152.  
  153.     if (!inited) {
  154.         init_timer();
  155.     }
  156.     pif = change_if(0);
  157.     if (ms == 0) {
  158.         timeoutp = &bad;
  159.         timecnt = 0;
  160.     } else {
  161.         timeoutp = flagp;
  162.         timecnt = (ms + (MSECPTK - 1)) / MSECPTK + 1;
  163.     }
  164.     change_if(pif);
  165. }
  166.  
  167.  
  168. /******************************************************************************
  169.  * TICK()
  170.  *    C interrupt service routine.
  171.  ******************************************************************************/
  172. #pragma interrupt(TICK)
  173. static void
  174. TICK(void)
  175. {
  176.     if (timecnt && !--timecnt) {
  177.         *timeoutp = 1;
  178.         ++occurcnt;            /* for debug */
  179.     }
  180.     _chain_intr(prev_timer_int);
  181. }
  182.  
  183.  
  184. /******************************************************************************
  185.  * init_timer()
  186.  *    Initialize our timer support.  Return 1 on success, 0 on failure.
  187.  ******************************************************************************/
  188. static int
  189. init_timer(void)
  190. {
  191.     if (inited) {
  192.         return 0;
  193.     }
  194.     prev_timer_int = _dos_getvect(TMRVEC);
  195.     _dos_setvect(TMRVEC, TICK);
  196.     inited = 1;
  197.     return 1;
  198. }
  199.  
  200. /******************************************************************************
  201.  * term_timer()
  202.  *    Terminate our timer support, releasing any resources which were used.
  203.  ******************************************************************************/
  204. static int
  205. term_timer(void)
  206. {
  207.     if (inited) {
  208.         _dos_setvect(TMRVEC, prev_timer_int);
  209.         inited = 0;
  210.     }
  211. }
  212.  
  213. static int
  214. xltbaud(baud, baudmap)
  215.     unsigned long baud;
  216.     register struct baudmap *baudmap;
  217. {
  218.     for ( ; baudmap->baud; baudmap++){
  219.         if (baudmap->baud == baud){
  220.             return baudmap->code;
  221.         }
  222.     }
  223.     return -1;
  224. }
  225.  
  226. /******************************************************************************
  227.  * sputch()
  228.  *    Put a serial character, wait if not currently ready to send.
  229.  ******************************************************************************/
  230. static void
  231. sputch(ch)
  232.     int ch;
  233. {
  234.  
  235.     while ( !(_inbyte(ST_REG) & PUTRDYBIT) ){
  236.         ;
  237.     }
  238.     _outbyte( serial_iobase, ch );
  239. }
  240.  
  241.  
  242. /******************************************************************************
  243.  * sendbreak()
  244.  *    Send a break "character" (RS232 low for more than a character period).
  245.  ******************************************************************************/
  246. static void
  247. sendbreak()
  248. {
  249.     unsigned char    ch;
  250.     int    cnt;
  251.  
  252.     ch = _inbyte( LCR_REG );
  253.     _outbyte( LCR_REG, ch|SETBREAK );
  254.     for ( cnt = BREAKMS*LOOPERMS; cnt; --cnt ){
  255.         ;
  256.     }
  257.     _outbyte( LCR_REG, ch );
  258. }
  259.  
  260. /******************************************************************************
  261.  * serial_open()
  262.  *    Open the serial device passed in as a parameter and prepare it for IO.
  263.  *    Return -1 on error (unable to initialize requested device).
  264.  ******************************************************************************/
  265. static int
  266. serial_open()
  267. {
  268.     if (strncmp(serial_device, "com", 3) == 0) {
  269.         int port = serial_device[3] - '0';
  270.         if (serial_iobase == 0){
  271.             serial_iobase = get_port(port);
  272.         }
  273.         if (serial_ivec == 0) {
  274.             switch (port) {
  275.             case 1: serial_ivec = IR4; break; /* COM1 interrupt */
  276.             case 2: serial_ivec = IR3; break; /* COM2 interrupt */
  277.             case 3: serial_ivec = IR5; break; /* COM3 interrupt */
  278.             }
  279.         }
  280.     } else if (strcmp(serial_device, "aux") == 0) {
  281.         if (serial_iobase == 0){
  282.             serial_iobase = 0x3e8;
  283.         }
  284.         if (serial_ivec == 0){
  285.             serial_ivec = IR5;
  286.         }
  287.     }
  288.  
  289.     if ( (serial_iobase == 0)
  290.     ||   (serial_ivec   == 0)
  291.     ||   !set_mode(serial_baud,serial_ivec)
  292.     ||   !init_timer()) {
  293.         return -1;
  294.     }
  295.     return 0;
  296. }
  297.  
  298. /******************************************************************************
  299.  * serial_close()
  300.  *    Close the serial device, terminating usage in current context.
  301.  ******************************************************************************/
  302. static void
  303. serial_close()
  304. {
  305.     _outbyte( IER_REG, 0);        /* disable ints */
  306.     _outbyte( MCR_REG, 0);
  307.     uinit_8259(serial_ivec);
  308.     term_timer();
  309. }
  310.  
  311. static int
  312. serial_read1(int port, char *bufptr, int want)
  313. {
  314.     int cnt;
  315.     int pif;
  316.  
  317.     pif = change_if( 0 );
  318.     if ((cnt = siq.q_in - siq.q_out) < 0){
  319.         cnt = &siq.q_buf[QBUFSZ] - siq.q_out;    /* don't wrap */
  320.     }
  321.     change_if( pif );
  322.  
  323.     if (cnt == 0) {
  324.         return 0;
  325.     }
  326.     if (want < cnt){
  327.         cnt = want;
  328.     }
  329.  
  330.     memcpy( bufptr, siq.q_out, cnt );
  331.  
  332.     pif = change_if( 0 );
  333.     siq.q_cnt -= cnt;
  334.     if ((siq.q_out += cnt) >= &siq.q_buf[QBUFSZ]) {
  335.         siq.q_out = siq.q_buf;
  336.     } else if (siq.q_in == siq.q_out) {
  337.         siq.q_in = siq.q_out = siq.q_buf;    /* reduce wraps */
  338.     }
  339.     change_if( pif );
  340.     return cnt;
  341. }
  342.  
  343. /******************************************************************************
  344.  * serial_read()
  345.  *    Attempt to read N bytes from the serial device, waiting up to
  346.  *    timo (time-out) milliseconds for data to become available.  Return:
  347.  *        0-N    Actual number of bytes read, 0 if none.
  348.  *        -1    error condition
  349.  ******************************************************************************/
  350. static int
  351. serial_read(int port, char *buf, int size, unsigned timo)
  352. {
  353.     int actual;
  354.     int flag;
  355.  
  356.     flag = 0;
  357.     settimeout(timo, &flag);
  358.     do {
  359.         actual = serial_read1(port, (char *)buf, size);
  360.     } while ((actual == 0) && !flag);
  361.     settimeout(0, &flag);
  362.     return actual;
  363. }
  364.  
  365. /******************************************************************************
  366.  * serial_write()
  367.  *    Attempt to write N bytes from the serial device, stopping as soon 
  368.  *    as unable to send more without waiting.  Return:
  369.  *        0-N    Actual number of bytes written, 0 if none.
  370.  *        -1    error condition
  371.  ******************************************************************************/
  372. static int
  373. serial_write( port, bufptr, want )
  374.     int   port;
  375.     char *bufptr;
  376.     int   want;
  377. {
  378.     int i;
  379.  
  380.     for (i = 0; i < want; i++){
  381.         sputch(*bufptr++);
  382.     }
  383.     return want;
  384. }
  385.  
  386.  
  387.  
  388. /******************************************************************************
  389.  * set_mode()
  390.  *    Set the serial device to a specified operating mode.
  391.  *    Return 0 on success, -1 on failure
  392.  ******************************************************************************/
  393. static int
  394. set_mode(baud,ivec)
  395.     unsigned long baud; /* Buad rate    */
  396.     unsigned ivec;    /* Interrupt vector */
  397. {
  398.     int val;
  399.  
  400.     if ((val = xltbaud(baud, baudmap)) <= 0){
  401.         return 0;
  402.     }
  403.     _outbyte( LCR_REG, ENCNTREG );        /* enable count regs */
  404.     _outbyte( LCNT_REG, (unsigned char)val);
  405.     _outbyte( HCNT_REG, (unsigned char)(val >>8) );
  406.     _outbyte( LCR_REG, CHLEN1 | CHLEN0 );    /* n,8,1 */
  407.     _outbyte( MCR_REG, OUT2 | RTS | DTR );
  408.  
  409.     if (baud >= 57600) {
  410.         /* Enable receive and transmit FIFOs.
  411.          *
  412.          * FCR<7:6>    00    trigger level = 1 byte
  413.          * FCR<5:4>    00    reserved
  414.          * FCR<3>    0    mode 0 - interrupt on data ready
  415.          * FCR<2>    0
  416.          * FCR<1>    0
  417.          * FCR<0>    1    turn on fifo mode
  418.          */
  419.         _outbyte(ISR_REG, 0x01);
  420.     }
  421.  
  422.     /* initialize serial queue and chip */
  423.     siq.q_cnt = siq.q_ovfl = 0;
  424.     siq.q_in = siq.q_out = siq.q_buf;
  425.     init_8259(ivec);
  426.     _outbyte(IER_REG, ENRXINT); /* enable ints */
  427.     _outbyte(IER_REG, ENRXINT); /* do twice because of chip bug */
  428.     return 1;
  429. }
  430.  
  431.  
  432. /******************************************************************************
  433.  * S_INT()
  434.  *    C serial interrupt routine (can't use debug).
  435.  *    Assumes that only Data ready interrupt is enabled.
  436.  ******************************************************************************/
  437. #pragma interrupt(S_INT)
  438. void
  439. S_INT()
  440. {
  441.     int c;
  442.     register struct queue *qp = &siq;
  443.     int pif;
  444.     
  445.     pif = change_if(0);
  446.     while (_inbyte(ST_REG) & GETRDYBIT) {
  447.         c = _inbyte(serial_iobase);
  448.         if (qp->q_cnt >= (QBUFSZ-1)) {
  449.             qp->q_ovfl++;
  450.             return;
  451.         }
  452.         *qp->q_in++ = c;
  453.         qp->q_cnt++;
  454.         if (qp->q_in >= &qp->q_buf[QBUFSZ]){
  455.             qp->q_in = qp->q_buf;    /* pre-advance pointer */
  456.         }
  457.     }
  458.     _outbyte(0x20, 0x20);
  459.     change_if(pif);
  460. }
  461.  
  462.  
  463. /******************************************************************************
  464.  * init_8259()
  465.  *    Initailize the PCDOS 8259 serial vector for interrupt driven usage.
  466.  *    return Boolean indicating success.
  467.  ******************************************************************************/
  468. static void
  469. init_8259(ivec)
  470.     unsigned ivec;    /* Interrupt vector */
  471. {
  472.     int pif;
  473.  
  474.     if (!orig_serial_vec) {
  475.         orig_serial_vec = _dos_getvect(ivec);
  476.         _dos_setvect(ivec, S_INT);
  477.     }
  478.     pif = change_if( 0 );
  479.     _outbyte( IMR_8259, (_inbyte(IMR_8259) & ~(1 << ivec - 8)) );
  480.     change_if( pif );
  481. }
  482.  
  483.  
  484. /******************************************************************************
  485.  * uinit_8259()
  486.  *    Unset the PCDOS 8259 interrupt controller serial interrupt vector 
  487.  *    used for interrupt mode.  Return Boolean indicating success.
  488.  ******************************************************************************/
  489. static void
  490. uinit_8259(ivec)
  491.     unsigned ivec;    /* Interrupt vector */
  492. {
  493.     int pif;
  494.  
  495.     pif = change_if( 0 );
  496.     _outbyte( IMR_8259, (_inbyte(IMR_8259) | (1 << ivec - 8)) ); /* mask */
  497.     change_if( pif );
  498.     if (orig_serial_vec) {
  499.         _dos_setvect(ivec, orig_serial_vec);
  500.         orig_serial_vec = 0;
  501.     }
  502. }
  503.  
  504. /******************************************************************************
  505.  * get_port()
  506.  *    equipment check bios call (bit #)
  507.  *        15-14    printers
  508.  *           12    game io
  509.  *         11-9    com devices
  510.  *          7-6    disk drives (0=1)
  511.  *          5-4    init video mode
  512.  *          3-2    ram size
  513.  *            0    are any disk drives
  514.  ******************************************************************************/
  515. static int
  516. get_port(comwhich)
  517.     int comwhich;
  518. {
  519.     union REGS regs;
  520.     int combase;
  521.  
  522.     int86( 0x11, ®s, ®s );
  523.     if (comwhich > ((regs.x.ax >> 9) & 7)){
  524.         return 0;
  525.     }
  526.     combase = ((unsigned short *)0x400)[comwhich-1];
  527.     return combase;
  528. }
  529.  
  530.  
  531. int
  532. change_if(int f)
  533. {
  534.     volatile unsigned int old_f = _getflags();
  535.     _setflags(f ? old_f | _FLAG_INTERRUPT : old_f & ~_FLAG_INTERRUPT);
  536.     return (old_f & _FLAG_INTERRUPT) != 0;
  537. }
  538.  
  539.  
  540.  
  541.  
  542. [LISTING TWO]
  543.  
  544. /***************************************************************************
  545.  * open_port()
  546.  *    This routine is used to interface from the System V "open" format
  547.  *    to the serial driver for the dos port we have provided.
  548.  *
  549.  *    Because of the interface to the driver, this routine does not
  550.  *    do the final open of the port.    Instead, it sets up a data structure
  551.  *    that is filled with pertinent data.  The data structure is further
  552.  *    filled by subsequent ioctl() calls.  When the program actually
  553.  *    requests a read or write, the the port is implicitly reopened with 
  554.  *    the correct values.
  555.  *
  556.  *    Returns:
  557.  *        I/O register base value; -1 if error
  558.  ***************************************************************************/
  559. int
  560. open_port(port_id, mode)
  561.     char *port_id;        /* Name of serial port to open    */
  562.     int  mode;        /* mode parameter not used    */
  563. {
  564.  
  565.     if (port_id == NULL){
  566.         return -1;
  567.     }
  568.  
  569.     if ((strlen(port_id) == 4)
  570.     && (!strcspn(port_id, "com") || !strcspn(port_id, "COM"))) {
  571.         strcpy(serial_device, port_id);
  572.         serial_iobase = 0;
  573.         serial_ivec = 0;
  574.         serial_baud = B9600>>16;
  575.         serial_opened = 1;
  576.         serial_setup = 1;
  577.         serial_updated = 0 ;
  578.         return serial_open() == -1 ? 0 : (int)serial_iobase;
  579.     }
  580.     return open(port_id, mode);
  581. }
  582.  
  583. static int
  584. serial_check()
  585. {
  586.     if (!serial_setup){
  587.         return 0;
  588.     }
  589.  
  590.     if (serial_updated) {
  591.         close_port(serial_iobase);
  592.         serial_setup = 1;
  593.     }
  594.     if (!serial_opened) {
  595.         serial_opened = 1;
  596.         if (serial_open() == -1){
  597.             return 0;
  598.  
  599.         }
  600.     }
  601.     return 1;
  602. }
  603.  
  604.  
  605. /***************************************************************************
  606.  * read_port()
  607.  *    This routine is used to read from the serial port of an MS/DOS
  608.  *    system.  It interfaces to a driver that handles all port communication.
  609.  *
  610.  *    First, the routine checks to see if the port has been opened for
  611.  *    use yet.  If not, it opens the device and prepares it for reading.
  612.  *    If so, it passes the information on to the serial driver to actually
  613.  *    get the data.
  614.  *
  615.  *    Returns:
  616.  *        int number of bytes read, or -1 if error
  617.  ***************************************************************************/
  618. int
  619. read_port(devindex, buffer, n, timeout)
  620.     unsigned int devindex;    /* Index into device array for port    */
  621.     char *buffer;        /* Buffer for data read from port    */
  622.     int n;        /* Number of bytes to read    */
  623.     int timeout;        /* Timeout value in seconds    */
  624.                     /* The low lever driver is            */
  625.                     /* expecting milliseconds.            */
  626. {
  627.     if (!buffer){
  628.         return -1;
  629.     } else if (is_serial(devindex)) {
  630.         return serial_check() ? 
  631.             serial_read(serial_iobase, buffer, n, 1000*timeout):-1;
  632.     } else {
  633.         /* Not the serial device, do normal I/O */
  634.         if (devindex == fileno(stdin)){
  635.             return -2;
  636.         } else {
  637.             read(devindex, buffer, n);
  638.         }
  639.     }
  640. }
  641.  
  642.  
  643. /***************************************************************************
  644.  * write_port()
  645.  *    This routine is used to write to the serial port of an MS/DOS
  646.  *    system.  It interfaces to a driver that handles all port communication.
  647.  *
  648.  *    First, the routine checks to see if the port has been opened for
  649.  *    use yet.  If not, it opens the device and prepares it for writing.
  650.  *    If so, it passes the information on to the serial driver to actually
  651.  *    send the data.
  652.  *
  653.  *    Returns:
  654.  *        int  number of bytes actually written; -1 if error.
  655.  ***************************************************************************/
  656. int
  657. write_port(devindex, buffer, n)
  658.     unsigned int devindex;    /* Index into device array for port    */
  659.     char *buffer;        /* Buffer of data to write to port    */
  660.     int n;        /* Number of bytes to write    */
  661. {
  662.     if (!buffer){
  663.         return -1;
  664.     } else if (is_serial(devindex)) {
  665.         return serial_check() ?
  666.                 serial_write(serial_iobase,buffer,n) : -1;
  667.     } else {
  668.         /* Not the serial device */
  669.         return write(devindex, buffer, n);
  670.     }
  671. }
  672. /***************************************************************************
  673.  * close_port()
  674.  *    This routine is used to interface from the System V "close" format
  675.  *    to the serial driver for the dos port we have provided.
  676.  ***************************************************************************/
  677. close_port(devindex)
  678.     unsigned int devindex;    /* serial port to close */
  679. {
  680.     if (is_serial(devindex)) {
  681.         serial_close();
  682.         serial_opened = 0;
  683.         serial_setup = 0;
  684.         serial_updated = 0;
  685.     } else {
  686.         close(devindex);
  687.     }
  688. }
  689.  
  690.  
  691.  
  692.  
  693. [LISTING THREE]
  694.  
  695. /***************************************************************************
  696.  * dup2_port()
  697.  *    This routine is emulates the System V "dup2" function for our
  698.  *    DOS serial driver.  It causes all reads or writes to fd2 to be
  699.  *    issued as if they were thru fd1.
  700.  ***************************************************************************/
  701. dup2_port(fd1, fd2)
  702.     unsigned int fd1;    /* file descriptor to be duplicated */
  703.     unsigned int fd2;    /* file descriptor to be replaced */
  704. {
  705.     if (fd1 != serial_iobase) {
  706.         /*
  707.          * fd1 is not assigned to the serial port:
  708.          * we can ship this off to the real dup2() routine.
  709.          */
  710.         dup2(fd1, fd2);
  711.     } else {
  712.         /*
  713.          * Keep track of the number of dup'ed fds seen so far
  714.          */
  715.         if (serial_dup.fd == NULL) {
  716.             serial_dup.fd = (int*)
  717.                     malloc(serial_dup.max * sizeof(int*));
  718.         }
  719.         if (serial_dup.num >= serial_dup.max) {
  720.             serial_dup.max *= 2;
  721.             serial_dup.fd = (int*) realloc(serial_dup.fd,
  722.                         serial_dup.max * sizeof(int*));
  723.         }
  724.         serial_dup.fd[serial_dup.num++] = fd2;
  725.     }
  726. }
  727.  
  728.  
  729. /**********************************************************************
  730.  * is_dupd();
  731.  *    Return true (1) iff fd is a dup2'd file descriptor.
  732.  **********************************************************************/
  733. static int
  734. is_dupd(fd)
  735.     int fd;
  736. {
  737.     int i;
  738.  
  739.     for (i = 0; i < serial_dup.num; i++) {
  740.         if (serial_dup.fd[i] == fd){
  741.             return 1;
  742.         }
  743.     }
  744.     return 0;
  745. }
  746.  
  747.  
  748.  
  749. Figure 1: Macros to handle text and binary files in DOS.
  750.  
  751. #ifdef DOS
  752. #    define READ_BIN    "rb"
  753. #    define READ_TXT    "r"
  754. #    define WRITE_BIN "wb"
  755. #    define WRITE_TXT "w"
  756. #else    /* the unix way */
  757. #    define READ_BIN    "r"
  758. #    define READ_TXT    "r"
  759. #    define WRITE_BIN "w"
  760. #    define WRITE_TXT    
  761. #endif     /* DOS */
  762.  
  763.  
  764.  
  765. Figure 2:  Mapping the UNIX SIGALRM to a DOS user-defined signal.
  766.  
  767. #ifdef DOS
  768. # define SIGALRM SIGUSR1
  769. #endif     /*DOS*/
  770.  
  771.  
  772.  
  773.  
  774. Figure 3. Writing files using a specified file handle.
  775.  
  776. write_files(fp, buffer, bytes)
  777. int fp;
  778. char *buffer;
  779. int bytes;
  780. {
  781.   if (bytes > 0) write(fp, buffer, bytes);
  782. }
  783.  
  784.  
  785.  
  786. Figure 4: Mapping WRIT_TTY to either DOS or UNIX I/O calls.
  787.  
  788. #ifdef DOS
  789. # define WRITE_TTY write_port
  790. #else  /* unix */
  791. # define WRITE_TTY write
  792. #endif    /* DOS */
  793.  
  794.  
  795.  
  796.