/* Copy -- Buffered Copy -- Amiga Style wildcards
** A modification of Rick Shaeffer's CP utility to accept Amiga style
** wildcards and the normal Copy utility "From" and "To" optional keywords.
** This Copy uses a 32K buffer which speeds copying on the same disk, but
** it does not implement the "All" option.
** Mainly of interest in that it shows how to implement Amiga Style wildcards.
** See PatMatch.c for implementation of the regular expression pattern 
** matcher.
**
** Modifications by: Jeff Lydiatt
**                   Vancouver, B.C., Canada
**		     08Jun86.
**
** Usage: copy [From] filein [To] fileout [All]
**        Amiga style wildcards permitted in filein
**        Filein consisting of a directory name is assumed to mean ALL files
**          in that directory
**        Fileout must be either a directory name or a file name
**        '.' (meaning "current directory") permitted for fileout
**        '..' (meaning "parent directory") not supported
** Files are read and written 32k at a time...yielding good
** performance for file copies on the same disk
**
** Restriction:
**    Must be linked with wildexp.o
**
**  written by: Rick Schaeffer
**              E. 113611 26th Ave.
**              Spokane, Wa.  99216
**
**              Compuserve ID: 70120,174
**              BIX ID: ricks.
**              Usenet address: ihnp4!tektronix!reed!iscuva!ricks
**
** Placed in public domain 5/10/86 by the author
** May be used for any purpose.  The author assumes NO responsibility
** for support or for any problems use of this program may cause.
*/

/*
** This version has been compiled and tested under Aztec C for the
** Commodore Amiga computer.
*/

#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <functions.h>

#undef NULL
#include "wildexp.h"

#define BUFMAX 32768

extern int Enable_Abort;

char	*largv[128];
int		bufsize = BUFMAX;
int		con;

main(argc,argv)
int	argc;
char	*argv[];
{
	char	outpath[80];
	char	outname[80];
	char	inpath[80];
	int	All, outisdir;
	char	*malloc(),*rindex(),*nameonly;
	int	nextparm, j, k;
	int	fin, fout;
	register char *parm;

	Enable_Abort = 1;
	con = fileno(stdout); /* did this 'cause "write" faster than "puts" */

   /*-------- Get inpath and outpath from command line ----------------*/

   if ((argc < 2) || ( strcmp( argv [1], "?" ) == 0) )
     {
       useage();
       exit(1);
     }

   All = FALSE;
   nextparm = 1;
   argc--;
   inpath [0] = '\0';
   outpath[0] = '\0';
   while ( nextparm <= argc )
     {
	parm = argv[ nextparm ];
	if ( (nextparm < argc) && (blindcmp( parm, "from" ) == 0) )
	  {
	    nextparm++;
	    strncpy( inpath, argv [nextparm], 78);
	  }
	else if ( (nextparm < argc) && (blindcmp( parm, "to" ) == 0) )
	  {
	    nextparm++;
	    strncpy( outpath, argv [nextparm], 78 );
	   }
	else if ( (nextparm == argc) && (blindcmp( parm, "all") == 0) )
	    All = TRUE;
	else if ( inpath[0] == '\0' )
	   strncpy( inpath, parm, 78 );
	else
	   strncpy( outpath, parm, 78 );
	nextparm++;
    }
   
    if ( iswild( outpath ) )
	{
	   wstr("No wildcards permitted in 'Fileout' path!\n");
	   exit(1);
	}
    if ( All )
	wstr( "Warning: Option All not implemented\n" );

    if (outpath[strlen(outpath)-1] == ':')
	outisdir = 1;
    else if (outisdir = isdir( outpath ) )
	strcat( outpath, "/" );

    if ( isdir(inpath) )
	strcat(inpath,"/#?");
    if ( iswild(inpath) )
	wildexp( inpath, largv, 127 );
    else
	{
	   largv[0] = malloc(strlen(inpath)+1);
	   strcpy( largv[0], inpath);
	   largv[1] = NULL;
	}

    j=0;
    while (largv[j] != NULL)
     {
	strcpy( outname, outpath );
	k = strlen( outname );
	if (outname[k-1] == '.')
	  {
	    outname[k-1] = 0;
	    outisdir = 1;
	  }

	if (outisdir) 
	  {
	     nameonly = rindex(largv[j],'/');
	     if (nameonly == NULL)
	     nameonly = rindex(largv[j],':');
	     if (nameonly == NULL)
		nameonly = largv[j];
	     else
		nameonly++;

	     if ((strlen(outname) + strlen(nameonly)) > 79)
	       {
		 wstr("Pathname+Filename too long\n");
		 break;
	       }
	     strcat(outname,nameonly);
	   }

	if ((fin = open(largv[j],O_RDONLY)) == -1)
	  {
	    wstr("Couldn't open input file ==> ");
	    wstr(largv[j]); wstr("\n");
	    break;
	  }
	if ((fout = creat(outname,0777)) == -1)
	  {
	    wstr("Couldn't open output file ==> ");
	    wstr(outname); wstr("\n");
	    close(fin);
	    break;
	  }

	wstr(largv[j]); wstr(" ==> "); wstr(outname); wstr("\n");
	dowork(fin,fout);
	close(fin);
	close(fout);
	j++;
    } /* end while */
}

