#include "cmd.h"

#define Wild(spec)  ((spec)->flags & (CI_NAMEWILD))

extern jmp_buf CmdJBuf2 ;

extern TCHAR Fmt19[], Fmt17[], Fmt14[];
extern TCHAR CrLf[] ;
extern TCHAR CurDrvDir[] ;

extern TCHAR YesChar, NoChar ;

extern TCHAR *SaveDir ;

extern TCHAR PathChar, TmpBuf[], SwitChar;

extern unsigned DosErr ;
extern unsigned flgwd ;                 /* M021 */

extern int LastRetCode ;

extern BOOL CtrlCSeen;
extern PTCHAR    pszTitleCur;
extern BOOLEAN  fTitleChanged;

//
// Internal prototypes
//
struct cpyinfo *SetFsSetSaveDir() ;

/*
** This routine returns the longest pathlength possible from the input path
** It assumes that the input path is a buffer that it can extend by a
** wildcard '\*' to search the file, if it is a directory.
** The input path must be fully qualified, eg: "c:\winnt\system32\kernel32.dll"
**
** Input:
**      pPath   fully qualified Pathname
**      pCch    pointer to length of pathname
** Returns:
**      TRUE    succeeded, pCch contains length
**      FALSE   error occurred
*/
BOOL
GreatestLength(
    TCHAR       *pPath,
    int         *pCch
    )
{
    WIN32_FIND_DATA     fd;
    HANDLE              hFind;
    DWORD               err;
    int                 cch;
    int                 cchThis;
    DWORD               attr;
    TCHAR               *pLast;
    BOOL        MoreFiles;

                                        /* assume a file, or empty directory */
    *pCch = cch = _tcslen(pPath) - 2;   /* _tcslen(TEXT("C:")) */

    if ((attr=GetFileAttributes(pPath)) == 0xffffffff) {
        PutStdErr(GetLastError(), NOARGS);
        return FALSE;
    }
    if ( !(attr & FILE_ATTRIBUTE_DIRECTORY)) {   /* if just a file... */
        return TRUE;
    }

    /* path is a directory, search it ... */

    pLast = pPath + _tcslen(pPath);
    if (*(pLast-1) == BSLASH) {
        *pLast = STAR;
        *(pLast+1) = NULLC;
    }
    else {
        *pLast = BSLASH;
        *(pLast+1) = STAR;
        *(pLast+2) = NULLC;
    }

    if ((hFind=FindFirstFile(pPath, &fd)) == INVALID_HANDLE_VALUE) {
        //
        // Check that failure was not due to some system error such
        // as an abort on access to floppy
        //
        err = GetLastError();
        FindClose(hFind);
        if (err != ERROR_FILE_NOT_FOUND && err != ERROR_NO_MORE_FILES) {
            PutStdErr(err, NOARGS);
            return FALSE;
        }
        return TRUE;
    }

    MoreFiles = TRUE;
    do {
        if (!_tcscmp(fd.cFileName, TEXT(".")))
            continue;
        if (!_tcscmp(fd.cFileName, TEXT("..")))
            continue;

        if ((fd.dwFileAttributes | FILE_ATTRIBUTE_DIRECTORY) == 0) {
            TCHAR       path[MAX_PATH];

            _tcscpy(path, pPath);
            *(path+_tcslen(path)-1) = NULLC;    /* zap asterisk */
            _tcscat(path, fd.cFileName);
            if (!GreatestLength(path, &cchThis))
                break;

            *pCch = max(*pCch, cch + cchThis);
        }
        else {
            *pCch = max(*pCch, (int) _tcslen(fd.cFileName));
        }

    } while ( MoreFiles = FindNextFile(hFind, &fd) );

    err = GetLastError();
    FindClose(hFind);

    if ( MoreFiles ) {
        return FALSE;
    } else if ( err != ERROR_NO_MORE_FILES ) {
        PutStdErr(err, NOARGS);
        return FALSE;
    }

    return TRUE;
}

int eCopy(n)
struct cmdnode *n ;
{
        return(LastRetCode = copy(n->argptr)) ;
}


int eDelete(n)
struct cmdnode *n ;
{
        int DelWork() ;

        return(LastRetCode = DelWork(n->argptr));
}


void MoveErrExit()                    // exit without display
{

        if (SaveDir) {
           mystrcpy(CurDrvDir,SaveDir);
           SaveDir = NULL ;             /* Reset SaveDir                  */
        }

        longjmp(CmdJBuf2,1) ;
}

