Skip to content

Commit

Permalink
Merge branch 'feature-issue23' #23
Browse files Browse the repository at this point in the history
* feature-issue23:
  Updated CHANGES for this issue.
  Merged 'master' into 'feature-issue23' branch.
  Added a small contribution.
  Small correction in exprtk attribute documentation.
  Added documentation for exprtk attribute on <property> elements.
  Small corrections.
  Fixed libEval::evaluate() to prevent buffer overflows.
  Implemented exprtk attribute support for ActionProperty. Created unit tests for ActionProperty.
  Implemented exprtk error logging when validating for visibility or validity. Errors are added to the logs.
  Implemented error support in libEval (with unit tests).
  Updated INSTALL.md document for exprtk dependency. Updated UserManual.md for exprtk attribute
  Added exprtk license file: exprtk LICENSE.txt
  Implemented logging for Validator class when an invalid value for class or exprtk attributes. Implemented more testing for exprtk attribute. Added exprtk license file: exprtk LICENSE.txt
  Implemented inversed exprtk support and tests.
  Implemented parsing of attribute `exprtk`. For issue #23.
  Partially reverted code that was commented in error.
  Added a dependency to Exprtk. The library is downloaded and used automatically. The project `libeval` was created to wrap exprtk library for easier usage. Implemented Validator::SetExprtk() and Validator::GetExprtk() with tests. Created the following new properties: `selection.count`, `selection.files.count` and `selection.directories.count`. For issue #23.
  Enabled building of branch `feature-issue23`.
  • Loading branch information
end2endzone committed Nov 14, 2020
2 parents b0ebc99 + da19eaf commit 5969148
Show file tree
Hide file tree
Showing 24 changed files with 1,194 additions and 6 deletions.
5 changes: 5 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
Changes for 0.6.0

* Fixed issue #23: Implement menu validation based on a string expression


Changes for 0.5.1

* Fixed issue #75: Wix Installer: Incorrect shortcuts in Start Menu
Expand Down
37 changes: 37 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,43 @@ find_package(WIX)
find_package(NSIS)
find_package(GRIP)

##############################################################################################################################################
# Dependencies
##############################################################################################################################################

# packages directory
set(PACKAGE_DOWNLOAD_DIR ${CMAKE_BINARY_DIR}/external)
if(NOT EXISTS ${PACKAGE_DOWNLOAD_DIR})
file(MAKE_DIRECTORY ${PACKAGE_DOWNLOAD_DIR})
endif()

# exprtk
# The exprtk library do not provides version based releases.
# At the time of this writing, HEAD revision is commit d312ba91419c9cb12c8279fd3a19096d39dfcb5e
# available at https://github.com/ArashPartow/exprtk/archive/d312ba91419c9cb12c8279fd3a19096d39dfcb5e.zip
# Using latest revision to get all bug fixes.
set(EXPRTK_PACKAGE_URL "https://github.com/ArashPartow/exprtk/archive/master.zip")
set(EXPRTK_PACKAGE_PATH ${PACKAGE_DOWNLOAD_DIR}/exprtk.zip)
if(NOT EXISTS ${EXPRTK_PACKAGE_PATH})
message(STATUS "Downloading exprtk package from ${EXPRTK_PACKAGE_URL}")
file(DOWNLOAD ${EXPRTK_PACKAGE_URL} ${EXPRTK_PACKAGE_PATH}
TIMEOUT 60 # seconds
TLS_VERIFY ON
)

message(STATUS "Extracting exprtk package to ${EXPRTK_PACKAGE_PATH}")
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf
${EXPRTK_PACKAGE_PATH}
WORKING_DIRECTORY ${PACKAGE_DOWNLOAD_DIR}
)
endif()
set(EXPRTK_HEADER_PATH ${PACKAGE_DOWNLOAD_DIR}/exprtk-master/exprtk.hpp)
if(EXISTS ${EXPRTK_HEADER_PATH})
message(STATUS "Found exprtk header file: ${EXPRTK_HEADER_PATH}")
else()
message(FATAL_ERROR "exprtk header file not found.")
endif()

