https://github.com/j123b567/scpi-parser

Dependents:   scpi_sx127x scpi_sx127x_firstTest MLX90418_I2C_master

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?

UserRevisionLine numberNew 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