home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
c_spec
/
sources
/
cp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1986-02-20
|
8KB
|
354 lines
#include <stdio.h>
#include <fcntl.h>
#include <types.h>
#include <stat.h>
#include <errno.h>
/*
* CP.C: Copyright (C) 1985, Allen I. Holub. All rights reserved.
*
* A version of the unix copy utility for MSDOS. Note
* That unlike copy you have to specify a target.
* So, a file to the current directory you have to say:
*
* cp <src file> .
*
* (the '.' is the current directory).
*
* Usage: cp [-ie] file [... file] target
* where "target" may be a filename of
* a directory name. In the first case
*
* -i Interactive, ask before copying anything.
* -v Verfify before overwriting an existing file
* -e Do not echo actions to screen as they are done (this will
* make cp behave like the unix version, which is silent).
*
* Exit status: 0 if copy is made successfully, 1 otherwise;
*/
extern int errno;
extern char *malloc (unsigned);
extern int open (char*,int,);
extern int read (int, char*, unsigned);
extern int stat (char*,struct stat *);
extern int write (int, char*, int);
extern char *cpy (char*, char*);
#define isslash(c) ((c)=='/' || (c) == '\\')
/*---------------------------------------------------------------------*/
int Verify = 0; /* Verify before overwriting existing file */
int Echo = 1; /* Say what we're doing as we do it */
int Interactive = 0;/* Ask before copying anyting */
/*---------------------------------------------------------------------*/
args(argc, argv)
char **argv;
{
/* Process command line arguments. If -i iv found set
* Verify true, if -e is found set Echo false. Return
* 1 if we found an argument, 0 otherwise
* On entry argv should point at argv[1]
*/
register char *p;
if( **argv == '-' )
{
for( p = *argv + 1 ; *p ; p++ )
{
if ( *p == 'v' ) Verify = 1;
else if ( *p == 'i' ) Interactive = 1;
else if ( *p == 'e' ) Echo = 0;
else usage("Illegal argument" );
}
if( Verify || Interactive )
Echo = 1;
return 1;
}
return 0;
}
/*----------------------------------------------------------------------*/
doargs( argcp, argvp )
char ***argvp;
int *argcp;
{
/* Parse the command line arguements and modify argv and
* argc so that the filename and arguments (if present)
* will be removed.
*/
char **argv = *argvp;
int argc = *argcp;
if( argc < 3 )
usage("Too few arguments");
if( args(--argc, ++argv) ) /* Process command line arguments */
{ /* and delete file name and any */
++argv ; /* arguments from argv */
--argc ;
}
*argvp = argv;
*argcp = argc;
}
/*----------------------------------------------------------------------*/
int getbuf( bufp )
char **bufp;
{
register unsigned bsize = 0x7fff; /* Buffer size */
register char *buf;
/* Get the biggest buffer you can from malloc.
*/
while( !( buf = malloc(bsize)) && (int)bsize > 0 )
bsize -= 512 ;
*bufp = buf;
return bsize;
}
/*----------------------------------------------------------------------*/
getdisk( pp )
char **pp;
{
register char *p = *pp;
if( p[0] && p[1] == ':' )
{
*pp = p + 2;
return *p;
}
else
return 0;
}
/*----------------------------------------------------------------------*/
char *fname( str )
char *str;
{
/* Return a pointer to the filename part of str.
*/
register char *last, *s ;
for( s = last = str; *s ; s++ )
if( isslash(*s) || *s == ':' )
last = s;
return( last == str ? str : last + 1 );
}
/*---------------------------------------------------------------------*/
char *make_tname( disk, targ, isfile, srcname )
char *targ, *srcname;
{
static char tbuf[128] ;
register char *p = tbuf;
if( disk ) /* Copy the disk id if one */
{ /* exists and a trailing : */
*p++ = disk;
*p++ = ':';
if( !*targ )
{
*p++ = '.';
isfile = 0;
}
}
p = cpy( p, targ ); /* Copy the target name */
if( !isfile )
{
if( p != tbuf && p[-1] != '/') /* If target is a */
*p++ = '/' ; /* directory copy a */
/* slash and the file */
cpy( p, fname( srcname ) ); /* name part of the */
} /* srcname. */
return tbuf;
}
/*----------------------------------------------------------------------*/
yes(str)
char *str;
{
register int c;
fprintf(stderr, "%s (y/n): ", str );
fprintf(stderr, "%c\n", c = getch() );
return( c == 'y' || c == 'Y' );
}
/*----------------------------------------------------------------------*/
exists( file )
char *file;
{
/* Return 1 if the file exists, 0 if not
*/
struct stat status;
return( stat(file, &status) == 0 );
}
/*----------------------------------------------------------------------*/
go_ahead( src, dest )
char *src, *dest;
{
if( Echo )
fprintf(stderr, "copy: %20s to %-20s ", src, dest );
if( Interactive )
return( yes("?") );
else if( Verify && exists( dest ) )
return( yes("overwrite?") );
putc('\n', stderr );
}
/*----------------------------------------------------------------------*/
doerror( fname, read_write )
char *fname, *read_write;
{
fprintf(stderr,"\nCan't open %s for %s: ", fname, read_write );
fprintf(stderr,( errno == ENOENT )
? "File not found\n"
: "File is a directory or is write protected\n" );
}
/*----------------------------------------------------------------------*/
main(argc, argv)
char **argv;
{
char *buf;
char *targ; /* Target name from cmd line */
char *tname; /* Actual target name */
int isfile; /* True if targ is a file */
int disk; /* Disk id of target */
register int got; /* # bytes got from read */
register int src, dest; /* File handles */
unsigned bsize; /* Buffer size */
int exit_status = 0 ; /* value returned to shell */
int err;
ctlc(); /* Fix ^C Interrupt handling */
reargv( &argc, &argv ); /* Remake argv from CMDLINE */
doargs( &argc, &argv ); /* Parse command line args */
bsize = getbuf( &buf ); /* Get a buffer to use for xfer */
targ = argv[--argc] ; /* targ = name of target */
isfile = !isdir(targ) ; /* isfile = 1 if its a file */
disk = getdisk( &targ ); /* extract disk id part of name */
if( isfile && argc > 2 )
usage("%s is not a directory", targ );
for( ; --argc >= 0 ; ++argv )
{
if( isdir( *argv ) )
continue;
tname = make_tname( disk, targ, isfile, *argv );
if( !go_ahead(*argv, tname) )
{
exit_status = 1;
continue;
}
if( (src = open(*argv, O_RDONLY | O_BINARY)) == -1)
{
doerror( *argv, "read" );
exit_status = 1;
continue;
}
dest = open(tname, O_TRUNC | O_CREAT | O_WRONLY | O_BINARY,
S_IWRITE | S_IREAD );
if( dest == -1 )
{
exit_status = 1;
doerror( tname, "write" );
continue;
}
while( got = read(src, buf, bsize) )
{
if( got == -1 || (err = write(dest,buf,got)) != got )
{
fprintf( stderr,
"No space or File marked read only\n");
exit_status = 1;
if( err == ENOSPC )
goto abort;
break;
}
}
close( src );
close( dest );
}
abort:
free( buf );
exit( exit_status );
}
/*---------------------------------------------------------------------*/
#define E(x) fprintf(stderr,"%s\n", x);
usage(str, s)
char *str, *s;
{
fprintf(stderr, str, s );
E("\n");
E("CP: Copyright (c) 1986, Allen I. Holub. All rights reserved");
E("");
E("Usage: cp [-iev] file [... file] [d:]directory");
E(" cp [-iev] <source file> <dest file>\n");
E("-i ask before copying every file");
E("-v ask only before over-writing existing files");
E("-e don't echo names as they're copied\n");
E("Copies one file to another (the bottom syntax above) or a group");
E("of files to another directory or disk (the top syntax).");
E("Unlike the DOS \"copy\" command, a target must be named.");
E(". (the current directory) and .. (the parent directory)");
E("alone or in combination (ie. \"cp file ../..\" or");
E("\"cp d:/dir/file .\") are acceptable. If the target directory");
E("is a disk id only (ie: \"cp file b:\") the current directory");
E("on the specified disk is assumed.");
exit(1);
}