/*
 * Tee - pipe fitting
 *
 * Version 37.2 =TP= 29-Jan-92
 * Compile with SAS/C 5.10 and link without startup code:
 *      lc -cqfist -v -b0 -rr -O -ms Tee
 *      blink Tee.o to Tee sd sc
 *      protect Tee +p
 *
 * Copyright (c) 1989, 1992 Torsten Poulin
 *
 * Torsten Poulin
 * Banebrinken 99, 2, lejlighed 77
 * DK 2400  København NV
 * DENMARK
 */
/* section: Essential Utilities */

/****** English:TEE *******************************************************
*
*   FORMAT
*       TEE [[TO] <files>] [APPEND] [IGNORE]
*
*   TEMPLATE
*       TO/M,APPEND/S,IGNORE/S
*
*   PURPOSE
*       Tee is a pipe fitting.
*
*   SPECIFICATION
*       Tee transcribes the default input to the default output and
*       makes copies in the files specified by the TO option.
*
*       The APPEND switch causes the output to be appended to the
*       files rather than overwriting them.
*
*       Ctrl-C's can be ignored by giving the IGNORE switch.
*
***************************************************************************
*
*/
/****** dansk:TEE *********************************************************
*
*   FORMAT
*       TEE [[TO] <filer>] [APPEND] [IGNORE]
*
*   SKABELON
*       TO/M,APPEND/S,IGNORE/S
*
*   FORMÅL
*       Tee er en rørfitting.
*
*   SPECIFIKATION
*       Tee transskiberer sit standardinput til sit standardoutput
*       og laver kopier i de filer der angives med argumentet TO.
*
*       Med kontakten APPEND tilføjes uddata til filerne fremfor
*       at overskrive dem.
*
*       Ctrl-C'er kan ignoreres ved at bruge kontakten IGNORE.
*
***************************************************************************
*
*/
 

#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>

#define OPT_TO      0
#define OPT_APPEND  1
#define OPT_IGNORE  2


struct fileList {
    struct fileList *next;
    BPTR file;
};


char const *version = "\0$VER: Tee 37.2 (29.1.92) ©1989,92 Torsten Poulin";

int entrypoint(void)
{
    struct RDArgs        *args;

    struct DosLibrary    *DOSBase;
    struct Library       *SysBase;

    struct fileList *list, *p;
    register UBYTE breakcheck = 0;
    LONG c;    
    LONG arg[3];
    LONG rc = RETURN_OK;


    SysBase = *(struct Library **) 4L;
    if(!(DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37L)))
    {
        rc = RETURN_FAIL;
        goto exit1;
    }

    arg[OPT_TO] = arg[OPT_APPEND] = arg[OPT_IGNORE] = 0L;
    
    if(args = ReadArgs("TO/M,APPEND/S,IGNORE/S", arg, NULL))
    {
        list = NULL;
        
        if(arg[OPT_TO])
        {
            UBYTE **name;
            struct fileList *newnode;
            LONG mode;
            BPTR file;
            
            mode = arg[OPT_APPEND] ? MODE_READWRITE : MODE_NEWFILE;
            
            list = NULL;
            name = (UBYTE **) arg[OPT_TO];
            
            /* Open the files */
            for(; *name; name++)
            {
                if(!(file = Open(*name, mode)))
                {
                    BPTR console;
                    if(console = Open("CONSOLE:", MODE_OLDFILE))
                    {
                        PutStr("Tee: can't open ");
                        PutStr(*name);
                        FPutC(console, '\n');
                        Close(console);
                    }
                    continue;
                }
                if(arg[OPT_APPEND])
                    Seek(file, 0L, OFFSET_END);

                /* Store the filehandle */
                if(!(newnode=AllocMem(sizeof(struct fileList),MEMF_PUBLIC)))
                {
                    PrintFault(ERROR_NO_FREE_STORE, "Tee");
                    rc = RETURN_FAIL;
                    goto exit2;
                }
                newnode->file = file;
                newnode->next = list;
                list = newnode;
            }
	}

        /* Do the copying ... */
        while((c = FGetC(Input())) != -1L)
        {
            if(!arg[OPT_IGNORE]
               && !(breakcheck -= 8)
               && SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
            {
                rc = RETURN_WARN;
                break;
            }
            FPutC(Output(), c);
            for(p = list; p; p = p->next)
                FPutC(p->file, c);
        }
 exit2:       
        /* Close the files and free up memory*/
        for(p = list; p; )
        {
            struct fileList *remember;
                
            remember = p;
            Close(p->file);
            p = p->next;
            FreeMem(remember, sizeof(struct fileList));
        }
	
        FreeArgs(args);
    }
    else
    {
        LONG err = IoErr();
        PrintFault(err, "Tee");
        rc = RETURN_ERROR;
    }

    CloseLibrary((struct Library *) DOSBase);
 exit1:
    return rc;
}
