/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1992 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 source code is provided to you solely for       */
/*    the purpose of assisting you in your development of OS/2 device        */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Developer Connection Device Driver       */
/*    Source Kit for OS/2. This Copyright statement may not be removed.      */
/*                                                                           */
/*****************************************************************************/
/*static char *SCCSID = "src/dev/dasd/ibm/ibm1s506/cmdparse.c, idsk, r207, 8.005p 93/03/18";*/
/**************************************************************************
 *
 * SOURCE FILE NAME = CMDPARSE.C
 *
 * DESCRIPTIVE NAME =  IBM1S506.ADD - Adapter Driver for ST506/IDE DASD
 *
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION : ADD CONFIG.SYS Command Line Parser Helper Routine
 *
 * Purpose: This module consists of the Command_Parser Function and
 *          its associated local routines.  For detailed description
 *          of the Command_Parser interface refer to the CMDPARSE.H
 *          file.
 *
 *
 *
*/

 #define INCL_NOBASEAPI
 #define INCL_NOPMAPI
 #define INCL_NO_SCB
 #define INCL_INITRP_ONLY
 #include "os2.h"
 #include "dos.h"

 #include "iorb.h"
 #include "reqpkt.h"
 #include "dhcalls.h"
 #include "addcalls.h"
 #include "dskinit.h"

 #include "s506cons.h"
 #include "s506type.h"
 #include "s506ext.h"

 #include "cmdproto.h"

#define TOKVBUF_LEN 255
#define UNDEFINED   -1

/*******************************************************************************
*                                                                              *
*   Command_Parser -  external entry point into this module                    *
*                                                                              *
*******************************************************************************/

CC FAR Command_Parser(pCmdLine,pOptTable,pOutBuf,OutBuf_Len)

PSZ           pCmdLine;
POPTIONTABLE  pOptTable;
PBYTE         pOutBuf;
USHORT        OutBuf_Len;

{
   USHORT j, end_index;

   if (OutBuf_Len < (TOKL_ID_END + TOK_MIN_LENGTH))
   {
      cc.ret_code = BUF_TOO_SMALL_ERR;
      cc.err_index = 0;
      return (cc);
   }

   poutbuf_end = pOutBuf + OutBuf_Len;

   poutbuf1 = pOutBuf;
   for (poutbuf1 = pOutBuf;
        (poutbuf1 < poutbuf_end);
        poutbuf1++)
       *poutbuf1 = 0;
   poutbuf1 = pOutBuf;

   Insert_End_Token();

   /*-------------------------------------------------------------------*/
   /*  Locate the last entry in the Option Table. This special entry    */
   /*  defines whether or not an option is required based on the index  */
   /*  in the state table.                                              */
   /*-------------------------------------------------------------------*/

   for (end_index = 0 ;
        (pOptTable->poption[end_index]->id != TOK_ID_END);
        end_index++);
   pend_option = pOptTable->poption[end_index];

   /*-------------------------------------------------*/
   /*  Setup the initial index into the state table.  */
   /*-------------------------------------------------*/

   state_index = pOptTable->entry_state;
   if (!Validate_State_Index(pOptTable->max_states))
      return (cc);

   /*--------------------------------------------------------*/
   /*  On return from Locate_First_Slash call pcmdline_slash */
   /*  contains the ptr to the / in the command line.        */
   /*--------------------------------------------------------*/

   pcmdline_start = pCmdLine;
   pcmdline1 = pCmdLine;
   if (!Locate_First_Slash())
      return (cc);

   for (j=0;j < end_index;j++)
   {
      /*--------------------------------------------------------------------*/
      /*  Locate valid options in Option Table, based on state table index. */
      /*--------------------------------------------------------------------*/

      if (pOptTable->poption[j]->state[state_index] != E)
      {
        /*-----------------------------------------------------------*/
        /*  Found a valid option. Check to see if this is the option */
        /*  entered at this point in command line.                   */
        /*-----------------------------------------------------------*/

        ptable_option = pOptTable->poption[j];
        length = strlen(ptable_option->string);
        if (strncmp(pcmdline_slash,ptable_option->string, length) == TRUE)
        {

           /*--------------------------------------------------------*/
           /* Found the command line option.  Now, syntax check its  */
           /* associated value.                                      */
           /*--------------------------------------------------------*/

           if (!Parse_Option_Value())
              return (cc);

           /*----------------------------------------------------------*/
           /* No syntax err detected.  Now, insert the option and its  */
           /* associated value into the output buffer in token format. */
           /*----------------------------------------------------------*/

           if (!Insert_Token())
              return (cc);

           /*-----------------------------------------*/
           /*  Setup next index into the state table. */
           /*-----------------------------------------*/

           state_index = ptable_option->state[state_index];
           if (!Validate_State_Index(pOptTable->max_states))
              return (cc);

           /*-----------------------------------------------------------*/
           /*  Setup cmdline_slash to point the the next / (option) in  */
           /*  the command line.                                        */
           /*  Parsing stops once either an invalid character is        */
           /*  found on the command line or the end of the command line */
           /*  is detected.                                             */
           /*-----------------------------------------------------------*/

           if (!Locate_Next_Slash())
              return (cc);

           /*----------------------------------------------------------------*/
           /* Setup for option search. Point to the top of the Option Table. */
           /*----------------------------------------------------------------*/

           j = -1;

        } /* endif */

      } /* endif */

   } /* endfor */


   if (pend_option->state[state_index] == R)
   {
   /*------------------------------------------------------*/
   /* A required option was not found on the command line. */
   /*------------------------------------------------------*/

      cc.ret_code = REQ_OPT_ERR;
   }
   else
   {
   /*--------------------------------------------------------------------*/
   /* Characters on the command line are not defined in the Option Table */
   /* as a valid option.  All options must start with a / character.     */
   /*--------------------------------------------------------------------*/

      cc.ret_code = INVALID_OPT_ERR;
   }
   cc.err_index = pcmdline_slash-pCmdLine;
   return (cc);

}