/********************* START OF SPECIFICATION **************************/
/*                                                                     */
/* SUBROUTINE NAME: eRename                                            */
/*                                                                     */
/* DESCRIPTIVE NAME:  Rename Internal Command                          */
/*                                                                     */
/* FUNCTION: Rename files and subdirectories.  Wildcards only applies  */
/*           to file names.                                            */
/*                                                                     */
/* NOTES:    @@5*                                                      */
/*                                                                     */
/* ENTRY POINT: eRename                                                */
/*    LINKAGE: NEAR                                                    */
/*                                                                     */
/* INPUT:                                                              */
/*            n - the parse tree node containing the rename command    */
/*                                                                     */
/* OUTPUT: None.                                                       */
/*                                                                     */
/* EXIT-NORMAL:                                                        */
/*         Return SUCCESS to the caller.                               */
/*                                                                     */
/* EXIT-ERROR:                                                         */
/*         Return FAILURE to the caller.                               */
/*                                                                     */
/* EFFECTS: None.                                                      */
/*                                                                     */
/* INTERNAL REFERENCES:                                                */
/*      ROUTINES:                                                      */
/*       RenWork     - Worker routine for rename.                      */
/*                                                                     */
/* EXTERNAL REFERENCES:                                                */
/*      ROUTINES:                                                      */
/*       None                                                          */
/*                                                                     */
/********************** END  OF SPECIFICATION **************************/

int eRename(n)
struct cmdnode *n ;
{
    int RenWork();                           /* @@ */

    return(LastRetCode = RenWork( n ));      /* @@ */
}


/********************* START OF SPECIFICATION **************************/
/*                                                                     */
/* SUBROUTINE NAME: RenWork                                            */
/*                                                                     */
/* DESCRIPTIVE NAME:  Rename Internal Command Worker                   */
/*                                                                     */
/* FUNCTION: Rename files and subdirectories.  Wildcards only applies  */
/*           to file names.                                            */
/*                                                                     */
/* NOTES:    @@5*                                                      */
/*                                                                     */
/* ENTRY POINT: RenWork                                                */
/*    LINKAGE: NEAR                                                    */
/*                                                                     */
/* INPUT:                                                              */
/*            n - The parse tree node containing the rename command    */
/*                                                                     */
/* OUTPUT: None.                                                       */
/*                                                                     */
/* EXIT-NORMAL:                                                        */
/*         Return SUCCESS to the caller.                               */
/*                                                                     */
/* EXIT-ERROR:                                                         */
/*         Return FAILURE to the caller.                               */
/*                                                                     */
/* EFFECTS: None.                                                      */
/*                                                                     */
/* INTERNAL REFERENCES:                                                */
/*      ROUTINES:                                                      */
/*       ffirst          - Find the first matching specified file.     */
/*       fnext           - Find the next matching specified file handle*/
/*       findclose - Close the file with the specified file handle,    */
/*                       hnFirst which is given by ffirst or fnext.                */
/*       TokStr          - Tokenize argument strings.                  */
/*       wildcard_rename - Obtain name based on wildcard specification.*/
/*       SetFsSetSaveDir - Save the current directory.                 */
/*       GetDir          - Get the specified directory.                */
/*       ChangeDir       - Change to the specified directory.          */
/*       RenError        - Process error condition for rename command. */
/*       PutStdErr - Displays an error message.                        */
/*       Wild      - check if the arg contains wild card.              */
/*                                                                     */
/* EXTERNAL REFERENCES:                                                */
/*      ROUTINES:                                                      */
/*       None                                                          */
/*        DOSMOVE      - Rename file and directory names.              */
/*        DOSCASEMAP   - Change lower case character to upper case.    */
/*        DOSFILEMODE  - Get attribute of specified file.              */
/*                                                                     */
/********************** END  OF SPECIFICATION **************************/

int RenWork(n)                                  /* @@ */
struct cmdnode *n ;
{
   TCHAR *arg1 ;                          /* Ptr to 1st arg          */
   TCHAR *arg2 ;                          /* Ptr to 2nd arg          */
   struct cpyinfo *a1info ;                       /* Holds arg1 fspec info   */
   struct cpyinfo *SetFsSetSaveDir();
   TCHAR bufsrc[MAX_PATH];                        /* path of source file     */
   TCHAR bufdst[MAX_PATH];                        /* path of destination file*/
   TCHAR tmpbuf1[MAX_PATH];                       /* path of source file     */
   int wlen;                              /* length of source path       */
   int rc;                                        /* return code             */
   HANDLE hnFirst ;                               /* Findfirst handle            */
   unsigned attr ;
   unsigned i;                                    /* Temp Return Code        */
   TCHAR *j ;                                     /* Temp Ptr to dir name    */
   unsigned wild_flag ;                           /* wildcard flag           */
   TCHAR pcstr[3] ;
   unsigned retval = SUCCESS;

   DEBUG((FCGRP, RELVL, "RENAME: arptr = `%ws'", n->argptr)) ;

   if (setjmp(CmdJBuf2))
      return(FAILURE) ;

    /* There should be only two arguments */
   if (!*(arg1 = TokStr(n->argptr, NULL, TS_NOFLAGS)) ||
        !*(arg2 = arg1 + mystrlen(arg1) + 1) ||
        *(arg2 + mystrlen(arg2) +1)) {             /* @@5g */

      RenError(MSG_BAD_SYNTAX);                   /* Err if arg missing   */
   }

   mystrcpy( arg1, stripit(arg1) );       /* 509 */
   mystrcpy( arg2, stripit(arg2) );       /* 509 */

