/*
 * console.c
 *
 * Copyright 2001-2009 Texas Instruments, Inc. - http://www.ti.com/
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and  
 * limitations under the License.
 */

/****************************************************************************
*
*   MODULE:  console.c
*   
*   PURPOSE: 
* 
*   DESCRIPTION:  
*   ============
*      
*
****************************************************************************/

/* includes */
/************/
#include <stdio.h>
#include "cu_osapi.h"
#include "console.h"
#include "cu_cmd.h"

/* defines */
/***********/
#define INBUF_LENGTH            2100
#define MAX_NAME_LEN        64
#define MAX_HELP_LEN        40
#define MAX_PARM_LEN        20
#define ALIAS_LEN           1

#define TOKEN_UP           ".."
#define TOKEN_ROOT         "/"
#define TOKEN_BREAK        "#"
#define TOKEN_HELP         "?"
#define TOKEN_DIRHELP      "help"
#define TOKEN_QUIT         "q1"

/* local types */
/***************/

typedef enum 
{ 
    Dir, 
    Token
} ConEntry_type_t;

/* Token types */
typedef enum
{
    EmptyToken,
    UpToken,
    RootToken,
    BreakToken,
    HelpToken,
    DirHelpToken,
    QuitToken,
    NameToken
} TokenType_t;


/* Monitor token structure */
typedef struct ConEntry_t
{
    struct ConEntry_t   *next;
    S8                  name[MAX_NAME_LEN+1];    /* Entry name */
    S8                  help[MAX_HELP_LEN+1];    /* Help string */
    PS8                 alias;                  /* Alias - always in upper case*/
    ConEntry_type_t     sel;                   /* Entry selector */
    
    union 
    {
        struct
        {
            struct ConEntry_t   *upper;            /* Upper directory */
            struct ConEntry_t   *first;            /* First entry */
        } dir;
        struct t_Token
        {
            FuncToken_t    f_tokenFunc;            /* Token handler */
            S32            totalParams;
            ConParm_t      *parm;                  /* Parameters array with totalParams size */
            PS8            *name;                 /* Parameter name with totalParams size */
        } token;
    } u;
} ConEntry_t;

/* Module control block */
typedef struct Console_t
{
    THandle hCuCmd;

    S32 isDeviceOpen;
    
    ConEntry_t *p_mon_root;
    ConEntry_t *p_cur_dir;
    PS8         p_inbuf;
    volatile S32 stop_UI_Monitor;
} Console_t;

/* local variables */
/*******************/

/* local fucntions */
/*******************/
static VOID Console_allocRoot(Console_t* pConsole);
int consoleRunScript( char *script_file, THandle hConsole);


/* Remove leading blanks */
static PS8 Console_ltrim(PS8 s)
{
    while( *s == ' ' || *s == '\t' ) s++;
    return s;
}

/* 
Make a preliminary analizis of <name> token.
Returns a token type (Empty, Up, Root, Break, Name)
*/
static TokenType_t Console_analizeToken( PS8 name )
{
    if (!name[0])
        return EmptyToken;
    
    if (!os_strcmp(name, (PS8)TOKEN_UP ) )
        return UpToken;
    
    if (!os_strcmp(name, (PS8)TOKEN_ROOT ) )
        return RootToken;
    
    if (!os_strcmp(name, (PS8)TOKEN_BREAK ) )
        return BreakToken;
    
    if (!os_strcmp(name, (PS8)TOKEN_HELP ) )
        return HelpToken;
    
    if (!os_strcmp(name, (PS8)TOKEN_DIRHELP ) )
        return DirHelpToken;
    
    if (!os_strcmp(name, (PS8)TOKEN_QUIT ) )
        return QuitToken;

    return NameToken;
    
}

/* Compare strings case insensitive */
static S32 Console_stricmp( PS8 s1, PS8 s2, U16 len )
{
    S32  i;
    
    for( i=0; i<len && s1[i] && s2[i]; i++ )
    {
        if (os_tolower(s1[i])  != os_tolower(s2[i] ))
            break;
    }
    
    return ( (len - i) * (s1[i] - s2[i]) );
}

/* Convert string s to lower case. Return pointer to s */
static PS8 Console_strlwr( PS8 s )
{
    PS8 s0=s;
    
    while( *s )
    {
        *s = (S8)os_tolower(*s );
        ++s;
    }
    
    return s0;
}

