Skip to content
Snippets Groups Projects
dsl_cpe_cli.c 31.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • Kenneth Johansson's avatar
    Kenneth Johansson committed
    /******************************************************************************
    
    
    Oussama Ghorbel's avatar
    Oussama Ghorbel committed
             Copyright 2016 - 2019 Intel Corporation
             Copyright 2015 - 2016 Lantiq Beteiligungs-GmbH & Co. KG
             Copyright 2009 - 2014 Lantiq Deutschland GmbH
             Copyright 2007 - 2008 Infineon Technologies AG
    
    Kenneth Johansson's avatar
    Kenneth Johansson committed
    
      For licensing information, see the file 'LICENSE' in the root folder of
      this software module.
    
    ******************************************************************************/
    
    /** \file
       DSL daemon command line interface
    */
    
    /*#define DSL_INTERN*/
    
    #include "dsl_cpe_control.h"
    #include "dsl_cpe_os.h"
    #include "dsl_cpe_cli.h"
    #ifdef LOGGING_ID
       #include "ulogging.h"
    
       #ifndef LOG_LEVEL
       uint16_t LOGLEVEL = SYS_LOG_DEBUG + 1;
       #else
       uint16_t LOGLEVEL = LOG_LEVEL + 1;
       #endif
    
       #ifndef LOG_TYPE
       uint16_t LOGTYPE = SYS_LOG_TYPE_FILE;
       #else
       uint16_t LOGTYPE = LOG_TYPE;
       #endif 
    #else /* LOGGING_ID */
       #define LOGF_LOG_INFO(...)
    #endif /* LOGGING_ID */
    
    #ifdef INCLUDE_DSL_CPE_CLI_SUPPORT
    
    #undef DSL_CCA_DBG_BLOCK
    #define DSL_CCA_DBG_BLOCK DSL_CCA_DBG_CLI
    
    
    static DSL_void_t DSL_CPE_CLI_Cleanup(void);
    
    static DSL_Error_t DSL_CPE_CLI_PrintHelp
    (
       const DSL_char_t *psHelp,
       DSL_char_t *psCmdLong,
       DSL_char_t *psCmdShort,
       DSL_uint32_t nCmdMask,
       DSL_CPE_CLI_PrintHelpCallback_t pFct,
       DSL_CPE_File_t *out
    );
    
    /** 'less then' defintion for binary tree, (a < b)*/
    #define compLT(a,b) (strcmp(a,b) < 0)
    /** 'equal' defintion for binary tree, (a == b)*/
    #define compEQ(a,b) (strcmp(a,b) == 0)
    
    #define DSL_CLI_HELP_NOT_AVAILABLE "nReturn=-1 (wrong number of parameters/help not available) \n"
    #define DSL_CLI_HELP_MEMORY_ERROR  "nReturn=-1 (help string memory allocation error) \n"
    
    #define DSL_CLI_HELP_NOTE_FUNCTION_DEPRECATED  "Note: This function is deprecated! \n"
    
    /** implementation dependend declarations */
    typedef enum
    {
       DSL_CPE_STATUS_OK,
       DSL_CPE_STATUS_MEM_EXHAUSTED,
       DSL_CPE_STATUS_DUPLICATE_KEY,
       DSL_CPE_STATUS_KEY_NOT_FOUND,
       DSL_CPE_STATUS_KEY_INVALID
    } DSL_CPE_statusEnum;
    
    /** type of key */
    typedef char* DSL_CPE_keyType;
    
    /** user data stored in tree */
    typedef struct
    {
       DSL_char_t *sCmdShort;
       DSL_char_t *sCmdLong;
       const DSL_char_t *psHelp;
       unsigned int mask;
       DSL_int_t (*func)(DSL_int_t, DSL_char_t*, DSL_CPE_File_t*);
       DSL_CPE_CLI_PrintHelpCallback_t printFunc;
    } DSL_CPE_recType;
    
    typedef struct DSL_CPE_nodeTag
    {
       /* left child */
       struct DSL_CPE_nodeTag *left;
       /** right child */
       struct DSL_CPE_nodeTag *right;
       /** parent */
       struct DSL_CPE_nodeTag *parent;
       /** key used for searching */
       DSL_CPE_keyType key;
       /** user data */
       DSL_CPE_recType rec;
    } DSL_CPE_nodeType;
    
    static DSL_CPE_statusEnum DSL_CPE_keyInsert
    (
       DSL_CPE_keyType key,
       DSL_CPE_recType *rec
    );
    
    #ifdef INCLUDE_DSL_RESOURCE_STATISTICS
    static void DSL_CPE_treeResourceUsageGet
    (
       DSL_CPE_nodeType *node,
       unsigned int *pResStatic,
       unsigned int *pResDynamic
    );
    #endif /* INCLUDE_DSL_RESOURCE_STATISTICS*/
    
    static DSL_CPE_statusEnum DSL_CPE_keyDelete
    (
       DSL_CPE_keyType key
    );
    
    DSL_CPE_statusEnum DSL_CPE_keyFind
    (
       DSL_CPE_keyType key,
       DSL_CPE_recType *rec
    );
    
    static void DSL_CPE_treePrint
    (
       DSL_CPE_nodeType *node,
       unsigned int mask,
       DSL_CPE_File_t *
    );
    
    static void DSL_CPE_treeDelete
    (
       DSL_CPE_nodeType *node
    );
    
    static void DSL_CPE_nodeDelete
    (
       DSL_CPE_nodeType *node
    );
    
    /** root of binary tree */
    DSL_CPE_nodeType *root_node = DSL_NULL;
    
    struct DSL_CLI_Context
    {
       /**
       pointer for list */
       DSL_CLI_Context_t *next;
       /**
       Context for CLI Callbacks */
       DSL_void_t *pCBContext;
       /**
       Callback for CLI Shutdown */
       DSL_CPE_Exit_Callback_t pExitCallback;
       /**
       DSL_CPE_API Event Callback, may be DSL_NULL */
       DSL_CLI_Event_Callback_t pEventCallback;
    };
    
    DSL_char_t CLI_EventText[16000];
    
    static DSL_CLI_Context_t *CLI_List_head = DSL_NULL;
    
    /** indicates if the CLI already initialized */
    static DSL_boolean_t bCLI_Init = DSL_FALSE;
    
    static const DSL_char_t g_sQuit[] =
    #ifndef DSL_CPE_DEBUG_DISABLE
       "Long Form: %s" DSL_CPE_CRLF
       "Short Form: %s" DSL_CPE_CRLF
       DSL_CPE_CRLF
       "Quits DSL CPE API Control Application" DSL_CPE_CRLF
       DSL_CPE_CRLF "";
    #else
       "";
    #endif
    
    static DSL_int_t DSL_CPE_CLI_Quit(
       DSL_int_t fd,
       DSL_char_t *pCommands,
       DSL_CPE_File_t *out)
    {
       if (DSL_CPE_CLI_CheckParamNumber(pCommands, 0, DSL_CLI_EQUALS) == DSL_FALSE)
       {
          return -1;
       }
    
       DSL_CPE_FPrintf (out,
          "DSL CPE API Control Application termination started..."DSL_CPE_CRLF);
    
       return 0;
    }
    
    /******************************************************************************/
    
    DSL_Error_t DSL_CPE_CLI_Init(DSL_void_t)
    {
       if(bCLI_Init == DSL_FALSE)
       {
          DSL_CPE_CLI_CMD_ADD_COMM("help", "Help", DSL_CPE_CLI_HelpPrint, DSL_NULL);
          DSL_CPE_CLI_CMD_ADD_COMM("quit", "Quit", DSL_CPE_CLI_Quit, g_sQuit);
          DSL_CPE_CLI_AccessCommandsRegister();
    
          bCLI_Init = DSL_TRUE;
       }
       return DSL_SUCCESS;
    }
    
    DSL_Error_t DSL_CPE_CLI_Shutdown(DSL_void_t)
    {
       DSL_CPE_CLI_CommandClear();
    
       DSL_CPE_FPrintf (DSL_CPE_STDOUT, DSL_CPE_PREFIX "Goodbye from DSL CPE API CLI "
          "interface" DSL_CPE_CRLF );
    
       bCLI_Init = DSL_FALSE;
    
       return DSL_SUCCESS;
    }
    
    DSL_Error_t DSL_CPE_CLI_HandleEvent(DSL_char_t *pMsg)
    {
       DSL_CLI_Context_t *pCLIList = CLI_List_head;
    
       /* Using logging framework for event data content */
       LOGF_LOG_INFO("%s", pMsg);
    
       while (pCLIList != DSL_NULL)
       {
          if (pCLIList->pEventCallback != DSL_NULL)
          {
             (void)pCLIList->pEventCallback(pCLIList->pCBContext, CLI_EventText);
          }
          pCLIList = pCLIList->next;
       };
    
       return DSL_SUCCESS;
    }
    
    DSL_Error_t DSL_CPE_CLI_Register(
       DSL_CLI_Context_t **pNewCLIContext,
       DSL_void_t *pCBContext,
       DSL_CPE_Exit_Callback_t pExitCallback,
       DSL_CLI_Event_Callback_t pEventCallback)
    {
       DSL_CLI_Context_t *pCLIContext;
    
       if(*pNewCLIContext != DSL_NULL)
       {
          DSL_CPE_FPrintf (DSL_CPE_STDOUT, DSL_CPE_PREFIX "expecting zero context pointer "
             "'*pNewCLIContext'" DSL_CPE_CRLF);
          return DSL_ERROR;
       }
    
       *pNewCLIContext = malloc(sizeof(DSL_CLI_Context_t));
       if(*pNewCLIContext == DSL_NULL)
       {
          DSL_CPE_FPrintf (DSL_CPE_STDOUT, DSL_CPE_PREFIX "no memory for '*pNewCLIContext'"
             DSL_CPE_CRLF);
          return DSL_ERROR;
       }
       pCLIContext = *pNewCLIContext;
    
       memset(pCLIContext, 0x00, sizeof(*pCLIContext));
    
       pCLIContext->next = DSL_NULL;
       pCLIContext->pCBContext = pCBContext;
       pCLIContext->pExitCallback = pExitCallback;
       pCLIContext->pEventCallback = pEventCallback;
    
       if (CLI_List_head == DSL_NULL)
          CLI_List_head = pCLIContext;
       else
       {
          DSL_CLI_Context_t *pCLI_List = CLI_List_head;
          while (pCLI_List->next != DSL_NULL)
          {
             pCLI_List = pCLI_List->next;
          }
          pCLI_List->next = pCLIContext;
       }
    
       return DSL_SUCCESS;
    }
    
    #if defined(INCLUDE_DSL_API_CONSOLE_EXTRA) || defined(INCLUDE_DSL_CPE_DTI_SUPPORT)
    DSL_Error_t DSL_CPE_CLI_Unregister(DSL_CLI_Context_t *pCLIContext)
    {
       DSL_CLI_Context_t *pCLIList=DSL_NULL;
    
       if(pCLIContext == DSL_NULL)
       {
          return DSL_SUCCESS;
       }
    
       if (CLI_List_head == pCLIContext)
       {
          CLI_List_head = pCLIContext->next;
          return DSL_SUCCESS;
       }
       else
       {
          pCLIList = CLI_List_head;
          while (pCLIList != DSL_NULL)
          {
             if (pCLIList->next == pCLIContext)
             {
                /* entry found, remove from list */
                pCLIList->next = pCLIContext->next;
                return DSL_SUCCESS;
             }
             pCLIList = pCLIList->next;
          }
       }
    
       return DSL_ERROR;
    }
    #endif /* #if defined(INCLUDE_DSL_API_CONSOLE_EXTRA) || defined(INCLUDE_DSL_CPE_DTI_SUPPORT)*/
    
    /**
       Cleanup the CLI (and stop the DSL CPE API)
    */
    static DSL_void_t DSL_CPE_CLI_Cleanup(void)
    {
       DSL_CLI_Context_t *pCLIList = CLI_List_head;
       DSL_CLI_Context_t *pCLI_del;
    
       CLI_List_head = DSL_NULL;
       while (pCLIList != DSL_NULL)
       {
          if (pCLIList->pExitCallback != DSL_NULL)
          {
             /*DSL_CPE_FPrintf(DSL_CPE_STDERR, "CLI: calling pExitCallback()" DSL_CPE_CRLF );*/
             (void)pCLIList->pExitCallback(pCLIList->pCBContext);
          }
          pCLI_del = pCLIList;
          pCLIList = pCLIList->next;
          free(pCLI_del);
       };
    }
    
    /**
       Checks if the command string includes option to display help text.
    
       \param pCommands
          user command line arguments
    
       \return
          returns 0 in case of no help request or any other value if help is
          requested from user.
    */
    DSL_int_t DSL_CPE_CLI_CheckHelp (const DSL_char_t * pCommands)
    {
       if (pCommands && (strstr (pCommands, "-h") || strstr (pCommands, "--help") ||
             strstr (pCommands, "/h") || strstr (pCommands, "-?")))
       {
          return -1;
       }
       return 0;
    }
    
    static DSL_Error_t DSL_CPE_CLI_PrintHelp(
       const DSL_char_t *psHelp,
       DSL_char_t *psCmdLong,
       DSL_char_t *psCmdShort,
       DSL_uint32_t nCmdMask,
       DSL_CPE_CLI_PrintHelpCallback_t pFct,
       DSL_CPE_File_t *out)
    {
    #ifndef DSL_CPE_DEBUG_DISABLE
       DSL_char_t *sHelp = DSL_NULL;
    
       if (psHelp == DSL_NULL)
       {
          return DSL_ERROR;
       }
    
       if (nCmdMask & DSL_CPE_MASK_DEPRECATED)
       {
          DSL_CPE_FPrintf (out, DSL_CLI_HELP_NOTE_FUNCTION_DEPRECATED);
       }
    
       if (pFct != NULL)
       {
          return pFct(psHelp, psCmdLong, psCmdShort, nCmdMask,out);
       }
       else
       {
          sHelp = (DSL_char_t*)DSL_CPE_Malloc(4096);
          if (sHelp == DSL_NULL)
          {
             DSL_CPE_FPrintf(out, DSL_CLI_HELP_MEMORY_ERROR);
             return DSL_ERROR;
          }
    
    Oussama Ghorbel's avatar
    Oussama Ghorbel committed
          snprintf(sHelp, 4096, psHelp, psCmdLong, psCmdShort);
    
    Kenneth Johansson's avatar
    Kenneth Johansson committed
    
          DSL_CPE_FPrintf (out, "%s", sHelp);
    
          DSL_CPE_Free(sHelp);
       }
    #else
       DSL_CPE_FPrintf (out, DSL_CLI_HELP_NOT_AVAILABLE);
    #endif /* DSL_CPE_DEBUG_DISABLE */
    
       return DSL_SUCCESS;
    }
    
    /**
       Checks a given command list (string) according to the included number of
       parameter.
    
       \param pCommands
          specifies a pointer to a list of parameters
       \param nParams
          specifies the expected number of parameters that has to be included
          within the command list
    
       \return
          Returns DSL_TRUE if the number of scanned parameters equals to the
          given value of nParams otherwise returns DSL_FALSE
    */
    DSL_boolean_t DSL_CPE_CLI_CheckParamNumber(
       DSL_char_t *pCommands,
       DSL_int_t nParams,
       DSL_CLI_ParamCheckType_t nCheckType)
    {
       DSL_char_t string[256] = { 0 };
       DSL_char_t seps[] = " ";
       DSL_boolean_t bRet = DSL_FALSE;
       DSL_char_t *token;
       DSL_int_t i = 0;
    
    
    Oussama Ghorbel's avatar
    Oussama Ghorbel committed
       cpe_control_strncpy_s(string, sizeof(string)-1, pCommands, strlen(pCommands));
    
    Kenneth Johansson's avatar
    Kenneth Johansson committed
       string[sizeof(string)-1]=0;
    
       /* Get first token */
       token = strtok (string, seps);
       if (token != DSL_NULL)
       {
          for (i = 1; ; i++)
          {
             /* Get next token */
             token = strtok(DSL_NULL, seps);
    
             /* Exit scanning if no further information is included */
             if (token == DSL_NULL)
             {
                break;
             }
          }
       }
    
       bRet = DSL_FALSE;
       switch (nCheckType)
       {
       case DSL_CLI_EQUALS:
          if (i == nParams) bRet =DSL_TRUE;
          break;
       case DSL_CLI_MIN:
          if (i >= nParams) bRet = DSL_TRUE;
          break;
       case DSL_CLI_MAX:
          if (i <= nParams) bRet = DSL_TRUE;
          break;
       default:
          DSL_CPE_FPrintf(DSL_CPE_STDERR, DSL_CPE_PREFIX "DSL_CPE_CLI_CheckParamNumber: "
             "unknown check type" DSL_CPE_CRLF);
          break;
       }
    
       return bRet;
    }
    
    /**
       Inform the user about the built in commands.
    
       \param command not used
    */
    DSL_int_t DSL_CPE_CLI_HelpPrint(
       DSL_int_t fd,
       DSL_char_t *command,
       DSL_CPE_File_t *out)
    {
       unsigned int mask = 0;
       DSL_CPE_File_t *target = out;
       #ifdef WIN32
       DSL_CPE_File_t *file = DSL_NULL;
       #endif
    
       if( (command != DSL_NULL) && ( strstr(command,"--help") ||
           strstr(command,"-h")) )
       {
          DSL_CPE_FPrintf(out, DSL_CPE_PREFIX "help [-h | --help"
       #ifdef DSL_CPE_MASK_LONG
          " | -l | --long |"
       #endif
       #ifdef WIN32
          " | file |"
       #endif
          " all | device | g997 | pm | bnd | dsm"
       #ifdef INCLUDE_DEPRECATED
          " deprecated |"
       #endif
          " detailed]" DSL_CPE_CRLF );
    
          return 0;
       }
    
       if(command)
       {
       #ifdef WIN32
          if(strstr(command, "file") != 0)
          {
             file = DSL_CPE_FOpen("cli_help.txt","a+");
             target = file;
          }
       #endif
    
       #ifdef DSL_CPE_MASK_LONG
          if((strstr(command, "-l") != 0) || (strstr(command, "--long") != 0) )
             mask = DSL_CPE_MASK_LONG;
       #endif
          if(strstr(command, "detailed") != 0)
          {
             DSL_CPE_FPrintf(out, DSL_CPE_PREFIX "detailed information" DSL_CPE_CRLF );
             mask |= DSL_CPE_MASK_DETAILED;
          }
          #ifdef INCLUDE_DEPRECATED
          if(strstr(command, "deprecated") != 0)
          {
             DSL_CPE_FPrintf(out, DSL_CPE_PREFIX "deprecated functions" DSL_CPE_CRLF );
             mask |= DSL_CPE_MASK_DEPRECATED;
          }
          #endif
          if(strstr(command, "device") != 0)
          {
             DSL_CPE_FPrintf(out, DSL_CPE_PREFIX "device related functions" DSL_CPE_CRLF );
             DSL_CPE_treePrint(root_node, mask | DSL_CPE_MASK_DEVICE, target);
          }
          if(strstr(command, "g997") != 0)
          {
             DSL_CPE_FPrintf(out, DSL_CPE_PREFIX "G997 related functions" DSL_CPE_CRLF );
             DSL_CPE_treePrint(root_node, mask | DSL_CPE_MASK_G997, target);
          }
          if(strstr(command, "pm") != 0)
          {
             DSL_CPE_FPrintf(out, DSL_CPE_PREFIX "performance related functions" DSL_CPE_CRLF );
             DSL_CPE_treePrint(root_node, mask | DSL_CPE_MASK_PM, target);
          }
          if(strstr(command, "bnd") != 0)
          {
             DSL_CPE_FPrintf(out, DSL_CPE_PREFIX "Bonding related functions" DSL_CPE_CRLF );
             DSL_CPE_treePrint(root_node, mask | DSL_CPE_MASK_BND, target);
          }
          if(strstr(command, "dsm") != 0)
          {
             DSL_CPE_FPrintf(out, DSL_CPE_PREFIX
                "(D)igital (S)pectrum (M)anagement (vectoring) related functions" DSL_CPE_CRLF );
             DSL_CPE_treePrint(root_node, mask | DSL_CPE_MASK_DSM, target);
          }
          if(strlen(command)==0 || strstr(command, "all") != 0)
          {
             DSL_CPE_treePrint(root_node, mask | DSL_CPE_MASK_ALL, target);
          }
       }
       else
       {
          DSL_CPE_treePrint(root_node, DSL_CPE_MASK_ALL | mask, target);
       }
    
       #ifdef WIN32
       if(file != DSL_NULL)
          DSL_CPE_FClose(file);
       #endif
    
       return 0;
    }
    
    /**
       Execute command.
    
       \param name Command name
       \param command Command line (optional parameters)
    */
    DSL_int_t DSL_CPE_CLI_CommandExecute(
       DSL_int_t fd,
       DSL_char_t *cmd,
       DSL_char_t *arg,
       DSL_CPE_File_t *out)
    {
       DSL_CPE_recType  rec = {DSL_NULL, DSL_NULL, DSL_NULL, 0, DSL_NULL};
       DSL_char_t dummy_arg[10] = "";
    
       if(cmd == DSL_NULL)
       {
          DSL_CPE_CLI_HelpPrint (fd, "all", out);
          return -1;
       }
    
       cmd = DSL_CPE_CLI_WhitespaceRemove(cmd);
       if(arg != DSL_NULL)
       {
          arg = DSL_CPE_CLI_WhitespaceRemove(arg);
       }
       else
       {
          arg = dummy_arg;
       }
    
       switch(DSL_CPE_keyFind(cmd, &rec))
       {
          case DSL_CPE_STATUS_OK:
          if(rec.func == DSL_NULL)
          {
             DSL_CPE_FPrintf(out, DSL_CPE_CRLF "Error: command \"%s\" without callback" DSL_CPE_CRLF ,cmd);
          }
          else
          {
             if ((rec.psHelp != DSL_NULL) && (DSL_CPE_CLI_CheckHelp(arg) != 0))
             {
                DSL_CPE_CLI_PrintHelp(rec.psHelp, rec.sCmdLong, rec.sCmdShort, rec.mask, rec.printFunc, out);
             }
             else
             {
    
    Oussama Ghorbel's avatar
    Oussama Ghorbel committed
                if (rec.func(fd, arg, out) != 0)
    
    Oussama Ghorbel's avatar
    Oussama Ghorbel committed
                   DSL_CPE_CLI_PrintHelp(rec.psHelp, rec.sCmdLong, rec.sCmdShort, rec.mask, rec.printFunc, out);
    
    Oussama Ghorbel's avatar
    Oussama Ghorbel committed
                if (strcmp(cmd, "quit") == 0)
    
    Kenneth Johansson's avatar
    Kenneth Johansson committed
                {
                   DSL_CPE_CLI_Cleanup();
                   /* main() will execute exit */
                   return 1;
                }
             }
          }
          break;
    
          default:
    #if 0 /* #ifdef LINUX */
    /* FIXME: This leads into a crash on the RefBoard */
          {
             DSL_int_t   k=0;
             DSL_char_t  *argv[DSL_MAX_ARGS];
             DSL_char_t  *ptr;
             DSL_char_t  file_name[64], *brkt;
             DSL_int_t   status;
    
             /* try to call external utility */
             argv[k++] = cmd;
    
             ptr = strtok_r(arg, " ", &brkt);
    
             while(ptr && (k<(DSL_MAX_ARGS-1)))
             {
                argv[k++] = ptr;
                ptr = strtok_r(DSL_NULL, " ", &brkt);
             }
    
             argv[k] = DSL_NULL;
    
             switch (fork())
             {
             case -1:
                DSL_CPE_FPrintf(DSL_CPE_STDERR, DSL_CPE_PREFIX "fork failed" DSL_CPE_CRLF );
                break;
    
             case 0:
    
    Oussama Ghorbel's avatar
    Oussama Ghorbel committed
                snprintf(file_name, sizeof(file_name),"/bin/%s",cmd);
    
    Kenneth Johansson's avatar
    Kenneth Johansson committed
                execv(file_name,argv);
    
    
    Oussama Ghorbel's avatar
    Oussama Ghorbel committed
                snprintf(file_name, sizeof(file_name),"/usr/bin/%s",cmd);
    
    Kenneth Johansson's avatar
    Kenneth Johansson committed
                execv(file_name,argv);
    
    
    Oussama Ghorbel's avatar
    Oussama Ghorbel committed
                snprintf(file_name, sizeof(file_name),"/opt/ifx/%s",cmd);
    
    Kenneth Johansson's avatar
    Kenneth Johansson committed
                execv(file_name,argv);
    
                DSL_CPE_FPrintf(DSL_CPE_STDERR, "%s: command not found" DSL_CPE_CRLF,cmd);
                exit(1);
                break;
    
             default:
                wait(&status);
                break;
             }
          }
          return 0;
    #else
          DSL_CPE_FPrintf(out, "%s: command not found" DSL_CPE_CRLF, cmd);
          DSL_CPE_CLI_HelpPrint (fd, "all", out);
          return -1;
    #endif /* LINUX */
       }
       return 0;
    }
    
    /**
       Add a command to the static list.
    
       \param name Command name
       \param help Help string
       \param func Command entry point
    
       \return
       DSL_ERROR no more space left in command table
       DSL_SUCCESS command added to the command table
    */
    DSL_Error_t DSL_CPE_CLI_CommandAdd(
       DSL_char_t *name,
       DSL_char_t *long_name,
       DSL_int_t (*func)(DSL_int_t, DSL_char_t*, DSL_CPE_File_t*),
       const DSL_char_t *psHelp,
       DSL_uint32_t nCmdSortMask,
       DSL_CPE_CLI_PrintHelpCallback_t printCallback)
    {
       DSL_CPE_recType rec;
       DSL_char_t buf[64+1]="";
       DSL_uint8_t i=0,k=0;
    
       rec.mask = 0;
    
       if(name == DSL_NULL)
       {
          DSL_CPE_FPrintf(DSL_CPE_STDERR, DSL_CPE_PREFIX " name pointer is invalid" DSL_CPE_CRLF );
          return DSL_ERROR;
       }
    
       if(long_name == DSL_NULL)
       {
          DSL_CPE_FPrintf(DSL_CPE_STDERR, DSL_CPE_PREFIX " long_name pointer is invalid" DSL_CPE_CRLF );
          return DSL_ERROR;
       }
    
       for(i = 0; (i < strlen(long_name)) && (k < sizeof(buf)/sizeof(buf[0]) - 1); i++)
       {
          if(long_name[i] >= 'A' && long_name[i] <= 'Z')
          {
             buf[k++] = 'a' + (long_name[i] - 'A');
          }
          else if(long_name[i] >= '0' && long_name[i] <= '9')
          {
             buf[k++] = long_name[i];
          }
       }
       buf[k] = 0;
    
       if(strcmp(buf, name) != 0)
       {
          if( ! ((strcmp(long_name,"Help") == 0) || (strcmp(long_name,"Quit") == 0)) )
          {
             DSL_CPE_FPrintf(DSL_CPE_STDERR, DSL_CPE_PREFIX " CLI short name mismatch %s / %s / %s " DSL_CPE_CRLF, name, buf, long_name );
          }
       }
    
       rec.func = func;
    
       if(strstr(name, "g997") != 0)
       {
          rec.mask |= DSL_CPE_MASK_G997;
       }
       else if(long_name[0] == 'P' && long_name[1] == 'M')
       {
          rec.mask |= DSL_CPE_MASK_PM;
       }
       else if(strstr(name, "bnd") != 0)
       {
          rec.mask |= DSL_CPE_MASK_BND;
       }
       else if(strstr(name, "dsm") != 0)
       {
          rec.mask |= DSL_CPE_MASK_DSM;
       }
       else
       {
          rec.mask |= DSL_CPE_MASK_DEVICE;
       }
    
       rec.mask |= nCmdSortMask;
    
       rec.sCmdShort = malloc(strlen(name)+1);
       if(rec.sCmdShort)
       {
    
    Oussama Ghorbel's avatar
    Oussama Ghorbel committed
          cpe_control_strncpy_s(rec.sCmdShort, strlen(name)+1, name, strlen(name));
    
    Kenneth Johansson's avatar
    Kenneth Johansson committed
          rec.sCmdShort[strlen(name)] = 0;
       }
    
       rec.sCmdLong = malloc(strlen(long_name)+1);
       if(rec.sCmdLong)
       {
    
    Oussama Ghorbel's avatar
    Oussama Ghorbel committed
          cpe_control_strncpy_s(rec.sCmdLong, strlen(long_name)+1, long_name, strlen(long_name));
    
    Kenneth Johansson's avatar
    Kenneth Johansson committed
          rec.sCmdLong[strlen(long_name)] = 0;
       }
    
       if(rec.sCmdShort == DSL_NULL || rec.sCmdLong == DSL_NULL)
       {
          free(rec.sCmdShort);
          free(rec.sCmdLong);
          return DSL_ERROR;
       }
    
       rec.psHelp = psHelp;
       rec.printFunc = printCallback;
    
       switch(DSL_CPE_keyInsert(rec.sCmdShort, &rec))
       {
          case DSL_CPE_STATUS_KEY_INVALID:
          DSL_CPE_FPrintf(DSL_CPE_STDERR, DSL_CPE_PREFIX " invalid key %s for %s" DSL_CPE_CRLF , rec.sCmdShort, rec.sCmdLong);
          free(rec.sCmdShort);
          free(rec.sCmdLong);
          return DSL_ERROR;
    
          case DSL_CPE_STATUS_DUPLICATE_KEY:
          DSL_CPE_FPrintf(DSL_CPE_STDERR, DSL_CPE_PREFIX " duplicate key %s for %s" DSL_CPE_CRLF , rec.sCmdShort, rec.sCmdLong);
          free(rec.sCmdShort);
          free(rec.sCmdLong);
          return DSL_ERROR;
    
          case DSL_CPE_STATUS_MEM_EXHAUSTED:
          DSL_CPE_FPrintf(DSL_CPE_STDERR, DSL_CPE_PREFIX " memory error" DSL_CPE_CRLF );
          free(rec.sCmdShort);
          free(rec.sCmdLong);
          return DSL_ERROR;
    
          case DSL_CPE_STATUS_OK:
          break;
    
          default:
          DSL_CPE_FPrintf(DSL_CPE_STDERR, DSL_CPE_PREFIX " insert key aborted" DSL_CPE_CRLF );
          free(rec.sCmdShort);
          free(rec.sCmdLong);
          return DSL_ERROR;
       }
    
    #ifdef DSL_CPE_MASK_LONG
       rec.mask |= DSL_CPE_MASK_LONG;
    
       switch(DSL_CPE_keyInsert(rec.sCmdLong, &rec))
       {
          case DSL_CPE_STATUS_KEY_INVALID:
          DSL_CPE_FPrintf(DSL_CPE_STDERR, DSL_CPE_PREFIX " invalid key %s for %s" DSL_CPE_CRLF , rec.sCmdShort, rec.sCmdLong);
          free(rec.sCmdShort);
          free(rec.sCmdLong);
          return DSL_ERROR;
    
          case DSL_CPE_STATUS_DUPLICATE_KEY:
          DSL_CPE_FPrintf(DSL_CPE_STDERR, DSL_CPE_PREFIX " duplicate key %s for %s" DSL_CPE_CRLF , rec.sCmdShort, rec.sCmdLong);
          free(rec.sCmdShort);
          free(rec.sCmdLong);
          return DSL_ERROR;
    
          case DSL_CPE_STATUS_MEM_EXHAUSTED:
          DSL_CPE_FPrintf(DSL_CPE_STDERR, DSL_CPE_PREFIX " memory error" DSL_CPE_CRLF );
          free(rec.sCmdShort);
          free(rec.sCmdLong);
          return DSL_ERROR;
    
          case DSL_CPE_STATUS_OK:
          break;
    
          default:
          DSL_CPE_FPrintf(DSL_CPE_STDERR, DSL_CPE_PREFIX " insert key aborted" DSL_CPE_CRLF );
          free(rec.sCmdShort);
          free(rec.sCmdLong);
          return DSL_ERROR;
       }
    #endif
    
       return DSL_SUCCESS;
    }
    
    
    /**
       Clean command  list.
    
       \return
       DSL_SUCCESS successfull operation
    */
    DSL_Error_t DSL_CPE_CLI_CommandClear(DSL_void_t)
    {
       DSL_CPE_nodeType *tmp_root = root_node;
    
       /*root_node = DSL_NULL;*/
       DSL_CPE_treeDelete(tmp_root);
    
       return DSL_SUCCESS;
    }
    
    #ifdef INCLUDE_DSL_RESOURCE_STATISTICS
    DSL_Error_t DSL_CPE_CLI_ResourceUsageGet(
       DSL_CLI_ResourceUsageStatisticsData_t *pData)
    {
       DSL_Error_t ret = DSL_SUCCESS;
       unsigned int ResStatic = 0, ResDynamic = 0;
    
       if (pData == DSL_NULL)
       {
          return DSL_ERROR;
       }
    
       pData->staticMemUsage  = 0;
       pData->dynamicMemUsage = 0;
    
       pData->staticMemUsage += sizeof(CLI_EventText) ;
    
       DSL_CPE_treeResourceUsageGet(root_node, &ResStatic, &ResDynamic);
    
       pData->staticMemUsage  += ResStatic;
       pData->dynamicMemUsage += ResDynamic;
    
       return ret;
    }
    
    static void DSL_CPE_treeResourceUsageGet(
       DSL_CPE_nodeType *node,
       unsigned int *pResStatic,
       unsigned int *pResDynamic)
    {
       if(node == DSL_NULL)
          return;
    
       DSL_CPE_treeResourceUsageGet(node->left, pResStatic, pResDynamic);
    
       if (node->rec.psHelp)
       {
          *pResStatic  += strlen(node->rec.psHelp);
       }
    
       *pResDynamic += sizeof(DSL_CPE_nodeType);
       if (node->key)
       {
          *pResDynamic += strlen(node->key);
       }
    
       if (node->rec.sCmdShort)
       {
          *pResDynamic += strlen(node->rec.sCmdShort);
       }
    
       if (node->rec.sCmdLong)
       {
          *pResDynamic += strlen(node->rec.sCmdLong);
       }
    
       DSL_CPE_treeResourceUsageGet(node->right, pResStatic, pResDynamic);
    
       return;
    }
    #endif /* INCLUDE_DSL_RESOURCE_STATISTICS*/
    
    /**
       allocate node for data and insert in tree
    */
    static DSL_CPE_statusEnum DSL_CPE_keyInsert(DSL_CPE_keyType key, DSL_CPE_recType *rec)
    {
        DSL_CPE_nodeType *x, *current, *parent;
    
        if(key == DSL_NULL)
          return DSL_CPE_STATUS_KEY_INVALID;
    
        /* find future parent */
        current = root_node;
        parent = 0;
        while (current) {
            if (compEQ(key, current->key))
                return DSL_CPE_STATUS_DUPLICATE_KEY;
            parent = current;
            current = compLT(key, current->key) ?
                current->left : current->right;
        }
    
        /* setup new node */
        if ((x = malloc(sizeof(*x))) == 0) {
            return DSL_CPE_STATUS_MEM_EXHAUSTED;
        }
        x->parent = parent;
        x->left = DSL_NULL;
        x->right = DSL_NULL;
        x->key = key;
    
    Oussama Ghorbel's avatar
    Oussama Ghorbel committed
        cpe_control_memcpy_s((void *)&x->rec, sizeof(DSL_CPE_recType), (void *)rec, sizeof(DSL_CPE_recType));
    
    Kenneth Johansson's avatar
    Kenneth Johansson committed
    
        /* insert x in tree */
        if(parent)
            if(compLT(x->key, parent->key))
                parent->left = x;
            else
                parent->right = x;
        else
            root_node = x;
    
        return DSL_CPE_STATUS_OK;
    }