   if ((a1info = SetFsSetSaveDir(arg1)) == (struct cpyinfo *)FAILURE)
   {
      RenError(DosErr);         /* @@5d */        /* Error if invalid dir */
   }

   mystrcpy(bufsrc,CurDrvDir);                    /*  save path of source */

   mystrcpy(bufdst,CurDrvDir);                    /*  save path of dest   */

   wlen = mystrlen(bufsrc);                       /*  get len of src path */

   if ( a1info->buf->dwFileAttributes != A_D )
      {
         mystrcpy(&bufsrc[wlen],a1info->fnptr);
      }
   else
      {
         bufsrc[--wlen] = NULLC ;
         bufdst[wlen] = NULLC ;
      }

                                                   /* if not wild since    */
   if (!Wild(a1info))                              /* DQFM == 3 if wild    */
      {                                            /*  then                */
         a1info->buf->dwFileAttributes =
            GetFileAttributes( stripit(bufsrc) );

         if (a1info->buf->dwFileAttributes == -1 )
            {
               RenError(GetLastError()) ;
            }
      }


   if (*(arg2+1) == COLON ||
        mystrchr(arg2,PathChar))
      {
         RenError(MSG_BAD_SYNTAX);                 /* bad arg2             */
      }

   /**********************************************/
   /*  M009 - Always specifiy drive, filename,   */
   /*         and extension.  Note, it is        */
   /*         assumed that SaveDir always starts */
   /*         with a drive letter                */
   /**********************************************/

   tmpbuf1[0] = CurDrvDir[0] ;      /* @@5h */
   tmpbuf1[1] = COLON ;


   /**********************************************/
   /* Set flag whether arg1 contains             */
   /* wildcard or not.                           */
   /**********************************************/

   pcstr[0] = STAR ;
   pcstr[1] = QMARK ;
   pcstr[2] = NULLC ;
   wild_flag = ((mystrcspn(arg1,pcstr)) < mystrlen(arg1)) ;

   /**********************************************/
   /* Issue ffirst for a file name               */
   /**********************************************/
   if ( !ffirst(bufsrc, attr = A_A, a1info->buf, &hnFirst ))
      {
         /*********************************************/
         /* Issue ffirst for a directory name         */
         /*********************************************/
         if (!ffirst(bufsrc, attr = A_D, a1info->buf, &hnFirst ))
            {
               RenError(DosErr);                    /* @@5d  M017                       */
            }
         else
            {
               if (wild_flag)
                  {
                     RenError(MSG_BAD_SYNTAX);               /* bad arg1 */
                  }
            }
      }

   bufsrc[wlen] = NULLC;                            /* make filename = NULL */

   rc = 0 ;                                         /* @@5 */

   do {

      if (CtrlCSeen) {
          findclose(hnFirst) ;
          if (SaveDir) {
              mystrcpy(CurDrvDir,SaveDir);
              SaveDir = NULL;
          }

          return(FAILURE);
      }

      /**********************************************/
      /* if the file attribute of bufsrc is         */
      /* directory then concatenate arg2 after the  */
      /* last "\" character of bufdst               */
      /**********************************************/

      if ( a1info->buf->dwFileAttributes & A_D )       /* @@5c*/
         {                                             /* @@5 */
            j = mystrrchr(bufdst,PathChar) ;          /* @@5 */

            *(++j) = NULLC;

            if ( (mystrlen(arg2) + 1 + mystrlen(bufdst)) > MAX_PATH )
               {
                  RenError(MSG_REN_INVAL_PATH_FILENAME);
               }

            mystrcpy(j,arg2);                             /* @@5 */

            bufdst[mystrlen(bufdst)] = NULLC ;            /* @@5 */
         }                                                /* @@5 */
      else                                                /* @@5 */
         {
            mystrcpy(&bufsrc[wlen],a1info->buf->cFileName);

            wildcard_rename(&tmpbuf1[0],arg2,&bufsrc[wlen],MAX_PATH);

            if ( (wlen + 1 + mystrlen( tmpbuf1 )) > MAX_PATH )
               {
                  RenError(MSG_REN_INVAL_PATH_FILENAME);
               }

            mystrcpy(&bufdst[wlen],&tmpbuf1[0]); /*@@4 @J1*/
         }

      /**********************************************/
      /* Rename a file or directory                 */
      /**********************************************/
      DEBUG((FCGRP, RELVL, "RENAME: src:`%ws', dst:`%ws'", bufsrc, bufdst)) ;
      if ( !MoveFile( bufsrc, bufdst) )
         {
            /**********************************************/
            /* rename fails                               */
            /**********************************************/

            i = GetLastError();
            if (i == ERROR_ALREADY_EXISTS)
               {
                  i = MSG_DUP_FILENAME_OR_NOT_FD;
               }

            rc = i ;                            /* @@5 Save the error code*/
            PutStdErr(rc,NOARGS);               /* @@5 Put our err message*/
         }

   } while (fnext(a1info->buf, attr, hnFirst ));

   /**********************************************/
   /* No more file is found                      */
   /**********************************************/
   findclose(hnFirst) ;

