/*
** args.c - Command-line argument manipulation functions.
**
** Author:  DavidDi
**
** N.b., setargv.obj must be linked with this module for the command-line
** parsing to function properly.
*/


// Headers
///////////

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "lz_common.h"
#include "lz_header.h"

#include "args.h"
#include "main.h"
#include "messages.h"
#include <diamondc.h>
#include "mydiam.h"

extern BOOL PathType(LPSTR lpszFileString);   /* WIN32 MOD*/

// Globals
///////////

// All the globals defined in this module are set by ParseArguments().

BOOL bDoRename,      // flag for performing compressed file renaming
     bDisplayHelp,   // flag for displaying help information
     bTargetIsDir,   // flag telling whether or not files are being
                     // compressed to a directory
     bDirectives,    // One or more directive files on command-line
     bUpdateOnly,    // flag for conditional compression based on
                     // existing target file's date/time stamp relative
                     // to source file.
     bNoLogo;        // flag to suppress printing copyright information

INT nNumFileSpecs,   // number of non-switch, non-directory command-line
                     // arguments, assumed to be file specifications
    iTarget;         // argv[] index of target directory argument, or FAIL if
                     // none present

BYTE byteAlgorithm;  // compression / expansion algorithm to use
TCOMP DiamondCompressionType;  // 0 if not diamond (ie, LZ)


/*
** BOOL ParseArguments(int argc, char ARG_PTR *argv[]);
**
** Parse command-line arguments.
**
** Arguments:  like arguments to main()
**
** Returns:    TRUE if command-line arguments parsed successfully.  FALSE if
**             not.
**
** Globals:    All globals defined in this module are set in this function,
**             as described above.
*/


BOOL ParseArguments(INT argc, CHAR ARG_PTR *argv[])
{
   INT i;
   CHAR chSwitch;
   TCOMP Level;
   TCOMP Mem;
   CHAR *p;

   // Set up default values for globals.
   bDoRename = FALSE;
   bDisplayHelp = FALSE;
   bTargetIsDir = FALSE;
   bDirectives = FALSE;
   bNoLogo = FALSE;
   nNumFileSpecs = 0;
   iTarget = FAIL;
   byteAlgorithm = DEFAULT_ALG;
   DiamondCompressionType = 0;

   // Look at each command-line argument.
   for (i = 1; i < argc; i++)
      if (ISSWITCH(*(argv[i])))
      {
         // Get switch character.
         chSwitch = *(argv[i] + 1);

         //for bad DBCS argument
         if( IsDBCSLeadByte(chSwitch) )
         {
            CHAR work[3];
            lstrcpyn(work, argv[i] + 1, 3);
            LoadString(NULL, SID_BAD_SWITCH2, ErrorMsg, 1024);
            printf(ErrorMsg, work);
            return(FALSE);
         }

         // Classify switch.
         if (toupper(chSwitch) == toupper(chRENAME_SWITCH))
            bDoRename = TRUE;
         else if (toupper(chSwitch) == toupper(chHELP_SWITCH))
            bDisplayHelp = TRUE;
         else if (toupper(chSwitch) == toupper(chUPDATE_SWITCH))
            bUpdateOnly = TRUE;
         else if (toupper(chSwitch) == toupper(chNO_LOGO_SWITCH))
            bNoLogo= TRUE;
         else if (toupper(chSwitch) == toupper(chALG_SWITCH)) {

            switch(*(argv[i] + 2)) {

            case 'x':
            case 'X':
                //
                // LZX. Also set memory.
                //
                Mem = (TCOMP)atoi(argv[i] + 3);

                if((Mem < (tcompLZX_WINDOW_LO >> tcompSHIFT_LZX_WINDOW))
                || (Mem > (tcompLZX_WINDOW_HI >> tcompSHIFT_LZX_WINDOW))) {

                    Mem = (tcompLZX_WINDOW_LO >> tcompSHIFT_LZX_WINDOW);
                }

                byteAlgorithm = LZX_ALG;
                DiamondCompressionType = TCOMPfromLZXWindow( Mem );
                break;

            case 'q':
            case 'Q':
                //
                // Quantum. Also set level.
                //
                Level = (TCOMP)atoi(argv[i] + 3);
                Mem = (p = strchr(argv[i]+3,',')) ? (TCOMP)atoi(p+1) : 0;

                if((Level < (tcompQUANTUM_LEVEL_LO >> tcompSHIFT_QUANTUM_LEVEL))
                || (Level > (tcompQUANTUM_LEVEL_HI >> tcompSHIFT_QUANTUM_LEVEL))) {

                    Level = ((tcompQUANTUM_LEVEL_HI - tcompQUANTUM_LEVEL_LO) / 2)
                          + tcompQUANTUM_LEVEL_LO;

                    Level >>= tcompSHIFT_QUANTUM_LEVEL;
                }

                if((Mem < (tcompQUANTUM_MEM_LO >> tcompSHIFT_QUANTUM_MEM))
                || (Mem > (tcompQUANTUM_MEM_HI >> tcompSHIFT_QUANTUM_MEM))) {

                    Mem = ((tcompQUANTUM_MEM_HI - tcompQUANTUM_MEM_LO) / 2)
                        + tcompQUANTUM_MEM_LO;

                    Mem >>= tcompSHIFT_QUANTUM_MEM;
                }

                byteAlgorithm = QUANTUM_ALG;
                DiamondCompressionType = TCOMPfromTypeLevelMemory(
                                            tcompTYPE_QUANTUM,
                                            Level,
                                            Mem
                                            );
                break;

            case 'l':
            case 'L':
                DiamondCompressionType = 0;
                byteAlgorithm = DEFAULT_ALG;
                break;

            default:
                DiamondCompressionType = tcompTYPE_MSZIP;
                byteAlgorithm = MSZIP_ALG;
                break;
            }
         } else
         {
            // Unrecognized switch.
            LoadString(NULL, SID_BAD_SWITCH, ErrorMsg, 1024);
            printf(ErrorMsg, chSwitch);
            return(FALSE);
         }
      }
      else
      {
         // Keep track of last non-switch command-line argument as
         // destination argument.
         iTarget = i;

         // Determine if this is a directive file
         if ( '@' == argv[i][0] )
             bDirectives = TRUE;
         else if (IsDir((LPSTR)argv[i]) == FALSE)
            // Non-switch arguments are assumed to be file specifications.
            nNumFileSpecs++;
      }

   // Set bTargetIsDir.
   if (iTarget != FAIL)
      bTargetIsDir = IsDir((LPSTR)argv[iTarget]);

   // Command-line arguments parsed successsfully.
   return(TRUE);
}