/* free the entries tree */
static VOID Console_FreeEntry(ConEntry_t *pEntry)
{   
    ConEntry_t *pEntryTemp,*pEntryTemp1;
    
    if(pEntry->sel == Dir)
    {
        pEntryTemp = pEntry->u.dir.first;

        while (pEntryTemp)
        {
            pEntryTemp1 = pEntryTemp->next;
            Console_FreeEntry(pEntryTemp);
            pEntryTemp = pEntryTemp1;
        }
    }

    /* free the current entry */
    os_MemoryFree(pEntry);
}


/* Allocate root directory */
static VOID Console_allocRoot(Console_t* pConsole)
{   
    /* The very first call. Allocate root structure */
    if ((pConsole->p_mon_root=(ConEntry_t *)os_MemoryCAlloc(sizeof( ConEntry_t ), 1) ) == NULL)
    {
        os_error_printf(CU_MSG_ERROR, (PS8)( "ERROR - Console_allocRoot(): cant allocate root\n") );
        return;
    }
    os_strcpy((PS8)pConsole->p_mon_root->name, (PS8)("\\") );
    pConsole->p_mon_root->sel = Dir;
    pConsole->p_cur_dir = pConsole->p_mon_root;
}

/* Display current directory */
static VOID Console_displayDir(Console_t* pConsole)
{
    S8 out_buf[512];
    ConEntry_t *p_token;
    ConEntry_t *p_dir = pConsole->p_cur_dir;

    os_sprintf((PS8)out_buf, (PS8)("%s%s> "), (PS8)(p_dir==pConsole->p_mon_root)? (PS8)("") : (PS8)(".../"), (PS8)p_dir->name );
    p_token = p_dir->u.dir.first;
    while( p_token )
    {
        if( (os_strlen(out_buf) + os_strlen(p_token->name) + 2)>= sizeof(out_buf) )
        {
            os_error_printf(CU_MSG_ERROR, ( (PS8)"ERROR - Console_displayDir(): buffer too small....\n") );
            break;
        }
        os_strcat(out_buf, p_token->name );
        if ( p_token->sel == Dir )
            os_strcat((PS8)out_buf, (PS8)("/" ) );
        p_token = p_token->next;
        if (p_token)
            os_strcat((PS8)out_buf, (PS8)(", ") );
    }
    
    os_error_printf(CU_MSG_INFO2, (PS8)("%s\n"), (PS8)out_buf );   
}


/* 
Cut the first U16 from <p_inbuf>.
Return the U16 in <name> and updated <p_inbuf>
*/
static TokenType_t Console_getWord(Console_t* pConsole, PS8 name, U16 len )
{
    U16         i=0;
    TokenType_t tType;  
    
    pConsole->p_inbuf = Console_ltrim(pConsole->p_inbuf);
    
    while( *pConsole->p_inbuf && *pConsole->p_inbuf!=' ' && i<len )
        name[i++] = *(pConsole->p_inbuf++);     
    
    if (i<len)
        name[i] = 0;
    
    tType   = Console_analizeToken( name );
    
    return tType;
}

static TokenType_t Console_getStrParam(Console_t* pConsole, PS8 buf, ConParm_t *param )
{
    TokenType_t tType;
    U32         i, len = param->hi_val;
    PS8         end_buf;
    
    pConsole->p_inbuf = Console_ltrim(pConsole->p_inbuf);
    
    if( param->flags & CON_PARM_LINE )
    {
        os_strcpy(buf, (PS8)pConsole->p_inbuf );
        pConsole->p_inbuf += os_strlen(pConsole->p_inbuf);
    }
    else
    {
        if( *pConsole->p_inbuf == '\"' )
        {
            end_buf = os_strchr(pConsole->p_inbuf+1, '\"' );
            if( !end_buf )
            {
                os_error_printf(CU_MSG_ERROR, (PS8)("ERROR - invalid string param: '%s'\n"), (PS8)pConsole->p_inbuf );
                pConsole->p_inbuf += os_strlen(pConsole->p_inbuf);
                return EmptyToken;
            }
            if( (end_buf - pConsole->p_inbuf - 1) > (int)len )
            {
                os_error_printf(CU_MSG_ERROR, (PS8)("ERROR - param is too long: '%s'\n"), (PS8)pConsole->p_inbuf );
                pConsole->p_inbuf += os_strlen(pConsole->p_inbuf);
                return EmptyToken;
            }
            *end_buf = 0;
            os_strcpy( buf, (PS8)(pConsole->p_inbuf+1 ) );
            pConsole->p_inbuf = end_buf + 1;
        }
        else
        {
            for( i=0; *pConsole->p_inbuf && *pConsole->p_inbuf!=' ' && i<len; i++ )
                buf[i] = *(pConsole->p_inbuf++);
            
            buf[i] = 0;
            if( *pConsole->p_inbuf && *pConsole->p_inbuf != ' ' )
            {
                os_error_printf(CU_MSG_ERROR, (PS8)("ERROR - param is too long: '%s'\n"), (PS8)( pConsole->p_inbuf-os_strlen( buf) ) );
                pConsole->p_inbuf += os_strlen(pConsole->p_inbuf);
                return EmptyToken;
            }
        }
    }
    
    tType   = Console_analizeToken( buf );
    
    return tType;
}

