summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTaylor R Campbell <campbell+ledger@mumble.net>2024-04-27 19:54:23 +0000
committerJohn Wiegley <johnw@newartisans.com>2024-08-06 14:51:38 -1000
commitd9967c2638052730c6eeb1624586d633d6482003 (patch)
treef6dd9d0a94cc633f4e1a4f0588c2cb613e0100e2 /src
parent762353945a744ae4b89970b9e08c2c22a52ddbff (diff)
downloadfork-ledger-d9967c2638052730c6eeb1624586d633d6482003.tar.gz
fork-ledger-d9967c2638052730c6eeb1624586d633d6482003.tar.bz2
fork-ledger-d9967c2638052730c6eeb1624586d633d6482003.zip
Avoid ctype abuse.
fix https://github.com/ledger/ledger/issues/2338 fix https://github.com/ledger/ledger/issues/2340
Diffstat (limited to 'src')
-rw-r--r--src/amount.cc7
-rw-r--r--src/expr.cc2
-rw-r--r--src/format.cc18
-rw-r--r--src/item.cc3
-rw-r--r--src/lookup.cc8
-rw-r--r--src/option.cc3
-rw-r--r--src/pool.cc6
-rw-r--r--src/report.cc4
-rw-r--r--src/strptime.cc6
-rw-r--r--src/textual.cc36
-rw-r--r--src/times.cc22
-rw-r--r--src/utils.cc2
-rw-r--r--src/xact.cc6
13 files changed, 76 insertions, 47 deletions
diff --git a/src/amount.cc b/src/amount.cc
index da8cd6fc..22282150 100644
--- a/src/amount.cc
+++ b/src/amount.cc
@@ -1013,7 +1013,8 @@ namespace {
std::isdigit(c) || c == '.' || c == ',');
string::size_type len = std::strlen(buf);
- while (len > 0 && ! std::isdigit(buf[len - 1])) {
+ while (len > 0 &&
+ ! std::isdigit(static_cast<unsigned char>(buf[len - 1]))) {
buf[--len] = '\0';
in.unget();
}
@@ -1048,7 +1049,7 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags)
parse_quantity(in, quant);
if (! in.eof() && ((n = static_cast<char>(in.peek())) != '\n')) {
- if (std::isspace(n))
+ if (std::isspace(static_cast<unsigned char>(n)))
comm_flags |= COMMODITY_STYLE_SEPARATED;
commodity_t::parse_symbol(in, symbol);
@@ -1064,7 +1065,7 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags)
commodity_t::parse_symbol(in, symbol);
if (! in.eof() && ((n = static_cast<char>(in.peek())) != '\n')) {
- if (std::isspace(static_cast<char>(in.peek())))
+ if (std::isspace(in.peek()))
comm_flags |= COMMODITY_STYLE_SEPARATED;
parse_quantity(in, quant);
diff --git a/src/expr.cc b/src/expr.cc
index 0866b8bb..720a6618 100644
--- a/src/expr.cc
+++ b/src/expr.cc
@@ -222,7 +222,7 @@ bool merged_expr_t::check_for_single_identifier(const string& expr)
{
bool single_identifier = true;
for (const char * p = expr.c_str(); *p; ++p)
- if (! std::isalnum(*p) || *p == '_') {
+ if (! std::isalnum(static_cast<unsigned char>(*p)) || *p == '_') {
single_identifier = false;
break;
}
diff --git a/src/format.cc b/src/format.cc
index 708b9edd..a3596b26 100644
--- a/src/format.cc
+++ b/src/format.cc
@@ -109,7 +109,7 @@ namespace {
// Don't gobble up any whitespace
const char * base = p;
- while (p >= base && std::isspace(*p))
+ while (p >= base && std::isspace(static_cast<unsigned char>(*p)))
p--;
}
return expr;
@@ -183,7 +183,7 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
}
std::size_t num = 0;
- while (*p && std::isdigit(*p)) {
+ while (*p && std::isdigit(static_cast<unsigned char>(*p))) {
num *= 10;
num += static_cast<std::size_t>(*p++ - '0');
}
@@ -192,7 +192,7 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
if (*p == '.') {
++p;
num = 0;
- while (*p && std::isdigit(*p)) {
+ while (*p && std::isdigit(static_cast<unsigned char>(*p))) {
num *= 10;
num += static_cast<std::size_t>(*p++ - '0');
}
@@ -201,7 +201,7 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
current->min_width = current->max_width;
}
- if (std::isalpha(*p)) {
+ if (std::isalpha(static_cast<unsigned char>(*p))) {
bool found = false;
for (std::size_t i = 0; i < (sizeof(single_letter_mappings) /
sizeof(format_mapping_t)); i++) {
@@ -210,7 +210,7 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
for (const char * ptr = single_letter_mappings[i].expr; *ptr;) {
if (*ptr == '$') {
const char * beg = ++ptr;
- while (*ptr && std::isalpha(*ptr))
+ while (*ptr && std::isalpha(static_cast<unsigned char>(*ptr)))
++ptr;
string::size_type klen = static_cast<string::size_type>(ptr - beg);
string keyword(beg, 0, klen);
@@ -250,12 +250,13 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
throw_(format_error, _("Prior field reference, but no template"));
p++;
- if (*p == '0' || (! std::isdigit(*p) &&
+ if (*p == '0' || (! std::isdigit(static_cast<unsigned char>(*p)) &&
*p != 'A' && *p != 'B' && *p != 'C' &&
*p != 'D' && *p != 'E' && *p != 'F'))
throw_(format_error, _("%$ field reference must be a digit from 1-9"));
- int index = std::isdigit(*p) ? *p - '0' : (*p - 'A' + 10);
+ int index = std::isdigit(static_cast<unsigned char>(*p))
+ ? *p - '0' : (*p - 'A' + 10);
element_t * tmpl_elem = tmpl->elements.get();
for (int i = 1; i < index && tmpl_elem; i++) {
@@ -630,7 +631,8 @@ string format_t::truncate(const unistring& ustr,
if (adjust > 0) {
DEBUG("format.abbrev",
"Reducing segment " << ++index << " by " << adjust << " chars");
- while (std::isspace((*x)[*i - adjust - 1]) && adjust < *i) {
+ while (std::isspace(static_cast<unsigned char>(
+ (*x)[*i - adjust - 1])) && adjust < *i) {
DEBUG("format.abbrev",
"Segment ends in whitespace, adjusting down");
++adjust;
diff --git a/src/item.cc b/src/item.cc
index c5db3cad..052d70eb 100644
--- a/src/item.cc
+++ b/src/item.cc
@@ -157,7 +157,8 @@ void item_t::parse_tags(const char * p,
if (! std::strchr(p, ':')) {
if (const char * b = std::strchr(p, '[')) {
if (*(b + 1) != '\0' &&
- (std::isdigit(*(b + 1)) || *(b + 1) == '=')) {
+ (std::isdigit(static_cast<unsigned char>(*(b + 1))) ||
+ *(b + 1) == '=')) {
if (const char * e = std::strchr(b, ']')) {
char buf[256];
std::strncpy(buf, b + 1, static_cast<std::size_t>(e - b - 1));
diff --git a/src/lookup.cc b/src/lookup.cc
index 228a1d31..56820e99 100644
--- a/src/lookup.cc
+++ b/src/lookup.cc
@@ -188,7 +188,13 @@ lookup_probable_account(const string& ident,
#if 0
#if !HAVE_BOOST_REGEX_UNICODE
- if (pos == 0 || (pos > 0 && !std::isalnum(value_key[pos - 1])))
+ // Probably doesn't make sense with value_key as unistring,
+ // but this code is under #if 0 anyway, so if anyone is
+ // tempted to use this by changing value_key to string, let's
+ // avoid leaving a rake to step on.
+ if (pos == 0 ||
+ (pos > 0 &&
+ !std::isalnum(static_cast<unsigned char>(value_key[pos - 1]))))
addend++;
#else
// jww (2010-03-07): Not yet implemented
diff --git a/src/option.cc b/src/option.cc
index 43dd853c..44b135e6 100644
--- a/src/option.cc
+++ b/src/option.cc
@@ -132,7 +132,8 @@ void process_environment(const char ** envp, const string& tag,
if (*q == '_')
*r++ = '-';
else
- *r++ = static_cast<char>(std::tolower(*q));
+ *r++ = static_cast<char>(std::tolower(
+ static_cast<unsigned char>(*q)));
*r = '\0';
if (*q == '=') {
diff --git a/src/pool.cc b/src/pool.cc
index 73e76644..2d2b17cb 100644
--- a/src/pool.cc
+++ b/src/pool.cc
@@ -327,13 +327,15 @@ commodity_pool_t::parse_price_directive
datetime_t datetime;
string symbol;
- if (! no_date && std::isdigit(time_field_ptr[0])) {
+ if (! no_date &&
+ std::isdigit(static_cast<unsigned char>(time_field_ptr[0]))) {
symbol_and_price = next_element(time_field_ptr);
if (! symbol_and_price) return none;
datetime = parse_datetime(date_field + " " + time_field_ptr);
}
- else if (! no_date && std::isdigit(date_field_ptr[0])) {
+ else if (! no_date &&
+ std::isdigit(static_cast<unsigned char>(date_field_ptr[0]))) {
symbol_and_price = time_field_ptr;
datetime = datetime_t(parse_date(date_field));
}
diff --git a/src/report.cc b/src/report.cc
index d632a0d2..cf71a895 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -642,10 +642,10 @@ value_t report_t::fn_trim(call_scope_t& args)
const char * p = buf.get();
const char * e = buf.get() + temp.length() - 1;
- while (p <= e && std::isspace(*p))
+ while (p <= e && std::isspace(static_cast<unsigned char>(*p)))
p++;
- while (e > p && std::isspace(*e))
+ while (e > p && std::isspace(static_cast<unsigned char>(*e)))
e--;
if (p > e) {
diff --git a/src/strptime.cc b/src/strptime.cc
index d390d1fa..77593665 100644
--- a/src/strptime.cc
+++ b/src/strptime.cc
@@ -62,7 +62,9 @@ static const char* kMonthAbbr[] = {
static const char* _parse_num(const char* s, int low, int high, int* value) {
const char* p = s;
- for (*value = 0; *p != NULL && isdigit(*p); ++p) {
+ for (*value = 0;
+ *p != NULL && isdigit(static_cast<unsigned char>(*p));
+ ++p) {
*value = (*value) * 10 + static_cast<int>(*p) - static_cast<int>('0');
}
@@ -177,7 +179,7 @@ static char* _strptime(const char *s, const char *format, struct tm *tm) {
// arbitrary whitespace.
case 't':
case 'n':
- while (isspace(*s)) ++s;
+ while (isspace(static_cast<unsigned char>(*s))) ++s;
break;
// '%'.
diff --git a/src/textual.cc b/src/textual.cc
index 5488c6a3..4105a42d 100644
--- a/src/textual.cc
+++ b/src/textual.cc
@@ -349,7 +349,8 @@ std::streamsize instance_t::read_line(char *& line)
--len;
}
- while (len > 0 && std::isspace(line[len - 1])) // strip trailing whitespace
+ // strip trailing whitespace
+ while (len > 0 && std::isspace(static_cast<unsigned char>(line[len - 1])))
line[--len] = '\0';
return len;
@@ -364,7 +365,7 @@ xact_t * instance_t::read_next_directive(bool& error_flag, xact_t * previous_xac
if (len == 0 || line == NULL)
return NULL;
- if (! std::isspace(line[0]))
+ if (! std::isspace(static_cast<unsigned char>(line[0])))
error_flag = false;
switch (line[0]) {
@@ -625,12 +626,16 @@ void instance_t::automated_xact_directive(char * line)
item->pos->end_line++;
}
else if ((remlen > 7 && *p == 'a' &&
- std::strncmp(p, "assert", 6) == 0 && std::isspace(p[6])) ||
+ std::strncmp(p, "assert", 6) == 0 &&
+ std::isspace(static_cast<unsigned char>(p[6]))) ||
(remlen > 6 && *p == 'c' &&
- std::strncmp(p, "check", 5) == 0 && std::isspace(p[5])) ||
+ std::strncmp(p, "check", 5) == 0 &&
+ std::isspace(static_cast<unsigned char>(p[5]))) ||
(remlen > 5 && *p == 'e' &&
- ((std::strncmp(p, "expr", 4) == 0 && std::isspace(p[4])) ||
- (std::strncmp(p, "eval", 4) == 0 && std::isspace(p[4]))))) {
+ ((std::strncmp(p, "expr", 4) == 0 &&
+ std::isspace(static_cast<unsigned char>(p[4]))) ||
+ (std::strncmp(p, "eval", 4) == 0 &&
+ std::isspace(static_cast<unsigned char>(p[4])))))) {
const char c = *p;
p = skip_ws(&p[*p == 'a' ? 6 : (*p == 'c' ? 5 : 4)]);
if (! ae->check_exprs)
@@ -1028,7 +1033,7 @@ void instance_t::alias_directive(char * line)
{
if (char * e = std::strchr(line, '=')) {
char * z = e - 1;
- while (std::isspace(*z))
+ while (std::isspace(static_cast<unsigned char>(*z)))
*z-- = '\0';
*e++ = '\0';
e = skip_ws(e);
@@ -1247,7 +1252,7 @@ void instance_t::python_directive(char * line)
if (read_line(line) > 0) {
if (! indent) {
const char * p = line;
- while (*p && std::isspace(*p)) {
+ while (*p && std::isspace(static_cast<unsigned char>(*p))) {
++indent;
++p;
}
@@ -1255,7 +1260,7 @@ void instance_t::python_directive(char * line)
const char * p = line;
for (std::size_t i = 0; i < indent; i++) {
- if (std::isspace(*p))
+ if (std::isspace(static_cast<unsigned char>(*p)))
++p;
else
break;
@@ -1486,7 +1491,7 @@ post_t * instance_t::parse_post(char * line,
char * next = next_element(p, true);
char * e = p + std::strlen(p);
- while (e > p && std::isspace(*(e - 1)))
+ while (e > p && std::isspace(static_cast<unsigned char>(*(e - 1))))
e--;
if ((*p == '[' && *(e - 1) == ']') || (*p == '(' && *(e - 1) == ')')) {
@@ -1898,7 +1903,7 @@ xact_t * instance_t::parse_xact(char * line,
}
else if (*p == ';' && (tabs > 0 || spaces > 1)) {
char *q = p - 1;
- while (q > next && std::isspace(*q))
+ while (q > next && std::isspace(static_cast<unsigned char>(*q)))
--q;
if (q >= next)
*(q + 1) = '\0';
@@ -1951,11 +1956,14 @@ xact_t * instance_t::parse_xact(char * line,
item->pos->end_line++;
}
else if ((remlen > 7 && *p == 'a' &&
- std::strncmp(p, "assert", 6) == 0 && std::isspace(p[6])) ||
+ std::strncmp(p, "assert", 6) == 0 &&
+ std::isspace(static_cast<unsigned char>(p[6]))) ||
(remlen > 6 && *p == 'c' &&
- std::strncmp(p, "check", 5) == 0 && std::isspace(p[5])) ||
+ std::strncmp(p, "check", 5) == 0 &&
+ std::isspace(static_cast<unsigned char>(p[5]))) ||
(remlen > 5 && *p == 'e' &&
- std::strncmp(p, "expr", 4) == 0 && std::isspace(p[4]))) {
+ std::strncmp(p, "expr", 4) == 0 &&
+ std::isspace(static_cast<unsigned char>(p[4])))) {
const char c = *p;
p = skip_ws(&p[*p == 'a' ? 6 : (*p == 'c' ? 5 : 4)]);
expr_t expr(p);
diff --git a/src/times.cc b/src/times.cc
index b66a6e30..89ffd710 100644
--- a/src/times.cc
+++ b/src/times.cc
@@ -1477,7 +1477,7 @@ date_parser_t::lexer_t::token_t date_parser_t::lexer_t::next_token()
return tok;
}
- while (begin != end && std::isspace(*begin))
+ while (begin != end && std::isspace(static_cast<unsigned char>(*begin)))
begin++;
if (begin == end)
@@ -1496,9 +1496,11 @@ date_parser_t::lexer_t::token_t date_parser_t::lexer_t::next_token()
// date using the typical date formats. This allows not only dates like
// "2009/08/01", but also dates that fit the user's --input-date-format,
// assuming their format fits in one argument and begins with a digit.
- if (std::isdigit(*begin)) {
+ if (std::isdigit(static_cast<unsigned char>(*begin))) {
string::const_iterator i = begin;
- for (i = begin; i != end && ! std::isspace(*i); i++) {}
+ for (i = begin;
+ i != end && ! std::isspace(static_cast<unsigned char>(*i));
+ i++) {}
assert(i != begin);
string possible_date(start, i);
@@ -1523,18 +1525,20 @@ date_parser_t::lexer_t::token_t date_parser_t::lexer_t::next_token()
start = begin;
string term;
- bool alnum = std::isalnum(*begin);
- for (; (begin != end && ! std::isspace(*begin) &&
- ((alnum && static_cast<bool>(std::isalnum(*begin))) ||
- (! alnum && ! static_cast<bool>(std::isalnum(*begin))))); begin++)
+ bool alnum = std::isalnum(static_cast<unsigned char>(*begin));
+ for (; (begin != end && ! std::isspace(static_cast<unsigned char>(*begin)) &&
+ ((alnum && static_cast<bool>(std::isalnum(
+ static_cast<unsigned char>(*begin)))) ||
+ (! alnum && ! static_cast<bool>(std::isalnum(
+ static_cast<unsigned char>(*begin)))))); begin++)
term.push_back(*begin);
if (! term.empty()) {
- if (std::isdigit(term[0])) {
+ if (std::isdigit(static_cast<unsigned char>(term[0]))) {
return token_t(token_t::TOK_INT,
token_t::content_t(lexical_cast<unsigned short>(term)));
}
- else if (std::isalpha(term[0])) {
+ else if (std::isalpha(static_cast<unsigned char>(term[0]))) {
to_lower(term);
if (optional<date_time::months_of_year> month =
diff --git a/src/utils.cc b/src/utils.cc
index 6ca7eeb7..1cc19ca0 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -516,7 +516,7 @@ strings_list split_arguments(const char * line)
char in_quoted_string = '\0';
for (const char * p = line; *p; p++) {
- if (! in_quoted_string && std::isspace(*p)) {
+ if (! in_quoted_string && std::isspace(static_cast<unsigned char>(*p))) {
if (q != buf) {
*q = '\0';
args.push_back(buf);
diff --git a/src/xact.cc b/src/xact.cc
index a0e5b8b4..0a080901 100644
--- a/src/xact.cc
+++ b/src/xact.cc
@@ -116,8 +116,10 @@ value_t xact_base_t::magnitude() const
namespace {
inline bool account_ends_with_special_char(const string& name) {
string::size_type len(name.length());
- return (std::isdigit(name[len - 1]) || name[len - 1] == ')' ||
- name[len - 1] == '}' || name[len - 1] == ']');
+ return (std::isdigit(static_cast<unsigned char>(name[len - 1])) ||
+ name[len - 1] == ')' ||
+ name[len - 1] == '}' ||
+ name[len - 1] == ']');
}
struct add_balancing_post