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

/****** English:COMMON ****************************************************
*
*   FORMAT
*       COMMON [FILE1] <file1> [[FILE2] <file2>] [-1] [-2] [-3]
*
*   TEMPLATE
*       FILE1/A,FILE2,-1/S,-2/S,-3/S
*
*   PURPOSE
*       To select or reject lines common to two sorted files.
*
*   SPECIFICATION
*       The command Common reads <file1> and <file2>, which should be
*       ordered in the collating sequence of SORT, and produces a
*       three-column output: lines only in <file1>; lines only in
*       <file2>; and lines in both files.
*
*       Switches -1, -2, or -3 suppress printing of the corresponding
*       column.  Thus Common -1 -2 prints only the lines common to
*       the two files; Common -2 -3 prints only the lines in the first
*       file but not in the second; Common -1 -2 -3 is a no-op.
*
*   SEE ALSO
*       SORT, UNIQUE
*
*   UNIX EQUIVALENT
*       comm(BU_CMD)
*
***************************************************************************
*
*/
/****** dansk:COMMON ******************************************************
*
*   FORMAT
*       COMMON [FILE1] <fil1> [[FILE2] <fil2>] [-1] [-2] [-3]
*
*   SKABELON
*       FILE1/A,FILE2,-1/S,-2/S,-3/S
*
*   FORMÅL
*       At vælge eller fravælge linjer fælles for to sorterede filer.
*
*   SPECIFIKATION
*       Kommandoen Common læser <fil1> og <fil2>, som skal være
*       ordnet i rangfølgen brugt af SORT, og udskriver tre spalter:
*       linjer der kun findes i <fil1>, linjer der kun findes i
*       <fil2> og linjer der findes i begge filer.
*
*       Kontakterne -1, -2 og -3 undertrykker udskrivningen af de
*       tilsvarende spalter.  Således udskriver Common -1 -2 kun de
*       linjer som er fælles for de to filer; Common -2 -3 udskriver
*       kun linjer som findes i den første fil, men ikke i den anden.
*       Common -1 -2 -3 udskriver ingenting.
*
*   SE OGSÅ
*       SORT, UNIQUE
*
*   TILSVARENDE I UNIX
*       comm(BU_CMD)
*
***************************************************************************
*
*/


#include <exec/types.h>
#include <exec/libraries.h>
#include <dos/dos.h>
#include <dos/dostags.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <string.h>

#define MAXLEN (512+1)
#define TEMPLATE "FILE1/A,FILE2,-1/S,-2/S,-3/S"
#define OPT_FILE1 0
#define OPT_FILE2 1
#define OPT_NOT1  2
#define OPT_NOT2  3
#define OPT_NOT3  4

char const *version = "\0$VER: Common 37.2 (18.2.92)\
 ©1990,92 Torsten Poulin";

LONG Common(struct Library *SysBase, struct DosLibrary *DOSBase,
            BPTR f1, BPTR f2, BOOL print1, BOOL print2, BOOL print3);


LONG entrypoint(VOID)
{
    struct RDArgs     *args;
    struct DosLibrary *DOSBase;
    struct Library    *SysBase;
    LONG  arg[5];
    LONG  rc = RETURN_OK;
    BPTR  f1, f2;
    UBYTE *name1, *name2;
    BOOL  print1, print2, print3;
    
    SysBase = *(struct Library **) 4L;
    if(!(DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37L)))
        return RETURN_FAIL;

    arg[OPT_FILE1] = arg[OPT_FILE2] = 0L;
    arg[OPT_NOT1] = arg[OPT_NOT2] = arg[OPT_NOT3] = 0L;
    
    if(args = ReadArgs(TEMPLATE, arg, NULL))
    {
        name1 = (UBYTE *) arg[OPT_FILE1];
        name2 = (UBYTE *) arg[OPT_FILE2];

        print1 = ! (BOOL) arg[OPT_NOT1];
        print2 = ! (BOOL) arg[OPT_NOT2];
        print3 = ! (BOOL) arg[OPT_NOT3];
        
        if(!(f1 = Open(name1, MODE_OLDFILE)))
        {
            LONG err = IoErr();
            PrintFault(err, name1);
            rc = RETURN_ERROR;
        }
        
        if(!arg[OPT_FILE2])
            f2 = Input();
        else if(!(f2 = Open(name2, MODE_OLDFILE)))
        {
            LONG err = IoErr();
            PrintFault(err, name2);
            Close(f1);
            rc = RETURN_ERROR;
        }
        
        if(f1 && f2)
        {
            rc = Common(SysBase, DOSBase, f1, f2, print1, print2, print3);
            Close(f1);
            if(arg[OPT_FILE2])
                Close(f2);
        }
        FreeArgs(args);
    }
    else
    {
        LONG err = IoErr();
        PrintFault(err, "Common");
        rc = RETURN_ERROR;
    }
    CloseLibrary((struct Library *) DOSBase);
    return rc;
}


LONG Common(struct Library *SysBase, struct DosLibrary *DOSBase,
            BPTR f1, BPTR f2, BOOL print1, BOOL print2, BOOL print3)
{
    UBYTE *stat1, *stat2;
    UBYTE line1[MAXLEN], line2[MAXLEN];
    LONG  cmp_result;
    LONG  err;
    BPTR  out = Output();
    
    stat1 = FGets(f1, line1, MAXLEN);
    stat2 = FGets(f2, line2, MAXLEN);
    
    while(stat1 != 0 && stat2 != 0)
    {
        cmp_result = strcmp(line1, line2);
        if(cmp_result == 0)
        {
            if(print3)
            {
                if(print1) FPutC(out, '\t');
                if(print2) FPutC(out, '\t');
                PutStr(line1);
            }
            stat1 = FGets(f1, line1, MAXLEN);
            stat2 = FGets(f2, line2, MAXLEN);
        }
        else if(cmp_result < 0)
        {
            if(print1)
                PutStr(line1);
            stat1 = FGets(f1, line1, MAXLEN);
        }
        else
        {
            if(print2)
            {
                if(print1) FPutC(out, '\t');
                PutStr(line2);
            }
            stat2 = FGets(f2, line2, MAXLEN);
        }
        
        if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
        {
            PrintFault(ERROR_BREAK, NULL);
            return RETURN_WARN;
        }
    }
    if(err = IoErr())
    {
        PrintFault(err, "Common");
        return RETURN_ERROR;
    }

    /* Output the remainder of the longest file */
    if(stat1 || stat2)
    {
        if(print1 && stat1)
            PutStr(line1);
        if(print2 && stat2)
        {
            if(print1)
                FPutC(out, '\t');
            PutStr(line2);
        }
        while(FGets(stat1 ? f1 : f2, line1, MAXLEN))
        {
            if(print1 && print2 && stat2)
                FPutC(out, '\t');
            if(stat1 ? print1 : print2)
                PutStr(line1);

            if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
            {
                PrintFault(ERROR_BREAK, NULL);
                return RETURN_WARN;
            }
        }
        if(err = IoErr())
        {
            PrintFault(err, "Common");
            return RETURN_ERROR;
        }
    }
}
