From 2118b725707d2482dc853b6ee0e14200fcb3bb6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Tue, 10 Jan 2017 22:02:33 -0800 Subject: [PATCH] Cleanup. --- include/bx/string.h | 448 +++--------------------------------------- src/commandline.cpp | 2 + src/os.cpp | 2 + src/string.cpp | 468 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 496 insertions(+), 424 deletions(-) create mode 100644 src/string.cpp diff --git a/include/bx/string.h b/include/bx/string.h index 44002f5..07e40c3 100644 --- a/include/bx/string.h +++ b/include/bx/string.h @@ -8,10 +8,7 @@ #include "bx.h" #include -#include // tolower #include // va_list -#include // vsnprintf, vsnwprintf -#include #include // wchar_t #include @@ -24,359 +21,69 @@ namespace bx { /// - inline bool toBool(const char* _str) - { - char ch = (char)::tolower(_str[0]); - return ch == 't' || ch == '1'; - } + bool toBool(const char* _str); /// Case insensitive string compare. - inline int32_t stricmp(const char* _a, const char* _b) - { -#if BX_CRT_MSVC - return ::_stricmp(_a, _b); -#else - return ::strcasecmp(_a, _b); -#endif // BX_COMPILER_ - } + int32_t stricmp(const char* _a, const char* _b); /// - inline size_t strnlen(const char* _str, size_t _max) - { - const char* ptr; - for (ptr = _str; 0 < _max && *ptr != '\0'; ++ptr, --_max) {}; - return ptr - _str; - } + size_t strnlen(const char* _str, size_t _max); /// Copy _num characters from string _src to _dst buffer of maximum _dstSize capacity /// including zero terminator. Copy will be terminated with '\0'. - inline size_t strlncpy(char* _dst, size_t _dstSize, const char* _src, size_t _num = -1) - { - BX_CHECK(NULL != _dst, "_dst can't be NULL!"); - BX_CHECK(NULL != _src, "_src can't be NULL!"); - BX_CHECK(0 < _dstSize, "_dstSize can't be 0!"); - - const size_t len = strnlen(_src, _num); - const size_t max = _dstSize-1; - const size_t num = (len < max ? len : max); - strncpy(_dst, _src, num); - _dst[num] = '\0'; - - return num; - } + size_t strlncpy(char* _dst, size_t _dstSize, const char* _src, size_t _num = -1); /// Find substring in string. Limit search to _size. - inline const char* strnstr(const char* _str, const char* _find, size_t _size) - { - char first = *_find; - if ('\0' == first) - { - return _str; - } - - const char* cmp = _find + 1; - size_t len = strlen(cmp); - do - { - for (char match = *_str++; match != first && 0 < _size; match = *_str++, --_size) - { - if ('\0' == match) - { - return NULL; - } - } - - if (0 == _size) - { - return NULL; - } - - } while (0 != strncmp(_str, cmp, len) ); - - return --_str; - } + const char* strnstr(const char* _str, const char* _find, size_t _size); /// Find substring in string. Case insensitive. - inline const char* stristr(const char* _str, const char* _find) - { - const char* ptr = _str; - - for (size_t len = strlen(_str), searchLen = strlen(_find) - ; len >= searchLen - ; ++ptr, --len) - { - // Find start of the string. - while (tolower(*ptr) != tolower(*_find) ) - { - ++ptr; - --len; - - // Search pattern lenght can't be longer than the string. - if (searchLen > len) - { - return NULL; - } - } - - // Set pointers. - const char* string = ptr; - const char* search = _find; - - // Start comparing. - while (tolower(*string++) == tolower(*search++) ) - { - // If end of the 'search' string is reached, all characters match. - if ('\0' == *search) - { - return ptr; - } - } - } - - return NULL; - } + const char* stristr(const char* _str, const char* _find); /// Find substring in string. Case insensitive. Limit search to _max. - inline const char* stristr(const char* _str, const char* _find, size_t _max) - { - const char* ptr = _str; - - size_t stringLen = strnlen(_str, _max); - const size_t findLen = strlen(_find); - - for (; stringLen >= findLen; ++ptr, --stringLen) - { - // Find start of the string. - while (tolower(*ptr) != tolower(*_find) ) - { - ++ptr; - --stringLen; - - // Search pattern lenght can't be longer than the string. - if (findLen > stringLen) - { - return NULL; - } - } - - // Set pointers. - const char* string = ptr; - const char* search = _find; - - // Start comparing. - while (tolower(*string++) == tolower(*search++) ) - { - // If end of the 'search' string is reached, all characters match. - if ('\0' == *search) - { - return ptr; - } - } - } - - return NULL; - } + const char* stristr(const char* _str, const char* _find, size_t _max); /// Find new line. Returns pointer after new line terminator. - inline const char* strnl(const char* _str) - { - for (; '\0' != *_str; _str += strnlen(_str, 1024) ) - { - const char* eol = strnstr(_str, "\r\n", 1024); - if (NULL != eol) - { - return eol + 2; - } - - eol = strnstr(_str, "\n", 1024); - if (NULL != eol) - { - return eol + 1; - } - } - - return _str; - } + const char* strnl(const char* _str); /// Find end of line. Retuns pointer to new line terminator. - inline const char* streol(const char* _str) - { - for (; '\0' != *_str; _str += strnlen(_str, 1024) ) - { - const char* eol = strnstr(_str, "\r\n", 1024); - if (NULL != eol) - { - return eol; - } - - eol = strnstr(_str, "\n", 1024); - if (NULL != eol) - { - return eol; - } - } - - return _str; - } + const char* streol(const char* _str); /// Skip whitespace. - inline const char* strws(const char* _str) - { - for (; isspace(*_str); ++_str) {}; - return _str; - } + const char* strws(const char* _str); /// Skip non-whitespace. - inline const char* strnws(const char* _str) - { - for (; !isspace(*_str); ++_str) {}; - return _str; - } + const char* strnws(const char* _str); /// Skip word. - inline const char* strword(const char* _str) - { - for (char ch = *_str++; isalnum(ch) || '_' == ch; ch = *_str++) {}; - return _str-1; - } + const char* strword(const char* _str); /// Find matching block. - inline const char* strmb(const char* _str, char _open, char _close) - { - int count = 0; - for (char ch = *_str++; ch != '\0' && count >= 0; ch = *_str++) - { - if (ch == _open) - { - count++; - } - else if (ch == _close) - { - count--; - if (0 == count) - { - return _str-1; - } - } - } - - return NULL; - } + const char* strmb(const char* _str, char _open, char _close); // Normalize string to sane line endings. - inline void eolLF(char* _out, size_t _size, const char* _str) - { - if (0 < _size) - { - char* end = _out + _size - 1; - for (char ch = *_str++; ch != '\0' && _out < end; ch = *_str++) - { - if ('\r' != ch) - { - *_out++ = ch; - } - } - - *_out = '\0'; - } - } + void eolLF(char* _out, size_t _size, const char* _str); // Finds identifier. - inline const char* findIdentifierMatch(const char* _str, const char* _word) - { - size_t len = strlen(_word); - const char* ptr = strstr(_str, _word); - for (; NULL != ptr; ptr = strstr(ptr + len, _word) ) - { - if (ptr != _str) - { - char ch = *(ptr - 1); - if (isalnum(ch) || '_' == ch) - { - continue; - } - } - - char ch = ptr[len]; - if (isalnum(ch) || '_' == ch) - { - continue; - } - - return ptr; - } - - return ptr; - } + const char* findIdentifierMatch(const char* _str, const char* _word); // Finds any identifier from NULL terminated array of identifiers. - inline const char* findIdentifierMatch(const char* _str, const char* _words[]) - { - for (const char* word = *_words; NULL != word; ++_words, word = *_words) - { - const char* match = findIdentifierMatch(_str, word); - if (NULL != match) - { - return match; - } - } - - return NULL; - } + const char* findIdentifierMatch(const char* _str, const char* _words[]); /// Cross platform implementation of vsnprintf that returns number of /// characters which would have been written to the final string if /// enough space had been available. - inline int32_t vsnprintf(char* _str, size_t _count, const char* _format, va_list _argList) - { -#if BX_COMPILER_MSVC - va_list argListCopy; - va_copy(argListCopy, _argList); - int32_t len = ::vsnprintf_s(_str, _count, size_t(-1), _format, argListCopy); - va_end(argListCopy); - return -1 == len ? ::_vscprintf(_format, _argList) : len; -#else - return ::vsnprintf(_str, _count, _format, _argList); -#endif // BX_COMPILER_MSVC - } + int32_t vsnprintf(char* _str, size_t _count, const char* _format, va_list _argList); /// Cross platform implementation of vsnwprintf that returns number of /// characters which would have been written to the final string if /// enough space had been available. - inline int32_t vsnwprintf(wchar_t* _str, size_t _count, const wchar_t* _format, va_list _argList) - { -#if BX_COMPILER_MSVC - va_list argListCopy; - va_copy(argListCopy, _argList); - int32_t len = ::_vsnwprintf_s(_str, _count, size_t(-1), _format, argListCopy); - va_end(argListCopy); - return -1 == len ? ::_vscwprintf(_format, _argList) : len; -#elif defined(__MINGW32__) - return ::vsnwprintf(_str, _count, _format, _argList); -#else - return ::vswprintf(_str, _count, _format, _argList); -#endif // BX_COMPILER_MSVC - } + int32_t vsnwprintf(wchar_t* _str, size_t _count, const wchar_t* _format, va_list _argList); /// - inline int32_t snprintf(char* _str, size_t _count, const char* _format, ...) // BX_PRINTF_ARGS(3, 4) - { - va_list argList; - va_start(argList, _format); - int32_t len = vsnprintf(_str, _count, _format, argList); - va_end(argList); - return len; - } + int32_t snprintf(char* _str, size_t _count, const char* _format, ...); /// - inline int32_t swnprintf(wchar_t* _out, size_t _count, const wchar_t* _format, ...) - { - va_list argList; - va_start(argList, _format); - int32_t len = vsnwprintf(_out, _count, _format, argList); - va_end(argList); - return len; - } + int32_t swnprintf(wchar_t* _out, size_t _count, const wchar_t* _format, ...); /// template @@ -423,129 +130,22 @@ namespace bx } /// Extract base file name from file path. - inline const char* baseName(const char* _filePath) - { - const char* bs = strrchr(_filePath, '\\'); - const char* fs = strrchr(_filePath, '/'); - const char* slash = (bs > fs ? bs : fs); - const char* colon = strrchr(_filePath, ':'); - const char* basename = slash > colon ? slash : colon; - if (NULL != basename) - { - return basename+1; - } - - return _filePath; - } + const char* baseName(const char* _filePath); /// Convert size in bytes to human readable string. - inline void prettify(char* _out, size_t _count, uint64_t _size) - { - uint8_t idx = 0; - double size = double(_size); - while (_size != (_size&0x7ff) - && idx < 9) - { - _size >>= 10; - size *= 1.0/1024.0; - ++idx; - } - - snprintf(_out, _count, "%0.2f %c%c", size, "BkMGTPEZY"[idx], idx > 0 ? 'B' : '\0'); - } - - /* - * Copyright (c) 1998 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ + void prettify(char* _out, size_t _count, uint64_t _size); /// Copy src to string dst of size siz. At most siz-1 characters /// will be copied. Always NUL terminates (unless siz == 0). /// Returns strlen(src); if retval >= siz, truncation occurred. - inline size_t strlcpy(char* _dst, const char* _src, size_t _siz) - { - char* dd = _dst; - const char* ss = _src; - size_t nn = _siz; - - /* Copy as many bytes as will fit */ - if (nn != 0) - { - while (--nn != 0) - { - if ( (*dd++ = *ss++) == '\0') - { - break; - } - } - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (nn == 0) - { - if (_siz != 0) - { - *dd = '\0'; /* NUL-terminate dst */ - } - - while (*ss++) - { - } - } - - return(ss - _src - 1); /* count does not include NUL */ - } + size_t strlcpy(char* _dst, const char* _src, size_t _siz); /// Appends src to string dst of size siz (unlike strncat, siz is the /// full size of dst, not space left). At most siz-1 characters /// will be copied. Always NUL terminates (unless siz <= strlen(dst)). /// Returns strlen(src) + MIN(siz, strlen(initial dst)). /// If retval >= siz, truncation occurred. - inline size_t strlcat(char* _dst, const char* _src, size_t _siz) - { - char* dd = _dst; - const char *s = _src; - size_t nn = _siz; - size_t dlen; - - /* Find the end of dst and adjust bytes left but don't go past end */ - while (nn-- != 0 && *dd != '\0') - { - dd++; - } - - dlen = dd - _dst; - nn = _siz - dlen; - - if (nn == 0) - { - return(dlen + strlen(s)); - } - - while (*s != '\0') - { - if (nn != 1) - { - *dd++ = *s; - nn--; - } - s++; - } - *dd = '\0'; - - return(dlen + (s - _src)); /* count does not include NUL */ - } + size_t strlcat(char* _dst, const char* _src, size_t _siz); /// Non-zero-terminated string view. class StringView diff --git a/src/commandline.cpp b/src/commandline.cpp index c46b67f..3e609e9 100644 --- a/src/commandline.cpp +++ b/src/commandline.cpp @@ -5,6 +5,8 @@ #include +#include + namespace bx { // Reference: diff --git a/src/os.cpp b/src/os.cpp index dbdcd69..7123dc8 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -7,6 +7,8 @@ #include #include +#include + #if BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT # include # include diff --git a/src/string.cpp b/src/string.cpp new file mode 100644 index 0000000..7d48bce --- /dev/null +++ b/src/string.cpp @@ -0,0 +1,468 @@ +/* + * Copyright 2010-2017 Branimir Karadzic. All rights reserved. + * License: https://github.com/bkaradzic/bx#license-bsd-2-clause + */ + +#include +#include // tolower +#include // va_list +#include // vsnprintf, vsnwprintf +#include +#include // wchar_t + +#include + +#include +#include + +#ifndef va_copy +# define va_copy(_a, _b) (_a) = (_b) +#endif // va_copy + +namespace bx +{ + bool toBool(const char* _str) + { + char ch = (char)::tolower(_str[0]); + return ch == 't' || ch == '1'; + } + + int32_t stricmp(const char* _a, const char* _b) + { +#if BX_CRT_MSVC + return ::_stricmp(_a, _b); +#else + return ::strcasecmp(_a, _b); +#endif // BX_COMPILER_ + } + + size_t strnlen(const char* _str, size_t _max) + { + const char* ptr; + for (ptr = _str; 0 < _max && *ptr != '\0'; ++ptr, --_max) {}; + return ptr - _str; + } + + size_t strlncpy(char* _dst, size_t _dstSize, const char* _src, size_t _num) + { + BX_CHECK(NULL != _dst, "_dst can't be NULL!"); + BX_CHECK(NULL != _src, "_src can't be NULL!"); + BX_CHECK(0 < _dstSize, "_dstSize can't be 0!"); + + const size_t len = strnlen(_src, _num); + const size_t max = _dstSize-1; + const size_t num = (len < max ? len : max); + strncpy(_dst, _src, num); + _dst[num] = '\0'; + + return num; + } + + const char* strnstr(const char* _str, const char* _find, size_t _size) + { + char first = *_find; + if ('\0' == first) + { + return _str; + } + + const char* cmp = _find + 1; + size_t len = strlen(cmp); + do + { + for (char match = *_str++; match != first && 0 < _size; match = *_str++, --_size) + { + if ('\0' == match) + { + return NULL; + } + } + + if (0 == _size) + { + return NULL; + } + + } while (0 != strncmp(_str, cmp, len) ); + + return --_str; + } + + const char* stristr(const char* _str, const char* _find) + { + const char* ptr = _str; + + for (size_t len = strlen(_str), searchLen = strlen(_find) + ; len >= searchLen + ; ++ptr, --len) + { + // Find start of the string. + while (tolower(*ptr) != tolower(*_find) ) + { + ++ptr; + --len; + + // Search pattern lenght can't be longer than the string. + if (searchLen > len) + { + return NULL; + } + } + + // Set pointers. + const char* string = ptr; + const char* search = _find; + + // Start comparing. + while (tolower(*string++) == tolower(*search++) ) + { + // If end of the 'search' string is reached, all characters match. + if ('\0' == *search) + { + return ptr; + } + } + } + + return NULL; + } + + const char* stristr(const char* _str, const char* _find, size_t _max) + { + const char* ptr = _str; + + size_t stringLen = strnlen(_str, _max); + const size_t findLen = strlen(_find); + + for (; stringLen >= findLen; ++ptr, --stringLen) + { + // Find start of the string. + while (tolower(*ptr) != tolower(*_find) ) + { + ++ptr; + --stringLen; + + // Search pattern lenght can't be longer than the string. + if (findLen > stringLen) + { + return NULL; + } + } + + // Set pointers. + const char* string = ptr; + const char* search = _find; + + // Start comparing. + while (tolower(*string++) == tolower(*search++) ) + { + // If end of the 'search' string is reached, all characters match. + if ('\0' == *search) + { + return ptr; + } + } + } + + return NULL; + } + + const char* strnl(const char* _str) + { + for (; '\0' != *_str; _str += strnlen(_str, 1024) ) + { + const char* eol = strnstr(_str, "\r\n", 1024); + if (NULL != eol) + { + return eol + 2; + } + + eol = strnstr(_str, "\n", 1024); + if (NULL != eol) + { + return eol + 1; + } + } + + return _str; + } + + const char* streol(const char* _str) + { + for (; '\0' != *_str; _str += strnlen(_str, 1024) ) + { + const char* eol = strnstr(_str, "\r\n", 1024); + if (NULL != eol) + { + return eol; + } + + eol = strnstr(_str, "\n", 1024); + if (NULL != eol) + { + return eol; + } + } + + return _str; + } + + const char* strws(const char* _str) + { + for (; isspace(*_str); ++_str) {}; + return _str; + } + + const char* strnws(const char* _str) + { + for (; !isspace(*_str); ++_str) {}; + return _str; + } + + const char* strword(const char* _str) + { + for (char ch = *_str++; isalnum(ch) || '_' == ch; ch = *_str++) {}; + return _str-1; + } + + const char* strmb(const char* _str, char _open, char _close) + { + int count = 0; + for (char ch = *_str++; ch != '\0' && count >= 0; ch = *_str++) + { + if (ch == _open) + { + count++; + } + else if (ch == _close) + { + count--; + if (0 == count) + { + return _str-1; + } + } + } + + return NULL; + } + + void eolLF(char* _out, size_t _size, const char* _str) + { + if (0 < _size) + { + char* end = _out + _size - 1; + for (char ch = *_str++; ch != '\0' && _out < end; ch = *_str++) + { + if ('\r' != ch) + { + *_out++ = ch; + } + } + + *_out = '\0'; + } + } + + const char* findIdentifierMatch(const char* _str, const char* _word) + { + size_t len = strlen(_word); + const char* ptr = strstr(_str, _word); + for (; NULL != ptr; ptr = strstr(ptr + len, _word) ) + { + if (ptr != _str) + { + char ch = *(ptr - 1); + if (isalnum(ch) || '_' == ch) + { + continue; + } + } + + char ch = ptr[len]; + if (isalnum(ch) || '_' == ch) + { + continue; + } + + return ptr; + } + + return ptr; + } + + const char* findIdentifierMatch(const char* _str, const char* _words[]) + { + for (const char* word = *_words; NULL != word; ++_words, word = *_words) + { + const char* match = findIdentifierMatch(_str, word); + if (NULL != match) + { + return match; + } + } + + return NULL; + } + + int32_t vsnprintf(char* _str, size_t _count, const char* _format, va_list _argList) + { +#if BX_COMPILER_MSVC + va_list argListCopy; + va_copy(argListCopy, _argList); + int32_t len = ::vsnprintf_s(_str, _count, size_t(-1), _format, argListCopy); + va_end(argListCopy); + return -1 == len ? ::_vscprintf(_format, _argList) : len; +#else + return ::vsnprintf(_str, _count, _format, _argList); +#endif // BX_COMPILER_MSVC + } + + int32_t vsnwprintf(wchar_t* _str, size_t _count, const wchar_t* _format, va_list _argList) + { +#if BX_COMPILER_MSVC + va_list argListCopy; + va_copy(argListCopy, _argList); + int32_t len = ::_vsnwprintf_s(_str, _count, size_t(-1), _format, argListCopy); + va_end(argListCopy); + return -1 == len ? ::_vscwprintf(_format, _argList) : len; +#elif defined(__MINGW32__) + return ::vsnwprintf(_str, _count, _format, _argList); +#else + return ::vswprintf(_str, _count, _format, _argList); +#endif // BX_COMPILER_MSVC + } + + int32_t snprintf(char* _str, size_t _count, const char* _format, ...) + { + va_list argList; + va_start(argList, _format); + int32_t len = vsnprintf(_str, _count, _format, argList); + va_end(argList); + return len; + } + + int32_t swnprintf(wchar_t* _out, size_t _count, const wchar_t* _format, ...) + { + va_list argList; + va_start(argList, _format); + int32_t len = vsnwprintf(_out, _count, _format, argList); + va_end(argList); + return len; + } + + const char* baseName(const char* _filePath) + { + const char* bs = strrchr(_filePath, '\\'); + const char* fs = strrchr(_filePath, '/'); + const char* slash = (bs > fs ? bs : fs); + const char* colon = strrchr(_filePath, ':'); + const char* basename = slash > colon ? slash : colon; + if (NULL != basename) + { + return basename+1; + } + + return _filePath; + } + + void prettify(char* _out, size_t _count, uint64_t _size) + { + uint8_t idx = 0; + double size = double(_size); + while (_size != (_size&0x7ff) + && idx < 9) + { + _size >>= 10; + size *= 1.0/1024.0; + ++idx; + } + + snprintf(_out, _count, "%0.2f %c%c", size, "BkMGTPEZY"[idx], idx > 0 ? 'B' : '\0'); + } + + /* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + size_t strlcpy(char* _dst, const char* _src, size_t _siz) + { + char* dd = _dst; + const char* ss = _src; + size_t nn = _siz; + + /* Copy as many bytes as will fit */ + if (nn != 0) + { + while (--nn != 0) + { + if ( (*dd++ = *ss++) == '\0') + { + break; + } + } + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (nn == 0) + { + if (_siz != 0) + { + *dd = '\0'; /* NUL-terminate dst */ + } + + while (*ss++) + { + } + } + + return(ss - _src - 1); /* count does not include NUL */ + } + + size_t strlcat(char* _dst, const char* _src, size_t _siz) + { + char* dd = _dst; + const char *s = _src; + size_t nn = _siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (nn-- != 0 && *dd != '\0') + { + dd++; + } + + dlen = dd - _dst; + nn = _siz - dlen; + + if (nn == 0) + { + return(dlen + strlen(s)); + } + + while (*s != '\0') + { + if (nn != 1) + { + *dd++ = *s; + nn--; + } + s++; + } + *dd = '\0'; + + return(dlen + (s - _src)); /* count does not include NUL */ + } + +} // namespace bx