diff options
author | Taylor R Campbell <campbell+ledger@mumble.net> | 2024-04-27 19:54:23 +0000 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2024-08-06 14:51:38 -1000 |
commit | d9967c2638052730c6eeb1624586d633d6482003 (patch) | |
tree | f6dd9d0a94cc633f4e1a4f0588c2cb613e0100e2 /src | |
parent | 762353945a744ae4b89970b9e08c2c22a52ddbff (diff) | |
download | fork-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.cc | 7 | ||||
-rw-r--r-- | src/expr.cc | 2 | ||||
-rw-r--r-- | src/format.cc | 18 | ||||
-rw-r--r-- | src/item.cc | 3 | ||||
-rw-r--r-- | src/lookup.cc | 8 | ||||
-rw-r--r-- | src/option.cc | 3 | ||||
-rw-r--r-- | src/pool.cc | 6 | ||||
-rw-r--r-- | src/report.cc | 4 | ||||
-rw-r--r-- | src/strptime.cc | 6 | ||||
-rw-r--r-- | src/textual.cc | 36 | ||||
-rw-r--r-- | src/times.cc | 22 | ||||
-rw-r--r-- | src/utils.cc | 2 | ||||
-rw-r--r-- | src/xact.cc | 6 |
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 |