/*******************************************************************************
*                                                                              *
*   FUNCTION: Insert the end of token marker into the output buffer            *
*                                                                              *
*******************************************************************************/
STATIC VOID NEAR Insert_End_Token()
{
     *poutbuf1 = TOKL_ID_END;
     *(poutbuf1+1) = TOK_ID_END;
     return;
}

/*******************************************************************************
*                                                                              *
*   FUNCTION: Locate the / on the command line.  All characters entered prior  *
*             to the first / are ignored.  This allows the parser to bypass    *
*             the BASEDEV = xxxxxxxx.xxx portion of the command line.          *
*                                                                              *
*******************************************************************************/
STATIC BOOL NEAR Locate_First_Slash()
{


     while ((*pcmdline1 != '\0') &&
            (*pcmdline1 != '\n') &&
            (*pcmdline1 != '\r'))
     {
         if (*pcmdline1 == '/')
         {
            pcmdline_slash = pcmdline1;
            return(TRUE);
         }

         pcmdline1++;
     }

     cc.err_index = 0;
     cc.ret_code = NO_OPTIONS_FND_ERR;
     if (pend_option->state[state_index] == R)
        cc.ret_code = REQ_OPT_ERR;

     return(FALSE);
}


/*
** @V155162 - Moved strlen() and strncmp() to S506CSUB.C because
**            they are now needed at task time.
*/


/*******************************************************************************
*                                                                              *
*   FUNCTION: Parse the command line for the value assigned to located option  *
*                                                                              *
*******************************************************************************/
STATIC BOOL  NEAR Parse_Option_Value()
{
      pcmdline1 = pcmdline_slash + length;
      Skip_Over_Blanks();

      for (tokv_index = 0; tokv_index <= TOKVBUF_LEN; tokv_index++)
           tokvbuf[tokv_index].byte_value= 0;

      tokv_index = UNDEFINED;

      cc.ret_code = NO_ERR;
      cc.err_index = 0;

      switch (ptable_option->type)
      {
      case TYPE_0:
           break;

      case TYPE_CHAR:
           char_parser();
           break;

      case TYPE_D:
           d_parser();
           break;

      case TYPE_DD:
           dd_parser();
           break;

      case TYPE_DDDD:
           dddd_parser();
           break;

      case TYPE_HH:
           hh_parser();
           break;

      case TYPE_HHHH:
           hhhh_parser();
           break;
#ifdef BBR
      case TYPE_BBR:
           bad_block_parser();
           break;
#endif

      case TYPE_FORMAT:
           format_parser();
           break;

      case TYPE_SCSI_ID:
           scsi_id_parser();
           break;

      case TYPE_GEOMETRY:
           geometry_parser();
           break;

      case TYPE_CHGLINE:
           chgline_parser();
           break;

      default:
           cc.ret_code = UNDEFINED_TYPE_ERR;

      } /* endswitch */

      if (cc.ret_code != NO_ERR)
      {
         cc.err_index = pcmdline1 - pcmdline_start;
         return(FALSE);
      }

      return(TRUE);
}


