From 007889b4128e8656c55ba31404a698e98719c262 Mon Sep 17 00:00:00 2001 From: Jan Breuer <jan.breuer@mobatime.cz> Date: 周六, 14 7月 2018 01:57:31 +0800 Subject: [PATCH] Fix license wordings to correspond with BSD-2-Clause --- libscpi/src/utils.c | 1171 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 985 insertions(+), 186 deletions(-) diff --git a/libscpi/src/utils.c b/libscpi/src/utils.c index 9f9e2e7..328f8be 100644 --- a/libscpi/src/utils.c +++ b/libscpi/src/utils.c @@ -1,54 +1,59 @@ /*- - * Copyright (c) 2012-2013 Jan Breuer, + * BSD 2-Clause License * - * All Rights Reserved - * + * Copyright (c) 2012-2018, Jan Breuer, Richard.hmm + * All rights reserved. + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @file scpi_utils.c * @date Thu Nov 15 10:58:45 UTC 2012 - * + * * @brief Conversion routines and string manipulation routines - * - * + * + * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> +#include <math.h> -#include "utils.h" +#include "utils_private.h" +#include "scpi/utils.h" static size_t patternSeparatorShortPos(const char * pattern, size_t len); +static size_t patternSeparatorPos(const char * pattern, size_t len); +static size_t cmdSeparatorPos(const char * cmd, size_t len); /** * Find the first occurrence in str of a character in set. * @param str * @param size * @param set - * @return + * @return */ char * strnpbrk(const char *str, size_t size, const char *set) { const char *scanp; @@ -64,50 +69,199 @@ } /** - * Converts signed 32b integer value to string + * Converts signed/unsigned 32 bit integer value to string in specific base * @param val integer value * @param str converted textual representation * @param len string buffer length + * @param base output base + * @param sign * @return number of bytes written to str (without '\0') */ -size_t longToStr(int32_t val, char * str, size_t len) { - uint32_t x = 1000000000L; +size_t UInt32ToStrBaseSign(uint32_t val, char * str, size_t len, int8_t base, scpi_bool_t sign) { + const char digits[] = "0123456789ABCDEF"; + +#define ADD_CHAR(c) if (pos < len) str[pos++] = (c) + uint32_t x = 0; int_fast8_t digit; size_t pos = 0; + uint32_t uval = val; - if (val == 0) { - if (pos < len) str[pos++] = '0'; + if (uval == 0) { + ADD_CHAR('0'); } else { - if (val < 0) { - val = -val; - if (pos < len) str[pos++] = '-'; + + switch (base) { + case 2: + x = 0x80000000L; + break; + case 8: + x = 0x40000000L; + break; + default: + case 10: + base = 10; + x = 1000000000L; + break; + case 16: + x = 0x10000000L; + break; } - while ((val / x) == 0) { - x /= 10; + /* add sign for numbers in base 10 */ + if (sign && ((int32_t) val < 0) && (base == 10)) { + uval = -val; + ADD_CHAR('-'); + } + + /* remove leading zeros */ + while ((uval / x) == 0) { + x /= base; } do { - digit = (uint8_t) (val / x); - if (pos < len) str[pos++] = digit + '0'; - val -= digit * x; - x /= 10; + digit = (uint8_t) (uval / x); + ADD_CHAR(digits[digit]); + uval -= digit * x; + x /= base; } while (x && (pos < len)); } if (pos < len) str[pos] = 0; return pos; +#undef ADD_CHAR } /** - * Converts double value to string + * Converts signed 32 bit integer value to string + * @param val integer value + * @param str converted textual representation + * @param len string buffer length + * @return number of bytes written to str (without '\0') + */ +size_t SCPI_Int32ToStr(int32_t val, char * str, size_t len) { + return UInt32ToStrBaseSign((uint32_t) val, str, len, 10, TRUE); +} + +/** + * Converts unsigned 32 bit integer value to string in specific base + * @param val integer value + * @param str converted textual representation + * @param len string buffer length + * @param base output base + * @return number of bytes written to str (without '\0') + */ +size_t SCPI_UInt32ToStrBase(uint32_t val, char * str, size_t len, int8_t base) { + return UInt32ToStrBaseSign(val, str, len, base, FALSE); +} + +/** + * Converts signed/unsigned 64 bit integer value to string in specific base + * @param val integer value + * @param str converted textual representation + * @param len string buffer length + * @param base output base + * @param sign + * @return number of bytes written to str (without '\0') + */ +size_t UInt64ToStrBaseSign(uint64_t val, char * str, size_t len, int8_t base, scpi_bool_t sign) { + const char digits[] = "0123456789ABCDEF"; + +#define ADD_CHAR(c) if (pos < len) str[pos++] = (c) + uint64_t x = 0; + int_fast8_t digit; + size_t pos = 0; + uint64_t uval = val; + + if (uval == 0) { + ADD_CHAR('0'); + } else { + + switch (base) { + case 2: + x = 0x8000000000000000ULL; + break; + case 8: + x = 0x8000000000000000ULL; + break; + default: + case 10: + x = 10000000000000000000ULL; + base = 10; + break; + case 16: + x = 0x1000000000000000ULL; + break; + } + + /* add sign for numbers in base 10 */ + if (sign && ((int64_t) val < 0) && (base == 10)) { + uval = -val; + ADD_CHAR('-'); + } + + /* remove leading zeros */ + while ((uval / x) == 0) { + x /= base; + } + + do { + digit = (uint8_t) (uval / x); + ADD_CHAR(digits[digit]); + uval -= digit * x; + x /= base; + } while (x && (pos < len)); + } + + if (pos < len) str[pos] = 0; + return pos; +#undef ADD_CHAR +} + +/** + * Converts signed 64 bit integer value to string + * @param val integer value + * @param str converted textual representation + * @param len string buffer length + * @return number of bytes written to str (without '\0') + */ +size_t SCPI_Int64ToStr(int64_t val, char * str, size_t len) { + return UInt64ToStrBaseSign((uint64_t) val, str, len, 10, TRUE); +} + +/** + * Converts signed/unsigned 64 bit integer value to string in specific base + * @param val integer value + * @param str converted textual representation + * @param len string buffer length + * @param base output base + * @return number of bytes written to str (without '\0') + */ +size_t SCPI_UInt64ToStrBase(uint64_t val, char * str, size_t len, int8_t base) { + return UInt64ToStrBaseSign(val, str, len, base, FALSE); +} + +/** + * Converts float (32 bit) value to string + * @param val long value + * @param str converted textual representation + * @param len string buffer length + * @return number of bytes written to str (without '\0') + */ +size_t SCPI_FloatToStr(float val, char * str, size_t len) { + SCPIDEFINE_floatToStr(val, str, len); + return strlen(str); +} + +/** + * Converts double (64 bit) value to string * @param val double value * @param str converted textual representation * @param len string buffer length * @return number of bytes written to str (without '\0') */ -size_t doubleToStr(double val, char * str, size_t len) { - return snprintf(str, len, "%lg", val); +size_t SCPI_DoubleToStr(double val, char * str, size_t len) { + SCPIDEFINE_doubleToStr(val, str, len); + return strlen(str); } /** @@ -116,14 +270,62 @@ * @param val 32bit integer result * @return number of bytes used in string */ -size_t strToLong(const char * str, int32_t * val) { +size_t strBaseToInt32(const char * str, int32_t * val, int8_t base) { char * endptr; - *val = strtol(str, &endptr, 0); + *val = strtol(str, &endptr, base); return endptr - str; } /** - * Converts string to double representation + * Converts string to unsigned 32bit integer representation + * @param str string value + * @param val 32bit integer result + * @return number of bytes used in string + */ +size_t strBaseToUInt32(const char * str, uint32_t * val, int8_t base) { + char * endptr; + *val = strtoul(str, &endptr, base); + return endptr - str; +} + +/** + * Converts string to signed 64bit integer representation + * @param str string value + * @param val 64bit integer result + * @return number of bytes used in string + */ +size_t strBaseToInt64(const char * str, int64_t * val, int8_t base) { + char * endptr; + *val = SCPIDEFINE_strtoll(str, &endptr, base); + return endptr - str; +} + +/** + * Converts string to unsigned 64bit integer representation + * @param str string value + * @param val 64bit integer result + * @return number of bytes used in string + */ +size_t strBaseToUInt64(const char * str, uint64_t * val, int8_t base) { + char * endptr; + *val = SCPIDEFINE_strtoull(str, &endptr, base); + return endptr - str; +} + +/** + * Converts string to float (32 bit) representation + * @param str string value + * @param val float result + * @return number of bytes used in string + */ +size_t strToFloat(const char * str, float * val) { + char * endptr; + *val = SCPIDEFINE_strtof(str, &endptr); + return endptr - str; +} + +/** + * Converts string to double (64 bit) representation * @param str string value * @param val double result * @return number of bytes used in string @@ -142,156 +344,60 @@ * @param len2 * @return TRUE if len1==len2 and "len" characters of both strings are equal */ -bool_t compareStr(const char * str1, size_t len1, const char * str2, size_t len2) { +scpi_bool_t compareStr(const char * str1, size_t len1, const char * str2, size_t len2) { if (len1 != len2) { return FALSE; } - if (strncasecmp(str1, str2, len2) == 0) { + if (SCPIDEFINE_strncasecmp(str1, str2, len2) == 0) { return TRUE; } return FALSE; } -bool_t locateText(const char * str1, size_t len1, char ** str2, size_t * len2) { +/** + * Compare two strings, one be longer but may contains only numbers in that section + * @param str1 + * @param len1 + * @param str2 + * @param len2 + * @return TRUE if strings match + */ +scpi_bool_t compareStrAndNum(const char * str1, size_t len1, const char * str2, size_t len2, int32_t * num) { + scpi_bool_t result = FALSE; size_t i; - int quot = 0; - int32_t strStart = -1; - int32_t strStop = -1; - int valid = 0; - - for (i = 0; i < len1; i++) { - if ((strStart < 0) && isspace(str1[i])) { - continue; - } - - if ((strStart < 0) && !quot && (str1[i] == '"')) { - quot = 1; - continue; - } - - if (strStart < 0) { - strStart = i; - } - - if ((strStop < 0) && quot && (str1[i] == '"')) { - strStop = i; - valid = 1; - continue; - } - - if ((strStop >= 0) && quot && (str1[i] == ',')) { - break; - } - - if ((strStop >= 0) && quot && !isspace(str1[i])) { - valid = 0; - } - - if (!quot && !isspace(str1[i]) && (str1[i] != ',')) { - strStop = i; - } - - if (isspace(str1[i])) { - continue; - } - - if ((strStop >= 0) && (str1[i] == ',')) { - valid = 1; - break; - } + if (len2 < len1) { + return FALSE; } - if ((i == len1) && !quot) { - valid = 1; - if (strStop < 0) { - strStop = i; - } else { - strStop++; - } - if (strStart < 0) { - strStart = i; - } - } else if (!quot) { - strStop++; - } + if (SCPIDEFINE_strncasecmp(str1, str2, len1) == 0) { + result = TRUE; - - if (valid) { - if (str2) { - *str2 = (char *) &str1[strStart]; - } - - if (len2) { - *len2 = strStop - strStart; - } - } - - return valid; -} - -bool_t locateStr(const char * str1, size_t len1, char ** str2, size_t * len2) { - size_t i; - int32_t strStart = -1; - int32_t strStop = -1; - int valid = 0; - - - for (i = 0; i < len1; i++) { - if ((strStart < 0) && isspace(str1[i])) { - continue; - } - - if (strStart < 0) { - strStart = i; - } - - if (!isspace(str1[i]) && (str1[i] != ',')) { - strStop = i; - } - - if (isspace(str1[i])) { - continue; - } - - if (str1[i] == ',') { - valid = 1; - - if (strStop < 0) { - strStop = i; + if (num) { + if (len1 == len2) { + /* *num = 1; */ + } else { + int32_t tmpNum; + i = len1 + strBaseToInt32(str2 + len1, &tmpNum, 10); + if (i != len2) { + result = FALSE; + } else { + *num = tmpNum; + } } - break; - } - } - - if (i == len1) { - valid = 1; - if (strStop < 0) { - strStop = i; } else { - strStop++; - } - if (strStart < 0) { - strStart = i; - } - } else { - strStop++; - } - - - if (valid) { - if (str2) { - *str2 = (char *) &str1[strStart]; - } - - if (len2) { - *len2 = strStop - strStart; + for (i = len1; i < len2; i++) { + if (!isdigit((int) str2[i])) { + result = FALSE; + break; + } + } } } - return valid; + return result; } /** @@ -303,13 +409,12 @@ size_t skipWhitespace(const char * cmd, size_t len) { size_t i; for (i = 0; i < len; i++) { - if (!isspace(cmd[i])) { + if (!isspace((unsigned char) cmd[i])) { return i; } } return len; } - /** * Pattern is composed from upper case an lower case letters. This function @@ -318,14 +423,48 @@ * @param len - max search length * @return position of separator or len */ -size_t patternSeparatorShortPos(const char * pattern, size_t len) { +static size_t patternSeparatorShortPos(const char * pattern, size_t len) { size_t i; for (i = 0; (i < len) && pattern[i]; i++) { - if (islower(pattern[i])) { + if (islower((unsigned char) pattern[i])) { return i; } } return i; +} + +/** + * Find pattern separator position + * @param pattern + * @param len - max search length + * @return position of separator or len + */ +static size_t patternSeparatorPos(const char * pattern, size_t len) { + + char * separator = strnpbrk(pattern, len, "?:[]"); + if (separator == NULL) { + return len; + } else { + return separator - pattern; + } +} + +/** + * Find command separator position + * @param cmd - input command + * @param len - max search length + * @return position of separator or len + */ +static size_t cmdSeparatorPos(const char * cmd, size_t len) { + char * separator = strnpbrk(cmd, len, ":?"); + size_t result; + if (separator == NULL) { + result = len; + } else { + result = separator - cmd; + } + + return result; } /** @@ -334,10 +473,670 @@ * @param pattern_len * @param str * @param str_len - * @return + * @return */ -bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len) { - int pattern_sep_pos_short = patternSeparatorShortPos(pattern, pattern_len); - return compareStr(pattern, pattern_len, str, str_len) || - compareStr(pattern, pattern_sep_pos_short, str, str_len); +scpi_bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len, int32_t * num) { + int pattern_sep_pos_short; + + if ((pattern_len > 0) && pattern[pattern_len - 1] == '#') { + size_t new_pattern_len = pattern_len - 1; + + pattern_sep_pos_short = patternSeparatorShortPos(pattern, new_pattern_len); + + return compareStrAndNum(pattern, new_pattern_len, str, str_len, num) || + compareStrAndNum(pattern, pattern_sep_pos_short, str, str_len, num); + } else { + + pattern_sep_pos_short = patternSeparatorShortPos(pattern, pattern_len); + + return compareStr(pattern, pattern_len, str, str_len) || + compareStr(pattern, pattern_sep_pos_short, str, str_len); + } +} + +/** + * Compare pattern and command + * @param pattern eg. [:MEASure]:VOLTage:DC? + * @param cmd - command + * @param len - max search length + * @return TRUE if pattern matches, FALSE otherwise + */ +scpi_bool_t matchCommand(const char * pattern, const char * cmd, size_t len, int32_t *numbers, size_t numbers_len, int32_t default_value) { +#define SKIP_PATTERN(n) do {pattern_ptr += (n); pattern_len -= (n);} while(0) +#define SKIP_CMD(n) do {cmd_ptr += (n); cmd_len -= (n);} while(0) + + scpi_bool_t result = FALSE; + int brackets = 0; + int cmd_sep_pos = 0; + + size_t numbers_idx = 0; + int32_t *number_ptr = NULL; + + const char * pattern_ptr = pattern; + int pattern_len = strlen(pattern); + + const char * cmd_ptr = cmd; + size_t cmd_len = SCPIDEFINE_strnlen(cmd, len); + + /* both commands are query commands? */ + if (pattern_ptr[pattern_len - 1] == '?') { + if (cmd_ptr[cmd_len - 1] == '?') { + cmd_len -= 1; + pattern_len -= 1; + } else { + return FALSE; + } + } + + /* now support optional keywords in pattern style, e.g. [:MEASure]:VOLTage:DC? */ + if (pattern_ptr[0] == '[') { /* skip first '[' */ + SKIP_PATTERN(1); + brackets++; + } + if (pattern_ptr[0] == ':') { /* skip first ':' */ + SKIP_PATTERN(1); + } + + if (cmd_ptr[0] == ':') { + /* handle errornouse ":*IDN?" */ + if (cmd_len >= 2) { + if (cmd_ptr[1] != '*') { + SKIP_CMD(1); + } else { + return FALSE; + } + } + } + + while (1) { + int pattern_sep_pos = patternSeparatorPos(pattern_ptr, pattern_len); + + cmd_sep_pos = cmdSeparatorPos(cmd_ptr, cmd_len); + + if ((pattern_sep_pos > 0) && pattern_ptr[pattern_sep_pos - 1] == '#') { + if (numbers && (numbers_idx < numbers_len)) { + number_ptr = numbers + numbers_idx; + *number_ptr = default_value; /* default value */ + } else { + number_ptr = NULL; + } + numbers_idx++; + } else { + number_ptr = NULL; + } + + if (matchPattern(pattern_ptr, pattern_sep_pos, cmd_ptr, cmd_sep_pos, number_ptr)) { + SKIP_PATTERN(pattern_sep_pos); + SKIP_CMD(cmd_sep_pos); + result = TRUE; + + /* command is complete */ + if ((pattern_len == 0) && (cmd_len == 0)) { + break; + } + + /* pattern complete, but command not */ + if ((pattern_len == 0) && (cmd_len > 0)) { + result = FALSE; + break; + } + + /* command complete, but pattern not */ + if (cmd_len == 0) { + /* verify all subsequent pattern parts are also optional */ + while (pattern_len) { + pattern_sep_pos = patternSeparatorPos(pattern_ptr, pattern_len); + switch (pattern_ptr[pattern_sep_pos]) { + case '[': + brackets++; + break; + case ']': + brackets--; + break; + default: + break; + } + SKIP_PATTERN(pattern_sep_pos + 1); + if (brackets == 0) { + if ((pattern_len > 0) && (pattern_ptr[0] == '[')) { + continue; + } else { + break; + } + } + } + if (pattern_len != 0) { + result = FALSE; + } + break; /* exist optional keyword, command is complete */ + } + + /* both command and patter contains command separator at this position */ + if ((pattern_len > 0) + && ((pattern_ptr[0] == cmd_ptr[0]) + && (pattern_ptr[0] == ':'))) { + SKIP_PATTERN(1); + SKIP_CMD(1); + } else if ((pattern_len > 1) + && (pattern_ptr[1] == cmd_ptr[0]) + && (pattern_ptr[0] == '[') + && (pattern_ptr[1] == ':')) { + SKIP_PATTERN(2); /* for skip '[' in "[:" */ + SKIP_CMD(1); + brackets++; + } else if ((pattern_len > 1) + && (pattern_ptr[1] == cmd_ptr[0]) + && (pattern_ptr[0] == ']') + && (pattern_ptr[1] == ':')) { + SKIP_PATTERN(2); /* for skip ']' in "]:" */ + SKIP_CMD(1); + brackets--; + } else if ((pattern_len > 2) + && (pattern_ptr[2] == cmd_ptr[0]) + && (pattern_ptr[0] == ']') + && (pattern_ptr[1] == '[') + && (pattern_ptr[2] == ':')) { + SKIP_PATTERN(3); /* for skip '][' in "][:" */ + SKIP_CMD(1); + /* brackets++; */ + /* brackets--; */ + } else { + result = FALSE; + break; + } + } else { + SKIP_PATTERN(pattern_sep_pos); + if ((pattern_ptr[0] == ']') && (pattern_ptr[1] == ':')) { + SKIP_PATTERN(2); /* for skip ']' in "]:" , pattern_ptr continue, while cmd_ptr remain unchanged */ + brackets--; + } else if ((pattern_len > 2) && (pattern_ptr[0] == ']') + && (pattern_ptr[1] == '[') + && (pattern_ptr[2] == ':')) { + SKIP_PATTERN(3); /* for skip ']' in "][:" , pattern_ptr continue, while cmd_ptr remain unchanged */ + /* brackets++; */ + /* brackets--; */ + } else { + result = FALSE; + break; + } + } + } + + return result; +#undef SKIP_PATTERN +#undef SKIP_CMD +} + +/** + * Compose command from previous command anc current command + * + * @param prev pointer to previous command + * @param current pointer of current command + * + * prev and current should be in the same memory buffer + */ +scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current) { + size_t i; + + /* Invalid input */ + if (current == NULL || current->ptr == NULL || current->len == 0) + return FALSE; + + /* no previous command - nothing to do*/ + if (prev->ptr == NULL || prev->len == 0) + return TRUE; + + /* Common command or command root - nothing to do */ + if (current->ptr[0] == '*' || current->ptr[0] == ':') + return TRUE; + + /* Previsou command was common command - nothing to do */ + if (prev->ptr[0] == '*') + return TRUE; + + /* Find last occurence of ':' */ + for (i = prev->len; i > 0; i--) { + if (prev->ptr[i - 1] == ':') { + break; + } + } + + /* Previous command was simple command - nothing to do*/ + if (i == 0) + return TRUE; + + current->ptr -= i; + current->len += i; + memmove(current->ptr, prev->ptr, i); + return TRUE; +} + + + +#if !HAVE_STRNLEN +/* use FreeBSD strnlen */ + +/*- + * Copyright (c) 2009 David Schultz <das@FreeBSD.org> + * All rights reserved. + */ +size_t +BSD_strnlen(const char *s, size_t maxlen) { + size_t len; + + for (len = 0; len < maxlen; len++, s++) { + if (!*s) + break; + } + return (len); +} +#endif + +#if !HAVE_STRNCASECMP && !HAVE_STRNICMP + +int OUR_strncasecmp(const char *s1, const char *s2, size_t n) { + unsigned char c1, c2; + + for (; n != 0; n--) { + c1 = tolower((unsigned char) *s1++); + c2 = tolower((unsigned char) *s2++); + if (c1 != c2) { + return c1 - c2; + } + if (c1 == '\0') { + return 0; + } + } + return 0; +} +#endif + +#if USE_MEMORY_ALLOCATION_FREE && !HAVE_STRNDUP +char *OUR_strndup(const char *s, size_t n) { + size_t len = SCPIDEFINE_strnlen(s, n); + char * result = malloc(len + 1); + if (!result) { + return NULL; + } + memcpy(result, s, len); + result[len] = '\0'; + return result; +} +#endif + +#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE + +/** + * Initialize heap structure + * @param heap - pointer to manual allocated heap buffer + * @param error_info_heap - buffer for the heap + * @param error_info_heap_length - length of the heap + */ +void scpiheap_init(scpi_error_info_heap_t * heap, char * error_info_heap, size_t error_info_heap_length) +{ + heap->data = error_info_heap; + heap->wr = 0; + heap->size = error_info_heap_length; + heap->count = heap->size; + memset(heap->data, 0, heap->size); +} + +/** + * Duplicate string if "strdup" ("malloc/free") not supported on system. + * Allocate space in heap if it possible + * + * @param heap - pointer to manual allocated heap buffer + * @param s - current pointer of duplication string + * @return - pointer of duplicated string or NULL, if duplicate is not possible. + */ +char * scpiheap_strndup(scpi_error_info_heap_t * heap, const char *s, size_t n) { + if (!s || !heap || !heap->size) { + return NULL; + } + + if (heap->data[heap->wr] != '\0') { + return NULL; + } + + if (*s == '\0') { + return NULL; + } + + size_t len = SCPIDEFINE_strnlen(s, n) + 1; /* additional '\0' at end */ + if (len > heap->count) { + return NULL; + } + const char * ptrs = s; + char * head = &heap->data[heap->wr]; + size_t rem = heap->size - (&heap->data[heap->wr] - heap->data); + + if (len >= rem) { + memcpy(&heap->data[heap->wr], s, rem); + len = len - rem; + ptrs += rem; + heap->wr = 0; + heap->count -= rem; + } + + memcpy(&heap->data[heap->wr], ptrs, len); + heap->wr += len; + heap->count -= len; + + /* ensure '\0' a the end */ + if (heap->wr > 0) { + heap->data[heap->wr - 1] = '\0'; + } else { + heap->data[heap->size - 1] = '\0'; + } + return head; +} + +/** + * Return pointers and lengths two parts of string in the circular buffer from heap + * + * @param heap - pointer to manual allocated heap buffer + * @param s - pointer of duplicate string. + * @return len1 - lenght of first part of string. + * @return s2 - pointer of second part of string, if string splited . + * @return len2 - lenght of second part of string. + */ +scpi_bool_t scpiheap_get_parts(scpi_error_info_heap_t * heap, const char * s, size_t * len1, const char ** s2, size_t * len2) { + if (!heap || !s || !len1 || !s2 || !len2) { + return FALSE; + } + + if (*s == '\0') { + return FALSE; + } + + *len1 = 0; + size_t rem = heap->size - (s - heap->data); + *len1 = strnlen(s, rem); + + if (&s[*len1 - 1] == &heap->data[heap->size - 1]) { + *s2 = heap->data; + *len2 = strnlen(*s2, heap->size); + } else { + *s2 = NULL; + *len2 = 0; + } + return TRUE; +} + +/** + * Frees space in heap, if "malloc/free" not supported on system, or nothing. + * + * @param heap - pointer to manual allocated heap buffer + * @param s - pointer of duplicate string + * @param rollback - backward write pointer in heap + */ +void scpiheap_free(scpi_error_info_heap_t * heap, char * s, scpi_bool_t rollback) { + + if (!s) return; + + char * data_add; + size_t len[2]; + + if (!scpiheap_get_parts(heap, s, &len[0], (const char **)&data_add, &len[1])) return; + + if (data_add) { + len[1]++; + memset(data_add, 0, len[1]); + heap->count += len[1]; + } else { + len[0]++; + } + memset(s, 0, len[0]); + heap->count += len[0]; + if (heap->count == heap->size) { + heap->wr = 0; + return; + } + if (rollback) { + size_t rb = len[0] + len[1]; + if (rb > heap->wr) { + heap->wr += heap->size; + } + heap->wr -= rb; + } +} + +#endif + +/* + * Floating point to string conversion routines + * + * Copyright (C) 2002 Michael Ringgaard. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +static char *scpi_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf, size_t bufsize) { + int r1, r2; + double fi, fj; + int w1, w2; + + if (ndigits < 0) ndigits = 0; + if (ndigits >= (int) (bufsize - 1)) ndigits = bufsize - 2; + + r2 = 0; + *sign = 0; + w1 = 0; + if (arg < 0) { + *sign = 1; + arg = -arg; + } + frexp(arg, &r1); + arg = modf(arg, &fi); + + if (fi != 0) { + r1 = r1 * 308 / 1024 - ndigits; + w2 = bufsize; + while (r1 > 0) { + fj = modf(fi / 10, &fi); + r2++; + r1--; + } + while (fi != 0) { + fj = modf(fi / 10, &fi); + buf[--w2] = (int) ((fj + .03) * 10) + '0'; + r2++; + } + while (w2 < (int) bufsize) buf[w1++] = buf[w2++]; + } else if (arg > 0) { + while ((fj = arg * 10) < 1) { + arg = fj; + r2--; + } + } + w2 = ndigits; + *decpt = r2; + if (w2 < 0) { + buf[0] = '\0'; + return buf; + } + while (w1 <= w2 && w1 < (int) bufsize) { + arg *= 10; + arg = modf(arg, &fj); + buf[w1++] = (int) fj + '0'; + } + if (w2 >= (int) bufsize) { + buf[bufsize - 1] = '\0'; + return buf; + } + w1 = w2; + buf[w2] += 5; + while (buf[w2] > '9') { + buf[w2] = '0'; + if (w2 > 0) { + ++buf[--w2]; + } else { + buf[w2] = '1'; + (*decpt)++; + } + } + buf[w1] = '\0'; + return buf; +} + +#define SCPI_DTOSTRE_BUFFER_SIZE 32 + +char * SCPI_dtostre(double __val, char * __s, size_t __ssize, unsigned char __prec, unsigned char __flags) { + char buffer[SCPI_DTOSTRE_BUFFER_SIZE]; + + int sign = SCPIDEFINE_signbit(__val); + char * s = buffer; + int decpt; + if (sign) { + __val = -__val; + s[0] = '-'; + s++; + } else if (!SCPIDEFINE_isnan(__val)) { + if (SCPI_DTOSTRE_PLUS_SIGN & __flags) { + s[0] = '+'; + s++; + } else if (SCPI_DTOSTRE_ALWAYS_SIGN & __flags) { + s[0] = ' '; + s++; + } + } + + if (!SCPIDEFINE_isfinite(__val)) { + if (SCPIDEFINE_isnan(__val)) { + strcpy(s, (__flags & SCPI_DTOSTRE_UPPERCASE) ? "NAN" : "nan"); + } else { + strcpy(s, (__flags & SCPI_DTOSTRE_UPPERCASE) ? "INF" : "inf"); + } + strncpy(__s, buffer, __ssize); + __s[__ssize - 1] = '\0'; + return __s; + } + + scpi_ecvt(__val, __prec, &decpt, &sign, s, SCPI_DTOSTRE_BUFFER_SIZE - 1); + if (decpt > 1 && decpt <= __prec) { + memmove(s + decpt + 1, s + decpt, __prec + 1 - decpt); + s[decpt] = '.'; + decpt = 0; + } else if (decpt > -4 && decpt <= 0) { + decpt = -decpt + 1; + memmove(s + decpt + 1, s, __prec + 1); + memset(s, '0', decpt + 1); + s[1] = '.'; + decpt = 0; + } else { + memmove(s + 2, s + 1, __prec + 1); + s[1] = '.'; + decpt--; + } + + s = &s[__prec]; + while (s[0] == '0') { + s[0] = 0; + s--; + } + if (s[0] == '.') { + s[0] = 0; + s--; + } + + if (decpt != 0) { + s++; + s[0] = 'e'; + s++; + if (decpt != 0) { + if (decpt > 0) { + s[0] = '+'; + } + if (decpt < 0) { + s[0] = '-'; + decpt = -decpt; + } + s++; + } + UInt32ToStrBaseSign(decpt, s, 5, 10, 0); + if (s[1] == 0) { + s[2] = s[1]; + s[1] = s[0]; + s[0] = '0'; + } + } + + strncpy(__s, buffer, __ssize); + __s[__ssize - 1] = '\0'; + return __s; +} + +/** + * Get native CPU endiannes + * @return + */ +scpi_array_format_t SCPI_GetNativeFormat(void) { + + union { + uint32_t i; + char c[4]; + } bint = {0x01020304}; + + return bint.c[0] == 1 ? SCPI_FORMAT_BIGENDIAN : SCPI_FORMAT_LITTLEENDIAN; +} + +/** + * Swap 16bit number + * @param val + * @return + */ +uint16_t SCPI_Swap16(uint16_t val) { + return ((val & 0x00FF) << 8) | + ((val & 0xFF00) >> 8); +} + +/** + * Swap 32bit number + * @param val + * @return + */ +uint32_t SCPI_Swap32(uint32_t val) { + return ((val & 0x000000FFul) << 24) | + ((val & 0x0000FF00ul) << 8) | + ((val & 0x00FF0000ul) >> 8) | + ((val & 0xFF000000ul) >> 24); +} + +/** + * Swap 64bit number + * @param val + * @return + */ +uint64_t SCPI_Swap64(uint64_t val) { + return ((val & 0x00000000000000FFull) << 56) | + ((val & 0x000000000000FF00ull) << 40) | + ((val & 0x0000000000FF0000ull) << 24) | + ((val & 0x00000000FF000000ull) << 8) | + ((val & 0x000000FF00000000ull) >> 8) | + ((val & 0x0000FF0000000000ull) >> 24) | + ((val & 0x00FF000000000000ull) >> 40) | + ((val & 0xFF00000000000000ull) >> 56); } -- Gitblit v1.9.1