/*
** BOOL CheckArguments(void);
**
** Check command-line arguments for error conditions.
**
** Arguments:  void
**
** Returns:    BOOL - TRUE if no problems found.  FALSE if problem found.
**
** Globals:    none
*/
BOOL CheckArguments(VOID)
{
   if (nNumFileSpecs < 1 && !bDirectives )
   {
      // No file specifications given.
      LoadString(NULL, SID_NO_FILE_SPECS, ErrorMsg, 1024);
      printf(ErrorMsg);
      return(FALSE);
   }
   else if (nNumFileSpecs == 1 && bDoRename == FALSE && bTargetIsDir == FALSE)
   {
      // We don't want to process a source file on to itself.
      LoadString(NULL, SID_NO_OVERWRITE, ErrorMsg, 1024);
      printf(ErrorMsg, pszTargetName);
      return(FALSE);
   }
   else if (nNumFileSpecs >  2 && bDoRename == FALSE && bTargetIsDir == FALSE)
   {
      // There are multiple files to process, and the destination
      // specification argument is not a directory.  But we weren't told to
      // rename the output files.  Bail out since we don't want to wipe out
      // the input files.
      LoadString(NULL, SID_NOT_A_DIR, ErrorMsg, 1024);
      printf(ErrorMsg, pszTargetName);
      return(FALSE);
   }
   else
      // No problems encountered.
      return(TRUE);
}


/*
** int GetNextFileArg(char ARG_PTR *argv[]);
**
** Find the next file name argument on the command-line.
**
** Arguments:  like argument to main()
**
** Returns:    int - Index in argv[] of next file name argument.  FAIL if
**                   none found.
**
** Globals:    none
*/
INT GetNextFileArg(CHAR ARG_PTR *argv[])
{
   INT i;
   static INT iLastArg = 0;

   for (i = iLastArg + 1; i <= iTarget; i++)
      if (! ISSWITCH(*(argv[i])) &&
          (i < iTarget || bTargetIsDir == FALSE)
          && (! IsDir((LPSTR)argv[i])))
         return(iLastArg = i);

   return(FAIL);
}

/* WIN32 MODS   */

/* returns 0 if not directory, 1 if so */
INT IsDir(LPSTR lpszTestString)
{

    BOOL bRetVal;

    bRetVal = PathType(lpszTestString);
	 if(bRetVal == 0){		/*assert*/
		bRetVal++;				/* this is because if lpszTestString file doesnt exist*/
									/* API returns 0, so I increment to 1, cause is NOT directory*/
    }
	 return(--bRetVal);       /* because returns 2 if dir, 1 if not*/

}
