# Simple command user interface for conditional logic

This is a command-line interface wrap for any application involving conditional logic. I have posted the source here on bitbucket.

Usage:

1. Myself using as a starting point for a time series processing application for weather data. The command line options allow to jump between a number of unrelated functions, and to populate objects of inputs manually. I can load data into apps memory via several methods, excel, csv, or populate manually, and then choose between which test to run, i.e. once a weather time series is loaded, I can choose via command-line whether to calculate standard deviation, means. In the posted code I have kept all the mechanisms / classes for doing this.
2. I think this will be helpful to people learning programming / school projects - it takes away a lot of work when normally starting from a blank file and having to add commonly used functions and interface
for invoking various functions

Any feedback on the layout of the code would be appreciated, but in particular:

1. How files are structured
2. Structure of the Settings singleton and the cli namespace which contains functions to process command-based input from user
3. Feedback on whether using a DEFINES file as I did is good practice
4. Whether the way I populate privileges is good practice
5. Whether it is a good idea to use a shell like this to start any basic project

## File Structure:

• 0_UTILITIES - some basic utility functions which often pop up and are commonly presented in intro to C++ books
• 1_COMMAND_LINE_INTERFACE - collection of functions which allows to control the interface
• 2_ACTUAL_APP - actual app code you want to use goes here (some dummy functions populated to illustrate how information collected from user is packaged into objects and passed around the application

## Code item 1 - declaration of Settings singleton and associated functions:

struct command_info_container{
void* container_1;
void* container_2;
}; // this is an object to pass information between commands user invokes. each next node always knows what to cast the void container to

class command;

class user{
public:
user(){}
std::map<std::string,int> command_permissions;
}; // allows for different user with customized command_permissions objects. The command_permissions matches the text command invoke and allows to remove user's access to certain commands

namespace cli{ /// cli - command line interface. Certain functions which could also be in Settings singleton are implemented here. Not sure if this is the right design practice

void run_authorisation(command_info_container*); /// every function which is potentially packageable into a vector of functions takes the same shape, with an input of command_info_container pointer
void display_welcome_message(command_info_container*);
void display_completion_message(command_info_container*);

void run_command_junction(COMMAND_JUNCTION_KEY key,command_info_container* user_data); /// this pulls out the vector of commands packaged to a particular key. Commands are stored in Singleton Settings
void display_available_commands(COMMAND_JUNCTION_KEY key); /// at each stage, user is presented with a printout of available commands
std::string prompt_for_command(std::string message_to_user_if_different_from_default);
command match_input_text_to_a_command(std::string cmd,COMMAND_JUNCTION_KEY key);

void exit_program(command_info_container* info_to_pass);

void run_command_junction_C_MAIN(command_info_container* info_to_pass);
void run_command_junction_C_QUIT(command_info_container* info_to_pass);
void run_command_junction_C_GO_BACK(command_info_container* info_to_pass);
void run_command_junction_C_TEST(command_info_container* info_to_pass);
void run_command_junction_C_CHANGE_USER(command_info_container* info_to_pass); /// these functions are wrappers around run_command_junction, invoking a particular key - i.e. run_command_junction_C_MAIN invokes the C_MAIN command junction

void test_code_snippet(command_info_container* info_to_pass); /// this is for testing a snippet, for debugging purposes

}

struct command{ /// commands are contained in this class, main contents being pointer to immediate function to execute, and pointer to the function to execute after first function finishes running
command(){}
command(std::vector<std::string> inv, std::string desc,ptr_to_command_func p,ptr_to_command_func pn = &cli::run_command_junction_C_MAIN,std::string w = EMPTY_STRING,std::string cm = EMPTY_STRING):
text_of_command(inv),description_of_command(desc),func_to_execute(p),next_func_to_execute(pn){}
command(std::string inv, std::string desc,ptr_to_command_func p,ptr_to_command_func pn = &cli::run_command_junction_C_MAIN,std::string w = EMPTY_STRING,std::string cm = EMPTY_STRING):
description_of_command(desc),func_to_execute(p),next_func_to_execute(pn){text_of_command.push_back(inv);}

std::vector<std::string> text_of_command;
std::string description_of_command;

ptr_to_command_func func_to_execute = nullptr;
ptr_to_command_func next_func_to_execute = nullptr;

};

class settings{
settings();
map_of_command_junctions command_storage;

public:
static settings& get(){static settings S; return S;}

void initialise_command_tree();
void apply_permissions_to_command_availability();
command match_input_text_to_a_command(std::string cmd,COMMAND_JUNCTION_KEY key);

bool quit_flag;

map_of_command_junctions permissioned_command_tree;

std::string active_user;

COMMAND_JUNCTION_KEY previous_junction;
COMMAND_JUNCTION_KEY current_junction;

command cmd_J1_quit_confirmation;
command cmd_J1_go_back;
};


## Code item 2 - implementation of Settings singleton:

#include "0_UTILITIES/Includes.h"
#include COMMAND_LINE_INTERFACE

settings::settings(){

quit_flag = false;

initialise_command_tree();

}

std::map<std::string,int> normaluser_permissions;

}


## Code item 3 - populating the commands user is able to use in Settings singleton:

void settings::initialise_command_tree(){

command_storage.clear();
command cmd_continue_with_default_user("CONTD","Continue with default user",&cli::run_command_junction_C_MAIN);

command cmd_F_exit_program("FINALQUIT","Exit for good",&cli::exit_program);
command cmd_J1_test_snippet("SNPT","Test a code snippet",&cli::test_code_snippet);
cmd_J1_go_back = command("GOBACK","Go back",&cli::run_command_junction_C_GO_BACK);

command cmd_J1_prompt_for_test_inputs("RTST","Input data to run Test",&cli::run_command_junction_C_TEST);

cmd_J1_quit_confirmation = command("EXIT","Confirm exiting program",&cli::run_command_junction_C_QUIT);

command cmd_F0_J1_test_manual_input("TSTM","Test - input via console",&cli::prompt_for_single_test_inputs,&cli::run_test);
command cmd_F1_J1_test_from_xls("TXLS","Test - input via xls",&cli::load_test_input_xls,&cli::run_test);
command cmd_F2_J1_test_from_csv("TCSV","Test - input via csv",&cli::load_test_input_csv,&cli::run_test);

command_storage[COMMAND_JUNCTION_KEY::C_MAIN].push_back(cmd_J1_quit_confirmation);
command_storage[COMMAND_JUNCTION_KEY::C_MAIN].push_back(cmd_J1_test_snippet);
command_storage[COMMAND_JUNCTION_KEY::C_MAIN].push_back(cmd_J1_prompt_for_test_inputs);

command_storage[COMMAND_JUNCTION_KEY::C_QUIT].push_back(cmd_F_exit_program);

command_storage[COMMAND_JUNCTION_KEY::C_TEST].push_back(cmd_F0_J1_test_manual_input);
command_storage[COMMAND_JUNCTION_KEY::C_TEST].push_back(cmd_F1_J1_test_from_xls);
command_storage[COMMAND_JUNCTION_KEY::C_TEST].push_back(cmd_F2_J1_test_from_csv);

command_storage[COMMAND_JUNCTION_KEY::C_CHANGE_USER].push_back(cmd_continue_with_default_user);
`