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