Ken Yourek / ucmd

Dependents:   nucleo_ucmd_helloworld

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ucCmdLineOpt.c Source File

ucCmdLineOpt.c

00001 #include <string.h>
00002 #include "ucmd_internal.h"
00003 
00004 ucMemoryManager_INIT(ucCmdLineOpt, ucCmdLineOpt_COUNT);
00005 
00006 static ucCmdLineOpt *create_cmd_line_opt(void) {
00007     return ucMemoryManager_create();
00008 }
00009 
00010 static const char *add_opt_to_usage_response(ucOpt *opt, ucCmdLine *cmd, const char *response) {
00011     static const char *required_format = "%s %s";
00012     static const char *optional_format = "%s [%s]";
00013     return ucCmdLine_format_response(
00014         cmd,
00015         ucOpt_is_required(opt) ? required_format : optional_format,
00016         response,
00017         ucOpt_get_name(opt)
00018     );
00019 }
00020 
00021 static const char *add_arg_opts_to_usage_response(ucArgOpt *arg_opt, ucCmdLine *cmd, const char *response) {
00022     
00023     while (NULL != arg_opt) {
00024         response = add_opt_to_usage_response((ucOpt*)arg_opt, cmd, response);
00025         arg_opt = ucArgOpt_get_next(arg_opt);
00026     }
00027 
00028     return response;
00029 }
00030 
00031 static void send_arg_opts_help(ucArgOpt *arg_opt, ucCmdLine *cmd, const char *prefix) {
00032     while (NULL != arg_opt) {
00033         ucOpt_send_help((ucOpt*)arg_opt, cmd, prefix);
00034         arg_opt = ucArgOpt_get_next(arg_opt);
00035     }
00036 }
00037 
00038 ucCmdLineOpt *ucCmdLineOpt_get_next(ucCmdLineOpt *p) {
00039     if (NULL == p) return NULL;
00040     return p->next;
00041 }
00042 
00043 ucArgOpt *ucCmdLineOpt_get_arg_opt(ucCmdLineOpt *p) {
00044     if (NULL == p) return NULL;
00045     return ucArgOptOwner_get_arg_opt((ucArgOptOwner*)p);
00046 }
00047 
00048 ucSwitchOpt *ucCmdLineOpt_get_switch_opt(ucCmdLineOpt *p) {
00049     if (NULL == p) return NULL;
00050     return p->switch_opt;
00051 }
00052 
00053 ucCmdLineOpt *ucCmdLineOpt_init(ucCmdLineOpt *p, ucCmdLineOpt_Func *func, void* state, const char *name, const char *desc, ucArgOpt *arg_opt, ucSwitchOpt *switch_opt, ucCmdLineOpt* next) {
00054     if (NULL == p) return NULL;
00055     if (NULL == ucArgOptOwner_init((ucArgOptOwner*)p, name, desc, ucBool_TRUE, arg_opt)) return NULL;
00056     p->func = func;
00057     p->state = state;
00058     p->switch_opt = switch_opt;
00059     p->next = next;
00060     return p;
00061 }
00062 
00063 ucCmdLineOpt *ucCmdLineOpt_create(ucCmdLineOpt_Func *func, void *state, const char *name, const char *desc, ucArgOpt* arg_opt, ucSwitchOpt *switch_opt, ucCmdLineOpt *next) {
00064     return ucCmdLineOpt_init(create_cmd_line_opt(), func, state, name, desc, arg_opt, switch_opt, next);
00065 }
00066 
00067 ucCmdLineOpt *ucCmdLineOpt_find_by_name(ucCmdLineOpt* p, const char *name) {
00068     while (NULL != p) {
00069         if (0 == strcmp(name, ucOpt_get_name((ucOpt*)p))) {
00070             return p;
00071         }
00072         p = ucCmdLineOpt_get_next(p);
00073     }
00074     return NULL;
00075 }
00076 
00077 ucCmdLineOpt_Func *ucCmdLineOpt_get_func(ucCmdLineOpt *p) {
00078     if (NULL == p) return NULL;
00079     return p->func;
00080 }
00081 
00082 void *ucCmdLineOpt_get_state(ucCmdLineOpt *p) {
00083     if (NULL == p) return NULL;
00084     return p->state;
00085 }
00086 
00087 void ucCmdLineOpt_send_usage(ucCmdLineOpt *p, ucCmdLine *cmd) {
00088     ucSwitchOpt *switch_opt;
00089 
00090     /* start the usage string with the name of the command */
00091     const char *response = ucCmdLine_format_response(cmd, "%s", ucOpt_get_name((ucOpt*)p));
00092 
00093     /* add each available argument option of the command
00094        to the usage string */
00095     response = add_arg_opts_to_usage_response(ucCmdLineOpt_get_arg_opt(p), cmd, response);
00096 
00097     /* loop through each available switch option */
00098     switch_opt = ucCmdLineOpt_get_switch_opt(p);
00099     while (NULL != switch_opt) {
00100 
00101         /* add it to the usage string */
00102         response = add_opt_to_usage_response((ucOpt*)switch_opt, cmd, response);
00103 
00104         /* also add each of the switch's argument options to the
00105            usage string */
00106         response = add_arg_opts_to_usage_response(ucSwitchOpt_get_arg_opt(switch_opt), cmd, response);
00107 
00108         /* go to the next switch */
00109         switch_opt = ucSwitchOpt_get_next(switch_opt);
00110     }
00111 
00112     /* send the completed usage string */
00113     ucCmdLine_respond(cmd, response);
00114 }
00115 
00116 void ucCmdLineOpt_send_help(ucCmdLineOpt *p, ucCmdLine *cmd) {
00117     static const char *single_tab = "\t";
00118     static const char *double_tab = "\t\t";
00119 
00120     ucSwitchOpt *switch_opt;
00121 
00122     ucCmdLineOpt_send_usage(p, cmd);
00123 
00124     ucOpt_send_help((ucOpt*)p, cmd, "");
00125     send_arg_opts_help(ucCmdLineOpt_get_arg_opt(p), cmd, single_tab);    
00126 
00127     switch_opt = ucCmdLineOpt_get_switch_opt(p);
00128     while (NULL != switch_opt) {
00129         ucOpt_send_help((ucOpt*)switch_opt, cmd, single_tab);
00130         send_arg_opts_help(ucSwitchOpt_get_arg_opt(switch_opt), cmd, double_tab);
00131         switch_opt = ucSwitchOpt_get_next(switch_opt);
00132     }
00133 }
00134 
00135 const char *ucCmdLineOpt_format_validation_err(ucCmdLineOpt *p, ucCmdLine *cmd) {
00136     static const char *invalid_switch = "Invalid switch: ";
00137 
00138     ucCmdTok *cmd_tok;
00139     ucSwitchOpt *switch_opt, *found_switch_opt, *next_switch_opt;
00140     ucSwitchTok *switch_tok, *found_switch_tok, *next_switch_tok;
00141     const char *switch_name, *validation;
00142 
00143     cmd_tok = ucCmdLine_get_cmd_tok(cmd);
00144     
00145     validation = ucArgOptOwner_format_validation_err((ucArgOptOwner*)p, cmd, ucCmdTok_get_arg(cmd_tok), NULL);
00146     if (NULL != validation) return validation;
00147 
00148     switch_tok = ucCmdTok_get_switch(cmd_tok);
00149     switch_opt = ucCmdLineOpt_get_switch_opt(p);
00150 
00151     if (NULL == switch_opt) {
00152         if (NULL != switch_tok) {
00153             return ucCmdLine_format_response(cmd, "%sno switch options exist for command \"%s\".", invalid_switch, ucTok_get_value((ucTok*)cmd_tok));
00154         }
00155         return NULL;
00156     }
00157 
00158     next_switch_tok = switch_tok;
00159 
00160     while (NULL != next_switch_tok) {
00161         found_switch_opt = ucSwitchOpt_find(switch_opt, ucTok_get_value((ucTok*)next_switch_tok));
00162         if (NULL == found_switch_opt) {
00163             return ucCmdLine_format_response(cmd, "%sno option exists for switch \"%s\".", invalid_switch, ucTok_get_value(next_switch_tok));
00164         }
00165         next_switch_tok = ucSwitchTok_get_next(next_switch_tok);
00166     }
00167 
00168     next_switch_opt = switch_opt;
00169 
00170     while (NULL != next_switch_opt) {
00171         switch_name = ucOpt_get_name((ucOpt*)next_switch_opt);
00172         found_switch_tok = ucSwitchTok_find(switch_tok, switch_name);
00173 
00174         if (ucOpt_is_required((ucOpt*)next_switch_opt)) {
00175             if (NULL == found_switch_tok) {
00176                 return ucCmdLine_format_response(cmd, "%sthe switch \"%s\" is required.", invalid_switch, switch_name);
00177             }
00178         }
00179 
00180         if (NULL != found_switch_tok) {
00181             validation = ucSwitchOpt_format_validation_err(next_switch_opt, cmd, found_switch_tok);
00182             if (NULL != validation) return validation;
00183         }
00184 
00185         next_switch_opt = ucSwitchOpt_get_next(next_switch_opt);
00186     }
00187     
00188     return NULL;
00189 }
00190 
00191 static const char *internal_process(ucCmdLineOpt *p, ucCmdLine *cmd, ucBool *invalid_command_handled) {
00192     ucCmdTok *cmd_tok;
00193     ucCmdLineOpt *opt;
00194     ucCmdLineOpt_Func *func;
00195     const char *cmd_value;
00196     const char *validation;
00197 
00198     /* Get the command token of the command structure. */
00199     cmd_tok = ucCmdLine_get_cmd_tok(cmd);
00200 
00201     /* Get the command option that we'll process by finding
00202     the one that matches the name of the command. */
00203     cmd_value = ucTok_get_value((ucTok*)cmd_tok);
00204     opt = ucCmdLineOpt_find_by_name(p, cmd_value);
00205     if (NULL == opt) {
00206 
00207         /* The command is invalid (meaning it doesn't exist).
00208         Try to handle it. */
00209         *invalid_command_handled = ucCmdLine_handle_invalid_command(cmd, cmd_value);
00210 
00211         /* If the command was handled, then we don't return an error. */
00212         if (*invalid_command_handled) {
00213             return NULL;
00214         }
00215     }
00216 
00217     /* Send an indication that the command was received. */
00218     ucCmdLine_acknowledge_command(cmd);
00219 
00220     /* Check to see if the command is unknown. */
00221     if (NULL == opt) return ucCmdLine_format_response(cmd, "Invalid command: no option found for \"%s\"", cmd_value);
00222 
00223     /* Validate the command structure against the option.
00224     If validation fails, then return the validation result. */
00225     validation = ucCmdLineOpt_format_validation_err(opt, cmd);
00226     if (validation) return validation;
00227 
00228     /* Get the function callback from the command option. */
00229     func = ucCmdLineOpt_get_func(opt);
00230     if (NULL == func) return "Invalid function: null pointer";
00231 
00232     /* Invoke the callback. */
00233     return func(cmd, ucCmdLineOpt_get_state(opt));
00234 }
00235 
00236 const char *ucCmdLineOpt_process(ucCmdLineOpt* p, ucCmdLine *cmd) {
00237     ucBool invalid_command_handled = ucBool_FALSE;
00238     const char *response = internal_process(p, cmd, &invalid_command_handled);
00239     if (invalid_command_handled) {
00240         return response;
00241     }
00242 
00243     if (response) {
00244         ucCmdLine_respond(cmd, response);
00245     }
00246 
00247     ucCmdLine_terminate_response(cmd);
00248 
00249     return response;
00250 }
00251 
00252 void ucCmdLineOpt_destroy(ucCmdLineOpt *p) {
00253     ucMemoryManager_destroy(p);
00254 }
00255 
00256 void ucCmdLineOpt_destroy_chain(ucCmdLineOpt *p) {
00257     ucCmdLineOpt *next = p;
00258     while (NULL != next) {
00259         p = next;
00260         next = ucCmdLineOpt_get_next(p);
00261         ucArgOpt_destroy_chain(ucCmdLineOpt_get_arg_opt(p));
00262         ucSwitchOpt_destroy_chain(ucCmdLineOpt_get_switch_opt(p));
00263         ucCmdLineOpt_destroy(p);
00264     }
00265 }
00266