SlideShare a Scribd company logo
Add an interactive command
line to your applications
Daniele Pallastrelli, daniele77.github.io
13.01.2022, Italian C++
My typical projects
• Run for a long period of time
• No classic interaction with the user (i.e., no GUI)
• Run in a server, custom board, almost never desktop applications
• They're not CPU bound applications
Why an interactive console in your apps?
• Need to have some sort of console to interact with my
applications (e.g., embedded systems running around the clock)
to:
• monitor,
• configure,
• manage the system
• E.g., CISCO routers
• Traditional systems: SSH connections + logs
Why an interactive console in your apps?
• Debugging
• Poke around internal state
• Dump internal structures
• Change the log level at runtime
• Change the working mode
• Enable / disable modules
• Load / unload plugins
• Early stage of development
Reinventing the wheel?
Existing solutions in open source domain:
• Linux only
• They're applications where you hook external programs to commands
• No remote sessions
• Few in C++
• None of them in "modern" C++
Enter the shell (cli?)
• My own library in C++14
• Production code quality
• Used in several industrial projects
• Demo time 
• C++14
• Cross-platform (Linux and windows tested)
• Menus and submenus
• Command history (navigation with arrow keys)
• Autocompletion (with TAB key)
• Async interface
• Colors
Something missing…
• Good when you start the app from a console (e.g. desktop
applications or development stage)
• What about processes that run in background (e.g., embedded,
servers & c)?
Try #1
Try #1
Try #2
Add an interactive command line to your C++ application
Features summary
• C++14
• Header only
• Cross-platform (linux and windows)
• Menus and submenus
• Remote sessions (telnet)
• Persistent history (navigation with arrow keys)
• Autocompletion (with TAB key)
• Async interface
• Colors
auto rootMenu = make_unique<Menu>("cli");
rootMenu->Insert(
"hello",
[](std::ostream& out){ out << "Hello, worldn"; },
"Print hello world" );
rootMenu->Insert(
"hello_everysession",
[](std::ostream&){ Cli::cout() << "Hello, everybody" << std::endl; },
"Print hello everybody on all open sessions" );
rootMenu->Insert(
"reverse", {"string_to_revert"},
[](std::ostream& out, const string& arg)
{
string copy(arg);
std::reverse(copy.begin(), copy.end());
out << copy << "n";
},
"Print the reverse string" );
rootMenu->Insert(
"add", {"first_term", "second_term"},
[](std::ostream& out, int x, int y)
{
out << x << " + " << y << " = " << (x+y) << "n";
},
"Print the sum of the two numbers" );
rootMenu->Insert(
"sort", {"list of strings separated by space"},
[](std::ostream& out, std::vector<std::string> data)
{
std::sort(data.begin(), data.end());
out << "sorted list: ";
std::copy(data.begin(), data.end(), std::ostream_iterator<std::string>(out, " "));
out << "n";
},
"Alphabetically sort a list of words" );
auto subMenu = make_unique<Menu>("sub");
subMenu->Insert(
"demo",
[](std::ostream& out){ out << "This is a sample!n"; },
"Print a demo string" );
rootMenu->Insert( std::move(subMenu) );
// create a cli with the given root menu and a persistent storage
Cli cli( std::move(rootMenu), std::make_unique<FileHistoryStorage>(".cli") );
// global exit action
cli.ExitAction( [](auto& out){ out << "Goodbye and thanks for all the fish.n"; } );
// std exception custom handler
cli.StdExceptionHandler(
[](std::ostream& out, const std::string& cmd, const std::exception& e)
{
out << "Exception caught in cli handler: "
<< e.what()
<< " handling command: "
<< cmd
<< ".n";
}
);
LoopScheduler scheduler;
CliLocalTerminalSession localSession(cli, scheduler, std::cout, 200);
localSession.ExitAction(
[&scheduler](auto& out) // session exit action
{
out << "Closing App...n";
scheduler.Stop();
}
);
scheduler.Run();
StandaloneAsioScheduler scheduler;
CliLocalTerminalSession localSession(cli, scheduler, std::cout, 200);
localSession.ExitAction(
[&scheduler](auto& out) // session exit action
{
out << "Closing App...n";
scheduler.Stop();
}
);
// setup server
StandaloneAsioCliTelnetServer server(cli, scheduler, 5000);
// exit action for all the connections
server.ExitAction( [](auto& out) { out << "Terminating this session...n"; } );
scheduler.Run();
How does it work
Core idea
• Command list
• The user enters a string: command and parameters
• Iteration over the command list:
• Command name
• Parameter number and type
• The handler is called with the typed parameters
cli
hello hello_everysession sub
hello
demo
cli
hello
hello_everysession
sub
hello
demo
class Command {};
class Menu : public Command
{
private:
Menu* parent{ nullptr };
std::vector<Command*> cmds;
};
template <typename F, typename ... Args>
class VariadicFunctionCommand : public Command {};
Menu is-a Command, because when you start the CLI, every Menu shows as a command
you can digit at the prompt (e.g., if you define a Menu "foo", you get the command "foo" in
the Cli to enter the submenu).
auto rootMenu = make_unique<Menu>("cli");
rootMenu->Insert(
"hello",
[](std::ostream& out)
{
out << "Hello, worldn";
}
);
rootMenu->Insert(
"hello_everysession",
[](std::ostream&)
{
Cli::cout() << "Hello, everybodyn";
}
);
auto subMenu = make_unique<Menu>("sub");
subMenu->Insert(
"hello",
[](std::ostream& out)
{
out << "Hello, submenu worldn";
}
);
subMenu->Insert(
"demo",
[](std::ostream&)
{
out << "Demon";
}
);
rootMenu->Insert( std::move(subMenu) );
auto rootMenu = make_unique<Menu>("cli");
...
Cli cli( std::move(rootMenu) );
auto rootMenu = make_unique<Menu>("cli");
...
Cli cli( std::move(rootMenu) );
CliLocalTerminalSession localSession(cli,
scheduler, std::cout, 200);
CliTelnetServer server(cli, scheduler, 5000);
Cli cli( std::move(rootMenu) );
CliLocalTerminalSession localSession(cli,
scheduler, std::cout, 200);
CliTelnetServer server(cli, scheduler, 5000);
CliFileSession fileSession(cli, infile, outfile);
CliLocalTerminalSession localSession(
scheduler, std::cout, 200);
CliTelnetServer server(scheduler, 5000);
CliFileSession fileSession(infile, outfile);
Cli cli( std::move(rootMenu) );
cli.SetLocalSession( localSession );
cli.SetFileSession( fileSession );
cli.SetTelnetServer( server );
Add an interactive command line to your C++ application
rootMenu->Insert(
"add", {"first_term", "second_term"},
[](std::ostream& out, int x, int y)
{
out << x << " + " << y << " = " << (x+y) << "n";
},
"Print the sum of two numbers"
);
rootMenu->Insert(
"add", {"first_term", "second_term"},
[](std::ostream& out, int x, int y)
{
out << x << " + " << y << " = " << (x+y) << "n";
},
"Print the sum of two numbers"
);
Interlude – How do you get the type of a
lambda argument?
template <typename F>
void foo(F f)
{
// what's the type of "f" first parameter?
// something like:
// using T = F::first_parameter_type
)
foo( [](int){} );
Interlude – How do you get the type of a
lambda argument?
template<typename F, typename Ret, typename A, typename... Rest>
A helper(Ret (F::*)(A, Rest...) const);
template <typename F>
void foo(F f)
{
using T = decltype( helper(&F::operator()) );
}
foo( [](int){} );
class Menu : public Command
{
public:
template <typename F>
CmdHandler Insert(const string& cmdName, F f)
{
return CreateCmd(cmdName, f, &F::operator());
}
private:
template <typename F, typename R, typename ... Args>
CmdHandler CreateCmd(const string& cmdName, F& f, R (F::*)(Args...) const)
{
auto cmd = make_unique< VariadicFunctionCommand< F, Args ... > >(cmdName, f);
// insert cmd into this menu commands
...
}
};
Works with lambdas
and std::function
class Menu : public Command
{
public:
...
template <typename R, typename ... Args>
CmdHandler Insert(const std::string& cmdName, R (*f)(Args...))
{
using F = R (*)(Args...);
auto cmd = make_unique<VariadicFunctionCommand<F, Args ...>>(cmdName, f);
// insert cmd into this menu commands
...
}
...
};
Overload for free-
functions
template <typename F, typename ... Args>
class VariadicFunctionCommand : public Command
{
public:
VariadicFunctionCommand(const std::string& _name, F fun) :
Command(_name), func(std::move(fun))
{}
bool Exec(const vector<string>& cmdLine) override
{
...
try
{
Select<Args...>::Exec(func, std::next(cmdLine.begin()), cmdLine.end());
}
catch (std::bad_cast&)
{
return false;
}
return true;
...
}
};
template <typename ... Args>
struct Select;
template <typename P, typename ... Args>
struct Select<P, Args...>
{
template <typename F, typename InputIt>
static void Exec(const F& f, InputIt first, InputIt last)
{
assert( first != last );
assert( std::distance(first, last) == 1+sizeof...(Args) );
const P firstPar = detail::from_string<typename std::decay<P>::type>(*first);
auto g = [&](auto ... pars){ f(firstPar, pars...); };
Select<Args...>::Exec(g, std::next(first), last);
}
};
template <>
struct Select<>
{
template <typename F, typename InputIt>
static void Exec(const F& f, InputIt first, InputIt last)
{
assert(first == last);
f();
}
};
Interlude
How do you manage concurrency?
Concurrency in my projects
• Single thread (when possible), using Proactor pattern.
• When I must: multiple threads, using Proactor pattern 
By the way…
…what's the PROACTOR pattern?
The proactor pattern: Concurrency Without Threads
The Proactor solution
Split every application service into:
• Long-duration operations. execute asynchronously
• Completion handlers. processes the results of the associated
asynchronous operations (potentially invoking additional
asynchronous operations).
Add an interactive command line to your C++ application
Add an interactive command line to your C++ application
Waiting for
completion events
Unblocking
Add an interactive command line to your C++ application
Concurrency in my projects
• asio for asynchonous I/O (timers, too)
• asio::io_context available
• When I/O is ready, asio puts handler in the asio::io_context
• If more threads are needed (e.g., time consuming computations or
blocking I/O), the result is put in asio::io_context
• => everything runs in (my) single thread of execution
Back to the library 
• Input coming from:
• Keyboard, using blocking primitives (std::getchar() and _getch())
• Sockets
• Commands callbacks (in which thread?)
• => proactor (asio::io_context)
Consequences
• The user must instantiate a boost::asio::io_context object
• The whole library depends on boost::asio
Concurrency summary (v. 1.0)
• The library depends on boost::asio, even when you don't need the
telnet server
• Library users ask to use standalone asio instead of boost::asio
• The truth is that the whole library depends on boost::asio because:
• Telnet server needs it
• Keyboard handler needs an event handler
• The two must use the same event manager, i.e. boost::asio::io_context
Release 2.0 – Goals:
• Optionally use standalone asio instead of boost::asio for the telnet
server
• Remove all dependencies if the telnet server is not needed
Release 2.0 – The solution
• New abstraction: "Scheduler"
• schedules async event
• The library provides three kind of schedulers:
• StandaloneAsioScheduler (based on asio::io_context)
• BoostAsioScheduler (based on boost::asio::io_context)
• LoopScheduler (hand made sync queue)
Release 2.0 – The solution
• Cli library can use all the schedulers, but if you need the telnet server
you must use *AsioScheduler
• Bottom line:
• If ( you need telnet server OR your app already uses [boost::]asio::io_context
=> StandaloneAsioScheduler or BoostAsioScheduler
• Else
=> LoopScheduler (no external dependencies)
Release 2.0 – Standalone Asio
#include <cli/standaloneasioscheduler.h>
#include <cli/standaloneasioremotecli.h>
...
StandaloneAsioScheduler scheduler;
// setup local session
CliLocalTerminalSession localSession(cli, scheduler, std::cout, 200);
// setup server
StandaloneAsioCliTelnetServer server(cli, scheduler, 5000);
// start event loop
scheduler.Run();
Release 2.0 – Boost Asio
#include <cli/boostasioscheduler.h>
#include <cli/boostasioremotecli.h>
...
BoostAsioScheduler scheduler;
// setup local session
CliLocalTerminalSession localSession(cli, scheduler, std::cout, 200);
// setup server
BoostAsioCliTelnetServer server(cli, scheduler, 5000);
// start event loop
scheduler.Run();
Release 2.0 – No Asio
#include <cli/loopscheduler.h>
...
LoopScheduler scheduler;
// setup local session
CliLocalTerminalSession localSession(cli, scheduler, std::cout, 200);
// start event loop
scheduler.Run();
Conclusions
Miles to go…
• User-defined arguments (and completion for them)
• More (bash-like) shortcuts
• Conan support
• Rename the library (?)
Library core: design decisions
• Reflection (?)
• Preprocessors (???)
• "Composite" Design Pattern VS Template metaprogramming
Intentional architecture VS emergent design
"Many times, thinking things out in advance saved us serious development headaches later on. ... [on
making a particular specification change] ... Making this change in the spec took an hour or two. If we
had made this change in code, it would have added weeks to the schedule. I can’t tell you how
strongly I believe in Big Design Up Front, which the proponents of Extreme Programming consider
anathema. I have consistently saved time and made better products by using BDUF and I’m proud to
use it, no matter what the XP fanatics claim. They’re just wrong on this point and I can’t be any clearer
than that."
-- Joel Spolsky "The project Aardwark Spec" – Joel On Software
Take away
• Use the right technique
• Use Cli library  (when you need it)
• Use Proactor pattern (when you need it)
• Use your brain (always)
References
Me: daniele.pallastrelli@gmail.com
Me: @DPallastrelli
Github: http://github.com/daniele77
Web: daniele77.github.io
63