/* Returns number of parameters of the given token
*/
static U16 Console_getNParms( ConEntry_t *p_token )
{
    U16 i;
    if ( !p_token->u.token.parm )
        return 0;
    for( i=0;
         (i<p_token->u.token.totalParams) &&
          p_token->u.token.parm[i].name &&
          p_token->u.token.parm[i].name[0];
         i++ )
        ;
    return i;
}

/* Parse p_inbuf string based on parameter descriptions in <p_token>.
Fill parameter values in <p_token>.
Returns the number of parameters filled.
To Do: add a option of one-by-one user input of missing parameters.
*/
static S32 Console_parseParms(Console_t* pConsole, ConEntry_t *p_token, U16 *pnParms )
{
    U16 nTotalParms = Console_getNParms( p_token );
    U16 nParms=0;
    PS8 end_buf = NULL;
    S8  parm[INBUF_LENGTH];
    U16 i, print_params = 0;
    U32 val = 0;
    S32 sval = 0;
    
    /* Mark all parameters as don't having an explicit value */
    for( i=0; i<nTotalParms; i++ )
        p_token->u.token.parm[i].flags |= CON_PARM_NOVAL;

    /*        -----------------              */
    pConsole->p_inbuf = Console_ltrim(pConsole->p_inbuf);
    if( pConsole->p_inbuf[0] == '!' && pConsole->p_inbuf[1] == '!' )
    {
        pConsole->p_inbuf += 2; print_params = 1;
    }
    /*        -----------------              */

    /* Build a format string */
    for( i=0; i<nTotalParms; i++ )
    {
        if (p_token->u.token.parm[i].flags & (CON_PARM_STRING | CON_PARM_LINE) )
        {
            /* For a string parameter value is the string address */
            /* and hi_val is the string length                   */
            if (Console_getStrParam(pConsole, parm, &p_token->u.token.parm[i] ) != NameToken)
                break;
            if( os_strlen( parm) > p_token->u.token.parm[i].hi_val ||
                (p_token->u.token.parm[i].low_val && p_token->u.token.parm[i].low_val > os_strlen( parm) ) )
            {
                os_error_printf(CU_MSG_ERROR, (PS8)("ERROR - param '%s' must be %ld..%ld chars\n"), (PS8)p_token->u.token.parm[i].name,
                    (PS8)p_token->u.token.parm[i].low_val, (PS8)p_token->u.token.parm[i].hi_val);
                return FALSE;               
            }
            os_strcpy((PS8)(char *)p_token->u.token.parm[i].value, (PS8)parm);
        }
        else
        {
            if (Console_getWord(pConsole, parm, MAX_PARM_LEN ) != NameToken)
                break;
            
            if (p_token->u.token.parm[i].flags & CON_PARM_SIGN)
            {
                sval = os_strtol( parm, &end_buf, 0 );
            }
            else
            {
                val = os_strtoul( parm, &end_buf, 0 );
            }
            if( end_buf <= parm )
                break;

            /* Check value */
            if (p_token->u.token.parm[i].flags & CON_PARM_RANGE)
            {        
                if (p_token->u.token.parm[i].flags & CON_PARM_SIGN)
                {
                    if ((sval < (S32)p_token->u.token.parm[i].low_val) ||
                        (sval > (S32)p_token->u.token.parm[i].hi_val) )
                    {
                        os_error_printf(CU_MSG_ERROR, (PS8)("%s: %d out of range (%d, %d)\n"),
                            (PS8)p_token->u.token.parm[i].name, (int)sval,
                            (int)p_token->u.token.parm[i].low_val, (int)p_token->u.token.parm[i].hi_val );
                        return FALSE;
                    }
                    
                }
                else
                {                    
                    if ((val < p_token->u.token.parm[i].low_val) ||
                        (val > p_token->u.token.parm[i].hi_val) )
                    {
                        os_error_printf(CU_MSG_ERROR , (PS8)("%s: %ld out of range (%ld, %ld)\n"),
                            (PS8)p_token->u.token.parm[i].name, (PS8)val,
                            (PS8)p_token->u.token.parm[i].low_val, (PS8)p_token->u.token.parm[i].hi_val );
                        return FALSE;
                    }
                }
            }
            
            if (p_token->u.token.parm[i].flags & CON_PARM_SIGN)                
                p_token->u.token.parm[i].value = sval;
            else
                p_token->u.token.parm[i].value = val;
        }

        p_token->u.token.parm[i].flags &= ~CON_PARM_NOVAL;
        ++nParms;
    }

    /* Process default values */
    for( ; i<nTotalParms; i++ )
    {
        if ((p_token->u.token.parm[i].flags & CON_PARM_DEFVAL) != 0)
        {
            p_token->u.token.parm[i].flags &= ~CON_PARM_NOVAL;
            ++nParms;
        }
        else if (!(p_token->u.token.parm[i].flags & CON_PARM_OPTIONAL) )
        {
            /* Mandatory parameter missing */
            return FALSE;
        }
    }

    if( print_params )
    {
        os_error_printf((S32)CU_MSG_INFO2, (PS8)("Params: %d\n"), nParms );
        for (i=0; i<nParms; i++ )
        {
            os_error_printf(CU_MSG_INFO2, (PS8)("%d: %s - flags:%d"), 
                i+1, (PS8)p_token->u.token.parm[i].name,
                p_token->u.token.parm[i].flags);
            
            if (p_token->u.token.parm[i].flags & CON_PARM_SIGN)  
                os_error_printf(CU_MSG_INFO2, (PS8)("min:%d, max:%d, value:%d "),(PS8)p_token->u.token.parm[i].low_val, (PS8)p_token->u.token.parm[i].hi_val,
                (PS8)p_token->u.token.parm[i].value);
            else
                os_error_printf(CU_MSG_INFO2, (PS8)("min:%ld, max:%ld, value:%ld "),(PS8)p_token->u.token.parm[i].low_val, (PS8)p_token->u.token.parm[i].hi_val,
                (PS8)p_token->u.token.parm[i].value);
            
            os_error_printf(CU_MSG_INFO2, (PS8)("(%#lx)"),(PS8)p_token->u.token.parm[i].value );
            
            if( p_token->u.token.parm[i].flags & (CON_PARM_LINE | CON_PARM_STRING ))
            {
                os_error_printf(CU_MSG_INFO2, (PS8)(" - '%s'"), (PS8)(char *) p_token->u.token.parm[i].value );
            }
            os_error_printf(CU_MSG_INFO2, (PS8)("\n") );
        }
        
    }
    *pnParms = nParms;

    return TRUE;
}

