2011-03-18 20:46:25 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* apps/nshlib/nsh_test.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
|
|
|
|
*
|
|
|
|
* 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.
|
2011-03-18 20:46:25 +01:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/* Test syntax:
|
|
|
|
*
|
|
|
|
* expression = simple-expression | !expression |
|
|
|
|
* expression -o expression | expression -a expression
|
|
|
|
*
|
|
|
|
* simple-expression = unary-expression | binary-expression
|
|
|
|
*
|
|
|
|
* unary-expression = string-unary | file-unary
|
|
|
|
*
|
|
|
|
* string-unary = -n string | -z string
|
|
|
|
*
|
|
|
|
* file-unary = -b file | -c file | -d file | -e file | -f file |
|
|
|
|
* -r file | -s file | -w file
|
|
|
|
*
|
|
|
|
* binary-expression = string-binary | numeric-binary
|
|
|
|
*
|
|
|
|
* string-binary = string = string | string == string | string != string
|
|
|
|
*
|
|
|
|
* numeric-binary = integer -eq integer | integer -ge integer |
|
|
|
|
* integer -gt integer | integer -le integer |
|
|
|
|
* integer -lt integer | integer -ne integer
|
|
|
|
*
|
|
|
|
* Note that the smallest expression consists of two strings.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Included Files
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "nsh.h"
|
2012-02-02 17:04:09 +01:00
|
|
|
#include "nsh_console.h"
|
2011-03-18 20:46:25 +01:00
|
|
|
|
2011-03-18 21:35:31 +01:00
|
|
|
#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_TEST)
|
2011-03-18 20:46:25 +01:00
|
|
|
|
|
|
|
/****************************************************************************
|
2015-10-02 22:06:11 +02:00
|
|
|
* Pre-processor Definitions
|
2011-03-18 20:46:25 +01:00
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#define TEST_TRUE OK
|
|
|
|
#define TEST_FALSE ERROR
|
|
|
|
#define TEST_ERROR 1
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: binaryexpression
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static inline int binaryexpression(FAR struct nsh_vtbl_s *vtbl, char **argv)
|
|
|
|
{
|
|
|
|
char *endptr;
|
|
|
|
long integer1;
|
|
|
|
long integer2;
|
|
|
|
|
|
|
|
/* STRING2 = STRING2 */
|
|
|
|
|
|
|
|
if (strcmp(argv[1], "=") == 0 || strcmp(argv[1], "==") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the strings are identical */
|
|
|
|
|
|
|
|
return strcmp(argv[0], argv[2]) == 0 ? TEST_TRUE : TEST_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* STRING1 != STRING2 */
|
|
|
|
|
|
|
|
if (strcmp(argv[1], "!=") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the strings are different */
|
|
|
|
|
|
|
|
return strcmp(argv[0], argv[2]) != 0 ? TEST_TRUE : TEST_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The remaining operators assuming that the two values are integers */
|
|
|
|
|
|
|
|
integer1 = strtol(argv[0], &endptr, 0);
|
|
|
|
if (argv[0][0] == '\0' || *endptr != '\0')
|
|
|
|
{
|
|
|
|
return TEST_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
integer2 = strtol(argv[2], &endptr, 0);
|
|
|
|
if (argv[2][0] == '\0' || *endptr != '\0')
|
|
|
|
{
|
|
|
|
return TEST_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* INTEGER1 -eq INTEGER2 */
|
|
|
|
|
|
|
|
if (strcmp(argv[1], "-eq") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the strings are different */
|
|
|
|
|
|
|
|
return integer1 == integer2 ? TEST_TRUE : TEST_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* INTEGER1 -ge INTEGER2 */
|
|
|
|
|
|
|
|
if (strcmp(argv[1], "-ge") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the strings are different */
|
|
|
|
|
|
|
|
return integer1 >= integer2 ? TEST_TRUE : TEST_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* INTEGER1 -gt INTEGER2 */
|
|
|
|
|
|
|
|
if (strcmp(argv[1], "-gt") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the strings are different */
|
|
|
|
|
|
|
|
return integer1 > integer2 ? TEST_TRUE : TEST_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* INTEGER1 -le INTEGER2 */
|
|
|
|
|
|
|
|
if (strcmp(argv[1], "-le") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the strings are different */
|
|
|
|
|
|
|
|
return integer1 <= integer2 ? TEST_TRUE : TEST_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* INTEGER1 -lt INTEGER2 */
|
|
|
|
|
|
|
|
if (strcmp(argv[1], "-lt") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the strings are different */
|
|
|
|
|
|
|
|
return integer1 < integer2 ? TEST_TRUE : TEST_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* INTEGER1 -ne INTEGER2 */
|
|
|
|
|
|
|
|
if (strcmp(argv[1], "-ne") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the strings are different */
|
|
|
|
|
|
|
|
return integer1 != integer2 ? TEST_TRUE : TEST_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TEST_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: unaryexpression
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static inline int unaryexpression(FAR struct nsh_vtbl_s *vtbl, char **argv)
|
|
|
|
{
|
|
|
|
struct stat buf;
|
|
|
|
char *fullpath;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* -n STRING */
|
|
|
|
|
|
|
|
if (strcmp(argv[0], "-n") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the length of the string is non-zero */
|
|
|
|
|
|
|
|
return strlen(argv[1]) != 0 ? TEST_TRUE : TEST_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -z STRING */
|
|
|
|
|
|
|
|
if (strcmp(argv[0], "-z") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the length of the string is zero */
|
|
|
|
|
|
|
|
return strlen(argv[1]) == 0 ? TEST_TRUE : TEST_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All of the remaining assume that the following argument is the
|
|
|
|
* path to a file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
fullpath = nsh_getfullpath(vtbl, argv[1]);
|
|
|
|
if (!fullpath)
|
|
|
|
{
|
2020-11-02 12:30:26 +01:00
|
|
|
return TEST_FALSE;
|
2011-03-18 20:46:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = stat(fullpath, &buf);
|
|
|
|
nsh_freefullpath(fullpath);
|
|
|
|
|
|
|
|
if (ret != 0)
|
|
|
|
{
|
2020-11-02 12:30:26 +01:00
|
|
|
/* The file does not exist (or another error occurred) -- return
|
|
|
|
* FALSE.
|
|
|
|
*/
|
2011-03-18 20:46:25 +01:00
|
|
|
|
2020-11-02 12:30:26 +01:00
|
|
|
return TEST_FALSE;
|
2011-03-18 20:46:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* -b FILE */
|
|
|
|
|
|
|
|
if (strcmp(argv[0], "-b") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the path is a block device */
|
|
|
|
|
|
|
|
return S_ISBLK(buf.st_mode) ? TEST_TRUE : TEST_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -c FILE */
|
|
|
|
|
|
|
|
if (strcmp(argv[0], "-c") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the path is a character device */
|
|
|
|
|
|
|
|
return S_ISCHR(buf.st_mode) ? TEST_TRUE : TEST_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -d FILE */
|
|
|
|
|
|
|
|
if (strcmp(argv[0], "-d") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the path is a directory */
|
|
|
|
|
|
|
|
return S_ISDIR(buf.st_mode) ? TEST_TRUE : TEST_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -e FILE */
|
|
|
|
|
|
|
|
if (strcmp(argv[0], "-e") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the file exists */
|
|
|
|
|
|
|
|
return TEST_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -f FILE */
|
|
|
|
|
|
|
|
if (strcmp(argv[0], "-f") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the path refers to a regular file */
|
|
|
|
|
|
|
|
return S_ISREG(buf.st_mode) ? TEST_TRUE : TEST_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -r FILE */
|
|
|
|
|
|
|
|
if (strcmp(argv[0], "-r") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the file is readable */
|
|
|
|
|
2020-11-02 12:30:26 +01:00
|
|
|
return (buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) != 0 ?
|
2018-08-11 18:19:47 +02:00
|
|
|
TEST_TRUE : TEST_FALSE;
|
2011-03-18 20:46:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* -s FILE */
|
|
|
|
|
|
|
|
if (strcmp(argv[0], "-s") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the size of the file is greater than zero */
|
|
|
|
|
|
|
|
return buf.st_size > 0 ? TEST_TRUE : TEST_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -w FILE */
|
|
|
|
|
|
|
|
if (strcmp(argv[0], "-w") == 0)
|
|
|
|
{
|
|
|
|
/* Return true if the file is write-able */
|
|
|
|
|
2020-11-02 12:30:26 +01:00
|
|
|
return (buf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0 ?
|
2018-08-11 18:19:47 +02:00
|
|
|
TEST_TRUE : TEST_FALSE;
|
2011-03-18 20:46:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Unrecognized operator */
|
|
|
|
|
|
|
|
return TEST_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: expression
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int expression(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
|
|
|
|
{
|
|
|
|
int value;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
/* Check for unary operations on expressions */
|
|
|
|
|
|
|
|
if (strcmp(argv[0], "!") == 0)
|
|
|
|
{
|
|
|
|
if (argc < 2)
|
|
|
|
{
|
|
|
|
goto errout_syntax;
|
|
|
|
}
|
2018-08-11 18:19:47 +02:00
|
|
|
|
2020-11-02 12:30:26 +01:00
|
|
|
return expression(vtbl, argc - 1, &argv[1]) == TEST_TRUE ?
|
2018-08-11 18:19:47 +02:00
|
|
|
TEST_FALSE : TEST_TRUE;
|
2011-03-18 20:46:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for unary operations on simple, typed arguments */
|
|
|
|
|
|
|
|
else if (argv[0][0] == '-')
|
|
|
|
{
|
|
|
|
if (argc < 2)
|
|
|
|
{
|
|
|
|
goto errout_syntax;
|
|
|
|
}
|
2018-08-11 18:19:47 +02:00
|
|
|
|
2011-03-18 20:46:25 +01:00
|
|
|
i += 2;
|
|
|
|
value = unaryexpression(vtbl, argv);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for binary operations on simple, typed arguments */
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (argc < 3)
|
|
|
|
{
|
|
|
|
goto errout_syntax;
|
|
|
|
}
|
2018-08-11 18:19:47 +02:00
|
|
|
|
2011-03-18 20:46:25 +01:00
|
|
|
i += 3;
|
|
|
|
value = binaryexpression(vtbl, argv);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Test if there any failure */
|
|
|
|
|
|
|
|
if (value == TEST_ERROR)
|
|
|
|
{
|
|
|
|
goto errout_syntax;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Is there anything after the simple expression? */
|
|
|
|
|
|
|
|
if (i < argc)
|
|
|
|
{
|
|
|
|
/* EXPRESSION -a EXPRESSION */
|
|
|
|
|
2020-11-02 12:30:26 +01:00
|
|
|
if (strcmp(argv[i], "-a") == 0)
|
|
|
|
{
|
|
|
|
if (value != TEST_TRUE)
|
|
|
|
{
|
|
|
|
return TEST_FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
return expression(vtbl, argc - i, &argv[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* EXPRESSION -o EXPRESSION */
|
|
|
|
|
|
|
|
else if (strcmp(argv[i], "-o") == 0)
|
|
|
|
{
|
|
|
|
if (value == TEST_TRUE)
|
|
|
|
{
|
|
|
|
return TEST_TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
return expression(vtbl, argc - i, &argv[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
goto errout_syntax;
|
|
|
|
}
|
2011-03-18 20:46:25 +01:00
|
|
|
}
|
2018-08-11 18:19:47 +02:00
|
|
|
|
2014-04-14 00:24:28 +02:00
|
|
|
return value;
|
2011-03-18 20:46:25 +01:00
|
|
|
|
|
|
|
errout_syntax:
|
2018-12-09 01:53:54 +01:00
|
|
|
nsh_error(vtbl, g_fmtsyntax, "test");
|
2011-03-18 20:46:25 +01:00
|
|
|
return TEST_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Public Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: cmd_test
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
int cmd_test(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
|
|
|
|
{
|
2020-11-02 12:30:26 +01:00
|
|
|
return expression(vtbl, argc - 1, &argv[1]);
|
2011-03-18 20:46:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: cmd_lbracket
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
int cmd_lbracket(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
|
|
|
|
{
|
2018-08-11 18:19:47 +02:00
|
|
|
/* Verify that the closing right bracket is the last thing on the command
|
|
|
|
* line.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (strcmp(argv[argc - 1], "]") != 0)
|
2011-03-18 20:46:25 +01:00
|
|
|
{
|
2018-12-09 01:53:54 +01:00
|
|
|
nsh_error(vtbl, g_fmtsyntax, argv[0]);
|
2011-03-18 20:46:25 +01:00
|
|
|
return ERROR;
|
|
|
|
}
|
2018-08-11 18:19:47 +02:00
|
|
|
|
2018-08-11 18:47:46 +02:00
|
|
|
/* Then perform the test on the arguments enclosed by the left and right
|
|
|
|
* brackets.
|
|
|
|
*/
|
2018-08-11 18:19:47 +02:00
|
|
|
|
2018-08-11 18:47:46 +02:00
|
|
|
return expression(vtbl, argc - 2, &argv[1]);
|
2011-03-18 20:46:25 +01:00
|
|
|
}
|
|
|
|
|
2011-03-18 21:35:31 +01:00
|
|
|
#endif /* !CONFIG_NSH_DISABLESCRIPT && !CONFIG_NSH_DISABLE_TEST */
|