2015-03-31 22:16:04 +08:00
|
|
|
/****************************************************************************
|
2015-05-28 15:40:24 +08:00
|
|
|
** gmio
|
2015-05-01 00:19:45 +08:00
|
|
|
** Copyright Fougue (2 Mar. 2015)
|
2015-07-13 17:42:03 +08:00
|
|
|
** contact@fougue.pro
|
2015-03-31 22:16:04 +08:00
|
|
|
**
|
|
|
|
** This software is a reusable library whose purpose is to provide complete
|
|
|
|
** I/O support for various CAD file formats (eg. STL)
|
|
|
|
**
|
|
|
|
** This software is governed by the CeCILL-B license under French law and
|
|
|
|
** abiding by the rules of distribution of free software. You can use,
|
|
|
|
** modify and/ or redistribute the software under the terms of the CeCILL-B
|
|
|
|
** license as circulated by CEA, CNRS and INRIA at the following URL
|
|
|
|
** "http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html".
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifndef GMIO_INTERNAL_STRING_UTILS_H
|
|
|
|
#define GMIO_INTERNAL_STRING_UTILS_H
|
|
|
|
|
|
|
|
#include "../global.h"
|
|
|
|
|
2015-10-22 00:37:21 +08:00
|
|
|
#include <string.h>
|
|
|
|
|
2015-05-28 19:57:18 +08:00
|
|
|
#ifdef GMIO_STRINGUTILS_CTYPE_H
|
|
|
|
# include <ctype.h>
|
|
|
|
#endif
|
|
|
|
|
2015-03-31 22:16:04 +08:00
|
|
|
/*! Returns non-zero if \p c is a space (for C-locale), zero otherwise */
|
|
|
|
GMIO_INLINE int gmio_clocale_isspace(char c)
|
|
|
|
{
|
2015-05-28 19:57:18 +08:00
|
|
|
/* 0x20 : space (SPC)
|
|
|
|
* 0x09 : horizontal tab (TAB)
|
|
|
|
* 0x0a : newline (LF)
|
|
|
|
* 0x0b : vertical tab (VT)
|
|
|
|
* 0x0c : feed (FF)
|
|
|
|
* 0x0d : carriage return (CR) */
|
2015-10-22 00:37:21 +08:00
|
|
|
#if defined(GMIO_STRINGUTILS_DIRECT_TESTS)
|
|
|
|
/* TODO: eliminate branch */
|
2015-05-28 19:57:18 +08:00
|
|
|
return c == 0x20 || ((uint8_t)(c - 0x09) < 5);
|
|
|
|
#elif defined(GMIO_STRINGUTILS_C_ARRAYS)
|
2015-05-07 21:55:54 +08:00
|
|
|
static const unsigned char space_chars[] = {
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
|
|
};
|
|
|
|
return space_chars[c];
|
2015-05-28 19:57:18 +08:00
|
|
|
#elif defined(GMIO_STRINGUTILS_CTYPE_H)
|
|
|
|
return isspace(c);
|
2015-05-07 21:55:54 +08:00
|
|
|
#endif
|
2015-03-31 22:16:04 +08:00
|
|
|
}
|
|
|
|
|
2015-10-22 00:37:21 +08:00
|
|
|
GMIO_INLINE int gmio_clocale_isdigit(char c)
|
|
|
|
{
|
|
|
|
static const unsigned char digit_chars[] = {
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
|
|
};
|
|
|
|
return digit_chars[c];
|
|
|
|
}
|
|
|
|
|
2015-05-28 17:04:41 +08:00
|
|
|
/*! Returns non-zero if \p c is an uppercase letter (for C-locale), zero
|
|
|
|
* otherwise */
|
|
|
|
GMIO_INLINE int gmio_clocale_isupper(char c)
|
|
|
|
{
|
2015-05-28 19:57:18 +08:00
|
|
|
#if defined(GMIO_STRINGUTILS_DIRECT_TESTS)
|
2015-10-22 00:37:21 +08:00
|
|
|
/* TODO: eliminate branch */
|
2015-05-28 17:04:41 +08:00
|
|
|
return 65 <= c && c <= 90;
|
2015-05-28 19:57:18 +08:00
|
|
|
#elif defined(GMIO_STRINGUTILS_C_ARRAYS)
|
2015-05-28 17:04:41 +08:00
|
|
|
static const unsigned char upper_chars[] = {
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
|
|
};
|
|
|
|
return upper_chars[c];
|
2015-05-28 19:57:18 +08:00
|
|
|
#elif defined(GMIO_STRINGUTILS_CTYPE_H)
|
|
|
|
return isupper(c);
|
2015-05-28 17:04:41 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! Returns non-zero if \p c is a lowercase letter (for C-locale), zero
|
|
|
|
* otherwise */
|
|
|
|
GMIO_INLINE int gmio_clocale_islower(char c)
|
|
|
|
{
|
2015-05-28 19:57:18 +08:00
|
|
|
#if defined(GMIO_STRINGUTILS_DIRECT_TESTS)
|
2015-10-22 00:37:21 +08:00
|
|
|
/* TODO: eliminate branch */
|
2015-05-28 17:04:41 +08:00
|
|
|
return 97 <= c && c <= 122;
|
2015-05-28 19:57:18 +08:00
|
|
|
#elif defined(GMIO_STRINGUTILS_C_ARRAYS)
|
2015-05-28 17:04:41 +08:00
|
|
|
static const unsigned char lower_chars[] = {
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
|
|
};
|
|
|
|
return lower_chars[c];
|
2015-05-28 19:57:18 +08:00
|
|
|
#elif defined(GMIO_STRINGUTILS_CTYPE_H)
|
|
|
|
return islower(c);
|
2015-05-28 17:04:41 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! Returns the lowercase letter converted to uppercase */
|
|
|
|
GMIO_INLINE char gmio_clocale_toupper(char c)
|
|
|
|
{
|
2015-10-22 00:37:21 +08:00
|
|
|
static const uint8_t table_toupper[128] = {
|
|
|
|
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,0x09,0x0A, 0 , 0 ,0x0D, 0 , 0 ,
|
|
|
|
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
|
|
|
|
' ', '!', '"', '#', '$', '%', '&','\'', '(', ')', '*', '+', ',', '-', '.', '/',
|
|
|
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
|
|
|
|
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
|
|
|
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[','\\', ']', '^', '_',
|
|
|
|
'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
|
|
|
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', 0,
|
|
|
|
};
|
|
|
|
return table_toupper[c];
|
2015-05-28 17:04:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*! Returns the uppercase letter converted to lowercase */
|
|
|
|
GMIO_INLINE char gmio_clocale_tolower(char c)
|
|
|
|
{
|
2015-10-22 00:37:21 +08:00
|
|
|
static const uint8_t table_tolower[128] = {
|
|
|
|
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,0x09,0x0A, 0 , 0 ,0x0D, 0 , 0 ,
|
|
|
|
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
|
|
|
|
' ', '!', '"', '#', '$', '%', '&','\'', '(', ')', '*', '+', ',', '-', '.', '/',
|
|
|
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
|
|
|
|
'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
|
|
|
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '[','\\', ']', '^', '_',
|
|
|
|
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
|
|
|
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0,
|
|
|
|
};
|
|
|
|
return table_tolower[c];
|
2015-05-28 17:04:41 +08:00
|
|
|
}
|
|
|
|
|
2015-03-31 22:16:04 +08:00
|
|
|
/*! Returns true if \p c1 compare equals to \p c2
|
|
|
|
*
|
|
|
|
* Comparison is case-insensitive
|
|
|
|
*/
|
|
|
|
GMIO_INLINE gmio_bool_t gmio_clocale_char_iequals(char c1, char c2)
|
|
|
|
{
|
2015-10-22 00:37:21 +08:00
|
|
|
/* TODO: eliminate branch */
|
2015-05-28 17:04:41 +08:00
|
|
|
return c1 == c2 || (gmio_clocale_toupper(c1) == gmio_clocale_toupper(c2));
|
2015-03-31 22:16:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*! Returns 0 if \p str1 and \p str2 compare equal, non-zero otherwise
|
|
|
|
*
|
|
|
|
* Comparison is case-insensitive
|
|
|
|
*/
|
|
|
|
GMIO_INLINE int gmio_stricmp(const char* str1, const char* str2)
|
|
|
|
{
|
|
|
|
while (*str1 != 0 && *str2 != 0) {
|
2015-10-22 00:37:21 +08:00
|
|
|
if (!gmio_clocale_char_iequals(*str1, *str2))
|
2015-03-31 22:16:04 +08:00
|
|
|
return 1;
|
|
|
|
++str1;
|
|
|
|
++str2;
|
|
|
|
}
|
|
|
|
return *str1 == 0 && *str2 == 0 ? 0 : 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! Returns true if \p str starts with string \p begin
|
|
|
|
*
|
|
|
|
* Comparison is case-insensitive
|
|
|
|
*/
|
|
|
|
GMIO_INLINE gmio_bool_t gmio_istarts_with(const char* str, const char* begin)
|
|
|
|
{
|
|
|
|
while (*begin != 0) {
|
|
|
|
if (*str == 0
|
|
|
|
|| gmio_clocale_char_iequals(*str, *begin) == GMIO_FALSE)
|
|
|
|
{
|
|
|
|
return GMIO_FALSE;
|
|
|
|
}
|
|
|
|
++str;
|
|
|
|
++begin;
|
|
|
|
}
|
|
|
|
return GMIO_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* GMIO_INTERNAL_STRING_UTILS_H */
|