Browse Source

implement basic CLI with command and option parser

Missingmew 4 years ago
parent
commit
4e915afdb8
2 changed files with 130 additions and 0 deletions
  1. 13 0
      cli/CMakeLists.txt
  2. 117 0
      cli/src/main.cpp

+ 13 - 0
cli/CMakeLists.txt

@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 2.8)
+
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
+project(ccats-cli)
+
+add_executable(ccats-cli src/main.cpp)
+
+find_package(Threads)
+find_package(Boost 1.67 REQUIRED COMPONENTS system program_options)
+
+include_directories(${Boost_INCLUDE_DIR})
+target_link_libraries(ccats-cli PRIVATE ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})

+ 117 - 0
cli/src/main.cpp

@@ -0,0 +1,117 @@
+#include <boost/program_options.hpp>
+#include <iostream>
+#include <cctype>
+
+#define COMMANDLEN 10
+#define sizeofarr(a) (sizeof(a) / sizeof(a[0]))
+
+namespace bpo = boost::program_options;
+
+typedef enum {
+	CMD_HELP,
+	CMD_CONNECT,
+	CMD_DISCONNECT,
+	CMD_PUT,
+	CMD_REMOVE,
+	CMD_GET,
+	CMD_QUERY,
+	CMD_SETUP,
+	CMD_LOG,
+	CMD_UNKNOWN
+} COMMANDTYPES;
+
+typedef struct {
+	COMMANDTYPES cmd;
+	const char *name;
+	const char *desc;
+} CMD;
+
+CMD commands[] {
+	{ CMD_HELP, "help", "show help" },
+	{ CMD_CONNECT, "connect", "connect to IP" },
+	{ CMD_DISCONNECT, "disconnect", "disconnect from IP" },
+	{ CMD_PUT, "put", "upload file to IP and add to queue" },
+	{ CMD_REMOVE, "remove", "remove file from IP and queue (stops xfer if required)" },
+	{ CMD_GET, "get", "retrieve file from IP" },
+	{ CMD_QUERY, "query", "query status of IP" },
+	{ CMD_SETUP, "setup", "configure server at IP" },
+	{ CMD_LOG, "log", "show log from IP" }
+};
+
+COMMANDTYPES getCommand(char *str, unsigned int isshort) {
+	COMMANDTYPES ret = CMD_UNKNOWN;
+	char temp[11] = {0};
+	if(strlen(str) > COMMANDLEN) return ret;
+	if(isshort) temp[0] = tolower(str[0]);
+	else for(int i = 0; i < 10; i++) temp[i] = tolower(str[i]);
+	
+	for(int i = 0; i < sizeofarr(commands); i++) {
+		if(isshort) {
+			if(tolower(str[0]) == commands[i].name[0]) ret = commands[i].cmd;
+		}
+		else {
+			if(!strncmp(temp, commands[i].name, COMMANDLEN)) ret = commands[i].cmd;
+		}
+	}
+	return ret;
+}
+
+void show_help(char *exec) {
+	printf("ccats command line interface\n");
+	printf("usage: %s COMMAND IP [Options]\n", exec);
+	printf("available COMMANDs are:\n");
+	for(int i = 0; i < sizeofarr(commands); i++) {
+		printf("%10s - %s\n", commands[i].name, commands[i].desc);
+	}
+	printf("IP should be in the format \"xxx.xxx.xxx.xxx\"\n");
+}
+
+int main(int argc, char **argv) {
+	bpo::options_description desc{"Options"};
+	desc.add_options()
+		("cooloption", "Cooloption to use with command FOON")
+	;
+	bpo::variables_map vm;
+	
+	if(argc < 2) {
+		show_help(argv[0]);
+		exit(1);
+	}
+	COMMANDTYPES cmd = getCommand(argv[1], (strlen(argv[1]) == 1));
+	switch(cmd) {
+		case CMD_UNKNOWN:
+			printf("unknown command\n");
+		case CMD_HELP:
+			show_help(argv[0]);
+			std::cout << desc;
+			exit(1);
+	}
+	
+	// have enough valid arguments
+	switch(cmd) {
+		case CMD_CONNECT:
+			printf("connecting to %s\n", argv[2]);
+			break;
+		case CMD_DISCONNECT:
+			printf("disconnecting from %s\n", argv[2]);
+			break;
+		default:
+			printf("command %s not implemented\n", argv[1]);
+			break;
+	}
+	
+	try {
+		store(parse_command_line(argc-2, argv+2, desc), vm);
+		notify(vm);
+		
+		if(vm.count("help")) {
+			std::cout << desc;
+		}
+		else {
+			printf("no additional options\n");
+		}
+	}
+	catch (const bpo::error &ex) {
+		fprintf(stderr, "%s\n", ex.what());
+	}
+}