michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: michael@0: /** michael@0: * MODULE NOTES: michael@0: * @update gess7/30/98 michael@0: * michael@0: * Much as I hate to do it, we were using string compares wrong. michael@0: * Often, programmers call functions like strcmp(s1,s2), and pass michael@0: * one or more null strings. Rather than blow up on these, I've michael@0: * added quick checks to ensure that cases like this don't cause michael@0: * us to fail. michael@0: * michael@0: * In general, if you pass a null into any of these string compare michael@0: * routines, we simply return 0. michael@0: */ michael@0: michael@0: michael@0: #include "nsCRT.h" michael@0: #include "nsDebug.h" michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // My lovely strtok routine michael@0: michael@0: #define IS_DELIM(m, c) ((m)[(c) >> 3] & (1 << ((c) & 7))) michael@0: #define SET_DELIM(m, c) ((m)[(c) >> 3] |= (1 << ((c) & 7))) michael@0: #define DELIM_TABLE_SIZE 32 michael@0: michael@0: char* nsCRT::strtok(char* string, const char* delims, char* *newStr) michael@0: { michael@0: NS_ASSERTION(string, "Unlike regular strtok, the first argument cannot be null."); michael@0: michael@0: char delimTable[DELIM_TABLE_SIZE]; michael@0: uint32_t i; michael@0: char* result; michael@0: char* str = string; michael@0: michael@0: for (i = 0; i < DELIM_TABLE_SIZE; i++) michael@0: delimTable[i] = '\0'; michael@0: michael@0: for (i = 0; delims[i]; i++) { michael@0: SET_DELIM(delimTable, static_cast(delims[i])); michael@0: } michael@0: NS_ASSERTION(delims[i] == '\0', "too many delimiters"); michael@0: michael@0: // skip to beginning michael@0: while (*str && IS_DELIM(delimTable, static_cast(*str))) { michael@0: str++; michael@0: } michael@0: result = str; michael@0: michael@0: // fix up the end of the token michael@0: while (*str) { michael@0: if (IS_DELIM(delimTable, static_cast(*str))) { michael@0: *str++ = '\0'; michael@0: break; michael@0: } michael@0: str++; michael@0: } michael@0: *newStr = str; michael@0: michael@0: return str == result ? nullptr : result; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * Compare unichar string ptrs, stopping at the 1st null michael@0: * NOTE: If both are null, we return 0. michael@0: * NOTE: We terminate the search upon encountering a nullptr michael@0: * michael@0: * @update gess 11/10/99 michael@0: * @param s1 and s2 both point to unichar strings michael@0: * @return 0 if they match, -1 if s1s2 michael@0: */ michael@0: int32_t nsCRT::strcmp(const char16_t* s1, const char16_t* s2) { michael@0: if(s1 && s2) { michael@0: for (;;) { michael@0: char16_t c1 = *s1++; michael@0: char16_t c2 = *s2++; michael@0: if (c1 != c2) { michael@0: if (c1 < c2) return -1; michael@0: return 1; michael@0: } michael@0: if ((0==c1) || (0==c2)) break; michael@0: } michael@0: } michael@0: else { michael@0: if (s1) // s2 must have been null michael@0: return -1; michael@0: if (s2) // s1 must have been null michael@0: return 1; michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: /** michael@0: * Compare unichar string ptrs, stopping at the 1st null or nth char. michael@0: * NOTE: If either is null, we return 0. michael@0: * NOTE: We DO NOT terminate the search upon encountering nullptr's before N michael@0: * michael@0: * @update gess 11/10/99 michael@0: * @param s1 and s2 both point to unichar strings michael@0: * @return 0 if they match, -1 if s1s2 michael@0: */ michael@0: int32_t nsCRT::strncmp(const char16_t* s1, const char16_t* s2, uint32_t n) { michael@0: if(s1 && s2) { michael@0: if(n != 0) { michael@0: do { michael@0: char16_t c1 = *s1++; michael@0: char16_t c2 = *s2++; michael@0: if (c1 != c2) { michael@0: if (c1 < c2) return -1; michael@0: return 1; michael@0: } michael@0: } while (--n != 0); michael@0: } michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: const char* nsCRT::memmem(const char* haystack, uint32_t haystackLen, michael@0: const char* needle, uint32_t needleLen) michael@0: { michael@0: // Sanity checking michael@0: if (!(haystack && needle && haystackLen && needleLen && michael@0: needleLen <= haystackLen)) michael@0: return nullptr; michael@0: michael@0: #ifdef HAVE_MEMMEM michael@0: return (const char*)::memmem(haystack, haystackLen, needle, needleLen); michael@0: #else michael@0: // No memmem means we need to roll our own. This isn't really optimized michael@0: // for performance ... if that becomes an issue we can take some inspiration michael@0: // from the js string compare code in jsstr.cpp michael@0: for (uint32_t i = 0; i < haystackLen - needleLen; i++) { michael@0: if (!memcmp(haystack + i, needle, needleLen)) michael@0: return haystack + i; michael@0: } michael@0: #endif michael@0: return nullptr; michael@0: } michael@0: michael@0: // This should use NSPR but NSPR isn't exporting its PR_strtoll function michael@0: // Until then... michael@0: int64_t nsCRT::atoll(const char *str) michael@0: { michael@0: if (!str) michael@0: return 0; michael@0: michael@0: int64_t ll = 0; michael@0: michael@0: while (*str && *str >= '0' && *str <= '9') { michael@0: ll *= 10; michael@0: ll += *str - '0'; michael@0: str++; michael@0: } michael@0: michael@0: return ll; michael@0: } michael@0: