home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Elysian Archive
/
AmigaElysianArchive.iso
/
prog
/
source
/
cp.lha
/
cp.c
next >
Wrap
C/C++ Source or Header
|
1988-03-03
|
13KB
|
507 lines
/* Cp: A replacement for AmigaDos Copy that does not modify the date
* by Jeff Lydiatt
* Vancouver, Canada.
*
* Features:
* 1) Handles all functions of AmigaDos copy, including the All switch.
* 2) Regular expression pattern matching that handles the AmigaDos'
* pattern matching characters "#?|%'()".
* 3) This copy keeps the date of the copied file!
* 4) Uses a 32K buffer which should speed up single disk copies.
* 5) In "Cp filex .", the "." is taken to mean the current directory.
*
* Created: 07May87
*
* Cp has been compiled and tested under Aztec v3.40a with patch v3
* applied. The 16 bit integer and small code, small data option is
* used in compiling and linking all modules.
*
* Maintenance Notes:
* 17May87 - Version 1.0 Released.
*
*/
/*
Cp and the c source is freely redistributable for personal
non-commercial use. Commercial rights are reserved by the
author. Feel free to make any modifications or use any
of the modules in other programs. I encourage you to do so
and hope you will release the code so others can learn by it.
*/
#include <stdio.h>
#include <libraries/dos.h>
#include <exec/memory.h>
#include <functions.h>
#define BUFMAX 32768
#define MAXSTR 127
extern int Enable_Abort;
extern char *malloc();
extern int CmplPat(), Match();
extern long Chk_Abort();
/*--- A poor man's "printf" which avoids the overhead of printf ---*/
static void msg(str, parm)
char *str, *parm;
{
register char *s;
register struct FileHandle *console;
console = Output();
for ( s=str; *s; ++s )
{
if ( *s == '%' && *(s+1) == 's' )
{
(void)Write( console, str, (long)(s - str));
(void)Write( console, parm, (long)strlen(parm));
(void)Write( console, (char *)(s + 2), (long)strlen((char *)(s+2)));
break;
}
}
if ( *s == '\0' )
(void)Write( console, str, (long)strlen(str));
}
static void error( str, parm )
char *str, *parm;
{
msg( str, parm );
exit(NULL);
}
static void useage(name)
char *name;
{
msg( "%s V1.0 buffered file copy by Jeff Lydiatt. Usage:\n", name );
msg( " %s [From] filein [To] fileout [All]\n", name );
msg( " AmigaDos style pattern matching characters permitted in filein.\n" );
msg( " Pattern matching characters not allowed in Fileout.\n\n" );
}
/*-----------------------------------------------------------*/
/* Parse the command string */
/*-----------------------------------------------------------*/
static int toupper(c)
register char c;
{
if ( 'a' <= c && c <= 'z' )
return c + ('A' - 'a');
return c;
}
/* Case-blind implementation of strcmp() */
static int blindcmp( s1, s2 )
register char *s1, *s2;
{
while (*s1 && *s2)
{
if ( (toupper( *s1 )) == (toupper( *s2 )) )
{
++s1;
++s2;
}
else
break;
}
if ( toupper(*s1) == toupper(*s2) )
return 0; /* It's Equal */
else if ( toupper(*s1) > toupper(*s2) )
return 1;
else
return -1;
}
static void parsecmd(fparm, tparm, All, argc, argv)
char *fparm, *tparm;
register char *argv[];
int *All, argc;
{
int nextparm;
register char *parm;
if ((argc < 2) || ( strcmp( argv[1], "?" ) == 0) )
{
useage( argv[0] );
exit( NULL );
}
*All = FALSE;
nextparm = 1;
argc--;
fparm [0] = '\0';
tparm[0] = '\0';
while ( nextparm <= argc )
{
parm = argv[ nextparm ];
if ( (nextparm < argc) && (blindcmp( parm, "from" ) == 0) )
{
++nextparm;
(void)strncpy( fparm, argv [nextparm], MAXSTR);
}
else if ( (nextparm < argc) && (blindcmp( parm, "to" ) == 0) )
{
++nextparm;
(void)strncpy( tparm, argv [nextparm], MAXSTR );
}
else if ( (nextparm == argc) && (blindcmp( parm, "all") == 0) )
*All = TRUE;
else if ( fparm[0] == '\0' )
(void)strncpy( fparm, parm, MAXSTR );
else
(void)strncpy( tparm, parm, MAXSTR );
++nextparm;
}
}
/*--------------------------------------------------------------*/
/* Internal stack manipulation routines */
/*--------------------------------------------------------------*/
struct stackframe
{
struct stackframe *next;
char *strptr;
};
static struct stackframe *Stackhead;
static void initstack()
{
Stackhead = NULL;
}
static int isempty()
{
return Stackhead == NULL;
}
/*--------------push a string on the stack------------------*/
static void push(str) char *str; /* Push a string on the stack */
{
register struct stackframe *p;
register char *s;
if ( (p = (struct stackframe *)malloc(sizeof(struct stackframe))) == NULL
||(s = malloc( strlen(str)+1 )) == NULL)
{
msg("Not enough memory\n");
return;
}
strcpy( s, str );
p->next = Stackhead;
p->strptr = s;
Stackhead = p;
}
/*---------pop the next string from the stack------------------*/
static void pop(str) char *str;
{
register struct stackframe *p;
if (isempty())
error("Can't happen: stack popped with nothing there\n");
p = Stackhead;
strcpy( str, p->strptr );
free( p->strptr );
Stackhead = p->next;
free( p );
}
/*--------------------------------------------------------------*/
/* Some handy path manipulation routines. */
/*--------------------------------------------------------------*/
/*------------separate path and pattern from str----------------*/
static char *getpath( path, pattern, str)
char *path, *pattern, *str;
{
register char *s1, *s2;
char *mark;
mark = NULL;
for ( s1=str; *s1; ++s1)
if ( *s1 == ':' || *s1 == '/' )
mark = s1;
if ( isdir(str) )
{
strcpy( path, str );
*pattern = '\0';
}
else if ( !mark )
{
strcpy( pattern, str );
*path = '\0';
}
else
{
s2 = path;
s1 = str;
while ( s1 < mark )
*s2++ = *s1++;
if ( *s1 == ':' )
*s2++ = *s1;
*s2 = '\0';
strcpy( pattern, (char*)( mark+1));
}
return path;
}
/*------return path from parent directory and member name-------*/
static char *makepath(path, parent, member)
register char *path;
char *member;
register char *parent;
{
register int len;
strcpy( path, parent );
len = strlen( path );
if ( len > 0 && *member )
if ( (path[len-1] != ':') && (path[len-1] != '/') )
strcat( path, "/" );
strcat( path, member );
return path;
}
/*--- isdir: Returns 0 if NOT a directory, 1 otherwise. ---*/
static 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), MEMF_CHIP);
if (f == 0)
error("Unable to allocate space for FileInfoBlock!\n");
if (Examine(outlk,f))
if (f->fib_DirEntryType >= 0)
result = 1;
UnLock(outlk);
FreeMem((void *)f,(long) sizeof(struct FileInfoBlock));
}
return(result);
}
static int iswild(pattern)
register char *pattern;
{
for (; *pattern; ++pattern )
{
switch( *pattern )
{
case '#':
case '?':
case '(':
case '%':
case '\'':
case '|': return 1;
}
}
return 0;
}
static int cp(fpath, tpath, name )
char *fpath, *tpath, *name;
{
char fname[MAXSTR+1], tname[MAXSTR+1];
char *buffer;
long status, count, bufsize;
struct FileHandle *fin, *fout;
struct DateStamp date;
(void)makepath( fname, fpath, name );
if ( tpath[0] != '\0' && !isdir(tpath) )
strcpy( tname, tpath );
else
(void)makepath( tname, tpath, name );
msg( "%s ==> ", fname ); msg( "%s\n", tname);
if ( (fin = Open( fname, MODE_OLDFILE )) == NULL )
{
msg( "Can't open %s for input.\n", fname );
return 1;
}
if ( (fout = Open( tname, MODE_NEWFILE )) == NULL )
{
msg( "Can't open %s for ouput.\n", tname );
Close( fin );
return 1;
}
for ( bufsize = BUFMAX; bufsize > 2048; bufsize -= 2048 )
if ( (buffer = malloc( (unsigned int)bufsize)) != NULL )
break;
if ( bufsize <= 2048 )
{
Close( fin );
Close( fout );
msg( "Not enough memory.\n" );
return 1;
}
status = 1;
while( status > 0 && (count = Read( fin, buffer, bufsize )) == bufsize )
if ( Chk_Abort() )
status = -1;
else
status = Write( fout, buffer, count );
if (status > 0 && count > 0 )
status = Write( fout, buffer, count );
Close( fin );
Close( fout);
free( buffer );
if ( status < 0 || count < 0 )
{
(void)DeleteFile( tname );
msg( " %s [removed].\n", tname );
return 1;
}
if ( getDate( fname, &date ))
(void)setDate( tname, &date );
return 0;
}
main(argc,argv)
int argc;
char *argv[];
{
int aux[MAXSTR+1];
char fparm[MAXSTR+1], tparm[MAXSTR+1];
char fpath[MAXSTR+1], tpath[MAXSTR+1];
char fparent[MAXSTR+1], dontSearch[MAXSTR+1];
char fpattern[MAXSTR+1];
char relpath[MAXSTR+1], junk[MAXSTR+1];
void *dirlock;
register struct FileInfoBlock *fileptr;
int All;
Enable_Abort = 0;
parsecmd( fparm, tparm, &All, argc, argv );
(void)getpath( fparent, fpattern, fparm );
if ( strcmp(tparm, ".") == 0 )
tparm[0] = '\0';
/*--- Are the parms ok? --- */
if ( iswild(fparent) )
error( "Regular expression not allowed in path: %s.\n", fparm );
if ( iswild(tparm) )
error( "Regular expression not allowed as output name.\n" );
/*----- if it's just a single file copy, just do it and exit----*/
if ( !All && !iswild( fpattern ) && !isdir( fparm ))
{
(void)cp( fparent, tparm, fpattern );
exit( NULL );
}
/*--- For "All" option, don't search the "to" directory --- */
fileptr = (struct FileInfoBlock *)
AllocMem( (long)sizeof(struct FileInfoBlock), MEMF_CHIP);
strcpy( dontSearch, tparm );
if ( dontSearch[0] == '\0' )
{
dirlock = Lock("", ACCESS_READ);
if ( dirlock )
{
(void)Examine( dirlock, fileptr );
strcpy( dontSearch, fileptr->fib_FileName );
UnLock( dirlock );
}
}
initstack();
push( "" );
if ( fpattern[0] == '\0' )
strcpy( fpattern, "#?" );
if ( CmplPat( fpattern, aux ) == 0 )
{
msg("Bad regular expression pattern: %s.\n", fpattern);
goto all_done;
}
while( !isempty() )
{
pop( relpath );
(void)makepath( fpath, fparent, relpath );
(void)makepath( tpath, tparm, relpath );
if ( All && !isdir(tpath) )
{
if ( (dirlock = CreateDir( tpath )) == NULL )
{
msg( "Can't create %s \n", tpath );
continue;
}
else
{
msg("%s ... [created]\n", tpath);
UnLock( dirlock );
}
}
if ( (dirlock = Lock( fpath, ACCESS_READ )) == NULL
|| !Examine( dirlock, fileptr) )
{
msg( "Can't find directory %s\n", fpath );
if ( dirlock )
UnLock( dirlock );
goto all_done;
}
while ( ExNext( dirlock, fileptr ) )
{
if ( fileptr->fib_DirEntryType > 0 )
{
if ( All && strcmp( dontSearch, fileptr->fib_FileName) )
push( makepath( junk, relpath, fileptr->fib_FileName ) );
}
else if (Match( fpattern, aux, fileptr->fib_FileName ) )
{
if ( Chk_Abort() || cp( fpath, tpath, fileptr->fib_FileName ) )
{
UnLock( dirlock );
goto all_done;
}
}
}
UnLock( dirlock );
}
all_done:
FreeMem( fileptr, (long)sizeof(struct FileInfoBlock));
exit(NULL);
}