/* Serach a token by name in the current directory */
static ConEntry_t *Console_searchToken( ConEntry_t *p_dir, PS8 name )
{
    ConEntry_t *p_token;
    U16        name_len = (U16)os_strlen( name );
    
    /* Check alias */
    p_token = p_dir->u.dir.first;
    while( p_token )
    {
        if (p_token->alias &&
            (name_len == ALIAS_LEN) &&
            !Console_stricmp( p_token->alias, name, ALIAS_LEN ) )
            return p_token;
        p_token = p_token->next;
    }
    
    /* Check name */
    p_token = p_dir->u.dir.first;
    while( p_token )
    {
        if (!Console_stricmp( p_token->name, name, name_len ) )
            break;
        p_token = p_token->next;
    }
    
    return p_token;
}


/* Display help for each entry in the current directory */
VOID  Console_dirHelp(Console_t* pConsole)
{
    ConEntry_t *p_token;
    S8        print_str[80];
    
    p_token = pConsole->p_cur_dir->u.dir.first;
    
    while( p_token )
    {
        if (p_token->sel == Dir)
            os_sprintf( print_str, (PS8)"%s: directory\n", (PS8)p_token->name );
        else
            os_sprintf( print_str, (PS8)("%s(%d parms): %s\n"),
            (PS8)p_token->name, Console_getNParms(p_token), p_token->help );
        os_error_printf(CU_MSG_INFO2,  (PS8)print_str );
        p_token = p_token->next;
    }
    
    os_error_printf(CU_MSG_INFO2, (PS8)("Type ? <name> for command help, \"/\"-root, \"..\"-upper\n") );
}


