| //***************************************************************************** |
| // |
| //! @file am_util_string.c |
| //! |
| //! @brief A subset of the functions provided in the C standard string library. |
| //! |
| //! The functions here are reimplementation of some of the standard "string" |
| //! functions. |
| // |
| //***************************************************************************** |
| |
| //***************************************************************************** |
| // |
| // Copyright (c) 2017, Ambiq Micro |
| // 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 copyright holder 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 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. |
| // |
| // This is part of revision v1.2.10-2-gea660ad-hotfix2 of the AmbiqSuite Development Package. |
| // |
| //***************************************************************************** |
| |
| #include <stdint.h> |
| #include <stdbool.h> |
| #include "am_util_string.h" |
| |
| |
| //***************************************************************************** |
| // |
| //! @brief Table for quick lookup of character attributes. |
| // |
| //***************************************************************************** |
| #if MINIMIZE_CATTR_TABLE |
| #define CATTR_TBL_SIZE 128 |
| #else |
| #define CATTR_TBL_SIZE 256 |
| #endif |
| |
| const uint8_t am_cattr[CATTR_TBL_SIZE] = |
| { |
| AM_CATTR_NONE, /* 0x00 */ |
| AM_CATTR_NONE, /* 0x01 */ |
| AM_CATTR_NONE, /* 0x02 */ |
| AM_CATTR_NONE, /* 0x03 */ |
| AM_CATTR_NONE, /* 0x04 */ |
| AM_CATTR_NONE, /* 0x05 */ |
| AM_CATTR_NONE, /* 0x06 */ |
| AM_CATTR_NONE, /* 0x07 */ |
| AM_CATTR_NONE, /* 0x08 */ |
| AM_CATTR_WHSPACE, /* 0x09 */ |
| AM_CATTR_WHSPACE, /* 0x0A */ |
| AM_CATTR_WHSPACE, /* 0x0B */ |
| AM_CATTR_WHSPACE, /* 0x0C */ |
| AM_CATTR_WHSPACE, /* 0x0D */ |
| AM_CATTR_NONE, /* 0x0E */ |
| AM_CATTR_NONE, /* 0x0F */ |
| AM_CATTR_NONE, /* 0x00 */ |
| AM_CATTR_NONE, /* 0x11 */ |
| AM_CATTR_NONE, /* 0x12 */ |
| AM_CATTR_NONE, /* 0x13 */ |
| AM_CATTR_NONE, /* 0x14 */ |
| AM_CATTR_NONE, /* 0x15 */ |
| AM_CATTR_NONE, /* 0x16 */ |
| AM_CATTR_NONE, /* 0x17 */ |
| AM_CATTR_NONE, /* 0x18 */ |
| AM_CATTR_NONE, /* 0x19 */ |
| AM_CATTR_NONE, /* 0x1A */ |
| AM_CATTR_NONE, /* 0x1B */ |
| AM_CATTR_NONE, /* 0x1C */ |
| AM_CATTR_NONE, /* 0x1D */ |
| AM_CATTR_NONE, /* 0x1E */ |
| AM_CATTR_NONE, /* 0x1F */ |
| AM_CATTR_WHSPACE, /* 0x20, space */ |
| AM_CATTR_FILENM83, /* 0x21, ! */ |
| AM_CATTR_NONE, /* 0x22, " */ |
| AM_CATTR_FILENM83, /* 0x23, # */ |
| AM_CATTR_FILENM83, /* 0x24, $ */ |
| AM_CATTR_FILENM83, /* 0x25, % */ |
| AM_CATTR_FILENM83, /* 0x26, & */ |
| AM_CATTR_FILENM83, /* 0x27, ' */ |
| AM_CATTR_FILENM83, /* 0x28, ( */ |
| AM_CATTR_FILENM83, /* 0x29, ) */ |
| AM_CATTR_NONE, /* 0x2A, * */ |
| AM_CATTR_NONE, /* 0x2B, + */ |
| AM_CATTR_NONE, /* 0x2C, , */ |
| AM_CATTR_FILENM83, /* 0x2D, - */ |
| AM_CATTR_FILENM83, /* 0x2E, . */ |
| AM_CATTR_NONE, /* 0x2F, / */ |
| AM_CATTR_DIGIT | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x30, 0 */ |
| AM_CATTR_DIGIT | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x31, 1 */ |
| AM_CATTR_DIGIT | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x32, 2 */ |
| AM_CATTR_DIGIT | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x33, 3 */ |
| AM_CATTR_DIGIT | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x34, 4 */ |
| AM_CATTR_DIGIT | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x35, 5 */ |
| AM_CATTR_DIGIT | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x36, 6 */ |
| AM_CATTR_DIGIT | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x37, 7 */ |
| AM_CATTR_DIGIT | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x38, 8 */ |
| AM_CATTR_DIGIT | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x39, 9 */ |
| AM_CATTR_NONE, /* 0x3A, : */ |
| AM_CATTR_NONE, /* 0x3B, ; */ |
| AM_CATTR_NONE, /* 0x3C, < */ |
| AM_CATTR_NONE, /* 0x3D, = */ |
| AM_CATTR_NONE, /* 0x3E, > */ |
| AM_CATTR_NONE, /* 0x3F, ? */ |
| AM_CATTR_FILENM83, /* 0x40, @ */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x41, A */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x42, B */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x43, C */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x44, D */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x45, E */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x46, F */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x47, G */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x48, H */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x49, I */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x4A, J */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x4B, K */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x4C, L */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x4D, M */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x4E, N */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x4F, O */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x50, P */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x51, Q */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x52, R */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x53, S */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x54, T */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x55, U */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x56, V */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x57, W */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x58, X */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x59, Y */ |
| AM_CATTR_ALPHA | AM_CATTR_UPPER | AM_CATTR_FILENM83, /* 0x5A, Z */ |
| AM_CATTR_NONE, /* 0x5B, [ */ |
| AM_CATTR_NONE, /* 0x5C, \ */ |
| AM_CATTR_NONE, /* 0x5D, ] */ |
| AM_CATTR_FILENM83, /* 0x5E, ^ */ |
| AM_CATTR_FILENM83, /* 0x5F, _ */ |
| AM_CATTR_FILENM83, /* 0x60, ` */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x61, a */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x62, b */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x63, c */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x64, d */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x65, e */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_XDIGIT | AM_CATTR_FILENM83, /* 0x66, f */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x67, g */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x68, h */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x69, i */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x6A, j */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x6B, k */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x6C, l */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x6D, m */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x6E, n */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x6F, o */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x70, p */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x71, q */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x72, r */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x73, s */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x74, t */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x75, u */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x76, v */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x77, w */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x78, x */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x79, y */ |
| AM_CATTR_ALPHA | AM_CATTR_LOWER | AM_CATTR_FILENM83, /* 0x7A, z */ |
| AM_CATTR_FILENM83, /* 0x7B, { */ |
| AM_CATTR_NONE, /* 0x7C, | */ |
| AM_CATTR_FILENM83, /* 0x7D, } */ |
| AM_CATTR_FILENM83, /* 0x7E, ~ */ |
| AM_CATTR_NONE /* 0x7F, delete */ |
| |
| // |
| // All bit7 chars are AM_CATTR_NONE. |
| // |
| }; |
| |
| //***************************************************************************** |
| // |
| //! @brief Character "is" functions |
| //! |
| //! This family of functions tests a given integer value in order to determine |
| //! whether the integer satisfies the test condition. |
| //! These functions are generally based on the C99 standard functions. |
| //! |
| //! By default all of the "is" functions are implemented as macros. To implement |
| //! as functions rather than macros, use a global compiler command line (-D) |
| //! option to define AM_UTIL_STRING_CTYPE_DISABLE_MACROS. |
| //! |
| //! Standard functions currently implemented include: |
| //! isalnum(), isalpha(), islower(), isupper(), isdigit(), isxdigit(), |
| //! isspace(). |
| //! |
| //! Standard functions not currently implemented include: |
| //! iscntrl(), isgraph(), isprint(), ispunct(), isblank() (new for C99). |
| //! |
| //! Non-standard functions currently implemented include: |
| //! isfilenm83(). |
| //! |
| //! @return Each function returns a nonzero value if the integer satisfies |
| //! the test condition and 0 if it does not. |
| // |
| //***************************************************************************** |
| |
| #ifdef AM_UTIL_STRING_CTYPE_DISABLE_MACROS |
| int |
| am_util_string_isalnum(int c) |
| { |
| #if MINIMIZE_CATTR_TABLE |
| return (c & 0xffffff80) ? 0 : (am_cattr[c] & (AM_CATTR_ALPHA | AM_CATTR_DIGIT)) ? 1 : 0; |
| #else |
| return (am_cattr[c & 0xff] & (AM_CATTR_ALPHA | AM_CATTR_DIGIT)) ? 1 : 0; |
| #endif |
| } |
| |
| int |
| am_util_string_isalpha(int c) |
| { |
| #if MINIMIZE_CATTR_TABLE |
| return (c & 0xffffff80) ? 0 : (am_cattr[c] & AM_CATTR_ALPHA) ? 1 : 0; |
| #else |
| return (am_cattr[c & 0xff] & AM_CATTR_ALPHA) ? 1 : 0; |
| #endif |
| } |
| |
| int |
| am_util_string_isdigit(int c) |
| { |
| #if MINIMIZE_CATTR_TABLE |
| return (c & 0xffffff80) ? 0 : (am_cattr[c] & AM_CATTR_DIGIT) ? 1 : 0; |
| #else |
| return (am_cattr[c & 0xff] & AM_CATTR_DIGIT) ? 1 : 0; |
| #endif |
| } |
| |
| int am_util_string_islower(int c) |
| { |
| #if MINIMIZE_CATTR_TABLE |
| return (c & 0xffffff80) ? 0 : (am_cattr[c] & AM_CATTR_LOWER) ? 1 : 0; |
| #else |
| return (am_cattr[c & 0xff] & AM_CATTR_LOWER) ? 1 : 0; |
| #endif |
| } |
| |
| int |
| am_util_string_isspace(int c) |
| { |
| #if MINIMIZE_CATTR_TABLE |
| return (c & 0xffffff80) ? 0 : (am_cattr[c] & AM_CATTR_WHSPACE) ? 1 : 0; |
| #else |
| return (am_cattr[c & 0xff] & AM_CATTR_WHSPACE) ? 1 : 0; |
| #endif |
| } |
| |
| int |
| am_util_string_isupper(int c) |
| { |
| #if MINIMIZE_CATTR_TABLE |
| return (c & 0xffffff80) ? 0 : (am_cattr[c] & AM_CATTR_UPPER) ? 1 : 0; |
| #else |
| return (am_cattr[c & 0xff] & AM_CATTR_UPPER) ? 1 : 0; |
| #endif |
| } |
| |
| int |
| am_util_string_isxdigit(int c) |
| { |
| #if MINIMIZE_CATTR_TABLE |
| return (c & 0xffffff80) ? 0 : (am_cattr[c] & AM_CATTR_XDIGIT) ? 1 : 0; |
| #else |
| return (am_cattr[c & 0xff] & AM_CATTR_XDIGIT) ? 1 : 0; |
| #endif |
| } |
| |
| int am_util_string_tolower(int c) |
| { |
| #if MINIMIZE_CATTR_TABLE |
| return (am_cattr[c & 0x7f] & AM_CATTR_UPPER) ? c | 0x20 : c; |
| #else |
| return (am_cattr[c & 0xff] & AM_CATTR_UPPER) ? c | 0x20 : c; |
| #endif |
| } |
| |
| int am_util_string_toupper(int c) |
| { |
| #if MINIMIZE_CATTR_TABLE |
| return (am_cattr[c & 0x7f] & AM_CATTR_LOWER) ? c & ~0x20 : c; |
| #else |
| return (am_cattr[c & 0xff] & AM_CATTR_LOWER) ? c & ~0x20 : c; |
| #endif |
| } |
| |
| |
| // |
| // Non-standard "is" Functions |
| // |
| int |
| am_util_string_isfilenm83(int c) |
| { |
| #if MINIMIZE_CATTR_TABLE |
| return (c & 0xffffff80) ? 0 : (am_cattr[c] & AM_CATTR_FILENM83) ? 1 : 0; |
| #else |
| return (am_cattr[c & 0xff] & AM_CATTR_FILENM83) ? 1 : 0; |
| #endif |
| } |
| #endif // AM_UTIL_STRING_CTYPE_DISABLE_MACROS |
| |
| |
| //***************************************************************************** |
| // |
| //! @brief Compare two strings. |
| //! |
| //! @param str1 is the first string to compare. |
| //! @param str2 is the second string to compare |
| //! |
| //! This function steps through a pair of strings, character by character, to |
| //! determine if the strings contain the same characters. If the strings match, |
| //! this function will return a zero. If str1 is alphabetically earlier than |
| //! str2, the return value will be negative. Otherwise, the return value will |
| //! be positive. |
| //! |
| //! @return 0 for a perfect match, negative value if str1<str2, positive value |
| //! if str1>str2. |
| // |
| //***************************************************************************** |
| int32_t |
| am_util_string_strcmp(const char *str1, const char *str2) |
| { |
| return am_util_string_strncmp(str1, str2, 0xffffffff); |
| } |
| |
| //***************************************************************************** |
| // |
| //! @brief Compare two strings with a specified count. |
| //! |
| //! @param str1 is the first string to compare. |
| //! @param str2 is the second string to compare |
| //! @param num is the maximum number of characters to compare. |
| //! |
| //! This function steps through a pair of strings, character by character, to |
| //! determine if the strings contain the same characters. If the strings match, |
| //! this function will return a zero. If str1 is alphabetically earlier than |
| //! str2, the return value will be negative. Otherwise, the return value will |
| //! be positive. |
| //! |
| //! @return 0 for a perfect match, negative value if str1<str2, positive value |
| //! if str1>str2. |
| // |
| //***************************************************************************** |
| int32_t |
| am_util_string_strncmp(const char *str1, const char *str2, uint32_t num) |
| { |
| while ( num-- ) |
| { |
| // Check for inequality OR end of string |
| if ( *str1 != *str2 || *str1 == '\0' ) |
| { |
| return *str1 - *str2; |
| } |
| |
| str1++; |
| str2++; |
| } |
| |
| // |
| // Since we made it here, the strings must be equal to n characters. |
| // |
| return 0; |
| } |
| |
| //***************************************************************************** |
| // |
| //! @brief Compare two strings with a specified count and without regard to |
| //! letter case in the strings. |
| //! |
| //! @param str1 is the first string to compare. |
| //! @param str2 is the second string to compare |
| //! @param num is the maximum number of characters to compare. |
| //! |
| //! This function steps through a pair of strings, character by character, to |
| //! determine if the strings contain the same characters. If the strings match, |
| //! this function will return a zero. If str1 is alphabetically earlier than |
| //! str2, the return value will be negative. Otherwise, the return value will |
| //! be positive. |
| //! |
| //! @return 0 for a perfect match, negative value if str1<str2, positive value |
| //! if str1>str2. |
| // |
| //***************************************************************************** |
| int32_t |
| am_util_string_strnicmp(const char *str1, const char *str2, int num) |
| { |
| uint8_t cChar1, cChar2; |
| |
| while ( *str1 && *str2 && num ) |
| { |
| cChar1 = *str1; |
| cChar2 = *str2; |
| |
| cChar1 |= ( am_cattr[cChar1] & AM_CATTR_UPPER ) ? 0x20 : 0x00; |
| cChar2 |= ( am_cattr[cChar2] & AM_CATTR_UPPER ) ? 0x20 : 0x00; |
| |
| if ( cChar1 != cChar2 ) |
| { |
| return cChar1 - cChar2; |
| } |
| |
| str1++; |
| str2++; |
| num--; |
| } |
| |
| // |
| // Since we made it here, the strings must be equal to n characters. |
| // |
| return 0; |
| } |
| |
| //***************************************************************************** |
| // |
| //! @brief Compare two strings with case-insensitivity. |
| //! |
| //! @param str1 is the first string to compare. |
| //! @param str2 is the second string to compare |
| //! |
| //! This function compares each character in the 2 strings, converting all |
| //! alpha characters to lower-case to make the comparison. |
| //! |
| //! To illustrate a possible unexpected outcome due to comparing the strings |
| //! as lower case, consider the example strings "AMBIQ_MICRO" and "AMBIQMICRO". |
| //! For these strings, stricmp() will return a negative value (indicating the |
| //! first as before the second), whereas strcmp() will return a positive value. |
| //! |
| //! @return 0 for a case-insensitive match, negative value if str1<str2, |
| //! positive value if str1>str2. |
| // |
| //***************************************************************************** |
| int32_t |
| am_util_string_stricmp(const char *str1, const char *str2) |
| { |
| uint8_t cChar1, cChar2; |
| |
| while ( *str1 && *str2 ) |
| { |
| cChar1 = *str1++; |
| cChar2 = *str2++; |
| |
| cChar1 |= ( am_cattr[cChar1] & AM_CATTR_UPPER ) ? 0x20 : 0x00; |
| cChar2 |= ( am_cattr[cChar2] & AM_CATTR_UPPER ) ? 0x20 : 0x00; |
| |
| if ( cChar1 != cChar2 ) |
| { |
| return cChar1 - cChar2; |
| } |
| } |
| |
| return *str1 - *str2; |
| } |
| |
| //***************************************************************************** |
| // |
| //! @brief Return the length of a string. |
| //! |
| //! @param pcStr pointer to the string. |
| //! |
| //! This function returns the length of the string at pcStr. |
| //! |
| //! @return length of the string pcStr. |
| // |
| //***************************************************************************** |
| uint32_t |
| am_util_string_strlen(const char *pcStr) |
| { |
| const char *pcS; |
| |
| // |
| // Loop through the string. |
| // |
| for (pcS = pcStr; *pcS; ++pcS); |
| |
| // |
| // Return the length. |
| // |
| return(pcS - pcStr); |
| } |
| |
| //***************************************************************************** |
| // |
| //! @brief Copies a string. |
| //! |
| //! @param pcDst pointer to the destination string. |
| //! @param pcSrc pointer to the source string to be copied to pcDst. |
| //! |
| //! This function copies pcSrc to the location specified by pcDst. |
| //! |
| //! @return pcDst (the location of the destination string). |
| // |
| //***************************************************************************** |
| char * |
| am_util_string_strcpy(char *pcDst, const char *pcSrc) |
| { |
| char *pcRet = pcDst; |
| |
| // |
| // Blindly copy the string until we hit a terminating NULL char. |
| // |
| do |
| { |
| *pcDst++ = *pcSrc; |
| } while ( *pcSrc++ ); |
| |
| return pcRet; |
| } |
| |
| //***************************************************************************** |
| // |
| //! @brief Copies a specified number of characters of a string. |
| //! |
| //! @param pcDst pointer to the destination string. |
| //! @param pcSrc pointer to the source string to be copied to pcDst. |
| //! |
| //! This function copies uNum characters of pcSrc to the location specified |
| //! by pcDst. |
| //! If uNum is less than the length of pcSrc, a NULL terminating character |
| //! is not appended to the copied string. Thus the resultant string will be |
| //! exactly uNum chars in length and not terminated. |
| //! If uNum is greater than the length of pcSrc, then pcDst is padded with |
| //! NULL characters up to the uNum length. |
| //! Behavior is undefined if the addresses ranges overlap. |
| //! |
| //! @return pcDst (the location of the destination string). |
| // |
| //***************************************************************************** |
| char * |
| am_util_string_strncpy(char *pcDst, const char *pcSrc, uint32_t uNum) |
| { |
| char *pcRet = pcDst; |
| |
| while (uNum > 0) |
| { |
| if ( *pcSrc ) |
| { |
| *pcDst++ = *pcSrc++; |
| } |
| else |
| { |
| *pcDst++ = 0x00; |
| } |
| uNum--; |
| } |
| |
| return pcRet; |
| } |
| |
| //***************************************************************************** |
| // |
| //! @brief Concatenate a string. |
| //! |
| //! @param pcDst pointer to the destination string. |
| //! @param pcSrc pointer to the source string to be copied to pcDst. |
| //! |
| //! This function concatenates the string at pcSrc to the existing string |
| //! at pcDst. |
| //! |
| //! Both strings, pcDst and pcSrc, must be NULL-terminated. |
| //! No overflow checking is performed. |
| //! pcDst and pcSrc shall not overlap. |
| //! |
| //! @return pcDst (the location of the destination string). |
| // |
| //***************************************************************************** |
| char * |
| am_util_string_strcat(char *pcDst, const char *pcSrc) |
| { |
| char *pcRet = pcDst; |
| |
| // |
| // Find the end of the existing string. |
| // |
| while ( *pcDst++ ); |
| pcDst--; |
| |
| // |
| // Now, copy the new string. |
| // |
| am_util_string_strcpy(pcDst, pcSrc); |
| |
| return pcRet; |
| } |