Interactive Console Programming for C/C++

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

  1. File > New > New Project
  2. Mac OS X > Application > Command Line Tool
  3. Choose Name
  4. Type > Foundation
  5. Next
  6. Create
  7. Open the main.m file
  8. Paste the code below
  9. 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:

Screenshot

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 an
xterm, 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



Leave a reply



Submit