dowork(fin,fout)
int	fin;
int	fout;
{
	char	*dwbuff;
	char	*malloc();
	int		dwcnt;

	while ((dwbuff = malloc(bufsize)) == NULL) 
	  {
	    bufsize -= 1024;
	    if (bufsize <= 0)
	      break;
	  }
	if (dwbuff == NULL) 
	  {
	    wstr("Couldn't allocate dwbuff!\n");
	    exit(1);
	  }
	while ((dwcnt = read(fin,dwbuff,bufsize)) == bufsize)
	   write(fout,dwbuff,bufsize);
	if (dwcnt > 0)
	   write(fout,dwbuff,dwcnt);
	free(dwbuff);
}

/* ISDIR -- Check a file name to see if it's a directory
** Returns 0 if NOT a directory, 1 otherwise.
*/
int isdir(filename)
char	*filename;
{
	struct FileInfoBlock *f;
	struct Lock *outlk;
	int		result;

	result = 0;
	outlk = (struct Lock *)Lock(filename,ACCESS_READ);
	if (outlk) 
	  {
	    f = (struct FileInfoBlock *) AllocMem((long) sizeof(struct FileInfoBlock),0l);
	    if (f == 0) 
	      {
		wstr("Unable to allocate space for FileInfoBlock!\n");
		exit(1);
	      }
	    if (Examine(outlk,f))
	    if (f->fib_DirEntryType >= 0)
		result = 1;
	    UnLock(outlk);
	    FreeMem(f,(long) sizeof(struct FileInfoBlock));
	  }
	return(result);
}

wstr(s)
char	*s;
{
	write(con,s,strlen(s));
}

useage()
{
    wstr( "copy -- Buffered File Copy.  Usage:\n" );
    wstr( "copy [From] filein [To] fileout [All]\n" );
    wstr( "  Amiga style wildcards permitted in filein.\n" );
    wstr( "  Option 'All' not implemented in this version\n" );
    wstr( "  Fileout must be either a directory name or a file name\n\n" );
}

/* Case-blind implementation of strcmp() */
int
blindcmp( s1, s2 )
register unsigned char *s1, *s2;
{
     
   while (*s1 && *s2)
     {
	if ( (_toupper( *s1 )) == (_toupper( *s2 )) )
	   {
	      s1++; 
	      s2++;
	   }
        else
	   break;
     }

   if ( *s1 == *s2 )
      return 0; /* It's Equal */
   else if ( *s1 > *s2 )
      return 1;
   else
      return -1; 
}

