Host library for controlling a WiConnect enabled Wi-Fi module.

Dependents:   wiconnect-ota_example wiconnect-web_setup_example wiconnect-test-console wiconnect-tcp_server_example ... more

api/StringUtil.h

Committer:
aymangrais
Date:
2015-09-28
Revision:
42:8ffb253b09e7
Parent:
34:2616445d0823

File content as of revision 42:8ffb253b09e7:

/**
 * ACKme WiConnect Host Library is licensed under the BSD licence: 
 * 
 * Copyright (c)2014 ACKme Networks.
 * 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. The name of the author may not be used to endorse or promote products 
 * derived from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
 */
#pragma once


#include <string.h>
#include <ctype.h>
#include <stdint.h>
#include <limits.h>


#ifdef WICONNECT_USE_STRTOLL
// Necessary to get strtoll in C99 mode.
// http://sourceware.org/ml/newlib/2012/msg00425.html
extern long long strtoll(const char *__n, char **__end_PTR, int __base);
#endif


class StringUtil
{

public:
    /*************************************************************************************************/
    // Helper to find an occurrence of a delimiter string,
    // insert '\0' in its place and return string after
    // the delimiter e.g.
    //     if char s[] = "foo://bar";
    //     - strchop(s, "://") returns "bar"
    //     - s becomes "foo"
    static char *chop(char *haystack, const char *needle)
    {
        if (!haystack)
        {
            return NULL;
        }
        char *end = strstr(haystack, needle);
        if (end)
        {
            *end = '\0';
            return end + strlen(needle);
        }
        return NULL;
    }

    /*************************************************************************************************/
    // Check if string is non-null and non-empty.
    static bool empty(const char *s)
    {
        return !(s && *s);
    }

    /*************************************************************************************************/
    static bool isSpace(const char *s)
    {
        while(*s != 0)
        {
            if(!isspace((uint8_t)*s++))
                return false;
        }
        return true;
    }

    /*************************************************************************************************/
    // Convert null-terminated string to lower case.
    // ASCII charset only.
    static void toLower(char *s)
    {
        for (; *s; ++s)
        {
            *s = tolower((int) * s);
        }
    }

    /*************************************************************************************************/
    // Combination of strip left + right.
    static char *strip(char *s, const char *chars)
    {
        return rightStrip(leftStrip(s, chars), chars);
    }

    /*************************************************************************************************/
    // Strip string from the left.
    // Returns pointer into the input string.
    static char *leftStrip(char *s, const char *chars)
    {
        return s + strspn(s, chars);
    }

    /*************************************************************************************************/
    // Strip string from the right.
    // Modified in place.
    static char *rightStrip(char *s, const char *chars)
    {
        char *end = s + strlen(s) - 1;
        while (end > s && strstr(chars, end))
        {
            *end-- = '\0';
        }
        return s;
    }

    /*************************************************************************************************/
    // Parse decimal integer and check if it's in bounds [min, max].
    static bool parseInt(const char *s, intmax_t *result, intmax_t min, intmax_t max)
    {
        return parseBase(s, result, min, max, 10);
    }

    // Parse hexadecimal integer and check if it's in bounds [min, max].
    static bool parseHex(const char *s, intmax_t *result, intmax_t min, intmax_t max)
    {
        return parseBase(s, result, min, max, 16);
    }

    /*************************************************************************************************/
    static bool parseBase(const char *s, intmax_t *result, intmax_t min, intmax_t max, int base)
    {
        if (!s)
        {
            return false;
        }
        char *end;
#ifdef WICONNECT_USE_STRTOLL
        intmax_t value = strtoll(s, &end, base);
#else
        intmax_t value = strtol(s, &end, base);
#endif
        if (*end || value < min || value > max)
        {
            return false;
        }
        *result = value;
        return true;
    }

    /*************************************************************************************************/
    // Parse an long long integer.
    static bool parseBool(const char *onoff, bool *var)
    {
        const char* const on_vals[] =
        {
                "1",
                "on",
                "true",
                "yes",
        };

        for(uint8_t i = 0; i < ARRAY_COUNT(on_vals); ++i)
        {
            if(strcasecmp(on_vals[i], onoff) == 0)
            {
                *var = true;
                return true;
            }
        }

        const char* const off_vals[] =
        {
                "0",
                "false",
                "no",
                "off",
                NULL
        };
        for(uint8_t i = 0; i < ARRAY_COUNT(off_vals); ++i)
        {
            if(strcasecmp(off_vals[i], onoff) == 0)
            {
                *var = false;
                return true;
            }
        }

        return false;
    }

    /*************************************************************************************************/
    // convert binary data to hex string
    static void binToHex(char *dst, int max_dst, const void *data, int data_len)
    {
        char *end = dst + max_dst - 1;
        for (int i = 0; i < data_len; ++i)
        {
            if (dst < end)
            {
                dst += sprintf(dst, "%2.2x", ((uint8_t *)data)[i]);
            }
        }
    }


