/*
    SerialRouter 1.0 Copyright 1994 Barry McConnell.
    Opens two serial devices, and copies data between them.
    If the second device is console.device, creates a window for it.
*/

#include <exec/memory.h>
#include <exec/io.h>
#include <devices/serial.h>
#include <intuition/intuition.h>
#include <dos/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/dos.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void __regargs __chkabort(void) {}  /* turn off SAS/C v6 CTRL-C checking */

static UBYTE *version = "$VER: SerialRouter 1.0 (19.6.94)";

void main(int argc, char *argv[])
{
struct Library *IntuitionBase;
struct IORequest *read1 = 0, *write1 = 0, *read2 = 0, *write2 = 0;
struct MsgPort *port = 0;
struct Window *window = 0;
ULONG signal;
char data1, data2;

if (argc == 5)  /* no defaults! */
    {
    if (IntuitionBase = OpenLibrary("intuition.library", 37))
        {
        if (port = CreateMsgPort())
            {
            if ((read1 = CreateIORequest(port, sizeof(struct IOExtSer)))  /* for communicating with the device */
                && (read2 = CreateIORequest(port, sizeof(struct IOExtSer)))
                && (write1 = CreateIORequest(port, sizeof(struct IOExtSer)))
                && (write2 = CreateIORequest(port, sizeof(struct IOExtSer))))
                {
                ((struct IOExtSer *)read1) -> io_SerFlags |= (SERF_RAD_BOOGIE | SERF_SHARED);  /* high-speed mode */
                if (strcmp(argv[3], "console.device"))  /* special case */
                    ((struct IOExtSer *)read2) -> io_SerFlags |= (SERF_RAD_BOOGIE | SERF_SHARED);  /* probably a serial device */
                else
                    {
                    window = OpenWindowTags(NULL,   WA_Left, 50, WA_Top, 50, WA_Width, 600, WA_Height, 400,
                                                    WA_MinWidth, 80, WA_MaxWidth, -1, WA_MinHeight, 55, WA_MaxHeight, -1,
                                                    WA_Title, argv[1], WA_SizeGadget, TRUE, WA_DragBar, TRUE,
                                                    WA_DepthGadget, TRUE, WA_Activate, TRUE, WA_RMBTrap, TRUE,
                                                    TAG_END);
                    ((struct IOStdReq *)read2) -> io_Data = window;
                    }

                if ((OpenDevice(argv[1], atoi(argv[2]), read1, NULL)) == 0)
                    {
                    if ((OpenDevice(argv[3], atoi(argv[4]), read2, NULL)) == 0)
                        {
                        printf("SerialRouter v1.0 Copyright 1994 Barry McConnell\n");
                        printf("%s unit %s <-> %s unit %s\n", argv[1], argv[2], argv[3], argv[4]);
                        printf("Ctrl-C exits\n");

                        ((struct IOExtSer *)read1) -> IOSer.io_Length = 1;
                        ((struct IOExtSer *)read2) -> IOSer.io_Length = 1;
                        CopyMem(read1, write1, sizeof(struct IOExtSer));  /* duplicate copy for writes */
                        CopyMem(read2, write2, sizeof(struct IOExtSer));
                        ((struct IOExtSer *)read1) -> IOSer.io_Data = &data1;
                        ((struct IOExtSer *)read2) -> IOSer.io_Data = &data2;
                        ((struct IOExtSer *)write1) -> IOSer.io_Data = &data2;
                        ((struct IOExtSer *)write2) -> IOSer.io_Data = &data1;
                        read1 -> io_Command = CMD_READ;
                        read2 -> io_Command = CMD_READ;
                        write1 -> io_Command = CMD_WRITE;
                        write2 -> io_Command = CMD_WRITE;

                        SendIO(read1);  /* non-blocking read to kick it all off */
                        SendIO(read2);

                        do  /* main loop copying between units */
                            {
                            signal = Wait(1L << port -> mp_SigBit | SIGBREAKF_CTRL_C);  /* wait for something to happen */
                            if (CheckIO(read1))  /* check which one completed */
                                {
                                WaitIO(read1);  /* remove it from port */
                                DoIO(write2);  /* blocking write; already pointing to the data we read */
                                ((struct IOExtSer *)read1) -> IOSer.io_Length = 1;
                                ((struct IOExtSer *)read1) -> IOSer.io_Data = &data1;
                                read1 -> io_Command = CMD_READ;  /* ready for next time round */
                                ((struct IOExtSer *)write2) -> IOSer.io_Length = 1;
                                ((struct IOExtSer *)write2) -> IOSer.io_Data = &data1;
                                write2 -> io_Command = CMD_WRITE;
                                SendIO(read1);  /* restart this */
                                }
                            if (CheckIO(read2))  /* could also have been this */
                                {
                                WaitIO(read2);  /* remove it from port */
                                DoIO(write1);  /* blocking write; already pointing to the data we read */
                                ((struct IOExtSer *)read2) -> IOSer.io_Length = 1;
                                ((struct IOExtSer *)read2) -> IOSer.io_Data = &data2;
                                read2 -> io_Command = CMD_READ;
                                ((struct IOExtSer *)write1) -> IOSer.io_Length = 1;
                                ((struct IOExtSer *)write1) -> IOSer.io_Data = &data2;
                                SendIO(read2);  /* restart this */
                                write1 -> io_Command = CMD_WRITE;
                                }
                            }
                        while (!(signal & SIGBREAKF_CTRL_C));  /* quit when user presses Ctrl-C */

                        AbortIO(read1);  /* clean up */
                        AbortIO(read2);
                        WaitIO(read1);  /* wait until everything can be safely freed */
                        WaitIO(read2);

                        CloseDevice(read2);
                        }
                    else printf("Can't open %s unit %s\n", argv[3], argv[4]);

                    CloseDevice(read1);
                    }
                else printf("Can't open %s unit %s\n", argv[1], argv[2]);

                DeleteIORequest(read1);
                DeleteIORequest(read2);
                DeleteIORequest(write1);
                DeleteIORequest(write2);
                }
            else printf("Can't create IO requests (out of memory?)\n");

            DeleteMsgPort(port);
            if (window)
                CloseWindow(window);
            }
        else printf("Can't create message port (out of memory?)\n");

        CloseLibrary(IntuitionBase);
        }
    else printf("This utility requires at least Release 2!\n");
    }
else printf("Usage: SerialRouter <device1> <unit1> <device2> <unit2>\n");
}