/*******************************************************************************
*                                                                              *
*   FUNCTION: Skip over all the blank and tab characters                       *
*                                                                              *
*******************************************************************************/
STATIC VOID NEAR Skip_Over_Blanks()
{
     while ((*pcmdline1 == ' ') || (*pcmdline1 == '\t'))
           pcmdline1++;
     return;
}

/*******************************************************************************
*                                                                              *
*   FUNCTION: TYPE_CHAR option parser - scan till blank,tab,cr,new line or     *
*                                       end of string char                     *
*                                                                              *
*******************************************************************************/
STATIC VOID NEAR  char_parser()
{
     while ((*pcmdline1 != '\0') &&
            (*pcmdline1 != '\n') &&
            (*pcmdline1 != '\r') &&
            (*pcmdline1 != '/'))

     {
           tokv_index++;
           tokvbuf[tokv_index].char_value = *pcmdline1;
           pcmdline1++;
     }

     return;
}


/*******************************************************************************
*                                                                              *
*   FUNCTION: TYPE_D option parser - one digit decimal number (d)              *
*                                                                              *
*******************************************************************************/
STATIC VOID NEAR  d_parser()
{
     if ((*pcmdline1 >= '0') && (*pcmdline1 <= '9'))
     {
        tokv_index++;
        tokvbuf[tokv_index].byte_value = *pcmdline1 - '0';
        pcmdline1++;
     }
     else
     {
        cc.ret_code = SYNTAX_ERR;
     }

     return;
}

/*******************************************************************************
*                                                                              *
*   FUNCTION: TYPE_DD option parser - two digit decimal number (dd)            *
*                                                                              *
*******************************************************************************/
STATIC VOID NEAR dd_parser()
{
   USHORT     num;

   num = dd_parsersub();

   if ( cc.ret_code == NO_ERR )
   {
      if ( num < 100 )
      {
         tokv_index++;
         tokvbuf[tokv_index].byte_value = (UCHAR) num;
      }
      else
      {
         cc.ret_code = SYNTAX_ERR;
      }
   }


}
/*******************************************************************************
*                                                                              *
*   FUNCTION: option parser - four digit decimal number ((-)dddd)              *
*                                                                              *
*******************************************************************************/

STATIC VOID NEAR dddd_parser()
{
   USHORT     num;

   num = dd_parsersub();

   if ( cc.ret_code == NO_ERR )
   {
      tokv_index++;
      tokvbuf[tokv_index].byte_value = (UCHAR) num;
      tokv_index++;
      tokvbuf[tokv_index].byte_value = (UCHAR) (num >> 8);
   }

}

/*******************************************************************************
*                                                                              *
*   FUNCTION: option parser -                                                  *
*                                                                              *
*******************************************************************************/

/* STATIC*/ USHORT NEAR dd_parsersub()
{
     INT        i;
     USHORT     n;
     BOOL       flag;
     USHORT     sign = 0;

     if ( *pcmdline1 == '-' )
     {
       sign = 1;
       pcmdline1++;
     }

     n = 0;
     flag = FALSE;

     /*-------------------------------------------------------------*/
     /* Changed from 4 to 5 to allow up to 5 digit drive parameters */
     /*-------------------------------------------------------------*/
     for ( i = 0; i < 5; i++)                                  /* @V182487 */
     {
         if ((*pcmdline1 >= '0') && (*pcmdline1 <= '9'))
         {
            n = 10 * n + *pcmdline1 - '0';
            pcmdline1++;
            flag = TRUE;
         }
         else
         {
            /*--------------------------------------------------*/
            /* Was at least 1 digit found on the command line?  */
            /*--------------------------------------------------*/

            if (flag)
               break;

            cc.ret_code = SYNTAX_ERR;
            return( 0 );
         }
     }


     return ((sign) ? -n : n);
}

