/**************************************************************************** * apps/nshlib/nsh_test.c * * Copyright (C) 2008, 2011-2012, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /* 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 #include #include #include #include "nsh.h" #include "nsh_console.h" #if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_TEST) /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #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) { return TEST_FALSE; } ret = stat(fullpath, &buf); nsh_freefullpath(fullpath); if (ret != 0) { /* The file does not exist (or another error occurred) -- return * FALSE. */ return TEST_FALSE; } /* -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 */ return (buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) != 0 ? TEST_TRUE : TEST_FALSE; } /* -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 */ return (buf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0 ? TEST_TRUE : TEST_FALSE; } /* 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; } return expression(vtbl, argc - 1, &argv[1]) == TEST_TRUE ? TEST_FALSE : TEST_TRUE; } /* Check for unary operations on simple, typed arguments */ else if (argv[0][0] == '-') { if (argc < 2) { goto errout_syntax; } i += 2; value = unaryexpression(vtbl, argv); } /* Check for binary operations on simple, typed arguments */ else { if (argc < 3) { goto errout_syntax; } 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 */ 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; } } return value; errout_syntax: nsh_error(vtbl, g_fmtsyntax, "test"); return TEST_FALSE; } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: cmd_test ****************************************************************************/ int cmd_test(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { return expression(vtbl, argc - 1, &argv[1]); } /**************************************************************************** * Name: cmd_lbracket ****************************************************************************/ int cmd_lbracket(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { /* Verify that the closing right bracket is the last thing on the command * line. */ if (strcmp(argv[argc - 1], "]") != 0) { nsh_error(vtbl, g_fmtsyntax, argv[0]); return ERROR; } /* Then perform the test on the arguments enclosed by the left and right * brackets. */ return expression(vtbl, argc - 2, &argv[1]); } #endif /* !CONFIG_NSH_DISABLESCRIPT && !CONFIG_NSH_DISABLE_TEST */