Cập nhật: Tôi chưa tìm thấy giải pháp thỏa đáng (đa nền tảng) cho tùy chọn lịch sử/hoàn thành, vì vậy tôi đã bỏ qua điều đó, nhưng tôi muốn cập nhật câu hỏi này với cách tôi đã triển khai một lớp tương tác đơn giản. Giao diện này sẽ không dành cho người dùng chính thống nhưng tôi thấy nó rất tiện dụng để kiểm tra mã của tôi trong khi triển khai. Dưới đây là việc thực hiện ban đầu mà có thể giúp đỡ người khác ra (lưu ý rằng mã này tham chiếu các phương pháp và các loại tôi đã không được công bố, như vậy sẽ không biên dịch ra khỏi hộp)
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
Tương tác .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);
}
Rất cám ơn các đề xuất. Tất cả các thư viện này chỉ dành cho UNIX/LINUX và không dành cho Windows, không đáp ứng yêu cầu đa nền tảng. Tại thời điểm này tôi đã viết trình thông dịch lệnh đơn giản của riêng mình và đã bỏ qua khía cạnh lịch sử/hoàn thành lệnh. TBH này có lẽ sẽ đủ để giữ cho tôi hạnh phúc trong một thời gian. – trojanfoe