Skip to content

Commit 448ef57

Browse files
committed
Cosmetic changes
1 parent faf07c5 commit 448ef57

File tree

7 files changed

+168
-348
lines changed

7 files changed

+168
-348
lines changed

README.md

Lines changed: 116 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,15 @@ A cross-platform header only C++14 library for interactive command line interfac
2828

2929
## Dependencies
3030

31+
The library has no dependencies if you don't need remote sessions.
32+
3133
The library depends on asio (either the standalone version or the boost version)
32-
only to provide telnet server.
33-
Therefore, the library has no dependencies if you don't need remote sessions.
34+
*only* to provide telnet server (i.e., remote sessions).
3435

3536
## Installation
3637

3738
The library is header-only: it consists entirely of header files
38-
containing templates and inline functions, and require no separately-compiled
39+
containing templates and inline functions, and requires no separately-compiled
3940
library binaries or special treatment when linking.
4041

4142
Extract the archive wherever you want.
@@ -49,7 +50,7 @@ If you fancy it, a Cmake script is provided. To install you can use:
4950
cmake ..
5051
sudo make install
5152

52-
and, if you want to specify the installation path:
53+
or, if you want to specify the installation path:
5354

5455
mkdir build && cd build
5556
cmake .. -DCMAKE_INSTALL_PREFIX:PATH=<cli_install_location>
@@ -64,29 +65,47 @@ and linking pthread on linux (and optionally boost system).
6465

6566
To compile the examples using cmake, use:
6667

67-
mkdir build
68-
cd build
68+
mkdir build && cd build
69+
70+
# compile only the examples that do not require boost/asio libraries
6971
cmake .. -DCLI_BuildExamples=ON
70-
# or: cmake .. -DCLI_BuildExamples=ON -DBOOST_INCLUDEDIR=<boost_include_directory>
71-
make all
72-
# or: cmake --build .
72+
73+
# compile the examples by using boost asio libraries
74+
cmake .. -DCLI_BuildExamples=ON -DCLI_UseBoostAsio=ON
75+
# or: cmake .. -DCLI_BuildExamples=ON -DCLI_UseBoostAsio=ON -DBOOST_ROOT=<boost_path>
76+
77+
# compile the examples by using standalone asio library
78+
cmake .. -DCLI_BuildExamples=ON -DCLI_UseStandaloneAsio=ON
79+
# or: cmake .. -DCLI_BuildExamples=ON -DCLI_UseStandaloneAsio=ON -DASIO_INCLUDEDIR=<asio_path>
80+
81+
cmake --build .
7382

7483
In the same directory you can also find:
7584

76-
* a GNU make file (Makefile)
77-
* a Windows nmake file (makefile.win)
85+
* GNU make files (Makefile.noasio, Makefile.boostasio, Makefile.standaloneasio)
86+
* Windows nmake files (makefile.noasio.win, makefile.boostasio.win, makefile.standaloneasio.win)
7887
* a Visual Studio solution
7988

80-
You can specify boost library path in the following ways:
89+
You can specify boost/asio library path in the following ways:
8190

8291
### GNU Make
8392

93+
for boost:
94+
8495
make CXXFLAGS="-isystem <boost_include>" LDFLAGS="-L<boost_lib>"
8596

8697
example:
8798

8899
make CXXFLAGS="-isystem /opt/boost_1_66_0/install/x86/include" LDFLAGS="-L/opt/boost_1_66_0/install/x86/lib"
89100

101+
for standalone asio:
102+
103+
make CXXFLAGS="-isystem <asio_include>"
104+
105+
example:
106+
107+
make CXXFLAGS="-isystem /opt/asio-1.18.0/include"
108+
90109
(if you want to use clang instead of gcc, you can set the variable CXX=clang++)
91110

92111
### Windows nmake
@@ -133,6 +152,91 @@ Some example:
133152
cli> echo "you can also show backslash \\ ... "
134153
you can also show backslash \ ...
135154

