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
ucTok.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 <stdlib.h> |
| kyourek | 0:9e2fc73e5a12 | 2 | #include <string.h> |
| kyourek | 0:9e2fc73e5a12 | 3 | #include "ucmd_internal.h" |
| kyourek | 0:9e2fc73e5a12 | 4 | |
| kyourek | 0:9e2fc73e5a12 | 5 | const char ucTok_separator = '\0'; |
| kyourek | 0:9e2fc73e5a12 | 6 | const char uc_cmd_terminator = '\n'; |
| kyourek | 0:9e2fc73e5a12 | 7 | |
| kyourek | 0:9e2fc73e5a12 | 8 | static ucBool is_char_digit(char c) { |
| kyourek | 0:9e2fc73e5a12 | 9 | /* The native isdigit function in ctype.h was giving some weird behavior in the uVision simulator. */ |
| kyourek | 0:9e2fc73e5a12 | 10 | static const char *digits = "0123456789"; |
| kyourek | 0:9e2fc73e5a12 | 11 | const char *d; |
| kyourek | 0:9e2fc73e5a12 | 12 | for (d = digits; *d; d++) { |
| kyourek | 0:9e2fc73e5a12 | 13 | if (*d == c) { |
| kyourek | 0:9e2fc73e5a12 | 14 | return ucBool_TRUE; |
| kyourek | 0:9e2fc73e5a12 | 15 | } |
| kyourek | 0:9e2fc73e5a12 | 16 | } |
| kyourek | 0:9e2fc73e5a12 | 17 | return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 18 | } |
| kyourek | 0:9e2fc73e5a12 | 19 | |
| kyourek | 0:9e2fc73e5a12 | 20 | int ucTok_get_length(ucTok *p) { |
| kyourek | 0:9e2fc73e5a12 | 21 | int length; |
| kyourek | 0:9e2fc73e5a12 | 22 | if (NULL == p) return 0; |
| kyourek | 0:9e2fc73e5a12 | 23 | |
| kyourek | 0:9e2fc73e5a12 | 24 | for (length = 0; *p != ucTok_separator; length++, p++); |
| kyourek | 0:9e2fc73e5a12 | 25 | |
| kyourek | 0:9e2fc73e5a12 | 26 | return length; |
| kyourek | 0:9e2fc73e5a12 | 27 | } |
| kyourek | 0:9e2fc73e5a12 | 28 | |
| kyourek | 0:9e2fc73e5a12 | 29 | const char *ucTok_get_value(ucTok *p) { |
| kyourek | 0:9e2fc73e5a12 | 30 | if (NULL == p) return NULL; |
| kyourek | 0:9e2fc73e5a12 | 31 | return (const char*)p; |
| kyourek | 0:9e2fc73e5a12 | 32 | } |
| kyourek | 0:9e2fc73e5a12 | 33 | |
| kyourek | 0:9e2fc73e5a12 | 34 | ucBool ucTok_equals(ucTok *p, const char *value) { |
| kyourek | 0:9e2fc73e5a12 | 35 | int i, len; |
| kyourek | 0:9e2fc73e5a12 | 36 | |
| kyourek | 0:9e2fc73e5a12 | 37 | /* check if these pointers are the same */ |
| kyourek | 0:9e2fc73e5a12 | 38 | if (value == p) return ucBool_TRUE; |
| kyourek | 0:9e2fc73e5a12 | 39 | |
| kyourek | 0:9e2fc73e5a12 | 40 | /* make sure neither arg is null */ |
| kyourek | 0:9e2fc73e5a12 | 41 | if (NULL == p) return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 42 | if (NULL == value) return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 43 | |
| kyourek | 0:9e2fc73e5a12 | 44 | /* check if the string lengths are the same */ |
| kyourek | 0:9e2fc73e5a12 | 45 | len = ucTok_get_length(p); |
| kyourek | 0:9e2fc73e5a12 | 46 | if (strlen(value) != len) return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 47 | |
| kyourek | 0:9e2fc73e5a12 | 48 | /* check for character equality */ |
| kyourek | 0:9e2fc73e5a12 | 49 | for (i = 0; i < len; i++) { |
| kyourek | 0:9e2fc73e5a12 | 50 | if (p[i] != value[i]) { |
| kyourek | 0:9e2fc73e5a12 | 51 | return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 52 | } |
| kyourek | 0:9e2fc73e5a12 | 53 | } |
| kyourek | 0:9e2fc73e5a12 | 54 | |
| kyourek | 0:9e2fc73e5a12 | 55 | /* if we got here, then the strings are equal */ |
| kyourek | 0:9e2fc73e5a12 | 56 | return ucBool_TRUE; |
| kyourek | 0:9e2fc73e5a12 | 57 | } |
| kyourek | 0:9e2fc73e5a12 | 58 | |
| kyourek | 0:9e2fc73e5a12 | 59 | ucBool ucTok_is_numeric(ucTok *p) { |
| kyourek | 0:9e2fc73e5a12 | 60 | int i, len; |
| kyourek | 0:9e2fc73e5a12 | 61 | ucBool dec_found; |
| kyourek | 0:9e2fc73e5a12 | 62 | |
| kyourek | 0:9e2fc73e5a12 | 63 | /* check if p is NULL */ |
| kyourek | 0:9e2fc73e5a12 | 64 | if (NULL == p) return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 65 | |
| kyourek | 0:9e2fc73e5a12 | 66 | /* get the length of the string */ |
| kyourek | 0:9e2fc73e5a12 | 67 | len = ucTok_get_length(p); |
| kyourek | 0:9e2fc73e5a12 | 68 | |
| kyourek | 0:9e2fc73e5a12 | 69 | /* numbers need to have at least 1 character */ |
| kyourek | 0:9e2fc73e5a12 | 70 | if (len < 1) return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 71 | |
| kyourek | 0:9e2fc73e5a12 | 72 | /* we are allowed to start with a '-' or '.' for negative numbers and decimals */ |
| kyourek | 0:9e2fc73e5a12 | 73 | if ((p[0] == '-') || (p[0] == '.')) { |
| kyourek | 0:9e2fc73e5a12 | 74 | |
| kyourek | 0:9e2fc73e5a12 | 75 | /* but we need more than 1 char if we do */ |
| kyourek | 0:9e2fc73e5a12 | 76 | if (len < 2) return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 77 | } |
| kyourek | 0:9e2fc73e5a12 | 78 | |
| kyourek | 0:9e2fc73e5a12 | 79 | // initialize vars |
| kyourek | 0:9e2fc73e5a12 | 80 | dec_found = ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 81 | |
| kyourek | 0:9e2fc73e5a12 | 82 | /* loop through the chars */ |
| kyourek | 0:9e2fc73e5a12 | 83 | for (i = 0; i < len; i++) { |
| kyourek | 0:9e2fc73e5a12 | 84 | |
| kyourek | 0:9e2fc73e5a12 | 85 | switch(p[i]) { |
| kyourek | 0:9e2fc73e5a12 | 86 | |
| kyourek | 0:9e2fc73e5a12 | 87 | /* allow a dash only at the beginning */ |
| kyourek | 0:9e2fc73e5a12 | 88 | case '-': |
| kyourek | 0:9e2fc73e5a12 | 89 | if (i != 0) return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 90 | break; |
| kyourek | 0:9e2fc73e5a12 | 91 | |
| kyourek | 0:9e2fc73e5a12 | 92 | /* allow only 1 dot */ |
| kyourek | 0:9e2fc73e5a12 | 93 | case '.': |
| kyourek | 0:9e2fc73e5a12 | 94 | if (dec_found) return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 95 | dec_found = ucBool_TRUE; |
| kyourek | 0:9e2fc73e5a12 | 96 | break; |
| kyourek | 0:9e2fc73e5a12 | 97 | |
| kyourek | 0:9e2fc73e5a12 | 98 | /* everything else has to be a number */ |
| kyourek | 0:9e2fc73e5a12 | 99 | default: |
| kyourek | 0:9e2fc73e5a12 | 100 | if (is_char_digit(p[i]) == ucBool_FALSE) return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 101 | break; |
| kyourek | 0:9e2fc73e5a12 | 102 | } |
| kyourek | 0:9e2fc73e5a12 | 103 | } |
| kyourek | 0:9e2fc73e5a12 | 104 | |
| kyourek | 0:9e2fc73e5a12 | 105 | /* if we got here, it's a number */ |
| kyourek | 0:9e2fc73e5a12 | 106 | return ucBool_TRUE; |
| kyourek | 0:9e2fc73e5a12 | 107 | } |
| kyourek | 0:9e2fc73e5a12 | 108 | |
| kyourek | 0:9e2fc73e5a12 | 109 | ucBool ucTok_try_parse_numeric(ucTok *p, double *value) { |
| kyourek | 0:9e2fc73e5a12 | 110 | if (ucTok_is_numeric(p)) { |
| kyourek | 0:9e2fc73e5a12 | 111 | if (value) { |
| kyourek | 0:9e2fc73e5a12 | 112 | *value = atof(ucTok_get_value(p)); |
| kyourek | 0:9e2fc73e5a12 | 113 | } |
| kyourek | 0:9e2fc73e5a12 | 114 | return ucBool_TRUE; |
| kyourek | 0:9e2fc73e5a12 | 115 | } |
| kyourek | 0:9e2fc73e5a12 | 116 | return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 117 | } |
| kyourek | 0:9e2fc73e5a12 | 118 | |
| kyourek | 0:9e2fc73e5a12 | 119 | double ucTok_parse_numeric(ucTok *p) { |
| kyourek | 0:9e2fc73e5a12 | 120 | double value = 0; |
| kyourek | 0:9e2fc73e5a12 | 121 | ucTok_try_parse_numeric(p, &value); |
| kyourek | 0:9e2fc73e5a12 | 122 | return value; |
| kyourek | 0:9e2fc73e5a12 | 123 | } |
| kyourek | 0:9e2fc73e5a12 | 124 | |
| kyourek | 0:9e2fc73e5a12 | 125 | ucBool ucTok_is_boolean(ucTok *p) { |
| kyourek | 0:9e2fc73e5a12 | 126 | int i, len; |
| kyourek | 0:9e2fc73e5a12 | 127 | const char *b[] = { ucTok_BOOLEAN_FALSE, ucTok_BOOLEAN_TRUE }; |
| kyourek | 0:9e2fc73e5a12 | 128 | if (NULL == p) return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 129 | len = sizeof(b) / sizeof(b[0]); |
| kyourek | 0:9e2fc73e5a12 | 130 | for (i = 0; i < len; i++) { |
| kyourek | 0:9e2fc73e5a12 | 131 | if (ucTok_equals(p, b[i])) { |
| kyourek | 0:9e2fc73e5a12 | 132 | return ucBool_TRUE; |
| kyourek | 0:9e2fc73e5a12 | 133 | } |
| kyourek | 0:9e2fc73e5a12 | 134 | } |
| kyourek | 0:9e2fc73e5a12 | 135 | return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 136 | } |
| kyourek | 0:9e2fc73e5a12 | 137 | |
| kyourek | 0:9e2fc73e5a12 | 138 | ucBool ucTok_try_parse_boolean(ucTok *p, ucBool *value) { |
| kyourek | 0:9e2fc73e5a12 | 139 | int i, len; |
| kyourek | 0:9e2fc73e5a12 | 140 | const char *t[] = { ucTok_BOOLEAN_TRUE }; |
| kyourek | 0:9e2fc73e5a12 | 141 | const char *f[] = { ucTok_BOOLEAN_FALSE }; |
| kyourek | 0:9e2fc73e5a12 | 142 | len = sizeof(t) / sizeof(t[0]); |
| kyourek | 0:9e2fc73e5a12 | 143 | for (i = 0; i < len; i++) { |
| kyourek | 0:9e2fc73e5a12 | 144 | if (ucTok_equals(p, t[i])) { |
| kyourek | 0:9e2fc73e5a12 | 145 | if (value) { |
| kyourek | 0:9e2fc73e5a12 | 146 | *value = ucBool_TRUE; |
| kyourek | 0:9e2fc73e5a12 | 147 | } |
| kyourek | 0:9e2fc73e5a12 | 148 | return ucBool_TRUE; |
| kyourek | 0:9e2fc73e5a12 | 149 | } |
| kyourek | 0:9e2fc73e5a12 | 150 | } |
| kyourek | 0:9e2fc73e5a12 | 151 | len = sizeof(f) / sizeof(f[0]); |
| kyourek | 0:9e2fc73e5a12 | 152 | for (i = 0; i < len; i++) { |
| kyourek | 0:9e2fc73e5a12 | 153 | if (ucTok_equals(p, f[i])) { |
| kyourek | 0:9e2fc73e5a12 | 154 | if (value) { |
| kyourek | 0:9e2fc73e5a12 | 155 | *value = ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 156 | } |
| kyourek | 0:9e2fc73e5a12 | 157 | return ucBool_TRUE; |
| kyourek | 0:9e2fc73e5a12 | 158 | } |
| kyourek | 0:9e2fc73e5a12 | 159 | } |
| kyourek | 0:9e2fc73e5a12 | 160 | return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 161 | } |
| kyourek | 0:9e2fc73e5a12 | 162 | |
| kyourek | 0:9e2fc73e5a12 | 163 | ucBool ucTok_parse_boolean(ucTok *p) { |
| kyourek | 0:9e2fc73e5a12 | 164 | ucBool value = ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 165 | ucTok_try_parse_boolean(p, &value); |
| kyourek | 0:9e2fc73e5a12 | 166 | return value; |
| kyourek | 0:9e2fc73e5a12 | 167 | } |
| kyourek | 0:9e2fc73e5a12 | 168 | |
| kyourek | 0:9e2fc73e5a12 | 169 | ucBool ucTok_is_switch(ucTok* p) { |
| kyourek | 0:9e2fc73e5a12 | 170 | int len = 0; |
| kyourek | 0:9e2fc73e5a12 | 171 | |
| kyourek | 0:9e2fc73e5a12 | 172 | /* check for a null pointer */ |
| kyourek | 0:9e2fc73e5a12 | 173 | if (NULL == p) return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 174 | |
| kyourek | 0:9e2fc73e5a12 | 175 | /* get the length so we can use it */ |
| kyourek | 0:9e2fc73e5a12 | 176 | len = ucTok_get_length(p); |
| kyourek | 0:9e2fc73e5a12 | 177 | |
| kyourek | 0:9e2fc73e5a12 | 178 | /* check for at least 2 characters (one '-' and at least another char) */ |
| kyourek | 0:9e2fc73e5a12 | 179 | if (len < 2) return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 180 | |
| kyourek | 0:9e2fc73e5a12 | 181 | /* check if it starts with a '-' */ |
| kyourek | 0:9e2fc73e5a12 | 182 | if (p[0] != '-') return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 183 | |
| kyourek | 0:9e2fc73e5a12 | 184 | /* check if this is a numeric argument (negative numbers aren't switches) */ |
| kyourek | 0:9e2fc73e5a12 | 185 | if (ucTok_is_numeric(p)) return ucBool_FALSE; |
| kyourek | 0:9e2fc73e5a12 | 186 | |
| kyourek | 0:9e2fc73e5a12 | 187 | /* ok, it's a switch */ |
| kyourek | 0:9e2fc73e5a12 | 188 | return ucBool_TRUE; |
| kyourek | 0:9e2fc73e5a12 | 189 | } |
| kyourek | 0:9e2fc73e5a12 | 190 | |
| kyourek | 0:9e2fc73e5a12 | 191 | ucTok *ucTok_get_next(ucTok *p) { |
| kyourek | 0:9e2fc73e5a12 | 192 | int i; |
| kyourek | 0:9e2fc73e5a12 | 193 | if (NULL == p) return NULL; |
| kyourek | 0:9e2fc73e5a12 | 194 | |
| kyourek | 0:9e2fc73e5a12 | 195 | /* loop until we've hit the max length */ |
| kyourek | 0:9e2fc73e5a12 | 196 | i = 0; |
| kyourek | 0:9e2fc73e5a12 | 197 | while (ucTok_LENGTH_MAX > ++i) { |
| kyourek | 0:9e2fc73e5a12 | 198 | |
| kyourek | 0:9e2fc73e5a12 | 199 | /* check if the previous character was a separator */ |
| kyourek | 0:9e2fc73e5a12 | 200 | if (ucTok_separator == p[i - 1]) { |
| kyourek | 0:9e2fc73e5a12 | 201 | |
| kyourek | 0:9e2fc73e5a12 | 202 | /* check if this character is the terminator */ |
| kyourek | 0:9e2fc73e5a12 | 203 | if (uc_cmd_terminator == p[i]) { |
| kyourek | 0:9e2fc73e5a12 | 204 | |
| kyourek | 0:9e2fc73e5a12 | 205 | /* it is, so no more tokens exist */ |
| kyourek | 0:9e2fc73e5a12 | 206 | return NULL; |
| kyourek | 0:9e2fc73e5a12 | 207 | } |
| kyourek | 0:9e2fc73e5a12 | 208 | |
| kyourek | 0:9e2fc73e5a12 | 209 | /* make sure this character isn't another separator */ |
| kyourek | 0:9e2fc73e5a12 | 210 | if (ucTok_separator == p[i]) { |
| kyourek | 0:9e2fc73e5a12 | 211 | continue; |
| kyourek | 0:9e2fc73e5a12 | 212 | } |
| kyourek | 0:9e2fc73e5a12 | 213 | |
| kyourek | 0:9e2fc73e5a12 | 214 | /* the previous character was a separator, |
| kyourek | 0:9e2fc73e5a12 | 215 | and this character is NOT the terminator, |
| kyourek | 0:9e2fc73e5a12 | 216 | OR another separator, so this character is |
| kyourek | 0:9e2fc73e5a12 | 217 | the start of a new token */ |
| kyourek | 0:9e2fc73e5a12 | 218 | return (ucTok*)&p[i]; |
| kyourek | 0:9e2fc73e5a12 | 219 | } |
| kyourek | 0:9e2fc73e5a12 | 220 | } |
| kyourek | 0:9e2fc73e5a12 | 221 | |
| kyourek | 0:9e2fc73e5a12 | 222 | /* the max length was exceeded, |
| kyourek | 0:9e2fc73e5a12 | 223 | which probably means something |
| kyourek | 0:9e2fc73e5a12 | 224 | went wrong. */ |
| kyourek | 0:9e2fc73e5a12 | 225 | return NULL; |
| kyourek | 0:9e2fc73e5a12 | 226 | } |
| kyourek | 0:9e2fc73e5a12 | 227 | |
| kyourek | 0:9e2fc73e5a12 | 228 | int ucTok_count(ucTok *p) { |
| kyourek | 0:9e2fc73e5a12 | 229 | int count; |
| kyourek | 0:9e2fc73e5a12 | 230 | |
| kyourek | 0:9e2fc73e5a12 | 231 | /* make sure we have a pointer */ |
| kyourek | 0:9e2fc73e5a12 | 232 | if (NULL == p) return 0; |
| kyourek | 0:9e2fc73e5a12 | 233 | |
| kyourek | 0:9e2fc73e5a12 | 234 | /* if the first character is the terminator, then we have no tokens */ |
| kyourek | 0:9e2fc73e5a12 | 235 | if (p[0] == uc_cmd_terminator) return 0; |
| kyourek | 0:9e2fc73e5a12 | 236 | |
| kyourek | 0:9e2fc73e5a12 | 237 | /* start off the count according to whether or not |
| kyourek | 0:9e2fc73e5a12 | 238 | we're starting at a token */ |
| kyourek | 0:9e2fc73e5a12 | 239 | count = ucTok_separator == p[0] ? -1 : 0; |
| kyourek | 0:9e2fc73e5a12 | 240 | |
| kyourek | 0:9e2fc73e5a12 | 241 | /* count the tokens in the chain */ |
| kyourek | 0:9e2fc73e5a12 | 242 | while (NULL != p) { |
| kyourek | 0:9e2fc73e5a12 | 243 | count++; |
| kyourek | 0:9e2fc73e5a12 | 244 | p = ucTok_get_next(p); |
| kyourek | 0:9e2fc73e5a12 | 245 | } |
| kyourek | 0:9e2fc73e5a12 | 246 | return count; |
| kyourek | 0:9e2fc73e5a12 | 247 | } |
| kyourek | 0:9e2fc73e5a12 | 248 |