fixed #3: CompareNoCase incorrectly returned that string1 is greater than string2 for some characters

when converting from 'char' to 'int' we should first convert to 'unsigned char' and then to 'int'
This commit is contained in:
Tomasz Sowa 2021-05-08 22:37:31 +02:00
parent 463cec3283
commit b055c46ae8
3 changed files with 176 additions and 40 deletions

View File

@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2017-2018, Tomasz Sowa * Copyright (c) 2017-2021, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -153,42 +153,55 @@ bool IsDigit(wchar_t c, int base, int * digit)
wchar_t ToLower(wchar_t c) char ToLower(char c)
{ {
if( c >= 'A' && c <= 'Z' ) return pt_private::ToLowerGeneric(c);
return c - 'A' + 'a';
return c;
} }
wchar_t ToLower(wchar_t c)
{
return pt_private::ToLowerGeneric(c);
}
char ToUpper(char c)
{
return pt_private::ToUpperGeneric(c);
}
wchar_t ToUpper(wchar_t c) wchar_t ToUpper(wchar_t c)
{ {
if( c >= 'a' && c <= 'z' ) return pt_private::ToUpperGeneric(c);
return c - 'a' + 'A';
return c;
} }
void ToLower(std::wstring & s)
void ToLower(std::string & str)
{ {
std::wstring::size_type i; pt_private::ToLowerStrGeneric(str);
for(i=0 ; i<s.size() ; ++i)
s[i] = ToLower(s[i]);
} }
void ToLower(std::wstring & str)
void ToUpper(std::wstring & s)
{ {
std::wstring::size_type i; pt_private::ToLowerStrGeneric(str);
for(i=0 ; i<s.size() ; ++i)
s[i] = ToUpper(s[i]);
} }
void ToUpper(std::string & str)
{
pt_private::ToLowerStrGeneric(str);
}
void ToUpper(std::wstring & str)
{
pt_private::ToLowerStrGeneric(str);
}
} }

View File

@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2017-2018, Tomasz Sowa * Copyright (c) 2017-2021, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -38,7 +38,7 @@
#ifndef headerfile_picotools_convert_text #ifndef headerfile_picotools_convert_text
#define headerfile_picotools_convert_text #define headerfile_picotools_convert_text
#include <string> #include "text_private.h"
@ -51,6 +51,23 @@ bool IsWhite(wchar_t c, bool check_additional_chars = true, bool treat_new_line_
bool IsDigit(wchar_t c, int base = 10, int * digit = 0); bool IsDigit(wchar_t c, int base = 10, int * digit = 0);
char ToLower(char c);
wchar_t ToLower(wchar_t c);
char ToUpper(char c);
wchar_t ToUpper(wchar_t c);
// rename to something like to_lower_emplace
// and add to_lower which returns string
void ToLower(std::string & str);
void ToLower(std::wstring & str);
void ToUpper(std::string & str);
void ToUpper(std::wstring & str);
////////////////////////////
template<class CharType> template<class CharType>
CharType * SkipWhite(CharType * str, bool check_additional_chars = true, bool treat_new_line_as_white = true) CharType * SkipWhite(CharType * str, bool check_additional_chars = true, bool treat_new_line_as_white = true)
{ {
@ -97,19 +114,6 @@ CharType * SkipWhiteFromBack(CharType * str, bool check_additional_chars = true,
} }
wchar_t ToLower(wchar_t c);
wchar_t ToUpper(wchar_t c);
// change to a template
void ToLower(std::wstring & s);
void ToUpper(std::wstring & s);
template<class StringType1, class StringType2> template<class StringType1, class StringType2>
int CompareNoCase(const StringType1 * str1, const StringType2 * str2) int CompareNoCase(const StringType1 * str1, const StringType2 * str2)
{ {
@ -122,7 +126,21 @@ int CompareNoCase(const StringType1 * str1, const StringType2 * str2)
if( *str1 == 0 && *str2 == 0 ) if( *str1 == 0 && *str2 == 0 )
return 0; return 0;
return (int)ToLower(*str1) - (int)ToLower(*str2); int c1;
int c2;
if constexpr (sizeof(StringType1) == 1 && sizeof(StringType2) == 1)
{
c1 = ToLower((wchar_t)(unsigned char)(*str1));
c2 = ToLower((wchar_t)(unsigned char)(*str2));
}
else
{
c1 = ToLower(*str1);
c2 = ToLower(*str2);
}
return c1 - c2;
} }
@ -154,12 +172,21 @@ int CompareNoCase(const StringType1 * str1_begin, const StringType1 * str1_end,
if( str1_begin == str1_end && *str2 == 0 ) if( str1_begin == str1_end && *str2 == 0 )
return 0; return 0;
wchar_t str1_char = 0; int c1;
int c2;
if( str1_begin < str1_end ) if constexpr (sizeof(StringType1) == 1 && sizeof(StringType2) == 1)
str1_char = *str1_begin; {
c1 = str1_begin < str1_end ? ToLower((wchar_t)(unsigned char)(*str1_begin)) : 0;
c2 = ToLower((wchar_t)(unsigned char)(*str2));
}
else
{
c1 = str1_begin < str1_end ? ToLower(*str1_begin) : 0;
c2 = ToLower(*str2);
}
return (int)ToLower(str1_char) - (int)ToLower(*str2); return c1 - c2;
} }

96
convert/text_private.h Normal file
View File

@ -0,0 +1,96 @@
/*
* This file is a part of PikoTools
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2021, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * 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.
*
* * Neither the name Tomasz Sowa nor the names of contributors to this
* project 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 OWNER 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.
*/
#ifndef headerfile_picotools_convert_text_private
#define headerfile_picotools_convert_text_private
#include <string>
namespace PT
{
namespace pt_private
{
template<class CharType>
CharType ToLowerGeneric(CharType c)
{
if( c >= 'A' && c <= 'Z' )
return c - 'A' + 'a';
return c;
}
template<class CharType>
CharType ToUpperGeneric(CharType c)
{
if( c >= 'a' && c <= 'z' )
return c - 'a' + 'A';
return c;
}
template<class StringType>
void ToLowerStrGeneric(StringType & s)
{
typename StringType::size_type i;
for(i=0 ; i<s.size() ; ++i)
s[i] = ToLowerGeneric(s[i]);
}
template<class StringType>
void ToUpperStrGeneric(StringType & s)
{
typename StringType::size_type i;
for(i=0 ; i<s.size() ; ++i)
s[i] = ToUpperGeneric(s[i]);
}
} // namespace pt_private
} // namespace PT
#endif