   mystrcpy(CurDrvDir,SaveDir);
   SaveDir = NULL ;

   return ( rc ? FAILURE : SUCCESS ); /* @@5 */
}


/***    RenError - handle Rename errors
 *
 *  Purpose:
 *      eRename()'s error handler.  Returns to eRename() via longjmp().
 *
 *  RenError(unsigned int errmsg)
 *
 *
 *  Args:
 *      errmsg - the error message to print
 *
 */

void RenError(errmsg)
unsigned int errmsg ;
{



        PutStdErr(errmsg, NOARGS);

/*@@4 @J1   ChangeDir(SaveDir) ;   */

        if (SaveDir) {
           mystrcpy(CurDrvDir,SaveDir);    /* @@5h */
           SaveDir = NULL ;
        }
        longjmp(CmdJBuf2,1) ;
}


/********************* START OF SPECIFICATION **************************/
/*                                                                     */
/* SUBROUTINE NAME: eMove                                              */
/*                                                                     */
/* DESCRIPTIVE NAME: Move Internal Command                             */
/*                                                                     */
/* FUNCTION: Parse the parameter passed and                            */
/*           moves one or more files from directory to another         */
/*           directory on the same drive.  If you prefer you can give  */
/*           the files different names.                                */
/*                                                                     */
/* NOTES:    ( New routine for Relaese 1.2 )  @@5*                     */
/*                                                                     */
/* ENTRY POINT: eMove                                                  */
/*    LINKAGE: NEAR                                                    */
/*                                                                     */
/* INPUT:                                                              */
/*            n - the parse tree node containing the copy command      */
/*                                                                     */
/* OUTPUT: None.                                                       */
/*                                                                     */
/* EXIT-NORMAL:                                                        */
/*         Return SUCCESS to the caller.                               */
/*                                                                     */
/* EXIT-ERROR:                                                         */
/*         Return FAILURE to caller.                                   */
/*                                                                     */
/* EFFECTS: None.                                                      */
/*                                                                     */
/* INTERNAL REFERENCES:                                                */
/*      ROUTINES:                                                      */
/*       MoveParse   - parse move command parameter                    */
/*       Move        - routine which actually call DosMove to move     */
/*                     file or directory.                              */
/*                                                                     */
/* EXTERNAL REFERENCES:                                                */
/*      ROUTINES:                                                      */
/*       None                                                          */
/*                                                                     */
/********************** END  OF SPECIFICATION **************************/

int eMove(n)
struct cmdnode *n ;
{
        unsigned i;
        TCHAR arg1[MAX_PATH] ;       /* Ptr to 1st arg   */
        TCHAR arg2[MAX_PATH] ;       /* Ptr to 2nd arg   */
        struct cpyinfo *a1info ;     /* Holds arg1 fspec info   */
        unsigned int is_dest_dir;    /* generated by MoveParse(), used by Move() */

        DEBUG((FCGRP, RELVL, "RENAME: arptr = `%ws'", n->argptr)) ;

        if (setjmp(CmdJBuf2))
           return(LastRetCode = FAILURE) ;

        /* MoveParse parses the command line parameters to arg1   */
        /* and arg1. In addition, a1info holds the fspec          */
        /* information for arg1.                                  */
        /* Based on arg1 and arg2, Move moves file(s)/directory.  */
        /* Move uses a1info to determine that arg1 contains       */
        /* wildcard.                                              */

        if ( !(i = MoveParse( n, arg1, arg2, &a1info, &is_dest_dir, MAX_PATH, MAX_PATH)) )
           {
              i = Move( arg1, arg2, a1info, is_dest_dir ) ;
           }

        return(LastRetCode = i) ;
}


/********************* START OF SPECIFICATION **************************/
/*                                                                     */
/* SUBROUTINE NAME: MoveParse                                          */
/*                                                                     */
/* DESCRIPTIVE NAME: Move Parser                                       */
/*                                                                     */
/* FUNCTION: Move Internal Function Parser                             */
/*                                                                     */
/* NOTES:    This parser breaks up the command line information        */
/*           into two parameters.                                      */
/*           ( New routine for Relaese 1.2 )  @@5*                     */
/*                                                                     */
/* ENTRY POINT: MoveParse                                              */
/*    LINKAGE: NEAR                                                    */
/*                                                                     */
/* INPUT:                                                              */
/*            n - the parse tree node containing the move command      */
/*                                                                     */
/* OUTPUT:   ptr1 - pointer to [drive:][path]filename to be moved from */
/*           ptr2 - pointer to [path]filename to be moved to           */
/*           a1info - pointer to cpyinfo which has arg1 fspec info     */
/*           is_dest_dir - flag used by Move()                         */
/*                                                                     */
/* EXIT-NORMAL:                                                        */
/*         Return SUCCESS to the caller.                               */
/*                                                                     */
/* EXIT-ERROR:                                                         */
/*         Return FAILURE to the caller.                               */
/*                                                                     */
/* EFFECTS: None.                                                      */
/*                                                                     */
/* INTERNAL REFERENCES:                                                */
/*      ROUTINES:                                                      */
/*         TokStr       - Tokenize argument strings.                   */
/*         FullPath     - Figure out the full path for a file.         */
/*         MoveError    - Process error condition for move command.    */
/*         SetFsSetSaveDir - Save current directory.                   */
/*                                                                     */
/* EXTERNAL REFERENCES:                                                */
/*      ROUTINES:                                                      */
/*         DOSQFILEMODE - Get file mode of the specified file/dir.     */
/*                                                                     */
/********************** END  OF SPECIFICATION **************************/
int MoveParse(n, source, target , a1info, is_dest_dir, sizpath1, sizpath2)
struct cmdnode *n ;
TCHAR *source ;                  /* Ptr to source file(s)/directory name  */
TCHAR *target ;                  /* Ptr to target file(s)/directory name  */
struct cpyinfo **a1info ;        /* Holds arg1 fspec information          */
unsigned int *is_dest_dir;       /* to pass to move                       */
unsigned sizpath1;               /* size of source buffer                 */
unsigned sizpath2;               /* size of target buffer                 */

