Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: nucleo_ucmd_helloworld
ucCmdLineApp.c@0:9e2fc73e5a12, 2015-10-12 (annotated)
- 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?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| kyourek | 0:9e2fc73e5a12 | 1 | #include <stdio.h> |
| kyourek | 0:9e2fc73e5a12 | 2 | #include <stdlib.h> |
| kyourek | 0:9e2fc73e5a12 | 3 | #include <string.h> |
| kyourek | 0:9e2fc73e5a12 | 4 | #include "ucmd_internal.h" |
| kyourek | 0:9e2fc73e5a12 | 5 | |
| kyourek | 0:9e2fc73e5a12 | 6 | typedef struct HelpState { |
| kyourek | 0:9e2fc73e5a12 | 7 | ucCmdLineApp *app; |
| kyourek | 0:9e2fc73e5a12 | 8 | ucCmdLineOpt *cmd_opt; |
| kyourek | 0:9e2fc73e5a12 | 9 | } HelpState; |
| kyourek | 0:9e2fc73e5a12 | 10 | |
| kyourek | 0:9e2fc73e5a12 | 11 | typedef struct QuitState { |
| kyourek | 0:9e2fc73e5a12 | 12 | ucCmdLineApp *app; |
| kyourek | 0:9e2fc73e5a12 | 13 | } QuitState; |
| kyourek | 0:9e2fc73e5a12 | 14 | |
| kyourek | 0:9e2fc73e5a12 | 15 | static const char *quit(ucCmdLine *cmd, void *state) { |
| kyourek | 0:9e2fc73e5a12 | 16 | QuitState *s = (QuitState*)state; |
| kyourek | 0:9e2fc73e5a12 | 17 | return ucCmdLineApp_get_escape_response(s->app); |
| kyourek | 0:9e2fc73e5a12 | 18 | } |
| kyourek | 0:9e2fc73e5a12 | 19 | |
| kyourek | 0:9e2fc73e5a12 | 20 | static const char *help(ucCmdLine *cmd, void *state) { |
| kyourek | 0:9e2fc73e5a12 | 21 | HelpState *s; |
| kyourek | 0:9e2fc73e5a12 | 22 | ucArgTok *arg_tok; |
| kyourek | 0:9e2fc73e5a12 | 23 | ucCmdLineOpt *cmd_opt; |
| kyourek | 0:9e2fc73e5a12 | 24 | |
| kyourek | 0:9e2fc73e5a12 | 25 | s = (HelpState*)state; |
| kyourek | 0:9e2fc73e5a12 | 26 | cmd_opt = s->cmd_opt; |
| kyourek | 0:9e2fc73e5a12 | 27 | |
| kyourek | 0:9e2fc73e5a12 | 28 | arg_tok = ucCmdTok_get_arg(ucCmdLine_get_cmd_tok(cmd)); |
| kyourek | 0:9e2fc73e5a12 | 29 | if (NULL != arg_tok) { |
| kyourek | 0:9e2fc73e5a12 | 30 | cmd_opt = ucCmdLineOpt_find_by_name(cmd_opt, ucTok_get_value(arg_tok)); |
| kyourek | 0:9e2fc73e5a12 | 31 | if (NULL != cmd_opt) { |
| kyourek | 0:9e2fc73e5a12 | 32 | ucCmdLineOpt_send_help(cmd_opt, cmd); |
| kyourek | 0:9e2fc73e5a12 | 33 | return 0; |
| kyourek | 0:9e2fc73e5a12 | 34 | } |
| kyourek | 0:9e2fc73e5a12 | 35 | ucCmdLine_respond(cmd, ucCmdLine_format_response(cmd, "Invalid command: no option found for \"%s\".", ucTok_get_value(arg_tok))); |
| kyourek | 0:9e2fc73e5a12 | 36 | return 0; |
| kyourek | 0:9e2fc73e5a12 | 37 | } |
| kyourek | 0:9e2fc73e5a12 | 38 | |
| kyourek | 0:9e2fc73e5a12 | 39 | ucCmdLine_respond(cmd, "Commands"); |
| kyourek | 0:9e2fc73e5a12 | 40 | while (NULL != cmd_opt) { |
| kyourek | 0:9e2fc73e5a12 | 41 | ucOpt_send_help((ucOpt*)cmd_opt, cmd, "\t"); |
| kyourek | 0:9e2fc73e5a12 | 42 | cmd_opt = ucCmdLineOpt_get_next(cmd_opt); |
| kyourek | 0:9e2fc73e5a12 | 43 | } |
| kyourek | 0:9e2fc73e5a12 | 44 | ucCmdLine_respond(cmd, ucCmdLine_format_response(cmd, "Type \"%s\" followed by a command name for additional help with that command.", ucCmdLineApp_get_help_command(s->app))); |
| kyourek | 0:9e2fc73e5a12 | 45 | |
| kyourek | 0:9e2fc73e5a12 | 46 | return 0; |
| kyourek | 0:9e2fc73e5a12 | 47 | } |
| kyourek | 0:9e2fc73e5a12 | 48 | |
| kyourek | 0:9e2fc73e5a12 | 49 | static ucErr run(ucCmdLineApp *p, ucCmdLineOpt *cmd_opt) { |
| kyourek | 0:9e2fc73e5a12 | 50 | char *command; |
| kyourek | 0:9e2fc73e5a12 | 51 | const char *response; |
| kyourek | 0:9e2fc73e5a12 | 52 | ucCmdTok *cmd_tok; |
| kyourek | 0:9e2fc73e5a12 | 53 | ucCmdLine *cmd; |
| kyourek | 0:9e2fc73e5a12 | 54 | ucCmdLineOpt *quit_opt, *main_opt; |
| kyourek | 0:9e2fc73e5a12 | 55 | HelpState HelpState_s; |
| kyourek | 0:9e2fc73e5a12 | 56 | QuitState QuitState_s; |
| kyourek | 0:9e2fc73e5a12 | 57 | |
| kyourek | 0:9e2fc73e5a12 | 58 | if (NULL == p) return -1; |
| kyourek | 0:9e2fc73e5a12 | 59 | |
| kyourek | 0:9e2fc73e5a12 | 60 | /* Create options for help and quit. */ |
| kyourek | 0:9e2fc73e5a12 | 61 | quit_opt = ucCmdLineOpt_create(quit, &QuitState_s, ucCmdLineApp_get_quit_command(p), "Exits the command interface.", NULL, NULL, cmd_opt); |
| kyourek | 0:9e2fc73e5a12 | 62 | main_opt = ucCmdLineOpt_create(help, &HelpState_s, ucCmdLineApp_get_help_command(p), "Shows command information.", ucArgOpt_create("<command>", "If provided, help is shown for the given command.", NULL), NULL, quit_opt); |
| kyourek | 0:9e2fc73e5a12 | 63 | |
| kyourek | 0:9e2fc73e5a12 | 64 | /* Set the state used for the help and quit commands. */ |
| kyourek | 0:9e2fc73e5a12 | 65 | QuitState_s.app = p; |
| kyourek | 0:9e2fc73e5a12 | 66 | HelpState_s.app = p; |
| kyourek | 0:9e2fc73e5a12 | 67 | HelpState_s.cmd_opt = main_opt; |
| kyourek | 0:9e2fc73e5a12 | 68 | |
| kyourek | 0:9e2fc73e5a12 | 69 | /* Get this app's command object. */ |
| kyourek | 0:9e2fc73e5a12 | 70 | cmd = ucCmdLineApp_get_cmd(p); |
| kyourek | 0:9e2fc73e5a12 | 71 | |
| kyourek | 0:9e2fc73e5a12 | 72 | /* Show the banner. */ |
| kyourek | 0:9e2fc73e5a12 | 73 | ucCmdLine_respond(cmd, ucCmdLine_format_response(cmd, "Type %s to quit.", ucCmdLineApp_get_quit_command(p))); |
| kyourek | 0:9e2fc73e5a12 | 74 | ucCmdLine_respond(cmd, ucCmdLine_format_response(cmd, "Type %s for help.", ucCmdLineApp_get_help_command(p))); |
| kyourek | 0:9e2fc73e5a12 | 75 | |
| kyourek | 0:9e2fc73e5a12 | 76 | /* Loop until quit. */ |
| kyourek | 0:9e2fc73e5a12 | 77 | for (;;) { |
| kyourek | 0:9e2fc73e5a12 | 78 | |
| kyourek | 0:9e2fc73e5a12 | 79 | /* Read the command. */ |
| kyourek | 0:9e2fc73e5a12 | 80 | command = ucCmdLineApp_receive(p); |
| kyourek | 0:9e2fc73e5a12 | 81 | |
| kyourek | 0:9e2fc73e5a12 | 82 | /* Parse the input into a command token. */ |
| kyourek | 0:9e2fc73e5a12 | 83 | cmd_tok = ucCmdParser_parse(ucCmdLineApp_get_cmd_parser(p), command); |
| kyourek | 0:9e2fc73e5a12 | 84 | |
| kyourek | 0:9e2fc73e5a12 | 85 | /* Set the command's parsed command token. */ |
| kyourek | 0:9e2fc73e5a12 | 86 | ucCmdLine_set_cmd_tok(cmd, cmd_tok); |
| kyourek | 0:9e2fc73e5a12 | 87 | |
| kyourek | 0:9e2fc73e5a12 | 88 | /* Process the command. */ |
| kyourek | 0:9e2fc73e5a12 | 89 | response = ucCmdLineOpt_process(main_opt, cmd); |
| kyourek | 0:9e2fc73e5a12 | 90 | |
| kyourek | 0:9e2fc73e5a12 | 91 | /* Check if we got a response. */ |
| kyourek | 0:9e2fc73e5a12 | 92 | if (response) { |
| kyourek | 0:9e2fc73e5a12 | 93 | |
| kyourek | 0:9e2fc73e5a12 | 94 | /* Check if the response is the escape response. */ |
| kyourek | 0:9e2fc73e5a12 | 95 | if (0 == strcmp(response, ucCmdLineApp_get_escape_response(p))) { |
| kyourek | 0:9e2fc73e5a12 | 96 | |
| kyourek | 0:9e2fc73e5a12 | 97 | /* We've been signaled to quit the app. */ |
| kyourek | 0:9e2fc73e5a12 | 98 | break; |
| kyourek | 0:9e2fc73e5a12 | 99 | } |
| kyourek | 0:9e2fc73e5a12 | 100 | } |
| kyourek | 0:9e2fc73e5a12 | 101 | } |
| kyourek | 0:9e2fc73e5a12 | 102 | |
| kyourek | 0:9e2fc73e5a12 | 103 | /* Clear the options we created. */ |
| kyourek | 0:9e2fc73e5a12 | 104 | ucCmdLineOpt_destroy(quit_opt); |
| kyourek | 0:9e2fc73e5a12 | 105 | ucCmdLineOpt_destroy(main_opt); |
| kyourek | 0:9e2fc73e5a12 | 106 | |
| kyourek | 0:9e2fc73e5a12 | 107 | /* If we got here, then the app was quit. */ |
| kyourek | 0:9e2fc73e5a12 | 108 | return ucErr_NONE; |
| kyourek | 0:9e2fc73e5a12 | 109 | } |
| kyourek | 0:9e2fc73e5a12 | 110 | |
| kyourek | 0:9e2fc73e5a12 | 111 | void ucCmdLineApp_set_escape_response(ucCmdLineApp *p, const char *value) { |
| kyourek | 0:9e2fc73e5a12 | 112 | if (NULL == p) return; |
| kyourek | 0:9e2fc73e5a12 | 113 | p->escape_response = value; |
| kyourek | 0:9e2fc73e5a12 | 114 | } |
| kyourek | 0:9e2fc73e5a12 | 115 | |
| kyourek | 0:9e2fc73e5a12 | 116 | const char *ucCmdLineApp_get_escape_response(ucCmdLineApp *p) { |
| kyourek | 0:9e2fc73e5a12 | 117 | if (NULL == p) return NULL; |
| kyourek | 0:9e2fc73e5a12 | 118 | return p->escape_response; |
| kyourek | 0:9e2fc73e5a12 | 119 | } |
| kyourek | 0:9e2fc73e5a12 | 120 | |
| kyourek | 0:9e2fc73e5a12 | 121 | void ucCmdLineApp_set_receive(ucCmdLineApp *p, ucCmdLineApp_ReceiveFunc *value) { |
| kyourek | 0:9e2fc73e5a12 | 122 | if (NULL == p) return; |
| kyourek | 0:9e2fc73e5a12 | 123 | p->receive = value; |
| kyourek | 0:9e2fc73e5a12 | 124 | } |
| kyourek | 0:9e2fc73e5a12 | 125 | |
| kyourek | 0:9e2fc73e5a12 | 126 | ucCmdLineApp_ReceiveFunc *ucCmdLineApp_get_receive(ucCmdLineApp *p) { |
| kyourek | 0:9e2fc73e5a12 | 127 | if (NULL == p) return NULL; |
| kyourek | 0:9e2fc73e5a12 | 128 | return p->receive; |
| kyourek | 0:9e2fc73e5a12 | 129 | } |
| kyourek | 0:9e2fc73e5a12 | 130 | |
| kyourek | 0:9e2fc73e5a12 | 131 | void *ucCmdLineApp_get_receive_state(ucCmdLineApp *p) { |
| kyourek | 0:9e2fc73e5a12 | 132 | if (NULL == p) return NULL; |
| kyourek | 0:9e2fc73e5a12 | 133 | return p->receive_state; |
| kyourek | 0:9e2fc73e5a12 | 134 | } |
| kyourek | 0:9e2fc73e5a12 | 135 | |
| kyourek | 0:9e2fc73e5a12 | 136 | void ucCmdLineApp_set_receive_state(ucCmdLineApp *p, void *value) { |
| kyourek | 0:9e2fc73e5a12 | 137 | if (NULL == p) return; |
| kyourek | 0:9e2fc73e5a12 | 138 | p->receive_state = value; |
| kyourek | 0:9e2fc73e5a12 | 139 | } |
| kyourek | 0:9e2fc73e5a12 | 140 | |
| kyourek | 0:9e2fc73e5a12 | 141 | void ucCmdLineApp_set_quit_command(ucCmdLineApp *p, const char *value) { |
| kyourek | 0:9e2fc73e5a12 | 142 | if (NULL == p) return; |
| kyourek | 0:9e2fc73e5a12 | 143 | p->quit_command = value; |
| kyourek | 0:9e2fc73e5a12 | 144 | } |
| kyourek | 0:9e2fc73e5a12 | 145 | |
| kyourek | 0:9e2fc73e5a12 | 146 | const char *ucCmdLineApp_get_quit_command(ucCmdLineApp *p) { |
| kyourek | 0:9e2fc73e5a12 | 147 | if (NULL == p) return NULL; |
| kyourek | 0:9e2fc73e5a12 | 148 | return p->quit_command; |
| kyourek | 0:9e2fc73e5a12 | 149 | } |
| kyourek | 0:9e2fc73e5a12 | 150 | |
| kyourek | 0:9e2fc73e5a12 | 151 | void ucCmdLineApp_set_help_command(ucCmdLineApp *p, const char *value) { |
| kyourek | 0:9e2fc73e5a12 | 152 | if (NULL == p) return; |
| kyourek | 0:9e2fc73e5a12 | 153 | p->help_command = value; |
| kyourek | 0:9e2fc73e5a12 | 154 | } |
| kyourek | 0:9e2fc73e5a12 | 155 | |
| kyourek | 0:9e2fc73e5a12 | 156 | const char *ucCmdLineApp_get_help_command(ucCmdLineApp *p) { |
| kyourek | 0:9e2fc73e5a12 | 157 | if (NULL == p) return NULL; |
| kyourek | 0:9e2fc73e5a12 | 158 | return p->help_command; |
| kyourek | 0:9e2fc73e5a12 | 159 | } |
| kyourek | 0:9e2fc73e5a12 | 160 | |
| kyourek | 0:9e2fc73e5a12 | 161 | void ucCmdLineApp_set_cmd(ucCmdLineApp *p, ucCmdLine *value) { |
| kyourek | 0:9e2fc73e5a12 | 162 | if (NULL == p) return; |
| kyourek | 0:9e2fc73e5a12 | 163 | p->cmd = value; |
| kyourek | 0:9e2fc73e5a12 | 164 | } |
| kyourek | 0:9e2fc73e5a12 | 165 | |
| kyourek | 0:9e2fc73e5a12 | 166 | ucCmdLine *ucCmdLineApp_get_cmd(ucCmdLineApp *p) { |
| kyourek | 0:9e2fc73e5a12 | 167 | if (NULL == p) return NULL; |
| kyourek | 0:9e2fc73e5a12 | 168 | return p->cmd; |
| kyourek | 0:9e2fc73e5a12 | 169 | } |
| kyourek | 0:9e2fc73e5a12 | 170 | |
| kyourek | 0:9e2fc73e5a12 | 171 | ucCmdParser *ucCmdLineApp_get_cmd_parser(ucCmdLineApp *p) { |
| kyourek | 0:9e2fc73e5a12 | 172 | if (NULL == p) return NULL; |
| kyourek | 0:9e2fc73e5a12 | 173 | return p->cmd_parser; |
| kyourek | 0:9e2fc73e5a12 | 174 | } |
| kyourek | 0:9e2fc73e5a12 | 175 | |
| kyourek | 0:9e2fc73e5a12 | 176 | ucCmdLineApp *ucCmdLineApp_init(ucCmdLineApp *p, ucCmdParser *cmd_parser, ucCmdLine *cmd) { |
| kyourek | 0:9e2fc73e5a12 | 177 | if (NULL == p) return NULL; |
| kyourek | 0:9e2fc73e5a12 | 178 | p->cmd = cmd; |
| kyourek | 0:9e2fc73e5a12 | 179 | p->cmd_parser = cmd_parser; |
| kyourek | 0:9e2fc73e5a12 | 180 | p->run = run; |
| kyourek | 0:9e2fc73e5a12 | 181 | p->receive = NULL; |
| kyourek | 0:9e2fc73e5a12 | 182 | p->receive_state = NULL; |
| kyourek | 0:9e2fc73e5a12 | 183 | p->help_command = "help"; |
| kyourek | 0:9e2fc73e5a12 | 184 | p->quit_command = "quit"; |
| kyourek | 0:9e2fc73e5a12 | 185 | p->escape_response = "\x1b"; |
| kyourek | 0:9e2fc73e5a12 | 186 | return p; |
| kyourek | 0:9e2fc73e5a12 | 187 | } |
| kyourek | 0:9e2fc73e5a12 | 188 | |
| kyourek | 0:9e2fc73e5a12 | 189 | ucCmdLineApp *ucCmdLineApp_get_instance(void) { |
| kyourek | 0:9e2fc73e5a12 | 190 | static ucCmdLineApp instance = { 0 }; |
| kyourek | 0:9e2fc73e5a12 | 191 | static ucCmdLineApp *pointer = NULL; |
| kyourek | 0:9e2fc73e5a12 | 192 | if (pointer == NULL) { |
| kyourek | 0:9e2fc73e5a12 | 193 | pointer = ucCmdLineApp_init(&instance, ucCmdParser_get_instance(), ucCmdLine_get_instance()); |
| kyourek | 0:9e2fc73e5a12 | 194 | } |
| kyourek | 0:9e2fc73e5a12 | 195 | return pointer; |
| kyourek | 0:9e2fc73e5a12 | 196 | } |
| kyourek | 0:9e2fc73e5a12 | 197 | |
| kyourek | 0:9e2fc73e5a12 | 198 | ucErr ucCmdLineApp_run(ucCmdLineApp *p, ucCmdLineOpt *cmd_opt) { |
| kyourek | 0:9e2fc73e5a12 | 199 | if (NULL == p) return -1; |
| kyourek | 0:9e2fc73e5a12 | 200 | if (NULL == p->run) return -2; |
| kyourek | 0:9e2fc73e5a12 | 201 | return p->run(p, cmd_opt); |
| kyourek | 0:9e2fc73e5a12 | 202 | } |
| kyourek | 0:9e2fc73e5a12 | 203 | |
| kyourek | 0:9e2fc73e5a12 | 204 | char *ucCmdLineApp_receive(ucCmdLineApp *p) { |
| kyourek | 0:9e2fc73e5a12 | 205 | if (NULL == p) return NULL; |
| kyourek | 0:9e2fc73e5a12 | 206 | if (NULL == p->receive) return NULL; |
| kyourek | 0:9e2fc73e5a12 | 207 | return p->receive(p->cmd_str, sizeof(p->cmd_str), p->receive_state); |
| kyourek | 0:9e2fc73e5a12 | 208 | } |
| kyourek | 0:9e2fc73e5a12 | 209 | |
| kyourek | 0:9e2fc73e5a12 | 210 | size_t ucCmdLineApp_get_cmd_str_size_max(ucCmdLineApp *p) { |
| kyourek | 0:9e2fc73e5a12 | 211 | if (NULL == p) return 0; |
| kyourek | 0:9e2fc73e5a12 | 212 | return ucCmdLineApp_CMD_STR_SIZE; |
| kyourek | 0:9e2fc73e5a12 | 213 | } |
| kyourek | 0:9e2fc73e5a12 | 214 |