155+
## Async programming and Schedulers
156+
157+
`cli` is an asynchronous library, and the handlers of commands are executed
158+
by a scheduler, in a thread provided by the user (possibly the main thread),
159+
this allows you to develop a single thread application
160+
without need to worry about synchronization.
161+
162+
So, your application must have a scheduler and pass it to `CliLocalTerminalSession`.
163+
164+
The library provides three schedulers:
165+
166+
- `LoopScheduler`
167+
- `BoostAsioScheduler`
168+
- `StandaloneAsioScheduler`
169+
170+
`LoopScheduler` is the simplest: it does not depend on other libraries
171+
and should be your first choice if you don't need remote sessions.
172+
173+
`BoostAsioScheduler` and `StandaloneAsioScheduler` are wrappers around
174+
asio `io_context` objects.
175+
You should use one of them if you need a `BoostAsioCliTelnetServer` or a `StandaloneAsioCliTelnetServer`
176+
because they internally use `boost::asio` and `asio`.
177+
178+
You should use one of them also if your application uses `asio` in some way.
179+
180+
After setting up your application, you must call `Scheduler::Run()`
181+
to enter the scheduler loop. Each comamnd handler of the library
182+
will execute in the thread that called `Scheduler::Run()`.
183+
184+
You can exit the scheduler loop by calling `Scheduler::Stop()`
185+
(e.g., as an action associated to the "exit" command).
186+
187+
You can submit work to be executed by the scheduler invoking the method
188+
`Scheduler::Post(const std::function<void()>& f)`.
189+
Schedulers are thread safe, so that you can post function object
190+
from any thread, to be executed in the scheduler thread.
191+
192+
This is an example of use of `LoopScheduler`:
193+
194+
```C++
195+
...
196+
LoopScheduler scheduler;
197+
CliLocalTerminalSession localSession(cli, scheduler);
198+
...
199+
// in another thread you can do:
200+
scheduler.Post([](){ cout << "This will be executed in the scheduler thread" << endl; });
201+
...
202+
// start the scheduler main loop
203+
// it will exit from this method only when scheduler.Stop() is called
204+
// each cli callback will be executed in this thread
205+
scheduler.Run();
206+
...
207+
```
208+
209+
This is an example of use of `BoostAsioScheduler`
210+
211+
```C++
212+
...
213+
BoostAsioScheduler scheduler;
214+
CliLocalTerminalSession localSession(cli, scheduler);
215+
BoostAsioCliTelnetServer server(cli, scheduler, 5000);
216+
...
217+
scheduler.Run();
218+
...
219+
```
220+
221+
Finally, this is an example of use of `BoostAsioScheduler`
222+
when your application already uses `boost::asio` and has
223+
a `boost::asio::io_context` object (the case of standalone asio is similar).
224+
225+
```C++
226+
...
227+
// somewhere else in your application
228+
boost::asio::io_context ioc;
229+
...
230+
// cli setup
231+
BoostAsioScheduler scheduler(ioc);
232+
CliLocalTerminalSession localSession(cli, scheduler);
233+
BoostAsioCliTelnetServer server(cli, scheduler, 5000);
234+
...
235+
// somewhere else in your application
236+
ioc.run();
237+
...
238+
```
239+
136240
## License
137241
138242
Distributed under the Boost Software License, Version 1.0.

doc/doxy/Doxyfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ GENERATE_AUTOGEN_DEF = NO
5353
GENERATE_PERLMOD = NO
5454
#---------------------------------------------------------------------------
5555
HAVE_DOT = YES
56-
CLASS_DIAGRAMS = NO
56+
CLASS_DIAGRAMS = YES
5757
CLASS_GRAPH = YES
5858
COLLABORATION_GRAPH = NO
5959
INCLUDE_GRAPH = YES

examples/complete.cpp

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
#include <cli/clilocalsession.h>
5656
#include <cli/filehistorystorage.h>
5757

58+
#include <vector>
59+
#include <algorithm> // std::copy
5860

5961
using namespace cli;
6062
using namespace std;
@@ -66,49 +68,49 @@ int main()
6668

6769
// setup cli
6870

