Interactive console programming for c/c++?
The readline library is a common choice: http://www.gnu.org/s/readline
If you are more ambitious, ncurses gives you more control, but has less functionality to begin with and a steeper learning curve.
Edit:
icktoofay mentioned that readline is licensed under the GPL. If this is a problem for your software, tecla is an alternative licensed under an X11 style license, so it can be used in proprietary projects.
Creating an Interactive Prompt in C++
If the number of command is small and possible parameters are really few, you could keep on with switch case !
If the number of commands increases, consider the command design pattern (which is IMHO some sort of strategy pattern disguised: cf Using a strategy pattern and a command pattern for the differences between command and strategy patterns).
If most of your commands are all sharing a part of the same behaviour, don't forget the template method pattern.
If the complexity for creating your command objects increases ( i.e. there is complexity in decoding/understanding the input of your command line), you should start looking at the interpreter design pattern
If while designing with the help of the interpreter pattern, you happen to see some complexity ( if the interpreter needs too much work, you see syntax issues and so on ), then you should probably look at DSL, domain specific language, and design your own language that fits (and only fits) to you own inputs.
Dead-simple example of an interactive command-line application in c or objective-c?
Xcode 4 - Foundation Command Line Tool
- File > New > New Project
- Mac OS X > Application > Command Line Tool
- Choose Name
- Type > Foundation
- Next
- Create
- Open the
main.m
file - Paste the code below
- Hit run
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
@autoreleasepool {
int inputOne;
NSLog (@"Enter number: ");
scanf("%i", &inputOne);
int inputTwo;
NSLog (@"Enter another number: ");
scanf("%i", &inputTwo);
NSLog (@"%i + %i = %d", inputOne, inputTwo, inputOne + inputTwo);
}
return 0;
}
Note: In case the command line interface does not appear, hit the second button:
Now you can interact with the command line tool.
Cross platform, Interactive text-based interface with command completion
Update: I haven't found a satisfactory (cross-platform) solution to the history/completion option, so I've ignored that for the time being, but I wanted to update this question with how I've implemented a simple interactive class. This interface won't be for mainstream user's but I'm finding it very handy for testing my code during implementation. Below is the initial implementation that might help others out (note that this code references methods and types I have not published, so won't compile out of the box)
Interact.h:
#ifndef INTERACT_H
#define INTERACT_H
class Interact;
class InteractCommand;
typedef void (Interact::*PF_FUNC)(const InteractCommand &command, const StringVector &args);
struct InteractCommand
{
const char *command;
const char *argDesc;
const char *desc;
PF_FUNC func;
};
class Interact
{
private:
static Log m_log;
static InteractCommand m_commands[];
static unsigned m_numCommands;
bool m_stop;
Database &m_database;
StringVector &m_dirs;
public:
Interact(Database &database, StringVector &dirs);
~Interact();
/**
* Main 'interact' loop.
*
* @return true if the loop exitted normally, else false if an error occurred.
*/
bool interact();
private:
// Functions
#define DEFFUNC(f) void FUNC_##f(const InteractCommand &command, const StringVector &args)
DEFFUNC(database);
DEFFUNC(dirs);
DEFFUNC(exit);
DEFFUNC(help);
#undef DEFFUNC
/**
* Print usage information for the specified command.
*
* @param command The command to print usage for.
*/
static void usage(const InteractCommand &command);
static void describeCommand(string &dest, const InteractCommand &command);
};
#endif // INTERACT_H
Interact.cpp:
#include "Interact.h"
Log Interact::m_log("Interact");
#define IFUNC(f) &Interact::FUNC_##f
InteractCommand Interact::m_commands[] =
{
{ "database", "<file>|close", "Use database <file> or close opened database", IFUNC(database) },
{ "dirs", "dir[,dir...]", "Set the directories to scan", IFUNC(dirs) },
{ "exit", 0, "Exit", IFUNC(exit) },
{ "help", 0, "Print help", IFUNC(help) }
};
#undef IFUNC
unsigned Interact::m_numCommands = sizeof(m_commands) / sizeof(m_commands[0]);
Interact::Interact(MusicDatabase &database, StringVector &dirs) :
m_stop(false),
m_database(database),
m_dirs(dirs)
{
}
Interact::~Interact()
{
}
bool Interact::interact()
{
string line;
StringVector args;
unsigned i;
m_stop = false;
while (!m_stop)
{
args.clear();
cout << "> ";
if (!getline(cin, line) || cin.eof())
break;
else if (cin.fail())
return false;
if (!Util::splitString(line, " ", args) || args.size() == 0)
continue;
for (i = 0; i < m_numCommands; i++)
if (strncasecmp(args[0].c_str(), m_commands[i].command, args[0].length()) == 0)
break;
if (i < m_numCommands)
(this->*m_commands[i].func)(m_commands[i], args);
else
cout << "Unknown command '" << args[0] << "'" << endl;
}
return true;
}
void Interact::FUNC_database(const InteractCommand &command, const StringVector &args)
{
if (args.size() != 2)
{
usage(command);
return;
}
if (args[1] == "close")
{
if (m_database.opened())
m_database.close();
else
cout << "Database is not open" << endl;
}
else
{
if (!m_database.open(args[1]))
{
cout << "Failed to open database" << endl;
}
}
}
void Interact::FUNC_dirs(const InteractCommand &command, const StringVector &args)
{
if (args.size() == 1)
{
usage(command);
return;
}
// TODO
}
void Interact::FUNC_exit(const InteractCommand &command, const StringVector &args)
{
m_stop = true;
}
void Interact::FUNC_help(const InteractCommand &command, const StringVector &/*args*/)
{
string descr;
for (unsigned i = 0; i < m_numCommands; i++)
{
describeCommand(descr, m_commands[i]);
cout << descr << endl;
}
}
void Interact::usage(const InteractCommand &command)
{
string descr;
describeCommand(descr, command);
cout << "usage: " << endl;
cout << descr << endl;
}
void Interact::describeCommand(string &dest, const InteractCommand &command)
{
dest.clear();
string cmdStr = command.command;
if (command.argDesc != 0)
{
cmdStr += " ";
cmdStr += command.argDesc;
}
Util::format(dest, " %-30s%s", cmdStr.c_str(), command.desc);
}
C/C++ interactive interpreter
You've got cling, it's not perfect, but it's a c++ repl
http://blog.coldflake.com/posts/On-the-fly-C++/
git clone http://root.cern.ch/git/llvm.git src
cd src
git checkout cling-patches
cd tools
git clone http://root.cern.ch/git/cling.git
git clone http://root.cern.ch/git/clang.git
cd clang
git checkout cling-patches
cd ../..
./configure --enable-cxx11
make
sudo make install
$ cling -Wc++11-extensions -std=c++11
****************** CLING ******************
* Type C++ code and press enter to run it *
* Type .q to exit *
*******************************************
[cling]$ #include <arpa/inet.h>
[cling]$ htons(5294)
(uint16_t) 44564
[cling]$ printf("%04x\n", htons(5294))
input_line_5:2:2: error: use of undeclared identifier 'printf'
printf("%04x\n", htons(5294))
^
[cling]$ #include <stdio.h>
[cling]$ printf("%04x\n", htons(5294))
ae14
Writing a real interactive terminal program like vim, htop, ... in C/C++ without ncurses
I'm a bit confused. You speak of a “terminal application”,
like vim; terminal applications don't get mouse events, and don't
respond to the mouse.
If you're talking about real terminal applications, which run in anxterm
, the important thing to note is that many of the portability
issues concern the terminal, and not the OS. The terminal is controlled
by sending different escape sequences. Which ones do what depend on the terminal; the ANSI escape codes are now fairly widespread, however, see http://en.wikipedia.org/wiki/ANSI_escape_code. These are generally understood by xterm
, for example.
You may have to output an additional sequence at the start and at the end to enter and leave “full screen” mode; this is necessary for xterm
.
Finally, you'll have to do something special at the input/output level to ensure that your output driver doesn't add any characters (e.g. convert a simple LF into a CRLF), and ensure that input doesn't echo, is transparent, and returns immediately. Under Linux, this is done using ioctl
. (Again, don't forget to restore it when you finish.)
Is there an interactive shell for programming quick C# code snippets?
LINQPad is very neat for that:
LINQPad is more than a LINQ tool: it's an ergonomic C#/VB/F#
scratchpad that instantly executes any expression, statement block or
program with rich output formatting – the ultimate in dynamic
development. Put an end to those hundreds of Visual Studio Console
projects cluttering your source folder!
Related Topics
Why Do My Sfinae Expressions No Longer Work with Gcc 8.2
Performance of Std::Function Compared to Raw Function Pointer and Void* This
Can You Make a Computed Goto in C++
C++: How to Catch Mouse Clicks Wherever They Happen
Overloading Postfix and Prefix Operators
In C++, Is There a Difference Between "Throw" and "Throw Ex"
Unordered_Map Constructor Error (Equal_To Templated Function)
Raw Socket Promiscuous Mode Not Sniffing What I Write
What Are the Different Character Sets Used For
Partial Template Specialization Based on "Signed-Ness" of Integer Type
Modifying Reference Member from Const Member Function in C++
Is Gcc Considering Builtins of Non-Constant Expression Functions to Be Constant Expressions
How to Turn on Multi-Cpu/Core C++ Compiles in the Visual Studio Ide (2008)