{       struct cpyinfo *SetFsSetSaveDir() ;
        TCHAR *arg1 ;                   /* Ptr to 1st arg          */
        TCHAR *arg2 ;                   /* Ptr to 2nd arg          */
        TCHAR arg22[MAX_PATH] ;        /* Ptr to modified 2nd arg */
        unsigned i;
        unsigned concat_flag ;
        unsigned att ;
/*509*/ unsigned arg1len, arg2len;


        /* Get arg1.  If fail to get arg1, display error message. */
        if (!*(arg1 = TokStr(n->argptr, NULL, TS_NOFLAGS)))
          {
           MoveError(MSG_BAD_SYNTAX) ; /* no arg */
          }
/*509*/ else if ( (arg1len = mystrlen(arg1)) > MAX_PATH)
          {
           MoveError(MSG_REN_INVAL_PATH_FILENAME);
          }

        /*CurDrvDir = current directory or directory which is specified in arg1*/
/*509*/   mystrcpy( arg1, stripit( arg1 ) );
          if (((*a1info) = SetFsSetSaveDir(arg1)) == (struct cpyinfo *)FAILURE)
          {
            MoveError(DosErr) ;     /* Error if invalid dir @@5d */
          }
                                                      /*                   */
        /* Get arg2 out of arg1 */

        arg2 = arg1 + arg1len + 1;

        if ( !(*arg2) )
              {

                 arg22[0] = SaveDir[0];    /* get current drive */
                 arg22[1] = COLON;
                 arg22[2] = NULLC;
              }
        else if (*(arg2 + mystrlen(arg2) + 1))  /* @@5g */
          {
           MoveError(MSG_BAD_SYNTAX) ;  /* too many arguments */
          }
/*509*/ else if ( (arg2len = mystrlen(arg2)) > MAX_PATH)
          {
           MoveError(MSG_REN_INVAL_PATH_FILENAME);
          }
        else
          {
           /* If arg2 conatins a drive name, display an error message. */

/*509*/    mystrcpy( arg2, stripit( arg2 ) );

           // UNC names fix

           if (  ( *(arg2+1) != COLON )  &&  ( ! (  ( *arg2 == BSLASH ) && ( *(arg2+1) == BSLASH )  )  )  )
             {
                 arg22[0] = SaveDir[0];    /* get drive we're using */
                 arg22[1] = COLON;
                 arg22[2] = NULLC;
                 if ((mystrlen(arg22) + mystrlen(arg2)+1) > MAX_PATH)
                   {
                   MoveError(MSG_REN_INVAL_PATH_FILENAME);
                 }
                 mystrcat( arg22, arg2 ) ;

            //  MoveError(MSG_BAD_SYNTAX) ; /*bad arg2*/
             } else

           //if (*(arg1+1) == COLON)     /* If arg1 contains a drive */
           //  {                                 /* name, put the same drive */
           //                            /* name in arg2.            */
           //   i = 0 ;
           //
           //   arg22[i++] = arg1[0] ;
           //   arg22[i++] = arg1[1] ;
           //   arg22[i] = NULLC ;
           //   if ((mystrlen(arg22) + mystrlen(arg2)+1) > MAX_PATH)
           //   {
           //    MoveError(MSG_REN_INVAL_PATH_FILENAME);
           //   }
           //   mystrcat( arg22, arg2 ) ;
           //
           //  }
           //else
             {
              mystrcpy(arg22,arg2) ;
             }
          }


        /* source = complete path for arg1 */

        if ( i = FullPath(source, arg1,sizpath1) )
           {
             MoveError( MSG_REN_INVAL_PATH_FILENAME ) ;
           }


        /* target = complete path for arg2 */


        if ( i = FullPath(target, arg22,sizpath2) )           /* @@5b */
           {
             MoveError( MSG_REN_INVAL_PATH_FILENAME ) ;
           }


        concat_flag = FALSE ;
        DosErr = NO_ERROR ;
        SetLastError(NO_ERROR);
        *is_dest_dir = 0;

        if (*lastc(target) == PathChar)          /* test for last non DBCS character path char  @@5@J3 */
          {
              concat_flag = TRUE ;
              target[mystrlen(target)-1] = NULLC ;
          } ;

        if ( (att = GetFileAttributes( target )) != -1 )
          {
            if (att & A_D)   /* if target is a directory, copy the file      */
              {              /* name from source.                            */
                 *is_dest_dir = 1;
                 concat_flag = TRUE ;
              } ;
          }
        else if( (DosErr = GetLastError()) &&
                ( ( DosErr != ERROR_FILE_NOT_FOUND ) &&
                  ( DosErr !=  ERROR_PATH_NOT_FOUND )    )   )
          {
             MoveError( DosErr ) ;
          } ;

        if (concat_flag)
          {
              arg1 = mystrrchr(source,PathChar);
              if ((mystrlen(arg1) + mystrlen(target) + 1) > MAX_PATH)
                {
                  MoveError( MSG_REN_INVAL_PATH_FILENAME ) ;
                }
              mystrcat( target, arg1 ) ;
          } ;

        return(SUCCESS) ;
 }


/********************* START OF SPECIFICATION **************************/
/*                                                                     */
/* SUBROUTINE NAME: MoveError                                          */
/*                                                                     */
/* DESCRIPTIVE NAME: Move Error Handling                               */
/*                                                                     */
/* FUNCTION: Handles error condition from MoveParse and change         */
/*           back to the original directory.                           */
/*                                                                     */
/* NOTES:    ( New routine for Release 1.2 )  @@5*                     */
/*                                                                     */
/* ENTRY POINT: MoveError                                              */
/*    LINKAGE: NEAR                                                    */
/*                                                                     */
/* INPUT:    Error condition or error code from API calls.             */
/*                                                                     */
/* OUTPUT: None.                                                       */
/*                                                                     */
/* EXIT-NORMAL:                                                        */
/*         None.                                                       */
/*                                                                     */
/* EXIT-ERROR:                                                         */
/*         None.                                                       */
/*                                                                     */
/* EFFECTS: None.                                                      */
/*                                                                     */
/* INTERNAL REFERENCES:                                                */
/*      ROUTINES:                                                      */
/*       PutStdErr - Displays an error message.                        */
/*                                                                     */
/* EXTERNAL REFERENCES:                                                */
/*      ROUTINES:                                                      */
/*       None.                                                         */
/*                                                                     */
/********************** END  OF SPECIFICATION **************************/

void MoveError(errmsg)
unsigned int errmsg ;
{

        PutStdErr(errmsg, NOARGS);   /* display an error message       */

   /*   ChangeDir(SaveDir) ;            change back to the current dir */
        if (SaveDir) {
           mystrcpy(CurDrvDir,SaveDir);
           SaveDir = NULL ;             /* Reset SaveDir                  */
        }

        longjmp(CmdJBuf2,1) ;
}





/********************* START OF SPECIFICATION **************************/
/*                                                                     */
/* SUBROUTINE NAME: Move                                               */
/*                                                                     */
/* DESCRIPTIVE NAME: Move Process                                      */
/*                                                                     */
/* FUNCTION: Moves one or more files from directory to another         */
/*           directory on the same drive.  If you prefer you can give  */
/*           the files different names.                                */
/*                                                                     */
/* NOTES:    ( New routine for Release 1.2 )  @@5*                     */
/*                                                                     */
/* ENTRY POINT: eMove                                                  */
/*    LINKAGE: NEAR                                                    */
/*                                                                     */
/* INPUT:    ptr1 - pointer to [drive:][path]filename to be moved from */
/*           ptr2 - pointer to [path]filename to be moved to           */
/*           a1info - pointer to cpyinfo which has arg1 fspec info     */
/*           is_dest_dir - from MoveParse()                            */
/*                                                                     */
/* OUTPUT: None.                                                       */
/*                                                                     */
/* EXIT-NORMAL:                                                        */
/*         Return Success to the caller.                               */
/*                                                                     */
/* EXIT-ERROR:                                                         */
/*         Return error code from DosMove API.                         */
/*                                                                     */
/* EFFECTS: None.                                                      */
/*                                                                     */
/* INTERNAL REFERENCES:                                                */
/*      ROUTINES:                                                      */
/*       MoveError    - Process error condition for move command.      */
/*       ChangeDir - Change back to the original directory.            */
/*       wildcard_rename - Replace the file name with wildcard to      */
/*                         a complete file name without * or ?.        */
/*       ffirst - Find the first file which matches the specified      */
/*                file name that may contain * or ?.                   */
/*       fnext  - Find the next file which matches the specified       */
/*                file name that may contain * or ?.                   */
/*       findclose - Close the file with the specified file handle,    */
/*                       hnFirst which is given by ffirst or fnext.    */
/*       PutStdErr - Displays an error message.                        */
/*       PutStdOut - Displays a message.                               */
/*       Wild      - check if the arg contains wild card.              */
/*                                                                     */
/* EXTERNAL REFERENCES:                                                */
/*      ROUTINES:                                                      */
/*       DOSMOVE     -  move directories and files.                    */
/*                                                                     */
/********************** END  OF SPECIFICATION **************************/

