page%swap@Sun.COM (Bob Page) (05/10/89)
Submitted-by: edwin@watcsc.waterloo.edu (Edwin Hoogerbeets)
Posting-number: Volume 89, Issue 125
Archive-name: unix/mv-cp-rm11.1
Move, copy, or remove files in the style of Unix mv/cp/rm.
[uuencoded executable included. ..bob]
# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
# ReadMe
# makefile
# mv.c
# mv.uu
# mvtest.sh
# This is archive 1 of a 1-part kit.
# This archive created: Tue May 9 22:24:48 1989
echo "extracting ReadMe"
sed 's/^X//' << \SHAR_EOF > ReadMe
X mv/cp/rm v1.1 - move, copy, or remove
X files in the style of Unix mv/cp/rm
X
X Copyright 1989 Edwin Hoogerbeets
X
XThis code is freely redistributable as long as no charge other than
Xreasonable copying fees is levied for it.
X
XUsage:
X
X mv [-cfix] [-] file1 file2
X mv [-cfix] [-] path1 [path2 ...] dir
X cp [-fimnx] [-] file1 file2
X cp [-fimnxrR] [-] path1 [path2 ...] dir
X rm [-cdfimrR] [-] path [path ...]
X
X Where path is either a file or a directory.
X
XOptions:
X
X -c act like cp instead (as in "mv -c" means do a cp instead of mv)
X
X -d remove directories only if they are empty (as in AmigaDOS Delete)
X
X -f force quiet mode, overwriting destination files if necessary.
X
X -i force interactive mode
X
X -m act like mv instead
X
X -n do not copy file dates, comments and protections (use "n"ew dates..)
X
X -R same as -r
X -r recursively do directories as well (mv is always recursive)
X
X -x act like rm instead (I ran out of option letters, that's why...)
X
X - end of options (useful to remove a file whose name starts with
X a dash eg. "-d")
X
X Options f and i are mutually exclusive, with i taking precedence.
X
XNotes:
X
X Yes, a three in one program! It slices, it dices, it even does
X julienne fries!
X
X This version has the following features: [if I did not screw up :-]
X
X - file permissions, dates, and comments are also copied or moved
X by default (switchable)
X - supports arp wildcarding, but does not insist on it (see below)
X - moves across volumes are supported
X - directories can be moved or copied recursively, even across
X volumes
X - attempts to allocate a big enough buffer to be able to copy
X or move files in one pass (reduces thrashing and increases speed)
X - does not print the bloody "foobar...copied" message for each file
X (which also increases speed)
X - can detect when two files are on the same volume (even if an
X assigned name is given) and uses Rename instead of copying
X - honours the delete bit
X - supports "" as current directory (eg. mv df1:* "")
X
X This version has the following misfeatures:
X
X - if a copy or move fails, it does not remove any files whatsoever
X (maybe it is a feature, I do not know)
X - all options are available to all forms of this program, though
X some are not used by some forms. (hence the usage information
X above) No checks are done for non-useful options.
X
X
X that maybe Manx specific. (I don't have Lattice, so I don't really
X know!)
X
X The action performed depends on the executable's name. There are entries
X in the makefile to change the default name of the executables, if a
X different name is desired. Copy one executable to a different name to
X get a different action. The default action is to copy, since no files
X are removed and this is the least destructive option.
X
X There is a small test script for the Dillon/Drew shell (easily ported to
X other shells) to test almost everything I can think of. If you can get
X cp/rm/mv to guru, or at least do something wierd, please send me a test
X case for the script and I will fix it pronto!
X
X It is possible to get by with only one copy of the executable if you
X use a shell that supports aliases. The following aliases might be
X helpful:
X
X alias cp mv -c - mv is the single executable name
X alias rm mv -x - x for remove. (makes sense, eh??)
X alias delete mv -xd - act like AmigaDOS Delete command
X alias rmdir mv -xd - remove directory a la unix
X alias mv Mv - use the external mv/cp/rm command instead
X alias rm Rm of the built in one!
X alias cp Cp
X
XWildcards:
X
X Wildcards (arp) are supported at the request of Monsieur Dan Schein.
X To access them, there are appropriate spots in the makefile to define
X their use (using -DARP). The distribution binary was compiled with arp
X wildcarding.
X
X If you do not have arp's programmers bindings, or if you do not wish to
X have wildcards, I have put in numerous [ugly-looking] #ifdef's throughout
X the code, so that it will compile without arp stuff as well. The
X executables I use do not have the wildcarding because I use Matt's
X (Drew Manxified) shell that expands the wildcards already.
X
XAcknowledgements:
X
X If you thought your silly little example of Amiga programming is not
X worth publicly releasing, think again. This whole program is made of
X various hacked up examples, and has been very instructive for me to
X write! Please give out any examples you think could be remotely useful,
X as they probably are to someone. I hope that maybe this hack will be of
X use to someone as an example (even though it is a mess).
X
X I would like to thank Matt Dillon (again) for his shell, from which
X I hacked the remove routines and the date setting routines.
X Thanks also to Chuck McManis for the GetVolume example from Fish 56.
X Thanks to Doug Tittle for the initial inspiration for this program.
X And finally, thanks to Rob Peck for his book, "Programmer's Guide to
X the Amiga" from which most of the know-how in this program was
X learned.
X
XFiles:
X
X ReadMe rwed 6392 13 27-Apr-89 22:01:43
X cp rwed 13864 28 27-Apr-89 21:53:41
X makefile arwed 1099 3 23-Apr-89 21:56:40
X mv.c arwed 39338 78 24-Apr-89 00:30:35
X mvtest.sh arwed 5812 12 23-Apr-89 22:09:09
X139 Blocks, 66505 Bytes used in 5 files
X
XRevision History:
X
X1.1
X - added in c, m and x options to allow one executable and different
X actions using a shell's alias mechanism. (ie. alias cp mv -c)
X - added d option to remove directories but only if they are empty
X (as in the behaviour of AmigaDOS Delete)
X - fixed problem with copying 0 byte files
X - fixed problem with moving a file to itself with different
X capitalization (mv foo Foo)
X - detects much better if there is an attempt to copy a file to itself
X - uses *much* less stack space (major problem with 1.0)
X - somewhat smaller size (but now Manx dependant...)
X
X1.0
X - initial effort
X
XPlease redirect any comments, criticisms or spare Swimsuit Issues
Xof Sports Illustrated to:
X
XEdwin Hoogerbeets
XUsenet: edwin@watcsc.waterloo.edu (May '89 to Aug '89)
XCIS: 72647,3675 (any time at all)
X
X
X
X
SHAR_EOF
echo "extracting makefile"
sed 's/^X//' << \SHAR_EOF > makefile
X#
X# makefile for mv v1.0 - Unix-like move file utility
X#
X# Copyright 1989 Edwin Hoogerbeets
X#
X# This code may be freely redistributed as long as no charges other than
X# reasonable copying fees are levied for it.
X#
X
X#
X# Set these to the executable names you want.
X#
XMVNAME=mv
XCPNAME=cp
XRMNAME=rm
X
X# destination of the executables
XDESTDIR=c:
X
X#
X# Set this to -DARP and -la32 to include arp wildcarding
X#
XARP=-DARP
XARPLIB=-la32
X
X#
X# Set this to -g for sdb
X#
XLNDEBUG=
X#-g
X
X#
X# Add -DDEBUG and -n for verbose debugging and sdb
X#
XDEBUG=
X#-n
X#-DDEBUG
X
XCFLAGS=+L $(DEBUG) $(ARP) -DMVNAME="$(MVNAME)" -DCPNAME="$(CPNAME)" \
X-DRMNAME="$(RMNAME)"
X
X#
X# do copy first, so we can use it to copy itself, instead of relinking!
X#
Xall: $(CPNAME) $(RMNAME) $(MVNAME)
X
X$(CPNAME): mv.o
X ln $(LNDEBUG) mv.o $(ARPLIB) -lc32 -o $@
X
X$(MVNAME): $(CPNAME)
X $(CPNAME) $(CPNAME) $@
X
X$(RMNAME): $(CPNAME)
X $(CPNAME) $(CPNAME) $@
X
Xclean:
X $(RMNAME) -f $(CPNAME) $(MVNAME) $(RMNAME) $(CPNAME).dbg \
X$(RMNAME).dbg $(MVNAME).dbg mv.o
X
Xmv.o: mv.c
X
Xinstall: all
X $(CPNAME) -f $(CPNAME) $(RMNAME) $(MVNAME) $(DESTDIR)
X
X
X
SHAR_EOF
echo "extracting mv.c"
sed 's/^X//' << \SHAR_EOF > mv.c
X/*
X * mv v1.0 - Unix-like move file utility
X *
X * Copyright 1989 Edwin Hoogerbeets
X *
X * This code may be freely redistributed as long as no charges other than
X * reasonable copying fees are levied for it.
X *
X * Manx version by Edwin Hoogerbeets
X * usenet: edwin@watcsc.waterloo.edu
X * CIS: 72647,3675
X *
X * Works mostly like the Unix move.
X *
X * Usage: mv [-cfix] [-] file1 file2
X * mv [-cfix] [-] path1 [path2 ...] dir
X * cp [-fimnx] [-] file1 file2
X * cp [-fimnxrR] [-] path1 [path2 ...] dir
X * rm [-cdfimrR] [-] path [path ...]
X *
X * Where path is either a file or a directory.
X *
X * -c act like cp instead (as in "mv -c" means do a cp instead of mv)
X * -d remove directories only if they are empty (as in AmigaDOS Delete)
X * -f force quiet mode, overwriting destination files if necessary.
X * -i force interactive mode
X * -m act like mv instead
X * -n do not copy file dates, comments and protections (use "n"ew dates..)
X * -R same as -r
X * -r recursively do directories as well (mv is always recursive)
X * -x act like rm instead
X * - end of options (useful to remove a file whose name starts with
X * a dash eg. "-d")
X *
X * Moves, etc. across devices are supported.
X *
X */
X
X#include <fcntl.h>
X#include <libraries/dos.h>
X#include <libraries/dosextens.h>
X#ifdef ARP
X#include <libraries/arpbase.h>
X#include <libraries/arpfunc.h>
X#endif
X#include <exec/memory.h>
X#include <ctype.h>
X
X#define FIBSIZE (long)sizeof(struct FileInfoBlock)
X#define BUFSIZE 256
X
Xtypedef struct fl {
X char name[BUFSIZE];
X struct fl *next;
X} filenode;
X
X#define FNSIZE (long)sizeof(filenode)
X
Xstruct FileLock *lock;
Xstruct FileInfoBlock *fib;
X
Xint mvflag = 0, /* is this a move command? */
X cpflag = 0, /* is this a copy command? */
X rmflag = 0, /* is this a remove command? */
X rflag = 0, /* is this command recursive? */
X fflag = 0, /* don't ask if it should overwrite, just do it */
X iflag = 0, /* do interactive mode */
X nflag = 1, /* copy file dates, comments and protections */
X dflag = 0; /* delete directories only if they are empty */
X
Xchar commandname[32] = "";
X
Xlong ofile; /* output file handle */
Xlong ifile; /* input file handle */
X
X#ifdef ARP
X
Xtypedef struct BAP {
X struct AnchorPath bap_ap;
X char padding[BUFSIZE];
X} BigAnchorPath;
X
X#define APSIZE (long)sizeof(BigAnchorPath)
X
Xint arpflag = 0;
X
X#endif
X
X/* these are so Manx won't complain about ptr/int conversions, etc. */
Xextern struct FileLock *ParentDir();
Xextern struct FileLock *CreateDir();
Xextern struct FileLock *Lock();
Xextern struct FileLock *CurrentDir();
Xextern int Examine();
Xextern char *AllocMem();
Xextern struct FileHandle *Open();
Xextern struct MsgPort *DeviceProc();
Xextern struct Library *OpenLibrary();
Xextern struct _dev *_devtab;
X
X#ifdef ARP
Xstruct ArpBase *ArpBase;
Xstruct IntuitionBase *IntuitionBase;
Xstruct GfxBase *GfxBase;
X#endif
X
X#include <exec/alerts.h>
X#include <workbench/startup.h>
X
Xextern long _savsp, _stkbase;
X
Xextern int errno;
Xextern int Enable_Abort;
X
Xextern int _argc, _arg_len;
Xextern char **_argv, *_arg_lin;
X
X_main(alen, aptr)
Xlong alen;
Xchar *aptr;
X{
X struct Process *pp, *FindTask();
X
X _stkbase = _savsp - *((long *)_savsp+1) + 8;
X *(long *)_stkbase = 0x4d414e58L;
X
X pp = FindTask(0L);
X _cli_parse(pp, alen, aptr);
X Enable_Abort = 1;
X
X exit(main(_argc, _argv));
X}
X
X/*
X * The following few routines were taken from my edlib1.1 source. They
X * are included here so that anyone can recompile this source without
X * the library. (I'll be happy to send you edlib if you want it.)
X */
X
Xchar *strrpbrk(str, charset)
Xregister char *str, *charset;
X{
X register char *temp;
X extern char *index();
X
X temp = str + strlen(str) - 1;
X
X while ( temp != (str - 1) && !index(charset, *temp) )
X --temp;
X
X return( (temp != (str - 1)) ? temp : NULL);
X}
X
Xint stricmp(str1,str2)
Xregister char *str1,*str2;
X{
X register int index = 0;
X
X while ( str1[index] && str2[index] &&
X tolower(str1[index]) == tolower(str2[index]) )
X ++index;
X
X return( (tolower(str1[index]) < tolower(str2[index])) ? -1 :
X ( (tolower(str1[index]) > tolower(str2[index])) ? 1 : 0) );
X}
X
X
X/* return a pointer to the first character of a file name in a path name */
Xchar *basename(buf)
Xregister char *buf;
X{
X register char *foo = strrpbrk(buf,":/");
X
X return( foo ? (foo + 1) : buf );
X}
X
X/* end of edlib routines */
X
X/* write out a string */
Xint emit(file,str)
Xlong file;
Xchar *str;
X{
X Write(file,str,strlen(str));
X}
X
X/*
X * return the length of the largest piece of memory that is possibly
X * contiguous
X */
Xlong mem()
X{
X long chip, fast;
X extern long AvailMem();
X
X Forbid();
X chip = AvailMem(MEMF_CHIP);
X fast = AvailMem(MEMF_FAST);
X Permit();
X
X return(chip>fast ? chip : fast);
X}
X
X/* make a new file info block and return a pointer to it */
Xstruct FileInfoBlock *newfib()
X{
X struct FileInfoBlock *fib;
X
X fib = (struct FileInfoBlock *) AllocMem(FIBSIZE, MEMF_CLEAR);
X
X if ( !fib ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": Out of memory!\n");
X }
X return(NULL);
X }
X
X return(fib);
X}
X
X/* get rid of a used file info block */
Xint freefib(fib)
X{
X if ( fib )
X FreeMem(fib,FIBSIZE);
X}
X
X/* make a new buffer and return a pointer to it */
Xchar *newbuf()
X{
X register char *temp = AllocMem(BUFSIZE,MEMF_CLEAR|MEMF_PUBLIC);
X
X if ( !temp ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": Out of memory!\n");
X }
X return(NULL);
X }
X
X return(temp);
X}
X
X/* free a buffer previously allocated with newbuf() */
Xint freebuf(buf)
Xchar *buf;
X{
X if ( buf ) {
X FreeMem(buf,BUFSIZE);
X }
X}
X
X/* make a new filenode structure and return a pointer to it */
Xfilenode *newfilenode()
X{
X filenode *new = (filenode *)
X AllocMem(FNSIZE,MEMF_PUBLIC|MEMF_CLEAR);
X
X if ( new ) {
X new->name[0] = '\0';
X new->next = NULL;
X }
X
X return(new);
X}
X
X/* free a list of filenode structures */
Xint freefilenodes(file)
Xfilenode *file;
X{
X if ( file ) {
X freefilenodes(file->next);
X
X FreeMem(file,FNSIZE);
X }
X}
X
X/* return a pointer to the last element of a filenode list */
Xfilenode *end(file)
Xfilenode *file;
X{
X if ( file ) {
X if ( file->next ) {
X return(end(file->next));
X } else {
X return(file);
X }
X } else {
X return(NULL);
X }
X}
X
X/* return the length of a list of filenodes */
Xint arglength(file)
Xfilenode *file;
X{
X if ( file->next ) {
X return(arglength(file->next)+1);
X } else {
X return(1);
X }
X}
X
X/* Does the input string contain a wildcard? */
Xint haswild(name)
Xchar *name;
X{
X register int foo = 0;
X
X while ( name[foo] && name[foo] != '*' && name[foo] != '?' &&
X name[foo] != '#' )
X ++foo;
X
X return ( name[foo] );
X}
X
X
X/*
X * This routine takes a string with possibly a wildcard in it and expands
X * it to a list of filenode structures. If arp isn't opened or if it
X * wasn't compiled with arp, then it creates a list of 1 filenode containing
X * the argument it was passed. The pointer to nomem is where it puts the
X * error code for "low on available memory" errors.
X */
Xfilenode *expand(name,nomem)
Xchar *name;
Xint *nomem;
X{
X filenode *file;
X
X# ifdef ARP
X if ( arpflag && haswild(name) ) {
X filenode *temp;
X int error;
X BigAnchorPath *anchor;
X
X *nomem = 0;
X
X anchor = (BigAnchorPath *)
X AllocMem(APSIZE,MEMF_CLEAR|MEMF_PUBLIC);
X
X anchor->bap_ap.ap_Length = BUFSIZE;
X
X if ( FindFirst(name,anchor) ) {
X FreeAnchorChain(anchor);
X return(NULL);
X }
X
X if ( file = newfilenode() ) {
X strcat(file->name,anchor->bap_ap.ap_Buf);
X } else {
X *nomem = 1;
X FreeAnchorChain(anchor);
X return(NULL);
X }
X# ifdef DEBUG
X printf("First matched file: %s\n",file->name);
X# endif
X
X temp = file;
X
X while ( !(error = FindNext(anchor)) ) {
X
X if ( !(temp->next = newfilenode()) ) {
X *nomem = 1;
X FreeAnchorChain(anchor);
X freefilenodes(file);
X return(NULL);
X }
X
X temp = temp->next;
X
X strcat(temp->name,anchor->bap_ap.ap_Buf);
X
X# ifdef DEBUG
X printf("Next matched file: %s\n",temp->name);
X# endif
X }
X
X FreeAnchorChain(anchor);
X } else {
X# endif
X file = newfilenode();
X
X if ( file ) {
X *nomem = 0;
X strcat(file->name,name);
X } else {
X *nomem = 1;
X return(NULL);
X }
X
X# ifdef ARP
X }
X# endif
X
X return(file);
X}
X
X/* well, I guess this is a pro-choice program. ;-) */
X_abort()
X{
X if ( lock )
X UnLock(lock);
X
X exit(-1);
X}
X
X/*
X * make a string containing the path part of a full AmigaDOS path name.
X * return a pointer to this string.
X */
Xchar *parent(name)
Xchar *name;
X{
X register char *foo;
X char *temp = AllocMem((long)strlen(name)+1,MEMF_CLEAR);
X
X strcat(temp,name);
X
X /* get a pointer to the filename part */
X foo = basename(temp);
X
X /*
X * lop off the file name part -- the length of the whole original
X * string must still be freed when freeing what temp points to.
X */
X *foo = '\0';
X
X return(temp);
X}
X
X/* are the two files on the same volume? If you can't tell, guess */
Xint samedev(src,dst)
Xchar *src, *dst;
X{
X char srcbuf[40], dstbuf[40], *temp;
X struct FileLock *lock;
X
X /* Simultaneous get a lock and convert BPTR to a C pointer */
X lock = (struct FileLock *)BADDR(Lock(src,ACCESS_READ));
X
X if (lock == NULL) {
X return(-1);
X }
X
X temp = (char *)
X BADDR(((struct DeviceList *)BADDR(lock->fl_Volume))->dl_Name);
X
X strncpy(srcbuf,&temp[1],temp[0]+1);
X srcbuf[temp[0]+2] = '\0';
X
X UnLock(((long)lock) >> 2); /* You must UnLock or the GURU visits */
X
X temp = parent(dst);
X
X lock = (struct FileLock *)BADDR(Lock(temp,ACCESS_READ));
X
X FreeMem(temp,strlen(dst)+1);
X
X if (lock == NULL) {
X return(-1);
X }
X
X temp = (char *)
X BADDR(((struct DeviceList *)BADDR(lock->fl_Volume))->dl_Name);
X
X strncpy(dstbuf,&temp[1],temp[0]+1);
X dstbuf[temp[0]+2] = '\0';
X
X UnLock(((long)lock) >> 2); /* You must UnLock or the GURU visits */
X
X# ifdef DEBUG
X printf("%s and %s are %son the same volume\n",src,dst,
X (!stricmp(srcbuf,dstbuf))?"":"not ");
X# endif
X return( !stricmp(srcbuf,dstbuf) );
X}
X
X/*
X * Is the named file a directory? Get a File Info Block and point fib to
X * it and return the results.
X *
X * return 0 for not a dir (ie. file)
X * return 1 for a dir
X * return 2 for no access to file
X * return 3 for not being able to examine file
X *
X */
Xint isdir(path,fib)
Xchar *path;
Xstruct FileInfoBlock **fib;
X{
X struct FileLock *lock;
X register int result;
X
X /* allocate a word aligned memory block to hold our info */
X *fib = newfib();
X
X if ( !(lock = Lock(path,ACCESS_READ)) ) {
X return(2);
X }
X
X if ( *fib ) {
X if ( Examine(lock,*fib) ) {
X
X /* if the source is not a directory .. */
X result = (*fib)->fib_DirEntryType > 0 ? 1 : 0;
X
X } else {
X /* 3 for could not examine */
X result = 3;
X }
X
X } else {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": Out of memory!\n");
X }
X UnLock(lock);
X return(-1);
X }
X
X UnLock(lock);
X
X return(result);
X}
X
X#ifdef ARP
Xvoid closethings()
X{
X if ( ArpBase ) {
X CloseLibrary(ArpBase);
X }
X
X if ( IntuitionBase ) {
X CloseLibrary(IntuitionBase);
X }
X
X if ( GfxBase ) {
X CloseLibrary(GfxBase);
X }
X
X}
X#endif
X
Xvoid usage()
X{
X if ( !fflag ) {
X emit(ofile,"Usage: mv [-cfix] [-] file1 file2\n");
X emit(ofile," mv [-cfix] [-] path1 [path2 ...] dir\n");
X emit(ofile," cp [-fimnx] [-] file1 file2\n");
X emit(ofile," cp [-fimnxrR] [-] path1 [path2 ...] dir\n");
X emit(ofile," rm [-cdfimrR] [-] path [path ...]\n");
X emit(ofile,"\nWhere path is either a file or a directory.\n");
X }
X
X# ifdef ARP
X closethings();
X# endif
X
X exit(1);
X}
X
X/* the following is a mess. brace yourself. */
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X register int index, c;
X struct FileInfoBlock *startfib = NULL, *endfib = NULL;
X filenode *start = NULL, *temp = NULL, *endnode = NULL;
X int args, result, nomem;
X
X ofile = (long) Open("*",MODE_NEWFILE); /* open new file for stderr */
X ifile = Input();
X
X# ifdef ARP
X ArpBase = (struct ArpBase *) OpenLibrary(ArpName,0L);
X
X if ( ArpBase ) {
X# ifdef DEBUG
X printf("opened arp.library okay\n");
X# endif
X
X if ( !(IntuitionBase = (struct IntuitionBase *)
X OpenLibrary("intuition.library",0L)) ) {
X emit(ofile,"Could not open intuition.library\n");
X# ifdef ARP
X closethings();
X# endif
X exit(-1);
X }
X
X if ( !(GfxBase = (struct GfxBase *)
X OpenLibrary("graphics.library",0L)) ) {
X emit(ofile,"Could not open graphics.library\n");
X# ifdef ARP
X closethings();
X# endif
X exit(-1);
X }
X arpflag = 1;
X } else {
X# ifdef DEBUG
X printf("Arp.library not opened.\n");
X# endif
X arpflag = 0;
X }
X# endif
X
X if ( !stricmp(basename(argv[0]),MVNAME) ) {
X
X ++mvflag;
X ++rflag;
X
X } else if ( !stricmp(basename(argv[0]),RMNAME) ) {
X
X ++rmflag;
X
X } else {
X
X /*
X * default to the copy command so that if the user renames the
X * executable to something we don't understand, we don't do
X * anything really destructive.
X */
X ++cpflag;
X }
X
X index = 1;
X
X /* simplistic argument processing */
X
X while ( argv[index][0] == '-' ) {
X c = 1;
X
X /* - option was specified to end other options */
X if ( !argv[index][c] ) {
X ++index;
X break;
X }
X
X while ( argv[index][c] ) {
X switch ( argv[index][c] ) {
X case 'c':
X cpflag = 1;
X rflag = mvflag = rmflag = 0;
X break;
X
X case 'd':
X dflag = 1;
X break;
X
X case 'f':
X fflag = 1;
X iflag = 0;
X break;
X
X case 'i':
X fflag = 0;
X iflag = 1;
X break;
X
X case 'm':
X rflag = mvflag = 1;
X cpflag = rmflag = 0;
X break;
X
X case 'n':
X nflag = 0;
X break;
X
X case 'R':
X case 'r':
X rflag = 1;
X break;
X
X case 'x':
X rmflag = 1;
X rflag = mvflag = cpflag = 0;
X break;
X
X default:
X emit(ofile,"invalid option ");
X Write(ofile,&argv[index][c],1);
X emit(ofile,"\n");
X usage();
X }
X c++;
X }
X ++index;
X }
X
X /* if there are no file names left after the options were processed ... */
X if ( (argc - index) < (rmflag ? 1 : 2) ) {
X usage();
X }
X
X if ( mvflag ) {
X
X strcat(commandname,MVNAME);
X# ifdef DEBUG
X printf("mv command executing\n");
X# endif
X
X } else if ( rmflag ) {
X
X strcat(commandname,RMNAME);
X# ifdef DEBUG
X printf("rm command executing\n");
X# endif
X
X } else {
X
X strcat(commandname,CPNAME);
X# ifdef DEBUG
X printf("cp command executing\n");
X# endif
X
X }
X
X /*
X * expand the first argument. index contains the number of the first
X * file name argument at this point, because it is updated by the options
X * parsing piece of code above.
X */
X start = expand(argv[index++],&nomem);
X
X if ( nomem ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": Out of memory!\n");
X }
X# ifdef ARP
X closethings();
X# endif
X exit(-1);
X }
X
X temp = end(start);
X
X for ( ;index < argc; index++) {
X
X /*
X * it is possible that previous arguments had a wildcard and didn't
X * match anything, so temp would be NULL at this point, otherwise
X * attach the new file list from expand onto the end of the list.
X */
X if ( temp ) {
X temp->next = expand(argv[index],&nomem);
X } else {
X temp = expand(argv[index],&nomem);
X start = temp;
X }
X
X if ( nomem ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": Out of memory!\n");
X }
X# ifdef ARP
X closethings();
X# endif
X freefilenodes(start);
X exit(-1);
X }
X
X temp = end(temp);
X }
X
X endnode = end(start);
X args = arglength(start);
X
X# ifdef DEBUG
X printf("argc: %d\n",argc);
X
X for ( temp = start; temp; temp = temp->next ) {
X printf("argument \"%s\"\n", temp->name );
X }
X# endif
X
X if ( !rmflag ) {
X
X /*
X * main case statement for the program to find out what to do with
X * its life. (You gotta fight, for your right,
X * to PPPPPAAAAAAARRRRRRRRIIIIIIIITTTTTTTYYYYYY!!!!!!
X */
X
X /*
X * check last argument (ie. the destination file) to make sure it
X * is a directory
X */
X switch ( isdir(endnode->name,&endfib) ) {
X
X /*
X * destination is a file, check that there are only 2 arguments
X * and that the first one is also a file, or inform the user
X * of his (or her) silliness.
X */
X case 0:
X if ( args == 2 ) {
X if ( isdir(start->name,&startfib) ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": cannot move a directory onto a file\n");
X }
X
X freefib(startfib);
X freefib(endfib);
X freefilenodes(start);
X usage();
X
X } else {
X
X result = mv2f(start->name,startfib,endnode->name,endfib);
X
X if ( result == 2 && mvflag ) {
X rm(start->name,fflag,iflag);
X }
X
X freefib(startfib);
X freefib(endfib);
X freefilenodes(start);
X exit(0);
X }
X } else {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": cannot move a directory onto a file\n");
X }
X freefib(endfib);
X freefilenodes(start);
X usage();
X }
X break;
X
X /* destination is a directory */
X case 1:
X freefib(endfib);
X break;
X
X /* destination doesn't exist */
X case 2:
X if ( args == 2 && !isdir(start->name,&startfib) ) {
X
X /*
X * move file specified in start->name to a new
X * file in endnode->name
X */
X result = mv2f(start->name,startfib,endnode->name,NULL);
X
X if ( result == 2 && mvflag ) {
X rm(start->name,fflag,iflag);
X }
X
X freefib(endfib);
X freefib(startfib);
X freefilenodes(start);
X exit(0);
X } else {
X if ( args > 2 ) {
X struct FileLock *lock;
X char *buf = newbuf();
X
X freefib(startfib);
X freefib(endfib);
X
X if ( !buf ) {
X freefilenodes(start);
X exit(-1);
X }
X
X if ( iflag ) {
X buf[0] = '\0';
X emit(ofile,commandname);
X emit(ofile,": create directory ");
X emit(ofile,endnode->name);
X
X Read(ifile,buf,BUFSIZE);
X
X if ( buf[0] != 'y' && buf[0] != 'Y' ) {
X break;
X }
X }
X
X if ( !(lock = CreateDir(endnode->name)) ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": unable to create directory ");
X emit(ofile,endnode->name);
X emit(ofile,"\n");
X }
X# ifdef ARP
X closethings();
X# endif
X freefilenodes(start);
X freebuf(buf);
X exit(-1);
X } else {
X UnLock(lock);
X }
X freebuf(buf);
X }
X }
X break;
X
X case 3:
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": could not examine file ");
X emit(ofile,endnode->name);
X emit(ofile,"\n");
X }
X
X freefilenodes(start);
X freefib(endfib);
X exit(3);
X break;
X }
X
X# ifdef DEBUG
X printf("Move or copy files to directory %s\n",endnode->name);
X# endif
X }
X
X /*
X * For each source argument, move it to the correct directory.
X */
X for ( temp = start; temp; temp = temp->next ) {
X
X Chk_Abort();
X
X if ( (temp != endnode) && (mvflag || cpflag) ) {
X result = mv(temp->name,endnode->name);
X
X switch ( result ) {
X
X /* if there was an error, get out now */
X case -1:
X# ifdef ARP
X closethings();
X# endif
X freefilenodes(start);
X exit(-1);
X
X /* if there was a successful copy, then remove the source */
X case 2:
X if ( !cpflag )
X rm(temp->name,fflag,iflag);
X break;
X
X /*
X * if there was a successful move, then do nothing, 'cause the
X * source is gone already.
X */
X default:
X break;
X }
X } else if ( rmflag ) {
X rm(temp->name,fflag,iflag);
X }
X }
X
X# ifdef ARP
X closethings();
X# endif
X
X freefilenodes(start);
X
X exit(0);
X}
X
Xint rm_file(file,fflag,iflag)
Xchar *file;
Xint fflag, iflag;
X{
X register int result;
X char *buf = newbuf();
X
X if ( !buf ) {
X return(-1);
X }
X
X# ifdef DEBUG
X printf("Deleting file %s\n",file);
X# endif
X
X switch ( isdeletable(file) ) {
X case 2:
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": could not find file ");
X emit(ofile,file);
X emit(ofile,"\n");
X }
X result = -1;
X break;
X
X case 1:
X if ( iflag ) {
X buf[0] = '\0';
X
X emit(ofile,commandname);
X emit(ofile,": remove ");
X emit(ofile,file);
X emit(ofile,"? ");
X
X Read(ifile,buf,BUFSIZE);
X
X if ( buf[0] != 'y' && buf[0] != 'Y' ) {
X result = -1;
X break;
X }
X }
X
X SetProtection(file,0);
X
X if ( !DeleteFile(file) ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": could not remove ");
X emit(ofile,file);
X emit(ofile,"\n");
X }
X result = -1;
X } else {
X result = 1;
X }
X break;
X
X case 0:
X if ( !fflag ) {
X buf[0] = '\0';
X
X emit(ofile,commandname);
X emit(ofile,": overide delete protection for file ");
X emit(ofile,file);
X emit(ofile,"? ");
X
X Read(ifile,buf,BUFSIZE);
X
X if ( buf[0] == 'y' || buf[0] == 'Y' ) {
X
X SetProtection(file,0);
X
X if ( !DeleteFile(file) ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": could not remove ");
X emit(ofile,file);
X emit(ofile,"\n");
X }
X result = -1;
X } else {
X result = 1;
X }
X } else {
X result = -1;
X }
X } else {
X
X SetProtection(file,0);
X
X if ( !DeleteFile(file) ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": could not remove ");
X emit(ofile,file);
X emit(ofile,"\n");
X }
X result = -1;
X } else {
X result = 1;
X }
X }
X break;
X }
X
X freebuf(buf);
X return(result);
X}
X
X
X/* recursively remove a directory or a remove a file */
Xint rm_dir(name,fflag,iflag)
Xchar *name;
Xint fflag, iflag;
X{
X register struct FileLock *lock, *cwd;
X register struct FileInfoBlock *fib;
X register char *buf;
X register int result = 1;
X
X# ifdef DEBUG
X printf("Recursively deleting directory %s\n",name);
X# endif
X
X buf = newbuf();
X fib = (struct FileInfoBlock *)AllocMem(FIBSIZE,MEMF_CLEAR);
X
X if (lock = Lock(name, ACCESS_READ)) {
X
X cwd = CurrentDir(lock);
X
X if (Examine(lock, fib)) {
X
X buf[0] = '\0';
X
X while (result && ExNext(lock, fib)) {
X
X if ( fib->fib_DirEntryType > 0 )
X result = rm_dir(fib->fib_FileName,fflag,iflag);
X
X if (buf[0]) {
X rm_file(buf,fflag,iflag);
X }
X
X strcpy(buf, fib->fib_FileName);
X }
X
X if ( buf[0] ) {
X rm_file(buf,fflag,iflag);
X }
X }
X
X UnLock(CurrentDir(cwd));
X
X } else {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": could not get a lock on ");
X emit(ofile,name);
X emit(ofile,"\n");
X }
X result = -1;
X }
X
X FreeMem(fib, FIBSIZE);
X freebuf(buf);
X
X return(result);
X}
X
Xrm(name,fflag,iflag)
Xchar *name;
Xint fflag,iflag;
X{
X int result;
X struct FileInfoBlock *fib;
X
X switch ( isdir(name,&fib) ) {
X case 0:
X result = rm_file(name,fflag,iflag);
X break;
X
X case 1:
X if ( rflag ) {
X /* recursively delete the directory */
X result = rm_dir(name,fflag,iflag);
X if ( result ) {
X rm_file(name,fflag,iflag);
X }
X } else if ( dflag ) {
X
X /* only deletes directory if it is empty, as in AmigaDOS Delete */
X result = rm_file(name,fflag,iflag);
X
X } else {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": ");
X emit(ofile,name);
X emit(ofile," is a directory (not removed)\n");
X }
X result = -1;
X }
X break;
X
X case 2:
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": could not access file ");
X emit(ofile,name);
X emit(ofile,"\n");
X }
X break;
X
X
X case 3:
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": could not examine file ");
X emit(ofile,name);
X emit(ofile,"\n");
X }
X break;
X }
X
X if ( fib )
X freefib(fib);
X
X return(result);
X}
X
X
X/* mv a file or directory _to_a_directory_ */
Xint mv(src,dst)
Xchar *src, *dst;
X{
X register int result = 0;
X struct FileInfoBlock *srcfib;
X
X switch ( isdir(src,&srcfib) ) {
X
X /* source is a file */
X case 0:
X result = mvfile(src,srcfib,dst);
X break;
X
X /* source is a directory */
X case 1:
X result = mvdir(src,srcfib,dst);
X break;
X
X /* no access to source */
X case 2:
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": could not access file ");
X emit(ofile,src);
X emit(ofile,"\n");
X }
X result = 0;
X break;
X
X /* not able to examine source */
X case 3:
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": could not examine file ");
X emit(ofile,src);
X emit(ofile,"\n");
X }
X result = 0;
X break;
X }
X
X freefib(srcfib);
X return(result);
X}
X
X/* mv to a destination dir _from_ a directory source */
Xint mvdir(src,srcfib,dst)
Xchar *src, *dst;
Xstruct FileInfoBlock *srcfib;
X{
X register int result = 1, temp, onsame;
X struct FileInfoBlock *dstfib;
X
X if ( (onsame = samedev(src,dst)) == -1 )
X return(0);
X
X temp = isdir(dst,&dstfib);
X
X /* if they are on the same device, treat the src dir as a file */
X if ( onsame && mvflag ) {
X
X /* if the destination dir doesn't exist, then move onto it... */
X if ( temp == 2 ) {
X
X result = mv2f(src,srcfib,dst,NULL);
X } else {
X
X /* ...else move into it */
X result = mv2d(src,srcfib,dst);
X }
X
X } else if ( mvflag || (cpflag && rflag) ) {
X
X /* ugh. We have to copy the source dir to the destination dir */
X
X register int success, len;
X register char c;
X register struct FileLock *oldlock, *newlock, *dstlock;
X char *buf = newbuf();
X char *dstbuf = newbuf();
X register struct FileInfoBlock *fib = newfib();
X
X if ( !fib || !buf || !dstbuf ) {
X result = -1;
X } else {
X
X dstbuf[0] = '\0';
X
X strcat(dstbuf,dst);
X
X if ( temp != 2 ) {
X /*
X * build the name of the destination from the directory name and
X * later, the file name
X */
X
X len = strlen(dstbuf);
X
X /*
X * only append a slash if the file name is not the current directory,
X * (ie. "") the last character is not null, and the last character
X * is neither of ':' or '/'. This part is so much easier under Unix
X * path naming conventions, but hey, Amigoids gotta be different!
X */
X if ( len && (c = dstbuf[len - 1] ) && c != ':' && c != '/' )
X strcat(dstbuf,"/");
X
X /*
X * add only the file name onto the destination directory to
X * build the name of the file we want to move to
X */
X strcat(dstbuf,basename(src));
X }
X
X /* see if the directory exists */
X if ( !(dstlock = Lock(dstbuf,ACCESS_READ)) ) {
X struct DateStamp ds;
X
X /* if no lock, try creating it */
X
X if ( iflag ) {
X buf[0] = '\0';
X
X emit(ofile,commandname);
X emit(ofile,": create directory ");
X emit(ofile,dstbuf);
X emit(ofile,"? ");
X
X Read(ifile,buf,BUFSIZE);
X
X if ( buf[0] != 'y' && buf[0] != 'Y' ) {
X freefib(fib);
X freefib(dstfib);
X
X return(0);
X }
X }
X
X if ( !(dstlock = CreateDir(dstbuf)) ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": unable to create directory ");
X emit(ofile,dstbuf);
X emit(ofile,"\n");
X }
X return(0);
X }
X# ifdef DEBUG
X printf("Created directory %s\n",dstbuf);
X# endif
X
X setdate(&srcfib->fib_Date,dstbuf);
X
X }
X
X UnLock(dstlock);
X
X /*
X * get a lock on the source directory, since we have to copy it
X * recursively
X */
X newlock = Lock(src,ACCESS_READ);
X
X /* Take a look at the directory */
X success = Examine(newlock,fib);
X
X /*
X * while the examination of the source directory worked and the
X * last move worked...
X */
X while ( ExNext(newlock,fib) && result > 0 ) {
X
X /* build the source file name */
X buf[0] = '\0';
X
X strcat(buf,src);
X
X len = strlen(buf);
X
X if ( len && (c = buf[len - 1] ) && c != ':' && c != '/' )
X strcat(buf,"/");
X
X strcat(buf,&fib->fib_FileName[0]);
X
X result = mv(buf,dstbuf);
X }
X
X UnLock(newlock);
X }
X
X freefib(fib);
X freebuf(buf);
X freebuf(dstbuf);
X
X } else {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": ");
X emit(ofile,src);
X emit(ofile," is a directory (not copied)\n");
X }
X }
X
X freefib(dstfib);
X
X return(result);
X}
X
X/* mv to a destination file or directory _from_ a file */
Xint mvfile(src,srcfib,dst)
Xchar *src, *dst;
Xstruct FileInfoBlock *srcfib;
X{
X register int result = 0;
X struct FileInfoBlock *dstfib;
X char *buf = newbuf();
X
X if ( !buf ) {
X return(-1);
X }
X
X switch ( isdir(dst,&dstfib) ) {
X
X /* destination is a file */
X case 0:
X result = mv2f(src,srcfib,dst,dstfib);
X break;
X
X /* destination is a directory */
X case 1:
X result = mv2d(src,srcfib,dst);
X break;
X
X case 2:
X if ( iflag ) {
X buf[0] = '\0';
X
X emit(ofile,commandname);
X emit(ofile,": create directory ");
X emit(ofile,dst);
X emit(ofile,"? ");
X
X Read(ifile,buf,BUFSIZE);
X
X if ( buf[0] != 'y' && buf[0] != 'Y' ) {
X result = 0;
X break;
X }
X }
X# ifdef DEBUG
X printf("Creating dir %s\n",dst);
X# endif
X
X lock = CreateDir(dst);
X
X if ( !lock ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": could not create destination directory ");
X emit(ofile,dst);
X emit(ofile,"\n");
X }
X result = 0;
X } else {
X
X UnLock(lock);
X result = mv2d(src,srcfib,dst);
X }
X
X break;
X
X case 3:
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": could not examine directory ");
X emit(ofile,dst);
X emit(ofile,"\n");
X }
X result = 0;
X break;
X }
X
X freefib(dstfib);
X freebuf(buf);
X return(result);
X}
X
X/* mv a file _to_ a directory dst */
Xint mv2d(src,srcfib,dst)
Xchar *src, *dst;
Xstruct FileInfoBlock *srcfib;
X{
X char *buf = newbuf();
X register char c;
X register int result = 0;
X register int len = strlen(dst);
X struct FileInfoBlock *dstfib;
X
X if ( !buf ) {
X return(-1);
X }
X
X buf[0] = '\0';
X
X /* build the file name in the destination directory */
X strcat(buf,dst);
X
X if ( len && (c = buf[len - 1] ) && c != ':' && c != '/' )
X strcat(buf,"/");
X
X strcat(buf,basename(src));
X
X switch ( isdir(buf,&dstfib) ) {
X
X case 0:
X result = mv2f(src,srcfib,buf,dstfib);
X break;
X
X case 1:
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": could not move file ");
X emit(ofile,src);
X emit(ofile," onto directory ");
X emit(ofile,buf);
X emit(ofile,"\n");
X }
X result = 0;
X break;
X
X case 2:
X result = mv2f(src,srcfib,buf,NULL);
X break;
X
X case 3:
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": something is awry with file ");
X emit(ofile,buf);
X emit(ofile,"\n");
X }
X result = 0;
X break;
X }
X
X freefib(dstfib);
X freebuf(buf);
X return(result);
X}
X
X/* mv a file _to_ a file */
Xint mv2f(src,srcfib,dst,dstfib)
Xchar *src, *dst;
Xstruct FileInfoBlock *srcfib, *dstfib;
X{
X register int result = 0, cleanup = 0;
X char *inputbuf;
X register int onsame;
X
X /* are they on the same volume? */
X if ( (onsame = samedev(src,dst)) == -1) {
X freebuf(inputbuf);
X return(0);
X }
X
X if ( !(inputbuf = newbuf()) ) {
X return(-1);
X }
X
X if ( dstfib ) {
X if ( onsame && srcfib->fib_DiskKey == dstfib->fib_DiskKey ) {
X
X if ( !mvflag ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": cannot copy ");
X emit(ofile,src);
X emit(ofile," to itself!\n");
X }
X freebuf(inputbuf);
X return(1);
X }
X
X } else {
X
X if ( iflag ) {
X inputbuf[0] = '\0';
X
X emit(ofile,commandname);
X emit(ofile,": overwrite ");
X emit(ofile,dst);
X emit(ofile,"? ");
X
X Read(ifile,inputbuf,BUFSIZE);
X
X if ( inputbuf[0] != 'y' && inputbuf[0] != 'Y' ) {
X freebuf(inputbuf);
X return(1);
X }
X
X /* if remove unsuccessful, return an error */
X if ( rm_file(dst,1,0) == -1 ) {
X freebuf(inputbuf);
X return(0);
X }
X
X } else {
X
X /* if remove unsuccessful, return an error */
X if ( rm_file(dst,fflag,0) == -1 ) {
X freebuf(inputbuf);
X return(0);
X }
X
X }
X }
X }
X
X result = (onsame && mvflag) ? move(src,dst) : cp(src,srcfib,dst);
X
X freebuf(inputbuf);
X
X return(result);
X}
X
X/* copy a source file to a destination file */
Xint cp(src,srcfib,dst)
Xchar *src, *dst;
Xstruct FileInfoBlock *srcfib;
X{
X register int num;
X register long size;
X register char *buf;
X struct FileHandle *srchandle, *dsthandle;
X
X# ifdef DEBUG
X printf("copy file %s to %s\n",src,dst);
X# endif
X
X size = mem() - 4;
X
X if ( size < 128 ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": Out of memory!\n");
X }
X return(-1);
X }
X
X /*
X * allocate a maximum of "size" continous bytes, else source file
X * size worth of bytes. This allows one read and one write if there
X * is enough memory for it. The 8 is added in case there is a
X * zero size file we want to copy and we still want to allocate
X * a buffer anyways.
X */
X size = ( srcfib->fib_Size + 8 > size ) ? size : srcfib->fib_Size + 8;
X
X# ifdef DEBUG
X printf("Allocating %d bytes for the copy\n",size);
X# endif
X
X if ( !(buf = AllocMem(size,MEMF_CLEAR|MEMF_PUBLIC)) ) {
X /* didn't work, try again with a smaller size */
X size = size / 4;
X
X if ( !(buf = AllocMem(size,MEMF_CLEAR|MEMF_PUBLIC)) ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": Out of memory!\n");
X }
X return(-1);
X }
X }
X
X /* if we can't open the file, return an error */
X if ( !(dsthandle = Open(dst,MODE_NEWFILE)) ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": cannot Open file ");
X emit(ofile,dst);
X emit(ofile,"\n");
X }
X FreeMem(buf,size);
X
X /* returning 0 indicates an error to the above routines */
X return(0);
X }
X
X if ( !(srchandle = Open(src,MODE_OLDFILE)) ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": cannot Open file ");
X emit(ofile,src);
X emit(ofile,"\n");
X }
X Close(dsthandle);
X FreeMem(buf,size);
X return(0);
X }
X
X /* copy bytes back and forth. Read returns -1 for a read error */
X while ( (num = Read(srchandle,buf,size)) > 0 ) {
X if ( Write(dsthandle,buf,num) == -1 ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": error writing to file ");
X emit(ofile,dst);
X emit(ofile,". Disk may be full.\n");
X }
X Close(srchandle);
X Close(dsthandle);
X FreeMem(buf,size);
X return(-1);
X }
X }
X
X Close(srchandle);
X Close(dsthandle);
X
X if ( num == -1 ) {
X if ( !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": error reading from file ");
X emit(ofile,src);
X emit(ofile,"\n");
X }
X FreeMem(buf,size);
X return(0);
X }
X
X if ( nflag ) {
X /*
X * copy the protection bits, the comment and the datestamp to the
X * new file if the n flag is set (ie. -n was NOT specified in the
X * commandline)
X */
X SetProtection(dst,srcfib->fib_Protection);
X
X SetComment(dst,srcfib->fib_Comment);
X
X setdate(&srcfib->fib_Date,dst);
X
X FreeMem(buf,size);
X }
X
X /* return 2 for successful copy (not 1, because 1 is a move) */
X return(2);
X}
X
X/* rename a source file to a destination file */
Xint move(src,dst)
Xchar *src, *dst;
X{
X register int foo;
X
X# ifdef DEBUG
X printf("move file %s to %s\n",src,dst);
X# endif
X
X /* return 1 for successful move */
X foo = Rename(src,dst) ? 1 : 0;
X
X if ( !foo && !fflag ) {
X emit(ofile,commandname);
X emit(ofile,": could not move file ");
X emit(ofile,src);
X emit(ofile," to ");
X emit(ofile,dst);
X emit(ofile,"\n");
X }
X
X return(foo);
X}
X
Xint setdate(date,name)
Xstruct DateStamp *date;
Xchar *name;
X{
X register UBYTE *ptr;
X struct MsgPort *task;
X register struct FileLock *lock, *parent;
X register struct FileInfoBlock *fib;
X int stat, result, dos_packet();
X
X if ( !(task = DeviceProc(name)) ) {
X return(0);
X }
X
X if ( !(lock = Lock(name,ACCESS_READ)) ) {
X return(0);
X }
X
X fib = newfib();
X
X /*
X * thanks to Matt Dillon for this routine. I really don't know how
X * it does what it does, but it works, so no comments here.
X */
X
X /*
X * Well, I mean other than these comments...
X */
X
X /*
X * Oh, forget it.
X */
X if ( fib ) {
X if ( Examine(lock,fib) ) {
X
X parent = ParentDir(lock);
X
X UnLock(lock);
X
X ptr = (UBYTE *) AllocMem(256L,MEMF_CLEAR|MEMF_PUBLIC);
X
X strcpy((ptr + 1),fib->fib_FileName);
X
X *ptr = (UBYTE) strlen(fib->fib_FileName);
X
X result = dos_packet(task,34L,NULL,parent,(ULONG)&ptr[0] >> 2L,date);
X
X FreeMem(ptr,256L);
X
X UnLock(parent);
X }
X
X freefib(fib);
X
X } else {
X UnLock(lock);
X }
X}
X
X/* is a file delete protected? */
Xint isdeletable(file)
Xchar *file;
X{
X register struct FileLock *lock;
X register struct FileInfoBlock *fib;
X register int result = 0;
X
X if ( !(lock = Lock(file,ACCESS_READ)) ) {
X return(0);
X }
X
X /* allocate a word aligned memory block to hold our info */
X fib = newfib();
X
X if ( fib ) {
X if ( Examine(lock,fib) ) {
X
X result = fib->fib_Protection;
X freefib(fib);
X
X } else {
X
X freefib(fib);
X return(2);
X }
X
X }
X
X
X UnLock(lock);
X
X return( !(result & FIBF_DELETE) );
X}
X
X
SHAR_EOF
echo "extracting mv.uu"
sed 's/^X//' << \SHAR_EOF > mv.uu
X
Xbegin 644 mv
XM```#\P`````````#``````````(```U@````,0````$```/I```-8$[Z+I).)
XM5?_\(&R`;B`L@&Z0J``$4(`I0(!R(&R`<B"\34%.6$*G3KHTPEA/*T#__"\M)
XM``PO+0`(+RW__$ZZ+M!/[P`,*7P````!@'8O+(!Z+RR`?DZZ"-Q03R\`3KHQ4
XMJEA/3EU.=4Y5``!(YP@P)&T`""9M``PO"DZZ+/Y83]"**`!3A"!*4XBQQ&<:G
XM($00$$B`2,`O`"\+3KHM(%!/2H!F!%.$8-X@2E.(L<1G!"`$8`)P`$S?#!!.J
XM74YU3E4``$CG"#`D;0`()FT`#'@`2C)(`&<R2C-(`&<L$#)(`$B`2,`O`$ZZ@
XM++Q83R\`$#-(`$B`2,`O`$ZZ+*I83R(?LH!F!%*$8,@0,D@`2(!(P"\`3KHLE
XMD%A/+P`0,T@`2(!(P"\`3KHL?EA/(A^R@&P$</]@+A`R2`!(@$C`+P!.NBQD*
XM6$\O`!`S2`!(@$C`+P!.NBQ26$\B'[*`;P1P`6`"<`!,WPP03EU.=4Y5``!(6
XMYP`P)&T`"$AZ`"`O"DZZ_NI03R9`(`MG!B`+4H!@`B`*3-\,`$Y=3G4Z+P``O
XM3E4``"\M``Q.NBO46$\O`"\M``PO+0`(3KHR]D_O``Q.74YU3E7_^$ZZ,S9(O
XM>``"3KHR\%A/*T#__$AX``1.NC+B6$\K0/_X3KHS6B`M__RPK?_X;P8@+?_\(
XM8`0@+?_X3EU.=4Y5__Q(>0`!``!(>`$$3KHRRE!/*T#__$JM__QF*$JL@!)FR
XM'$AL@"(O+(!:3KK_;E!/2'H`&"\L@%I.NO]@4$]P`$Y=3G4@+?_\8/8Z($]UJ
XM="!O9B!M96UO<GDA"@!.50``2JT`"&<.2'@!!"\M``A.NC*64$].74YU3E4`-
XM`"\*2'D``0`!2'@!`$ZZ,DY03R1`(`IF*DJL@!)F'$AL@"(O+(!:3KK^]E!/R
XM2'H`&"\L@%I.NO[H4$]P`"1?3EU.=2`*8/8Z($]U="!O9B!M96UO<GDA"@!.V
XM50``2JT`"&<.2'@!`"\M``A.NC(>4$].74YU3E7__$AY``$``4AX`01.NC'8*
XM4$\K0/_\2JW__&<.(&W__$(0(&W__$*H`0`@+?_\3EU.=4Y5``!*K0`(9QH@R
XM;0`(+R@!`&'L6$](>`$$+RT`"$ZZ,<)03TY=3G5.50``2JT`"&<@(&T`"$JHB
XM`0!G$"!M``@O*`$`8>)83TY=3G4@+0`(8/9P`&#R3E4``"!M``A*J`$`9Q(@N
XM;0`(+R@!`&'H6$]2@$Y=3G5P`6#X3E4``"\$>``@;0`(2C!(`&<H(&T`"`PP+
XM`"I(`&<<(&T`"`PP`#](`&<0(&T`"`PP`"-(`&<$4H1@SB!M``@0,$@`2(!(<
XMP"@?3EU.=4Y5__!*K(!"9P``_B\M``AAHEA/2H!G``#P(&T`#$*02'D``0`!!
XM2'@"&DZZ,,)03RM`__`@;?_P(7P```$``!`O+?_P+RT`"$ZZ)LQ03TJ`9Q`OQ
XM+?_P3KHFV%A/<`!.74YU3KK^HBM`__QG%"!M__!(:`$8+RW__$ZZ+(!03V`87
XM(&T`#""\`````2\M__!.NB:@6$]P`&#&*VW__/_X+RW_\$ZZ)H!83RM`__1FZ
XM3DZZ_E8@;?_X(4`!`&8B(&T`#""\`````2\M__!.NB9D6$\O+?_\3KK^9%A/Z
XM<`!@@"!M__@K:`$`__@@;?_P2&@!&"\M__A.NBP$4$]@HB\M__!.NB8N6$]@^
XM-$ZZ_?PK0/_\2JW__&<6(&T`#$*0+RT`""\M__Q.NBO44$]@$"!M``P@O```[
XM``%P`&``_R0@+?_\8`#_'$Y5``!*K(!29PHO+(!23KHO7%A/2'C__TZZ+,!8$
XM3TY=3G5.5?_\+PI(>0`!```O+0`(3KHH%EA/4H`O`$ZZ+VQ03RM`__PO+0`(T
XM+RW__$ZZ*V903R\M__Q.NOO@6$\D0$(2("W__"1?3EU.=4Y5_ZA(>/_^+RT`$
XM"$ZZ+H)03^6`*T#_J$JM_ZAF!G#_3EU.=2!M_Z@@*``0Y8`@0"`H`"CE@"M`.
XM_ZP@;?^L$!!(@$C`4H`O`"!M_ZQ2B"\(2&W_V$ZZ*QY/[P`,(&W_K!`02(!(L
XMP$'M_]I",`@`("W_J.2`+P!.NBZ(6$\O+0`,3KK_-%A/*T#_K$AX__XO+?^L1
XM3KHM_%!/Y8`K0/^H+RT`#$ZZ)SI83U*`+P`O+?^L3KHNNE!/2JW_J&8&</]@O
XM`/]@(&W_J"`H`!#E@"!`("@`*.6`*T#_K"!M_ZP0$$B`2,!2@"\`(&W_K%*(6
XM+PA(;?^P3KHJ@$_O``P@;?^L$!!(@$C`0>W_LD(P"``@+?^HY(`O`$ZZ+>I86
XM3TAM_[!(;?_83KKY_E!/2H!F!'`!8`)P`$C`8`#^ZDY5__PO!$ZZ^R0@;0`,U
XM((!(>/_^+RT`"$ZZ+3Y03RM`__QF"'`"*!].74YU(&T`#$J09RX@;0`,+Q`O=
XM+?_\3KHL[%!/2H!G%B!M``PB4$JI``1O!'`!8`)P`"@`8`)X`V`P2JR`$F8<%
XM2&R`(B\L@%I.NOI64$](>@`H+RR`6DZZ^DA03R\M__Q.NBT^6$]P_V"4+RW_Y
XM_$ZZ+3!83R`$8(8Z($]U="!O9B!M96UO<GDA"@!.50``2JR`8F<*+RR`8DZZN
XM+3183TJL@&9G"B\L@&9.NBTD6$]*K(!J9PHO+(!J3KHM%%A/3EU.=4Y5``!*W
XMK(`29E1(>@!D+RR`6DZZ^<I03TAZ`'PO+(!:3KKYO%!/2'H`GB\L@%I.NOFN0
XM4$](>@"V+RR`6DZZ^:!03TAZ`-@O+(!:3KKYDE!/2'H`]2\L@%I.NOF$4$].K
XMNO]H2'@``4ZZ*>183TY=3G55<V%G93H@;78@6RUC9FEX72`@("!;+5T@9FELM
XM93$@9FEL93(*`"`@("`@("!M=B!;+6-F:7A=("`@(%LM72!P871H,2!;<&%TG
XM:#(@+BXN72!D:7(*`"`@("`@("!C<"!;+69I;6YX72`@(%LM72!F:6QE,2!F@
XM:6QE,@H`("`@("`@(&-P(%LM9FEM;GAR4ET@6RU=('!A=&@Q(%MP871H,B`N_
XM+BY=(&1I<@H`("`@("`@(')M(%LM8V1F:6UR4ET@6RU=('!A=&@@(%MP871H'
XM("XN+ET*``I7:&5R92!P871H(&ES(&5I=&AE<B!A(&9I;&4@;W(@82!D:7)E'
XM8W1O<GDN"@``3E7_V$CG#`!"K?_\0JW_^$*M__1"K?_P0JW_[$AX`^Y(>@?VX
XM3KHJY%!/*4"`6DZZ*KPI0(!>0J=(>@?@3KHKNE!/*4"`8DJL@&)G9D*G2'H'M
XMUDZZ*Z103RE`@&9F'$AZ!]@O+(!:3KKX`%!/3KK]Y$AX__].NBA@6$]"ITAZ;
XM!]Q.NBMV4$\I0(!J9AQ(>@?=+RR`6DZZ]])03TZZ_;9(>/__3KHH,EA/*7P`R
XM```!@$)@!$*L@$)(>@?4(&T`#"\03KKW=%A/+P!.NO;`4$]*@&8*4JR``E*LJ
XM@`Y@)DAZ![$@;0`,+Q!.NO=.6$\O`$ZZ]II03TJ`9@92K(`*8`12K(`&>`$@_
XM!.6`(&T`#")P"``,$0`M9@`!9GH!(`3E@"!M``PB,`@`($5*,!@`9@92A&``#
XM`4H@!.6`(&T`#"(P"``@14HP&`!G``$N(`3E@"!M``PB,`@`($40,!@`2(!(=
XMP&```-`I?`````&`!D*L@`I"K(`"0JR`#F```/8I?`````&`'F```.HI?```)
XM``&`$D*L@!9@``#:0JR`$BE\`````8`68```RBE\`````8`"*7P````!@`Y"5
XMK(`*0JR`!F```*Y"K(`:8```IBE\`````8`.8```FBE\`````8`*0JR`!D*L&
XM@`)"K(`.8```@DAZ!J`O+(!:3KKV;E!/2'@``2`$Y8`@;0`,(G`(`-/%+PDO$
XM+(!:3KHI8$_O``Q(>@:"+RR`6DZZ]D!03TZZ_%Q@/I"\````4F>2D+P````1O
XM9P#_(E.`9P#_-%6`9P#_.E>`9P#_1%F`9P#_3E.`9P#_9%F`9P#_9EV`9P#_]
XM;&"`4H5@`/[`4H1@`/Z*("T`")"$+P!*K(`*9P1P`6`"<`(B'[*`;`1.NOOR?
XM2JR``F<02'H&`DAL@").NB4(4$]@)$JL@`IG$$AZ!>](;(`B3KHD\E!/8`Y(=
XM>@7B2&R`(DZZ).)03TAM_^`@!%*$Y8`@;0`,+S`(`$ZZ]]!03RM`__1*K?_@Y
XM9S!*K(`29AQ(;(`B+RR`6DZZ]6)03TAZ!:$O+(!:3KKU5%!/3KK[.$AX__].^
XMNB6T6$\O+?_T3KKV[EA/*T#_\&```)A*K?_P9R!(;?_@(`3E@"!M``PO,`@`X
XM3KKW:%!/(&W_\"%``0!@($AM_^`@!.6`(&T`#"\P"`!.NO=(4$\K0/_P*VW_8
XM\/_T2JW_X&<Z2JR`$F8<2&R`(B\L@%I.NO344$](>@4E+RR`6DZZ],903TZZH
XM^JHO+?_T3KKV0EA/2'C__TZZ)1Q83R\M__!.NO966$\K0/_P4H2XK0`(;0#_7
XM9"\M__1.NO8^6$\K0/_L+RW_]$ZZ]EY83RM`_^A*K(`*9@`#5$AM__@O+?_L`
XM3KKYG%!/8``#,`RM`````O_H9@``PDAM__PO+?_T3KKY?E!/2H!G1DJL@!)F;
XM'$AL@"(O+(!:3KKT+E!/2'H$D2\L@%I.NO0@4$\O+?_\3KKTV%A/+RW_^$ZZD
XM],Y83R\M__1.NO6,6$].NOH>8&8O+?_X+RW_["\M__PO+?_T3KH48$_O`!`K#
XM0/_D#*T````"_^1F&DJL@`)G%"\L@!8O+(`2+RW_]$ZZ"4!/[P`,+RW__$ZZ;
XM]'183R\M__A.NO1J6$\O+?_T3KKU*%A/0J=.NB0$6$]@.DJL@!)F'$AL@"(OS
XM+(!:3KKS@%!/2'H$"B\L@%I.NO-R4$\O+?_X3KKT*EA/+RW_]$ZZ].A83TZZS
XM^7I@``(X+RW_^$ZZ]`Y83V```BH,K0````+_Z&9Z2&W__"\M__1.NOAH4$]*O
XM@&9H0J<O+?_L+RW__"\M__1.NA.23^\`$"M`_^0,K0````+_Y&8:2JR``F<4^
XM+RR`%B\L@!(O+?_T3KH(<D_O``PO+?_X3KKSIEA/+RW__$ZZ\YQ83R\M__1.&
XMNO1:6$]"ITZZ(S983V```2P,K0````+_Z&\``2!.NO.0*T#_V"\M__Q.NO-HF
XM6$\O+?_X3KKS7EA/2JW_V&84+RW_]$ZZ]!983TAX__].NB+P6$]*K(`69UP@X
XM;?_80A!(;(`B+RR`6DZZ\FA03TAZ`QDO+(!:3KKR6E!/+RW_["\L@%I.NO),J
XM4$](>`$`+RW_V"\L@%Y.NB3Z3^\`#"!M_]@,$`!Y9PX@;?_8#!``66<$8``!/
XM`B\M_^Q.NB1"6$\K0/_<9F)*K(`29CA(;(`B+RR`6DZZ\?Q03TAZ`L$O+(!:K
XM3KKQ[E!/+RW_["\L@%I.NO'@4$](>@+#+RR`6DZZ\=)03TZZ][8O+?_T3KKS?
XM3EA/+RW_V$ZZ\O183TAX__].NB(>6$]@"B\M_]Q.NB2D6$\O+?_83KKRU%A/J
XM8'A*K(`29CA(;(`B+RR`6DZZ\8103TAZ`FDO+(!:3KKQ=E!/+RW_["\L@%I.?
XMNO%H4$](>@)G+RR`6DZZ\5I03R\M__1.NO+:6$\O+?_X3KKR"%A/2'@``TZZ5
XM(:I83V`:_,+]S/W:_XJPO`````1D"N.`,#L`[$[[```K;?_T__!@``">3KHA5
XM3B!M__"Q[?_L9VI*K(`"9@9*K(`&9UXO+?_L+RW_\$ZZ"%)03RM`_^0@+?_D:
XM8#9.NO;(+RW_]$ZZ\F!83TAX__].NB$Z6$]*K(`&9A0O+(`6+RR`$B\M__!.A
XMN@8V3^\`#&`08`Z0O/____]GPE>`9]9@\&`:2JR`"F<4+RR`%B\L@!(O+?_P1
XM3KH&"$_O``P@;?_P*V@!`/_P2JW_\&8`_UY.NO96+RW_]$ZZ\>Y83T*G3KH@*
XMREA/3-\`,$Y=3G4J`&%R<"YL:6)R87)Y`&EN='5I=&EO;BYL:6)R87)Y`$-O"
XM=6QD(&YO="!O<&5N(&EN='5I=&EO;BYL:6)R87)Y"@!G<F%P:&EC<RYL:6)R@
XM87)Y`$-O=6QD(&YO="!O<&5N(&=R87!H:6-S+FQI8G)A<GD*`&UV`')M`&EN]
XM=F%L:60@;W!T:6]N(``*`&UV`')M`&-P`#H@3W5T(&]F(&UE;6]R>2$*`#H@-
XM3W5T(&]F(&UE;6]R>2$*`#H@8V%N;F]T(&UO=F4@82!D:7)E8W1O<GD@;VYTL
XM;R!A(&9I;&4*`#H@8V%N;F]T(&UO=F4@82!D:7)E8W1O<GD@;VYT;R!A(&9IT
XM;&4*`#H@8W)E871E(&1I<F5C=&]R>2``.B!U;F%B;&4@=&\@8W)E871E(&1I3
XM<F5C=&]R>2``"@`Z(&-O=6QD(&YO="!E>&%M:6YE(&9I;&4@``H``$Y5__PO2
XM!$ZZ[\XK0/_\2JW__&8(</\H'TY=3G4O+0`(3KH6/%A/8``"3$JM``QF.$AL;
XM@"(O+(!:3KKNOE!/2'H"5B\L@%I.NNZP4$\O+0`(+RR`6DZZ[J)03TAZ`E$O2
XM+(!:3KKNE%!/>/]@``(:2JT`$&=L(&W__$(02&R`(B\L@%I.NNYT4$](>@(E3
XM+RR`6DZZ[F903R\M``@O+(!:3KKN6%!/2'H"$R\L@%I.NNY*4$](>`$`+RW_]
XM_"\L@%Y.NB#X3^\`#"!M__P,$`!Y9Q`@;?_\#!``66<&>/]@``&H0J<O+0`(J
XM3KHA`E!/+RT`"$ZZ($Y83TJ`9D)*K0`,9CA(;(`B+RR`6DZZ[>Y03TAZ`:PO)
XM+(!:3KKMX%!/+RT`""\L@%I.NNW24$](>@&D+RR`6DZZ[<103WC_8`)X`6``?
XM`49*K0`,9@``S"!M__Q"$$AL@"(O+(!:3KKMGE!/2'H!<B\L@%I.NNV04$\O0
XM+0`(+RR`6DZZ[8)03TAZ`7PO+(!:3KKM=%!/2'@!`"\M__PO+(!>3KH@(D_O5
XM``P@;?_\#!``>6<*(&W__`P0`%EF8$*G+RT`"$ZZ(#)03R\M``A.NA]^6$]*=
XM@&9"2JT`#&8X2&R`(B\L@%I.NNT>4$](>@$;+RR`6DZZ[1!03R\M``@O+(!:6
XM3KKM`E!/2'H!$R\L@%I.NNST4$]X_V`">`%@`GC_8%Y"IR\M``A.NA_.4$\OA
XM+0`(3KH?&EA/2H!F0DJM``QF.$AL@"(O+(!:3KKLNE!/2'H`S2\L@%I.NNRLL
XM4$\O+0`(+RR`6DZZ[)Y03TAZ`,4O+(!:3KKLD%!/>/]@`G@!8!)*@&<`_LI38
XM@&<`_?!3@&<`_:8O+?_\3KKMIEA/(`1@`/V".B!C;W5L9"!N;W0@9FEN9"!FV
XM:6QE(``*`#H@<F5M;W9E(``_(``Z(&-O=6QD(&YO="!R96UO=F4@``H`.B!O.
XM=F5R:61E(&1E;&5T92!P<F]T96-T:6]N(&9O<B!F:6QE(``_(``Z(&-O=6QD0
XM(&YO="!R96UO=F4@``H`.B!C;W5L9"!N;W0@<F5M;W9E(``*``!.50``2.<.C
XM,'P!3KKLHBH`2'D``0``2'@!!$ZZ'O)03R@`2'C__B\M``A.NAXT4$\D0$J`;
XM9P``H"\*3KH=S%A/)D`O!"\*3KH=[%!/2H!G="!%0A!*AF=4+P0O"DZZ'>A0*
XM3TJ`9T8@1$JH``1O%B\M`!`O+0`,($10B"\(88)/[P`,+``@14H09Q(O+0`0I
XM+RT`#"\%3KK\0D_O``P@1%"(+P@O!4ZZ%OA03V"H($5*$&<2+RT`$"\M``PO+
XM!4ZZ_!I/[P`,+PM.NAU`6$\O`$ZZ'@!83V!`2JT`#&8X2&R`(B\L@%I.NNKJ7
XM4$](>@!(+RR`6DZZZMQ03R\M``@O+(!:3KKJSE!/2'H`1R\L@%I.NNK`4$]\.
XM_TAX`00O!$ZZ'AY03R\%3KKKY%A/(`9,WPQP3EU.=3H@8V]U;&0@;F]T(&=E5
XM="!A(&QO8VL@;VX@``H``$Y5__A(;?_X+RT`"$ZZ[ZA03V```4HO+0`0+RT``
XM#"\M``A.NOMB3^\`#"M`__Q@``%`2JR`#F<T+RT`$"\M``PO+0`(3KK^:$_OI
XM``PK0/_\2JW__&<4+RT`$"\M``PO+0`(3KK[(D_O``Q@9DJL@!YG&B\M`!`O\
XM+0`,+RT`"$ZZ^P9/[P`,*T#__&!&2JT`#&8X2&R`(B\L@%I.NNGB4$](>@#F"
XM+RR`6DZZZ=103R\M``@O+(!:3KKIQE!/2'H`S2\L@%I.NNFX4$\K?/______V
XM_&```)Q*K0`,9CA(;(`B+RR`6DZZZ9A03TAZ`+XO+(!:3KKIBE!/+RT`""\L:
XM@%I.NNE\4$](>@"[+RR`6DZZZ6Y03V!:2JT`#&8X2&R`(B\L@%I.NNE84$](L
XM>@"9+RR`6DZZZ4I03R\M``@O+(!:3KKI/%!/2'H`ER\L@%I.NNDN4$]@&OZHS
XM_L3_:/^HL+P````$9`KC@#`[`.Q.^P``2JW_^&<*+RW_^$ZZZ<183R`M__Q.5
XM74YU.B``(&ES(&$@9&ER96-T;W)Y("AN;W0@<F5M;W9E9"D*`#H@8V]U;&0@;
XM;F]T(&%C8V5S<R!F:6QE(``*`#H@8V]U;&0@;F]T(&5X86UI;F4@9FEL92``6
XM"@``3E7__"\$>`!(;?_\+RT`"$ZZ[<)03V```,(O+0`,+RW__"\M``A.N@34B
XM3^\`#"@`8```NB\M``PO+?_\+RT`"$ZZ`/1/[P`,*`!@``"@2JR`$F8X2&R`W
XM(B\L@%I.NN@^4$](>@":+RR`6DZZZ#!03R\M``@O+(!:3KKH(E!/2'H`ER\LR
XM@%I.NN@44$]X`&!<2JR`$F8X2&R`(B\L@%I.NN?\4$](>@!S+RR`6DZZY^Y0#
XM3R\M``@O+(!:3KKGX%!/2'H`<2\L@%I.NN?24$]X`&`:_S#_2O]D_Z:PO```\
XM``1D"N.`,#L`[$[[```O+?_\3KKH;%A/(`0H'TY=3G4Z(&-O=6QD(&YO="!A+
XM8V-E<W,@9FEL92``"@`Z(&-O=6QD(&YO="!E>&%M:6YE(&9I;&4@``H``$Y5Q
XM_]I(YP\P>`$O+0`0+RT`"$ZZZU)03RP`L+S_____9@IP`$S?#/!.74YU2&W_Q
XM_"\M`!!.NNQH4$\J`$J&9T)*K(`"9SRZO`````)F&D*G+RT`$"\M``PO+0`(Z
XM3KH'@D_O`!`H`&`6+RT`$"\M``PO+0`(3KH%?$_O``PH`&```MI*K(`"9A!*D
XMK(`&9P`"CDJL@`YG``*&3KKGJBM`_^Y.NN>B*T#_ZDZZYR`K0/_F2JW_YF<,@
XM2JW_[F<&2JW_ZF8&>/]@``(V(&W_ZD(0+RT`$"\M_^I.NA784$^ZO`````)G8
XM4B\M_^I.NA):6$\D0"`*9RP@;?_JT<H;:/____MG'@PM`#K_^V<6#"T`+__[P
XM9PY(>@)6+RW_ZDZZ%9103R\M``A.NN8.6$\O`"\M_^I.NA5^4$](>/_^+RW_Q
XMZDZZ&+903RM`__)F``#P2JR`%F<``((@;?_N0A!(;(`B+RR`6DZZY@)03TAZN
XM`@(O+(!:3KKE]%!/+RW_ZB\L@%I.NN7F4$](>@'Z+RR`6DZZY=A03TAX`0`OK
XM+?_N+RR`7DZZ&(9/[P`,(&W_[@P0`'EG)"!M_^X,$`!99QHO+?_F3KKF:%A/+
XM+RW__$ZZYEY83W``8`#^4B\M_^I.NA>X6$\K0/_R9D1*K(`29CA(;(`B+RR`*
XM6DZZY7)03TAZ`8DO+(!:3KKE9%!/+RW_ZB\L@%I.NN564$](>@&++RR`6DZZP
XMY4A03W``8`#]_B\M_^H@;0`,2&@`A$ZZ"[)03R\M__).NA@F6$](>/_^+RT`@
XM"$ZZ%ZA03RM`__8O+?_F+RW_]DZZ%VI03RX`+RW_YB\M__9.NA=L4$]*@&=Z=
XM2H1O=B!M_^Y"$"\M``@O+?_N3KH4)%!/+RW_[DZZ$*Y83R1`(`IG+"!M_^[1M
XMRAMH____^V<>#"T`.O_[9Q8,+0`O__MG#DAZ`.,O+?_N3KH3Z%!/(&W_YE"(E
XM+P@O+?_N3KH3UE!/+RW_ZB\M_^Y.NOOB4$\H`&``_W8O+?_V3KH7;EA/+RW__
XMYDZZY2983R\M_^Y.NN646$\O+?_J3KKEBEA/8#Y*K(`29CA(;(`B+RR`6DZZ+
XMY#I03TAZ`',O+(!:3KKD+%!/+RT`""\L@%I.NN0>4$](>@!:+RR`6DZZY!!0]
XM3R\M__Q.NN3(6$\@!&``_+PO`#H@8W)E871E(&1I<F5C=&]R>2``/R``.B!U]
XM;F%B;&4@=&\@8W)E871E(&1I<F5C=&]R>2``"@`O`#H@`"!I<R!A(&1I<F5CE
XM=&]R>2`H;F]T(&-O<&EE9"D*`$Y5__@O!'@`3KKD="M`__A*K?_X9@AP_R@?'
XM3EU.=4AM__PO+0`03KKHL%!/8``!;B\M__PO+0`0+RT`#"\M``A.N@/83^\`(
XM$"@`8``!8B\M`!`O+0`,+RT`"$ZZ`=!/[P`,*`!@``%(2JR`%F=L(&W_^$(0<
XM2&R`(B\L@%I.NN,B4$](>@%$+RR`6DZZXQ103R\M`!`O+(!:3KKC!E!/2'H!%
XM/"\L@%I.NN+X4$](>`$`+RW_^"\L@%Y.NA6F3^\`#"!M__@,$`!Y9Q`@;?_X@
XM#!``66<&>`!@``#6+RT`$$ZZ%.Q83RE`@%)*K(!29D)*K(`29CA(;(`B+RR`M
XM6DZZXJ)03TAZ`-LO+(!:3KKBE%!/+RT`$"\L@%I.NN*&4$](>@#I+RR`6DZZ,
XMXGA03W@`8"`O+(!23KH5:EA/+RT`$"\M``PO+0`(3KH`Y$_O``PH`&!<2JR`4
XM$F8X2&R`(B\L@%I.NN(^4$](>@"C+RR`6DZZXC!03R\M`!`O+(!:3KKB(E!/A
XM2'H`IB\L@%I.NN(44$]X`&`:_H3^HOZ\_Z:PO`````1D"N.`,#L`[$[[```O]
XM+?_\3KKBKEA/+RW_^$ZZXQQ83R`$8`#^4CH@8W)E871E(&1I<F5C=&]R>2``?
XM/R``.B!C;W5L9"!N;W0@8W)E871E(&1E<W1I;F%T:6]N(&1I<F5C=&]R>2``L
XM"@`Z(&-O=6QD(&YO="!E>&%M:6YE(&1I<F5C=&]R>2``"@!.5?_X2.<.`$ZZQ
XMXD@K0/_\>@`O+0`03KH-.EA/+`!*K?_\9@IP_TS?`'!.74YU(&W__$(0+RT`H
XM$"\M__Q.NA"`4$]*AF<F(&W__-'&&"C__V<:N#P`.F<4N#P`+V<.2'H!0"\MY
XM__Q.NA!64$\O+0`(3KK@T%A/+P`O+?_\3KH00%!/2&W_^"\M__Q.NN8@4$]@8
XM``#B+RW_^"\M__PO+0`,+RT`"$ZZ`4A/[P`0*@!@``#62JR`$F942&R`(B\L*
XM@%I.NN"R4$](>@#:+RR`6DZZX*103R\M``@O+(!:3KK@EE!/2'H`U2\L@%I.?
XMNN"(4$\O+?_\+RR`6DZZX'I03TAZ`,HO+(!:3KK@;%!/>@!@=D*G+RW__"\MN
XM``PO+0`(3KH`SD_O`!`J`&!<2JR`$F8X2&R`(B\L@%I.NN`Z4$](>@",+RR`5
XM6DZZX"Q03R\M__PO+(!:3KK@'E!/2'H`CR\L@%I.NN`04$]Z`&`:_Q#_+O^,6
XM_Z:PO`````1D"N.`,#L`[$[[```O+?_X3KK@JEA/+RW__$ZZX1A83R`%8`#^4
XMB"\`.B!C;W5L9"!N;W0@;6]V92!F:6QE(``@;VYT;R!D:7)E8W1O<GD@``H`/
XM.B!S;VUE=&AI;F<@:7,@87=R>2!W:71H(&9I;&4@``H``$Y5__Q(YPX`>`!Z:
XM`"\M`!`O+0`(3KKC<%!/+`"PO/____]F%"\M__Q.NN"66$]P`$S?`'!.74YU-
XM3KK@*BM`__QF!'#_8.I*K0`49P`!0$J&9V8@;0`,(FT`%"`0L)%F6$JL@`)FT
XM3DJL@!)F.$AL@"(O+(!:3KK?$%!/2'H!3B\L@%I.NM\"4$\O+0`(+RR`6DZZ$
XMWO103TAZ`4$O+(!:3KK>YE!/+RW__$ZZX!983W`!8`#_?F```-9*K(`69P``(
XMI"!M__Q"$$AL@"(O+(!:3KK>ME!/2'H!$"\L@%I.NMZH4$\O+0`0+RR`6DZZB
XMWII03TAZ`0$O+(!:3KK>C%!/2'@!`"\M__PO+(!>3KH1.D_O``P@;?_\#!``S
XM>6<:(&W__`P0`%EG$"\M__Q.NM^46$]P`6``_OQ"ITAX``$O+0`03KKO3$_O)
XM``RPO/____]F$"\M__Q.NM]J6$]P`&``_M)@*D*G+RR`$B\M`!!.NN\@3^\`Z
XM#+"\_____V80+RW__$ZZWSY83W``8`#^IDJ&9Q9*K(`"9Q`O+0`0+RT`"$ZZ5
XM`\103V`2+RT`$"\M``PO+0`(84)/[P`,*``O+?_\3KK?`%A/(`1@`/YH.B!CQ
XM86YN;W0@8V]P>2``('1O(&ET<V5L9B$*`#H@;W9E<G=R:71E(``_(`!.5?_X*
XM2.<,($ZZW:HJ`%F%NKP```"`;"Q*K(`29AQ(;(`B+RR`6DZZW6A03TAZ`J0O8
XM+(!:3KK=6E!/</],WP0P3EU.=2!M``P@*`!\4("PA6\$(`5@"B!M``P@*`!\A
XM4(`J`$AY``$``2\%3KH08E!/)$!*@&9$<@0@!4ZZ#*HJ`$AY``$``2\%3KH0T
XM1%!/)$!*@&8F2JR`$F8<2&R`(B\L@%I.NMSL4$](>@(Z+RR`6DZZW-Y03W#_D
XM8()(>`/N+RT`$$ZZ#VY03RM`__AF3DJL@!)F.$AL@"(O+(!:3KK<LE!/2'H"C
XM$B\L@%I.NMRD4$\O+0`0+RR`6DZZW)903TAZ`@HO+(!:3KK<B%!/+P4O"DZZK
XM#^I03W``8`#_(DAX`^TO+0`(3KH/#%!/*T#__&982JR`$F8X2&R`(B\L@%I."
XMNMQ04$](>@'&+RR`6DZZW$)03R\M``@O+(!:3KK<-%!/2'H!OB\L@%I.NMPF8
XM4$\O+?_X3KH..%A/+P4O"DZZ#WY03W``8`#^MB\%+PHO+?_\3KH.OD_O``PH6
XM`$J`;WXO!"\*+RW_^$ZZ#OA/[P`,L+S_____9F)*K(`29CA(;(`B+RR`6DZZW
XMV\I03TAZ`58O+(!:3KK;O%!/+RT`$"\L@%I.NMNN4$](>@%3+RR`6DZZVZ!0_
XM3R\M__Q.N@VR6$\O+?_X3KH-J%A/+P4O"DZZ#NY03W#_8`#^)F``_VXO+?_\R
XM3KH-BEA/+RW_^$ZZ#8!83[B\_____V9.2JR`$F8X2&R`(B\L@%I.NMM(4$](\
XM>@$"+RR`6DZZVSI03R\M``@O+(!:3KK;+%!/2'H!`2\L@%I.NML>4$\O!2\*[
XM3KH.@%!/<`!@`/VX2JR`&F=`(&T`#"\H`'0O+0`03KH-Z%!/(&T`#$AH`)`OE
XM+0`03KH-R%!/+RT`$"!M``Q(:`"$3KH!5%!/+P4O"DZZ#C103W`"8`#];#H@9
XM3W5T(&]F(&UE;6]R>2$*`#H@3W5T(&]F(&UE;6]R>2$*`#H@8V%N;F]T($]PX
XM96X@9FEL92``"@`Z(&-A;FYO="!/<&5N(&9I;&4@``H`.B!E<G)O<B!W<FET@
XM:6YG('1O(&9I;&4@`"X@1&ES:R!M87D@8F4@9G5L;"X*`#H@97)R;W(@<F5AO
XM9&EN9R!F<F]M(&9I;&4@``H``$Y5```O!"\M``PO+0`(3KH,Y%!/2H!G!'`!_
XM8`)P`"@`2H1F6DJL@!)F5$AL@"(O+(!:3KK9[E!/2'H`3"\L@%I.NMG@4$\O5
XM+0`(+RR`6DZZV=)03TAZ`$<O+(!:3KK9Q%!/+RT`#"\L@%I.NMFV4$](>@`P#
XM+RR`6DZZV:A03R`$*!].74YU.B!C;W5L9"!N;W0@;6]V92!F:6QE(``@=&\@R
XM``H`3E7_]$CG##`O+0`,3KH+R%A/*T#__&8*<`!,WPPP3EU.=4AX__XO+0`,U
XM3KH+XE!/)D!*@&8$<`!@X$ZZV:8J`$J%9P``E"\%+PM.N@N64$]*@&=Z+PM."
XMN@O:6$\H`"\+3KH,'%A/2'D``0`!2'@!`$ZZ#$I03R1`($50B"\(($I2B"\(3
XM3KH$QE!/($50B"\(3KH$REA/%(`O+0`((`KDB"\`+P1"ITAX`"(O+?_\3KH%!
XM"$_O`!@K0/_T2'@!`"\*3KH,*%!/+P1.N@NT6$\O!4ZZV6Y83V`(+PM.N@NBS
XM6$]@`/\X3E4``$CG"#!X`$AX__XO+0`(3KH+%E!/)$!*@&8*<`!,WPP03EU.W
XM=4ZZV-0F0"`+9R@O"R\*3KH*QE!/2H!G#B@K`'0O"TZZV1183V`,+PM.NMD*@
XM6$]P`F#&+PI.N@L\6$\(!```9@1P`6`"<`!(P&"N("\`!"QL@&).[OZJ(F\`_
XM!"QL@&).[OZD3.\!`0`$0^\`#"QL@&).[O\6(&\`!$/O``@L;(!B3N[_'"!O3
XM``0@+P`(+&R`8D[N_LXB;P`$+&R`8D[N_L@O"DSO!P$`""QL@&).KOZ\)%].S
XM=4SO`P$`!"QL@&).[O["(&\`!"QL@&).[O[X3.\!`0`$(B\`#"QL@&).[OZVU
XM(&\`!"QL@&).[O\*(&\`!"QL@&).KO[^9@I![(""(+P````!3G4B;P`$+&R`#
XM8D[N_Q`O"B1O``@L;(!B3J[^DB1?3G5,[P,```0L;(!B3N[^L"!O``1,[P`#$
XM``@L;(!B3N[^GB!O``1,[P`#``@L;(!B3N[^F"`O``0L;(!B3N[^7")O``0LC
XM;(!B3N[^\DSO`@(`!"QL@&).[O[L2.<`,"!O``P@+P`03.\.```4+&R`8DZN)
XM_P1,WPP`3G5,[P,```0@+P`,+&R`8D[N_N9,[P,```0L;(!B3N[^X$SO``,`(
XM!"QL@&).[OXX3.\#```$+&R`8D[N_E!,[P$!``0L;(!B3N[^2B!O``0L;(!B"
XM3N[^1"!O``0L;(!B3N[^/DSO`P``!"QL@&).[OWV3.\#```$("\`#"QL@&).3
XM[OWP("\`!"QL@&).[OWJ(&\`!$SO``,`"")O`!`L;(!B3N[^5B!O``0L;(!B<
XM3N[^VDSO`P``!"QL@&).[O[43.\#```$3.\``P`,+&R`8D[N_@(@;P`$("\`"
XM""QL@&).[OW\(F\`!"QL@&).[OX(+&R`8D[N_C),[P`%``0L;(!B3N[^ABQL$
XM@&).[OXL(F\`!"QL@&).[OXF3.\``P`$+&R`8DZN_GI![("&((E.=4SO``8`'
XM!"QL@&).KOYT8.@B+P`$+&R`8DZN_FY@VDSO``8`!"QL@&).KOYH8,HL;(!BJ
XM3J[^&F?`,V\`!O_^(`E@MB`O``0L;(!B3J[^@&"H(&\`!"`O``@L;(!B3J[^,
XM8F"6+&R`8D[N_HPB;P`$+&R`8D[N_B`B;P`$+&R`8D[N_A0B;P`$+&R`8D[NI
XM_@Y,[P,```1,[P`#``PL;(!B3N[]Y"\*3.\'```(+&R`8DZN_=XD7TYU(B\`:
XM!"QL@&).[OW83.\#```$+&R`8D[N_=(@;P`$+&R`8D[N_<P@;P`$+&R`8D[NQ
XM_<8@;P`$+&R`8D[N_<!,[P$"``0L;(!B3N[]NB!O``0L;(!B3N[]M"(O``0LS
XM;(!B3N[]KDSO``,`!"QL@&).[OVH3.\``P`$+&R`8D[N_:),[P`#``0L;(!BE
XM3N[]G"`O``0L;(!B3N[]EDSO`P``!"QL@&).[OV0(&\`!"QL@&).[OV*(B\`7
XM!"QL@&).[OV$(&\`!"`((F\`"!#99OQ.=2!O``0@"$H89OR1P"`(4X!.=7``;
XM$"\`![`\`&!C"K`\`'IB!)`\`"!.=7``$"\`![`\`$!C"K`\`%IB!-`\`"!.O
XM=2!O``0@+P`($AAG"K(`9O@@"%.`3G5P`$YU3E7__$CG`#!"IT*G3KK[RB9`]
XM2H!03V8*<`!,WPP`3EU.=4AY``$``4AX`$1.N@;6)$!*@%!/9@PO"TZZ^ZQPQ
XM`%A/8-8@2M'\````%"5(``HE2@`4)4L`&"5M``P`'"5M`!``*"5M`!0`+"5M2
XM`!@`,"5M`!P`-"5M`"``."5M`"0`/"5M`"@`0"\*+RT`"$ZZ!N(O"TZZ!P0O)
XM"TZZ!JHK:@`@__Q(>`!$+PI.N@:&+PM.NOLV("W__$_O`!Q@`/]<87!#[(!2F
XM1>R`4K7)9@XR/``<:PAT`"+"4<G__"E/@&XL>``$*4Z`BDCG@(`(+@`$`2EGH
XM$$OZ``A.KO_B8`9"I_-?3G-#^@`@3J[^:"E`@(YF#"X\``.`!TZN_Y1@!$ZZS
XMT1!03TYU9&]S+FQI8G)A<GD`2?D``'_^3G5.50``2.<,,"1M`!`@;0`(2J@`D
XMK&<8(&T`""`H`*SE@"@`($0@*``0Y8`F0&`$)FR`2!`32(!(P-"M``Q4@"E`_
XM@))"IR\L@)).N@6$*4"`EE!/9@A,WPPP3EU.=1`32(!(P"H`+P4@2U*(+P@O6
XM+("63KH!CB!L@);1Q4/Z`5@0V6;\+RT`#"\*+RR`EDZZ`4X@;("60C!8`"E\L
XM`````8!^(&R`EM'%)DA2BR1+3^\`&!`32(!(P"H`L+P````@9R"ZO`````EG=
XM&+J\````#&<0NKP````-9PBZO`````IF!%*+8,P,$P`@;0``C`P3`")F,E*+D
XM($M2BQ`02(!(P"H`9R`@2E**$(6ZO````")F$`P3`")F!%*+8`9"*O__8`)@L
XMTF!$($M2BQ`02(!(P"H`9S"ZO````"!G*+J\````"6<@NKP````,9QBZO```1
XM``UG$+J\````"F<(($I2BA"%8,(@2E**0A!*A68"4XM2K(!^8`#_/$(20J<@1
XM+(!^4H#E@"\`3KH$2"E`@'I03V8(0JR`?F``_KYZ`"9L@)9@'B`%Y8`@;(!Z,
XM(8L(`"!+(`A*&&;\D<!3B%*(U\A2A;JL@'YMW"`%Y8`@;(!Z0K`(`&``_H(@^
XM`#`\?_]@!#`O``X@;P`$2AAF_%-((F\`"%-`$-E7R/_\9P)"$"`O``1.=4SOH
XM`P``!"`((B\`#&`"$-E7R?_\9P9206`"0AA1R?_\3G5(YT@`0H1*@&H$1(!21
XM1$J!:@9$@0I$``%A/DI$9P)$@$S?`!)*@$YU2.=(`$*$2H!J!$2`4D1*@6H"]
XM1(%A&B`!8-@O`6$2(`$B'TJ`3G4O`6$&(A]*@$YU2.<P`$A!2D%F($A!-@$T]
XM`$)`2$"`PR(`2$`R`H+#,`%"04A!3-\`#$YU2$$F`2(`0D%(04A`0D!T#]"`B
XMTX&V@6($DH-20%'*__),WP`,3G5.5?_\2'@0`$*G3KH#?"M`__P(```,4$]G\
XM$DJL@'9F""`M__Q.74YU3KK3+'``8/1.50``2JR`FF<&(&R`FDZ0+RT`"$ZZ]
XM``A83TY=3G5.5?_\+P0K;0`(__Q*K("B9RQX`&`*+P1.N@#\6$]2A#`L@$9(T
XMP+B`;>PP+(!&P?P`!B\`+RR`HDZZ`JI03TJL@)YG!B!L@)Y.D$JL@$QG"B\L,
XM@$Q.N@(>6$]*K("F9P@@;("F(*R`JDJL@*YG"B\L@*Y.N@(R6$]*K("R9PHO7
XM+("R3KH"(EA/2JR`MF<*+RR`MDZZ`A)83TJL@+IG"B\L@+I.N@("6$\L>``$S
XM""X`!`$I9Q0O#4OZ``I.KO_B*E]@!D*G\U].<TJL@+YF*DJL@)9G(B\L@)(OG
XM+("63KH"!B`L@'Y2@.6`+P`O+(!Z3KH!]$_O`!!@#DZZ`=XO+("^3KH"+%A/M
XM("W__"YL@&Y.=2@?3EU.=4Y5``!(YPX@*"T`"'(&(`1.N@!$)$#5[("B2H1M/
XM#C`L@$9(P+B`;`1*DF82*7P````"@,)P_TS?!'!.74YU,"H`!,!\@`!F""\2B
XM3KH`,EA/0I)P`&#@2.=P`#0!Q,`F`4A#QL!(0T)#U(-(0,#!2$!"0-""3-\`L
XM#DYU3OH``B(O``0L;(".3N[_W"(O``0L;(".3N[_B$[Z``(B+P`$+&R`CD[NL
XM_X).^@`"(B\`!"QL@(Y.[O^X(B\`!"QL@(Y.[O]23OH``DSO``8`!"QL@(Y.$
XM[O^:3.\`!@`$+&R`CD[N_Y1.^@`"+&R`CD[N_\I.^@`"3.\`!@`$+&R`CD[NG
XM_ZQ.^@`"3.\`!@`$+&R`CD[N_^(B+P`$+&R`CD[N_RY.^@`"3.\`#@`$+&R`0
XMCD[N_]9.^@`"3.\`!@`$+&R`CD[N_[),[P`&``0L;(".3N[_3$SO``8`!"QL0
XM@(Y.[O]&3OH``B(O``0L;(".3N[_ID[Z``),[P`.``0L;(".3N[_T"(O``0L^
XM;("*3N[_*$[Z``(B;P`$+&R`BD[N_F).^@`"3.\``P`$+&R`BD[N_SI.^@`"C
XM(F\`!"QL@(I.[O[:3OH``BQL@(I.[O]\3OH``B)O``0@+P`(+&R`BD[N_RY.]
XM^@`"(&\`!"QL@(I.[OZ,3OH``BQL@(HB;P`$("\`"$[N_=@L;("*3N[_=DSON
XM`P``!"QL@(I.[OZ2(F\`!"QL@(I.[OZ&3.\``P`$+&R`BD[N_LY.^@`"(&\`Q
XM!"QL@(I.[OZ```````/L`````0````$``"\(`````````_(```/J````%```^
XM``````````````````````````````````$`````````````````````````!
XM`````````````````````````````!0````````````````#\@```^L````!X
X$```#\@``U
X``
Xend
Xsize 13864
SHAR_EOF
echo "extracting mvtest.sh"
sed 's/^X//' << \SHAR_EOF > mvtest.sh
X#
X# Regression test script for mv/cp/rm
X#
X# Copyright 1989 Edwin Hoogerbeets
X#
X# This code may be freely redistributed as long as no charges other than
X# reasonable copying fees are levied for it.
X#
X# This script is for the Dillon/Drew shell. To see what the utilities
X# are doing, compile with -DDEBUG and then source this script for a
X# verbose listing of what's happening.
X#
X
X# create the test environment
Xecho mkdir foo
Xmkdir foo
Xecho cp * foo
Xcp * foo
X
X#
X# test mv on same volume
X#
X
X# mv directory to a new name
X# expected result: foo will be renamed to bar
Xecho mv foo bar
Xmv foo bar
X
X# mv directory to existing directory
X# expected result: bar will be renamed foo/bar
Xecho mkdir foo
Xmkdir foo
Xecho mv bar foo
Xmv bar foo
X
X# mv file to directory
X# expected result: rm will be renamed to foo
Xecho mv rm foo
Xmv rm foo
X
X# mv multiple files to directory
X# expected result: foo/rm and cp will be renamed to foobar/rm and foobar/cp
Xecho mv foo/rm cp foobar
Xmv foo/rm cp foobar
X
X# test "" as current directory
X# expected results: everything in the foobar directory will be renamed
X# under the current directory
Xecho foobar/* \"\"
Xmv foobar/* \"\"
X
X# mv multiple directories to directory
X# expected result: foo and foobar will be renamed to barfoo/foo
X# and barfoo/foobar
Xecho mkdir barfoo
Xmkdir barfoo
Xecho mv foo foobar barfoo
Xmv foo foobar barfoo
X
X# mv file to file
X# expected result: rm will be renamed to arm and back to rm
Xecho mv rm arm
Xmv rm arm
Xecho mv arm rm
Xmv arm rm
X
Xecho mv barfoo/foo \"\"
Xmv barfoo/foo \"\"
X
X#
X# test mv across volumes
X#
X
Xecho mkdir ram:foo
Xmkdir ram:foo
X
X# mv directory to existing directory
X# expected result: foo will get recursively moved to ram:foo
Xecho mv foo ram:
Xmv foo ram:
X
X# mv directory to a non-existant directory
X# expected result: ram:foo will get recursively moved to rad:foo
Xecho mv ram:foo rad:foo
Xmv ram:foo rad:foo
X
X# mv file to existing directory
X# expected result: rm will get moved to ram:rm
Xecho mv rm ram:
Xmv rm ram:
X
X# mv file to non-existant name
X# expected result: ram:rm will be moved to arm and then to rm
Xecho mv ram:rm arm
Xmv ram:rm arm
Xecho mv arm rm
Xmv arm rm
X
X#
X# test cp
X#
X
X# create the test environment
Xecho mkdir foo
Xmkdir foo
Xecho cp * foo
Xcp * foo
Xecho cat "<nil: >bar"
Xcat <nil: >bar
X
X# copy a zero length file
Xecho cp bar booboo
Xcp bar booboo
Xecho rm bar booboo
Xrm bar booboo
X
X# copy directory to new directory
X# expected result: foo/* will be copied to be asdf/*
Xecho cp -r foo asdf
Xcp -r foo asdf
X
X# copy multiple directories to a directory
X# expected result: foo/* and asdf/* will be copied to fooasdf/foo/*
X# and to fooasdf/asdf/* respectively
Xecho cp -r foo asdf fooasdf
Xcp -r foo asdf fooasdf
X
X# copy directory to existing directory
X# expected result: barfoo/* will be copied to asdf/barfoo/*
Xecho cp -r barfoo asdf
Xcp -r barfoo asdf
X
X# copy files to directory
X# expected result: cp rm and mv will be copied to asdf/cp asdf/rm
X# and asdf/mv
Xecho cp rm cp mv asdf
Xcp rm cp mv asdf
X
X# test [lack of] -r option
X# expected result: complain about directories not being copied
Xecho cp * asdf
Xcp * asdf
X
X# cp across volumes (this test shouldn't matter)
X# expected result: * will be copied to ram:asdf/*
Xecho cp * ram:asdf
Xcp * ram:asdf
X
X#
X# test rm
X#
X
Xecho cd asdf
Xcd asdf
X
X# test [lack of] -r option
X# expected result: only files will be erased
Xecho rm *
Xrm *
X
X# test -r option
X# expected result: directories and all will be erased
Xecho rm -r *
Xrm -r *
X
Xecho cd /
Xcd /
X
X#
X# test -i option
X#
X
X# expected result: directory creation and clobbering files will be okayed
X# before proceding
Xecho mv -i rad:foo ram:foo
Xmv -i rad:foo ram:foo
X
X#
X# test delete protection and -f option
X#
X
X# set up
Xecho rm -r foo
Xrm -r foo
X
Xecho cp rm foo
Xcp rm foo
Xecho protect foo rwe
Xprotect foo rwe
X
X# test copying to a delete protected file
X# expected result: should ask for permission to overwrite foo
Xecho cp rm foo
Xcp rm foo
X
Xecho protect foo rwe
Xprotect foo rwe
X
X# test -f option on mv
X# expected result: rm will be renamed to foo despite delete protect
Xecho mv -f rm foo
Xmv -f rm foo
X
Xecho protect foo rwe
Xprotect foo rwe
X
X# test -f option on rm
X# expected result: foo will be deleted no problem
Xecho rm -f foo
Xrm -f foo
X
Xecho cp cp rm
Xcp cp rm
X
X#
X# test - option
X#
X
X# set up
Xecho mkdir -d
Xmkdir -d
X
X# expected result: -d will be recursively removed
Xecho rm -r - -d
Xrm -r - -d
X
X#
X# test bad input
X#
X
X# move non-existant files
X# expected result: complain about no access to non-existant files
Xecho mv FidgeMeJerk Kawanga BoongaBoonga Maximillian
Xmv FidgeMeJerk Kawanga BoongaBoonga Maximillian
X
X# remove non-existant file
X# expected result: complain about could not remove non-existant files
Xecho rm foobarandgrill
Xrm foobarandgrill
X
X# copy or move to the same file
X# expected result: mv works but cp should complain about not being
X# able to copy a file to itself
Xecho mv cp Cp
Xmv cp Cp
Xecho cp mv mv
Xcp mv mv
X
X# no args
X# expected result: usage info displayed
Xecho cp
Xcp
X
X# no files
X# expected result: usage info displayed
Xecho cp -r
Xcp -r
X
X# bad options
X# expected result: complain about bad option and usage
Xecho cp -q
Xcp -q
X
X# not enough args
X# expected result: usage info displayed
Xecho mv foo
Xmv foo
X
X# move directory onto a file
X# expected result: complain and give usage
Xecho mv asdf rm
Xmv asdf rm
X
X#
X# Test wildcarding (needs to compiled with -DARP and linked with -la32)
X#
X
X# expected result: everything will get copied to the new directory asdf
Xecho cp "*" asdf
Xcp "*" asdf
X
X# expected result: everything will get copied to the new directory asdf
Xecho cp "#?" asdf
Xcp "#?" asdf
X
X# expected result: two letter file names will get copied to directory asdf
Xecho cp "??" asdf
Xcp "??" asdf
X
X#
X# cleanup
X#
X
Xecho rm -fr asdf barfoo ram:asdf ram:foo foo fooasdf Maximillian rad:bar
Xrm -fr asdf barfoo ram:asdf ram:foo foo fooasdf Maximillian rad:bar
X
X
X
SHAR_EOF
echo "End of archive 1 (of 1)"
# if you want to concatenate archives, remove anything after this line
exit