More Related Content

What's hot

Parsing
ParsingParsing
Blazing Performance with Flame Graphs
Blazing Performance with Flame GraphsBlazing Performance with Flame Graphs
Blazing Performance with Flame Graphs
Brendan Gregg
 
Templates in C++
Templates in C++Templates in C++
Templates in C++
Tech_MX
 
What's new in Scala 2.13?
What's new in Scala 2.13?What's new in Scala 2.13?
What's new in Scala 2.13?
Hermann Hueck
 
Instruction Set Architecture: MIPS
Instruction Set Architecture: MIPSInstruction Set Architecture: MIPS
Instruction Set Architecture: MIPS
Prasenjit Dey
 
OpenCL Programming 101
OpenCL Programming 101OpenCL Programming 101
OpenCL Programming 101
Yoss Cohen
 
Functions in C++
Functions in C++Functions in C++
Functions in C++
Sachin Sharma
 
Interfacing With High Level Programming Language
Interfacing With High Level Programming Language Interfacing With High Level Programming Language
Interfacing With High Level Programming Language
.AIR UNIVERSITY ISLAMABAD
 
cs8251 unit 1 ppt
cs8251 unit 1 pptcs8251 unit 1 ppt
cs8251 unit 1 ppt
praveenaprakasam
 
C++ concept of Polymorphism
C++ concept of  PolymorphismC++ concept of  Polymorphism
C++ concept of Polymorphism
kiran Patel
 