/*******************************************************************************
*                                                                              *
*   FUNCTION: TYPE_HH option parser        hh,hh format (h = hex char)         *
*                                                                              *
*******************************************************************************/
STATIC VOID NEAR hh_parser()
{
     /*------------------------------------------------------------*/
     /*  Convert command line HH char and setup token value buffer */
     /*------------------------------------------------------------*/
     if (!HH_Char_To_Byte())
        return;

     Skip_Over_Blanks();
     if (*pcmdline1 != ',')
     {
        cc.ret_code = SYNTAX_ERR;
        return;
     }
     pcmdline1++;
     Skip_Over_Blanks();

     /*------------------------------------------------------------*/
     /*  Convert command line HH char and setup token value buffer */
     /*------------------------------------------------------------*/
     HH_Char_To_Byte();

     return;
}



/*******************************************************************************
*                                                                              *
*   FUNCTION: Convert HH char to byte value                                    *
*                                                                              *
*******************************************************************************/
STATIC BOOL NEAR HH_Char_To_Byte()
{
     BYTE n;
     INT  i;
     BOOL flag;

     n = 0;
     flag = FALSE;

     for ( i = 0; i < 2; i++)
     {
         if ((*pcmdline1 >= '0') && (*pcmdline1 <= '9'))
         {
            n = 16 * n + *pcmdline1 - '0';
            pcmdline1++;
            flag = TRUE;
            continue;
         }

         if ((*pcmdline1 >= 'A') && (*pcmdline1 <= 'F'))
         {
            n = 16 * n + *pcmdline1 - '7';
            pcmdline1++;
            flag = TRUE;
            continue;
         }

         if ((*pcmdline1 >= 'a') && (*pcmdline1 <= 'f'))
         {
            n = 16 * n + *pcmdline1 - 'W';
            pcmdline1++;
            flag = TRUE;
            continue;
         }

         /*-----------------------------------------------------*/
         /* Was at least 1 hex digit found on the command line? */
         /*-----------------------------------------------------*/
         if (flag)
            break;

         cc.ret_code = SYNTAX_ERR;
         return(FALSE);

     }

     tokv_index++;
     tokvbuf[tokv_index].byte_value = n;

     return(TRUE);
}


/*******************************************************************************
*                                                                              *
*   FUNCTION: TYPE_HHHH option parser       hhhh format (h = hex char)         *
*                                                                              *
*******************************************************************************/
STATIC VOID NEAR hhhh_parser()
{
     INT  i;
     BOOL flag;
     NUMBER un_number;

     un_number.n = 0;
     flag = FALSE;

     for ( i = 0; i < 4; i++)
     {
         if ((*pcmdline1 >= '0') && (*pcmdline1 <= '9'))
         {
            un_number.n = 16 * un_number.n + *pcmdline1 - '0';
            pcmdline1++;
            flag = TRUE;
            continue;
         }

         if ((*pcmdline1 >= 'A') && (*pcmdline1 <= 'F'))
         {
            un_number.n = 16 * un_number.n + *pcmdline1 - '7';
            pcmdline1++;
            flag = TRUE;
            continue;
         }

         if ((*pcmdline1 >= 'a') && (*pcmdline1 <= 'f'))
         {
            un_number.n = 16 * un_number.n + *pcmdline1 - 'W';
            pcmdline1++;
            flag = TRUE;
            continue;
         }

         /*------------------------------------------------------*/
         /* Was at least 1 hex digit found on the command line?  */
         /*------------------------------------------------------*/
         if (flag)
            break;

         cc.ret_code = SYNTAX_ERR;
         return;


     }

     tokv_index++;
     tokvbuf[tokv_index].byte_value = un_number.two_bytes.byte1;

     tokv_index++;
     tokvbuf[tokv_index].byte_value = un_number.two_bytes.byte2;

     return;
}

#ifdef BBR
//
// Parse a     block specifier which looks like:
//
//   (hhhhhhhh,hhhh)[,(hhhhhhhh,hhhh)]
//
// The first value is the starting RBA of the     block and second element
// is the number of     blocks to report as bad.  Sequence may be repeated.
//
/* STATIC */ VOID NEAR bad_block_parser()
{
   while( *pcmdline1 == '(' && cc.ret_code == NO_ERR )
   {
      pcmdline1++;   // skip the '('

      // Parse the     block sequence's starting RBA.
      hhhhhhhh_parser();

      if( *pcmdline1 != ',' )
      {
         cc.ret_code = SYNTAX_ERR;
         continue;
      }

      pcmdline1++;   // skip the ','

      // Parse the     block sequence's length.
      hhhh_parser();

      if( *pcmdline1 != ')' )
      {
         cc.ret_code = SYNTAX_ERR;
         continue;
      }

      pcmdline1++;   // skip the ')'

      // Skip seperator between any more     block specifiers.
      if( *pcmdline1 == ',' )
      {
         pcmdline1++;   // skip the ','
      }
   }
}

/*******************************************************************************
*                                                                              *
*   FUNCTION: TYPE_HHHHHHHH option parser       hhhhhhhh format (h = hex char) *
*                                                                              *
*******************************************************************************/
STATIC VOID NEAR hhhhhhhh_parser()
{
     INT  i;
     BOOL flag;
     LNUMBER un_number;

     un_number.n = 0;
     flag = FALSE;

     for ( i = 0; i < 8; i++)
     {
         if ((*pcmdline1 >= '0') && (*pcmdline1 <= '9'))
         {
            un_number.n = 16 * un_number.n + *pcmdline1 - '0';
            pcmdline1++;
            flag = TRUE;
            continue;
         }

         if ((*pcmdline1 >= 'A') && (*pcmdline1 <= 'F'))
         {
            un_number.n = 16 * un_number.n + *pcmdline1 - '7';
            pcmdline1++;
            flag = TRUE;
            continue;
         }

         if ((*pcmdline1 >= 'a') && (*pcmdline1 <= 'f'))
         {
            un_number.n = 16 * un_number.n + *pcmdline1 - 'W';
            pcmdline1++;
            flag = TRUE;
            continue;
         }

         /*------------------------------------------------------*/
         /* Was at least 1 hex digit found on the command line?  */
         /*------------------------------------------------------*/
         if (flag)
            break;

         cc.ret_code = SYNTAX_ERR;
         return;


     }

     tokv_index++;
     tokvbuf[tokv_index].byte_value = un_number.four_bytes.byte1;

     tokv_index++;
     tokvbuf[tokv_index].byte_value = un_number.four_bytes.byte2;

     tokv_index++;
     tokvbuf[tokv_index].byte_value = un_number.four_bytes.byte3;

     tokv_index++;
     tokvbuf[tokv_index].byte_value = un_number.four_bytes.byte4;

     return;
}
#endif

/*******************************************************************************
*                                                                              *
*   FUNCTION: TYPE_FORMAT option parser -  format_table chars accepted         *
*                                                                              *
*******************************************************************************/
STATIC VOID NEAR format_parser()
{

    typedef struct _formattable
     {
         PSZ        string;
         USHORT     type;
         NUMBER     MegBytes;

     } FORMATTABLE;

/* FORMATTABLE type definitions  */
                                    /* accepts # string followed by:    */
#define M_BYTES             1       /* accepts MB,mb,Mb,mB, or nothing  */
#define K_BYTES             2       /* accepts KB,kb,Kb,kB, or nothing  */

       INT  str_len, k;
static FORMATTABLE format_table[] =
     {
      { "360",  K_BYTES, 360},
      { "720",  K_BYTES, 720},
      { "1200", K_BYTES, 1200},
      { "1.2",  M_BYTES, 1200},
      { "1440", K_BYTES, 1440},
      { "1.44", M_BYTES, 1440},
      { "2880", K_BYTES, 2880},
      { "2.88", M_BYTES, 2880},
      { "-1"},
     };

     cc.ret_code = SYNTAX_ERR;
     for (k = 0; (format_table[k].string != "-1"); k++)
     {

         str_len = strlen(format_table[k].string);

         if (strncmp(pcmdline1,format_table[k].string, str_len)
            == TRUE)
         {
            pcmdline1 += str_len;
            if (format_table[k].type == K_BYTES)
            {
               if ((*pcmdline1 == 'K') || (*pcmdline1 == 'k'))
               {
                  ++pcmdline1;

                  if ((*(pcmdline1) == 'B') || (*(pcmdline1) == 'b'))
                     ++pcmdline1;
               }
            }
            else
            {
               if ((*pcmdline1 == 'M') || (*pcmdline1 == 'm'))
               {
                  ++pcmdline1;

                  if ((*(pcmdline1) == 'B') || (*(pcmdline1) == 'b'))
                     ++pcmdline1;
                }
            }

            tokv_index++;
            tokvbuf[tokv_index].byte_value = format_table[k].MegBytes.two_bytes.byte1;
            tokv_index++;
            tokvbuf[tokv_index].byte_value = format_table[k].MegBytes.two_bytes.byte2;

            cc.ret_code = NO_ERR;
            break;
         }
     }
     return;
}

