/* fcat.c : concatenate files to standard output using a buffer for the
**          Atari ST.
**
** Author : Thomas K”nig
**          UI0T@DKAUNI2.BITNET
**          UI0T@IBM3090.RZ.UNI-KARLSRUHE
**
** Date : 22.10.1990
**
** compiler used : gcc V 1.37
**
** Version : 1.1
** 
** This program is placed in the public domain.  If you want to incorporate
** it or parts of it into your own programs, that is fine by me; just don't
** blame me if they don't run correctly because of that.
*/

#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <osbind.h>

#define MIN(a,b)    (((a)<(b)) ? (a) : (b))
#define STD_HANDLE  (1)
#define RESERVE     (0x2000)
#define FMASK       FA_RDONLY
#define FOLDSEP     '\\'
#define DRIVESEP    ':'
#define MAXPLEN     (100)
#define READ_ONLY   (0)

/* define misc. error codes */
#define OUT_OF_MEMORY   (-39)
#define WRITE_ERROR     (-10)
#define READ_ERROR      (-11)

#define FATAL(str, rc) do { fprintf(stderr,"%s: %s\n",own_id,str); \
                            return (int) rc; } while (0)


/* function prototype */
void    cutpath(char *);

/* typedef for our own DTA */
typedef struct _dta DTA;

/* pointer to own name */
char *own_id;

int main(int argc,char *argv[])
{
    size_t      avail,buf_size,buf_rest,to_read,read,written,file_rest;
    short       fsret;
    int         handle;
    void        *buffer = NULL;
    extern char *own_id;
    DTA         Dta;
    char        path[MAXPLEN];
    char        errstr[MAXPLEN + 20];

/* Do we know who we are ? */
    if (**argv == '\0')
        own_id = "fcat";
    else
        own_id = *argv ;

/* Let's take the biggest chunk of memory we can get for a buffer */

/* How big is it ? */
    avail = (size_t) Malloc(-1);

    if (avail < 2*RESERVE)
        FATAL("Not enough memory",OUT_OF_MEMORY);

    buf_size = avail - RESERVE;

/* Allocate the buffer. */
    avail = (size_t) Malloc(buf_size);
    if (avail < 0)
        FATAL("Not enough memory",OUT_OF_MEMORY);

    buffer = (void *) avail;
    (void) Fsetdta(&Dta);
    buf_rest = buf_size;

/* Step through the argument list */
    while (--argc > 0)
    {
        fsret = Fsfirst(*++argv,FMASK);
        if (fsret <0)
            FATAL("File not found",fsret);

        strcpy(path,*argv);

/* Loop over all possible expansions */   
        while (fsret >=0)
        {
            cutpath(path);
            strcat(path,Dta.dta_name);
            handle = Fopen(path,READ_ONLY);
            if (handle < 0)
            {
                (void) sprintf(errstr,"Error opening %s",path);
                FATAL(errstr,handle);
            }
            file_rest = Dta.dta_size;

/* While there is still something in the file to read, do it */
            while (file_rest > 0)
            {

/* Read until end of file or buffer */
                to_read = MIN(file_rest,buf_rest);
                if (to_read > 0)
                {
                    read = Fread(handle, to_read, buffer +buf_size-buf_rest);
                    if (read != to_read)
                    {
                        (void) sprintf(errstr,"Error reading %s",path);
                        FATAL(errstr,WRITE_ERROR);
                    } /* if (read != to_read) */

                    buf_rest = buf_rest - read;
                    file_rest = file_rest - read;
                } /* if (to_read > 0) */

/* Is the buffer full? Then write it out. */
                if (buf_rest == 0)
                {
                    written = Fwrite(STD_HANDLE, buf_size, buffer);
                    if (written != buf_size)
                        FATAL("write error",WRITE_ERROR);

                    buf_rest = buf_size;
                } /* if (buf_rest == 0) */

            } /* while (file_rest > 0) */

            (void) Fclose(handle);
            fsret = Fsnext();
        } /* while (fsret >=0) */

    } /* while (--argc > 0) */

/* Is there still something left in the buffer? Write it out. */
    if (buf_size - buf_rest > 0)
    {
        written = Fwrite(STD_HANDLE, buf_size - buf_rest, buffer);
        if (written != buf_size - buf_rest)
            FATAL("Write error",WRITE_ERROR);

    } /* if (buf_size - buf_rest > 0) */

    return 0;
}

/* Isolate the name of the path from a filename */
void cutpath(char *path)
{
    size_t len;
    char *temp;

    len = strlen(path);
    for (temp = path + len - 1; temp >= path && *temp != FOLDSEP
                                && *temp !=DRIVESEP ; temp--)
        ;

    *(temp + 1) = '\0';
}