int
Move( arg1, arg2, a1info, is_dest_dir )
TCHAR *arg1 ;                         /* Ptr to 1st arg          */
TCHAR *arg2 ;                         /* Ptr to 2nd arg          */
struct cpyinfo *a1info ;              /* Holds arg1 fspec info   */
unsigned int is_dest_dir;             /* flag if set--> dest. is a dir */

#define f_RET_DIR      -1             /* from f_how_many() when directory */


               {
                unsigned attr ;
                unsigned i, n;
                unsigned long number_of_files_moved ;
                TCHAR bufsrc[MAX_PATH];      /* path of source file     */
                TCHAR bufdst[MAX_PATH];      /* path of destination file*/
                TCHAR Tmpbuf1[MAX_PATH];             /* path of temp buffer     */
                HANDLE hnFirst ;                                  /* Findfirst handle    */
                TCHAR *j, *k,*l;                      /* Tmp Ptr                 */
                unsigned wild_flag ;                  /* wildcard flag           */
                unsigned save_error ;                 /* Saved error code        */
                TCHAR pcstr[3] ;
                unsigned rc;
                int retc;
                int how_many_src=0;                   /* =f_RET_DIR if dir; =0 if none; = <number matching src files> else */
                char type_format_dest=0;              /* decide on how to format dest */
                char fl_move_once=0;                  /* if =1 execute move once only */



                how_many_src = f_how_many (arg1, (ULONG) (attr=A_A) );


                /**********************************************/
                /* Set flag whether arg1 contains             */
                /* wildcard or not.                           */
                /**********************************************/

                pcstr[0] = STAR ;
                pcstr[1] = QMARK ;
                pcstr[2] = NULLC ;
                wild_flag = ((mystrcspn(arg1,pcstr))
                                       < mystrlen(arg1)) ;



                // Decide on what to do depending on: <1.multiple/single src; 2.is dest dir ?>

                if (how_many_src == f_RET_DIR)  {
                    if (is_dest_dir)  {
                        if (!MoveFile(arg1, arg2) ) {

                           i = GetLastError();

                           if (i == ERROR_ACCESS_DENIED)  {
                              i = MSG_DUP_FILENAME_OR_NOT_FD;
                           }

                           PutStdErr(i, NOARGS);    /* Put out an error message */
                           MoveErrExit();
                        }
                        else {
                            if (SaveDir) {
                               mystrcpy(CurDrvDir,SaveDir);
                               SaveDir = NULL ;             /* Reset SaveDir                  */
                            }

                            return(SUCCESS) ;
                        }
                    }
                    else  {
                        type_format_dest = 2;
                        fl_move_once = 1;
                    }
                 }

                 else if (how_many_src > 1 )  {
                     if (is_dest_dir)  {
                        type_format_dest = 1;
                        fl_move_once = 0;
                     }
                     else {
                         PutStdErr(MSG_MOVE_MULTIPLE_FAIL, NOARGS);
                         MoveErrExit();
                     }
                 }

                 else { // single source or source doesn't exist
                     if (is_dest_dir)  {
                        type_format_dest = 1;
                        fl_move_once = 1;
                     }
                     else {
                         type_format_dest = 2;
                         fl_move_once = 1;
                     }
                 }


                /**********************************************/
                /* Issue ffirst for a file name               */
                /**********************************************/

/*M006*/        if (!ffirst(arg1, attr = A_A, a1info->buf, &hnFirst ))  {

                    /**********************************************/
                    /* Issue ffirst for a directory name          */
                    /**********************************************/

                    rc = ffirst(arg1, attr = A_D, a1info->buf, &hnFirst ) ;

                    if ( !rc) {
                       /**********************************************/
                       /* No file or directory which arg1            */
                       /* specifies found                            */
                       /**********************************************/

                       if (!rc && DosErr == ERROR_NO_MORE_FILES) { /* @@5e */
                          rc = ERROR_FILE_NOT_FOUND;
                       } else if (wild_flag) {
                          rc = MSG_DUP_FILENAME_OR_NOT_FD;
                       } else {
                          rc = DosErr;
                       }
                       MoveError(rc);                             /* @@5d */
                    }
                }

                number_of_files_moved = 0 ;                     /* Reset the counter to zero */
                save_error = NO_ERROR ;                         /* Reset error code to zero  */
                mystrcpy(bufsrc,arg1) ;
                j = mystrrchr(bufsrc,PathChar) ;
                ++j;                                            /* get to filename area      */


                do {
                    if (CtrlCSeen) {
                        findclose(hnFirst) ;
                        if (SaveDir) {
                            mystrcpy(CurDrvDir,SaveDir);
                            SaveDir = NULL;
                        }

                        return(FAILURE);
                    }

                    /**********************************************/
                    /* build bufdst                               */
                    /**********************************************/


                    mystrcpy(j,a1info->buf->cFileName) ;

                    // REMOVED call to a buggy wildcard_rename(Tmpbuf1,k,j,MAX_PATH) ;

                    mystrcpy(bufdst,arg2);

                    if (type_format_dest == 1 )  {
                        l = mystrrchr(bufdst,PathChar);
                        ++l;
                        mystrcpy(l,a1info->buf->cFileName) ;
                        if ((mystrlen(bufdst) ) > MAX_PATH) {
                            MoveError( MSG_REN_INVAL_PATH_FILENAME ) ;
                        }
                    }


                    /**********************************************/
                    /* check to see if filename is legal          */
                    /**********************************************/

                    if (!GetFullPathName(bufdst, TMPBUFLEN, TmpBuf, NULL)) {
                        goto badness;
                    }
                    n = _tcslen(TmpBuf);
                    if (!GetFullPathName(bufsrc, TMPBUFLEN, TmpBuf, NULL)) {
                        goto badness;
                    }
                    if (!GreatestLength(TmpBuf, &i))
                        continue;
                    if (n + i > MAX_PATH) {
                        i = ERROR_FILENAME_EXCED_RANGE;
                        goto badness2;
                    }

                    /**********************************************/
                    /* Move a file or directory                   */
                    /**********************************************/


                    if (!MoveFile(bufsrc,bufdst))  {

                       /**********************************************/
                       /* Move fails                                 */
                       /**********************************************/
badness:
                       i = GetLastError();
badness2:

                       if (i == ERROR_ACCESS_DENIED)  {
                          i = MSG_DUP_FILENAME_OR_NOT_FD;
                       }

                       save_error = i ;         /* Save the error code      */

                       PutStdErr(i, NOARGS);    /* Put out an error message */

                       i = mystrlen(bufdst) ;

                       if ( bufdst[--i] == DOT )    {             /* @@5a     */
                          bufdst[i] = 0 ;                         /* @@5a     */
                       }                                          /* @@5a     */
                                                                  /* @@5a     */
/*509*/                if(!_tcsicmp(bufsrc,bufdst))   {           /* @@5a     */
                          break ;                                 /* @@5a     */
                       }                                          /* @@5a     */

                    }
                    else  {
                       ++number_of_files_moved ;    /* Increment counter */

                       if ( wild_flag )  {           /* If wild card is used */
                          cmd_printf(Fmt17,bufsrc); /* display the file name*/
                       }

                    }

                    if (fl_move_once)
                        break;

                } while (fnext(a1info->buf, attr, hnFirst ));


                /**********************************************/
                /*           No more files to be found        */
                /**********************************************/

                findclose(hnFirst) ;
                mystrcpy(CurDrvDir,SaveDir);    /* @@5h */
                SaveDir = NULL ;

                /**********************************************/
                /* Display the total number of file(s) moved  */
                /**********************************************/

                if ( a1info->buf->dwFileAttributes != A_D )
                  {
                   PutStdOut(MSG_FILES_MOVED, ONEARG,
                   argstr1(TEXT("%9d"), (unsigned long)number_of_files_moved)) ;
                  }

                return(save_error == NO_ERROR ? SUCCESS : FAILURE) ;
                }


