/*static char *SCCSID = "src/dev/dasd/ibm/ibm1s506/cmdparse.c, idsk, basedd, initial 93/03/18";*/
/**************************************************************************
 *
 * SOURCE FILE NAME = CMDPARSE.C
 *
 * DESCRIPTIVE NAME =  IBM1S506.ADD - Adapter Driver for ST506/IDE DASD
 *
 *
 * Copyright : COPYRIGHT IBM CORPORATION, 1991, 1992
 *             LICENSED MATERIAL - PROGRAM PROPERTY OF IBM
 *             REFER TO COPYRIGHT INSTRUCTION FORM#G120-2083
 *             RESTRICTED MATERIALS OF IBM
 *             IBM CONFIDENTIAL
 *
 * 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.
 *
 *
 *
 * CHANGE ACTIVITY =
 *   DATE      FLAG        APAR   CHANGE DESCRIPTION
 *   --------  ----------  -----  --------------------------------------
 *   mm/dd/yy  @Vnnnnn     XXXXX  XXXXXXX
 *
 ****************************************************************************/


 #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 "cmdproto.h"
 #include "cmdphdr.h"
#define TOKVBUF_LEN 255
#define UNDEFINED   -1

extern CC           cc;


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

CC FAR Command_Parser(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 = strglen(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);
}

/*******************************************************************************
*                                                                              *
*   FUNCTION: Return the length of a string                                    *
*                                                                              *
*******************************************************************************/
INT  NEAR strglen(CHAR FAR *s)

{
     INT i;

     for (i = 0; *s != '\0' ; s++)
         i++;

     return(i);
}

/*******************************************************************************
*                                                                              *
*   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: Compare n number of characters in 2 strings, return TRUE if =    *
*             If s1 is in lower case, convert to upper prior to comparing.     *
*                                                                              *
*******************************************************************************/
BOOL NEAR strncmp(CHAR FAR *s1,CHAR FAR *s2,INT n)

// CHAR FAR *s1, FAR *s2;
{
     INT i;
     CHAR temp;

     for (i=0;i < n;i++,s1++,s2++)

         if (*s1 != *s2)
         {
            if ((*s1 >= 'a') && (*s1 <= 'z'))
            {
               temp = *s1 - ' ';
               if (temp == *s2)
                  continue;
            }
            return(FALSE);
         }

     return(TRUE);
}


/*******************************************************************************
*                                                                              *
*   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;


      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: 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(USHORT maxstate)
{

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

   return(TRUE);
}
