2011-01-13 8 views
5

テキストベースのインタラクティブインタフェースを提供するC++ライブラリを知っている人はいますか?アプリケーションの2つのバージョンを作成したいと思います。 GUIベースのプログラム(Mac CocoaとWindows MFC)だけでなく、コマンドラインやコンソールで対話的に実行されるアクションを実行するコンソールベースのプログラムです。どちらのバージョンも共通のC++バックエンドを共有します。クロスプラットフォーム、コマンド補完機能を備えたインタラクティブテキストベースインタフェース

コンソールベースのプログラムについては、同様の履歴機能をreadline(このアプリケーションはクローズソースには使用できません)にしたいと思います。

おそらくすでに利用可能なものがありますか?順不同

答えて

1

更新:歴史/補完オプションに満足できる(クロスプラットフォーム)ソリューションが見つかりませんでしたので、当面は無視していますが、この質問を実装方法シンプルなインタラクティブなクラスです。このインターフェースは、メインストリームのユーザーのためのものではありませんが、実装中に自分のコードをテストするのに非常に便利です。

#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.hです.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); 
} 
2

、(私はそれらのどれを使用しないてきた、)あなたが見ている必要がありますなしの場合

それらはあなたの想像を引きますが、他の可能性もありますし、おそらくそれが望ましいかもしれません。バックエンドをデーモンとして記述し、フロントエンドを任意の形式のプロセス間通信を介してバックエンドと通信するダムプログラムにする。フロントエンドをオープンソースとしてリリースできるので、問題なく、フロントエンド用のGPLライブラリを使用することができます。もちろん、これはフロントエンドとバックエンドの間の通信プロトコルを公開しますので、そのことで大丈夫でなければならず、他の人がフロントエンドにカスタマイズして、独自のものを作る必要性を感じる可能性があります。しかし、あなたの価値がとにかくバックエンドにあると仮定すれば、これは特別な問題を引き起こすべきではありません。また、それはプラスと見なされるかもしれません。明るいアイデアを持つ人は、あなたのソフトウェアの人気を高めてくれる新しい予期しない方法であなたのソフトウェアを使用することができます。

+0

多くの提案に感謝します。これらのライブラリはすべてUNIX/Linux専用であり、クロスプラットフォーム要件を満たしていないWindows用ではありません。現時点で私は自分の簡単なコマンドインタープリタを書いており、履歴/コマンドの完了の面を無視しています。これはおそらく私をしばらく幸せにするのに十分でしょう。 – trojanfoe

関連する問題