##############################################################################################################################################
# Standard CMake variables
##############################################################################################################################################
Expand Down
2 changes: 1 addition & 1 deletion INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ The following software must be installed on the system for compiling source code
* [Google Logging Library v0.4.0](https://github.com/google/glog/tree/v0.4.0)
* [TinyXML 2 v6.2.0](https://github.com/leethomason/tinyxml2/tree/6.2.0)
* [RapidAssist v0.8.1](https://github.com/end2endzone/RapidAssist/tree/0.8.1)
* [exprtk d312ba9](https://github.com/ArashPartow/exprtk) (downloaded automatically)
* [CMake](http://www.cmake.org/) v3.4.3 (or newer)
* (optional) [Grip (GitHub Readme Instant Preview)](https://github.com/joeyespo/grip) v4.5.2 (or newer)



### Windows Requirements ###

* Microsoft Visual C++ 2010 or newer
Expand Down
77 changes: 75 additions & 2 deletions UserManual.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ This manual includes a description of the system functionalities and capabilitie
* [pattern attribute](#pattern-attribute)
* [exists attribute](#exists-attribute)
* [properties attribute](#properties-attribute)
* [exprtk attribute](#exprtk-attribute)
* [inverse attribute](#inverse-attribute)
* [Icons](#icons)
* [Actions](#actions)
Expand Down Expand Up @@ -385,6 +386,42 @@ See [properties](#properties) section for how to define custom properties.



### exprtk attribute: ###

The `exprtk` attribute validates a menu based on a string expression algorithm. The expression must be specified as a mathematical expression and the result must evaluates to `true` or `false` such as `4 == 5` or `10 > 3`.

If `exprtk` attribute is specified, the expression must evaluates to `true` for the validation to be successful. The `exprtk` attribute does not support multiple expressions but logical `and` and `or` operators can be use to group expressions.

If `exprtk` attribute is not specified, then the validation is successful.

The attribute supports the following operators:
* Basic operators: `+`, `-`, `*`, `/`, `%`, `^`
* Equalities & Inequalities: `=`, `==`, `<>`, `!=`, `<`, `<=`, `>`, `>=`
* Logic operators: `and`, `not`, `or`, `xor`, `true`, `false`
* String operators: `in`, `like`, `ilike`, []

Strings may be comprised of any combination of letters, digits special characters including (~!@#$%^&*()[]|=+ ,./?<>;:"_) or hexadecimal escaped sequences (eg: \0x30) and must be enclosed with single-quotes.
eg: `'Frankly my dear, \0x49 do n0t give a damn!'`

The `exprtk` attribute allows advanced menu validation. The following table show useful expression examples:

| Use cases | Expression | Meaning |
|------------------------------------------------------------------|-----------------------------------|----------------------------------------------------------------------------------------------------------------------------|
| Test a property for a numeric value | ${value} == 6 | Evaluates to true when property `value` is set to numeric value `6`. |
| Test a property for a string value. | '${name}' == 'John' | Evaluates to true when property `name` is set to string value `John`. |
| Set a menu visible based on how many file are selected | ${selection.count} == 3 | Evaluates to true when user clicked on exactly 3 elements. |
| Set a menu visible based on a state machine | '${myapp.state}' == 'PAUSED' | Evaluates to true when application's state is `PAUSED`. |
| Set a menu *invisible* when it was selected 3 times. | ${myapp.runs} <= 2 | Evaluates to true when property `myapp.runs` is lower or equals to `2`. |
| Set a menu visible by filename length. | '${selection.filename}'[] == 9 | Evaluates to true when user clicked on a file whose filename<br>(including file extension) is exactly 9 characters. |
| Combine expressions with `and` and `or` logic. | ${foo} == 2 or ${bar} >= 5 | Evaluates to true when property `foo` is set to `2` *or*<br>when property `bar` is set to a value greater or equal to `5`. |
| Set a menu visible if user selection contains a specific string. | 'abc' in '${selection.path}' | Evaluates to true when user clicked on a file that contains the string `abc`. |
| Set a menu visible if user selection matches a string pattern. | '${selection.path}' ilike '*.exe' | Evaluates to true when user clicked on a file with `exe` extension. |

**Note:**
The `exprtk` attribute uses the *exprtk library* to parse the expression. For more details and supported expressions, see the exprtk documentation on the [official github page](https://github.com/ArashPartow/exprtk) or the [library website](http://www.partow.net/programming/exprtk/index.html).



### inverse attribute: ###

The `inverse` attribute inverts the logic of one or multiple attributes. For example, to inverse the meaning of the `maxfiles` attribute, set `inverse` attribute to the value `maxfiles`.
Expand Down Expand Up @@ -769,7 +806,7 @@ For example, the following sets the property `myprogram.user.name` to an empty v

#### value attribute: ####

The `value` attribute defines the actual new value of the given property.
The `value` attribute defines the new value of the given property.

For example, the following set the property `myprogram.user.name` to value `Al Coholic` :
```xml
Expand All @@ -778,6 +815,37 @@ For example, the following set the property `myprogram.user.name` to value `Al C



#### exprtk attribute: ####

The `exprtk` attribute defines an expression that is evaluated to set a new value for the given property. The expression must be specified as a mathematical expression and the result must evaluates to an integer or a floating point value such as `4+9` or `${foo}+1`.

The `exprtk` attribute can also be set to an expression that evaluates to `true` or `false` and logical `and` and `or` operators can be use to group expressions. eg: `${foo.count} > 1 and '${foo.state}'=='PAUSED'`.

The attribute supports the following operators:
* Basic operators: `+`, `-`, `*`, `/`, `%`, `^`
* Equalities & Inequalities: `=`, `==`, `<>`, `!=`, `<`, `<=`, `>`, `>=`
* Logic operators: `and`, `not`, `or`, `xor`, `true`, `false`
* String operators: `in`, `like`, `ilike`, []

Strings may be comprised of any combination of letters, digits special characters including (~!@#$%^&*()[]|=+ ,./?<>;:"_) or hexadecimal escaped sequences (eg: \0x30) and must be enclosed with single-quotes.
eg: `'Frankly my dear, \0x49 do n0t give a damn!'`

The `exprtk` attribute allows advanced property evaluation. The following table show useful expression examples:

| Use cases | Expression | Meaning |
|-----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Update a property using a generic equation | \${myvalue}^2 + 5*\${myvalue} + 100 | Evaluate the quadratic equation `x^2 + 5x + 100` where `x` is equal to the value of property `myvalue`. |
| Create a counter using properties.<br>(with a default property value set) | \<property name="mycounter" exprtk="${mycounter}+1"\> | The property update itself by increasing its own value by 1.<br>Note: this only work if the property is defined to a numeric value first. |
| Create a counter using properties.<br>(without having to initialize the property first) | if ('\${mycounter}' == '$'+'{mycounter}' or '\${mycounter}' == '0') 1;<br>else if ('\${mycounter}' == '1') 2;<br>else if ('\${mycounter}' == '2') 3;<br>else if ('\${mycounter}' == '3') 4;<br>else if ('\${mycounter}' == '4') 5;<br>else if ('\${mycounter}' == '5') 6;<br>else if ('\${mycounter}' == '6') 7;<br>else if ('\${mycounter}' == '7') 8;<br>else if ('\${mycounter}' == '8') 9;<br>else 10; | Increase the value of property `mycounter` by `1` going from `1` up to `10`.<br>On the first call, the first line of the expression detects if the property is unset and set it to `1`. |
| Get the length of a property value. | '\${command}'[] | Set the property to the length of the `command` property value. |
| Set a property to logical `true` or `false`. | ${foo} == 2 or ${bar} >= 5 | The property will be set to value `1` if the expression evaluates to `true` <br>and set to `0` if the expression evaluates to `false`. |


**Note:**
The `exprtk` attribute uses the *exprtk library* to parse the expression. For more details and supported expressions, see the exprtk documentation on the [official github page](https://github.com/ArashPartow/exprtk) or the [library website](http://www.partow.net/programming/exprtk/index.html).



### &lt;file&gt; action ###

The &lt;file&gt; element is used to create a text file on disk. The content of the file is specified between the opening and closing tags of the &lt;file&gt; element. The &lt;file&gt; element supports dynamic properties and can be used to create default configuration files or create support files for the menu.
Expand Down Expand Up @@ -953,6 +1021,9 @@ The following table defines the list of dynamic properties and their utility:
| selection.filename.extension | Matches the file extension of the clicked element. |
| selection.drive.letter | Matches the drive letter of the clicked element. For example 'C'. |
| selection.drive.path | Matches the drive path of the clicked element. For example 'C:\'. |
| selection.count | Matches the number of clicked elements (files and directories). |
| selection.files.count | Matches the number of clicked files. |
| selection.directories.count | Matches the number of clicked directories. |

Selection-based properties are encoded in utf-8.

Expand Down Expand Up @@ -981,7 +1052,9 @@ The system will generates the following property values (note the `\r\n` charact
| selection.drive.letter | C`\r\n`C`\r\n`C |
| selection.drive.path | C:\\`\r\n`C:\\`\r\n`C:\\ |

Note that properties `selection.drive.letter` and `selection.drive.path` are empty when all selected files are from a network share.
Notes:
* Properties `selection.drive.letter` and `selection.drive.path` are empty when all selected files are from a network share.
* Properties `selection.count`, `selection.files.count` and `selection.directories.count` are not multi-selection-based properties. They are defined as a single value whether a single or multiple elements are selected.



Expand Down
11 changes: 11 additions & 0 deletions include/shellanything/ActionProperty.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,20 @@ namespace shellanything
/// </summary>
void SetValue(const std::string & iValue);

/// <summary>
/// Getter for the 'exprtk' parameter.
/// </summary>
const std::string & GetExprtk() const;

/// <summary>
/// Setter for the 'exprtk' parameter.
/// </summary>
void SetExprtk(const std::string & iExprtk);

private:
std::string mName;
std::string mValue;
std::string mExprtk;
};


Expand Down
12 changes: 12 additions & 0 deletions include/shellanything/Validator.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,16 @@ namespace shellanything
/// </summary>
void SetPattern(const std::string & iPattern);

/// <summary>
/// Getter for the 'exprtk' parameter.
/// </summary>
const std::string & GetExprtk() const;

/// <summary>
/// Setter for the 'exprtk' parameter.
/// </summary>
void SetExprtk(const std::string & iExprtk);

/// <summary>
/// Getter for the 'inserve' parameter.
/// </summary>
Expand Down Expand Up @@ -152,6 +162,7 @@ namespace shellanything
bool ValidateClass(const Context & context, const std::string & class_, bool inversed) const;
bool ValidateClassSingle(const Context & context, const std::string & class_, bool inversed) const;
bool ValidatePattern(const Context & context, const std::string & pattern, bool inversed) const;
bool ValidateExprtk(const Context & context, const std::string & exprtk, bool inversed) const;

private:
int mMaxFiles;
Expand All @@ -161,6 +172,7 @@ namespace shellanything
std::string mFileExists;
std::string mClass;
std::string mPattern;
std::string mExprtk;
std::string mInverse;
};

Expand Down
18 changes: 18 additions & 0 deletions licenses/exprtk LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.

Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.

2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.

3. This notice may not be removed or altered from any source
distribution.
Loading

0 comments on commit 5969148

Please sign in to comment.