简体   繁体   中英

C++ command line interface

I'm currently designing a linux c++ application. It will be run from the command line, then once running I need to be able to issue commands to control its execution, ideally something like the following:

$ sudo ./myapplication
APP > 
APP > 
APP > //just pressing return
APP > openlog test1.txt //APP will now call the openlog function
APP >

I imagine this is a relatively simple task, but I have no idea what such an interface would be called in order to search for one. Does anybody know of a library or example that can perform this function? Or do I need to write my own using cout and cin? If so, would there be any preferred approach?

I recommend the GNU readline library for this. It takes care of the tedious work of getting lines of input, and allows the user to edit his line with backspace, left and right arrows, etc, and to recall older command using the up arrow and even search for older command using ^R, etc. Readline comes installed with typical unix-like distributions like linux, but if you don't have it, you can find it here .

Edit: Here is a minimal readline example:

#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>

int main(int argc, char ** argv)
{
    while(1)
    {
        char * line = readline("> ");
        if(!line) break;
        if(*line) add_history(line);
        /* Do something with the line here */
        free(line);
    }
}

The GNU readline library is great if you want full line-editing and history features, but if a simple prompt suffices (or if you don't want the GNU license), then you can do this with just the standard library:

#include <iostream>
#include <string>

void process(std::string const & line);

int main()
{
    for (std::string line; std::cout << "APP > " && std::getline(std::cin, line); )
    {
        if (!line.empty()) { process(line); }
    }

    std::cout << "Goodbye.\n";
}

I agree with Chris's comment that this will be harder in a language that isn't reflective. In C++, you'll need to explicitly map whatever you type to a specific function.

If you're going to roll your own, your general design should look something like this:

  • Read input line (most likely using cin.getline into a string)
  • Identify the first word and determine whether it maps to any function (eg you could use a simple switch statement, hash table, etc)
  • If it doesn't map to a function, post an error and reprint the prompt.
  • If it does map, you have to examine the other words in the line.
  • For each other word, you'll have to convert the string into whatever data type you want as the function parameters on a word-by-word basis (stringstreams will come in handy here).
  • Now you have to make sure that the parameters you supplied are legitimate for the function you've called. You can either pre-check them before calling the function, or check for errors inside the function.
  • Once you've verified your function name and parameters are correct (and of the right number) you can call the function.

In a reflective language, the first half of that is much simplified as you may be able to convert a string directly to a function name.

GNU readline is by far an excellent selection, as others have suggested. If licensing concerns would force you to rule it out, then you should then consider linenoise .

You will have to at least partially roll your own. GNU readline might be able to help slightly; check out http://en.wikipedia.org/wiki/GNU_readline for a short program that is the "skeleton" that achieves this and around which you can actually add code.

You should probably take a look at the readline library . It has a bit of a learning curve but it is still vastly easier than recreating a full CLI on your own. Check the licensing though since it might not be appropriate for your project.

A bit late, but whatever...

Just to let you know about the CLI toolkit project that had been specifically designed for this need: http://sourceforge.net/projects/aroyer-cli/

Be aware of the GPL license of GNU Readline. In the answers, folks have mentioned about GPL license of GNU readline. In this answer, I would like to emphasize on implications of GPL license - which new users/developers might overlook.

Text copied from https://en.wikipedia.org/wiki/GNU_Readline

Choice of the GPL as GNU Readline's license[edit] GNU Readline is notable for being a free software library which is licensed under the GNU General Public License (GPL) instead of the GNU Lesser General Public License (LGPL). Free software libraries are often licensed under the LGPL, for example, the GNU C Library, GNU gettext and FLTK.

A developer of an application who chooses to link to an LGPL licensed library when building a new application is required to have the LGPL licensed library which it uses remain under the LGPL when distributing the combined resulting application. The part of the combined application excluding the LGPL licensed library can remain under the original license.[1] This is in contrast to a developer choosing to use a GPL licensed library to create a new application, in which case the entire combined resulting application is required to be licensed under the GPL when distributed, to comply with section 5 of the GPL.[2][3]

Implications of GNU Readline's GPL license[edit] An important example of an application changing its licensing to comply with the copyleft conditions of GNU Readline is CLISP, an implementation of Common Lisp. Originally released in 1987, it changed to the GPL license in 1992,[4] after an email exchange between one of CLISP's original authors, Bruno Haible, and Richard Stallman, in which Stallman argued[5] that the linking of readline in CLISP meant that Haible was required to re-license CLISP under the GPL if he wished to distribute the implementation of CLISP which used readline.[6]

Alternative command line editing libraries which are permissively licensed can be used by software projects which want to implement command line editing functionality, but wish to remain under a permissive license. Typical among these is the BSD-licensed libedit. Some applications, such as MariaDB[7] or PHP[8], allow for the user to select at build time whether to link with GNU Readline or with libedit. Other command-line editing libraries serve a dual purpose: they have API's which align those of some main project and have compatible license terms. An example of this is the Haskeline library, which exposes a Haskell-compatible API to both the Glasgow Haskell Compiler[9] and to other Haskell projects which need line-editing services.[10]

Links to several such libraries are listed in the external links.

This library seems to do exactly what OP is asking for:

It's essentially a wrapper around the readline library, but parses/casts the arguments of your functions to their respective types:

shpp::service svc;
svc.provide_command("my_function", [](int arg1, string arg2) -> { /* Do Something */ });
shpp::shell sh(svc);
sh.start();

It works with both function pointers and lambdas.

您可以将应用程序编写为TCL或python应用程序,并将它们用作前端。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM