Skip to content

Commit

Permalink
Add and use our own ASCII routines
Browse files Browse the repository at this point in the history
`std::tolower` and `std::toupper` are locale-dependent and should not be
used anywhere we currently use them.

Adds and switches to our own implementations for these and other
locale-dependent functions.
  • Loading branch information
glebm committed Jun 18, 2019
1 parent 9616e95 commit 03bf13c
Show file tree
Hide file tree
Showing 14 changed files with 137 additions and 58 deletions.
2 changes: 0 additions & 2 deletions src/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
#include "sass.hpp"

#include "ast.hpp"
#include <cctype>
#include <locale>

namespace Sass {

Expand Down
20 changes: 11 additions & 9 deletions src/ast_selectors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -652,15 +652,17 @@ namespace Sass {
CssMediaQuery_Obj CssMediaQuery::merge(CssMediaQuery_Obj& other)
{

std::string ourType(this->type());
std::string theirType(other->type());
std::string ourModifier(this->modifier());
std::string theirModifier(other->modifier());

std::transform(ourType.begin(), ourType.end(), ourType.begin(), ::tolower);
std::transform(theirType.begin(), theirType.end(), theirType.begin(), ::tolower);
std::transform(ourModifier.begin(), ourModifier.end(), ourModifier.begin(), ::tolower);
std::transform(theirModifier.begin(), theirModifier.end(), theirModifier.begin(), ::tolower);
std::string ourType = this->type();
Util::ascii_str_tolower(&ourType);

std::string theirType = other->type();
Util::ascii_str_tolower(&theirType);

std::string ourModifier = this->modifier();
Util::ascii_str_tolower(&ourModifier);

std::string theirModifier = other->modifier();
Util::ascii_str_tolower(&theirModifier);

std::string type;
std::string modifier;
Expand Down
5 changes: 3 additions & 2 deletions src/color_maps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "ast.hpp"
#include "color_maps.hpp"
#include "util_string.hpp"

namespace Sass {

Expand Down Expand Up @@ -616,8 +617,8 @@ namespace Sass {
const Color_RGBA* name_to_color(const std::string& key)
{
// case insensitive lookup. See #2462
std::string lower{key};
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
std::string lower = key;
Util::ascii_str_tolower(&lower);

auto p = names_to_colors->find(lower);
if (p != names_to_colors->end()) {
Expand Down
22 changes: 11 additions & 11 deletions src/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#else
# include <unistd.h>
#endif
#include <cctype>
#include <cstdio>
#include <vector>
#include <algorithm>
Expand All @@ -25,6 +24,7 @@
#include "sass_functions.hpp"
#include "error_handling.hpp"
#include "util.hpp"
#include "util_string.hpp"
#include "sass2scss.h"

#ifdef _WIN32
Expand Down Expand Up @@ -106,13 +106,13 @@ namespace Sass {
bool is_absolute_path(const std::string& path)
{
#ifdef _WIN32
if (path.length() >= 2 && isalpha(path[0]) && path[1] == ':') return true;
if (path.length() >= 2 && Util::ascii_isalpha(path[0]) && path[1] == ':') return true;
#endif
size_t i = 0;
// check if we have a protocol
if (path[i] && Prelexer::is_alpha(path[i])) {
if (path[i] && Util::ascii_isalpha(static_cast<unsigned char>(path[i]))) {
// skip over all alphanumeric characters
while (path[i] && Prelexer::is_alnum(path[i])) ++i;
while (path[i] && Util::ascii_isalnum(static_cast<unsigned char>(path[i]))) ++i;
i = i && path[i] == ':' ? i + 1 : 0;
}
return path[i] == '/';
Expand Down Expand Up @@ -179,9 +179,9 @@ namespace Sass {

size_t proto = 0;
// check if we have a protocol
if (path[proto] && Prelexer::is_alpha(path[proto])) {
if (path[proto] && Util::ascii_isalpha(static_cast<unsigned char>(path[proto]))) {
// skip over all alphanumeric characters
while (path[proto] && Prelexer::is_alnum(path[proto++])) {}
while (path[proto] && Util::ascii_isalnum(static_cast<unsigned char>(path[proto++]))) {}
// then skip over the mandatory colon
if (proto && path[proto] == ':') ++ proto;
}
Expand Down Expand Up @@ -260,9 +260,9 @@ namespace Sass {

size_t proto = 0;
// check if we have a protocol
if (path[proto] && Prelexer::is_alpha(path[proto])) {
if (path[proto] && Util::ascii_isalpha(static_cast<unsigned char>(path[proto]))) {
// skip over all alphanumeric characters
while (path[proto] && Prelexer::is_alnum(path[proto++])) {}
while (path[proto] && Util::ascii_isalnum(static_cast<unsigned char>(path[proto++]))) {}
// then skip over the mandatory colon
if (proto && path[proto] == ':') ++ proto;
}
Expand All @@ -288,7 +288,8 @@ namespace Sass {
#else
// compare the charactes in a case insensitive manner
// windows fs is only case insensitive in ascii ranges
if (tolower(abs_path[i]) != tolower(abs_base[i])) break;
if (Util::ascii_tolower(static_cast<unsigned char>(abs_path[i])) !=
Util::ascii_tolower(static_cast<unsigned char>(abs_base[i]))) break;
#endif
if (abs_path[i] == '/') index = i + 1;
}
Expand Down Expand Up @@ -488,8 +489,7 @@ namespace Sass {
if (path.length() > 5) {
extension = path.substr(path.length() - 5, 5);
}
for(size_t i=0; i<extension.size();++i)
extension[i] = tolower(extension[i]);
Util::ascii_str_tolower(&extension);
if (extension == ".sass" && contents != 0) {
char * converted = sass2scss(contents, SASS2SCSS_PRETTIFY_1 | SASS2SCSS_KEEP_COMMENT);
free(contents); // free the indented contents
Expand Down
8 changes: 3 additions & 5 deletions src/fn_colors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
// __EXTENSIONS__ fix on Solaris.
#include "sass.hpp"

#include <cctype>
#include <iomanip>
#include "ast.hpp"
#include "fn_utils.hpp"
#include "fn_colors.hpp"
#include "util.hpp"
#include "util_string.hpp"

namespace Sass {

Expand Down Expand Up @@ -582,10 +582,8 @@ namespace Sass {
ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(g, ctx.c_options.precision));
ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(b, ctx.c_options.precision));

std::string result(ss.str());
for (size_t i = 0, L = result.length(); i < L; ++i) {
result[i] = std::toupper(result[i]);
}
std::string result = ss.str();
Util::ascii_str_toupper(&result);
return SASS_MEMORY_NEW(String_Quoted, pstate, result);
}

Expand Down
1 change: 0 additions & 1 deletion src/fn_numbers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include <cstdint>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <random>
#include <sstream>
#include <iomanip>
Expand Down
16 changes: 3 additions & 13 deletions src/fn_strings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
// __EXTENSIONS__ fix on Solaris.
#include "sass.hpp"

#include <cctype>
#include "utf8.h"
#include "ast.hpp"
#include "fn_utils.hpp"
#include "fn_strings.hpp"
#include "util_string.hpp"

namespace Sass {

Expand Down Expand Up @@ -212,12 +212,7 @@ namespace Sass {
{
String_Constant* s = ARG("$string", String_Constant);
std::string str = s->value();

for (size_t i = 0, L = str.length(); i < L; ++i) {
if (Sass::Util::isAscii(str[i])) {
str[i] = std::toupper(str[i]);
}
}
Util::ascii_str_toupper(&str);

if (String_Quoted* ss = Cast<String_Quoted>(s)) {
String_Quoted* cpy = SASS_MEMORY_COPY(ss);
Expand All @@ -233,12 +228,7 @@ namespace Sass {
{
String_Constant* s = ARG("$string", String_Constant);
std::string str = s->value();

for (size_t i = 0, L = str.length(); i < L; ++i) {
if (Sass::Util::isAscii(str[i])) {
str[i] = std::tolower(str[i]);
}
}
Util::ascii_str_tolower(&str);

if (String_Quoted* ss = Cast<String_Quoted>(s)) {
String_Quoted* cpy = SASS_MEMORY_COPY(ss);
Expand Down
1 change: 0 additions & 1 deletion src/lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// __EXTENSIONS__ fix on Solaris.
#include "sass.hpp"

#include <cctype>
#include <iostream>
#include <iomanip>
#include "lexer.hpp"
Expand Down
4 changes: 2 additions & 2 deletions src/prelexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
// __EXTENSIONS__ fix on Solaris.
#include "sass.hpp"

#include <cctype>
#include <iostream>
#include <iomanip>
#include "util.hpp"
#include "util_string.hpp"
#include "position.hpp"
#include "prelexer.hpp"
#include "constants.hpp"
Expand Down Expand Up @@ -1400,7 +1400,7 @@ namespace Sass {
}*/

const char* H(const char* src) {
return std::isxdigit(static_cast<unsigned char>(*src)) ? src+1 : 0;
return Util::ascii_isxdigit(static_cast<unsigned char>(*src)) ? src+1 : 0;
}

const char* W(const char* src) {
Expand Down
9 changes: 3 additions & 6 deletions src/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "sass.h"
#include "ast.hpp"
#include "util.hpp"
#include "util_string.hpp"
#include "lexer.hpp"
#include "prelexer.hpp"
#include "constants.hpp"
Expand Down Expand Up @@ -289,7 +290,7 @@ namespace Sass {

// parse as many sequence chars as possible
// ToDo: Check if ruby aborts after possible max
while (i + len < L && s[i + len] && isxdigit(s[i + len])) ++ len;
while (i + len < L && s[i + len] && Util::ascii_isxdigit(static_cast<unsigned char>(s[i + len]))) ++ len;

if (len > 1) {

Expand Down Expand Up @@ -375,7 +376,7 @@ namespace Sass {

// parse as many sequence chars as possible
// ToDo: Check if ruby aborts after possible max
while (i + len < L && s[i + len] && isxdigit(s[i + len])) ++ len;
while (i + len < L && s[i + len] && Util::ascii_isxdigit(static_cast<unsigned char>(s[i + len]))) ++ len;

// hex string?
if (keep_utf8_sequences) {
Expand Down Expand Up @@ -718,9 +719,5 @@ namespace Sass {
return false;
}

bool isAscii(const char chr) {
return unsigned(chr) < 128;
}

}
}
1 change: 0 additions & 1 deletion src/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ namespace Sass {
bool isPrintable(String_Constant* s, Sass_Output_Style style = NESTED);
bool isPrintable(String_Quoted* s, Sass_Output_Style style = NESTED);
bool isPrintable(Declaration* d, Sass_Output_Style style = NESTED);
bool isAscii(const char chr);

}
}
Expand Down
19 changes: 18 additions & 1 deletion src/util_string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,24 @@ namespace Sass {
// If not test was too long
return *lit == 0;
}
// EO equalsLiteral

void ascii_str_tolower(std::string* s) {
for (auto& ch : *s) {
ch = ascii_tolower(static_cast<unsigned char>(ch));
}
}

void ascii_str_toupper(std::string* s) {
for (auto& ch : *s) {
ch = ascii_toupper(static_cast<unsigned char>(ch));
}
}

std::string rtrim(std::string str) {
auto it = std::find_if_not(str.rbegin(), str.rend(), ascii_isspace);
str.erase(str.rend() - it);
return str;
}

// ###########################################################################
// Returns [name] without a vendor prefix.
Expand Down
43 changes: 39 additions & 4 deletions src/util_string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,44 @@ namespace Sass {
char opening_bracket_for(char closing_bracket);
char closing_bracket_for(char opening_bracket);

}
// namespace Util
}
// namespace Sass
// Locale-independent ASCII character routines.

inline bool ascii_isalpha(unsigned char c) {
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}

inline bool ascii_isdigit(unsigned char c) {
return (c >= '0' && c <= '9');
}

inline bool ascii_isalnum(unsigned char c) {
return ascii_isalpha(c) || ascii_isdigit(c);
}

inline bool ascii_isascii(unsigned char c) { return c < 128; }

inline bool ascii_isxdigit(unsigned char c) {
return ascii_isdigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
}

inline bool ascii_isspace(unsigned char c) {
return c == ' ' || c == '\t' || c == '\v' || c == '\f' || c == '\r' || c == '\n';
}

inline char ascii_tolower(unsigned char c) {
if (c >= 'A' && c <= 'Z') return c + 32;
return c;
}

void ascii_str_tolower(std::string* s);

inline char ascii_toupper(unsigned char c) {
if (c >= 'a' && c <= 'z') return c - 32;
return c;
}

void ascii_str_toupper(std::string* s);

} // namespace Sass
} // namespace Util
#endif // SASS_UTIL_STRING_H
Loading

0 comments on commit 03bf13c

Please sign in to comment.