/***    eChcp - Entry point for Chcp routine
 *
 *  Purpose:
 *      to call Chcp and pass it a pointer to the command line
 *      arguments
 *
 *  Args:
 *      a pointer to the command node structure
 *
 */

int eChcp( n )                     /* @@ */
struct cmdnode *n;                 /* @@ */
{                                  /* @@ */
    return(  LastRetCode = Chcp( n->argptr) );    /* @@ */
}                                  /* @@ */

int
eTitle (

    IN  struct cmdnode *pcmdnode
    ) {

    LPTSTR NewTitle;
    if (!pszTitleCur) {

        pszTitleCur = HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(TCHAR) + 2*sizeof(TCHAR));
        if (pszTitleCur == NULL) {

            PutStdErr(ERROR_NOT_ENOUGH_MEMORY, NOARGS);
            return( FAILURE );

        }

    }

    if (mystrlen(pcmdnode->argptr) >= MAX_PATH) {

            PutStdErr(ERROR_NOT_ENOUGH_MEMORY, NOARGS);
            return( FAILURE );

        }

    NewTitle = EatWS(pcmdnode->argptr, NULL);
    if (NewTitle && *NewTitle) {
        mystrcpy(pszTitleCur,NewTitle);
    }
    SetConsoleTitle(pszTitleCur);

    //
    // This insures that ResetConTitle does not undo what
    // we have just done
    //
    fTitleChanged = FALSE;
    return( SUCCESS );
}

/***    eStart - Entry point for Start routine
 *
 *  Purpose:
 *      to call Start and pass it a pointer to the command line
 *      arguments
 *
 *  Args:
 *      a pointer to the command node structure
 *
 */

int eStart( n )                     /* @@ */
struct cmdnode *n;                  /* @@ */
{                                       /* @@ */
          DBG_UNREFERENCED_PARAMETER( n );
      return( Start(n->argptr) );
}                                   /* @@ */