    /*************************************************************************************************/
    // Parse binary data into hex string
    // the input buffer MUST be len*2  long
    // as the parsing is destructive and done in-place
    static void binToHex(void *h, int len)
    {
        char *dst = (char*)h;
        char *src= (char*)h+len;

        memmove(src, dst, len);

        while(len--)
        {
            sprintf(dst, "%2.2X", (unsigned int)(*src & 0xff));
            dst += 2;
            ++src;
        }
    }


    /*************************************************************************************************/
    // Parses hex representation of binary data destructively.
    // Returns number of bytes parsed or -1 on error.
    static int hexToBin(char *s)
    {
        int len, i, j;
        len = strlen(s);
        if (len % 2)
        {
            return -1;
        }
        for (i = j = 0; i < len; i += 2, j++)
        {
            const int num = hexToInt(&s[i]);
            if(num == -1)
                return -1;
            s[j] = (char)num;
        }
        return j;
    }

    /*************************************************************************************************/
    // hex string to integer, returns -1 on error
    static int hexToInt(const char *hex_str)
    {
        int hi = hexToNibble(*hex_str);
        int lo = hexToNibble(*(hex_str+1));
        if (hi == -1 || lo == -1)
        {
            return -1;
        }
        return (hi << 4) | lo;
    }

    /*************************************************************************************************/
    static int hexToNibble(char c)
    {
        if (c >= '0' && c <= '9')
        {
            return c - '0';
        }
        if (c >= 'a' && c <= 'f')
        {
            return 10 + (c - 'a');
        }
        if (c >= 'A' && c <= 'F')
        {
            return 10 + (c - 'A');
        }
        return -1;
    }

    /*************************************************************************************************/
    static const char* uint32ToStr(char* intStrBuffer, int integer)
    {
        sprintf(intStrBuffer, "%u", integer);
        return intStrBuffer;
    }

    /*************************************************************************************************/
    static const char* hexToStr(char* intStrBuffer, uint32_t hexInteger)
    {
        sprintf(intStrBuffer, "%X", hexInteger);
        return intStrBuffer;
    }

    /*************************************************************************************************/
    static bool strToUint32(const char *str, uint32_t *uint32Ptr)
    {
        intmax_t r;
        bool result = (str[0] == '0' && str[1] == 'x') ? StringUtil::parseHex(&str[2], &r, 0, UINT_MAX): StringUtil::parseInt(str, &r, 0, UINT_MAX);
        *uint32Ptr = (uint32_t)r;
        return result;
    }


    /*************************************************************************************************/
    static bool strToUint16(const char *str, uint16_t *uint16Ptr)
    {
        intmax_t r;
        bool result = StringUtil::parseInt(str, &r, 0, USHRT_MAX);
        *uint16Ptr = (uint16_t)r;
        return result;
    }

    /*************************************************************************************************/
    static bool strToUint8(const char *str, uint8_t *uint8Ptr)
    {
        intmax_t r;
        bool result = StringUtil::parseInt(str, &r, 0, UCHAR_MAX);
        *uint8Ptr = (uint8_t)r;
        return result;
    }

    /*************************************************************************************************/
    static bool strToInt32(const char *str, int32_t *int32Ptr)
    {
        intmax_t r;
        bool result = StringUtil::parseInt(str, &r, INT_MIN, INT_MAX);
        *int32Ptr = (int32_t)r;
        return result;
    }

    /*************************************************************************************************/
    // uint32 hex string to uint32
    static bool strHexToUint32(const char *strHex, uint32_t *uint32Ptr)
    {
        intmax_t r;
        bool result = StringUtil::parseHex(strHex, &r, 0, UINT_MAX);
        *uint32Ptr = (uint32_t)r;
        return result;
    }

    /*************************************************************************************************/
    static char *strtok_r(char *str, const char *delim, char **nextp)
    {
        char *ret;

        if (str == NULL)
        {
            str = *nextp;
        }

        str += strspn(str, delim);

        if (*str == '\0')
        {
            return NULL;
        }

        ret = str;

        str += strcspn(str, delim);

        if (*str)
        {
            *str++ = '\0';
        }

        *nextp = str;

        return ret;
    }

    /*************************************************************************************************/
    static int strncasecmp(const char *s1, const char *s2, int n)
    {
        if (n == 0)
            return 0;

        while (n-- != 0 && tolower(*s1) == tolower(*s2))
        {
            if (n == 0 || *s1 == '\0' || *s2 == '\0')
                break;
            s1++;
            s2++;
        }

        return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
    }

    /*************************************************************************************************/
    static int strcasecmp(const char *s1, const char *s2)
    {
        register const unsigned char *p1 = (const unsigned char *) s1;
        register const unsigned char *p2 = (const unsigned char *) s2;
        unsigned char c1, c2;

        if (p1 == p2)
            return 0;

        do
        {
            c1 = tolower (*p1);
            c2 = tolower (*p2);

            if (c1 == '\0')
                break;

            ++p1;
            ++p2;
        }
        while (c1 == c2);

        if (UCHAR_MAX <= INT_MAX)
            return c1 - c2;
        else
            /* On machines where 'char' and 'int' are types of the same size, the
               difference of two 'unsigned char' values - including the sign bit -
               doesn't fit in an 'int'.  */
            return (c1 > c2 ? 1 : c1 < c2 ? -1 : 0);
    }
};