69-
auto rootMenu = make_unique< Menu >( "cli" );
70-
rootMenu -> Insert(
71+
auto rootMenu = make_unique<Menu>("cli");
72+
rootMenu->Insert(
7173
"hello",
7274
[](std::ostream& out){ out << "Hello, world\n"; },
7375
"Print hello world" );
74-
rootMenu -> Insert(
76+
rootMenu->Insert(
7577
"hello_everysession",
7678
[](std::ostream&){ Cli::cout() << "Hello, everybody" << std::endl; },
7779
"Print hello everybody on all open sessions" );
78-
rootMenu -> Insert(
80+
rootMenu->Insert(
7981
"answer",
8082
[](std::ostream& out, int x){ out << "The answer is: " << x << "\n"; },
8183
"Print the answer to Life, the Universe and Everything" );
82-
rootMenu -> Insert(
84+
rootMenu->Insert(
8385
"file",
8486
[](std::ostream& out, int fd)
8587
{
8688
out << "file descriptor: " << fd << "\n";
8789
},
8890
"Print the file descriptor specified",
8991
{"file_descriptor"} );
90-
rootMenu -> Insert(
92+
rootMenu->Insert(
9193
"echo", {"string to echo"},
9294
[](std::ostream& out, const string& arg)
9395
{
9496
out << arg << "\n";
9597
},
9698
"Print the string passed as parameter" );
97-
rootMenu -> Insert(
99+
rootMenu->Insert(
98100
"echo", {"first string to echo", "second string to echo"},
99101
[](std::ostream& out, const string& arg1, const string& arg2)
100102
{
101103
out << arg1 << ' ' << arg2 << "\n";
102104
},
103105
"Print the strings passed as parameter" );
104-
rootMenu -> Insert(
106+
rootMenu->Insert(
105107
"error",
106108
[](std::ostream&)
107109
{
108110
throw std::logic_error("Error in cmd");
109111
},
110112
"Throw an exception in the command handler" );
111-
rootMenu -> Insert(
113+
rootMenu->Insert(
112114
"reverse", {"string_to_revert"},
113115
[](std::ostream& out, const string& arg)
114116
{
@@ -117,21 +119,31 @@ int main()
117119
out << copy << "\n";
118120
},
119121
"Print the reverse string" );
120-
rootMenu -> Insert(
122+
rootMenu->Insert(
121123
"add", {"first_term", "second_term"},
122124
[](std::ostream& out, int x, int y)
123125
{
124126
out << x << " + " << y << " = " << (x+y) << "\n";
125127
},
126128
"Print the sum of the two numbers" );
127-
rootMenu -> Insert(
129+
rootMenu->Insert(
128130
"add",
129131
[](std::ostream& out, int x, int y, int z)
130132
{
131133
out << x << " + " << y << " + " << z << " = " << (x+y+z) << "\n";
132134
},
133135
"Print the sum of the three numbers" );
134-
colorCmd = rootMenu -> Insert(
136+
rootMenu->Insert(
137+
"sort", {"list of strings separated by space"},
138+
[](std::ostream& out, std::vector<std::string> data)
139+
{
140+
std::sort(data.begin(), data.end());
141+
out << "sorted list: ";
142+
std::copy(data.begin(), data.end(), std::ostream_iterator<std::string>(out, " "));
143+
out << "\n";
144+
},
145+
"Alphabetically sort a list of words" );
146+
colorCmd = rootMenu->Insert(
135147
"color",
136148
[&](std::ostream& out)
137149
{
@@ -141,7 +153,7 @@ int main()
141153
nocolorCmd.Enable();
142154
},
143155
"Enable colors in the cli" );
144-
nocolorCmd = rootMenu -> Insert(
156+
nocolorCmd = rootMenu->Insert(
145157
"nocolor",
146158
[&](std::ostream& out)
147159
{
@@ -160,24 +172,24 @@ int main()
160172
}
161173
);
162174

163-
auto subMenu = make_unique< Menu >( "sub" );
164-
subMenu -> Insert(
175+
auto subMenu = make_unique<Menu>("sub");
176+
subMenu->Insert(
165177
"hello",
166178
[](std::ostream& out){ out << "Hello, submenu world\n"; },
167179
"Print hello world in the submenu" );
168-
subMenu -> Insert(
180+
subMenu->Insert(
169181
"demo",
170182
[](std::ostream& out){ out << "This is a sample!\n"; },
171183
"Print a demo string" );
172184

173-
auto subSubMenu = make_unique< Menu >( "subsub" );
174-
subSubMenu -> Insert(
185+
auto subSubMenu = make_unique<Menu>("subsub");
186+
subSubMenu->Insert(
175187
"hello",
176188
[](std::ostream& out){ out << "Hello, subsubmenu world\n"; },
177189
"Print hello world in the sub-submenu" );
178-
subMenu -> Insert( std::move(subSubMenu));
190+
subMenu->Insert( std::move(subSubMenu) );
179191

180-
rootMenu -> Insert( std::move(subMenu) );
192+
rootMenu->Insert( std::move(subMenu) );
181193

182194
// create a cli with the given root menu and a persistent storage
183195
// you must pass to FileHistoryStorage the path of the history file
@@ -210,7 +222,7 @@ int main()
210222

211223
// setup server
212224

213-
CliTelnetServer server(scheduler, 5000, cli);
225+
CliTelnetServer server(cli, scheduler, 5000);
214226
// exit action for all the connections
215227
server.ExitAction( [](auto& out) { out << "Terminating this session...\n"; } );
216228

examples/pluginmanager.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,16 @@ class Strings : public RegisteredPlugin<Strings, StringsName>
226226
out << arg << "\n";
227227
},
228228
"Print the string in uppercase" );
229-
229+
subMenu->Insert(
230+
"sort", {"list of strings separated by space"},
231+
[](std::ostream& out, std::vector<std::string> data)
232+
{
233+
std::sort(data.begin(), data.end());
234+
out << "sorted list: ";
235+
std::copy(data.begin(), data.end(), std::ostream_iterator<std::string>(out, " "));
236+
out << "\n";
237+
},
238+
"Alphabetically sort a list of words" );
230239
menuHandler = menu->Insert(move(subMenu));
231240
}
232241
~Strings()

0 commit comments

Comments
 (0)