/* Display help a token */
static VOID  Console_displayHelp(Console_t* pConsole, ConEntry_t *p_token )
{
    S8 bra, ket;
    U16 nTotalParms = Console_getNParms( p_token );
    U16 i;
    
    
    os_error_printf(CU_MSG_INFO2, (PS8)("%s: %s "), (PS8)p_token->help, (PS8)p_token->name );
    for( i=0; i<nTotalParms; i++ )
    {
        if (p_token->u.token.parm[i].flags & CON_PARM_OPTIONAL)
        {
            bra = '['; ket=']';
        }
        else
        {
            bra = '<'; ket='>';
        }
        os_error_printf(CU_MSG_INFO2, (PS8)("%c%s"), bra, (PS8)p_token->u.token.parm[i].name );
        if (p_token->u.token.parm[i].flags & CON_PARM_DEFVAL)
        {
            os_error_printf(CU_MSG_INFO2, (PS8)("=%lu"), (PS8)p_token->u.token.parm[i].value);
        }
        if (p_token->u.token.parm[i].flags & CON_PARM_RANGE)
        {
            os_error_printf(CU_MSG_INFO2, (PS8)(p_token->u.token.parm[i].flags & CON_PARM_SIGN) ? (PS8)(" (%d..%d%s)") : (PS8)(" (%lu..%lu%s)"),
                (PS8)p_token->u.token.parm[i].low_val,
                (PS8)p_token->u.token.parm[i].hi_val,
                (PS8)(p_token->u.token.parm[i].flags & (CON_PARM_STRING | CON_PARM_LINE)) ? (PS8)(" chars") : (PS8)("") );
            
        }
        os_error_printf(CU_MSG_INFO2, (PS8)("%c \n"),ket );
    }
}

/* Choose unique alias for <name> in <p_dir> */
/* Currently only single-character aliases are supported */
static S32 Console_chooseAlias( ConEntry_t *p_dir, ConEntry_t *p_new_token )
{
    ConEntry_t *p_token;
    S32         i;
    S8          c;
    PS8         new_alias = NULL;
    
    /* find alias given from user */
    for(i=0; p_new_token->name[i]; i++ )
    {
        if( os_isupper( p_new_token->name[i]) )
        {
            new_alias = &p_new_token->name[i];
            break;
        }
    }
    
    Console_strlwr( p_new_token->name );
    
    if( new_alias )
    {
        p_token = p_dir->u.dir.first;
        
        while( p_token )
        {
            if (p_token->alias && (os_tolower(*p_token->alias ) == *new_alias) )
            {
                os_error_printf(CU_MSG_ERROR, (PS8)("Error - duplicated alias '%c' in <%s> and <%s>**\n"), *new_alias,
                    (PS8)p_token->name, (PS8)p_new_token->name );
                return 0;
            }
            p_token = p_token->next;
        }
        *new_alias = (S8)os_toupper(*new_alias);
        p_new_token->alias = new_alias;
        return 1;
    }
    
    i = 0;
    while( p_new_token->name[i] )
    {
        c = p_new_token->name[i];
        p_token = p_dir->u.dir.first;
        
        while( p_token )
        {
            if (p_token->alias &&
                (os_tolower(*p_token->alias ) == c) )
                break;
            p_token = p_token->next;
        }
        if (p_token)
            ++i;
        else
        {
            p_new_token->name[i] = (S8)os_toupper( c );
            p_new_token->alias   = &p_new_token->name[i];
            break;
        }
    }
    return 1;
}

/* Parse the given input string and exit.
All commands in the input string are executed one by one.
*/
static U8 Console_ParseString(Console_t* pConsole, PS8 input_string )
{
    ConEntry_t  *p_token;
    S8          name[MAX_NAME_LEN];
    TokenType_t tType;
    U16         nParms; 
        
    if (!pConsole->p_mon_root)
        return 1;

    if(!pConsole->isDeviceOpen)
    {
        Console_GetDeviceStatus(pConsole);
        if(!pConsole->isDeviceOpen)
        {
            os_error_printf(CU_MSG_ERROR, (PS8)("ERROR - Console_ParseString - Device isn't loaded !!!\n") );
            return 1;
        }
    }
    
    if( input_string[os_strlen( input_string)-1] == '\n' )
    {
        PS8 s = &input_string[os_strlen( input_string)-1];
        *s = 0;
    }
    pConsole->p_inbuf = input_string;
    pConsole->stop_UI_Monitor = FALSE;

    /* Interpret empty string as "display directory" */
    if ( pConsole->p_inbuf && !*pConsole->p_inbuf )
        Console_displayDir(pConsole);
    
    while(!pConsole->stop_UI_Monitor && pConsole->p_inbuf && *pConsole->p_inbuf)
    {
        tType = Console_getWord(pConsole, name, MAX_NAME_LEN );
        switch( tType )
        {
            
        case NameToken:
            p_token = Console_searchToken( pConsole->p_cur_dir, name );
            if (p_token == NULL)
            {
                os_error_printf(CU_MSG_ERROR, (PS8)("**Error: '%s'**\n"),name);
                pConsole->p_inbuf = NULL;
            }
            else if (p_token->sel == Dir)
            {
                pConsole->p_cur_dir = p_token;
                Console_displayDir(pConsole);
            }
            else
            {  /* Function token */
                if (!Console_parseParms(pConsole, p_token, &nParms ))
                {
                    Console_displayHelp(pConsole, p_token );
                }
                else
                {
                    p_token->u.token.f_tokenFunc(pConsole->hCuCmd, p_token->u.token.parm, nParms );
                }
            }
            break;
            
        case UpToken: /* Go to upper directory */
            if (pConsole->p_cur_dir->u.dir.upper)
                pConsole->p_cur_dir = pConsole->p_cur_dir->u.dir.upper;
            Console_displayDir(pConsole);
            break;
            
        case RootToken: /* Go to the root directory */
            if (pConsole->p_cur_dir->u.dir.upper)
                pConsole->p_cur_dir = pConsole->p_mon_root;
            Console_displayDir(pConsole);
            break;
            
        case HelpToken: /* Display help */
            if (( Console_getWord(pConsole, name, MAX_NAME_LEN ) == NameToken ) &&
                ((p_token = Console_searchToken( pConsole->p_cur_dir, name )) != NULL ) &&
                (p_token->sel == Token) )
                Console_displayHelp(pConsole, p_token);
            else
                Console_dirHelp(pConsole);
            break;
            
        case DirHelpToken:
            Console_displayDir(pConsole);
            os_error_printf(CU_MSG_INFO2, (PS8)("Type ? <name> for command help, \"/\"-root, \"..\"-upper\n") );
            break;
            
        case BreakToken: /* Clear buffer */
            pConsole->p_inbuf = NULL;
            break;
            
        case QuitToken: /* Go to upper directory */
			return 1;

        case EmptyToken:
            break;
            
        }
    }
	return 0;
}

/* functions */
/*************/

THandle Console_Create(const PS8 device_name, S32 BypassSupplicant, PS8 pSupplIfFile)
{
    Console_t* pConsole = (Console_t*)os_MemoryCAlloc(sizeof(Console_t), sizeof(U8));
    if(pConsole == NULL)
    {
        os_error_printf(CU_MSG_ERROR, (PS8)("Error - Console_Create - cant allocate control block\n") );
        return NULL;
    }

    pConsole->hCuCmd = CuCmd_Create(device_name, pConsole, BypassSupplicant, pSupplIfFile);
    if(pConsole->hCuCmd == NULL)
    {   
        Console_Destroy(pConsole);
        return NULL;
    }

    Console_allocRoot(pConsole);

    pConsole->isDeviceOpen = FALSE;

    return pConsole;
}

VOID Console_Destroy(THandle hConsole)
{
    Console_t* pConsole = (Console_t*)hConsole;

    if(pConsole->hCuCmd)
    {
        CuCmd_Destroy(pConsole->hCuCmd);
    }
    if (pConsole->p_mon_root)
    {
    Console_FreeEntry(pConsole->p_mon_root);
    }
    os_MemoryFree(pConsole);
}

VOID Console_Stop(THandle hConsole)
{   
    ((Console_t*)hConsole)->stop_UI_Monitor = TRUE;
}

