Compare commits

..

1 Commits

Author SHA1 Message Date
b17dd06733 Call continuous function even if there is no data 2020-04-27 17:49:10 +02:00
32 changed files with 406 additions and 8887 deletions

2
.vscode/launch.json vendored
View File

@ -9,7 +9,7 @@
"type": "cppdbg", "type": "cppdbg",
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/output/example/example", "program": "${workspaceFolder}/output/example/example",
"args": ["/dev/pts/2"], "args": ["/dev/pts/4"],
"stopAtEntry": false, "stopAtEntry": false,
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"environment": [], "environment": [],

View File

@ -1,62 +1,59 @@
Mozilla Public License Version 2.0 Mozilla Public License Version 2.0
================================== ==================================
1. Definitions ### 1. Definitions
--------------
1.1. "Contributor" **1.1. “Contributor”**
means each individual or legal entity that creates, contributes to means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software. the creation of, or owns Covered Software.
1.2. "Contributor Version" **1.2. “Contributor Version”**
means the combination of the Contributions of others (if any) used means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution. by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution" **1.3. “Contribution”**
means Covered Software of a particular Contributor. means Covered Software of a particular Contributor.
1.4. "Covered Software" **1.4. “Covered Software”**
means Source Code Form to which the initial Contributor has attached means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case Form, and Modifications of such Source Code Form, in each case
including portions thereof. including portions thereof.
1.5. "Incompatible With Secondary Licenses" **1.5. “Incompatible With Secondary Licenses”**
means means
(a) that the initial Contributor has attached the notice described * **(a)** that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or in Exhibit B to the Covered Software; or
* **(b)** that the Covered Software was made available under the terms of
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the version 1.1 or earlier of the License, but not also under the
terms of a Secondary License. terms of a Secondary License.
1.6. "Executable Form" **1.6. “Executable Form”**
means any form of the work other than Source Code Form. means any form of the work other than Source Code Form.
1.7. "Larger Work" **1.7. “Larger Work”**
means a work that combines Covered Software with other material, in means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software. a separate file or files, that is not Covered Software.
1.8. "License" **1.8. “License”**
means this document. means this document.
1.9. "Licensable" **1.9. “Licensable”**
means having the right to grant, to the maximum extent possible, means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License. all of the rights conveyed by this License.
1.10. "Modifications" **1.10. “Modifications”**
means any of the following: means any of the following:
(a) any file in Source Code Form that results from an addition to, * **(a)** any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered deletion from, or modification of the contents of Covered
Software; or Software; or
* **(b)** any new file in Source Code Form that contains any Covered
(b) any new file in Source Code Form that contains any Covered
Software. Software.
1.11. "Patent Claims" of a Contributor **1.11. “Patent Claims” of a Contributor**
means any patent claim(s), including without limitation, method, means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the Contributor that would be infringed, but for the grant of the
@ -64,50 +61,49 @@ Mozilla Public License Version 2.0
made, import, or transfer of either its Contributions or its made, import, or transfer of either its Contributions or its
Contributor Version. Contributor Version.
1.12. "Secondary License" **1.12. “Secondary License”**
means either the GNU General Public License, Version 2.0, the GNU means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those Public License, Version 3.0, or any later versions of those
licenses. licenses.
1.13. "Source Code Form" **1.13. “Source Code Form”**
means the form of the work preferred for making modifications. means the form of the work preferred for making modifications.
1.14. "You" (or "Your") **1.14. “You” (or “Your”)**
means an individual or a legal entity exercising rights under this means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that License. For legal entities, “You” includes any entity that
controls, is controlled by, or is under common control with You. For controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct purposes of this definition, “control” means **(a)** the power, direct
or indirect, to cause the direction or management of such entity, or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than whether by contract or otherwise, or **(b)** ownership of more than
fifty percent (50%) of the outstanding shares or beneficial fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity. ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants ### 2. License Grants and Conditions
#### 2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free, Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license: non-exclusive license:
(a) under intellectual property rights (other than patent or trademark) * **(a)** under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available, Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and as part of a Larger Work; and
* **(b)** under Patent Claims of such Contributor to make, use, sell, offer
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version. Contributions or its Contributor Version.
2.2. Effective Date #### 2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first become effective for each Contribution on the date the Contributor first
distributes such Contribution. distributes such Contribution.
2.3. Limitations on Grant Scope #### 2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the this License. No additional rights or licenses will be implied from the
@ -115,49 +111,47 @@ distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor: Contributor:
(a) for any code that a Contributor has removed from Covered Software; * **(a)** for any code that a Contributor has removed from Covered Software;
or or
* **(b)** for infringements caused by: **(i)** Your and any other third party's
(b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or **(ii)** the combination of its
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor Contributions with other software (except as part of its Contributor
Version); or Version); or
* **(c)** under Patent Claims infringed by Covered Software in the absence of
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions. its Contributions.
This License does not grant any rights in the trademarks, service marks, This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4). the notice requirements in Section 3.4).
2.4. Subsequent Licenses #### 2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3). permitted under the terms of Section 3.3).
2.5. Representation #### 2.5. Representation
Each Contributor represents that the Contributor believes its Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License. to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use #### 2.6. Fair Use
This License is not intended to limit any rights You have under This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other applicable copyright doctrines of fair use, fair dealing, or other
equivalents. equivalents.
2.7. Conditions #### 2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1. in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form ### 3. Responsibilities
#### 3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under Modifications that You create or to which You contribute, must be under
@ -167,22 +161,22 @@ License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code attempt to alter or restrict the recipients' rights in the Source Code
Form. Form.
3.2. Distribution of Executable Form #### 3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then: If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code * **(a)** such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this * **(b)** You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License. the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work #### 3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice, You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for provided that You also comply with the requirements of this License for
@ -195,7 +189,7 @@ the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary Software under the terms of either this License or such Secondary
License(s). License(s).
3.4. Notices #### 3.4. Notices
You may not remove or alter the substance of any license notices You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty, (including copyright notices, patent notices, disclaimers of warranty,
@ -203,7 +197,7 @@ or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies. the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms #### 3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support, You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered indemnity or liability obligations to one or more recipients of Covered
@ -216,27 +210,27 @@ indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any disclaimers of warranty and limitations of liability specific to any
jurisdiction. jurisdiction.
4. Inability to Comply Due to Statute or Regulation
--------------------------------------------------- ### 4. Inability to Comply Due to Statute or Regulation
If it is impossible for You to comply with any of the terms of this If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with statute, judicial order, or regulation then You must: **(a)** comply with
the terms of this License to the maximum extent possible; and (b) the terms of this License to the maximum extent possible; and **(b)**
describe the limitations and the code they affect. Such description must describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it. recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically ### 5. Termination
**5.1.** The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such Contributor are reinstated **(a)** provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an Contributor explicitly and finally terminates Your grants, and **(b)** on an
ongoing basis, if such Contributor fails to notify You of the ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular come back into compliance. Moreover, Your grants from a particular
@ -246,62 +240,53 @@ first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice. Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent **5.2.** If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions, infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate. 2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all **5.3.** In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License have been validly granted by You or Your distributors under this License
prior to termination shall survive termination. prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************ ### 6. Disclaimer of Warranty
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation > Covered Software is provided under this License on an “as is”
------------- > basis, without warranty of any kind, either expressed, implied, or
> statutory, including, without limitation, warranties that the
> Covered Software is free of defects, merchantable, fit for a
> particular purpose or non-infringing. The entire risk as to the
> quality and performance of the Covered Software is with You.
> Should any Covered Software prove defective in any respect, You
> (not any Contributor) assume the cost of any necessary servicing,
> repair, or correction. This disclaimer of warranty constitutes an
> essential part of this License. No use of any Covered Software is
> authorized under this License except under this disclaimer.
### 7. Limitation of Liability
> Under no circumstances and under no legal theory, whether tort
> (including negligence), contract, or otherwise, shall any
> Contributor, or anyone who distributes Covered Software as
> permitted above, be liable to You for any direct, indirect,
> special, incidental, or consequential damages of any character
> including, without limitation, damages for lost profits, loss of
> goodwill, work stoppage, computer failure or malfunction, or any
> and all other commercial damages or losses, even if such party
> shall have been informed of the possibility of such damages. This
> limitation of liability shall not apply to liability for death or
> personal injury resulting from such party's negligence to the
> extent applicable law prohibits such limitation. Some
> jurisdictions do not allow the exclusion or limitation of
> incidental or consequential damages, so this exclusion and
> limitation may not apply to You.
### 8. Litigation
Any litigation relating to this License may be brought only in the Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal courts of a jurisdiction where the defendant maintains its principal
@ -310,8 +295,8 @@ jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims. cross-claims or counter-claims.
9. Miscellaneous
---------------- ### 9. Miscellaneous
This License represents the complete agreement concerning the subject This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be matter hereof. If any provision of this License is held to be
@ -320,24 +305,24 @@ necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor. shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions ### 10. Versions of the License
#### 10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or 10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a publish new versions of this License. Each version will be given a
distinguishing version number. distinguishing version number.
10.2. Effect of New Versions #### 10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software, of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license or under the terms of any subsequent version published by the license
steward. steward.
10.3. Modified Versions #### 10.3. Modified Versions
If you create software not governed by this License, and you want to If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a create a new license for such software, you may create and use a
@ -345,15 +330,13 @@ modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that any references to the name of the license steward (except to note that
such modified license differs from this License). such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary #### 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
Licenses
If You choose to distribute Source Code Form that is Incompatible With If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached. notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice ## Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this License, v. 2.0. If a copy of the MPL was not distributed with this
@ -366,8 +349,8 @@ for such a notice.
You may add additional accurate notices of copyright ownership. You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice ## Exhibit B - “Incompatible With Secondary Licenses” Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0. defined by the Mozilla Public License, v. 2.0.

187
README.md
View File

@ -1,188 +1,3 @@
# Shellmatta # shellmatta
A tiny and flexible shell implementation to be used on embedded devices. A tiny and flexible shell implementation to be used on embedded devices.
## Name
The name `shellmatta` is the combination of `shell` and `shimatta`.
What the hell is `shimatta` you might ask.
...well if you really wanna know you might reach out to these nerds that are
running domains like [shimatta.net](https://git.shimatta.net) or
[shimatta.de](https://git.shimatta.de).
Do not pretend i didn't warn you.
## Intention
The intention is to enable a software project of nearly any size to have a
runtime command line interface to simplify debugging or
configuration/calibration of any kind of device.
The `shellmatta` is designed to fit in most tiny microcontroller.
It is based on a simple character based interface and can work with for example
network sockets or simple uarts.
Some features are removable at build time to save ressources on really tiny
platforms.
## Features
The `shellmatta` piled up some features over time:
1. history buffer (configurable)
2. auto complete
3. heredoc like interface to pass multiline data
4. option parser (getopt like)
## Documentation
Besides this readme most documentation is integrated directly in the sourcecode
as doxygen parsable comments.
To build the doxygen documentation just run `make doc`.
The html and latex documentation will be exported to `output/doc`
## Integration into your project
The basic integration into a softwareproject is quite easy.
1. add all *.c files from the `src` to your build
2. include the `api/shellmatta.h` file
3. implement a write function to output the data from the shell
4. initialize the shell providing static buffers
5. implement and add commands
6. pass data into the shellmatta and watch the magic happen
7. static constant command list (if you do not like dynamic lists)
Code example:
```
#include "shellmatta.h"
#include <unistd.h>
shellmatta_retCode_t writeFct(const char* data, uint32_t length)
{
write(1, data, length);
return SHELLMATTA_OK;
}
static shellmatta_retCode_t exampleCmdFct(shellmatta_handle_t handle, const char *arguments, uint32_t length)
{
shellmatta_retCode_t ret;
char option;
static const shellmatta_opt_long_t options[] =
{
{"version", 'v', SHELLMATTA_OPT_ARG_NONE},
{NULL, '\0', SHELLMATTA_OPT_ARG_NONE}
};
ret = shellmatta_opt_long(handle, options, &option, NULL, NULL);
while(SHELLMATTA_OK == ret)
{
switch(option)
{
case 'v':
shellmatta_printf(handle, "This should represent the version of this command");
break;
default:
shellmatta_printf(handle, "Unknown option: %c\r\n", option);
break;
}
ret = shellmatta_opt_long(handle, options, &option, NULL, NULL);
}
(void)arguments;
(void)length;
return SHELLMATTA_OK;
}
shellmatta_cmd_t exampleCmd = { "example", /**< command name */
"e", /**< command alias */
"example command", /**< command help */
"example [options]\n" /**< command usage text */
"\t-v, --version - print the version of the command",
exampleCmdFct, /**< command function */
NULL}; /**< intenally used */
int main(void)
{
static char buffer[1024]; /**< memory for inptu buffer */
static char historyBuffer[4096]; /**< memory for history buffer */
static shellmatta_instance_t instance; /**< instance variable */
shellmatta_handle_t handle; /**< handle used for accessing */
/** -# initialize the shellmatta instance */
shellmatta_doInit( &instance,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->", /**< prompt text */
NULL, /**< optional static command list */
writeFct); /**< write function */
/** -# add the command - one command can only be added to one instance */
shellmatta_addCmd(handle, &exampleCmd);
/** -# ready to put some data in there */
shellmatta_processData(handle, "example --version\r", 18u);
return 0;
}
```
## Compile time configuration
There are some defines you can use to change the behaviour of the shellmatta:
| Define | Description |
| -------------------------- | ---------------------------------------------- |
| SHELLMATTA_STRIP_PRINTF | removes stdio dependencies to reduce footprint |
| SHELLMATTA_HELP_COMMAND | string to overwrite the help command name |
| SHELLMATTA_HELP_ALIAS | string to overwrite the help command alias |
| SHELLMATTA_HELP_HELP_TEXT | string to overwrite the help command help |
| SHELLMATTA_HELP_USAGE_TEXT | string to overwrite the help command usage |
## Example
There is a quite confusing example in this repo to show and test some features.
To build it just rum `make example`.
The binary will be built to `output/example/example`
It requires a serial device as parameter to run e.g. `/dev/tty0`
To be able to play around a bit you can create a local serial loopback using
socat.
```
socat -d -d pty,raw,echo=0 pty,raw,echo=0
```
This will create two serial devices which are connected with a loopback.
The device numbers in this example might change on your system.
You can use one of them starting the example e.g.
```
./output/example/example /dev/pts2
```
And use the other one to connect using the terminal tool of your choice e.g.
```
minicom -D /dev/pts3
```
## Running tests
There are some tests implemented using catch2 and the function fake framework.
To run the tests just do:
```
make test
```
To be able to build the coverage report you need an installation of
(gcovr)[https://pypi.org/project/gcovr].

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> * Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -13,7 +13,7 @@
*/ */
/** /**
* @addtogroup shellmatta_api Shellmatta API description * @addtogroup shellmatta_api
* @{ * @{
*/ */
@ -77,7 +77,6 @@ typedef struct
*/ */
typedef struct typedef struct
{ {
uint32_t argStart; /**< start of the arguments of the command */
uint32_t offset; /**< current offset of the option parser */ uint32_t offset; /**< current offset of the option parser */
uint32_t nextOffset; /**< offset of the next hunk */ uint32_t nextOffset; /**< offset of the next hunk */
uint32_t len; /**< length of the current hunk */ uint32_t len; /**< length of the current hunk */
@ -109,7 +108,7 @@ typedef struct shellmatta_cmd
char *cmd; /**< command name */ char *cmd; /**< command name */
char *cmdAlias; /**< command alias */ char *cmdAlias; /**< command alias */
char *helpText; /**< help text to print in "help" command */ char *helpText; /**< help text to print in "help" command */
char *usageText; /**< usage text - printed on "help cmd" */ char *usageText; /**< usage text to print on parameter error */
shellmatta_cmdFct_t cmdFct; /**< pointer to the cmd callack function */ shellmatta_cmdFct_t cmdFct; /**< pointer to the cmd callack function */
struct shellmatta_cmd *next; /**< pointer to next command or NULL */ struct shellmatta_cmd *next; /**< pointer to next command or NULL */
} shellmatta_cmd_t; } shellmatta_cmd_t;

View File

@ -830,8 +830,7 @@ WARN_LOGFILE =
# Note: If this tag is empty the current directory is searched. # Note: If this tag is empty the current directory is searched.
INPUT = src \ INPUT = src \
api \ api
doc
# This tag can be used to specify the character encoding of the source files # This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@ -2475,7 +2474,7 @@ DIAFILE_DIRS =
# generate a warning when it encounters a \startuml command in this case and # generate a warning when it encounters a \startuml command in this case and
# will not generate output for the diagram. # will not generate output for the diagram.
PLANTUML_JAR_PATH = /usr/bin PLANTUML_JAR_PATH =
# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a # When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
# configuration file for plantuml. # configuration file for plantuml.

View File

@ -1,11 +0,0 @@
/**
@mainpage
This is the entry to the doxygen documentation of the shellmatta library.
Please find the documenation here:
@subpage shellmatta
*/

View File

@ -1,35 +0,0 @@
/**
@page shellmatta Shellmatta
The shellmatta is a tiny shell implementation to be integrated in all kinds
of software projects to add a debug and configuration interface.
Please take a look at the README.md file for some information that might
not be included here.
@section shellmatta_api_section Shellmatta api description
The complete api of the shellmatta is included in the file api/shellmatta.h.
The api description can be found here:
@subpage shellmatta_api
This is how the classic usage looks like:
@startuml
App -> Shellmatta: shellmatta_doInit()
loop for every command
App -> Shellmatta: shellmatta_addCmd(command)
end
loop until finished
IO -> Shellmatta: shellmatta_processData(data)
Shellmatta -> App: call command function
App -> Shellmatta: shellmatta_printf(output data)
Shellmatta -> IO: write(data)
end
@enduml
*/

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> * Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> # Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
# #
# This Source Code Form is subject to the terms of the Mozilla Public # This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this # License, v. 2.0. If a copy of the MPL was not distributed with this
@ -7,9 +7,6 @@
# #
OBJ_DIR := output/ OBJ_DIR := output/
INTEGRATIONTEST_CPP_OBJ_DIR := $(OBJ_DIR)test/integrationtest/
INTEGRATIONTEST_C_OBJ_DIR := $(INTEGRATIONTEST_CPP_OBJ_DIR)
UNITTEST_OBJ_DIR := $(OBJ_DIR)test/unittest/
CC := gcc CC := gcc
CPP := g++ CPP := g++
@ -26,7 +23,6 @@ INCLUDES := api .
UNITTEST_SOURCES := test/unittest/test_main.cpp \ UNITTEST_SOURCES := test/unittest/test_main.cpp \
test/unittest/shellmatta_opt/test_opt_findNextHunk.cpp \ test/unittest/shellmatta_opt/test_opt_findNextHunk.cpp \
test/unittest/shellmatta_opt/test_opt_peekNextHunk.cpp \
test/unittest/shellmatta_utils/test_utils_writeEcho.cpp \ test/unittest/shellmatta_utils/test_utils_writeEcho.cpp \
test/unittest/shellmatta_utils/test_utils_shellItoa.cpp \ test/unittest/shellmatta_utils/test_utils_shellItoa.cpp \
test/unittest/shellmatta_utils/test_utils_saveCursorPos.cpp \ test/unittest/shellmatta_utils/test_utils_saveCursorPos.cpp \
@ -37,7 +33,6 @@ UNITTEST_SOURCES := test/unittest/test_main.cpp
test/unittest/shellmatta_utils/test_utils_clearInput.cpp \ test/unittest/shellmatta_utils/test_utils_clearInput.cpp \
test/unittest/shellmatta_utils/test_utils_insertChars.cpp \ test/unittest/shellmatta_utils/test_utils_insertChars.cpp \
test/unittest/shellmatta_utils/test_utils_terminateInput.cpp \ test/unittest/shellmatta_utils/test_utils_terminateInput.cpp \
test/unittest/shellmatta_utils/test_utils_removeChars.cpp \
test/unittest/shellmatta_autocomplete/test_autocomplete_run.cpp \ test/unittest/shellmatta_autocomplete/test_autocomplete_run.cpp \
test/unittest/shellmatta_escape/test_escape_processArrowKeys.cpp \ test/unittest/shellmatta_escape/test_escape_processArrowKeys.cpp \
test/unittest/shellmatta_history/test_appendHistoryByte.cpp \ test/unittest/shellmatta_history/test_appendHistoryByte.cpp \
@ -47,18 +42,14 @@ INTEGRATIONTEST_SOURCES := test/integrationtest/test_main.cpp
test/integrationtest/test_integration.cpp \ test/integrationtest/test_integration.cpp \
test/integrationtest/test_integration_opt.cpp \ test/integrationtest/test_integration_opt.cpp \
test/integrationtest/test_integration_optLong.cpp \ test/integrationtest/test_integration_optLong.cpp \
test/integrationtest/test_integration_continue.cpp \ test/integrationtest/test_integration_busy.cpp
test/integrationtest/test_integration_busy.cpp \
test/integrationtest/test_integration_history.cpp \
test/integrationtest/test_integration_help.cpp
UNITTEST_CPPOBJ := $(patsubst %.cpp,$(UNITTEST_OBJ_DIR)%.o,$(UNITTEST_SOURCES)) UNITTEST_CPPOBJ := $(patsubst %.cpp,$(OBJ_DIR)%.o,$(UNITTEST_SOURCES))
INTEGRATIONTEST_CPPOBJ := $(patsubst %.cpp,$(INTEGRATIONTEST_CPP_OBJ_DIR)%.o,$(INTEGRATIONTEST_SOURCES)) INTEGRATIONTEST_CPPOBJ := $(patsubst %.cpp,$(OBJ_DIR)%.o,$(INTEGRATIONTEST_SOURCES))
INTEGRATIONTEST_COBJ := $(patsubst %.c,$(INTEGRATIONTEST_CPP_OBJ_DIR)%.o,$(SOURCES))
CFLAGS := $(INCLUDES:%=-I%) -g -Wall -Werror -Wextra -pedantic -DSHELLMATTA_HELP_ALIAS=\(char*\)\"?\" CFLAGS := $(INCLUDES:%=-I%) -g -Wall -Werror -Wextra -pedantic -DSHELLMATTA_HELP_ALIAS=\"?\"
TESTFLAGS := $(CFLAGS) -fprofile-arcs -ftest-coverage TESTFLAGS := $(INCLUDES:%=-I%) -g -Wall -Werror -Wextra -fprofile-arcs -ftest-coverage -pedantic
TESTLFLAGS := -fprofile-arcs -Wl,--allow-multiple-definition TESTLFLAGS := -fprofile-arcs -Wl,--allow-multiple-definition
DEPEND = -MT $@ -MF "$(@:%.o=%.d)" -MG -MM DEPEND = -MT $@ -MF "$(@:%.o=%.d)" -MG -MM
@ -74,13 +65,11 @@ UNITTEST_TARGET := $(OBJ_DIR)test/unittest/unittest
INTEGRATIONTEST_TARGET := $(OBJ_DIR)test/integrationtest/integrationtest INTEGRATIONTEST_TARGET := $(OBJ_DIR)test/integrationtest/integrationtest
OBJ := $(COBJ) $(EXAMPLE_COBJ) $(UNITTEST_CPPOBJ) $(INTEGRATIONTEST_CPPOBJ) $(INTEGRATIONTEST_COBJ) OBJ := $(COBJ) $(EXAMPLE_COBJ) $(UNITTEST_CPPOBJ) $(INTEGRATIONTEST_CPPOBJ)
DEPS := $(OBJ:%.o=%.d) DEPS := $(OBJ:%.o=%.d)
export export
.PHONY: help cppcheck doc clean
help: help:
@echo Shellmatta help @echo Shellmatta help
@echo ----------------------------------------------- @echo -----------------------------------------------
@ -100,24 +89,23 @@ cppcheck:
unittest: $(UNITTEST_TARGET) unittest: $(UNITTEST_TARGET)
- @mkdir -p output/test/unittest/report - @mkdir -p output/test/unittest/report
@echo running test: @echo running test:
# remove coverage from former run @# remove coverage from former run
@-find . -name "*.gcda" -type f -delete @-find . -name "*.gcda" -type f -delete
-$(UNITTEST_TARGET) -$(UNITTEST_TARGET)
@#gcov -o output/test/unittest $(UNITTEST_CPPOBJ) -r src
# remove report from former run @# remove report from former run
-rm -rf $(OBJ_DIR)test/unittest/report/* -rm -rf $(OBJ_DIR)test/unittest/report/*
gcovr --html-details --output $(OBJ_DIR)test/unittest/report/report.html output/test/unittest -f src -f api -d gcovr --html-details --output $(OBJ_DIR)test/unittest/report/report.html output/test/unittest -f src -f api
@#-rm *.gcov
integrationtest: $(INTEGRATIONTEST_TARGET) integrationtest: $(INTEGRATIONTEST_TARGET)
- @mkdir -p output/test/integrationtest/report - @mkdir -p output/test/integrationtest/report
@echo running test: @echo running test:
# remove coverage from former run
# @-find . -name "*.gcda" -type f -delete
-$(INTEGRATIONTEST_TARGET) -$(INTEGRATIONTEST_TARGET)
#gcov -o output/test $(TEST_CPPOBJ) -r
# remove report from former run gcovr --html-details --output $(OBJ_DIR)test/integrationtest/report/report.html output/src -f src -f api
# -rm -rf $(OBJ_DIR)test/unittest/report/* #-rm *.gcov
gcovr --html-details --output $(OBJ_DIR)test/integrationtest/report/report.html output/test/integrationtest -f src -f api -d
example: $(EXAMPLE_TARGET) example: $(EXAMPLE_TARGET)
@echo building example @echo building example
@ -138,7 +126,7 @@ $(UNITTEST_TARGET): $(UNITTEST_CPPOBJ)
- @mkdir -p $(@D) - @mkdir -p $(@D)
$(CPP) $(TESTLFLAGS) $(LIB_PATH) -o $@ $^ $(LIBS) $(CPP) $(TESTLFLAGS) $(LIB_PATH) -o $@ $^ $(LIBS)
$(INTEGRATIONTEST_TARGET): $(INTEGRATIONTEST_CPPOBJ) $(INTEGRATIONTEST_COBJ) $(INTEGRATIONTEST_TARGET): $(INTEGRATIONTEST_CPPOBJ) $(COBJ)
- @mkdir -p $(@D) - @mkdir -p $(@D)
$(CPP) $(TESTLFLAGS) $(LIB_PATH) -o $@ $^ $(LIBS) $(CPP) $(TESTLFLAGS) $(LIB_PATH) -o $@ $^ $(LIBS)
@ -156,20 +144,10 @@ $(EXAMPLE_COBJ):
@$(CC) -c $(CFLAGS) $(DEPEND) -o $@ $(subst $(OBJ_DIR), ,$(@:%.o=%.c)) @$(CC) -c $(CFLAGS) $(DEPEND) -o $@ $(subst $(OBJ_DIR), ,$(@:%.o=%.c))
$(CC) -c $(CFLAGS) -o $@ $(subst $(OBJ_DIR), ,$(@:%.o=%.c)) $(CC) -c $(CFLAGS) -o $@ $(subst $(OBJ_DIR), ,$(@:%.o=%.c))
$(UNITTEST_CPPOBJ): $(UNITTEST_CPPOBJ) $(INTEGRATIONTEST_CPPOBJ):
- @mkdir -p $(@D) - @mkdir -p $(@D)
@$(CPP) -c $(TESTFLAGS) $(DEPEND) -o $@ $(subst $(UNITTEST_OBJ_DIR), ,$(@:%.o=%.cpp)) @$(CPP) -c $(TESTFLAGS) $(DEPEND) -o $@ $(subst $(OBJ_DIR), ,$(@:%.o=%.cpp))
$(CPP) -c $(TESTFLAGS) -o $@ $(subst $(UNITTEST_OBJ_DIR), ,$(@:%.o=%.cpp)) $(CPP) -c $(TESTFLAGS) -o $@ $(subst $(OBJ_DIR), ,$(@:%.o=%.cpp))
$(INTEGRATIONTEST_CPPOBJ):
- @mkdir -p $(@D)
@$(CPP) -c $(TESTFLAGS) $(DEPEND) -o $@ $(subst $(INTEGRATIONTEST_CPP_OBJ_DIR), ,$(@:%.o=%.cpp))
$(CPP) -c $(TESTFLAGS) -o $@ $(subst $(INTEGRATIONTEST_CPP_OBJ_DIR), ,$(@:%.o=%.cpp))
$(INTEGRATIONTEST_COBJ):
- @mkdir -p $(@D)
@$(CC) -c $(TESTFLAGS) $(DEPEND) -o $@ $(subst $(INTEGRATIONTEST_C_OBJ_DIR), ,$(@:%.o=%.c))
$(CC) -c $(TESTFLAGS) -o $@ $(subst $(INTEGRATIONTEST_C_OBJ_DIR), ,$(@:%.o=%.c))
%.o: %.cpp %.o: %.cpp
- @mkdir -p $(@D) - @mkdir -p $(@D)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> * Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -101,7 +101,6 @@ shellmatta_retCode_t shellmatta_doInit(
inst->continuousCmd = NULL; inst->continuousCmd = NULL;
inst->busyCmd = NULL; inst->busyCmd = NULL;
inst->cmdListIsConst = false; inst->cmdListIsConst = false;
shellmatta_opt_init(inst, 0u);
/** -# copy the help command structure to this instance */ /** -# copy the help command structure to this instance */
memcpy(&(inst->helpCmd), &helpCmd, sizeof(shellmatta_cmd_t)); memcpy(&(inst->helpCmd), &helpCmd, sizeof(shellmatta_cmd_t));
@ -159,7 +158,6 @@ shellmatta_retCode_t shellmatta_resetShell( shellmatta_handle_t handle, bool pri
inst->hereStartIdx = 0u; inst->hereStartIdx = 0u;
inst->hereDelimiterIdx = 0u; inst->hereDelimiterIdx = 0u;
inst->hereLength = 0u; inst->hereLength = 0u;
shellmatta_opt_init(inst, 0u);
if(true == printPrompt) if(true == printPrompt)
{ {
@ -193,8 +191,8 @@ shellmatta_retCode_t shellmatta_addCmd(shellmatta_handle_t handle, shellmatta_cm
shellmatta_cmd_t **prevCmd; shellmatta_cmd_t **prevCmd;
bool cmdPlaced = false; bool cmdPlaced = false;
shellmatta_retCode_t ret = SHELLMATTA_OK; shellmatta_retCode_t ret = SHELLMATTA_OK;
int cmdDiff; int cmdDiff = 0;
int aliasDiff; int aliasDiff = 0;
/** -# check parameters for plausibility */ /** -# check parameters for plausibility */
if( (NULL != inst) if( (NULL != inst)
@ -232,7 +230,7 @@ shellmatta_retCode_t shellmatta_addCmd(shellmatta_handle_t handle, shellmatta_cm
{ {
ret = SHELLMATTA_DUPLICATE; ret = SHELLMATTA_DUPLICATE;
} }
else if(cmdDiff > 0) else if(0 < cmdDiff)
{ {
cmd->next = tempCmd; cmd->next = tempCmd;
*prevCmd = cmd; *prevCmd = cmd;
@ -289,7 +287,8 @@ shellmatta_retCode_t shellmatta_removeCmd(shellmatta_handle_t handle, shellmatta
while(NULL != tempCmd) while(NULL != tempCmd)
{ {
/** -# compare command strings to find the command to delete */ /** -# compare command strings to find the command to delete */
if (0 == strcmp(tempCmd->cmd, cmd->cmd) if (0 == strcmp( tempCmd->cmd,
cmd->cmd)
&& (strlen(tempCmd->cmd) == strlen(cmd->cmd))) && (strlen(tempCmd->cmd) == strlen(cmd->cmd)))
{ {
/** -# first command removed */ /** -# first command removed */
@ -343,7 +342,7 @@ shellmatta_retCode_t shellmatta_configure( shellmatta_handle_t handle,
/** -# check parameters for plausibility */ /** -# check parameters for plausibility */
if( (NULL != inst) if( (NULL != inst)
&& (SHELLMATTA_MAGIC == inst->magic) && (SHELLMATTA_MAGIC == inst->magic)
&& ((SHELLMATTA_MODE_INSERT == mode) || (SHELLMATTA_MODE_OVERWRITE == mode))) && ((mode == SHELLMATTA_MODE_INSERT) || (mode == SHELLMATTA_MODE_OVERWRITE)))
{ {
inst->mode = mode; inst->mode = mode;
inst->echoEnabled = echoEnabled; inst->echoEnabled = echoEnabled;
@ -386,37 +385,33 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
if(NULL != inst->busyCmd) if(NULL != inst->busyCmd)
{ {
/** -# just call the function until it is not busy anymore */ /** -# just call the function until it is not busy anymore */
(void)shellmatta_opt_reInit(inst); cmdRet = inst->busyCmd->cmdFct(handle, inst->buffer, inst->inputCount);
ret = inst->busyCmd->cmdFct(handle, inst->buffer, inst->inputCount);
if(SHELLMATTA_BUSY == ret) if(SHELLMATTA_BUSY != cmdRet)
{ {
/** -# do nothing - still busy */ utils_terminateInput(inst);
} }
else if(SHELLMATTA_CONTINUE == ret) else if(SHELLMATTA_CONTINUE == cmdRet)
{ {
inst->continuousCmd = inst->busyCmd; inst->continuousCmd = inst->busyCmd;
inst->busyCmd = NULL; inst->busyCmd = NULL;
} }
else else
{ {
utils_terminateInput(inst); ret = cmdRet;
} }
} }
/** -# call continuous function even if there is no data */ /** -# call continuous function even if there is no data */
else if((0u == size) && (NULL != inst->continuousCmd)) else if((0u != size) && (NULL != inst->continuousCmd))
{ {
/** -# just call the function without any new data */ /** -# just call the function until it is not busy anymore */
inst->stdinLength = 0u; cmdRet = inst->continuousCmd->cmdFct(handle, inst->buffer, size);
inst->buffer[inst->stdinIdx] = '\0';
(void)shellmatta_opt_reInit(inst);
ret = inst->continuousCmd->cmdFct(handle, inst->buffer, inst->inputCount);
if(SHELLMATTA_CONTINUE == ret) if(SHELLMATTA_CONTINUE == cmdRet)
{ {
/** -# do nothing just continue */ ret = cmdRet;
} }
else if(SHELLMATTA_BUSY == ret) else if(SHELLMATTA_BUSY == cmdRet)
{ {
inst->busyCmd = inst->continuousCmd; inst->busyCmd = inst->continuousCmd;
inst->continuousCmd = NULL; inst->continuousCmd = NULL;
@ -426,10 +421,6 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
utils_terminateInput(inst); utils_terminateInput(inst);
} }
} }
else
{
/* nothing to do here - continue parsing the command */
}
/** -# process byte wise */ /** -# process byte wise */
for (; (inst->byteCounter < size) && (NULL == inst->busyCmd); inst->byteCounter++) for (; (inst->byteCounter < size) && (NULL == inst->busyCmd); inst->byteCounter++)
@ -439,24 +430,20 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
{ {
/** -# copy data and call command function */ /** -# copy data and call command function */
inst->buffer[inst->stdinIdx] = data[inst->byteCounter]; inst->buffer[inst->stdinIdx] = data[inst->byteCounter];
inst->buffer[inst->stdinIdx + 1u] = '\0';
inst->stdinLength = 1u; inst->stdinLength = 1u;
(void)shellmatta_opt_reInit(inst); cmdRet = inst->continuousCmd->cmdFct(handle, inst->buffer, inst->inputCount);
ret = inst->continuousCmd->cmdFct(handle, inst->buffer, inst->inputCount);
/** -# check if continuous mode is canceled or interrupted by busy mode */ /** -# check if continuous mode is canceled or interrupted by busy mode */
if(SHELLMATTA_BUSY == ret) if(SHELLMATTA_BUSY == cmdRet)
{ {
inst->busyCmd = inst->continuousCmd; inst->busyCmd = inst->continuousCmd;
inst->continuousCmd = NULL; inst->continuousCmd = NULL;
} }
else if(('\x03' == data[inst->byteCounter])) else if(('\x03' == data[inst->byteCounter]))
{ {
/** -# cancel continue session */
utils_terminateInput(inst); utils_terminateInput(inst);
ret = SHELLMATTA_OK;
} }
else if(SHELLMATTA_CONTINUE == ret) else if(SHELLMATTA_CONTINUE == cmdRet)
{ {
/** -# do nothing - continue */ /** -# do nothing - continue */
} }
@ -600,11 +587,15 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
while (NULL != cmd) while (NULL != cmd)
{ {
/** -# compare command and alias string and length */ /** -# compare command and alias string and length */
if ( ((cmdLen == strlen(cmd->cmd)) if ( ((0 == strncmp( inst->buffer,
&& (0 == strncmp(inst->buffer, cmd->cmd, cmdLen))) cmd->cmd,
cmdLen))
&& (cmdLen == strlen(cmd->cmd)))
|| ((NULL != cmd->cmdAlias) || ((NULL != cmd->cmdAlias)
&& (cmdLen == strlen(cmd->cmdAlias)) && ((0 == strncmp( inst->buffer,
&& (0 == strncmp(inst->buffer, cmd->cmdAlias, cmdLen)))) cmd->cmdAlias,
cmdLen))
&& (cmdLen == strlen(cmd->cmdAlias)))))
{ {
utils_writeEcho(inst, "\r\n", 2u); utils_writeEcho(inst, "\r\n", 2u);
shellmatta_opt_init(inst, cmdLen + 1u); shellmatta_opt_init(inst, cmdLen + 1u);
@ -618,7 +609,6 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
inst->stdinIdx = inst->inputCount + 1u; inst->stdinIdx = inst->inputCount + 1u;
inst->stdinLength = 0u; inst->stdinLength = 0u;
inst->continuousCmd = cmd; inst->continuousCmd = cmd;
ret = cmdRet;
break; break;
case SHELLMATTA_BUSY: case SHELLMATTA_BUSY:
@ -638,7 +628,7 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
} }
} }
if ((0u == cmdExecuted) && (inst->inputCount > 0)) if ((cmdExecuted == 0u) && (inst->inputCount > 0))
{ {
inst->write("\r\nCommand: ", 11u); inst->write("\r\nCommand: ", 11u);
inst->write(inst->buffer, inst->inputCount); inst->write(inst->buffer, inst->inputCount);
@ -698,7 +688,7 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
} }
} }
/** -# initialize the byte buffer if processing of the input is finished */ /*! -# initialize the byte buffer if processing of the input is finished */
if(ret != SHELLMATTA_BUSY) if(ret != SHELLMATTA_BUSY)
{ {
inst->byteCounter = 0u; inst->byteCounter = 0u;
@ -818,3 +808,4 @@ shellmatta_retCode_t shellmatta_printf( shellmatta_handle_t handle,
#endif #endif
/** @} */ /** @} */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> * Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -34,16 +34,16 @@ void autocomplete_run(shellmatta_instance_t *inst)
shellmatta_cmd_t *cmd = inst->cmdList; shellmatta_cmd_t *cmd = inst->cmdList;
char *tempCmd = NULL; char *tempCmd = NULL;
uint32_t minLen = 0u; uint32_t minLen = 0u;
uint32_t sizeDiff = 0u;
bool exactMatch = true; bool exactMatch = true;
uint32_t printedLen = 0u; uint32_t printedLen = 0u;
uint32_t sizeDiff; uint32_t tempCursor = 0u;
uint32_t tempCursor;
/** -# increase the tab counter to print all matching commands next time */ /** -# increase the tab counter to print all matching commands next time */
inst->tabCounter++; inst->tabCounter++;
/** -# on douple tab show all matching commands */ /** -# on douple tab show all matching commands */
if (inst->tabCounter > 1u) if (1u < inst->tabCounter)
{ {
inst->tabCounter = 0u; inst->tabCounter = 0u;
@ -52,7 +52,7 @@ void autocomplete_run(shellmatta_instance_t *inst)
{ {
/** -# check if command matches the input */ /** -# check if command matches the input */
if( (strlen(cmd->cmd) >= inst->cursor) if( (strlen(cmd->cmd) >= inst->cursor)
&& (0 == strncmp(cmd->cmd, inst->buffer, inst->cursor))) && (0u == memcmp(cmd->cmd, inst->buffer, inst->cursor)))
{ {
/** -# add newline on first find */ /** -# add newline on first find */
if(0u == printedLen) if(0u == printedLen)
@ -67,7 +67,7 @@ void autocomplete_run(shellmatta_instance_t *inst)
/** -# check if command alias matches the input */ /** -# check if command alias matches the input */
if( (NULL != cmd->cmdAlias) if( (NULL != cmd->cmdAlias)
&& (strlen(cmd->cmdAlias) >= inst->cursor) && (strlen(cmd->cmdAlias) >= inst->cursor)
&& (0 == strncmp(cmd->cmdAlias, inst->buffer, inst->cursor))) && (0u == memcmp(cmd->cmdAlias, inst->buffer, inst->cursor)))
{ {
/** -# add newline on first find */ /** -# add newline on first find */
if(0u == printedLen) if(0u == printedLen)
@ -100,7 +100,7 @@ void autocomplete_run(shellmatta_instance_t *inst)
{ {
/** -# check if command matches the input */ /** -# check if command matches the input */
if( (strlen(cmd->cmd) >= inst->cursor) if( (strlen(cmd->cmd) >= inst->cursor)
&& (0 == strncmp(cmd->cmd, inst->buffer, inst->cursor))) && (0u == memcmp(cmd->cmd, inst->buffer, inst->cursor)))
{ {
/** -# store first match */ /** -# store first match */
if(NULL == tempCmd) if(NULL == tempCmd)
@ -126,7 +126,7 @@ void autocomplete_run(shellmatta_instance_t *inst)
/** -# check if command Alias matches the input */ /** -# check if command Alias matches the input */
if( (NULL != cmd->cmdAlias) if( (NULL != cmd->cmdAlias)
&& (strlen(cmd->cmdAlias) >= inst->cursor) && (strlen(cmd->cmdAlias) >= inst->cursor)
&& (0 == strncmp(cmd->cmdAlias, inst->buffer, inst->cursor))) && (0u == memcmp(cmd->cmdAlias, inst->buffer, inst->cursor)))
{ {
/** -# store first match */ /** -# store first match */
if(NULL == tempCmd) if(NULL == tempCmd)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> * Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -13,7 +13,7 @@
*/ */
/** /**
* @addtogroup shellmatta_autocomplete * @addtogroup shellmatta_api
* @{ * @{
*/ */
#ifndef _SHELLMATTA_AUTOCOMPLETE_H_ #ifndef _SHELLMATTA_AUTOCOMPLETE_H_

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> * Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -52,7 +52,7 @@ shellmatta_retCode_t escape_processArrowKeys(shellmatta_instance_t *inst)
break; break;
case 'B': /* arrow down */ case 'B': /* arrow down */
/*! -# ignore the key if the history buffer points to the last entry */
if((inst->historyRead != inst->historyEnd)) if((inst->historyRead != inst->historyEnd))
{ {
history_storeCmd(inst); history_storeCmd(inst);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> * Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> * Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -38,7 +38,7 @@ static void appendHistoryByte(shellmatta_instance_t *inst, char byte)
/** -# append the byte */ /** -# append the byte */
inst->historyBuffer[inst->historyEnd] = byte; inst->historyBuffer[inst->historyEnd] = byte;
/** -# check if we overwrite an existing stored command */ /** -# check if the we overwrite an existing stored command */
if(inst->historyEnd == inst->historyStart) if(inst->historyEnd == inst->historyStart)
{ {
/** -# move the start pointer to the next termination (0) */ /** -# move the start pointer to the next termination (0) */
@ -84,55 +84,6 @@ static bool getHistoryByte(shellmatta_instance_t *inst, char *byte)
return ret; return ret;
} }
/**
* @brief compares the current buffer to the last command in the history buffer
* @param[in] inst pointer to a shellmatta instance
* @return true: current command is identical to the last one in the history buffer
*/
static bool compareLastCommand(shellmatta_instance_t *inst)
{
bool ret = false;
uint32_t i;
uint32_t cnt;
/** -# check if there is anything in the buffer */
if(inst->historyStart != inst->historyEnd)
{
i = inst->historyEnd;
cnt = 0u;
ret = true;
while((true == ret) && (cnt < inst->inputCount))
{
/** -# terminate compare on first mismatch */
if((inst->historyBuffer[i] != inst->buffer[cnt]) || (0u == inst->historyBuffer[i]))
{
ret = false;
}
if(0u == i)
{
i = (inst->historyBufferSize - 1u);
}
else
{
i --;
}
cnt ++;
}
/*! -# check if we are at the end of the command in the buffer - there has to be a terminating 0 */
if(0u != inst->historyBuffer[i])
{
ret = false;
}
}
return ret;
}
/** /**
* @brief navigates in the history buffer by the given number of commands * @brief navigates in the history buffer by the given number of commands
* @param[in, out] inst pointer to a shellmatta instance * @param[in, out] inst pointer to a shellmatta instance
@ -142,7 +93,7 @@ static bool compareLastCommand(shellmatta_instance_t *inst)
bool history_navigate(shellmatta_instance_t *inst, int32_t cnt) bool history_navigate(shellmatta_instance_t *inst, int32_t cnt)
{ {
bool ret = true; bool ret = true;
uint32_t tempReadIdx; uint32_t tempReadIdx = 0u;
while((cnt > 0) && (true == ret)) while((cnt > 0) && (true == ret))
{ {
@ -155,7 +106,7 @@ bool history_navigate(shellmatta_instance_t *inst, int32_t cnt)
inst->historyRead ++; inst->historyRead ++;
if(inst->historyRead >= inst->historyBufferSize) if(inst->historyRead >= inst->historyBufferSize)
{ {
inst->historyRead -= inst->historyBufferSize; inst->historyRead = 0u;
} }
if( (inst->historyRead != inst->historyEnd) if( (inst->historyRead != inst->historyEnd)
@ -224,8 +175,7 @@ void history_storeCmd(shellmatta_instance_t *inst)
* and there is a new command to be stored */ * and there is a new command to be stored */
if( (inst->historyBufferSize > inst->inputCount) if( (inst->historyBufferSize > inst->inputCount)
&& (0u != inst->inputCount) && (0u != inst->inputCount)
&& (true == inst->dirty) && (true == inst->dirty))
&& (true != compareLastCommand(inst)))
{ {
/** -# append the command termination */ /** -# append the command termination */
appendHistoryByte(inst, 0u); appendHistoryByte(inst, 0u);
@ -237,6 +187,7 @@ void history_storeCmd(shellmatta_instance_t *inst)
} }
} }
/** -# remove the dirty flag - everything is nice and saved */
inst->dirty = false; inst->dirty = false;
} }
@ -259,7 +210,7 @@ void history_restoreCmd(shellmatta_instance_t *inst)
utils_clearInput(inst); utils_clearInput(inst);
anythingToRestore = true; anythingToRestore = true;
} }
while((true == ret) && (0u != byte)) while((ret == true) && (byte != 0u))
{ {
inst->buffer[inst->inputCount] = byte; inst->buffer[inst->inputCount] = byte;
inst->inputCount ++; inst->inputCount ++;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> * Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -13,7 +13,7 @@
*/ */
/** /**
* @addtogroup shellmatta_history * @addtogroup shellmatta_api
* @{ * @{
*/ */
#ifndef _SHELLMATTA_HISTORY_H_ #ifndef _SHELLMATTA_HISTORY_H_

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> * Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -51,7 +51,7 @@ static shellmatta_retCode_t findNextHunk(shellmatta_instance_t *inst)
&& (((' ' != inst->buffer[newOffset]) && ('\0' != inst->buffer[newOffset])) || '\0' != quotation)) && (((' ' != inst->buffer[newOffset]) && ('\0' != inst->buffer[newOffset])) || '\0' != quotation))
{ {
/** -# check for new quotation */ /** -# check for new quotation */
if((('\'' == inst->buffer[newOffset]) || ('"' == inst->buffer[newOffset])) && ('\0' == quotation)) if((('\'' == inst->buffer[newOffset]) || ('"' == inst->buffer[newOffset])) && (quotation == '\0'))
{ {
quotation = inst->buffer[newOffset]; quotation = inst->buffer[newOffset];
exeptionOffset ++; exeptionOffset ++;
@ -211,7 +211,7 @@ static shellmatta_retCode_t parseLongOpt( shellmatta_instance_t *inst,
} }
} }
/** -# check for correct syntax for long options */ /** -# check for correct syntax for long options */
else if((inst->optionParser.len >= 3u) && ('-' == buffer[0u]) && ('-' == buffer[1u])) else if((3u <= inst->optionParser.len) && ('-' == buffer[0u]) && ('-' == buffer[1u]))
{ {
/** -# search for long option in option list */ /** -# search for long option in option list */
for(i = 0u; ('\0' != longOptions[i].paramShort) && ('\0' == *option); i ++) for(i = 0u; ('\0' != longOptions[i].paramShort) && ('\0' == *option); i ++)
@ -410,21 +410,12 @@ shellmatta_retCode_t shellmatta_opt_long( shellmatta_handle_t handle,
* @param[in, out] inst pointer to a shellmatta instance * @param[in, out] inst pointer to a shellmatta instance
* @param[in] argStart start offset of the arguments (after command name/alias) * @param[in] argStart start offset of the arguments (after command name/alias)
*/ */
void shellmatta_opt_init(shellmatta_instance_t *inst, uint32_t argStart) shellmatta_retCode_t shellmatta_opt_init(shellmatta_instance_t *inst, uint32_t argStart)
{ {
/** -# initialize all relevant option parser variables */ /** -# initialize all relevant option parser variables */
inst->optionParser.argStart = argStart;
inst->optionParser.nextOffset = argStart; inst->optionParser.nextOffset = argStart;
}
/** return SHELLMATTA_OK;
* @brief re-initializes the option parser instance using the data from the last init
* @param[in, out] inst pointer to a shellmatta instance
*/
void shellmatta_opt_reInit(shellmatta_instance_t *inst)
{
/** -# initialize all relevant option parser variables */
inst->optionParser.nextOffset = inst->optionParser.argStart;
} }
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> * Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -22,10 +22,20 @@
#include "shellmatta.h" #include "shellmatta.h"
#include <stdint.h> #include <stdint.h>
void shellmatta_opt_init( shellmatta_instance_t *inst, shellmatta_retCode_t shellmatta_opt( shellmatta_handle_t handle,
uint32_t argStart); const char *optionString,
char *option,
char **argument,
uint32_t *argLen);
void shellmatta_opt_reInit( shellmatta_instance_t *inst); shellmatta_retCode_t shellmatta_opt_long( shellmatta_handle_t handle,
const shellmatta_opt_long_t *longOptions,
char *option,
char **argument,
uint32_t *argLen);
shellmatta_retCode_t shellmatta_opt_init( shellmatta_instance_t *inst,
uint32_t argStart);
#endif #endif

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> * Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -51,13 +51,13 @@ uint32_t utils_shellItoa(int32_t value, char *buffer, uint32_t base)
char tempBuffer[34u]; char tempBuffer[34u];
uint32_t i; uint32_t i;
uint32_t bufferIdx = 0u; uint32_t bufferIdx = 0u;
int8_t digitValue; char digitValue;
/** -# check the base for plausibility */ /** -# check the base for plausibility */
if((base >= 2) && (base <= 16)) if((2 <= base) && (16 >= base))
{ {
/** -# check for sign */ /** -# check for sign */
if(value < 0) if(0 > value)
{ {
value = value * (-1); value = value * (-1);
buffer[0u] = '-'; buffer[0u] = '-';
@ -68,8 +68,8 @@ uint32_t utils_shellItoa(int32_t value, char *buffer, uint32_t base)
i = 0u; i = 0u;
do do
{ {
digitValue = (int8_t) (value % base); digitValue = (char) (value % base);
tempBuffer[i] = (digitValue < 10) ? ('0' + digitValue) : ('A' + (digitValue - 10)); tempBuffer[i] = (digitValue < 10) ? ('0' + digitValue) : (('A' - 10) + digitValue);
value /= base; value /= base;
i ++; i ++;
}while(value > 0); }while(value > 0);
@ -91,7 +91,7 @@ uint32_t utils_shellItoa(int32_t value, char *buffer, uint32_t base)
*/ */
void utils_saveCursorPos(shellmatta_instance_t *inst) void utils_saveCursorPos(shellmatta_instance_t *inst)
{ {
utils_writeEcho(inst, "\x1b" "[s", 3u); utils_writeEcho(inst, "\x1b[s", 3u);
} }
/** /**
@ -100,7 +100,7 @@ void utils_saveCursorPos(shellmatta_instance_t *inst)
*/ */
void utils_restoreCursorPos(shellmatta_instance_t *inst) void utils_restoreCursorPos(shellmatta_instance_t *inst)
{ {
utils_writeEcho(inst, "\x1b" "[u", 3u); utils_writeEcho(inst, "\x1b[u", 3u);
} }
/** /**
@ -110,7 +110,7 @@ void utils_restoreCursorPos(shellmatta_instance_t *inst)
*/ */
void utils_eraseLine(shellmatta_instance_t *inst) void utils_eraseLine(shellmatta_instance_t *inst)
{ {
utils_writeEcho(inst, "\x1b" "[K", 3u); utils_writeEcho(inst, "\x1b[K", 3u);
} }
/** /**
@ -162,51 +162,46 @@ void utils_forwardCursor(shellmatta_instance_t *inst, uint32_t length)
* @param[in] inst pointer to shellmatta instance * @param[in] inst pointer to shellmatta instance
* @param[in] data pointer to the data to be inserted * @param[in] data pointer to the data to be inserted
* @param[in] length length of the data to be inserted * @param[in] length length of the data to be inserted
* @todo this function shall check buffer overflows
*/ */
void utils_insertChars( shellmatta_instance_t *inst, void utils_insertChars( shellmatta_instance_t *inst,
char *data, char *data,
uint32_t length) uint32_t length)
{ {
uint32_t tmpLength = length; if(0u != length)
/** -# limit the length to the space left in the buffer */
if((inst->inputCount + tmpLength) > inst->bufferSize)
{ {
tmpLength = inst->bufferSize - inst->inputCount;
}
if(0u != tmpLength)
{
/** -# check if we have to move chars in the buffer */ /** -# check if we have to move chars in the buffer */
if( (inst->cursor != inst->inputCount) if( (inst->cursor != inst->inputCount)
&& (SHELLMATTA_MODE_INSERT == inst->mode)) && (SHELLMATTA_MODE_INSERT == inst->mode))
{ {
/** -# move the existing chars */ /** -# move the existing chars */
for (uint32_t i = inst->inputCount; i > inst->cursor; i --) for ( uint32_t i = inst->inputCount;
i > inst->cursor;
i --)
{ {
inst->buffer[i + tmpLength - 1] = inst->buffer[i - 1]; inst->buffer[i + length - 1] = inst->buffer[i - 1];
} }
/** -# store and print the new chars */ /** -# store and print the new chars */
memcpy(&(inst->buffer[inst->cursor]), data, tmpLength); memcpy(&(inst->buffer[inst->cursor]), data, length);
utils_writeEcho(inst, data, tmpLength); utils_writeEcho(inst, data, length);
/** -# print the other chars and restore the cursor to this position */ /** -# print the other chars and restore the cursor to this position */
utils_eraseLine(inst); utils_eraseLine(inst);
utils_saveCursorPos(inst); utils_saveCursorPos(inst);
utils_writeEcho( inst, utils_writeEcho( inst,
&(inst->buffer[inst->cursor + tmpLength]), &(inst->buffer[inst->cursor + length]),
inst->inputCount - inst->cursor); inst->inputCount - inst->cursor);
utils_restoreCursorPos(inst); utils_restoreCursorPos(inst);
inst->cursor += tmpLength; inst->cursor += length;
inst->inputCount += tmpLength; inst->inputCount += length;
} }
/** -# overwrite - if the cursor reaches the end of the input it is pushed further */ /** -# overwrite - if the cursor reaches the end of the input it is pushed further */
else else
{ {
memcpy(&(inst->buffer[inst->cursor]), data, tmpLength); memcpy(&(inst->buffer[inst->cursor]), data, length);
utils_writeEcho(inst, data, tmpLength); utils_writeEcho(inst, data, length);
inst->cursor += tmpLength; inst->cursor += length;
if(inst->cursor > inst->inputCount) if(inst->cursor > inst->inputCount)
{ {
inst->inputCount = inst->cursor; inst->inputCount = inst->cursor;
@ -220,14 +215,13 @@ void utils_insertChars( shellmatta_instance_t *inst,
* position * position
* @param[in] inst pointer to a shellmatta instance * @param[in] inst pointer to a shellmatta instance
* @param[in] length number of characters to remove * @param[in] length number of characters to remove
* @param[in] backspace true ==> remove characters left of the cursor * @param[in] backspace remove characters left of the cursor
* false ==> remove characters right of the cursor
*/ */
void utils_removeChars( shellmatta_instance_t *inst, void utils_removeChars( shellmatta_instance_t *inst,
uint32_t length, uint32_t length,
bool backspace) bool backspace)
{ {
if((0u != length) && (inst->inputCount >= inst->cursor)) if(0u != length)
{ {
/** -# rewind the cursor in case of backspace */ /** -# rewind the cursor in case of backspace */
if(true == backspace) if(true == backspace)
@ -272,117 +266,32 @@ void utils_clearInput(shellmatta_instance_t *inst)
inst->dirty = false; inst->dirty = false;
} }
/**
* @brief prints the usage information of one passed command
* @param[in] inst handle shellmatta instance handle
* @param[in] cmd pointer to a command structure to print
* @return #SHELLMATTA_OK
* #SHELLMATTA_ERROR
*/
static shellmatta_retCode_t printUsage(const shellmatta_instance_t *inst, const shellmatta_cmd_t *cmd)
{
shellmatta_retCode_t ret = SHELLMATTA_OK;
/** -# write the command and alias if configured */
SHELLMATTA_RET(ret, inst->write("Help for command: ", 18u));
SHELLMATTA_RET(ret, inst->write(cmd->cmd, strlen(cmd->cmd)));
if((NULL != cmd->cmdAlias) && (0u != strlen(cmd->cmdAlias)))
{
SHELLMATTA_RET(ret, inst->write(" (", 2u));
SHELLMATTA_RET(ret, inst->write(cmd->cmdAlias, strlen(cmd->cmdAlias)));
SHELLMATTA_RET(ret, inst->write(")", 1u));
}
/** -# write the help text if configured */
if((NULL != cmd->helpText) && (0u != strlen(cmd->helpText)))
{
SHELLMATTA_RET(ret, inst->write("\r\n\r\n", 4u));
SHELLMATTA_RET(ret, inst->write(cmd->helpText, strlen(cmd->helpText)));
}
/** -# write the usage text if configured */
if((NULL != cmd->usageText) && (0u != strlen(cmd->usageText)))
{
SHELLMATTA_RET(ret, inst->write("\r\n\r\nUsage: \r\n", 13u));
SHELLMATTA_RET(ret, inst->write(cmd->usageText, strlen(cmd->usageText)));
}
SHELLMATTA_RET(ret, inst->write("\r\n", 2u));
return ret;
}
/** /**
* @brief prints all possible commands with description and usage * @brief prints all possible commands with description and usage
* @param[in] handle handle shellmatta instance handle * @param[in] handle handle shellmatta instance handle
* @param[in] arguments arguments containing a command name or alias * @param[in] arguments not used here
* @param[in] length length of the arguments * @param[in] length not used here
* @return #SHELLMATTA_OK * @return #SHELLMATTA_OK
* #SHELLMATTA_ERROR (buffer overflow) * #SHELLMATTA_ERROR (buffer overflow)
*/ */
static shellmatta_retCode_t helpCmdFct(const shellmatta_handle_t handle, const char *arguments, uint32_t length) static shellmatta_retCode_t helpCmdFct(shellmatta_handle_t handle, const char *arguments, uint32_t length)
{ {
shellmatta_retCode_t ret = SHELLMATTA_OK; shellmatta_retCode_t ret = SHELLMATTA_OK;
const shellmatta_instance_t *inst = (const shellmatta_instance_t*) handle; shellmatta_instance_t *inst = (shellmatta_instance_t*) handle;
shellmatta_cmd_t *cmd = NULL; shellmatta_cmd_t *cmd = inst->cmdList;
size_t maxCmdLen = 0u; size_t maxCmdLen = 0u;
size_t maxCmdAliasLen = 0u; size_t maxCmdAliasLen = 0u;
size_t maxCmdHelpLen = 0u;
size_t cmdLen = 0u; size_t cmdLen = 0u;
const char *subCmd = NULL; size_t cmdAliasLen = 0u;
size_t cmdAliasLen; size_t cmdHelpLen = 0u;
uint32_t tabCnt; uint32_t tabCnt = 0u;
uint32_t i;
static const char tabBuffer[] = { ' ', ' ', ' ', ' ', static const char tabBuffer[] = { ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' '}; ' ', ' ', ' ', ' '};
/** -# check if help is called with a command - find first space */
for(i = 1u; i < length; i ++)
{
if(' ' == arguments[i - 1])
{
subCmd = &(arguments[i]);
/** -# determine subcommand length*/
cmdLen = 0u;
while( ((i + cmdLen) < length)
&& (' ' != arguments[i + cmdLen])
&& ('\r' != arguments[i + cmdLen])
&& ('\n' != arguments[i + cmdLen])
&& ('\0' != arguments[i + cmdLen]))
{
cmdLen ++;
}
break;
}
}
/* print detailled help */
if(NULL != subCmd)
{
cmd = inst->cmdList;
/** -# search for a matching command */
while (NULL != cmd)
{
/** -# compare command and alias string and length */
if ( ((cmdLen == strlen(cmd->cmd))
&& (0 == strncmp(subCmd, cmd->cmd, cmdLen)))
|| ((NULL != cmd->cmdAlias)
&& (cmdLen == strlen(cmd->cmdAlias))
&& (0 == strncmp(subCmd, cmd->cmdAlias, cmdLen))))
{
SHELLMATTA_RET(ret, printUsage(inst, cmd));
break;
}
cmd = cmd->next;
}
}
/** -# print help list if no sub cmd was found */
if(NULL == cmd)
{
/** -# loop through all commands to determine the lengths of each cmd */ /** -# loop through all commands to determine the lengths of each cmd */
cmd = inst->cmdList;
while(NULL != cmd) while(NULL != cmd)
{ {
maxCmdLen = SHELLMATTA_MAX(maxCmdLen, strlen(cmd->cmd)); maxCmdLen = SHELLMATTA_MAX(maxCmdLen, strlen(cmd->cmd));
@ -390,6 +299,10 @@ static shellmatta_retCode_t helpCmdFct(const shellmatta_handle_t handle, const c
{ {
maxCmdAliasLen = SHELLMATTA_MAX(maxCmdAliasLen, strlen(cmd->cmdAlias)); maxCmdAliasLen = SHELLMATTA_MAX(maxCmdAliasLen, strlen(cmd->cmdAlias));
} }
if(NULL != cmd->helpText)
{
maxCmdHelpLen = SHELLMATTA_MAX(maxCmdHelpLen, strlen(cmd->helpText));
}
cmd = cmd->next; cmd = cmd->next;
} }
@ -400,34 +313,37 @@ static shellmatta_retCode_t helpCmdFct(const shellmatta_handle_t handle, const c
/** -# determine the length of each field to add padding */ /** -# determine the length of each field to add padding */
cmdLen = strlen(cmd->cmd); cmdLen = strlen(cmd->cmd);
cmdAliasLen = (NULL != cmd->cmdAlias) ? strlen(cmd->cmdAlias) : 0u; cmdAliasLen = (NULL != cmd->cmdAlias) ? strlen(cmd->cmdAlias) : 0u;
cmdHelpLen = (NULL != cmd->helpText) ? strlen(cmd->helpText) : 0u;
SHELLMATTA_RET(ret, inst->write(cmd->cmd, strlen(cmd->cmd))); inst->write(cmd->cmd, strlen(cmd->cmd));
tabCnt = (maxCmdLen - cmdLen) + 2u; tabCnt = (maxCmdLen - cmdLen) + 2u;
/** -# add padding if there is anything to be printed afterwards */
if( ((NULL != cmd->cmdAlias) && (0u != strlen(cmd->cmdAlias)))
|| ((NULL != cmd->helpText) && (0u != strlen(cmd->helpText))))
{
SHELLMATTA_PRINT_BUFFER(tabBuffer, tabCnt, inst->write); SHELLMATTA_PRINT_BUFFER(tabBuffer, tabCnt, inst->write);
}
if((NULL != cmd->cmdAlias) && (0u != strlen(cmd->cmdAlias))) if(NULL != cmd->cmdAlias)
{ {
SHELLMATTA_RET(ret, inst->write(cmd->cmdAlias, cmdAliasLen)); inst->write(cmd->cmdAlias, cmdAliasLen);
} }
tabCnt = (maxCmdAliasLen - cmdAliasLen) + 2u; tabCnt = (maxCmdAliasLen - cmdAliasLen) + 2u;
if((NULL != cmd->helpText) && (0u != strlen(cmd->helpText)))
{
SHELLMATTA_PRINT_BUFFER(tabBuffer, tabCnt, inst->write); SHELLMATTA_PRINT_BUFFER(tabBuffer, tabCnt, inst->write);
SHELLMATTA_RET(ret, inst->write(cmd->helpText, strlen(cmd->helpText)));
}
SHELLMATTA_RET(ret, inst->write("\r\n", 2u)); if(NULL != cmd->helpText)
{
inst->write(cmd->helpText, cmdHelpLen);
}
tabCnt = (maxCmdHelpLen - cmdHelpLen) + 2u;
SHELLMATTA_PRINT_BUFFER(tabBuffer, tabCnt, inst->write);
if(NULL != cmd->usageText)
{
inst->write(cmd->usageText, strlen(cmd->usageText));
}
inst->write("\r\n", 2u);
cmd = cmd->next; cmd = cmd->next;
} }
}
(void)arguments;
(void)length;
return ret; return ret;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> * Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -36,13 +36,6 @@
*/ */
#define SHELLMATTA_MAX(a,b) (((a) < (b)) ? (b) : (a)) #define SHELLMATTA_MAX(a,b) (((a) < (b)) ? (b) : (a))
/**
* @brief sums up #shellmatta_retCode_t
* @param[in] ret return variable
* @param[in] expression expression with the return value
*/
#define SHELLMATTA_RET(ret, expression) (ret) = (SHELLMATTA_OK != (expression)) ? SHELLMATTA_ERROR : (ret)
/** /**
* @brief calls fct with cnt bytes from buffer (to print cnt same bytes) * @brief calls fct with cnt bytes from buffer (to print cnt same bytes)
* @param[in] buffer buffer to send (shall contain the same char) * @param[in] buffer buffer to send (shall contain the same char)
@ -83,21 +76,16 @@ extern const shellmatta_cmd_t helpCmd;
* e.g. use _-DSHELLMATTA_HELP_ALIAS=\"?\"_ as compile option to change the alias to ? * e.g. use _-DSHELLMATTA_HELP_ALIAS=\"?\"_ as compile option to change the alias to ?
*/ */
#ifndef SHELLMATTA_HELP_COMMAND #ifndef SHELLMATTA_HELP_COMMAND
/** \brief help command */ #define SHELLMATTA_HELP_COMMAND (char*)"help" /**< help command */
#define SHELLMATTA_HELP_COMMAND (char*)"help"
#endif #endif
#ifndef SHELLMATTA_HELP_ALIAS #ifndef SHELLMATTA_HELP_ALIAS
/** \brief help command alias */ #define SHELLMATTA_HELP_ALIAS (char*)"h" /**< help command alias */
#define SHELLMATTA_HELP_ALIAS (char*)"h"
#endif #endif
#ifndef SHELLMATTA_HELP_HELP_TEXT #ifndef SHELLMATTA_HELP_HELP_TEXT
/** \brief help command help text */ #define SHELLMATTA_HELP_HELP_TEXT (char*)"Print this help text" /**< help command help text */
#define SHELLMATTA_HELP_HELP_TEXT (char*)"help [command] - print help or usage information"
#endif #endif
#ifndef SHELLMATTA_HELP_USAGE_TEXT #ifndef SHELLMATTA_HELP_USAGE_TEXT
/** \brief help command usage text */ #define SHELLMATTA_HELP_USAGE_TEXT (char*)"help" /**< help command usage text */
#define SHELLMATTA_HELP_USAGE_TEXT (char*) "help [command]\r\n" \
"\tcommand: optional command name or alias to print detailled help for"
#endif #endif
/** /**
* @} * @}

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,3 @@
/*
* Copyright (c) 2021 Stefan Strobel <stefan.strobel@shimatta.net>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
/**
* @file test_integration.cpp
* @brief integration test implementation for some general functions
* @author Stefan Strobel <stefan.strobel@shimatta.net>
*/
#include "test/framework/catch.hpp" #include "test/framework/catch.hpp"
extern "C" { extern "C" {
#include "shellmatta.h" #include "shellmatta.h"
@ -88,6 +74,71 @@ TEST_CASE( "shellmatta empty function" ) {
} }
TEST_CASE( "shellmatta help function" ) {
shellmatta_instance_t inst;
shellmatta_handle_t handle;
char buffer[1024];
char historyBuffer[1024];
char *dummyData = (char*)"?\r\n"
"doSomething do Function does something use me, please\r\n"
"empty \r\n"
"help ? Print this help text help\r\n"
"\r\nshellmatta->";
shellmatta_doInit( &inst,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->",
NULL,
writeFct);
shellmatta_addCmd(handle, &emptyCmd);
shellmatta_addCmd(handle, &doSomethingCmd);
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_length = 0u;
shellmatta_processData(handle, (char*)"?\r", 2);
CHECK( write_length == strlen(dummyData));
CHECK( strcmp(dummyData, write_data) == 0);
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_length = 0u;
dummyData = (char*)"? 564 321 56 465 46\r\n"
"doSomething do Function does something use me, please\r\n"
"empty \r\n"
"help ? Print this help text help\r\n"
"\r\nshellmatta->";
shellmatta_processData(handle, (char*)"? 564 321 56 465 46\r", 20);
CHECK( write_length == strlen(dummyData));
CHECK( strcmp(dummyData, write_data) == 0);
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_length = 0u;
dummyData = (char*)"?r\r\n"
"Command: ?r not found"
"\r\nshellmatta->";
shellmatta_processData(handle, (char*)"?r\r", 3);
CHECK( write_length == 39u);
REQUIRE( strcmp(dummyData, write_data) == 0);
}
TEST_CASE( "shellmatta heredoc test" ) { TEST_CASE( "shellmatta heredoc test" ) {
shellmatta_instance_t inst; shellmatta_instance_t inst;
@ -163,8 +214,8 @@ TEST_CASE( "shellmatta remove function" ) {
char buffer[1024]; char buffer[1024];
char historyBuffer[1024]; char historyBuffer[1024];
char *dummyData = (char*)"?\r\n" char *dummyData = (char*)"?\r\n"
"doSomething do Function does something\r\n" "doSomething do Function does something use me, please\r\n"
"help ? help [command] - print help or usage information\r\n" "help ? Print this help text help\r\n"
"\r\nshellmatta->"; "\r\nshellmatta->";
shellmatta_doInit( &inst, shellmatta_doInit( &inst,
@ -184,7 +235,7 @@ TEST_CASE( "shellmatta remove function" ) {
shellmatta_processData(handle, (char*)"?\r", 2); shellmatta_processData(handle, (char*)"?\r", 2);
CHECK( write_length == strlen(dummyData)); CHECK( write_length == 123u);
CHECK( strcmp(dummyData, write_data) == 0); CHECK( strcmp(dummyData, write_data) == 0);
@ -193,13 +244,13 @@ TEST_CASE( "shellmatta remove function" ) {
write_length = 0u; write_length = 0u;
dummyData = (char*)"? 564 321 56 465 46\r\n" dummyData = (char*)"? 564 321 56 465 46\r\n"
"doSomething do Function does something\r\n" "doSomething do Function does something use me, please\r\n"
"help ? help [command] - print help or usage information\r\n" "help ? Print this help text help\r\n"
"\r\nshellmatta->"; "\r\nshellmatta->";
shellmatta_processData(handle, (char*)"? 564 321 56 465 46\r", 20); shellmatta_processData(handle, (char*)"? 564 321 56 465 46\r", 20);
CHECK( write_length == strlen(dummyData)); CHECK( write_length == 141u);
CHECK( strcmp(dummyData, write_data) == 0); CHECK( strcmp(dummyData, write_data) == 0);
write_callCnt = 0u; write_callCnt = 0u;
@ -210,10 +261,10 @@ TEST_CASE( "shellmatta remove function" ) {
shellmatta_processData(handle, (char*)"? 564 321 56 465 46\r", 20); shellmatta_processData(handle, (char*)"? 564 321 56 465 46\r", 20);
dummyData = (char*)"? 564 321 56 465 46\r\n" dummyData = (char*)"? 564 321 56 465 46\r\n"
"help ? help [command] - print help or usage information\r\n" "help ? Print this help text help\r\n"
"\r\nshellmatta->"; "\r\nshellmatta->";
CHECK( write_length == strlen(dummyData)); CHECK( write_length == 72u);
REQUIRE( strcmp(dummyData, write_data) == 0); REQUIRE( strcmp(dummyData, write_data) == 0);
} }
@ -224,8 +275,8 @@ TEST_CASE( "shellmatta reset no prompt" ) {
char buffer[1024]; char buffer[1024];
char historyBuffer[1024]; char historyBuffer[1024];
char *dummyData = (char*)"dkfg hdlsfkgh ldksfjhg lkdjfsh glkd?\r\n" char *dummyData = (char*)"dkfg hdlsfkgh ldksfjhg lkdjfsh glkd?\r\n"
"doSomething do Function does something\r\n" "doSomething do Function does something use me, please\r\n"
"help ? help [command] - print help or usage information\r\n" "help ? Print this help text help\r\n"
"\r\nshellmatta->"; "\r\nshellmatta->";
shellmatta_doInit( &inst, shellmatta_doInit( &inst,
@ -259,8 +310,8 @@ TEST_CASE( "shellmatta reset with prompt" ) {
char historyBuffer[1024]; char historyBuffer[1024];
char *dummyData = (char*)"dkfg hdlsfkgh ldksfjhg lkdjfsh glkd" char *dummyData = (char*)"dkfg hdlsfkgh ldksfjhg lkdjfsh glkd"
"\r\nshellmatta->?\r\n" "\r\nshellmatta->?\r\n"
"doSomething do Function does something\r\n" "doSomething do Function does something use me, please\r\n"
"help ? help [command] - print help or usage information\r\n" "help ? Print this help text help\r\n"
"\r\nshellmatta->"; "\r\nshellmatta->";
shellmatta_doInit( &inst, shellmatta_doInit( &inst,
@ -293,8 +344,8 @@ TEST_CASE( "shellmatta reset no prompt history buffer" ) {
char buffer[1024]; char buffer[1024];
char historyBuffer[1024]; char historyBuffer[1024];
char *dummyData = (char*)"?\r\n" char *dummyData = (char*)"?\r\n"
"doSomething do Function does something\r\n" "doSomething do Function does something use me, please\r\n"
"help ? help [command] - print help or usage information\r\n" "help ? Print this help text help\r\n"
"\r\nshellmatta->"; "\r\nshellmatta->";
shellmatta_doInit( &inst, shellmatta_doInit( &inst,
@ -333,8 +384,8 @@ TEST_CASE( "shellmatta reset no prompt heredoc" ) {
char buffer[1024]; char buffer[1024];
char historyBuffer[1024]; char historyBuffer[1024];
char *dummyData = (char*)"?\r\n" char *dummyData = (char*)"?\r\n"
"doSomething do Function does something\r\n" "doSomething do Function does something use me, please\r\n"
"help ? help [command] - print help or usage information\r\n" "help ? Print this help text help\r\n"
"\r\nshellmatta->"; "\r\nshellmatta->";
shellmatta_doInit( &inst, shellmatta_doInit( &inst,
@ -374,12 +425,12 @@ TEST_CASE( "shellmatta configure disable echo" ) {
char buffer[1024]; char buffer[1024];
char historyBuffer[1024]; char historyBuffer[1024];
char *dummyData = (char*)"help this is some dummy Text\r\n" char *dummyData = (char*)"help this is some dummy Text\r\n"
"doSomething do Function does something\r\n" "doSomething do Function does something use me, please\r\n"
"help ? help [command] - print help or usage information\r\n" "help ? Print this help text help\r\n"
"\r\nshellmatta->"; "\r\nshellmatta->";
char *dummyData2 = (char*)"doSomething do Function does something\r\n" char *dummyData2 = (char*)"doSomething do Function does something use me, please\r\n"
"help ? help [command] - print help or usage information\r\n" "help ? Print this help text help\r\n"
"\r\nshellmatta->"; "\r\nshellmatta->";
shellmatta_doInit( &inst, shellmatta_doInit( &inst,
@ -511,3 +562,4 @@ TEST_CASE( "shellmatta configure delimiter" ) {
CHECK( write_length == strlen(dummyData)); CHECK( write_length == strlen(dummyData));
REQUIRE( strcmp(dummyData, write_data) == 0); REQUIRE( strcmp(dummyData, write_data) == 0);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> * Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -23,7 +23,6 @@ static char write_data[1024];
static uint32_t write_length; static uint32_t write_length;
static uint32_t busyCallCnt; static uint32_t busyCallCnt;
static uint32_t notBusyCallCnt; static uint32_t notBusyCallCnt;
static bool suspendBusy;
static shellmatta_retCode_t writeFct(const char* data, uint32_t length) static shellmatta_retCode_t writeFct(const char* data, uint32_t length)
{ {
@ -68,11 +67,6 @@ static shellmatta_retCode_t busyCmdFct(shellmatta_handle_t handle, const char *a
ret = SHELLMATTA_OK; ret = SHELLMATTA_OK;
} }
if(true == suspendBusy)
{
ret = SHELLMATTA_CONTINUE;
}
return ret; return ret;
} }
shellmatta_cmd_t busyCmd = {(char*)"busy", (char*)"b", NULL, NULL, busyCmdFct, NULL}; shellmatta_cmd_t busyCmd = {(char*)"busy", (char*)"b", NULL, NULL, busyCmdFct, NULL};
@ -117,7 +111,6 @@ TEST_CASE( "shellmatta busy 1" ) {
write_callCnt = 0u; write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data)); memset(write_data, 0, sizeof(write_data));
write_length = 0u; write_length = 0u;
suspendBusy = false;
shellmatta_addCmd(handle, &busyCmd); shellmatta_addCmd(handle, &busyCmd);
shellmatta_addCmd(handle, &notBusyCmd); shellmatta_addCmd(handle, &notBusyCmd);
@ -135,49 +128,3 @@ TEST_CASE( "shellmatta busy 1" ) {
CHECK( write_length == strlen(dummyData)); CHECK( write_length == strlen(dummyData));
REQUIRE( strcmp(dummyData, write_data) == 0); REQUIRE( strcmp(dummyData, write_data) == 0);
} }
TEST_CASE( "shellmatta busy suspend with continuous mode" ) {
shellmatta_retCode_t ret;
shellmatta_instance_t inst;
shellmatta_handle_t handle;
char buffer[1024];
char historyBuffer[1024];
char *dummyData = (char*) "busy and some arguments\r\n";
shellmatta_doInit( &inst,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->",
NULL,
writeFct);
busyCallCnt = 0u;
notBusyCallCnt = 0u;
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_length = 0u;
suspendBusy = false;
shellmatta_addCmd(handle, &busyCmd);
shellmatta_addCmd(handle, &notBusyCmd);
do
{
ret = shellmatta_processData(handle, (char*)"busy and some arguments\r123", 27u);
suspendBusy = true;
} while (SHELLMATTA_BUSY == ret);
ret = shellmatta_processData(handle, (char*)"", 0u);
CHECK( SHELLMATTA_CONTINUE == ret);
CHECK( 6u == busyCallCnt);
CHECK( 0u == notBusyCallCnt );
CHECK( write_length == strlen(dummyData));
REQUIRE( strcmp(dummyData, write_data) == 0);
}

View File

@ -1,284 +0,0 @@
/*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
/**
* @file test_integration_busy.cpp
* @brief integration test implementation for the cmd busy function
* @author Stefan Strobel <stefan.strobel@shimatta.net>
*/
#include "test/framework/catch.hpp"
extern "C" {
#include "shellmatta.h"
}
#include <string.h>
static uint32_t write_callCnt = 0u;
static char write_data[1024];
static uint32_t write_length;
static uint32_t contCallCnt;
static uint32_t busyCallCnt;
static shellmatta_retCode_t writeFct(const char* data, uint32_t length)
{
write_callCnt ++;
while((length > 0) && (write_length < sizeof(write_data)))
{
write_data[write_length] = *data;
data ++;
length --;
write_length ++;
}
return SHELLMATTA_OK;
}
static shellmatta_retCode_t continueCmdFct(shellmatta_handle_t handle, const char *arguments, uint32_t length)
{
(void) handle;
(void) arguments;
(void) length;
shellmatta_retCode_t ret = SHELLMATTA_CONTINUE;
char *stdinData;
uint32_t stdinLength = 0u;
shellmatta_read(handle, &stdinData, &stdinLength);
if(NULL == stdinData)
{
stdinData = (char *)"";
}
shellmatta_printf(handle, "arguments: %s length: %u\r\n", stdinData, stdinLength);
/** change to busy mode when k is pressed */
if('k' == stdinData[0])
{
ret = SHELLMATTA_BUSY;
busyCallCnt ++;
}
if(busyCallCnt > 1u)
{
ret = SHELLMATTA_CONTINUE;
}
if(contCallCnt >= 9u)
{
ret = SHELLMATTA_OK;
}
/* -# the arguments shall stay the same on every call - data is transferred per stdin */
CHECK(length == 28u);
CHECK(strcmp(arguments, "continue some arguments meow") == 0);
contCallCnt ++;
return ret;
}
shellmatta_cmd_t continueCmd = {(char*)"continue", (char*)"c", NULL, NULL, continueCmdFct, NULL};
TEST_CASE( "shellmatta continue 1" ) {
shellmatta_retCode_t ret;
shellmatta_instance_t inst;
shellmatta_handle_t handle;
char buffer[1024];
char historyBuffer[1024];
char *dummyData = (char*) "continue some arguments meow\r\n"
"arguments: length: 0\r\n"
"arguments: length: 0\r\n"
"arguments: a length: 1\r\n"
"arguments: b length: 1\r\n"
"arguments: c length: 1\r\n"
"arguments: 8 length: 1\r\n"
"arguments: 7 length: 1\r\n"
"arguments: 6 length: 1\r\n"
"arguments: 5 length: 1\r\n"
"arguments: length: 0\r\n"
"\r\n"
"shellmatta->\r\n"
"shellmatta->";
shellmatta_doInit( &inst,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->",
NULL,
writeFct);
contCallCnt = 0u;
busyCallCnt = 0u;
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_length = 0u;
shellmatta_addCmd(handle, &continueCmd);
ret = shellmatta_processData(handle, (char*)"continue some arguments meow\r", 29);
CHECK(SHELLMATTA_CONTINUE == ret);
/** -# call without any argument */
ret = shellmatta_processData(handle, NULL, 0);
CHECK(SHELLMATTA_CONTINUE == ret);
/** -# pass some argument */
ret = shellmatta_processData(handle, (char*)"abc", 3);
CHECK(SHELLMATTA_CONTINUE == ret);
ret = shellmatta_processData(handle, (char*)"8765", 4);
CHECK(SHELLMATTA_CONTINUE == ret);
/** -# call without any argument */
ret = shellmatta_processData(handle, NULL, 0);
CHECK(SHELLMATTA_OK == ret);
/** -# continue session should be over */
ret = shellmatta_processData(handle, (char*)"\r", 1);
CHECK(SHELLMATTA_OK == ret);
CHECK( 0u == busyCallCnt);
CHECK( 10u == contCallCnt);
CHECK( write_length == strlen(dummyData));
REQUIRE( strcmp(dummyData, write_data) == 0);
}
TEST_CASE( "shellmatta continue cancel" ) {
shellmatta_retCode_t ret;
shellmatta_instance_t inst;
shellmatta_handle_t handle;
char buffer[1024];
char historyBuffer[1024];
char *dummyData = (char*) "continue some arguments meow\r\n"
"arguments: length: 0\r\n"
"arguments: length: 0\r\n"
"arguments: a length: 1\r\n"
"arguments: b length: 1\r\n"
"arguments: \x03 length: 1\r\n"
"\r\n"
"shellmatta->\r\n"
"shellmatta->";
shellmatta_doInit( &inst,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->",
NULL,
writeFct);
contCallCnt = 0u;
busyCallCnt = 0u;
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_length = 0u;
shellmatta_addCmd(handle, &continueCmd);
ret = shellmatta_processData(handle, (char*)"continue some arguments meow\r", 29);
CHECK(SHELLMATTA_CONTINUE == ret);
/** -# call without any argument */
ret = shellmatta_processData(handle, NULL, 0);
CHECK(SHELLMATTA_CONTINUE == ret);
/** -# pass some argument */
ret = shellmatta_processData(handle, (char*)"ab", 2);
CHECK(SHELLMATTA_CONTINUE == ret);
ret = shellmatta_processData(handle, (char*)"\x03", 1);
CHECK(SHELLMATTA_OK == ret);
/** -# continue session should be over */
ret = shellmatta_processData(handle, (char*)"\r", 1);
CHECK(SHELLMATTA_OK == ret);
CHECK( 0u == busyCallCnt);
CHECK( 5u == contCallCnt);
CHECK( write_length == strlen(dummyData));
REQUIRE( strcmp(dummyData, write_data) == 0);
}
TEST_CASE( "shellmatta continue suspend with busy mode" ) {
shellmatta_retCode_t ret;
shellmatta_instance_t inst;
shellmatta_handle_t handle;
char buffer[1024];
char historyBuffer[1024];
char *dummyData = (char*) "continue some arguments meow\r\n"
"arguments: length: 0\r\n"
"arguments: length: 0\r\n"
"arguments: a length: 1\r\n"
"arguments: b length: 1\r\n"
"arguments: k length: 1\r\n"
"arguments: k length: 1\r\n"
"arguments: length: 0\r\n"
"arguments: a length: 1\r\n"
"arguments: b length: 1\r\n"
"arguments: c length: 1\r\n"
"\r\n"
"shellmatta->\r\n"
"shellmatta->";
shellmatta_doInit( &inst,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->",
NULL,
writeFct);
contCallCnt = 0u;
busyCallCnt = 0u;
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_length = 0u;
shellmatta_addCmd(handle, &continueCmd);
ret = shellmatta_processData(handle, (char*)"continue some arguments meow\r", 29);
CHECK(SHELLMATTA_CONTINUE == ret);
/** -# call without any argument */
ret = shellmatta_processData(handle, NULL, 0);
CHECK(SHELLMATTA_CONTINUE == ret);
/** -# pass some argument */
ret = shellmatta_processData(handle, (char*)"ab", 2);
CHECK(SHELLMATTA_CONTINUE == ret);
ret = shellmatta_processData(handle, (char*)"k", 1);
CHECK(SHELLMATTA_BUSY == ret);
ret = shellmatta_processData(handle, (char*)"k", 1);
CHECK(SHELLMATTA_CONTINUE == ret);
ret = shellmatta_processData(handle, (char*)"", 0);
CHECK(SHELLMATTA_CONTINUE == ret);
ret = shellmatta_processData(handle, (char*)"abc", 3);
CHECK(SHELLMATTA_OK == ret);
/** -# continue session should be over */
ret = shellmatta_processData(handle, (char*)"\r", 1);
CHECK(SHELLMATTA_OK == ret);
CHECK( 10u == contCallCnt);
CHECK( 2u == busyCallCnt);
CHECK( write_length == strlen(dummyData));
REQUIRE( strcmp(dummyData, write_data) == 0);
}

View File

@ -1,296 +0,0 @@
/*
* Copyright (c) 2021 Stefan Strobel <stefan.strobel@shimatta.net>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
/**
* @file test_integration_help.cpp
* @brief integration test implementation for the help command of the shellmatta
* @author Stefan Strobel <stefan.strobel@shimatta.net>
*/
#include "test/framework/catch.hpp"
extern "C" {
#include "test/framework/fff.h"
#include "shellmatta.h"
}
#include <string.h>
FAKE_VALUE_FUNC(shellmatta_retCode_t, writeFct, const char *, uint32_t)
FAKE_VALUE_FUNC(shellmatta_retCode_t, cmdFct1, shellmatta_handle_t, const char *, uint32_t)
FAKE_VALUE_FUNC(shellmatta_retCode_t, cmdFct2, shellmatta_handle_t, const char *, uint32_t)
FAKE_VALUE_FUNC(shellmatta_retCode_t, cmdFct3, shellmatta_handle_t, const char *, uint32_t)
static char fakeWriteData[1024];
static uint32_t fakeWriteLength;
static shellmatta_retCode_t writeFct_customFake(const char* data, uint32_t length)
{
while((length > 0) && (fakeWriteLength < sizeof(fakeWriteData)))
{
fakeWriteData[fakeWriteLength] = *data;
data ++;
length --;
fakeWriteLength ++;
}
return SHELLMATTA_OK;
}
/* List of fakes */
#define FFF_FAKES_LIST(FAKE) \
FAKE(writeFct) \
FAKE(cmdFct1) \
FAKE(cmdFct2) \
FAKE(cmdFct3)
#define PROCESS_INPUT(input) \
CHECK(SHELLMATTA_OK == shellmatta_processData(handle, (char*)(input), sizeof((input)) - 1u));
static shellmatta_cmd_t cmd1 = {(char*)"cmd1", (char*)"1", (char*)"cmd1 [options]", (char*)"cmd1 usage\r\n--option, -o: option", cmdFct1, NULL};
static shellmatta_cmd_t cmd2 = {(char*)"cmd2", NULL, NULL, NULL, cmdFct2, NULL};
static shellmatta_cmd_t cmd3 = {(char*)"cmd3", (char*)"", (char*)"", (char*)"", cmdFct3, NULL};
SCENARIO("Test the help function")
{
GIVEN("An initialized and empty Shellmatte instance")
{
shellmatta_instance_t inst;
shellmatta_handle_t handle;
char buffer[1024u];
char historyBuffer[1024u];
CHECK(SHELLMATTA_OK == shellmatta_doInit( &inst,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->",
NULL,
writeFct));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd1));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd2));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd3));
WHEN("The user hits help")
{
FFF_FAKES_LIST(RESET_FAKE)
fakeWriteLength = 0u;
memset(fakeWriteData, 0, sizeof(fakeWriteData));
shellmatta_write_t writeCustomFakeSeq[1] = {writeFct_customFake};
SET_CUSTOM_FAKE_SEQ(writeFct, writeCustomFakeSeq, 1)
PROCESS_INPUT("help\r\n")
THEN("The shellmatta prints the help text")
{
static const char * response = (char*) "help\r\n"
"cmd1 1 cmd1 [options]\r\n"
"cmd2\r\n"
"cmd3\r\n"
"help ? help [command] - print help or usage information\r\n\r\n"
"shellmatta->";
CHECK(writeFct_fake.call_count == 23);
CHECK(strlen(response) == fakeWriteLength);
CHECK(0 == strcmp(response, fakeWriteData));
}
}
WHEN("The user hits ?")
{
FFF_FAKES_LIST(RESET_FAKE)
fakeWriteLength = 0u;
memset(fakeWriteData, 0, sizeof(fakeWriteData));
shellmatta_write_t writeCustomFakeSeq[1] = {writeFct_customFake};
SET_CUSTOM_FAKE_SEQ(writeFct, writeCustomFakeSeq, 1)
PROCESS_INPUT("?\r\n")
THEN("The shellmatta prints the help text")
{
static const char * response = (char*) "?\r\n"
"cmd1 1 cmd1 [options]\r\n"
"cmd2\r\n"
"cmd3\r\n"
"help ? help [command] - print help or usage information\r\n\r\n"
"shellmatta->";
CHECK(writeFct_fake.call_count == 20);
CHECK(strlen(response) == fakeWriteLength);
CHECK(0 == strcmp(response, fakeWriteData));
}
}
}
}
SCENARIO("Test if the help command prints the usage correctly")
{
GIVEN("An initialized and empty Shellmatte instance")
{
shellmatta_instance_t inst;
shellmatta_handle_t handle;
char buffer[1024u];
char historyBuffer[1024u];
CHECK(SHELLMATTA_OK == shellmatta_doInit( &inst,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->",
NULL,
writeFct));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd1));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd2));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd3));
WHEN("The user requests usage information from a valid command")
{
FFF_FAKES_LIST(RESET_FAKE)
fakeWriteLength = 0u;
memset(fakeWriteData, 0, sizeof(fakeWriteData));
shellmatta_write_t writeCustomFakeSeq[1] = {writeFct_customFake};
SET_CUSTOM_FAKE_SEQ(writeFct, writeCustomFakeSeq, 1)
PROCESS_INPUT("help cmd1\r\n")
THEN("The shellmatta prints the help text")
{
static const char * response = (char*) "help cmd1\r\n"
"Help for command: cmd1 (1)\r\n\r\n"
"cmd1 [options]\r\n\r\n"
"Usage: \r\n"
"cmd1 usage\r\n--option, -o: option\r\n"
"\r\nshellmatta->";
CHECK(writeFct_fake.call_count == 22);
CHECK(strlen(response) == fakeWriteLength);
CHECK(0 == strcmp(response, fakeWriteData));
}
}
WHEN("The user requests usage information from a valid command using its alias")
{
FFF_FAKES_LIST(RESET_FAKE)
fakeWriteLength = 0u;
memset(fakeWriteData, 0, sizeof(fakeWriteData));
shellmatta_write_t writeCustomFakeSeq[1] = {writeFct_customFake};
SET_CUSTOM_FAKE_SEQ(writeFct, writeCustomFakeSeq, 1)
PROCESS_INPUT("help 1\r\n")
THEN("The shellmatta prints the help text")
{
static const char * response = (char*) "help 1\r\n"
"Help for command: cmd1 (1)\r\n\r\n"
"cmd1 [options]\r\n\r\n"
"Usage: \r\n"
"cmd1 usage\r\n--option, -o: option\r\n"
"\r\nshellmatta->";
CHECK(writeFct_fake.call_count == 19);
CHECK(strlen(response) == fakeWriteLength);
CHECK(0 == strcmp(response, fakeWriteData));
}
}
WHEN("The user requests usage information from an empty command")
{
FFF_FAKES_LIST(RESET_FAKE)
fakeWriteLength = 0u;
memset(fakeWriteData, 0, sizeof(fakeWriteData));
shellmatta_write_t writeCustomFakeSeq[1] = {writeFct_customFake};
SET_CUSTOM_FAKE_SEQ(writeFct, writeCustomFakeSeq, 1)
PROCESS_INPUT("help cmd2\r\n")
THEN("The shellmatta prints the help text - without alias, help and usage text")
{
static const char * response = (char*) "help cmd2\r\n"
"Help for command: cmd2\r\n"
"\r\nshellmatta->";
CHECK(writeFct_fake.call_count == 15);
CHECK(strlen(response) == fakeWriteLength);
CHECK(0 == strcmp(response, fakeWriteData));
}
}
WHEN("The user requests usage information from an empty stringed command")
{
FFF_FAKES_LIST(RESET_FAKE)
fakeWriteLength = 0u;
memset(fakeWriteData, 0, sizeof(fakeWriteData));
shellmatta_write_t writeCustomFakeSeq[1] = {writeFct_customFake};
SET_CUSTOM_FAKE_SEQ(writeFct, writeCustomFakeSeq, 1)
PROCESS_INPUT("help cmd3\r\n")
THEN("The shellmatta prints the help text - without alias, help and usage text")
{
static const char * response = (char*) "help cmd3\r\n"
"Help for command: cmd3\r\n"
"\r\nshellmatta->";
CHECK(writeFct_fake.call_count == 15);
CHECK(strlen(response) == fakeWriteLength);
CHECK(0 == strcmp(response, fakeWriteData));
}
}
WHEN("The user adds additional arguments to the help command")
{
FFF_FAKES_LIST(RESET_FAKE)
fakeWriteLength = 0u;
memset(fakeWriteData, 0, sizeof(fakeWriteData));
shellmatta_write_t writeCustomFakeSeq[1] = {writeFct_customFake};
SET_CUSTOM_FAKE_SEQ(writeFct, writeCustomFakeSeq, 1)
PROCESS_INPUT("help cmd2 foo bar meow this is nonsense\r\n")
THEN("The shellmatta ignores the superflous arguments")
{
static const char * response = (char*) "help cmd2 foo bar meow this is nonsense\r\n"
"Help for command: cmd2\r\n"
"\r\nshellmatta->";
CHECK(writeFct_fake.call_count == 45);
CHECK(strlen(response) == fakeWriteLength);
CHECK(0 == strcmp(response, fakeWriteData));
}
}
WHEN("The user requests help of a nonexisting command")
{
FFF_FAKES_LIST(RESET_FAKE)
fakeWriteLength = 0u;
memset(fakeWriteData, 0, sizeof(fakeWriteData));
shellmatta_write_t writeCustomFakeSeq[1] = {writeFct_customFake};
SET_CUSTOM_FAKE_SEQ(writeFct, writeCustomFakeSeq, 1)
PROCESS_INPUT("help cmd4\r\n")
THEN("The shellmatta prints the help list")
{
static const char * response = (char*) "help cmd4\r\n"
"cmd1 1 cmd1 [options]\r\n"
"cmd2\r\n"
"cmd3\r\n"
"help ? help [command] - print help or usage information\r\n\r\n"
"shellmatta->";
CHECK(writeFct_fake.call_count == 28);
CHECK(strlen(response) == fakeWriteLength);
CHECK(0 == strcmp(response, fakeWriteData));
}
}
}
}

View File

@ -1,501 +0,0 @@
/*
* Copyright (c) 2021 Stefan Strobel <stefan.strobel@shimatta.net>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
/**
* @file test_integration_history.cpp
* @brief integration test implementation for the history buffer of the shellmatta
* @author Stefan Strobel <stefan.strobel@shimatta.net>
*/
#include "test/framework/catch.hpp"
extern "C" {
#include "test/framework/fff.h"
#include "shellmatta.h"
}
#include <string.h>
FAKE_VALUE_FUNC(shellmatta_retCode_t, writeFct, const char *, uint32_t)
FAKE_VALUE_FUNC(shellmatta_retCode_t, cmdFct1, shellmatta_handle_t, const char *, uint32_t)
FAKE_VALUE_FUNC(shellmatta_retCode_t, cmdFct2, shellmatta_handle_t, const char *, uint32_t)
FAKE_VALUE_FUNC(shellmatta_retCode_t, cmdFct3, shellmatta_handle_t, const char *, uint32_t)
FAKE_VALUE_FUNC(shellmatta_retCode_t, cmdFct4, shellmatta_handle_t, const char *, uint32_t)
/* List of fakes */
#define FFF_FAKES_LIST(FAKE) \
FAKE(writeFct) \
FAKE(cmdFct1) \
FAKE(cmdFct2) \
FAKE(cmdFct3) \
FAKE(cmdFct4)
#define CHECK_FOR_COMMAND(hist, idx) \
CHECK(writeFct_fake.call_count == ((hist) + 1u)); \
CHECK(0 == memcmp(writeFct_fake.arg0_history[(hist)], commandSequence[(idx)], strlen(commandSequence[(idx)]) - 1)); \
CHECK((strlen(commandSequence[(idx)]) - 1) == writeFct_fake.arg1_history[(hist)]);
#define BUTTON_UP "\x1b" "[A"
#define BUTTON_DOWN "\x1b" "[B"
#define PROCESS_INPUT(input) \
CHECK(SHELLMATTA_OK == shellmatta_processData(handle, (char*)(input), sizeof((input)) - 1u));
static shellmatta_cmd_t cmd1 = {(char*)"cmd1", (char*)"1", NULL, NULL, cmdFct1, NULL};
static shellmatta_cmd_t cmd2 = {(char*)"cmd2", (char*)"2", NULL, NULL, cmdFct2, NULL};
static shellmatta_cmd_t cmd3 = {(char*)"cmd3", (char*)"3", NULL, NULL, cmdFct3, NULL};
static shellmatta_cmd_t cmd4 = {(char*)"cmd4", (char*)"4", NULL, NULL, cmdFct4, NULL};
char *commandSequence[] =
{
(char*)"foo\r",
(char*)"bar\r",
(char*)"cmd1\r",
(char*)"2\r",
(char*)"4\r",
(char*)"cmd3\r"
};
#define CMD_SEQ_LEN (sizeof(commandSequence) / sizeof(commandSequence[0]))
SCENARIO("Test the history buffer with a fixed sequence of commands in there")
{
GIVEN("An initialized Shellmatte instance with some commands already in the history buffer")
{
shellmatta_instance_t inst;
shellmatta_handle_t handle;
char buffer[1024u];
char historyBuffer[1024u];
FFF_FAKES_LIST(RESET_FAKE)
CHECK(SHELLMATTA_OK == shellmatta_doInit( &inst,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->",
NULL,
writeFct));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd1));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd2));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd3));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd4));
for(uint32_t i = 0u; i < CMD_SEQ_LEN; i++)
{
CHECK(SHELLMATTA_OK == shellmatta_processData(handle, commandSequence[i], strlen(commandSequence[i])));
}
WHEN("The up button is pressed")
{
THEN("The shellmatta prints the most recent command")
{
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK(writeFct_fake.call_count == 2);
CHECK(0 == memcmp(writeFct_fake.arg0_history[0], "\x1b" "[K", 3));
CHECK(3 == writeFct_fake.arg1_history[0]);
CHECK(0 == memcmp(writeFct_fake.arg0_history[1], commandSequence[CMD_SEQ_LEN - 1], strlen(commandSequence[CMD_SEQ_LEN - 1]) - 1));
CHECK((strlen(commandSequence[CMD_SEQ_LEN - 1]) - 1) == writeFct_fake.arg1_history[1]);
for(uint32_t i = CMD_SEQ_LEN - 1; i > 0; i--)
{
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK(writeFct_fake.call_count == 3);
CHECK(0 == memcmp(writeFct_fake.arg0_history[1], "\x1b" "[K", 3));
CHECK(3 == writeFct_fake.arg1_history[1]);
CHECK(0 == memcmp(writeFct_fake.arg0_history[2], commandSequence[i - 1u], strlen(commandSequence[i - 1u]) - 1));
CHECK((strlen(commandSequence[i - 1u]) - 1) == writeFct_fake.arg1_history[2]);
}
}
}
WHEN("The history buffer it at the oldest command yet")
{
for(uint32_t i = CMD_SEQ_LEN; i > 0; i--)
{
PROCESS_INPUT(BUTTON_UP)
}
AND_WHEN("The up button is pressed again")
{
THEN("The output is deleted and the oldest command is printed again")
{
for(uint32_t i = 0u; i < 64; i++)
{
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, 0u)
}
}
}
AND_WHEN("The down button is pressed")
{
THEN("On each button press one newer command is printed")
{
for(uint32_t i = 1; i < CMD_SEQ_LEN; i++)
{
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK(0 == memcmp(writeFct_fake.arg0_history[1], "\x1b" "[K", 3));
CHECK(3 == writeFct_fake.arg1_history[1]);
CHECK_FOR_COMMAND(2u, i)
}
}
}
}
WHEN("The user pushes the up and down button alternately")
{
THEN("The output shall be updated with the correct command or not updated at all when at the end")
{
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(1u, CMD_SEQ_LEN - 1u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 2u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 1u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK(writeFct_fake.call_count == 0u);
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK(writeFct_fake.call_count == 0u);
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 2u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 3u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 4u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 5u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 6u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 6u)
/* back down again */
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 5u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 4u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 3u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 2u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 1u)
/* end of the buffer - shellmatta shall not update */
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK(writeFct_fake.call_count == 0u);
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK(writeFct_fake.call_count == 0u);
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 2u)
}
}
}
}
SCENARIO("Test how the history buffer handles more commands than fits inside the buffer")
{
GIVEN("An initialized Shellmatte instance with some commands already in the history buffer")
{
shellmatta_instance_t inst;
shellmatta_handle_t handle;
char buffer[1024u];
char historyBuffer[16u] = {0};
FFF_FAKES_LIST(RESET_FAKE)
CHECK(SHELLMATTA_OK == shellmatta_doInit( &inst,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->",
NULL,
writeFct));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd1));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd2));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd3));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd4));
for(uint32_t i = 0u; i < CMD_SEQ_LEN; i++)
{
CHECK(SHELLMATTA_OK == shellmatta_processData(handle, commandSequence[i], strlen(commandSequence[i])));
}
WHEN("The user pushes the up and down button alternately")
{
THEN("The output shall be updated with the correct commands that did fit into the buffer")
{
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(1u, CMD_SEQ_LEN - 1u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 2u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 3u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 4u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 4u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 3u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 2u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 3u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 2u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 1u)
}
}
WHEN("A command dowes not fit into the history buffer")
{
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT("This is a very long command input\r")
THEN("The input is not stored")
{
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(1u, CMD_SEQ_LEN - 1u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 2u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 3u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 4u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 4u)
}
}
}
}
SCENARIO("Test if the history buffer stores changes done during navigating")
{
GIVEN("An initialized Shellmatte instance with some commands already in the history buffer")
{
shellmatta_instance_t inst;
shellmatta_handle_t handle;
char buffer[1024u];
char historyBuffer[16u] = {0};
FFF_FAKES_LIST(RESET_FAKE)
CHECK(SHELLMATTA_OK == shellmatta_doInit( &inst,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->",
NULL,
writeFct));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd1));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd2));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd3));
CHECK(SHELLMATTA_OK == shellmatta_addCmd(handle, &cmd4));
for(uint32_t i = 0u; i < CMD_SEQ_LEN; i++)
{
CHECK(SHELLMATTA_OK == shellmatta_processData(handle, commandSequence[i], strlen(commandSequence[i])));
}
WHEN("The user pushes the up and down button alternately and inputs data in between")
{
THEN("The output shall be updated with the correct commands and the input shall be stored")
{
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(1u, CMD_SEQ_LEN - 1u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 2u)
PROCESS_INPUT("\b123456")
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 3u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 2u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 1u)
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_DOWN)
CHECK(writeFct_fake.call_count == 3);
CHECK(0 == memcmp(writeFct_fake.arg0_history[2], "123456", 6));
CHECK(6 == writeFct_fake.arg1_history[2]);
PROCESS_INPUT("\r")
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK(writeFct_fake.call_count == 2);
CHECK(0 == memcmp(writeFct_fake.arg0_history[1], "123456", 6));
CHECK(6 == writeFct_fake.arg1_history[1]);
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK_FOR_COMMAND(2u, CMD_SEQ_LEN - 1u)
PROCESS_INPUT("\x03" "12345678\r")
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK(writeFct_fake.call_count == 2);
CHECK(0 == memcmp(writeFct_fake.arg0_history[1], "12345678", 8));
CHECK(8 == writeFct_fake.arg1_history[1]);
PROCESS_INPUT("\r")
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK(writeFct_fake.call_count == 2);
CHECK(0 == memcmp(writeFct_fake.arg0_history[1], "12345678", 8));
CHECK(8 == writeFct_fake.arg1_history[1]);
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK(writeFct_fake.call_count == 3);
CHECK(0 == memcmp(writeFct_fake.arg0_history[2], "123456", 6));
CHECK(6 == writeFct_fake.arg1_history[2]);
/* check if the compare gets it when the new command is exactly one character longer than the stored */
PROCESS_INPUT("\x03" "123456789\r")
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK(writeFct_fake.call_count == 2);
CHECK(0 == memcmp(writeFct_fake.arg0_history[1], "123456789", 9));
CHECK(9 == writeFct_fake.arg1_history[1]);
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK(writeFct_fake.call_count == 3);
CHECK(0 == memcmp(writeFct_fake.arg0_history[2], "123456789", 9));
CHECK(9 == writeFct_fake.arg1_history[2]);
/* check if the compare gets it when the last command ist longer than the new one */
PROCESS_INPUT("\x03" "12345678\r")
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK(writeFct_fake.call_count == 2);
CHECK(0 == memcmp(writeFct_fake.arg0_history[1], "12345678", 8));
CHECK(8 == writeFct_fake.arg1_history[1]);
/* check what happens when there is a \0 in the buffer */
PROCESS_INPUT("\x03" "1234" "\0" "678\r")
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK(writeFct_fake.call_count == 2);
CHECK(0 == memcmp(writeFct_fake.arg0_history[1], "1234", 4));
CHECK(4 == writeFct_fake.arg1_history[1]);
/* check what happens when there is a \0 in the buffer */
PROCESS_INPUT("\x03" "1234" "\0" "888\r")
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK(writeFct_fake.call_count == 2);
CHECK(0 == memcmp(writeFct_fake.arg0_history[1], "1234", 4));
CHECK(4 == writeFct_fake.arg1_history[1]);
FFF_FAKES_LIST(RESET_FAKE)
PROCESS_INPUT(BUTTON_UP)
CHECK(writeFct_fake.call_count == 3);
CHECK(0 == memcmp(writeFct_fake.arg0_history[2], "888", 3));
CHECK(3 == writeFct_fake.arg1_history[2]);
}
}
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> * Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net> * Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -4,8 +4,4 @@
#define CATCH_CONFIG_MAIN #define CATCH_CONFIG_MAIN
#include "test/framework/catch.hpp" #include "test/framework/catch.hpp"
extern "C" {
#include "test/framework/fff.h"
DEFINE_FFF_GLOBALS
}

View File

@ -1,72 +0,0 @@
#include "test/framework/catch.hpp"
#include "src/shellmatta_opt.c"
#include <string.h>
TEST_CASE( "shellmatta_opt peekNextHunk next char without space" ) {
char ret = 0;
shellmatta_instance_t inst;
char *dummyData = (char*) "Welcome... to Jurassic Park.";
char buffer[1024u];
memcpy(buffer, dummyData, strlen(dummyData));
inst.buffer = buffer;
inst.bufferSize = sizeof(buffer);
inst.inputCount = 28u;
inst.optionParser.nextOffset = 11u;
ret = peekNextHunk(&inst);
CHECK( ret == 't' );
}
TEST_CASE( "shellmatta_opt peekNextHunk next char with space" ) {
char ret = 0;
shellmatta_instance_t inst;
char *dummyData = (char*) "Welcome... to Jurassic Park.\0";
char buffer[1024u];
memcpy(buffer, dummyData, strlen(dummyData));
inst.buffer = buffer;
inst.bufferSize = sizeof(buffer);
inst.inputCount = 28u;
inst.optionParser.nextOffset = 13u;
ret = peekNextHunk(&inst);
CHECK( ret == 'J' );
}
TEST_CASE( "shellmatta_opt peekNextHunk next hunk escape and space" ) {
char ret = 0;
shellmatta_instance_t inst;
char *dummyData = (char*) "Welcome... to Jurassic Park.\0 Remind me to thank John for a lovely weekend.";
char buffer[1024u];
uint16_t stringsize = 77u;
memcpy(buffer, dummyData, stringsize);
inst.buffer = buffer;
inst.bufferSize = sizeof(buffer);
inst.inputCount = stringsize;
inst.optionParser.nextOffset = 28u;
ret = peekNextHunk(&inst);
CHECK( ret == 'R' );
}
TEST_CASE( "shellmatta_opt peekNextHunk next char with spaces" ) {
char ret = 0;
shellmatta_instance_t inst;
char *dummyData = (char*) "Welcome... to Jurassic Park.\0 Remind me to thank John for a lovely weekend.";
char buffer[1024u];
uint16_t stringsize = 77u;
memcpy(buffer, dummyData, stringsize);
inst.buffer = buffer;
inst.bufferSize = sizeof(buffer);
inst.inputCount = stringsize;
inst.optionParser.nextOffset = 36u;
ret = peekNextHunk(&inst);
CHECK( ret == 'm' );
}

View File

@ -123,58 +123,3 @@ TEST_CASE( "shellmatta_insertChars 0 length" ) {
CHECK( memcmp("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", write_data, sizeof(write_data) ) == 0u ); CHECK( memcmp("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", write_data, sizeof(write_data) ) == 0u );
REQUIRE( memcmp("abcdefghij\0\0\0\0\0\0\0\0\0", buffer, sizeof(buffer)) == 0); REQUIRE( memcmp("abcdefghij\0\0\0\0\0\0\0\0\0", buffer, sizeof(buffer)) == 0);
} }
TEST_CASE( "shellmatta_insertChars buffer full" ) {
shellmatta_instance_t inst;
char buffer[20] = "abcdefghij\0\0\0\0\0\0\0\0\0";
memset(&inst, 0, sizeof(inst));
inst.buffer = buffer;
inst.bufferSize = 20;
inst.cursor = 8;
inst.inputCount = 10;
inst.echoEnabled = true;
inst.write = writeFct;
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_idx = 0u;
utils_insertChars(&inst, (char*)"blksdflsd kfjlk", 10u);
CHECK( inst.cursor == 18u );
CHECK( inst.inputCount == 20u );
CHECK( write_callCnt == 5u );
CHECK( memcmp("blksdflsd ", write_data, 10u ) == 0u );
REQUIRE( memcmp("abcdefghblksdflsd ij", buffer, sizeof(buffer)) == 0);
}
TEST_CASE( "shellmatta_insertChars buffer overflow by 1" ) {
shellmatta_instance_t inst;
char buffer[20] = "abcdefghij\0\0\0\0\0\0\0\0\0";
memset(&inst, 0, sizeof(inst));
inst.buffer = buffer;
inst.bufferSize = 20;
inst.cursor = 8;
inst.inputCount = 10;
inst.echoEnabled = true;
inst.write = writeFct;
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_idx = 0u;
utils_insertChars(&inst, (char*)"blksdflsd kfjlk", 11u);
CHECK( inst.cursor == 18u );
CHECK( inst.inputCount == 20u );
CHECK( write_callCnt == 5u );
CHECK( memcmp("blksdflsd ", write_data, 10u ) == 0u );
REQUIRE( memcmp("abcdefghblksdflsd ij", buffer, sizeof(buffer)) == 0);
}

View File

@ -1,200 +0,0 @@
#include "test/framework/catch.hpp"
#include "src/shellmatta_utils.h"
#include <string.h>
static uint32_t write_callCnt = 0u;
static char write_data[20];
static uint32_t write_idx;
static shellmatta_retCode_t writeFct(const char* data, uint32_t length)
{
write_callCnt ++;
strncpy(&write_data[write_idx], data, length);
write_idx += length;
return SHELLMATTA_OK;
}
TEST_CASE("shellmatta_utils_removeChars_nothing_removed"){
shellmatta_instance_t inst;
memset(&inst, 0, sizeof(inst));
uint32_t length = 0u;
bool backspace = true;
inst.write = writeFct;
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_idx = 0u;
inst.cursor = 20u;
inst.inputCount = 20u;
char buffer[20] = "abcdefghijklmnopqr";
inst.buffer = buffer;
inst.bufferSize = 20u;
utils_removeChars( &inst, length, backspace);
CHECK( inst.cursor == 20u);
CHECK( inst.inputCount == 20);
REQUIRE(strncmp("abcdefghijklmnopqr", buffer, sizeof(buffer)) == 0);
}
TEST_CASE("shellmatta_utils_removeChars_backspace_false"){
shellmatta_instance_t inst;
char buffer[20] = "abcdefghijklmnopqr";
memset(&inst, 0, sizeof(inst));
uint32_t length = 5u;
bool backspace = false;
inst.write = writeFct;
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_idx = 0u;
inst.cursor = 20;
inst.inputCount = 20u;
inst.buffer = buffer;
inst.bufferSize = 20u;
utils_removeChars(&inst, length, backspace);
CHECK( inst.cursor == 20u);
CHECK( inst.inputCount == 20);
REQUIRE(strncmp("abcdefghijklmnopqr", buffer, sizeof(buffer)) == 0);
}
TEST_CASE("shellmatta_utils_removeChars_remove_five"){
shellmatta_instance_t inst;
char buffer[20] = "abcdefghijklmnopqr";
memset(&inst, 0, sizeof(inst));
inst.write = writeFct;
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_idx = 0u;
uint32_t length = 5u;
bool backspace = true;
inst.cursor = 10u;
inst.inputCount = 20u;
inst.bufferSize = 20u;
inst.buffer = buffer;
utils_removeChars(&inst, length, backspace);
CHECK( inst.cursor == 5u);
CHECK( inst.inputCount == 15u);
REQUIRE(strncmp("abcdeklmnopqr", buffer, sizeof(buffer)) == 0);
}
TEST_CASE("shellmatta_utils_removeChars_length_greater_than_CursorPos"){
shellmatta_instance_t inst;
char buffer[20] = "abcdefghijklmnopqr";
memset(&inst, 0, sizeof(inst));
inst.write = writeFct;
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_idx = 0u;
uint32_t length = 15u;
bool backspace = true;
inst.cursor = 10u;
inst.inputCount = 20u;
inst.bufferSize = 20u;
inst.buffer = buffer;
utils_removeChars(&inst, length, backspace);
CHECK( inst.cursor == 0u);
CHECK( inst.inputCount == 10u);
REQUIRE(strncmp("klmnopqr", buffer, sizeof(buffer)) == 0);
}
TEST_CASE("shellmatta_utils_removeChars_remove_chars_in_the_middle_of_the_buffer_backspace_false"){
shellmatta_instance_t inst;
char buffer[20] = "abcdefghijklmnopqr";
memset(&inst, 0, sizeof(inst));
inst.write = writeFct;
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_idx = 0u;
uint32_t length = 5u;
bool backspace = false;
inst.cursor = 10u;
inst.inputCount = 20u;
inst.bufferSize = 20u;
inst.buffer = buffer;
utils_removeChars(&inst, length, backspace);
CHECK( inst.cursor == 10u);
CHECK( inst.inputCount == 15u);
REQUIRE(strncmp("abcdefghijpqr", buffer, sizeof(buffer)) == 0);
}
TEST_CASE("shellmatta_utils_removeChars_remove_more_chars_in_middle_of_buffer_than_are_present_backspace_false"){
shellmatta_instance_t inst;
char buffer[20] = "abcdefghijklmnopqr";
memset(&inst, 0, sizeof(inst));
inst.write = writeFct;
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_idx = 0u;
uint32_t length = 15u;
bool backspace = false;
inst.cursor = 10u;
inst.inputCount = 20u;
inst.bufferSize = 20u;
inst.buffer = buffer;
utils_removeChars(&inst, length, backspace);
CHECK( inst.cursor == 10u);
CHECK( inst.inputCount == 10u);
REQUIRE(strncmp("abcdefghij", buffer, 10u) == 0);
}
TEST_CASE("shellmatta_utils_removeChars_curser_outside_buffer"){
shellmatta_instance_t inst;
char buffer[20] = "abcdefghijklmnopqr";
memset(&inst, 0, sizeof(inst));
inst.write = writeFct;
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_idx = 0u;
uint32_t length = 15u;
bool backspace = false;
inst.cursor = 21u;
inst.inputCount = 20u;
inst.bufferSize = 20u;
inst.buffer = buffer;
utils_removeChars(&inst, length, backspace);
CHECK( inst.cursor == 21u);
CHECK( inst.inputCount == 20u);
REQUIRE(strncmp("abcdefghijklmnopqr", buffer, sizeof(buffer)) == 0);
}