/*******************************************************************************
*                                                                              *
*   FUNCTION: TYPE_SCSI_ID option parser - format d and (d,d) accepted         *
*                                          where d = 0 - 7                     *
*                                                                              *
*******************************************************************************/
STATIC VOID NEAR scsi_id_parser()
{
     BOOL found_bracket, found_one;

     found_bracket = FALSE;
     found_one = FALSE;

     if (*pcmdline1 == '(')
     {
        found_bracket = TRUE;
        pcmdline1++;
        Skip_Over_Blanks();
     }


     while ((*pcmdline1 >= '0') && (*pcmdline1 <= '7'))
     {
           found_one = TRUE;
           tokv_index++;
           tokvbuf[tokv_index].byte_value = *pcmdline1 - '0';
           pcmdline1++;
           if (!found_bracket)
           {
              tokv_index++;
              tokvbuf[tokv_index].byte_value = 0;
           }

           Skip_Over_Blanks();
           if (*pcmdline1 != ',')
           {
              if (found_bracket)
                 cc.ret_code = SYNTAX_ERR;
              return;
           }

           pcmdline1++;
           Skip_Over_Blanks();
           if (found_bracket)
           {
              if ((*pcmdline1 >= '0') && (*pcmdline1 <= '7'))
              {
                 tokv_index++;
                 tokvbuf[tokv_index].byte_value = *pcmdline1 - '0';
                 pcmdline1++;
                 Skip_Over_Blanks();
                 if (*pcmdline1 != ')')
                 {
                   cc.ret_code = SYNTAX_ERR;
                   return;
                 }
                 pcmdline1++;
                 Skip_Over_Blanks();
                 found_bracket = FALSE;

                 if (*pcmdline1 != ',')
                    return;

                 pcmdline1++;
                 Skip_Over_Blanks();
              }
           }

           if (*pcmdline1 == '(')
           {
              found_bracket = TRUE;
              pcmdline1++;
              Skip_Over_Blanks();
           }
     }

     if (found_bracket)
        cc.ret_code = SYNTAX_ERR;

     if (!found_one)
        cc.ret_code = SYNTAX_ERR;

     return;
}


/*******************************************************************************
*                                                                              *
*   FUNCTION: TYPE_GEOMETRY option parser - dd or (dddd,dddd,dddd) accepted    *
*                                                                              *
*******************************************************************************/
/* STATIC */ VOID NEAR geometry_parser()
{
     USHORT i;
     USHORT j;
     USHORT k;

     USHORT GeomType;
     UCHAR  c;

     GeomType = ++tokv_index;

     tokvbuf[tokv_index].byte_value = 0;

     for ( j = 0; j < 2 && cc.ret_code == NO_ERR; j++ )
     {
       if (*pcmdline1 == '(')
       {
         pcmdline1++;

         tokvbuf[GeomType].byte_value |= GEOTYPE_DRIVESPEC << ((!j) ? 4 : 0);

         for ( k=0; k < 4 && cc.ret_code == NO_ERR ; k++ )
         {
           dddd_parser();

           if ( *pcmdline1 == ',' )
           {
              if ( k < 3 )
              {
                pcmdline1++;
              }
              else
              {
                cc.ret_code = SYNTAX_ERR;
                continue;
              }
           }
           else if ( *pcmdline1 == ')' )
           {
             pcmdline1++;
             break;
           }
           else
           {
             cc.ret_code = SYNTAX_ERR;
             break;
           }
         }

         if ( cc.ret_code == NO_ERR )
         {
           if ( k == 2 )
           {
             tokv_index++;
             tokvbuf[tokv_index].byte_value  = -1;
             tokv_index++;
             tokvbuf[tokv_index].byte_value  = -1;
           }
           else if ( k < 2 )
           {
             cc.ret_code = SYNTAX_ERR;
             continue;
           }
         }
       }
       else
       {
         tokvbuf[GeomType].byte_value |= GEOTYPE_DRIVETYPE << ((!j) ? 4 : 0);

         dddd_parser();
         tokv_index += 6;
       }

       if ( !j )
       {
         c = *pcmdline1;
         if ( c == ',')
         {
           pcmdline1++;
         }
         else
         {
           break;
         }
       }
     }
}

