/*static char *SCCSID = "@(#)parse.c    6.2 91/09/08";*/
/*static char *SCCSID = "@(#)parse.c    6.2 91/09/08";*/
/***    PARSE.C - Routines to parse the command line
 *
 *      CHKDSK
 *      Gregory A. Jones
 *      Copyright 1988 Microsoft Corporation
 *
 *      Modification history:
 *      G.A. Jones      05/24/88        Original for Pinball 1.0.
 *      D.Azzarito      5May 1994   @83390 - changed Autocheck password
 *      D.Azzarito      15Jul94     @88993 - Allow old pw (for HPFS386)
 *                                  but omly allow AutoCheck at init time
 */

#define INCL_DOSFILEMGR
#include "ldefs.h"
#include "ltypes.h"
#include "globals.h"
#include <pr_chk.h>
#undef  INCL_DOSFILEMGR
#include <utilmid.h>
#include <const.h>                                                   // 83390

/***    chk_parse_options - parse CHKDSK command line.
 *
 *      chk_parse_options is passed main()'s parameters, and evaluates the
 *      parameters given on the command line.  These parameters may include
 *      one optional drive letter, plus any of three switches which select
 *      the degree of recovery required.
 *
 *      chk_parse_options (argc, argv)
 *
 *      ENTRY           argc - number of command line arguments
 *                      argv - array of pointers to command line arguments
 *
 *      EXIT            Returns TRUE if required parameters were found.
 *
 *      CALLS           chk_argument_error
 *                      getcwd
 *                      chk_parse_arg
 *
 *      EFFECTS         Sets global variables:
 *                      disk_name
 *                      chk_delete_inconsistency
 *                      chk_recover_data
 *                      chk_search_free
 */
USHORT chk_parse_options (argc, argv)
  USHORT argc;
  UCHAR **argv;
{
  CHAR *drive_msg[1];                                                // @83390
#ifdef  TRACE
  USHORT i;

  for (i=0; i<argc; i++)                /* print arguments one by one */
    fprintf (stderr, "argv [%d] = %s\n", i, argv [i]);
  fflush (stderr);
#endif

  getcwd ((UCHAR *)disk_name, 80);      /* assume current working drive */

  while (--argc) {              /* pre-decrement to skip command name */
#ifdef TRACE
    fprintf (stderr, "Looking at %s\n", argv [argc]);
    fflush (stderr);
#endif

    if (argv [argc][0] == '/' || argv [argc][0] == '-') {
      if (!chk_parse_arg (argv [argc])) /* parse a switch */
        chk_argument_error (argv [argc]);   /* error in argument */
    }

#ifdef FILE_IO
    else if (isalnum (argv [argc][0]))
      strcpy (disk_name, argv [argc]);          /* copy file name */
#else
    else if (isalnum (argv [argc][0]) && argv [argc][1] == ':' &&
             !argv [argc][2])
      disk_name [0] = toupper (argv [argc][0]); /* found a drive letter */
#endif

    else
      chk_argument_error (NULL);                /* illegal argument */
  }

#ifndef FILE_IO
  disk_name [1] = ':';
  disk_name [2] = '\0';
#endif

#ifdef TRACE
  fprintf (stderr, "Will be checking drive `%s'\n", disk_name);
  fflush (stderr);
#endif

// If we're AUTOCHECKing, we don't call CHKDSK.COM, so we don't get the
// message about which drive we're on.  So, we print it ourselves.

  if (chk_autocheck)
  {
     drive_msg[0] = disk_name;    // get pointer to disk name       @83390
     CHK_COMPUTMSG( SYSTEM_MSG,   // Tell user what drive we're on  @83390
                    drive_msg,                                   // @83390
                    1,                                           // @83390
                    MSG_FDISK_CURRENTDISK,                       // @83390
                    msgfilename,                                 // @83390
                    STDOUT_CODE,                                 // @83390
                    NO_RESPONSE,                                 // @83390
                    NULL,                                        // @83390
                    0);                                          // @83390
  }

  return (1);
}

