mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-12-22 12:12:35 +03:00
412 lines
9.5 KiB
C
412 lines
9.5 KiB
C
/*
|
|
* Copyright 2016 Michael Drake <tlsa@netsurf-browser.org>
|
|
*
|
|
* This file is part of NetSurf, http://www.netsurf-browser.org/
|
|
*
|
|
* NetSurf is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; version 2 of the License.
|
|
*
|
|
* NetSurf is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/**
|
|
* \file utils/ascii.h
|
|
* \brief Helpers for ASCII string handling.
|
|
*
|
|
* These helpers for string parsing will have the correct effect for parsing
|
|
* ASCII text (as used by most web specs), regardless of system locale.
|
|
*/
|
|
|
|
#ifndef _NETSURF_UTILS_ASCII_H_
|
|
#define _NETSURF_UTILS_ASCII_H_
|
|
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <limits.h>
|
|
|
|
/**
|
|
* Test whether a character is a whitespace character.
|
|
*
|
|
* \param[in] c Character to test.
|
|
* \return true iff `c` is whitespace, else false.
|
|
*/
|
|
static inline bool ascii_is_space(char c)
|
|
{
|
|
return (c == ' ' || c == '\t' ||
|
|
c == '\n' || c == '\v' ||
|
|
c == '\f' || c == '\r');
|
|
}
|
|
|
|
/**
|
|
* Test whether a character is lower-case alphabetical.
|
|
*
|
|
* \param[in] c Character to test.
|
|
* \return true iff `c` is lower-case alphabetical, else false.
|
|
*/
|
|
static inline bool ascii_is_alpha_lower(char c)
|
|
{
|
|
return (c >= 'a' && c <= 'z');
|
|
}
|
|
|
|
/**
|
|
* Test whether a character is upper-case alphabetical.
|
|
*
|
|
* \param[in] c Character to test.
|
|
* \return true iff `c` is upper-case alphabetical, else false.
|
|
*/
|
|
static inline bool ascii_is_alpha_upper(char c)
|
|
{
|
|
return (c >= 'A' && c <= 'Z');
|
|
}
|
|
|
|
/**
|
|
* Test whether a character is alphabetical (upper or lower case).
|
|
*
|
|
* \param[in] c Character to test.
|
|
* \return true iff `c` is alphabetical, else false.
|
|
*/
|
|
static inline bool ascii_is_alpha(char c)
|
|
{
|
|
return (ascii_is_alpha_lower(c) || ascii_is_alpha_upper(c));
|
|
}
|
|
|
|
/**
|
|
* Test whether a character is a decimal digit.
|
|
*
|
|
* \param[in] c Character to test.
|
|
* \return true iff `c` is a decimal digit, else false.
|
|
*/
|
|
static inline bool ascii_is_digit(char c)
|
|
{
|
|
return (c >= '0' && c <= '9');
|
|
}
|
|
|
|
/**
|
|
* Test whether a character is a positive/negative numerical sign.
|
|
*
|
|
* \param[in] c Character to test.
|
|
* \return true iff `c` is a sign, else false.
|
|
*/
|
|
static inline bool ascii_is_sign(char c)
|
|
{
|
|
return (c == '-' || c == '+');
|
|
}
|
|
|
|
/**
|
|
* Test whether a character is alphanumerical (upper or lower case).
|
|
*
|
|
* \param[in] c Character to test.
|
|
* \return true iff `c` is alphanumerical, else false.
|
|
*/
|
|
static inline bool ascii_is_alphanumerical(char c)
|
|
{
|
|
return (ascii_is_alpha(c) || ascii_is_digit(c));
|
|
}
|
|
|
|
/**
|
|
* Test whether a character is 'a' to 'f' (lowercase).
|
|
*
|
|
* \param[in] c Character to test.
|
|
* \return true iff `c` is 'a' to 'f' (lowercase), else false.
|
|
*/
|
|
static inline bool ascii_is_af_lower(char c)
|
|
{
|
|
return (c >= 'a' && c <= 'f');
|
|
}
|
|
|
|
/**
|
|
* Test whether a character is hexadecimal (lower case).
|
|
*
|
|
* \param[in] c Character to test.
|
|
* \return true iff `c` is hexadecimal, else false.
|
|
*/
|
|
static inline bool ascii_is_hex_lower(char c)
|
|
{
|
|
return (ascii_is_digit(c) || ascii_is_af_lower(c));
|
|
}
|
|
|
|
/**
|
|
* Test whether a character is 'A' to 'F' (uppercase).
|
|
*
|
|
* \param[in] c Character to test.
|
|
* \return true iff `c` is 'A' to 'F' (uppercase), else false.
|
|
*/
|
|
static inline bool ascii_is_af_upper(char c)
|
|
{
|
|
return (c >= 'A' && c <= 'F');
|
|
}
|
|
|
|
/**
|
|
* Test whether a character is hexadecimal (upper case).
|
|
*
|
|
* \param[in] c Character to test.
|
|
* \return true iff `c` is hexadecimal, else false.
|
|
*/
|
|
static inline bool ascii_is_hex_upper(char c)
|
|
{
|
|
return (ascii_is_digit(c) || ascii_is_af_upper(c));
|
|
}
|
|
|
|
/**
|
|
* Test whether a character is hexadecimal (upper or lower case).
|
|
*
|
|
* \param[in] c Character to test.
|
|
* \return true iff `c` is hexadecimal, else false.
|
|
*/
|
|
static inline bool ascii_is_hex(char c)
|
|
{
|
|
return (ascii_is_digit(c) ||
|
|
ascii_is_af_upper(c) ||
|
|
ascii_is_af_lower(c));
|
|
}
|
|
|
|
/**
|
|
* Convert a hexadecimal character to its value.
|
|
*
|
|
* \param[in] c Character to convert.
|
|
* \return value of character (0-15), or -256 if not a hexadecimal character.
|
|
*/
|
|
static inline int ascii_hex_to_value(char c)
|
|
{
|
|
if (ascii_is_digit(c)) {
|
|
return c - '0';
|
|
} else if (ascii_is_af_lower(c)) {
|
|
return c - 'a' + 10;
|
|
} else if (ascii_is_af_upper(c)) {
|
|
return c - 'A' + 10;
|
|
}
|
|
|
|
/* Invalid hex */
|
|
return -256;
|
|
}
|
|
|
|
/**
|
|
* Converts two hexadecimal characters to a single number
|
|
*
|
|
* \param[in] c1 most significant hex digit.
|
|
* \param[in] c2 least significant hex digit.
|
|
* \return the total value of the two digit hex number (0-255),
|
|
* or -ve if input not hex.
|
|
*/
|
|
static inline int ascii_hex_to_value_2_chars(char c1, char c2)
|
|
{
|
|
return 16 * ascii_hex_to_value(c1) + ascii_hex_to_value(c2);
|
|
}
|
|
|
|
/**
|
|
* Convert an upper case character to lower case.
|
|
*
|
|
* If the given character is not upper case alphabetical, it is returned
|
|
* unchanged.
|
|
*
|
|
* \param[in] c Character to convert.
|
|
* \return lower case conversion of `c` else `c`.
|
|
*/
|
|
static inline char ascii_to_lower(char c)
|
|
{
|
|
return (ascii_is_alpha_upper(c)) ? (c + 'a' - 'A') : c;
|
|
}
|
|
|
|
/**
|
|
* Convert a lower case character to upper case.
|
|
*
|
|
* If the given character is not lower case alphabetical, it is returned
|
|
* unchanged.
|
|
*
|
|
* \param[in] c Character to convert.
|
|
* \return upper case conversion of `c` else `c`.
|
|
*/
|
|
static inline char ascii_to_upper(char c)
|
|
{
|
|
return (ascii_is_alpha_lower(c)) ? (c + 'A' - 'a') : c;
|
|
}
|
|
|
|
/**
|
|
* Count consecutive lower case alphabetical characters in string.
|
|
*
|
|
* \param[in] str String to count characters in.
|
|
* \return number of consecutive lower case characters at start of `str`.
|
|
*/
|
|
static inline size_t ascii_count_alpha_lower(const char *str)
|
|
{
|
|
size_t count = 0;
|
|
while (ascii_is_alpha_lower(*(str++))) {
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
/**
|
|
* Count consecutive upper case alphabetical characters in string.
|
|
*
|
|
* \param[in] str String to count characters in.
|
|
* \return number of consecutive upper case characters at start of `str`.
|
|
*/
|
|
static inline size_t ascii_count_alpha_upper(const char *str)
|
|
{
|
|
size_t count = 0;
|
|
while (ascii_is_alpha_upper(*(str++))) {
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
/**
|
|
* Count consecutive alphabetical characters in string (upper or lower case).
|
|
*
|
|
* \param[in] str String to count characters in.
|
|
* \return number of consecutive alphabetical characters at start of `str`.
|
|
*/
|
|
static inline size_t ascii_count_alpha(const char *str)
|
|
{
|
|
size_t count = 0;
|
|
while (ascii_is_alpha(*(str++))) {
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
/**
|
|
* Count consecutive decial digit characters in string.
|
|
*
|
|
* \param[in] str String to count characters in.
|
|
* \return number of consecutive decimal digit characters at start of `str`.
|
|
*/
|
|
static inline size_t ascii_count_digit(const char *str)
|
|
{
|
|
size_t count = 0;
|
|
while (ascii_is_digit(*(str++))) {
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
/**
|
|
* Count consecutive characters either decimal digit or colon in string.
|
|
*
|
|
* \param[in] str String to count characters in.
|
|
* \return number of consecutive decimal or ':' characters at start of `str`.
|
|
*/
|
|
static inline size_t ascii_count_digit_or_colon(const char *str)
|
|
{
|
|
size_t count = 0;
|
|
while (ascii_is_digit(*str) || *str == ':') {
|
|
count++;
|
|
str++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
/**
|
|
* Test for string equality (case insensitive).
|
|
*
|
|
* \param[in] s1 First string to compare.
|
|
* \param[in] s2 Second string to compare.
|
|
* \return true iff strings are equivalent, else false.
|
|
*/
|
|
static inline bool ascii_strings_equal_caseless(
|
|
const char *s1, const char *s2)
|
|
{
|
|
while (*s1 != '\0') {
|
|
if (ascii_to_lower(*s1) != ascii_to_lower(*s2)) {
|
|
break;
|
|
}
|
|
s1++;
|
|
s2++;
|
|
}
|
|
return (ascii_to_lower(*s1) == ascii_to_lower(*s2));
|
|
}
|
|
|
|
/**
|
|
* Test for string equality (case sensitive).
|
|
*
|
|
* \param[in] s1 First string to compare.
|
|
* \param[in] s2 Second string to compare.
|
|
* \return true iff strings are equal, else false.
|
|
*/
|
|
static inline bool ascii_strings_equal(
|
|
const char *s1, const char *s2)
|
|
{
|
|
while (*s1 != '\0') {
|
|
if (*s1 != *s2) {
|
|
break;
|
|
}
|
|
s1++;
|
|
s2++;
|
|
}
|
|
return (*s1 == *s2);
|
|
}
|
|
|
|
/**
|
|
* Count consecutive equal ascii characters (case insensitive).
|
|
*
|
|
* \param[in] s1 First string to compare.
|
|
* \param[in] s2 Second string to compare.
|
|
* \return number of equivalent characters.
|
|
*/
|
|
static inline size_t ascii_strings_count_equal_caseless(
|
|
const char *s1, const char *s2)
|
|
{
|
|
const char *s = s1;
|
|
while (*s1 != '\0') {
|
|
if (ascii_to_lower(*s1) != ascii_to_lower(*s2)) {
|
|
break;
|
|
}
|
|
s1++;
|
|
s2++;
|
|
}
|
|
return s1 - s;
|
|
}
|
|
|
|
/**
|
|
* Count consecutive equal ascii characters (case sensitive).
|
|
*
|
|
* \param[in] s1 First string to compare.
|
|
* \param[in] s2 Second string to compare.
|
|
* \return number of equal characters.
|
|
*/
|
|
static inline size_t ascii_strings_count_equal(
|
|
const char *s1, const char *s2)
|
|
{
|
|
const char *s = s1;
|
|
while (*s1 != '\0') {
|
|
if (*s1 != *s2) {
|
|
break;
|
|
}
|
|
s1++;
|
|
s2++;
|
|
}
|
|
return s1 - s;
|
|
}
|
|
|
|
/**
|
|
* Parse an int out of a string.
|
|
*
|
|
* \param[in] str String to parse integer out of.
|
|
* \param[out] res Returns parsed integer.
|
|
* \return The number of characters consumed in `str`.
|
|
* Returning 0 indicates failure to parse an integer out of the string.
|
|
*/
|
|
static inline size_t ascii_string_to_int(const char *str, int *res)
|
|
{
|
|
char *end = NULL;
|
|
long long temp = strtoll(str, &end, 10);
|
|
|
|
if (end == str || errno == ERANGE ||
|
|
temp < INT_MIN || temp > INT_MAX) {
|
|
return 0;
|
|
}
|
|
|
|
*res = temp;
|
|
return end - str;
|
|
}
|
|
|
|
#endif
|