/*******************************************************************************
*                                                                              *
*   FUNCTION: TYPE_CHGLINE option parser - Valid options: PS2                  *
*                                                         AT                   *
*                                                         NONE                 *
*                                                                              *
*******************************************************************************/
VOID NEAR chgline_parser()
{

     USHORT     k, str_len;
     NPBYTE     chgline_opts[] = { "\0", "NONE", "AT", "PS2" };

     for (k = 1; k < sizeof(chgline_opts)/sizeof(chgline_opts[0]); k++ )
     {
         str_len = strlen(chgline_opts[k]);

         if ( strncmp(pcmdline1,chgline_opts[k], str_len) )
         {
            pcmdline1 += str_len;
            tokv_index++;
            tokvbuf[tokv_index].byte_value = k;
            return;
         }
     }
     cc.ret_code = SYNTAX_ERR;
     return;
}

/*******************************************************************************
*                                                                              *
*   FUNCTION: Insert the parsed option (token) into the output buffer.         *
*                                                                              *
*******************************************************************************/
STATIC BOOL NEAR Insert_Token()
{
    USHORT t, tok_size;

    tok_size = TOK_MIN_LENGTH + tokv_index;
    if ((poutbuf1 + tok_size + TOKL_ID_END) >= poutbuf_end)
    {
       cc.err_index = pcmdline_slash-pcmdline_start;
       cc.ret_code = BUF_TOO_SMALL_ERR;
       return(FALSE);
    }

    *poutbuf1 = tok_size + 1;
    poutbuf1++;
    *poutbuf1 = ptable_option->id;
    poutbuf1++;

    if (tokv_index != UNDEFINED)
    {
       for (t=0;t <= tokv_index;t++)
       {
           *poutbuf1 = tokvbuf[t].byte_value;
            poutbuf1++;
       }
    }

    Insert_End_Token();

    return(TRUE);
}

/*******************************************************************************
*                                                                              *
*   FUNCTION: Locate the next / char.                                          *
*                                                                              *
*******************************************************************************/
/*STATIC*/ BOOL NEAR Locate_Next_Slash()
{

     while ((*pcmdline1 != '\0') &&
            (*pcmdline1 != '\n') &&
            (*pcmdline1 != '\r'))
     {

           if ((*pcmdline1 == ' ') ||
               (*pcmdline1 == '\t'))
           {
              pcmdline1++;
           }
           else
           {
              if (*pcmdline1 == '/')
              {
                 pcmdline_slash = pcmdline1;
                 return(TRUE);
              }
              else
              {
                 cc.ret_code = INVALID_OPT_ERR;
                 cc.err_index = pcmdline1-pcmdline_start;
                 return(FALSE);
              }
           }

     } /* endwhile */

     if (pend_option->state[state_index] == R)
     {
        cc.ret_code = REQ_OPT_ERR;
        cc.err_index = pcmdline1-pcmdline_start;
     }
     else
     {
        cc.ret_code = NO_ERR;
        cc.err_index = 0;
     }
     return(FALSE);
}


/*******************************************************************************
*                                                                              *
*   FUNCTION: Validate the State Index                                         *
*                                                                              *
*******************************************************************************/
STATIC BOOL NEAR Validate_State_Index(maxstate)

USHORT  maxstate;
{

   if ((state_index > maxstate) ||
       (state_index < 0))
   {
      cc.ret_code = UNDEFINED_STATE_ERR;
      cc.err_index = 0;
      return(FALSE);
   }

   return(TRUE);
}

