[comp.sources.amiga] v89i125: mv/cp/rm - unix

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