Timer
TimerTimer
Polymorphism in c++(ppt)
Polymorphism in c++(ppt)Polymorphism in c++(ppt)
Polymorphism in c++(ppt)
Sanjit Shaw
 
C/C++ History in few slides
C/C++ History in few slides C/C++ History in few slides
What is to loop in c++
What is to loop in c++What is to loop in c++
What is to loop in c++
03446940736
 
2.5 ambiguity in context free grammars
2.5 ambiguity in context free grammars2.5 ambiguity in context free grammars
2.5 ambiguity in context free grammars
Sampath Kumar S
 
Unit1 principle of programming language
Unit1 principle of programming languageUnit1 principle of programming language
Unit1 principle of programming language
Vasavi College of Engg
 
The Internals of "Hello World" Program
The Internals of "Hello World" ProgramThe Internals of "Hello World" Program
The Internals of "Hello World" Program
National Cheng Kung University
 
Debugging linux kernel tools and techniques
Debugging linux kernel tools and  techniquesDebugging linux kernel tools and  techniques
Debugging linux kernel tools and techniques
Satpal Parmar
 
11 constructors in derived classes
11 constructors in derived classes11 constructors in derived classes
11 constructors in derived classes
Docent Education
 
Virtual base class
Virtual base classVirtual base class
Virtual base class
Tech_MX
 

What's hot (20)

Parsing
ParsingParsing
Parsing
 
Blazing Performance with Flame Graphs
Blazing Performance with Flame GraphsBlazing Performance with Flame Graphs
Blazing Performance with Flame Graphs
 
Templates in C++
Templates in C++Templates in C++
Templates in C++
 
What's new in Scala 2.13?
What's new in Scala 2.13?What's new in Scala 2.13?
What's new in Scala 2.13?
 
Instruction Set Architecture: MIPS
Instruction Set Architecture: MIPSInstruction Set Architecture: MIPS
Instruction Set Architecture: MIPS
 
OpenCL Programming 101
OpenCL Programming 101OpenCL Programming 101
OpenCL Programming 101
 
Functions in C++
Functions in C++Functions in C++
Functions in C++
 
Interfacing With High Level Programming Language
Interfacing With High Level Programming Language Interfacing With High Level Programming Language
Interfacing With High Level Programming Language
 
cs8251 unit 1 ppt
cs8251 unit 1 pptcs8251 unit 1 ppt
cs8251 unit 1 ppt
 
C++ concept of Polymorphism
C++ concept of  PolymorphismC++ concept of  Polymorphism
C++ concept of Polymorphism
 
Timer
TimerTimer
Timer
 
Polymorphism in c++(ppt)
Polymorphism in c++(ppt)Polymorphism in c++(ppt)
Polymorphism in c++(ppt)
 
C/C++ History in few slides
C/C++ History in few slides C/C++ History in few slides
C/C++ History in few slides
 
What is to loop in c++
What is to loop in c++What is to loop in c++
What is to loop in c++
 
2.5 ambiguity in context free grammars
2.5 ambiguity in context free grammars2.5 ambiguity in context free grammars
2.5 ambiguity in context free grammars
 
Unit1 principle of programming language
Unit1 principle of programming languageUnit1 principle of programming language
Unit1 principle of programming language
 
The Internals of "Hello World" Program
The Internals of "Hello World" ProgramThe Internals of "Hello World" Program
The Internals of "Hello World" Program
 
Debugging linux kernel tools and techniques
Debugging linux kernel tools and  techniquesDebugging linux kernel tools and  techniques
Debugging linux kernel tools and techniques
 
11 constructors in derived classes
11 constructors in derived classes11 constructors in derived classes
11 constructors in derived classes
 
Virtual base class
Virtual base classVirtual base class
Virtual base class
 

Similar to Add an interactive command line to your C++ application

2 BytesC++ course_2014_c3_ function basics&parameters and overloading
2 BytesC++ course_2014_c3_ function basics&parameters and overloading2 BytesC++ course_2014_c3_ function basics&parameters and overloading
2 BytesC++ course_2014_c3_ function basics&parameters and overloading
kinan keshkeh
 
Getting started cpp full
Getting started cpp   fullGetting started cpp   full
Getting started cpp full
Võ Hòa
 
Introduction to typescript
Introduction to typescriptIntroduction to typescript
Introduction to typescript
Mario Alexandro Santini
 
Hands on Session on Python
Hands on Session on PythonHands on Session on Python
Hands on Session on Python
Sumit Raj
 
Modern C++ Concurrency API
Modern C++ Concurrency APIModern C++ Concurrency API
Modern C++ Concurrency API
Seok-joon Yun
 
System Calls.pptxnsjsnssbhsbbebdbdbshshsbshsbbs
System Calls.pptxnsjsnssbhsbbebdbdbshshsbshsbbsSystem Calls.pptxnsjsnssbhsbbebdbdbshshsbshsbbs
System Calls.pptxnsjsnssbhsbbebdbdbshshsbshsbbs
ashukiller7
 
Степан Кольцов — Rust — лучше, чем C++
Степан Кольцов — Rust — лучше, чем C++Степан Кольцов — Rust — лучше, чем C++
Степан Кольцов — Rust — лучше, чем C++
Yandex
 
Developer Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duoDeveloper Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duo
The Software House
 
C++11
C++11C++11
Summary of C++17 features
Summary of C++17 featuresSummary of C++17 features
Summary of C++17 features
Bartlomiej Filipek
 
The Challenge of Bringing FEZ to PlayStation Platforms
The Challenge of Bringing FEZ to PlayStation PlatformsThe Challenge of Bringing FEZ to PlayStation Platforms
The Challenge of Bringing FEZ to PlayStation Platforms
Miguel Angel Horna
 
TechTalk - Dotnet
TechTalk - DotnetTechTalk - Dotnet
TechTalk - Dotnet
heinrich.wendel
 
CP 04.pptx
CP 04.pptxCP 04.pptx
CP 04.pptx
RehmanRasheed3
 
Fantom - Programming Language for JVM, CLR, and Javascript
Fantom - Programming Language for JVM, CLR, and JavascriptFantom - Programming Language for JVM, CLR, and Javascript
Fantom - Programming Language for JVM, CLR, and Javascript
Kamil Toman
 
Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Rust: код может быть одновременно безопасным и быстрым, Степан КольцовRust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Yandex
 
New Functional Features of Java 8
New Functional Features of Java 8New Functional Features of Java 8
New Functional Features of Java 8
franciscoortin
 
Function
FunctionFunction
Function
yash patel
 
Oop object oriented programing topics
Oop object oriented programing topicsOop object oriented programing topics
Oop object oriented programing topics
(•̮̮̃•̃) Prince Do Not Work
 
please help finish sorting methods- import java-util-Arrays- import ja.pdf
please help finish sorting methods- import java-util-Arrays- import ja.pdfplease help finish sorting methods- import java-util-Arrays- import ja.pdf
please help finish sorting methods- import java-util-Arrays- import ja.pdf
anfenterprises
 
PyCon 2010 SQLAlchemy tutorial
PyCon 2010 SQLAlchemy tutorialPyCon 2010 SQLAlchemy tutorial
PyCon 2010 SQLAlchemy tutorial
jbellis
 

Similar to Add an interactive command line to your C++ application (20)

2 BytesC++ course_2014_c3_ function basics&parameters and overloading
2 BytesC++ course_2014_c3_ function basics&parameters and overloading2 BytesC++ course_2014_c3_ function basics&parameters and overloading
2 BytesC++ course_2014_c3_ function basics&parameters and overloading
 
Getting started cpp full
Getting started cpp   fullGetting started cpp   full
Getting started cpp full
 
Introduction to typescript
Introduction to typescriptIntroduction to typescript
Introduction to typescript
 
Hands on Session on Python
Hands on Session on PythonHands on Session on Python
Hands on Session on Python
 
Modern C++ Concurrency API
Modern C++ Concurrency APIModern C++ Concurrency API
Modern C++ Concurrency API
 
System Calls.pptxnsjsnssbhsbbebdbdbshshsbshsbbs
System Calls.pptxnsjsnssbhsbbebdbdbshshsbshsbbsSystem Calls.pptxnsjsnssbhsbbebdbdbshshsbshsbbs
System Calls.pptxnsjsnssbhsbbebdbdbshshsbshsbbs
 
Степан Кольцов — Rust — лучше, чем C++
Степан Кольцов — Rust — лучше, чем C++Степан Кольцов — Rust — лучше, чем C++
Степан Кольцов — Rust — лучше, чем C++
 
Developer Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duoDeveloper Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duo
 
C++11
C++11C++11
C++11
 
Summary of C++17 features
Summary of C++17 featuresSummary of C++17 features
Summary of C++17 features
 
The Challenge of Bringing FEZ to PlayStation Platforms
The Challenge of Bringing FEZ to PlayStation PlatformsThe Challenge of Bringing FEZ to PlayStation Platforms
The Challenge of Bringing FEZ to PlayStation Platforms
 
TechTalk - Dotnet
TechTalk - DotnetTechTalk - Dotnet
TechTalk - Dotnet
 
CP 04.pptx
CP 04.pptxCP 04.pptx
CP 04.pptx
 
Fantom - Programming Language for JVM, CLR, and Javascript
Fantom - Programming Language for JVM, CLR, and JavascriptFantom - Programming Language for JVM, CLR, and Javascript
Fantom - Programming Language for JVM, CLR, and Javascript
 
Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Rust: код может быть одновременно безопасным и быстрым, Степан КольцовRust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов
 
New Functional Features of Java 8
New Functional Features of Java 8New Functional Features of Java 8
New Functional Features of Java 8
 
Function
FunctionFunction
Function
 
Oop object oriented programing topics
Oop object oriented programing topicsOop object oriented programing topics
Oop object oriented programing topics
 
please help finish sorting methods- import java-util-Arrays- import ja.pdf
please help finish sorting methods- import java-util-Arrays- import ja.pdfplease help finish sorting methods- import java-util-Arrays- import ja.pdf
please help finish sorting methods- import java-util-Arrays- import ja.pdf
 
PyCon 2010 SQLAlchemy tutorial
PyCon 2010 SQLAlchemy tutorialPyCon 2010 SQLAlchemy tutorial
PyCon 2010 SQLAlchemy tutorial
 

Recently uploaded

Maximizing Efficiency and Profitability: Optimizing Data Systems, Enhancing C...
Maximizing Efficiency and Profitability: Optimizing Data Systems, Enhancing C...Maximizing Efficiency and Profitability: Optimizing Data Systems, Enhancing C...
Maximizing Efficiency and Profitability: Optimizing Data Systems, Enhancing C...
OnePlan Solutions
 
GT degree offer diploma Transcript
GT degree offer diploma TranscriptGT degree offer diploma Transcript
GT degree offer diploma Transcript
attueb
 
當測試開始左移
當測試開始左移當測試開始左移
當測試開始左移
Jersey (CHE-PING) Su
 
Agra Girls Call Agra 0X0000000X Unlimited Short Providing Girls Service Avail...
Agra Girls Call Agra 0X0000000X Unlimited Short Providing Girls Service Avail...Agra Girls Call Agra 0X0000000X Unlimited Short Providing Girls Service Avail...
Agra Girls Call Agra 0X0000000X Unlimited Short Providing Girls Service Avail...
rachitkumar09887
 
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in CityGirls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
neshakor5152
 
Wired_2.0_Create_AmsterdamJUG_09072024.pptx
Wired_2.0_Create_AmsterdamJUG_09072024.pptxWired_2.0_Create_AmsterdamJUG_09072024.pptx
Wired_2.0_Create_AmsterdamJUG_09072024.pptx
SimonedeGijt
 
Cisco Live Announcements: New ThousandEyes Release Highlights - July 2024
Cisco Live Announcements: New ThousandEyes Release Highlights - July 2024Cisco Live Announcements: New ThousandEyes Release Highlights - July 2024
Cisco Live Announcements: New ThousandEyes Release Highlights - July 2024
ThousandEyes
 
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docxComprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
Aardwolf Security
 
Attendance Tracking From Paper To Digital
Attendance Tracking From Paper To DigitalAttendance Tracking From Paper To Digital
Attendance Tracking From Paper To Digital
Task Tracker
 
ENISA Threat Landscape 2023 documentation
ENISA Threat Landscape 2023 documentationENISA Threat Landscape 2023 documentation
ENISA Threat Landscape 2023 documentation
sofiafernandezon
 
AWS DevOps-Tutorial CHANAKYA SRIYAN DUKKA.
AWS DevOps-Tutorial CHANAKYA SRIYAN DUKKA.AWS DevOps-Tutorial CHANAKYA SRIYAN DUKKA.
AWS DevOps-Tutorial CHANAKYA SRIYAN DUKKA.
Srinivas Dukka
 
welcome to presentation on Google Apps
welcome to   presentation on Google Appswelcome to   presentation on Google Apps
welcome to presentation on Google Apps
AsifKarimJim
 
Building infrastructure with code_ A deep dive into CDK for IaC in Java.pdf
Building infrastructure with code_ A deep dive into CDK for IaC in Java.pdfBuilding infrastructure with code_ A deep dive into CDK for IaC in Java.pdf
Building infrastructure with code_ A deep dive into CDK for IaC in Java.pdf
mohitd6
 
IoT In Manufacturing_ Use Cases, Benefits, and Challenges.pdf
IoT In Manufacturing_ Use Cases, Benefits, and Challenges.pdfIoT In Manufacturing_ Use Cases, Benefits, and Challenges.pdf
IoT In Manufacturing_ Use Cases, Benefits, and Challenges.pdf
mohitd6
 
Il Data Streaming per un’AI real-time di nuova generazione
Il Data Streaming per un’AI real-time di nuova generazioneIl Data Streaming per un’AI real-time di nuova generazione
Il Data Streaming per un’AI real-time di nuova generazione
confluent
 
Google ML-Kit - Understanding on-device machine learning
Google ML-Kit - Understanding on-device machine learningGoogle ML-Kit - Understanding on-device machine learning
Google ML-Kit - Understanding on-device machine learning
VishrutGoyani1
 
Odoo E-commerce website development guides
Odoo E-commerce website development guidesOdoo E-commerce website development guides
Odoo E-commerce website development guides
jhkdigitalmarketing
 
Prada Group Reports Strong Growth in First Quarter …
Prada Group Reports Strong Growth in First Quarter …Prada Group Reports Strong Growth in First Quarter …
Prada Group Reports Strong Growth in First Quarter …
908dutch
 
ERP Software Solutions Provider in Coimbatore
ERP Software Solutions Provider in CoimbatoreERP Software Solutions Provider in Coimbatore
ERP Software Solutions Provider in Coimbatore
Nextskill Technologies
 
Install Ruby on Rails Like a Pro: Effortless Guide
Install Ruby on Rails Like a Pro: Effortless GuideInstall Ruby on Rails Like a Pro: Effortless Guide
Install Ruby on Rails Like a Pro: Effortless Guide
rorbitssoftware
 

Recently uploaded (20)

Maximizing Efficiency and Profitability: Optimizing Data Systems, Enhancing C...
Maximizing Efficiency and Profitability: Optimizing Data Systems, Enhancing C...Maximizing Efficiency and Profitability: Optimizing Data Systems, Enhancing C...
Maximizing Efficiency and Profitability: Optimizing Data Systems, Enhancing C...
 
GT degree offer diploma Transcript
GT degree offer diploma TranscriptGT degree offer diploma Transcript
GT degree offer diploma Transcript
 
當測試開始左移
當測試開始左移當測試開始左移
當測試開始左移
 
Agra Girls Call Agra 0X0000000X Unlimited Short Providing Girls Service Avail...
Agra Girls Call Agra 0X0000000X Unlimited Short Providing Girls Service Avail...Agra Girls Call Agra 0X0000000X Unlimited Short Providing Girls Service Avail...
Agra Girls Call Agra 0X0000000X Unlimited Short Providing Girls Service Avail...
 
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in CityGirls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
 
Wired_2.0_Create_AmsterdamJUG_09072024.pptx
Wired_2.0_Create_AmsterdamJUG_09072024.pptxWired_2.0_Create_AmsterdamJUG_09072024.pptx
Wired_2.0_Create_AmsterdamJUG_09072024.pptx
 
Cisco Live Announcements: New ThousandEyes Release Highlights - July 2024
Cisco Live Announcements: New ThousandEyes Release Highlights - July 2024Cisco Live Announcements: New ThousandEyes Release Highlights - July 2024
Cisco Live Announcements: New ThousandEyes Release Highlights - July 2024
 
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docxComprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
 
Attendance Tracking From Paper To Digital
Attendance Tracking From Paper To DigitalAttendance Tracking From Paper To Digital
Attendance Tracking From Paper To Digital
 
ENISA Threat Landscape 2023 documentation
ENISA Threat Landscape 2023 documentationENISA Threat Landscape 2023 documentation
ENISA Threat Landscape 2023 documentation
 
AWS DevOps-Tutorial CHANAKYA SRIYAN DUKKA.
AWS DevOps-Tutorial CHANAKYA SRIYAN DUKKA.AWS DevOps-Tutorial CHANAKYA SRIYAN DUKKA.
AWS DevOps-Tutorial CHANAKYA SRIYAN DUKKA.
 
welcome to presentation on Google Apps
welcome to   presentation on Google Appswelcome to   presentation on Google Apps
welcome to presentation on Google Apps
 
Building infrastructure with code_ A deep dive into CDK for IaC in Java.pdf
Building infrastructure with code_ A deep dive into CDK for IaC in Java.pdfBuilding infrastructure with code_ A deep dive into CDK for IaC in Java.pdf
Building infrastructure with code_ A deep dive into CDK for IaC in Java.pdf
 
IoT In Manufacturing_ Use Cases, Benefits, and Challenges.pdf
IoT In Manufacturing_ Use Cases, Benefits, and Challenges.pdfIoT In Manufacturing_ Use Cases, Benefits, and Challenges.pdf
IoT In Manufacturing_ Use Cases, Benefits, and Challenges.pdf
 
Il Data Streaming per un’AI real-time di nuova generazione
Il Data Streaming per un’AI real-time di nuova generazioneIl Data Streaming per un’AI real-time di nuova generazione
Il Data Streaming per un’AI real-time di nuova generazione
 
Google ML-Kit - Understanding on-device machine learning
Google ML-Kit - Understanding on-device machine learningGoogle ML-Kit - Understanding on-device machine learning
Google ML-Kit - Understanding on-device machine learning
 
Odoo E-commerce website development guides
Odoo E-commerce website development guidesOdoo E-commerce website development guides
Odoo E-commerce website development guides
 
Prada Group Reports Strong Growth in First Quarter …
Prada Group Reports Strong Growth in First Quarter …Prada Group Reports Strong Growth in First Quarter …
Prada Group Reports Strong Growth in First Quarter …
 
ERP Software Solutions Provider in Coimbatore
ERP Software Solutions Provider in CoimbatoreERP Software Solutions Provider in Coimbatore
ERP Software Solutions Provider in Coimbatore
 
Install Ruby on Rails Like a Pro: Effortless Guide
Install Ruby on Rails Like a Pro: Effortless GuideInstall Ruby on Rails Like a Pro: Effortless Guide
Install Ruby on Rails Like a Pro: Effortless Guide
 

