https://github.com/j123b567/scpi-parser
Dependents: scpi_sx127x scpi_sx127x_firstTest MLX90418_I2C_master
src/utils.c@1:b497f235115a, 2015-08-07 (annotated)
- Committer:
- dudmuck
- Date:
- Fri Aug 07 21:54:11 2015 +0000
- Revision:
- 1:b497f235115a
- Parent:
- 0:aad43948c45c
update from github commit 6e5e3e0e3fc450eaf53feee059824ad85c4f270d
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
dudmuck | 0:aad43948c45c | 1 | /*- |
dudmuck | 0:aad43948c45c | 2 | * Copyright (c) 2013 Jan Breuer |
dudmuck | 0:aad43948c45c | 3 | * Richard.hmm |
dudmuck | 0:aad43948c45c | 4 | * Copyright (c) 2012 Jan Breuer |
dudmuck | 0:aad43948c45c | 5 | * |
dudmuck | 0:aad43948c45c | 6 | * All Rights Reserved |
dudmuck | 0:aad43948c45c | 7 | * |
dudmuck | 0:aad43948c45c | 8 | * Redistribution and use in source and binary forms, with or without |
dudmuck | 0:aad43948c45c | 9 | * modification, are permitted provided that the following conditions are |
dudmuck | 0:aad43948c45c | 10 | * met: |
dudmuck | 0:aad43948c45c | 11 | * 1. Redistributions of source code must retain the above copyright notice, |
dudmuck | 0:aad43948c45c | 12 | * this list of conditions and the following disclaimer. |
dudmuck | 0:aad43948c45c | 13 | * 2. Redistributions in binary form must reproduce the above copyright |
dudmuck | 0:aad43948c45c | 14 | * notice, this list of conditions and the following disclaimer in the |
dudmuck | 0:aad43948c45c | 15 | * documentation and/or other materials provided with the distribution. |
dudmuck | 0:aad43948c45c | 16 | * |
dudmuck | 0:aad43948c45c | 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR |
dudmuck | 0:aad43948c45c | 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
dudmuck | 0:aad43948c45c | 19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
dudmuck | 0:aad43948c45c | 20 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE |
dudmuck | 0:aad43948c45c | 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
dudmuck | 0:aad43948c45c | 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
dudmuck | 0:aad43948c45c | 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
dudmuck | 0:aad43948c45c | 24 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
dudmuck | 0:aad43948c45c | 25 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
dudmuck | 0:aad43948c45c | 26 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
dudmuck | 0:aad43948c45c | 27 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
dudmuck | 0:aad43948c45c | 28 | */ |
dudmuck | 0:aad43948c45c | 29 | |
dudmuck | 0:aad43948c45c | 30 | /** |
dudmuck | 0:aad43948c45c | 31 | * @file scpi_utils.c |
dudmuck | 0:aad43948c45c | 32 | * @date Thu Nov 15 10:58:45 UTC 2012 |
dudmuck | 0:aad43948c45c | 33 | * |
dudmuck | 0:aad43948c45c | 34 | * @brief Conversion routines and string manipulation routines |
dudmuck | 0:aad43948c45c | 35 | * |
dudmuck | 0:aad43948c45c | 36 | * |
dudmuck | 0:aad43948c45c | 37 | */ |
dudmuck | 0:aad43948c45c | 38 | |
dudmuck | 0:aad43948c45c | 39 | #include <stdio.h> |
dudmuck | 0:aad43948c45c | 40 | #include <stdlib.h> |
dudmuck | 0:aad43948c45c | 41 | #include <string.h> |
dudmuck | 0:aad43948c45c | 42 | #include <ctype.h> |
dudmuck | 0:aad43948c45c | 43 | |
dudmuck | 1:b497f235115a | 44 | #include "utils_private.h" |
dudmuck | 1:b497f235115a | 45 | #include "scpi/utils.h" |
dudmuck | 0:aad43948c45c | 46 | |
dudmuck | 0:aad43948c45c | 47 | static size_t patternSeparatorShortPos(const char * pattern, size_t len); |
dudmuck | 0:aad43948c45c | 48 | static size_t patternSeparatorPos(const char * pattern, size_t len); |
dudmuck | 0:aad43948c45c | 49 | static size_t cmdSeparatorPos(const char * cmd, size_t len); |
dudmuck | 0:aad43948c45c | 50 | |
dudmuck | 0:aad43948c45c | 51 | /** |
dudmuck | 0:aad43948c45c | 52 | * Find the first occurrence in str of a character in set. |
dudmuck | 0:aad43948c45c | 53 | * @param str |
dudmuck | 0:aad43948c45c | 54 | * @param size |
dudmuck | 0:aad43948c45c | 55 | * @param set |
dudmuck | 0:aad43948c45c | 56 | * @return |
dudmuck | 0:aad43948c45c | 57 | */ |
dudmuck | 1:b497f235115a | 58 | char * strnpbrk(const char *str, size_t size, const char *set) { |
dudmuck | 0:aad43948c45c | 59 | const char *scanp; |
dudmuck | 0:aad43948c45c | 60 | long c, sc; |
dudmuck | 0:aad43948c45c | 61 | const char * strend = str + size; |
dudmuck | 0:aad43948c45c | 62 | |
dudmuck | 0:aad43948c45c | 63 | while ((strend != str) && ((c = *str++) != 0)) { |
dudmuck | 0:aad43948c45c | 64 | for (scanp = set; (sc = *scanp++) != '\0';) |
dudmuck | 0:aad43948c45c | 65 | if (sc == c) |
dudmuck | 1:b497f235115a | 66 | return ((char *) (str - 1)); |
dudmuck | 0:aad43948c45c | 67 | } |
dudmuck | 0:aad43948c45c | 68 | return (NULL); |
dudmuck | 0:aad43948c45c | 69 | } |
dudmuck | 0:aad43948c45c | 70 | |
dudmuck | 0:aad43948c45c | 71 | /** |
dudmuck | 0:aad43948c45c | 72 | * Converts signed 32b integer value to string |
dudmuck | 0:aad43948c45c | 73 | * @param val integer value |
dudmuck | 0:aad43948c45c | 74 | * @param str converted textual representation |
dudmuck | 0:aad43948c45c | 75 | * @param len string buffer length |
dudmuck | 1:b497f235115a | 76 | * @param base output base |
dudmuck | 0:aad43948c45c | 77 | * @return number of bytes written to str (without '\0') |
dudmuck | 0:aad43948c45c | 78 | */ |
dudmuck | 1:b497f235115a | 79 | size_t SCPI_LongToStr(int32_t val, char * str, size_t len, int8_t base) { |
dudmuck | 1:b497f235115a | 80 | const char digits[] = "0123456789ABCDEF"; |
dudmuck | 1:b497f235115a | 81 | |
dudmuck | 1:b497f235115a | 82 | #define ADD_CHAR(c) if (pos < len) str[pos++] = (c) |
dudmuck | 1:b497f235115a | 83 | uint32_t x = 0; |
dudmuck | 0:aad43948c45c | 84 | int_fast8_t digit; |
dudmuck | 0:aad43948c45c | 85 | size_t pos = 0; |
dudmuck | 1:b497f235115a | 86 | uint32_t uval = val; |
dudmuck | 0:aad43948c45c | 87 | |
dudmuck | 1:b497f235115a | 88 | if (uval == 0) { |
dudmuck | 1:b497f235115a | 89 | ADD_CHAR('0'); |
dudmuck | 0:aad43948c45c | 90 | } else { |
dudmuck | 1:b497f235115a | 91 | |
dudmuck | 1:b497f235115a | 92 | switch (base) { |
dudmuck | 1:b497f235115a | 93 | case 2: |
dudmuck | 1:b497f235115a | 94 | x = 0x80000000L; |
dudmuck | 1:b497f235115a | 95 | break; |
dudmuck | 1:b497f235115a | 96 | case 8: |
dudmuck | 1:b497f235115a | 97 | x = 0x40000000L; |
dudmuck | 1:b497f235115a | 98 | break; |
dudmuck | 1:b497f235115a | 99 | case 10: |
dudmuck | 1:b497f235115a | 100 | x = 1000000000L; |
dudmuck | 1:b497f235115a | 101 | break; |
dudmuck | 1:b497f235115a | 102 | case 0x10: |
dudmuck | 1:b497f235115a | 103 | x = 0x10000000L; |
dudmuck | 1:b497f235115a | 104 | break; |
dudmuck | 1:b497f235115a | 105 | default: |
dudmuck | 1:b497f235115a | 106 | x = 1000000000L; |
dudmuck | 1:b497f235115a | 107 | base = 10; |
dudmuck | 1:b497f235115a | 108 | break; |
dudmuck | 0:aad43948c45c | 109 | } |
dudmuck | 0:aad43948c45c | 110 | |
dudmuck | 1:b497f235115a | 111 | // add sign for numbers in base 10 |
dudmuck | 1:b497f235115a | 112 | if ((val < 0) && (base == 10)) { |
dudmuck | 1:b497f235115a | 113 | uval = -val; |
dudmuck | 1:b497f235115a | 114 | ADD_CHAR('-'); |
dudmuck | 1:b497f235115a | 115 | } |
dudmuck | 1:b497f235115a | 116 | |
dudmuck | 1:b497f235115a | 117 | // remove leading zeros |
dudmuck | 1:b497f235115a | 118 | while ((uval / x) == 0) { |
dudmuck | 1:b497f235115a | 119 | x /= base; |
dudmuck | 0:aad43948c45c | 120 | } |
dudmuck | 0:aad43948c45c | 121 | |
dudmuck | 0:aad43948c45c | 122 | do { |
dudmuck | 1:b497f235115a | 123 | digit = (uint8_t) (uval / x); |
dudmuck | 1:b497f235115a | 124 | ADD_CHAR(digits[digit]); |
dudmuck | 1:b497f235115a | 125 | uval -= digit * x; |
dudmuck | 1:b497f235115a | 126 | x /= base; |
dudmuck | 0:aad43948c45c | 127 | } while (x && (pos < len)); |
dudmuck | 0:aad43948c45c | 128 | } |
dudmuck | 0:aad43948c45c | 129 | |
dudmuck | 0:aad43948c45c | 130 | if (pos < len) str[pos] = 0; |
dudmuck | 0:aad43948c45c | 131 | return pos; |
dudmuck | 1:b497f235115a | 132 | #undef ADD_CHAR |
dudmuck | 0:aad43948c45c | 133 | } |
dudmuck | 0:aad43948c45c | 134 | |
dudmuck | 0:aad43948c45c | 135 | /** |
dudmuck | 0:aad43948c45c | 136 | * Converts double value to string |
dudmuck | 0:aad43948c45c | 137 | * @param val double value |
dudmuck | 0:aad43948c45c | 138 | * @param str converted textual representation |
dudmuck | 0:aad43948c45c | 139 | * @param len string buffer length |
dudmuck | 0:aad43948c45c | 140 | * @return number of bytes written to str (without '\0') |
dudmuck | 0:aad43948c45c | 141 | */ |
dudmuck | 1:b497f235115a | 142 | size_t SCPI_DoubleToStr(double val, char * str, size_t len) { |
dudmuck | 1:b497f235115a | 143 | return SCPIDEFINE_doubleToStr(val, str, len); |
dudmuck | 0:aad43948c45c | 144 | } |
dudmuck | 0:aad43948c45c | 145 | |
dudmuck | 0:aad43948c45c | 146 | /** |
dudmuck | 0:aad43948c45c | 147 | * Converts string to signed 32bit integer representation |
dudmuck | 0:aad43948c45c | 148 | * @param str string value |
dudmuck | 0:aad43948c45c | 149 | * @param val 32bit integer result |
dudmuck | 0:aad43948c45c | 150 | * @return number of bytes used in string |
dudmuck | 0:aad43948c45c | 151 | */ |
dudmuck | 1:b497f235115a | 152 | size_t strToLong(const char * str, int32_t * val, int8_t base) { |
dudmuck | 0:aad43948c45c | 153 | char * endptr; |
dudmuck | 1:b497f235115a | 154 | *val = strtol(str, &endptr, base); |
dudmuck | 0:aad43948c45c | 155 | return endptr - str; |
dudmuck | 0:aad43948c45c | 156 | } |
dudmuck | 0:aad43948c45c | 157 | |
dudmuck | 0:aad43948c45c | 158 | /** |
dudmuck | 0:aad43948c45c | 159 | * Converts string to double representation |
dudmuck | 0:aad43948c45c | 160 | * @param str string value |
dudmuck | 0:aad43948c45c | 161 | * @param val double result |
dudmuck | 0:aad43948c45c | 162 | * @return number of bytes used in string |
dudmuck | 0:aad43948c45c | 163 | */ |
dudmuck | 0:aad43948c45c | 164 | size_t strToDouble(const char * str, double * val) { |
dudmuck | 0:aad43948c45c | 165 | char * endptr; |
dudmuck | 0:aad43948c45c | 166 | *val = strtod(str, &endptr); |
dudmuck | 0:aad43948c45c | 167 | return endptr - str; |
dudmuck | 0:aad43948c45c | 168 | } |
dudmuck | 0:aad43948c45c | 169 | |
dudmuck | 0:aad43948c45c | 170 | /** |
dudmuck | 0:aad43948c45c | 171 | * Compare two strings with exact length |
dudmuck | 0:aad43948c45c | 172 | * @param str1 |
dudmuck | 0:aad43948c45c | 173 | * @param len1 |
dudmuck | 0:aad43948c45c | 174 | * @param str2 |
dudmuck | 0:aad43948c45c | 175 | * @param len2 |
dudmuck | 0:aad43948c45c | 176 | * @return TRUE if len1==len2 and "len" characters of both strings are equal |
dudmuck | 0:aad43948c45c | 177 | */ |
dudmuck | 0:aad43948c45c | 178 | scpi_bool_t compareStr(const char * str1, size_t len1, const char * str2, size_t len2) { |
dudmuck | 0:aad43948c45c | 179 | if (len1 != len2) { |
dudmuck | 0:aad43948c45c | 180 | return FALSE; |
dudmuck | 0:aad43948c45c | 181 | } |
dudmuck | 0:aad43948c45c | 182 | |
dudmuck | 1:b497f235115a | 183 | if (SCPIDEFINE_strncasecmp(str1, str2, len2) == 0) { |
dudmuck | 0:aad43948c45c | 184 | return TRUE; |
dudmuck | 0:aad43948c45c | 185 | } |
dudmuck | 0:aad43948c45c | 186 | |
dudmuck | 0:aad43948c45c | 187 | return FALSE; |
dudmuck | 0:aad43948c45c | 188 | } |
dudmuck | 0:aad43948c45c | 189 | |
dudmuck | 0:aad43948c45c | 190 | /** |
dudmuck | 0:aad43948c45c | 191 | * Compare two strings, one be longer but may contains only numbers in that section |
dudmuck | 0:aad43948c45c | 192 | * @param str1 |
dudmuck | 0:aad43948c45c | 193 | * @param len1 |
dudmuck | 0:aad43948c45c | 194 | * @param str2 |
dudmuck | 0:aad43948c45c | 195 | * @param len2 |
dudmuck | 0:aad43948c45c | 196 | * @return TRUE if strings match |
dudmuck | 0:aad43948c45c | 197 | */ |
dudmuck | 1:b497f235115a | 198 | scpi_bool_t compareStrAndNum(const char * str1, size_t len1, const char * str2, size_t len2, int32_t * num) { |
dudmuck | 0:aad43948c45c | 199 | scpi_bool_t result = FALSE; |
dudmuck | 0:aad43948c45c | 200 | size_t i; |
dudmuck | 0:aad43948c45c | 201 | |
dudmuck | 0:aad43948c45c | 202 | if (len2 < len1) { |
dudmuck | 0:aad43948c45c | 203 | return FALSE; |
dudmuck | 0:aad43948c45c | 204 | } |
dudmuck | 0:aad43948c45c | 205 | |
dudmuck | 1:b497f235115a | 206 | if (SCPIDEFINE_strncasecmp(str1, str2, len1) == 0) { |
dudmuck | 0:aad43948c45c | 207 | result = TRUE; |
dudmuck | 0:aad43948c45c | 208 | |
dudmuck | 1:b497f235115a | 209 | if (num) { |
dudmuck | 1:b497f235115a | 210 | if (len1 == len2) { |
dudmuck | 1:b497f235115a | 211 | *num = 1; |
dudmuck | 1:b497f235115a | 212 | } else { |
dudmuck | 1:b497f235115a | 213 | int32_t tmpNum; |
dudmuck | 1:b497f235115a | 214 | i = len1 + strToLong(str2 + len1, &tmpNum, 10); |
dudmuck | 1:b497f235115a | 215 | if (i != len2) { |
dudmuck | 1:b497f235115a | 216 | result = FALSE; |
dudmuck | 1:b497f235115a | 217 | } else { |
dudmuck | 1:b497f235115a | 218 | *num = tmpNum; |
dudmuck | 1:b497f235115a | 219 | } |
dudmuck | 1:b497f235115a | 220 | } |
dudmuck | 1:b497f235115a | 221 | } else { |
dudmuck | 1:b497f235115a | 222 | for (i = len1; i<len2; i++) { |
dudmuck | 1:b497f235115a | 223 | if (!isdigit((int) str2[i])) { |
dudmuck | 1:b497f235115a | 224 | result = FALSE; |
dudmuck | 1:b497f235115a | 225 | break; |
dudmuck | 1:b497f235115a | 226 | } |
dudmuck | 1:b497f235115a | 227 | } |
dudmuck | 0:aad43948c45c | 228 | } |
dudmuck | 0:aad43948c45c | 229 | } |
dudmuck | 0:aad43948c45c | 230 | |
dudmuck | 0:aad43948c45c | 231 | return result; |
dudmuck | 0:aad43948c45c | 232 | } |
dudmuck | 0:aad43948c45c | 233 | |
dudmuck | 0:aad43948c45c | 234 | /** |
dudmuck | 0:aad43948c45c | 235 | * Count white spaces from the beggining |
dudmuck | 0:aad43948c45c | 236 | * @param cmd - command |
dudmuck | 0:aad43948c45c | 237 | * @param len - max search length |
dudmuck | 0:aad43948c45c | 238 | * @return number of white spaces |
dudmuck | 0:aad43948c45c | 239 | */ |
dudmuck | 0:aad43948c45c | 240 | size_t skipWhitespace(const char * cmd, size_t len) { |
dudmuck | 0:aad43948c45c | 241 | size_t i; |
dudmuck | 0:aad43948c45c | 242 | for (i = 0; i < len; i++) { |
dudmuck | 0:aad43948c45c | 243 | if (!isspace((unsigned char) cmd[i])) { |
dudmuck | 0:aad43948c45c | 244 | return i; |
dudmuck | 0:aad43948c45c | 245 | } |
dudmuck | 0:aad43948c45c | 246 | } |
dudmuck | 0:aad43948c45c | 247 | return len; |
dudmuck | 0:aad43948c45c | 248 | } |
dudmuck | 0:aad43948c45c | 249 | |
dudmuck | 0:aad43948c45c | 250 | /** |
dudmuck | 0:aad43948c45c | 251 | * Pattern is composed from upper case an lower case letters. This function |
dudmuck | 0:aad43948c45c | 252 | * search the first lowercase letter |
dudmuck | 0:aad43948c45c | 253 | * @param pattern |
dudmuck | 0:aad43948c45c | 254 | * @param len - max search length |
dudmuck | 0:aad43948c45c | 255 | * @return position of separator or len |
dudmuck | 0:aad43948c45c | 256 | */ |
dudmuck | 1:b497f235115a | 257 | static size_t patternSeparatorShortPos(const char * pattern, size_t len) { |
dudmuck | 0:aad43948c45c | 258 | size_t i; |
dudmuck | 0:aad43948c45c | 259 | for (i = 0; (i < len) && pattern[i]; i++) { |
dudmuck | 0:aad43948c45c | 260 | if (islower((unsigned char) pattern[i])) { |
dudmuck | 0:aad43948c45c | 261 | return i; |
dudmuck | 0:aad43948c45c | 262 | } |
dudmuck | 0:aad43948c45c | 263 | } |
dudmuck | 0:aad43948c45c | 264 | return i; |
dudmuck | 0:aad43948c45c | 265 | } |
dudmuck | 0:aad43948c45c | 266 | |
dudmuck | 0:aad43948c45c | 267 | /** |
dudmuck | 0:aad43948c45c | 268 | * Find pattern separator position |
dudmuck | 0:aad43948c45c | 269 | * @param pattern |
dudmuck | 0:aad43948c45c | 270 | * @param len - max search length |
dudmuck | 0:aad43948c45c | 271 | * @return position of separator or len |
dudmuck | 0:aad43948c45c | 272 | */ |
dudmuck | 1:b497f235115a | 273 | static size_t patternSeparatorPos(const char * pattern, size_t len) { |
dudmuck | 0:aad43948c45c | 274 | |
dudmuck | 1:b497f235115a | 275 | char * separator = strnpbrk(pattern, len, "?:[]"); |
dudmuck | 0:aad43948c45c | 276 | if (separator == NULL) { |
dudmuck | 0:aad43948c45c | 277 | return len; |
dudmuck | 0:aad43948c45c | 278 | } else { |
dudmuck | 0:aad43948c45c | 279 | return separator - pattern; |
dudmuck | 0:aad43948c45c | 280 | } |
dudmuck | 0:aad43948c45c | 281 | } |
dudmuck | 0:aad43948c45c | 282 | |
dudmuck | 0:aad43948c45c | 283 | /** |
dudmuck | 0:aad43948c45c | 284 | * Find command separator position |
dudmuck | 0:aad43948c45c | 285 | * @param cmd - input command |
dudmuck | 0:aad43948c45c | 286 | * @param len - max search length |
dudmuck | 0:aad43948c45c | 287 | * @return position of separator or len |
dudmuck | 0:aad43948c45c | 288 | */ |
dudmuck | 1:b497f235115a | 289 | static size_t cmdSeparatorPos(const char * cmd, size_t len) { |
dudmuck | 1:b497f235115a | 290 | char * separator = strnpbrk(cmd, len, ":?"); |
dudmuck | 0:aad43948c45c | 291 | size_t result; |
dudmuck | 0:aad43948c45c | 292 | if (separator == NULL) { |
dudmuck | 0:aad43948c45c | 293 | result = len; |
dudmuck | 0:aad43948c45c | 294 | } else { |
dudmuck | 0:aad43948c45c | 295 | result = separator - cmd; |
dudmuck | 0:aad43948c45c | 296 | } |
dudmuck | 0:aad43948c45c | 297 | |
dudmuck | 0:aad43948c45c | 298 | return result; |
dudmuck | 0:aad43948c45c | 299 | } |
dudmuck | 0:aad43948c45c | 300 | |
dudmuck | 0:aad43948c45c | 301 | /** |
dudmuck | 0:aad43948c45c | 302 | * Match pattern and str. Pattern is in format UPPERCASElowercase |
dudmuck | 0:aad43948c45c | 303 | * @param pattern |
dudmuck | 0:aad43948c45c | 304 | * @param pattern_len |
dudmuck | 0:aad43948c45c | 305 | * @param str |
dudmuck | 0:aad43948c45c | 306 | * @param str_len |
dudmuck | 0:aad43948c45c | 307 | * @return |
dudmuck | 0:aad43948c45c | 308 | */ |
dudmuck | 1:b497f235115a | 309 | scpi_bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len, int32_t * num) { |
dudmuck | 0:aad43948c45c | 310 | int pattern_sep_pos_short; |
dudmuck | 0:aad43948c45c | 311 | |
dudmuck | 0:aad43948c45c | 312 | if (pattern[pattern_len - 1] == '#') { |
dudmuck | 0:aad43948c45c | 313 | size_t new_pattern_len = pattern_len - 1; |
dudmuck | 0:aad43948c45c | 314 | |
dudmuck | 0:aad43948c45c | 315 | pattern_sep_pos_short = patternSeparatorShortPos(pattern, new_pattern_len); |
dudmuck | 0:aad43948c45c | 316 | |
dudmuck | 1:b497f235115a | 317 | return compareStrAndNum(pattern, new_pattern_len, str, str_len, num) || |
dudmuck | 1:b497f235115a | 318 | compareStrAndNum(pattern, pattern_sep_pos_short, str, str_len, num); |
dudmuck | 0:aad43948c45c | 319 | } else { |
dudmuck | 0:aad43948c45c | 320 | |
dudmuck | 0:aad43948c45c | 321 | pattern_sep_pos_short = patternSeparatorShortPos(pattern, pattern_len); |
dudmuck | 0:aad43948c45c | 322 | |
dudmuck | 0:aad43948c45c | 323 | return compareStr(pattern, pattern_len, str, str_len) || |
dudmuck | 0:aad43948c45c | 324 | compareStr(pattern, pattern_sep_pos_short, str, str_len); |
dudmuck | 0:aad43948c45c | 325 | } |
dudmuck | 0:aad43948c45c | 326 | } |
dudmuck | 0:aad43948c45c | 327 | |
dudmuck | 0:aad43948c45c | 328 | /** |
dudmuck | 0:aad43948c45c | 329 | * Compare pattern and command |
dudmuck | 0:aad43948c45c | 330 | * @param pattern eg. [:MEASure]:VOLTage:DC? |
dudmuck | 0:aad43948c45c | 331 | * @param cmd - command |
dudmuck | 0:aad43948c45c | 332 | * @param len - max search length |
dudmuck | 0:aad43948c45c | 333 | * @return TRUE if pattern matches, FALSE otherwise |
dudmuck | 0:aad43948c45c | 334 | */ |
dudmuck | 1:b497f235115a | 335 | scpi_bool_t matchCommand(const char * pattern, const char * cmd, size_t len, int32_t *numbers, size_t numbers_len) { |
dudmuck | 0:aad43948c45c | 336 | scpi_bool_t result = FALSE; |
dudmuck | 0:aad43948c45c | 337 | int leftFlag = 0; // flag for '[' on left |
dudmuck | 0:aad43948c45c | 338 | int rightFlag = 0; // flag for ']' on right |
dudmuck | 0:aad43948c45c | 339 | int cmd_sep_pos = 0; |
dudmuck | 0:aad43948c45c | 340 | |
dudmuck | 1:b497f235115a | 341 | size_t numbers_idx = 0; |
dudmuck | 1:b497f235115a | 342 | int32_t *number_ptr = NULL; |
dudmuck | 1:b497f235115a | 343 | |
dudmuck | 0:aad43948c45c | 344 | const char * pattern_ptr = pattern; |
dudmuck | 0:aad43948c45c | 345 | int pattern_len = strlen(pattern); |
dudmuck | 0:aad43948c45c | 346 | const char * pattern_end = pattern + pattern_len; |
dudmuck | 0:aad43948c45c | 347 | |
dudmuck | 0:aad43948c45c | 348 | const char * cmd_ptr = cmd; |
dudmuck | 1:b497f235115a | 349 | size_t cmd_len = SCPIDEFINE_strnlen(cmd, len); |
dudmuck | 0:aad43948c45c | 350 | const char * cmd_end = cmd + cmd_len; |
dudmuck | 0:aad43948c45c | 351 | |
dudmuck | 0:aad43948c45c | 352 | /* now support optional keywords in pattern style, e.g. [:MEASure]:VOLTage:DC? */ |
dudmuck | 0:aad43948c45c | 353 | if (pattern_ptr[0] == '[') { // skip first '[' |
dudmuck | 0:aad43948c45c | 354 | pattern_len--; |
dudmuck | 0:aad43948c45c | 355 | pattern_ptr++; |
dudmuck | 0:aad43948c45c | 356 | leftFlag++; |
dudmuck | 0:aad43948c45c | 357 | } |
dudmuck | 0:aad43948c45c | 358 | if (pattern_ptr[0] == ':') { // skip first ':' |
dudmuck | 0:aad43948c45c | 359 | pattern_len--; |
dudmuck | 0:aad43948c45c | 360 | pattern_ptr++; |
dudmuck | 0:aad43948c45c | 361 | } |
dudmuck | 0:aad43948c45c | 362 | |
dudmuck | 0:aad43948c45c | 363 | if (cmd_ptr[0] == ':') { |
dudmuck | 0:aad43948c45c | 364 | /* handle errornouse ":*IDN?" */ |
dudmuck | 1:b497f235115a | 365 | if ((cmd_len >= 2) && (cmd_ptr[1] != '*')) { |
dudmuck | 0:aad43948c45c | 366 | cmd_len--; |
dudmuck | 0:aad43948c45c | 367 | cmd_ptr++; |
dudmuck | 0:aad43948c45c | 368 | } |
dudmuck | 0:aad43948c45c | 369 | } |
dudmuck | 0:aad43948c45c | 370 | |
dudmuck | 0:aad43948c45c | 371 | while (1) { |
dudmuck | 0:aad43948c45c | 372 | int pattern_sep_pos = patternSeparatorPos(pattern_ptr, pattern_end - pattern_ptr); |
dudmuck | 0:aad43948c45c | 373 | |
dudmuck | 0:aad43948c45c | 374 | if ((leftFlag > 0) && (rightFlag > 0)) { |
dudmuck | 0:aad43948c45c | 375 | leftFlag--; |
dudmuck | 0:aad43948c45c | 376 | rightFlag--; |
dudmuck | 0:aad43948c45c | 377 | } else { |
dudmuck | 0:aad43948c45c | 378 | cmd_sep_pos = cmdSeparatorPos(cmd_ptr, cmd_end - cmd_ptr); |
dudmuck | 0:aad43948c45c | 379 | } |
dudmuck | 0:aad43948c45c | 380 | |
dudmuck | 1:b497f235115a | 381 | if (pattern_ptr[pattern_sep_pos - 1] == '#') { |
dudmuck | 1:b497f235115a | 382 | if (numbers && (numbers_idx < numbers_len)) { |
dudmuck | 1:b497f235115a | 383 | number_ptr = numbers + numbers_idx; |
dudmuck | 1:b497f235115a | 384 | *number_ptr = 1; // default value |
dudmuck | 1:b497f235115a | 385 | } else { |
dudmuck | 1:b497f235115a | 386 | number_ptr = NULL; |
dudmuck | 1:b497f235115a | 387 | } |
dudmuck | 1:b497f235115a | 388 | numbers_idx++; |
dudmuck | 1:b497f235115a | 389 | } else { |
dudmuck | 1:b497f235115a | 390 | number_ptr = NULL; |
dudmuck | 1:b497f235115a | 391 | } |
dudmuck | 1:b497f235115a | 392 | |
dudmuck | 1:b497f235115a | 393 | if (matchPattern(pattern_ptr, pattern_sep_pos, cmd_ptr, cmd_sep_pos, number_ptr)) { |
dudmuck | 0:aad43948c45c | 394 | pattern_ptr = pattern_ptr + pattern_sep_pos; |
dudmuck | 0:aad43948c45c | 395 | cmd_ptr = cmd_ptr + cmd_sep_pos; |
dudmuck | 0:aad43948c45c | 396 | result = TRUE; |
dudmuck | 0:aad43948c45c | 397 | |
dudmuck | 0:aad43948c45c | 398 | /* command is complete */ |
dudmuck | 0:aad43948c45c | 399 | if ((pattern_ptr == pattern_end) && (cmd_ptr >= cmd_end)) { |
dudmuck | 0:aad43948c45c | 400 | break; |
dudmuck | 0:aad43948c45c | 401 | } |
dudmuck | 0:aad43948c45c | 402 | |
dudmuck | 0:aad43948c45c | 403 | /* pattern complete, but command not */ |
dudmuck | 0:aad43948c45c | 404 | if ((pattern_ptr == pattern_end) && (cmd_ptr < cmd_end)) { |
dudmuck | 0:aad43948c45c | 405 | result = FALSE; |
dudmuck | 0:aad43948c45c | 406 | break; |
dudmuck | 0:aad43948c45c | 407 | } |
dudmuck | 0:aad43948c45c | 408 | |
dudmuck | 0:aad43948c45c | 409 | /* command complete, but pattern not */ |
dudmuck | 0:aad43948c45c | 410 | if (cmd_ptr >= cmd_end) { |
dudmuck | 0:aad43948c45c | 411 | if (cmd_end == cmd_ptr) { |
dudmuck | 0:aad43948c45c | 412 | if (cmd_ptr[0] == pattern_ptr[pattern_end - pattern_ptr - 1]) { |
dudmuck | 0:aad43948c45c | 413 | break; /* exist optional keyword, command is complete */ |
dudmuck | 0:aad43948c45c | 414 | } |
dudmuck | 0:aad43948c45c | 415 | if (']' == pattern_ptr[pattern_end - pattern_ptr - 1]) { |
dudmuck | 0:aad43948c45c | 416 | break; /* exist optional keyword, command is complete */ |
dudmuck | 0:aad43948c45c | 417 | } |
dudmuck | 0:aad43948c45c | 418 | } |
dudmuck | 0:aad43948c45c | 419 | result = FALSE; |
dudmuck | 0:aad43948c45c | 420 | break; |
dudmuck | 0:aad43948c45c | 421 | } |
dudmuck | 0:aad43948c45c | 422 | |
dudmuck | 0:aad43948c45c | 423 | /* both command and patter contains command separator at this position */ |
dudmuck | 0:aad43948c45c | 424 | if ((pattern_ptr[0] == cmd_ptr[0]) && ((pattern_ptr[0] == ':') || (pattern_ptr[0] == '?'))) { |
dudmuck | 0:aad43948c45c | 425 | pattern_ptr = pattern_ptr + 1; |
dudmuck | 0:aad43948c45c | 426 | cmd_ptr = cmd_ptr + 1; |
dudmuck | 0:aad43948c45c | 427 | } else if ((pattern_ptr[1] == cmd_ptr[0]) |
dudmuck | 0:aad43948c45c | 428 | && (pattern_ptr[0] == '[') |
dudmuck | 0:aad43948c45c | 429 | && (pattern_ptr[1] == ':')) { |
dudmuck | 0:aad43948c45c | 430 | pattern_ptr = pattern_ptr + 2; // for skip '[' in "[:" |
dudmuck | 0:aad43948c45c | 431 | cmd_ptr = cmd_ptr + 1; |
dudmuck | 0:aad43948c45c | 432 | leftFlag++; |
dudmuck | 0:aad43948c45c | 433 | } else if ((pattern_ptr[1] == cmd_ptr[0]) |
dudmuck | 0:aad43948c45c | 434 | && (pattern_ptr[0] == ']') |
dudmuck | 0:aad43948c45c | 435 | && (pattern_ptr[1] == ':')) { |
dudmuck | 0:aad43948c45c | 436 | pattern_ptr = pattern_ptr + 2; // for skip ']' in "]:" |
dudmuck | 0:aad43948c45c | 437 | cmd_ptr = cmd_ptr + 1; |
dudmuck | 0:aad43948c45c | 438 | } else if ((pattern_ptr[2] == cmd_ptr[0]) |
dudmuck | 0:aad43948c45c | 439 | && (pattern_ptr[0] == ']') |
dudmuck | 0:aad43948c45c | 440 | && (pattern_ptr[1] == '[') |
dudmuck | 0:aad43948c45c | 441 | && (pattern_ptr[2] == ':')) { |
dudmuck | 0:aad43948c45c | 442 | pattern_ptr = pattern_ptr + 3; // for skip '][' in "][:" |
dudmuck | 0:aad43948c45c | 443 | cmd_ptr = cmd_ptr + 1; |
dudmuck | 0:aad43948c45c | 444 | leftFlag++; |
dudmuck | 0:aad43948c45c | 445 | } else if (((pattern_ptr[0] == ']') |
dudmuck | 0:aad43948c45c | 446 | || (pattern_ptr[0] == '[')) |
dudmuck | 0:aad43948c45c | 447 | && (*(pattern_end - 1) == '?') // last is '?' |
dudmuck | 0:aad43948c45c | 448 | && (cmd_ptr[0] == '?')) { |
dudmuck | 0:aad43948c45c | 449 | result = TRUE; // exist optional keyword, and they are end with '?' |
dudmuck | 0:aad43948c45c | 450 | break; // command is complete OK |
dudmuck | 0:aad43948c45c | 451 | } else { |
dudmuck | 0:aad43948c45c | 452 | result = FALSE; |
dudmuck | 0:aad43948c45c | 453 | break; |
dudmuck | 0:aad43948c45c | 454 | } |
dudmuck | 0:aad43948c45c | 455 | } else { |
dudmuck | 0:aad43948c45c | 456 | pattern_ptr = pattern_ptr + pattern_sep_pos; |
dudmuck | 0:aad43948c45c | 457 | if ((pattern_ptr[0] == ']') && (pattern_ptr[1] == ':')) { |
dudmuck | 0:aad43948c45c | 458 | pattern_ptr = pattern_ptr + 2; // for skip ']' in "]:" , pattern_ptr continue, while cmd_ptr remain unchanged |
dudmuck | 0:aad43948c45c | 459 | rightFlag++; |
dudmuck | 0:aad43948c45c | 460 | } else if ((pattern_ptr[0] == ']') |
dudmuck | 0:aad43948c45c | 461 | && (pattern_ptr[1] == '[') |
dudmuck | 0:aad43948c45c | 462 | && (pattern_ptr[2] == ':')) { |
dudmuck | 0:aad43948c45c | 463 | pattern_ptr = pattern_ptr + 3; // for skip ']' in "][:" , pattern_ptr continue, while cmd_ptr remain unchanged |
dudmuck | 0:aad43948c45c | 464 | rightFlag++; |
dudmuck | 0:aad43948c45c | 465 | } else { |
dudmuck | 0:aad43948c45c | 466 | result = FALSE; |
dudmuck | 0:aad43948c45c | 467 | break; |
dudmuck | 0:aad43948c45c | 468 | } |
dudmuck | 0:aad43948c45c | 469 | } |
dudmuck | 0:aad43948c45c | 470 | } |
dudmuck | 0:aad43948c45c | 471 | |
dudmuck | 0:aad43948c45c | 472 | return result; |
dudmuck | 0:aad43948c45c | 473 | } |
dudmuck | 0:aad43948c45c | 474 | |
dudmuck | 0:aad43948c45c | 475 | /** |
dudmuck | 0:aad43948c45c | 476 | * Compose command from previsou command anc current command |
dudmuck | 1:b497f235115a | 477 | * |
dudmuck | 1:b497f235115a | 478 | * @param prev pointer to previous command |
dudmuck | 1:b497f235115a | 479 | * @param current pointer of current command |
dudmuck | 1:b497f235115a | 480 | * |
dudmuck | 1:b497f235115a | 481 | * prev and current should be in the same memory buffer |
dudmuck | 0:aad43948c45c | 482 | */ |
dudmuck | 1:b497f235115a | 483 | scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current) { |
dudmuck | 0:aad43948c45c | 484 | size_t i; |
dudmuck | 0:aad43948c45c | 485 | |
dudmuck | 0:aad43948c45c | 486 | /* Invalid input */ |
dudmuck | 1:b497f235115a | 487 | if (current == NULL || current->ptr == NULL || current->len == 0) |
dudmuck | 0:aad43948c45c | 488 | return FALSE; |
dudmuck | 0:aad43948c45c | 489 | |
dudmuck | 0:aad43948c45c | 490 | /* no previous command - nothing to do*/ |
dudmuck | 1:b497f235115a | 491 | if (prev->ptr == NULL || prev->len == 0) |
dudmuck | 0:aad43948c45c | 492 | return TRUE; |
dudmuck | 1:b497f235115a | 493 | |
dudmuck | 0:aad43948c45c | 494 | /* Common command or command root - nothing to do */ |
dudmuck | 1:b497f235115a | 495 | if (current->ptr[0] == '*' || current->ptr[0] == ':') |
dudmuck | 0:aad43948c45c | 496 | return TRUE; |
dudmuck | 1:b497f235115a | 497 | |
dudmuck | 0:aad43948c45c | 498 | /* Previsou command was common command - nothing to do */ |
dudmuck | 1:b497f235115a | 499 | if (prev->ptr[0] == '*') |
dudmuck | 0:aad43948c45c | 500 | return TRUE; |
dudmuck | 1:b497f235115a | 501 | |
dudmuck | 0:aad43948c45c | 502 | /* Find last occurence of ':' */ |
dudmuck | 1:b497f235115a | 503 | for (i = prev->len; i > 0; i--) { |
dudmuck | 1:b497f235115a | 504 | if (prev->ptr[i - 1] == ':') { |
dudmuck | 0:aad43948c45c | 505 | break; |
dudmuck | 0:aad43948c45c | 506 | } |
dudmuck | 0:aad43948c45c | 507 | } |
dudmuck | 1:b497f235115a | 508 | |
dudmuck | 0:aad43948c45c | 509 | /* Previous command was simple command - nothing to do*/ |
dudmuck | 0:aad43948c45c | 510 | if (i == 0) |
dudmuck | 0:aad43948c45c | 511 | return TRUE; |
dudmuck | 1:b497f235115a | 512 | |
dudmuck | 1:b497f235115a | 513 | current->ptr -= i; |
dudmuck | 1:b497f235115a | 514 | current->len += i; |
dudmuck | 1:b497f235115a | 515 | memmove(current->ptr, prev->ptr, i); |
dudmuck | 0:aad43948c45c | 516 | return TRUE; |
dudmuck | 0:aad43948c45c | 517 | } |
dudmuck | 0:aad43948c45c | 518 | |
dudmuck | 0:aad43948c45c | 519 | |
dudmuck | 0:aad43948c45c | 520 | |
dudmuck | 0:aad43948c45c | 521 | #if !HAVE_STRNLEN |
dudmuck | 0:aad43948c45c | 522 | /* use FreeBSD strnlen */ |
dudmuck | 0:aad43948c45c | 523 | |
dudmuck | 0:aad43948c45c | 524 | /*- |
dudmuck | 0:aad43948c45c | 525 | * Copyright (c) 2009 David Schultz <das@FreeBSD.org> |
dudmuck | 0:aad43948c45c | 526 | * All rights reserved. |
dudmuck | 0:aad43948c45c | 527 | */ |
dudmuck | 0:aad43948c45c | 528 | size_t |
dudmuck | 0:aad43948c45c | 529 | BSD_strnlen(const char *s, size_t maxlen) { |
dudmuck | 0:aad43948c45c | 530 | size_t len; |
dudmuck | 0:aad43948c45c | 531 | |
dudmuck | 0:aad43948c45c | 532 | for (len = 0; len < maxlen; len++, s++) { |
dudmuck | 0:aad43948c45c | 533 | if (!*s) |
dudmuck | 0:aad43948c45c | 534 | break; |
dudmuck | 0:aad43948c45c | 535 | } |
dudmuck | 0:aad43948c45c | 536 | return (len); |
dudmuck | 0:aad43948c45c | 537 | } |
dudmuck | 0:aad43948c45c | 538 | #endif |
dudmuck | 0:aad43948c45c | 539 | |
dudmuck | 0:aad43948c45c | 540 | #if !HAVE_STRNCASECMP && !HAVE_STRNICMP |
dudmuck | 1:b497f235115a | 541 | |
dudmuck | 0:aad43948c45c | 542 | int OUR_strncasecmp(const char *s1, const char *s2, size_t n) { |
dudmuck | 0:aad43948c45c | 543 | unsigned char c1, c2; |
dudmuck | 0:aad43948c45c | 544 | |
dudmuck | 1:b497f235115a | 545 | for (; n != 0; n--) { |
dudmuck | 1:b497f235115a | 546 | c1 = tolower((unsigned char) *s1++); |
dudmuck | 1:b497f235115a | 547 | c2 = tolower((unsigned char) *s2++); |
dudmuck | 0:aad43948c45c | 548 | if (c1 != c2) { |
dudmuck | 0:aad43948c45c | 549 | return c1 - c2; |
dudmuck | 0:aad43948c45c | 550 | } |
dudmuck | 1:b497f235115a | 551 | if (c1 == '\0') { |
dudmuck | 0:aad43948c45c | 552 | return 0; |
dudmuck | 0:aad43948c45c | 553 | } |
dudmuck | 0:aad43948c45c | 554 | } |
dudmuck | 0:aad43948c45c | 555 | return 0; |
dudmuck | 0:aad43948c45c | 556 | } |
dudmuck | 0:aad43948c45c | 557 | #endif |