/***    chk_parse_arg - parse a single command line argument
 *
 *      Parses a single word on the command line that begins with / or -.
 *      Currently, three switches are allowed:
 *
 *      /C     - initiate /F:2 iff spareblock->bFlag & SPF_DIRT.
 *      /V     - display each filename as it is checked, display %done messages.
 *      /F[:n] - recovery level n (if no /F switch at all, n=0):
 *               n = 0 --> check only, do not change the volume.
 *               n = 1 --> delete inconsistent structures.
 *               n = 2 --> n=1, plus scan in-use space for recoverable data.
 *               n = 3 --> n=2, plus scan free space for recoverable data.
 *      /F alone is equivalent to /F:2.
 *
 *      chk_parse_arg (p)
 *
 *      ENTRY           p - pointer to argument string
 *
 *      EXIT            Returns true if p points to a valid argument
 *
 *      CALLS           isalnum
 *
 *      EFFECTS         May set any of the following global variables:
 *                      chk_delete_inconsistency
 *                      chk_recover_data
 *                      chk_search_free
 *                      chk_check_if_dirty
 *                      chk_verbose_display
 */
USHORT chk_parse_arg (p)
   PUCHAR p;
{

   USHORT   fsType,
            usDeviceAttr;

#ifdef TRACE
   fprintf (stderr, "chk_parse_arg %s\n", p);
   fflush (stderr);
#endif

   while (*p)
   {

// The AUTOCHECK password lets us know we're being called at startup.
// We check this BEFORE converting to lowercase.

      if (!strncmp (p, "aUtOcHeCk", 9))  // Is this the AUTOCHECK passwd? @88993
      {
         APIRET  rc;
         PIDINFO PidInfo;

         rc = DosGetPID (&PidInfo);   // Get PID to see if it's INIT    @88993

         if (rc || (PidInfo.pid == 1))                               // @88993
         {                            // if Parent is 0, or unknown,    @88993
            chk_autocheck = TRUE;     // Autocheck is allowed           @88993
            p += 9;                   // Skip past the password         @88993
            continue;                                                // @88993
         }
      }
/* BUBUG - this cast is needed because the fn incorrectly returns an int. */
      *p = (UCHAR)com_tolower (*p);
      if ((*p == '/') || (*p == '-'))    /* skip switch characters */
      {
         p++;
         continue;
      }

      else if (*p == 'f')                /* recovery-level switch */
      {
         p++;
         if (*p == ':')
         {
            p++;
            switch (*p)
            {
               case '3': chk_search_free = TRUE;         /* fall into next case */
               case '2': chk_recover_data = TRUE;        /* fall into next case */
               case '1': chk_delete_inconsistency = TRUE; /* fall into "break" */
               case '0': break;
               default: return (0);                    /* illegal character */
            } // end switch
         } // end if ':'
         else
            chk_delete_inconsistency = chk_recover_data = TRUE; /* "/F" == "/F:2" */
      } // end if 'f'

      else if (*p == 'm')                /* recovery-level switch */
      {
         p++;
         if (*p == ':')
         {
            p++;
            hfileChkPipe = atoi( p++ );
            if ( !DosQHandType( hfileChkPipe, &fsType, &usDeviceAttr ) )
               if ( fsType == HANDTYPE_PIPE )
               {
                  chk_usepipe = TRUE;
               }
         }  // end if ':'
      } // end if 'm'
#ifdef PMFRONTEND
      else if (*p == 'p')                 //PCR PM FRONT END
         chk_pmfrontend = TRUE;            //PCR PM FRONT END
#endif
      else if (*p == 'c')                 /* check only if inconsistent */
         chk_check_if_dirty = TRUE;
      else if (*p == 'v')                 /* verbose -- display all filenames */
         chk_verbose_display = TRUE;
      else                                /* bad argument */
         return (0);

      if (*p)
        p++;
   } // end while p

   return (1);
}

/***    chk_argument_error - print informative message and exit
 *
 *      chk_argument_error (p)
 *
 *      ENTRY           p - pointer to offending argument
 *
 *      CALLS           chk_exit_error
 *                      computmsg
 *
 *      EFFECTS         Exits program
 *
 *      WARNINGS        Does not return
 */
void chk_argument_error (p)
  PUCHAR p;
{
  if (p != NULL)
    CHK_COMPUTMSG( SYSTEM_MSG, &p, 1, CHK_IV_PARAM_STR, msgfilename, STDERR_CODE, NO_RESPONSE,
               NULL, 0);

  CHK_COMPUTMSG( SYSTEM_MSG, NULL, 0, CHK_USAGE_STR, msgfilename, STDERR_CODE, NO_RESPONSE,
             NULL, 0);
  chk_exit_error (ARG_ERROR);
}