/* Monitor driver */
VOID Console_Start(THandle hConsole)
{
    Console_t* pConsole = (Console_t*)hConsole;
    S8  inbuf[INBUF_LENGTH];
    S32 res;
        
    if (!pConsole->p_mon_root)
        return;

    pConsole->stop_UI_Monitor = FALSE;
    Console_displayDir(pConsole);
    
    while(!pConsole->stop_UI_Monitor)
    {
        /* get input string */
        res = os_getInputString(inbuf, sizeof(inbuf));
        if (res == FALSE) 
        {
            if(pConsole->stop_UI_Monitor)
            {
                continue;
            }
            else
            {
                return;
            }
        }   

        if(res == OS_GETINPUTSTRING_CONTINUE)
            continue;

        /* change to NULL terminated strings */
        if( inbuf[os_strlen(inbuf)-1] == '\n' )
            inbuf[os_strlen(inbuf)-1] = 0;
        
        /* parse the string */
        Console_ParseString(pConsole, inbuf);
    }

}

VOID Console_GetDeviceStatus(THandle hConsole)
{
    Console_t* pConsole = (Console_t*)hConsole;

    if(OK == CuCmd_GetDeviceStatus(pConsole->hCuCmd))
    {
        pConsole->isDeviceOpen = TRUE;
    }
}


/***************************************************************

  Function : consoleAddDirExt
  
    Description: Add subdirectory
    
      Parameters: p_root - root directory handle (might be NULL)
      name   - directory name
      
        Output:  the new created directory handle
        =NULL - failure
***************************************************************/
THandle Console_AddDirExt(THandle  hConsole,
                          THandle   hRoot,         /* Upper directory handle. NULL=root */
                          const PS8  name,          /* New directory name */
                          const PS8  desc )         /* Optional dir description */
{
    Console_t* pConsole = (Console_t*)hConsole;
    ConEntry_t *p_root = (ConEntry_t *)hRoot;
    ConEntry_t *p_dir;
    ConEntry_t **p_e;
    
    if (!p_root)
        p_root = pConsole->p_mon_root;
    
    if(!( p_root && (p_root->sel == Dir)))
        return NULL;
    
    if ( (p_dir=(ConEntry_t *)os_MemoryAlloc(sizeof( ConEntry_t )) ) == NULL)
        return NULL;
    
    os_memset( p_dir, 0, sizeof( ConEntry_t ) );
    os_strncpy( p_dir->name, name, MAX_NAME_LEN );
    os_strncpy( p_dir->help, desc, MAX_HELP_LEN );
    p_dir->sel = Dir;
    
    Console_chooseAlias( p_root, p_dir );
    
    /* Add new directory to the root's list */
    p_dir->u.dir.upper = p_root;
    p_e = &(p_root->u.dir.first);
    while (*p_e)
        p_e = &((*p_e)->next);
    *p_e = p_dir;
    
    return p_dir;
}

/***************************************************************

  Function : consoleAddToken
  
    Description: Add token
    
      Parameters: p_dir  - directory handle (might be NULL=root)
      name   - token name
      help   - help string
      p_func - token handler
      p_parms- array of parameter descriptions.
      Must be terminated with {0}.
      Each parm descriptor is a struct
      { "myname",         - name
      10,               - low value
      20,               - high value
      0 }               - default value =-1 no default
      or address for string parameter
      
        Output:  E_OK - OK
        !=0 - error
***************************************************************/
consoleErr Console_AddToken(  THandle hConsole,
                                THandle      hDir,
                                const PS8     name,
                                const PS8     help,
                                FuncToken_t   p_func,
                                ConParm_t     p_parms[] )
{
    Console_t* pConsole = (Console_t*)hConsole;
    ConEntry_t *p_dir = (ConEntry_t *)hDir;
    ConEntry_t *p_token;
    ConEntry_t **p_e;       
    U16       i;

    if (!pConsole->p_mon_root)
      Console_allocRoot(pConsole);

    if (!p_dir)
      p_dir = pConsole->p_mon_root;
    
    if(!( p_dir && (p_dir->sel == Dir)))
        return E_ERROR;
    
    
    /* Initialize token structure */
    if((p_token = (ConEntry_t *)os_MemoryCAlloc(1,sizeof(ConEntry_t))) == NULL)
    {
     os_error_printf(CU_MSG_ERROR, (PS8)("** no memory **\n") );
      return E_NOMEMORY;
    }
    
    
    /* Copy name */
    os_strncpy( p_token->name, name, MAX_NAME_LEN );
    os_strncpy( p_token->help, help, MAX_HELP_LEN );
    p_token->sel = Token;
    p_token->u.token.f_tokenFunc = p_func;
    p_token->u.token.totalParams = 0;
    
    /* Convert name to lower case and choose alias */
    Console_chooseAlias( p_dir, p_token );
    
    /* Copy parameters */
    if ( p_parms )
    {
       ConParm_t     *p_tmpParms = p_parms; 
       
       /* find the number of params */
       while( p_tmpParms->name && p_tmpParms->name[0] )
       {
            p_token->u.token.totalParams++;
            p_tmpParms++;
       }
       /* allocate the parameters info */
       p_token->u.token.parm = (ConParm_t *)os_MemoryAlloc(p_token->u.token.totalParams * sizeof(ConParm_t));
       p_token->u.token.name = (PS8*)os_MemoryAlloc(p_token->u.token.totalParams * sizeof(PS8));
       if ((p_token->u.token.parm == NULL) || (p_token->u.token.name == NULL))
       {
            os_error_printf(CU_MSG_ERROR, (PS8)("** no memory for params\n") );
            os_MemoryFree(p_token);
            return E_NOMEMORY;
       }
       for (i=0; i < p_token->u.token.totalParams; i++)
       {
         ConParm_t *p_token_parm = &p_token->u.token.parm[i];
    
         /* String parameter must have an address */
         if(p_parms->flags & (CON_PARM_STRING | CON_PARM_LINE))
         {
            if ( p_parms->hi_val >= INBUF_LENGTH )
            {
               os_error_printf(CU_MSG_ERROR, (PS8)("** buffer too big: %s/%s\n"), p_dir->name, name);
                os_MemoryFree(p_token->u.token.parm);
                os_MemoryFree(p_token->u.token.name);
                os_MemoryFree(p_token);
                return E_NOMEMORY;
    
            }
            if (p_parms->hi_val == 0 || (p_parms->flags & CON_PARM_RANGE) )
            {
               os_error_printf(CU_MSG_ERROR, (PS8)("** Bad string param definition: %s/%s\n"), p_dir->name, name );
                os_MemoryFree(p_token->u.token.parm);
                os_MemoryFree(p_token->u.token.name);
                os_MemoryFree(p_token);
                return E_BADPARM;
            }
            p_parms->value = (U32)os_MemoryCAlloc(1,p_parms->hi_val+1);
            if( !p_parms->value )
            {
                os_error_printf(CU_MSG_ERROR, (PS8)("** No memory: %s/%s (max.size=%ld)\n"), p_dir->name, name, p_parms->hi_val );
                os_MemoryFree(p_token->u.token.parm);
                os_MemoryFree(p_token->u.token.name);
                os_MemoryFree(p_token);
                return E_NOMEMORY;
            }
        }
    
        /* Copy parameter */
        *p_token_parm = *p_parms;
        if( p_token_parm->hi_val || p_token_parm->low_val )
            p_token_parm->flags |= CON_PARM_RANGE;
         
        p_token->u.token.name[i] = os_MemoryAlloc(os_strlen(p_parms->name));  
        if (p_token->u.token.name[i] == NULL)
        {
            os_error_printf(CU_MSG_ERROR, (PS8)("** Error allocate param name\n"));
            os_MemoryFree(p_token->u.token.parm);
            os_MemoryFree(p_token->u.token.name);
            os_MemoryFree(p_token);
            return E_NOMEMORY;
        }
         p_token_parm->name = (PS8)p_token->u.token.name[i];
         os_strncpy( p_token->u.token.name[i], p_parms->name, os_strlen(p_parms->name) );
         ++p_parms;
      } /*end of for loop*/
    }
    
    /* Add token to the directory */
    p_e = &(p_dir->u.dir.first);
    while (*p_e)
      p_e = &((*p_e)->next);
    *p_e = p_token;
    
    return E_OK;
}

int consoleRunScript( char *script_file, THandle hConsole)
{
    FILE *hfile = fopen(script_file, "r" );
	U8 status = 0;
    Console_t* pConsole = (Console_t*)hConsole;

    if( hfile )
    {
        char buf[INBUF_LENGTH];
        pConsole->stop_UI_Monitor = FALSE;

        while( fgets(buf, sizeof(buf), hfile ) )
        {
            status = Console_ParseString(pConsole, buf);
			if (status == 1)
				return TRUE;
			if( pConsole->stop_UI_Monitor )
                break;
        }

        fclose(hfile);
    }
    else
	{
		os_error_printf(CU_MSG_ERROR, (PS8)("ERROR in script: %s \n"), (PS8)script_file);
	}
    return pConsole->stop_UI_Monitor;
}