Add an interactive command line to your C++ application

  • 1. Add an interactive command line to your applications Daniele Pallastrelli, daniele77.github.io 13.01.2022, Italian C++
  • 2. My typical projects • Run for a long period of time • No classic interaction with the user (i.e., no GUI) • Run in a server, custom board, almost never desktop applications • They're not CPU bound applications
  • 3. Why an interactive console in your apps? • Need to have some sort of console to interact with my applications (e.g., embedded systems running around the clock) to: • monitor, • configure, • manage the system • E.g., CISCO routers • Traditional systems: SSH connections + logs
  • 4. Why an interactive console in your apps? • Debugging • Poke around internal state • Dump internal structures • Change the log level at runtime • Change the working mode • Enable / disable modules • Load / unload plugins • Early stage of development
  • 5. Reinventing the wheel? Existing solutions in open source domain: • Linux only • They're applications where you hook external programs to commands • No remote sessions • Few in C++ • None of them in "modern" C++
  • 6. Enter the shell (cli?) • My own library in C++14 • Production code quality • Used in several industrial projects • Demo time  • C++14 • Cross-platform (Linux and windows tested) • Menus and submenus • Command history (navigation with arrow keys) • Autocompletion (with TAB key) • Async interface • Colors
  • 7. Something missing… • Good when you start the app from a console (e.g. desktop applications or development stage) • What about processes that run in background (e.g., embedded, servers & c)?
  • 12. Features summary • C++14 • Header only • Cross-platform (linux and windows) • Menus and submenus • Remote sessions (telnet) • Persistent history (navigation with arrow keys) • Autocompletion (with TAB key) • Async interface • Colors
  • 13. auto rootMenu = make_unique<Menu>("cli"); rootMenu->Insert( "hello", [](std::ostream& out){ out << "Hello, worldn"; }, "Print hello world" ); rootMenu->Insert( "hello_everysession", [](std::ostream&){ Cli::cout() << "Hello, everybody" << std::endl; }, "Print hello everybody on all open sessions" ); rootMenu->Insert( "reverse", {"string_to_revert"}, [](std::ostream& out, const string& arg) { string copy(arg); std::reverse(copy.begin(), copy.end()); out << copy << "n"; }, "Print the reverse string" );
  • 14. rootMenu->Insert( "add", {"first_term", "second_term"}, [](std::ostream& out, int x, int y) { out << x << " + " << y << " = " << (x+y) << "n"; }, "Print the sum of the two numbers" ); rootMenu->Insert( "sort", {"list of strings separated by space"}, [](std::ostream& out, std::vector<std::string> data) { std::sort(data.begin(), data.end()); out << "sorted list: "; std::copy(data.begin(), data.end(), std::ostream_iterator<std::string>(out, " ")); out << "n"; }, "Alphabetically sort a list of words" );
  • 15. auto subMenu = make_unique<Menu>("sub"); subMenu->Insert( "demo", [](std::ostream& out){ out << "This is a sample!n"; }, "Print a demo string" ); rootMenu->Insert( std::move(subMenu) );
  • 16. // create a cli with the given root menu and a persistent storage Cli cli( std::move(rootMenu), std::make_unique<FileHistoryStorage>(".cli") ); // global exit action cli.ExitAction( [](auto& out){ out << "Goodbye and thanks for all the fish.n"; } ); // std exception custom handler cli.StdExceptionHandler( [](std::ostream& out, const std::string& cmd, const std::exception& e) { out << "Exception caught in cli handler: " << e.what() << " handling command: " << cmd << ".n"; } );
  • 17. LoopScheduler scheduler; CliLocalTerminalSession localSession(cli, scheduler, std::cout, 200); localSession.ExitAction( [&scheduler](auto& out) // session exit action { out << "Closing App...n"; scheduler.Stop(); } ); scheduler.Run();
  • 18. StandaloneAsioScheduler scheduler; CliLocalTerminalSession localSession(cli, scheduler, std::cout, 200); localSession.ExitAction( [&scheduler](auto& out) // session exit action { out << "Closing App...n"; scheduler.Stop(); } ); // setup server StandaloneAsioCliTelnetServer server(cli, scheduler, 5000); // exit action for all the connections server.ExitAction( [](auto& out) { out << "Terminating this session...n"; } ); scheduler.Run();
  • 19. How does it work
  • 20. Core idea • Command list • The user enters a string: command and parameters • Iteration over the command list: • Command name • Parameter number and type • The handler is called with the typed parameters
  • 22. class Command {}; class Menu : public Command { private: Menu* parent{ nullptr }; std::vector<Command*> cmds; }; template <typename F, typename ... Args> class VariadicFunctionCommand : public Command {};
  • 23. Menu is-a Command, because when you start the CLI, every Menu shows as a command you can digit at the prompt (e.g., if you define a Menu "foo", you get the command "foo" in the Cli to enter the submenu).
  • 24. auto rootMenu = make_unique<Menu>("cli"); rootMenu->Insert( "hello", [](std::ostream& out) { out << "Hello, worldn"; } ); rootMenu->Insert( "hello_everysession", [](std::ostream&) { Cli::cout() << "Hello, everybodyn"; } );
  • 25. auto subMenu = make_unique<Menu>("sub"); subMenu->Insert( "hello", [](std::ostream& out) { out << "Hello, submenu worldn"; } ); subMenu->Insert( "demo", [](std::ostream&) { out << "Demon"; } ); rootMenu->Insert( std::move(subMenu) );
  • 26. auto rootMenu = make_unique<Menu>("cli"); ... Cli cli( std::move(rootMenu) );
  • 27. auto rootMenu = make_unique<Menu>("cli"); ... Cli cli( std::move(rootMenu) ); CliLocalTerminalSession localSession(cli, scheduler, std::cout, 200); CliTelnetServer server(cli, scheduler, 5000);
  • 28. Cli cli( std::move(rootMenu) ); CliLocalTerminalSession localSession(cli, scheduler, std::cout, 200); CliTelnetServer server(cli, scheduler, 5000); CliFileSession fileSession(cli, infile, outfile); CliLocalTerminalSession localSession( scheduler, std::cout, 200); CliTelnetServer server(scheduler, 5000); CliFileSession fileSession(infile, outfile); Cli cli( std::move(rootMenu) ); cli.SetLocalSession( localSession ); cli.SetFileSession( fileSession ); cli.SetTelnetServer( server );
  • 30. rootMenu->Insert( "add", {"first_term", "second_term"}, [](std::ostream& out, int x, int y) { out << x << " + " << y << " = " << (x+y) << "n"; }, "Print the sum of two numbers" );
  • 31. rootMenu->Insert( "add", {"first_term", "second_term"}, [](std::ostream& out, int x, int y) { out << x << " + " << y << " = " << (x+y) << "n"; }, "Print the sum of two numbers" );
  • 32. Interlude – How do you get the type of a lambda argument? template <typename F> void foo(F f) { // what's the type of "f" first parameter? // something like: // using T = F::first_parameter_type ) foo( [](int){} );
  • 33. Interlude – How do you get the type of a lambda argument? template<typename F, typename Ret, typename A, typename... Rest> A helper(Ret (F::*)(A, Rest...) const); template <typename F> void foo(F f) { using T = decltype( helper(&F::operator()) ); } foo( [](int){} );
  • 34. class Menu : public Command { public: template <typename F> CmdHandler Insert(const string& cmdName, F f) { return CreateCmd(cmdName, f, &F::operator()); } private: template <typename F, typename R, typename ... Args> CmdHandler CreateCmd(const string& cmdName, F& f, R (F::*)(Args...) const) { auto cmd = make_unique< VariadicFunctionCommand< F, Args ... > >(cmdName, f); // insert cmd into this menu commands ... } }; Works with lambdas and std::function
  • 35. class Menu : public Command { public: ... template <typename R, typename ... Args> CmdHandler Insert(const std::string& cmdName, R (*f)(Args...)) { using F = R (*)(Args...); auto cmd = make_unique<VariadicFunctionCommand<F, Args ...>>(cmdName, f); // insert cmd into this menu commands ... } ... }; Overload for free- functions
  • 36. template <typename F, typename ... Args> class VariadicFunctionCommand : public Command { public: VariadicFunctionCommand(const std::string& _name, F fun) : Command(_name), func(std::move(fun)) {} bool Exec(const vector<string>& cmdLine) override { ... try { Select<Args...>::Exec(func, std::next(cmdLine.begin()), cmdLine.end()); } catch (std::bad_cast&) { return false; } return true; ... } };
  • 37. template <typename ... Args> struct Select; template <typename P, typename ... Args> struct Select<P, Args...> { template <typename F, typename InputIt> static void Exec(const F& f, InputIt first, InputIt last) { assert( first != last ); assert( std::distance(first, last) == 1+sizeof...(Args) ); const P firstPar = detail::from_string<typename std::decay<P>::type>(*first); auto g = [&](auto ... pars){ f(firstPar, pars...); }; Select<Args...>::Exec(g, std::next(first), last); } }; template <> struct Select<> { template <typename F, typename InputIt> static void Exec(const F& f, InputIt first, InputIt last) { assert(first == last); f(); } };
  • 38. Interlude How do you manage concurrency?
  • 39. Concurrency in my projects • Single thread (when possible), using Proactor pattern. • When I must: multiple threads, using Proactor pattern 
  • 40. By the way… …what's the PROACTOR pattern?
  • 41. The proactor pattern: Concurrency Without Threads
  • 42. The Proactor solution Split every application service into: • Long-duration operations. execute asynchronously • Completion handlers. processes the results of the associated asynchronous operations (potentially invoking additional asynchronous operations).
  • 48. Concurrency in my projects • asio for asynchonous I/O (timers, too) • asio::io_context available • When I/O is ready, asio puts handler in the asio::io_context • If more threads are needed (e.g., time consuming computations or blocking I/O), the result is put in asio::io_context • => everything runs in (my) single thread of execution
  • 49. Back to the library  • Input coming from: • Keyboard, using blocking primitives (std::getchar() and _getch()) • Sockets • Commands callbacks (in which thread?) • => proactor (asio::io_context)
  • 50. Consequences • The user must instantiate a boost::asio::io_context object • The whole library depends on boost::asio
  • 51. Concurrency summary (v. 1.0) • The library depends on boost::asio, even when you don't need the telnet server • Library users ask to use standalone asio instead of boost::asio • The truth is that the whole library depends on boost::asio because: • Telnet server needs it • Keyboard handler needs an event handler • The two must use the same event manager, i.e. boost::asio::io_context
  • 52. Release 2.0 – Goals: • Optionally use standalone asio instead of boost::asio for the telnet server • Remove all dependencies if the telnet server is not needed
  • 53. Release 2.0 – The solution • New abstraction: "Scheduler" • schedules async event • The library provides three kind of schedulers: • StandaloneAsioScheduler (based on asio::io_context) • BoostAsioScheduler (based on boost::asio::io_context) • LoopScheduler (hand made sync queue)
  • 54. Release 2.0 – The solution • Cli library can use all the schedulers, but if you need the telnet server you must use *AsioScheduler • Bottom line: • If ( you need telnet server OR your app already uses [boost::]asio::io_context => StandaloneAsioScheduler or BoostAsioScheduler • Else => LoopScheduler (no external dependencies)
  • 55. Release 2.0 – Standalone Asio #include <cli/standaloneasioscheduler.h> #include <cli/standaloneasioremotecli.h> ... StandaloneAsioScheduler scheduler; // setup local session CliLocalTerminalSession localSession(cli, scheduler, std::cout, 200); // setup server StandaloneAsioCliTelnetServer server(cli, scheduler, 5000); // start event loop scheduler.Run();
  • 56. Release 2.0 – Boost Asio #include <cli/boostasioscheduler.h> #include <cli/boostasioremotecli.h> ... BoostAsioScheduler scheduler; // setup local session CliLocalTerminalSession localSession(cli, scheduler, std::cout, 200); // setup server BoostAsioCliTelnetServer server(cli, scheduler, 5000); // start event loop scheduler.Run();
  • 57. Release 2.0 – No Asio #include <cli/loopscheduler.h> ... LoopScheduler scheduler; // setup local session CliLocalTerminalSession localSession(cli, scheduler, std::cout, 200); // start event loop scheduler.Run();
  • 59. Miles to go… • User-defined arguments (and completion for them) • More (bash-like) shortcuts • Conan support • Rename the library (?)
  • 60. Library core: design decisions • Reflection (?) • Preprocessors (???) • "Composite" Design Pattern VS Template metaprogramming
  • 61. Intentional architecture VS emergent design "Many times, thinking things out in advance saved us serious development headaches later on. ... [on making a particular specification change] ... Making this change in the spec took an hour or two. If we had made this change in code, it would have added weeks to the schedule. I can’t tell you how strongly I believe in Big Design Up Front, which the proponents of Extreme Programming consider anathema. I have consistently saved time and made better products by using BDUF and I’m proud to use it, no matter what the XP fanatics claim. They’re just wrong on this point and I can’t be any clearer than that." -- Joel Spolsky "The project Aardwark Spec" – Joel On Software
  • 62. Take away • Use the right technique • Use Cli library  (when you need it) • Use Proactor pattern (when you need it) • Use your brain (always)
  • 63. References Me: daniele.pallastrelli@gmail.com Me: @DPallastrelli Github: http://github.com/daniele77 Web: daniele77.github.io 63