2018-10-01 21:31:06 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* apps/nshlib/nsh_vars.c
|
|
|
|
*
|
2021-06-10 16:34:12 +02:00
|
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
|
|
* this work for additional information regarding copyright ownership. The
|
|
|
|
* ASF licenses this file to you 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
|
2018-10-01 21:31:06 +02:00
|
|
|
*
|
2021-06-10 16:34:12 +02:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2018-10-01 21:31:06 +02:00
|
|
|
*
|
2021-06-10 16:34:12 +02:00
|
|
|
* 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.
|
2018-10-01 21:31:06 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Included Files
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
|
2023-03-13 14:27:05 +01:00
|
|
|
#include <stdio.h>
|
2018-10-01 21:31:06 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2021-06-08 18:13:43 +02:00
|
|
|
#include <assert.h>
|
2018-10-01 21:31:06 +02:00
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include "nsh.h"
|
|
|
|
#include "nsh_console.h"
|
|
|
|
|
|
|
|
#ifdef CONFIG_NSH_VARS
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: nsh_cmpname
|
|
|
|
****************************************************************************/
|
|
|
|
|
2022-09-22 05:38:12 +02:00
|
|
|
static bool nsh_cmpname(FAR const char *pszname, FAR const char *peqname)
|
2018-10-01 21:31:06 +02:00
|
|
|
{
|
|
|
|
/* Search until we find anything different in the two names */
|
|
|
|
|
|
|
|
for (; *pszname == *peqname; pszname++, peqname++)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/* On success, pszname will end with '\0' and peqname with '=' */
|
|
|
|
|
|
|
|
if (*pszname == '\0' && *peqname == '=')
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Public Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: nsh_findvar
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Search the provided NSH console structure for the variable of the
|
|
|
|
* specified name.
|
|
|
|
*
|
|
|
|
* Input Parameters:
|
|
|
|
* pstate - The console state containing NSH variable array to be searched.
|
|
|
|
* name - The variable name to find
|
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* A pointer to the name=value string in the NSH variable buffer
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
* - Not called from an interrupt handler
|
|
|
|
* - Pre-emption is disabled by caller
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
FAR char *nsh_findvar(FAR struct console_stdio_s *pstate,
|
|
|
|
FAR const char *name)
|
|
|
|
{
|
|
|
|
FAR char *ptr;
|
|
|
|
FAR char *end;
|
|
|
|
|
|
|
|
/* Verify input parameters */
|
|
|
|
|
|
|
|
DEBUGASSERT(pstate != NULL && name != NULL);
|
|
|
|
|
|
|
|
/* Search for a name=value string with matching name */
|
|
|
|
|
|
|
|
end = &pstate->varp[pstate->varsz];
|
|
|
|
for (ptr = pstate->varp;
|
|
|
|
ptr < end && !nsh_cmpname(name, ptr);
|
|
|
|
ptr += (strlen(ptr) + 1));
|
|
|
|
|
|
|
|
/* Check for success */
|
|
|
|
|
|
|
|
return (ptr < end) ? ptr : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: nsh_removevar
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Remove the referenced name=value pair from the NSH variable buffer
|
|
|
|
*
|
|
|
|
* Input Parameters:
|
|
|
|
* pstate - The task pstate with the NSH variable buffer containing the
|
|
|
|
* name=value pair
|
|
|
|
* pair - A pointer to the name=value pair in the restroom
|
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* Zero on success
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
int nsh_removevar(FAR struct console_stdio_s *pstate, FAR char *pair)
|
|
|
|
{
|
|
|
|
FAR char *end; /* Pointer to the end+1 of the NSH variable buffer */
|
|
|
|
int alloc; /* Size of the allocated NSH variable buffer */
|
|
|
|
int ret = ERROR;
|
|
|
|
|
|
|
|
/* Verify that the pointer lies within the NSH variable region */
|
|
|
|
|
|
|
|
alloc = pstate->varsz; /* Size of the allocated NSH variable buffer */
|
|
|
|
end = &pstate->varp[alloc]; /* Pointer to the end+1 of the NSH variable buffer */
|
|
|
|
|
|
|
|
if (pair >= pstate->varp && pair < end)
|
|
|
|
{
|
|
|
|
/* Set up for the removal */
|
|
|
|
|
|
|
|
int len = strlen(pair) + 1; /* Length of name=value string to remove */
|
|
|
|
FAR char *src = &pair[len]; /* Address of name=value string after */
|
|
|
|
FAR char *dest = pair; /* Location to move the next string */
|
|
|
|
int count = end - src; /* Number of bytes to move (might be zero) */
|
|
|
|
|
|
|
|
/* Move all of the NSH variable strings after the removed one 'down.'
|
|
|
|
* this is inefficient, but probably not high duty.
|
|
|
|
*/
|
|
|
|
|
|
|
|
while (count-- > 0)
|
|
|
|
{
|
|
|
|
*dest++ = *src++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then set to the new allocation size. The caller is expected to
|
|
|
|
* call realloc at some point but we don't do that here because the
|
|
|
|
* caller may add more stuff to the NSH variable buffer.
|
|
|
|
*/
|
|
|
|
|
|
|
|
pstate->varsz -= len;
|
|
|
|
ret = OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Public Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
2018-10-01 23:44:41 +02:00
|
|
|
* Name: nsh_getvar, nsh_setvar, and nsh_setvar
|
2018-10-01 21:31:06 +02:00
|
|
|
*
|
|
|
|
* Description:
|
2018-10-01 23:44:41 +02:00
|
|
|
* Get, set, or unset an NSH variable.
|
2018-10-01 21:31:06 +02:00
|
|
|
*
|
2018-10-02 19:54:18 +02:00
|
|
|
* Input Parameters:
|
2018-10-01 23:44:41 +02:00
|
|
|
* vtbl - NSH session data
|
|
|
|
* name - The name of the variable to get or set
|
|
|
|
* value - The value to use with nsh_setvar()
|
2018-10-01 21:31:06 +02:00
|
|
|
*
|
|
|
|
* Returned value:
|
|
|
|
* nsh_getvar() returns a read-only reference to the variable value on
|
|
|
|
* success or NULL on failure.
|
2018-10-02 19:54:18 +02:00
|
|
|
* nset_unsetvar() returns OK on success or an negated errno value on
|
2018-10-01 21:31:06 +02:00
|
|
|
* failure.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: nsh_getvar
|
|
|
|
****************************************************************************/
|
|
|
|
|
2020-11-02 12:30:26 +01:00
|
|
|
FAR char *nsh_getvar(FAR struct nsh_vtbl_s *vtbl, FAR const char *name)
|
2018-10-01 21:31:06 +02:00
|
|
|
{
|
|
|
|
FAR struct console_stdio_s *pstate = (FAR struct console_stdio_s *)vtbl;
|
|
|
|
FAR char *pair;
|
|
|
|
FAR char *value = NULL;
|
|
|
|
|
|
|
|
DEBUGASSERT(pstate != NULL && name != NULL);
|
|
|
|
|
|
|
|
/* Check if the variable exists */
|
|
|
|
|
|
|
|
if ((pair = nsh_findvar(pstate, name)) == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* It does! Get the value sub-string from the name=value string */
|
|
|
|
|
|
|
|
value = strchr(pair, '=');
|
|
|
|
DEBUGASSERT(value != NULL);
|
|
|
|
|
|
|
|
/* Adjust the pointer so that it points to the value right after the '=' */
|
|
|
|
|
|
|
|
value++;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: nsh_setvar
|
|
|
|
****************************************************************************/
|
|
|
|
|
2018-10-01 23:44:41 +02:00
|
|
|
#ifndef CONFIG_NSH_DISABLE_SET
|
2018-10-01 21:31:06 +02:00
|
|
|
int nsh_setvar(FAR struct nsh_vtbl_s *vtbl, FAR const char *name,
|
|
|
|
FAR const char *value)
|
|
|
|
{
|
|
|
|
FAR struct console_stdio_s *pstate = (FAR struct console_stdio_s *)vtbl;
|
|
|
|
FAR char *pair;
|
|
|
|
FAR char *newvarp;
|
|
|
|
int newsize;
|
|
|
|
int varlen;
|
|
|
|
|
|
|
|
DEBUGASSERT(pstate != NULL && name != NULL && value != NULL);
|
|
|
|
|
|
|
|
/* Check if the variable already exists */
|
|
|
|
|
|
|
|
if (pstate->varp != NULL &&
|
|
|
|
(pair = nsh_findvar(pstate, name)) != NULL)
|
|
|
|
{
|
|
|
|
/* Yes.. Remove the name=value pair from the NSH variable buffer. It
|
|
|
|
* will be added again below.
|
|
|
|
*/
|
|
|
|
|
2020-01-02 13:09:50 +01:00
|
|
|
nsh_removevar(pstate, pair);
|
2018-10-01 21:31:06 +02:00
|
|
|
}
|
|
|
|
|
2020-11-02 12:30:26 +01:00
|
|
|
/* Get the size of the new name=value string. The +2 is for the '=' and
|
|
|
|
* for null terminator
|
2018-10-01 21:31:06 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
varlen = strlen(name) + strlen(value) + 2;
|
|
|
|
|
|
|
|
/* Then allocate or reallocate the NSH variable buffer */
|
|
|
|
|
|
|
|
if (pstate->varp != NULL)
|
|
|
|
{
|
|
|
|
newsize = pstate->varsz + varlen;
|
|
|
|
newvarp = (FAR char *)realloc(pstate->varp, newsize);
|
|
|
|
if (newvarp == NULL)
|
|
|
|
{
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
pair = &newvarp[pstate->varsz];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
newsize = varlen;
|
|
|
|
newvarp = (FAR char *)malloc(varlen);
|
|
|
|
if (!newvarp)
|
|
|
|
{
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
pair = newvarp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save the new buffer and size */
|
|
|
|
|
|
|
|
pstate->varp = newvarp;
|
|
|
|
pstate->varsz = newsize;
|
|
|
|
|
|
|
|
/* Now, put the new name=value string into the NSH variable buffer */
|
|
|
|
|
2023-03-05 16:55:15 +01:00
|
|
|
snprintf(pair, varlen, "%s=%s", name, value);
|
2018-10-01 21:31:06 +02:00
|
|
|
return OK;
|
|
|
|
}
|
2018-10-01 23:44:41 +02:00
|
|
|
#endif
|
2018-10-01 21:31:06 +02:00
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: nsh_unsetvar
|
|
|
|
****************************************************************************/
|
|
|
|
|
2018-10-01 23:44:41 +02:00
|
|
|
#if !defined(CONFIG_NSH_DISABLE_UNSET) || !defined(CONFIG_NSH_DISABLE_EXPORT)
|
2018-10-01 21:31:06 +02:00
|
|
|
int nsh_unsetvar(FAR struct nsh_vtbl_s *vtbl, FAR const char *name)
|
|
|
|
{
|
|
|
|
FAR struct console_stdio_s *pstate = (FAR struct console_stdio_s *)vtbl;
|
|
|
|
FAR char *pair;
|
|
|
|
FAR char *newvarp;
|
|
|
|
int newsize;
|
|
|
|
int ret = OK;
|
|
|
|
|
|
|
|
DEBUGASSERT(name != NULL && pstate != NULL);
|
|
|
|
|
|
|
|
/* Check if the variable exists */
|
|
|
|
|
|
|
|
if (pstate != NULL && (pair = nsh_findvar(pstate, name)) != NULL)
|
|
|
|
{
|
|
|
|
/* It does! Remove the name=value pair from the NSH variables. */
|
|
|
|
|
2020-01-02 13:09:50 +01:00
|
|
|
nsh_removevar(pstate, pair);
|
2018-10-01 21:31:06 +02:00
|
|
|
|
|
|
|
/* Reallocate the new NSH variable buffer */
|
|
|
|
|
|
|
|
newsize = pstate->varsz;
|
|
|
|
if (newsize <= 0)
|
|
|
|
{
|
|
|
|
/* Free the old NSH variable (if there was one) */
|
|
|
|
|
|
|
|
if (pstate->varp != NULL)
|
|
|
|
{
|
|
|
|
free(pstate->varp);
|
|
|
|
pstate->varp = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pstate->varsz = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Reallocate the NSH variable buffer to reclaim a little memory */
|
|
|
|
|
|
|
|
newvarp = (FAR char *)realloc(pstate->varp, newsize);
|
|
|
|
if (newvarp == NULL)
|
|
|
|
{
|
|
|
|
return -ENOMEM; /* Shouldn't happen when realloc'ing down */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Save the new NSH variable pointer (it might have changed due
|
|
|
|
* to reallocation).
|
|
|
|
*/
|
|
|
|
|
|
|
|
pstate->varp = newvarp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sched_unlock();
|
|
|
|
return ret;
|
|
|
|
}
|
2018-10-01 23:44:41 +02:00
|
|
|
#endif
|
2018-10-01 21:31:06 +02:00
|
|
|
|
2018-10-02 19:54:18 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: nsh_foreach_var
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Visit each name-value pair in the environment.
|
|
|
|
*
|
|
|
|
* Input Parameters:
|
|
|
|
* vtbl - NSH session data
|
|
|
|
* cb - The callback function to be invoked for each environment
|
|
|
|
* variable.
|
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* Zero if the all NSH variables have been traversed. A non-zero value
|
|
|
|
* means that the callback function requested early termination by
|
|
|
|
* returning a nonzero value.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifndef CONFIG_NSH_DISABLE_SET
|
|
|
|
int nsh_foreach_var(FAR struct nsh_vtbl_s *vtbl, nsh_foreach_var_t cb,
|
|
|
|
FAR void *arg)
|
|
|
|
{
|
|
|
|
FAR struct console_stdio_s *pstate = (FAR struct console_stdio_s *)vtbl;
|
|
|
|
FAR char *ptr;
|
|
|
|
FAR char *end;
|
|
|
|
int ret = OK;
|
|
|
|
|
|
|
|
/* Verify input parameters */
|
|
|
|
|
|
|
|
DEBUGASSERT(pstate != NULL && cb != NULL);
|
|
|
|
|
|
|
|
/* Search for a name=value string with matching name */
|
|
|
|
|
|
|
|
end = &pstate->varp[pstate->varsz];
|
|
|
|
for (ptr = pstate->varp; ptr < end; ptr += (strlen(ptr) + 1))
|
|
|
|
{
|
|
|
|
/* Perform the callback */
|
|
|
|
|
|
|
|
ret = cb(vtbl, arg, ptr);
|
|
|
|
|
|
|
|
/* Terminate the traversal early if the callback so requests by
|
|
|
|
* returning a non-zero value.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (ret != 0)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-10-01 21:31:06 +02:00
|
|
|
#endif /* CONFIG_NSH_VARS */
|