Ken Yourek / ucmd

Dependents:   nucleo_ucmd_helloworld

Committer:
kyourek
Date:
Mon Oct 12 21:09:07 2015 +0000
Revision:
0:9e2fc73e5a12
Initial commit of the ucmd library for mbed.; https://github.com/kyourek/ucmd

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kyourek 0:9e2fc73e5a12 1 #include <string.h>
kyourek 0:9e2fc73e5a12 2 #include "ucmd_internal.h"
kyourek 0:9e2fc73e5a12 3
kyourek 0:9e2fc73e5a12 4 ucMemoryManager_INIT(ucCmdLineOpt, ucCmdLineOpt_COUNT);
kyourek 0:9e2fc73e5a12 5
kyourek 0:9e2fc73e5a12 6 static ucCmdLineOpt *create_cmd_line_opt(void) {
kyourek 0:9e2fc73e5a12 7 return ucMemoryManager_create();
kyourek 0:9e2fc73e5a12 8 }
kyourek 0:9e2fc73e5a12 9
kyourek 0:9e2fc73e5a12 10 static const char *add_opt_to_usage_response(ucOpt *opt, ucCmdLine *cmd, const char *response) {
kyourek 0:9e2fc73e5a12 11 static const char *required_format = "%s %s";
kyourek 0:9e2fc73e5a12 12 static const char *optional_format = "%s [%s]";
kyourek 0:9e2fc73e5a12 13 return ucCmdLine_format_response(
kyourek 0:9e2fc73e5a12 14 cmd,
kyourek 0:9e2fc73e5a12 15 ucOpt_is_required(opt) ? required_format : optional_format,
kyourek 0:9e2fc73e5a12 16 response,
kyourek 0:9e2fc73e5a12 17 ucOpt_get_name(opt)
kyourek 0:9e2fc73e5a12 18 );
kyourek 0:9e2fc73e5a12 19 }
kyourek 0:9e2fc73e5a12 20
kyourek 0:9e2fc73e5a12 21 static const char *add_arg_opts_to_usage_response(ucArgOpt *arg_opt, ucCmdLine *cmd, const char *response) {
kyourek 0:9e2fc73e5a12 22
kyourek 0:9e2fc73e5a12 23 while (NULL != arg_opt) {
kyourek 0:9e2fc73e5a12 24 response = add_opt_to_usage_response((ucOpt*)arg_opt, cmd, response);
kyourek 0:9e2fc73e5a12 25 arg_opt = ucArgOpt_get_next(arg_opt);
kyourek 0:9e2fc73e5a12 26 }
kyourek 0:9e2fc73e5a12 27
kyourek 0:9e2fc73e5a12 28 return response;
kyourek 0:9e2fc73e5a12 29 }
kyourek 0:9e2fc73e5a12 30
kyourek 0:9e2fc73e5a12 31 static void send_arg_opts_help(ucArgOpt *arg_opt, ucCmdLine *cmd, const char *prefix) {
kyourek 0:9e2fc73e5a12 32 while (NULL != arg_opt) {
kyourek 0:9e2fc73e5a12 33 ucOpt_send_help((ucOpt*)arg_opt, cmd, prefix);
kyourek 0:9e2fc73e5a12 34 arg_opt = ucArgOpt_get_next(arg_opt);
kyourek 0:9e2fc73e5a12 35 }
kyourek 0:9e2fc73e5a12 36 }
kyourek 0:9e2fc73e5a12 37
kyourek 0:9e2fc73e5a12 38 ucCmdLineOpt *ucCmdLineOpt_get_next(ucCmdLineOpt *p) {
kyourek 0:9e2fc73e5a12 39 if (NULL == p) return NULL;
kyourek 0:9e2fc73e5a12 40 return p->next;
kyourek 0:9e2fc73e5a12 41 }
kyourek 0:9e2fc73e5a12 42
kyourek 0:9e2fc73e5a12 43 ucArgOpt *ucCmdLineOpt_get_arg_opt(ucCmdLineOpt *p) {
kyourek 0:9e2fc73e5a12 44 if (NULL == p) return NULL;
kyourek 0:9e2fc73e5a12 45 return ucArgOptOwner_get_arg_opt((ucArgOptOwner*)p);
kyourek 0:9e2fc73e5a12 46 }
kyourek 0:9e2fc73e5a12 47
kyourek 0:9e2fc73e5a12 48 ucSwitchOpt *ucCmdLineOpt_get_switch_opt(ucCmdLineOpt *p) {
kyourek 0:9e2fc73e5a12 49 if (NULL == p) return NULL;
kyourek 0:9e2fc73e5a12 50 return p->switch_opt;
kyourek 0:9e2fc73e5a12 51 }
kyourek 0:9e2fc73e5a12 52
kyourek 0:9e2fc73e5a12 53 ucCmdLineOpt *ucCmdLineOpt_init(ucCmdLineOpt *p, ucCmdLineOpt_Func *func, void* state, const char *name, const char *desc, ucArgOpt *arg_opt, ucSwitchOpt *switch_opt, ucCmdLineOpt* next) {
kyourek 0:9e2fc73e5a12 54 if (NULL == p) return NULL;
kyourek 0:9e2fc73e5a12 55 if (NULL == ucArgOptOwner_init((ucArgOptOwner*)p, name, desc, ucBool_TRUE, arg_opt)) return NULL;
kyourek 0:9e2fc73e5a12 56 p->func = func;
kyourek 0:9e2fc73e5a12 57 p->state = state;
kyourek 0:9e2fc73e5a12 58 p->switch_opt = switch_opt;
kyourek 0:9e2fc73e5a12 59 p->next = next;
kyourek 0:9e2fc73e5a12 60 return p;
kyourek 0:9e2fc73e5a12 61 }
kyourek 0:9e2fc73e5a12 62
kyourek 0:9e2fc73e5a12 63 ucCmdLineOpt *ucCmdLineOpt_create(ucCmdLineOpt_Func *func, void *state, const char *name, const char *desc, ucArgOpt* arg_opt, ucSwitchOpt *switch_opt, ucCmdLineOpt *next) {
kyourek 0:9e2fc73e5a12 64 return ucCmdLineOpt_init(create_cmd_line_opt(), func, state, name, desc, arg_opt, switch_opt, next);
kyourek 0:9e2fc73e5a12 65 }
kyourek 0:9e2fc73e5a12 66
kyourek 0:9e2fc73e5a12 67 ucCmdLineOpt *ucCmdLineOpt_find_by_name(ucCmdLineOpt* p, const char *name) {
kyourek 0:9e2fc73e5a12 68 while (NULL != p) {
kyourek 0:9e2fc73e5a12 69 if (0 == strcmp(name, ucOpt_get_name((ucOpt*)p))) {
kyourek 0:9e2fc73e5a12 70 return p;
kyourek 0:9e2fc73e5a12 71 }
kyourek 0:9e2fc73e5a12 72 p = ucCmdLineOpt_get_next(p);
kyourek 0:9e2fc73e5a12 73 }
kyourek 0:9e2fc73e5a12 74 return NULL;
kyourek 0:9e2fc73e5a12 75 }
kyourek 0:9e2fc73e5a12 76
kyourek 0:9e2fc73e5a12 77 ucCmdLineOpt_Func *ucCmdLineOpt_get_func(ucCmdLineOpt *p) {
kyourek 0:9e2fc73e5a12 78 if (NULL == p) return NULL;
kyourek 0:9e2fc73e5a12 79 return p->func;
kyourek 0:9e2fc73e5a12 80 }
kyourek 0:9e2fc73e5a12 81
kyourek 0:9e2fc73e5a12 82 void *ucCmdLineOpt_get_state(ucCmdLineOpt *p) {
kyourek 0:9e2fc73e5a12 83 if (NULL == p) return NULL;
kyourek 0:9e2fc73e5a12 84 return p->state;
kyourek 0:9e2fc73e5a12 85 }
kyourek 0:9e2fc73e5a12 86
kyourek 0:9e2fc73e5a12 87 void ucCmdLineOpt_send_usage(ucCmdLineOpt *p, ucCmdLine *cmd) {
kyourek 0:9e2fc73e5a12 88 ucSwitchOpt *switch_opt;
kyourek 0:9e2fc73e5a12 89
kyourek 0:9e2fc73e5a12 90 /* start the usage string with the name of the command */
kyourek 0:9e2fc73e5a12 91 const char *response = ucCmdLine_format_response(cmd, "%s", ucOpt_get_name((ucOpt*)p));
kyourek 0:9e2fc73e5a12 92
kyourek 0:9e2fc73e5a12 93 /* add each available argument option of the command
kyourek 0:9e2fc73e5a12 94 to the usage string */
kyourek 0:9e2fc73e5a12 95 response = add_arg_opts_to_usage_response(ucCmdLineOpt_get_arg_opt(p), cmd, response);
kyourek 0:9e2fc73e5a12 96
kyourek 0:9e2fc73e5a12 97 /* loop through each available switch option */
kyourek 0:9e2fc73e5a12 98 switch_opt = ucCmdLineOpt_get_switch_opt(p);
kyourek 0:9e2fc73e5a12 99 while (NULL != switch_opt) {
kyourek 0:9e2fc73e5a12 100
kyourek 0:9e2fc73e5a12 101 /* add it to the usage string */
kyourek 0:9e2fc73e5a12 102 response = add_opt_to_usage_response((ucOpt*)switch_opt, cmd, response);
kyourek 0:9e2fc73e5a12 103
kyourek 0:9e2fc73e5a12 104 /* also add each of the switch's argument options to the
kyourek 0:9e2fc73e5a12 105 usage string */
kyourek 0:9e2fc73e5a12 106 response = add_arg_opts_to_usage_response(ucSwitchOpt_get_arg_opt(switch_opt), cmd, response);
kyourek 0:9e2fc73e5a12 107
kyourek 0:9e2fc73e5a12 108 /* go to the next switch */
kyourek 0:9e2fc73e5a12 109 switch_opt = ucSwitchOpt_get_next(switch_opt);
kyourek 0:9e2fc73e5a12 110 }
kyourek 0:9e2fc73e5a12 111
kyourek 0:9e2fc73e5a12 112 /* send the completed usage string */
kyourek 0:9e2fc73e5a12 113 ucCmdLine_respond(cmd, response);
kyourek 0:9e2fc73e5a12 114 }
kyourek 0:9e2fc73e5a12 115
kyourek 0:9e2fc73e5a12 116 void ucCmdLineOpt_send_help(ucCmdLineOpt *p, ucCmdLine *cmd) {
kyourek 0:9e2fc73e5a12 117 static const char *single_tab = "\t";
kyourek 0:9e2fc73e5a12 118 static const char *double_tab = "\t\t";
kyourek 0:9e2fc73e5a12 119
kyourek 0:9e2fc73e5a12 120 ucSwitchOpt *switch_opt;
kyourek 0:9e2fc73e5a12 121
kyourek 0:9e2fc73e5a12 122 ucCmdLineOpt_send_usage(p, cmd);
kyourek 0:9e2fc73e5a12 123
kyourek 0:9e2fc73e5a12 124 ucOpt_send_help((ucOpt*)p, cmd, "");
kyourek 0:9e2fc73e5a12 125 send_arg_opts_help(ucCmdLineOpt_get_arg_opt(p), cmd, single_tab);
kyourek 0:9e2fc73e5a12 126
kyourek 0:9e2fc73e5a12 127 switch_opt = ucCmdLineOpt_get_switch_opt(p);
kyourek 0:9e2fc73e5a12 128 while (NULL != switch_opt) {
kyourek 0:9e2fc73e5a12 129 ucOpt_send_help((ucOpt*)switch_opt, cmd, single_tab);
kyourek 0:9e2fc73e5a12 130 send_arg_opts_help(ucSwitchOpt_get_arg_opt(switch_opt), cmd, double_tab);
kyourek 0:9e2fc73e5a12 131 switch_opt = ucSwitchOpt_get_next(switch_opt);
kyourek 0:9e2fc73e5a12 132 }
kyourek 0:9e2fc73e5a12 133 }
kyourek 0:9e2fc73e5a12 134
kyourek 0:9e2fc73e5a12 135 const char *ucCmdLineOpt_format_validation_err(ucCmdLineOpt *p, ucCmdLine *cmd) {
kyourek 0:9e2fc73e5a12 136 static const char *invalid_switch = "Invalid switch: ";
kyourek 0:9e2fc73e5a12 137
kyourek 0:9e2fc73e5a12 138 ucCmdTok *cmd_tok;
kyourek 0:9e2fc73e5a12 139 ucSwitchOpt *switch_opt, *found_switch_opt, *next_switch_opt;
kyourek 0:9e2fc73e5a12 140 ucSwitchTok *switch_tok, *found_switch_tok, *next_switch_tok;
kyourek 0:9e2fc73e5a12 141 const char *switch_name, *validation;
kyourek 0:9e2fc73e5a12 142
kyourek 0:9e2fc73e5a12 143 cmd_tok = ucCmdLine_get_cmd_tok(cmd);
kyourek 0:9e2fc73e5a12 144
kyourek 0:9e2fc73e5a12 145 validation = ucArgOptOwner_format_validation_err((ucArgOptOwner*)p, cmd, ucCmdTok_get_arg(cmd_tok), NULL);
kyourek 0:9e2fc73e5a12 146 if (NULL != validation) return validation;
kyourek 0:9e2fc73e5a12 147
kyourek 0:9e2fc73e5a12 148 switch_tok = ucCmdTok_get_switch(cmd_tok);
kyourek 0:9e2fc73e5a12 149 switch_opt = ucCmdLineOpt_get_switch_opt(p);
kyourek 0:9e2fc73e5a12 150
kyourek 0:9e2fc73e5a12 151 if (NULL == switch_opt) {
kyourek 0:9e2fc73e5a12 152 if (NULL != switch_tok) {
kyourek 0:9e2fc73e5a12 153 return ucCmdLine_format_response(cmd, "%sno switch options exist for command \"%s\".", invalid_switch, ucTok_get_value((ucTok*)cmd_tok));
kyourek 0:9e2fc73e5a12 154 }
kyourek 0:9e2fc73e5a12 155 return NULL;
kyourek 0:9e2fc73e5a12 156 }
kyourek 0:9e2fc73e5a12 157
kyourek 0:9e2fc73e5a12 158 next_switch_tok = switch_tok;
kyourek 0:9e2fc73e5a12 159
kyourek 0:9e2fc73e5a12 160 while (NULL != next_switch_tok) {
kyourek 0:9e2fc73e5a12 161 found_switch_opt = ucSwitchOpt_find(switch_opt, ucTok_get_value((ucTok*)next_switch_tok));
kyourek 0:9e2fc73e5a12 162 if (NULL == found_switch_opt) {
kyourek 0:9e2fc73e5a12 163 return ucCmdLine_format_response(cmd, "%sno option exists for switch \"%s\".", invalid_switch, ucTok_get_value(next_switch_tok));
kyourek 0:9e2fc73e5a12 164 }
kyourek 0:9e2fc73e5a12 165 next_switch_tok = ucSwitchTok_get_next(next_switch_tok);
kyourek 0:9e2fc73e5a12 166 }
kyourek 0:9e2fc73e5a12 167
kyourek 0:9e2fc73e5a12 168 next_switch_opt = switch_opt;
kyourek 0:9e2fc73e5a12 169
kyourek 0:9e2fc73e5a12 170 while (NULL != next_switch_opt) {
kyourek 0:9e2fc73e5a12 171 switch_name = ucOpt_get_name((ucOpt*)next_switch_opt);
kyourek 0:9e2fc73e5a12 172 found_switch_tok = ucSwitchTok_find(switch_tok, switch_name);
kyourek 0:9e2fc73e5a12 173
kyourek 0:9e2fc73e5a12 174 if (ucOpt_is_required((ucOpt*)next_switch_opt)) {
kyourek 0:9e2fc73e5a12 175 if (NULL == found_switch_tok) {
kyourek 0:9e2fc73e5a12 176 return ucCmdLine_format_response(cmd, "%sthe switch \"%s\" is required.", invalid_switch, switch_name);
kyourek 0:9e2fc73e5a12 177 }
kyourek 0:9e2fc73e5a12 178 }
kyourek 0:9e2fc73e5a12 179
kyourek 0:9e2fc73e5a12 180 if (NULL != found_switch_tok) {
kyourek 0:9e2fc73e5a12 181 validation = ucSwitchOpt_format_validation_err(next_switch_opt, cmd, found_switch_tok);
kyourek 0:9e2fc73e5a12 182 if (NULL != validation) return validation;
kyourek 0:9e2fc73e5a12 183 }
kyourek 0:9e2fc73e5a12 184
kyourek 0:9e2fc73e5a12 185 next_switch_opt = ucSwitchOpt_get_next(next_switch_opt);
kyourek 0:9e2fc73e5a12 186 }
kyourek 0:9e2fc73e5a12 187
kyourek 0:9e2fc73e5a12 188 return NULL;
kyourek 0:9e2fc73e5a12 189 }
kyourek 0:9e2fc73e5a12 190
kyourek 0:9e2fc73e5a12 191 static const char *internal_process(ucCmdLineOpt *p, ucCmdLine *cmd, ucBool *invalid_command_handled) {
kyourek 0:9e2fc73e5a12 192 ucCmdTok *cmd_tok;
kyourek 0:9e2fc73e5a12 193 ucCmdLineOpt *opt;
kyourek 0:9e2fc73e5a12 194 ucCmdLineOpt_Func *func;
kyourek 0:9e2fc73e5a12 195 const char *cmd_value;
kyourek 0:9e2fc73e5a12 196 const char *validation;
kyourek 0:9e2fc73e5a12 197
kyourek 0:9e2fc73e5a12 198 /* Get the command token of the command structure. */
kyourek 0:9e2fc73e5a12 199 cmd_tok = ucCmdLine_get_cmd_tok(cmd);
kyourek 0:9e2fc73e5a12 200
kyourek 0:9e2fc73e5a12 201 /* Get the command option that we'll process by finding
kyourek 0:9e2fc73e5a12 202 the one that matches the name of the command. */
kyourek 0:9e2fc73e5a12 203 cmd_value = ucTok_get_value((ucTok*)cmd_tok);
kyourek 0:9e2fc73e5a12 204 opt = ucCmdLineOpt_find_by_name(p, cmd_value);
kyourek 0:9e2fc73e5a12 205 if (NULL == opt) {
kyourek 0:9e2fc73e5a12 206
kyourek 0:9e2fc73e5a12 207 /* The command is invalid (meaning it doesn't exist).
kyourek 0:9e2fc73e5a12 208 Try to handle it. */
kyourek 0:9e2fc73e5a12 209 *invalid_command_handled = ucCmdLine_handle_invalid_command(cmd, cmd_value);
kyourek 0:9e2fc73e5a12 210
kyourek 0:9e2fc73e5a12 211 /* If the command was handled, then we don't return an error. */
kyourek 0:9e2fc73e5a12 212 if (*invalid_command_handled) {
kyourek 0:9e2fc73e5a12 213 return NULL;
kyourek 0:9e2fc73e5a12 214 }
kyourek 0:9e2fc73e5a12 215 }
kyourek 0:9e2fc73e5a12 216
kyourek 0:9e2fc73e5a12 217 /* Send an indication that the command was received. */
kyourek 0:9e2fc73e5a12 218 ucCmdLine_acknowledge_command(cmd);
kyourek 0:9e2fc73e5a12 219
kyourek 0:9e2fc73e5a12 220 /* Check to see if the command is unknown. */
kyourek 0:9e2fc73e5a12 221 if (NULL == opt) return ucCmdLine_format_response(cmd, "Invalid command: no option found for \"%s\"", cmd_value);
kyourek 0:9e2fc73e5a12 222
kyourek 0:9e2fc73e5a12 223 /* Validate the command structure against the option.
kyourek 0:9e2fc73e5a12 224 If validation fails, then return the validation result. */
kyourek 0:9e2fc73e5a12 225 validation = ucCmdLineOpt_format_validation_err(opt, cmd);
kyourek 0:9e2fc73e5a12 226 if (validation) return validation;
kyourek 0:9e2fc73e5a12 227
kyourek 0:9e2fc73e5a12 228 /* Get the function callback from the command option. */
kyourek 0:9e2fc73e5a12 229 func = ucCmdLineOpt_get_func(opt);
kyourek 0:9e2fc73e5a12 230 if (NULL == func) return "Invalid function: null pointer";
kyourek 0:9e2fc73e5a12 231
kyourek 0:9e2fc73e5a12 232 /* Invoke the callback. */
kyourek 0:9e2fc73e5a12 233 return func(cmd, ucCmdLineOpt_get_state(opt));
kyourek 0:9e2fc73e5a12 234 }
kyourek 0:9e2fc73e5a12 235
kyourek 0:9e2fc73e5a12 236 const char *ucCmdLineOpt_process(ucCmdLineOpt* p, ucCmdLine *cmd) {
kyourek 0:9e2fc73e5a12 237 ucBool invalid_command_handled = ucBool_FALSE;
kyourek 0:9e2fc73e5a12 238 const char *response = internal_process(p, cmd, &invalid_command_handled);
kyourek 0:9e2fc73e5a12 239 if (invalid_command_handled) {
kyourek 0:9e2fc73e5a12 240 return response;
kyourek 0:9e2fc73e5a12 241 }
kyourek 0:9e2fc73e5a12 242
kyourek 0:9e2fc73e5a12 243 if (response) {
kyourek 0:9e2fc73e5a12 244 ucCmdLine_respond(cmd, response);
kyourek 0:9e2fc73e5a12 245 }
kyourek 0:9e2fc73e5a12 246
kyourek 0:9e2fc73e5a12 247 ucCmdLine_terminate_response(cmd);
kyourek 0:9e2fc73e5a12 248
kyourek 0:9e2fc73e5a12 249 return response;
kyourek 0:9e2fc73e5a12 250 }
kyourek 0:9e2fc73e5a12 251
kyourek 0:9e2fc73e5a12 252 void ucCmdLineOpt_destroy(ucCmdLineOpt *p) {
kyourek 0:9e2fc73e5a12 253 ucMemoryManager_destroy(p);
kyourek 0:9e2fc73e5a12 254 }
kyourek 0:9e2fc73e5a12 255
kyourek 0:9e2fc73e5a12 256 void ucCmdLineOpt_destroy_chain(ucCmdLineOpt *p) {
kyourek 0:9e2fc73e5a12 257 ucCmdLineOpt *next = p;
kyourek 0:9e2fc73e5a12 258 while (NULL != next) {
kyourek 0:9e2fc73e5a12 259 p = next;
kyourek 0:9e2fc73e5a12 260 next = ucCmdLineOpt_get_next(p);
kyourek 0:9e2fc73e5a12 261 ucArgOpt_destroy_chain(ucCmdLineOpt_get_arg_opt(p));
kyourek 0:9e2fc73e5a12 262 ucSwitchOpt_destroy_chain(ucCmdLineOpt_get_switch_opt(p));
kyourek 0:9e2fc73e5a12 263 ucCmdLineOpt_destroy(p);
kyourek 0:9e2fc73e5a12 264 }
kyourek 0:9e2fc73e5a12 265 }
kyourek 0:9e2fc73e5a12 266