#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef ARP
#include <ArpFileScan.h>
#include <libraries/arpbase.h>
#else
#include <FileScan.h>
#endif
#include <functions.h>

/*  mrcat - catenate files with wildcard expansion.
 *  This program copies a series of files to standard output. It uses smart file
 *  expansion with sorting. Each filename parameter can be thought of as representing
 *  a group of one or more files. Filenames within a group are sorted, but the
 *  original file specifications are not. For example:
 *
 *      mrcat >myfile c a b* d*
 *
 *  would result in
 *
 *      1.  copy file c
 *      2.  copy file a
 *      3.  sort all filenames beginning with b, then copy them
 *      4.  sort all filenames beginning with d, then copy them
 *
 *  If no input files are specified, standard input is copied to standard output.
 */

#ifndef ARP
#define Printf  printf
#define Puts    puts
#define SPrintf sprintf
#endif

#define BUFSIZE     32*1024             /* 32K copy buffer size */
#ifdef ARP
struct ArpBase  *ArpBase;
#endif
BPTR            myOutput;
char            *buffer;
char            errMsg[256];
char            *progName;

void
Abort(const char *errDesc, long fault)
{
    if (IsInteractive(myOutput)) {
        Write(myOutput,progName, strlen(progName));
        Write(myOutput,": ", 2L);
        Write(myOutput,errDesc, strlen(errDesc));
    }
#ifdef ARP
    ArpExit(20, fault);
#else
    exit(1);
#endif
}

void
CopyOne(BPTR inFile, const char *fileName)
{
    long    readCount, writeCount;
    long    faultCode;

    do {
        readCount = Read(inFile, buffer, BUFSIZE);
        if (readCount > 0) {
            writeCount = Write(myOutput, buffer, readCount);
            if (writeCount != readCount) {
                faultCode = IoErr();
                SPrintf(errMsg,"Write error %ld on '%s'\n", faultCode, fileName);
                Abort(errMsg, faultCode);
            }
        }
        else if (readCount < 0) {
            faultCode = IoErr();
            SPrintf(errMsg,"Read error %ld on '%s'\n", faultCode, fileName);
            Abort(errMsg, faultCode);
        }
    } while (readCount > 0);
}

void
CopyNamedFile(const char *fileName)
{
    long    faultCode;
    BPTR    inFile;

    inFile = Open(fileName, MODE_OLDFILE);
    if (inFile == 0) {
        faultCode = IoErr();
        SPrintf(errMsg, "'%s' failed to open: %ld!\n", fileName, faultCode);
        Abort(errMsg, faultCode);
    }
    CopyOne(inFile, fileName);
    Close(inFile);
}

main(int argc, char **argv)
{
#define NoMemory "Not enough memory!\n"

    int     argn;
    int     fileCount;
    int     fileIndex;
    char    **fileList;

#ifdef ARP
    ArpBase = (struct ArpBase *)OpenLibrary(ArpName, ArpVersion);
    if (! ArpBase) exit(1);
#endif

    progName = argv[0];
    myOutput = Output();

#ifdef ARP
    buffer = ArpAlloc(BUFSIZE);
#else
    buffer = malloc(BUFSIZE);
#endif
    if (!buffer) {
        Write(myOutput,NoMemory, sizeof(NoMemory));
        exit(1);    
    }
    if (argc < 2)
        CopyOne(Input(), "Standard input");     /* Copy standard input. */
    else for (argn = 1; argn < argc; ++argn) {
#ifdef ARP
        fileList = ArpFileScan(&argv[argn], 1, &fileCount, 1);
#else
        fileList = FileScan(&argv[argn], 1, &fileCount, 1);
#endif
        if (fileList != NULL) {
            for (fileIndex = 0; fileIndex < fileCount; ++fileIndex) {
                CopyNamedFile(fileList[fileIndex]);
            }
        }
    }
}
