| /* GLIB - Library of useful routines for C programming |
| * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
| * |
| * SPDX-License-Identifier: LGPL-2.1-or-later |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library 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 |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| /* |
| * Modified by the GLib Team and others 1997-2000. See the AUTHORS |
| * file for a list of people on the GLib Team. See the ChangeLog |
| * files for a list of changes. These files are distributed with |
| * GLib at ftp://ftp.gtk.org/pub/gtk/. |
| */ |
| |
| /* |
| * MT safe |
| */ |
| |
| #include "config.h" |
| |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <locale.h> |
| #include <string.h> |
| #include <locale.h> |
| #include <errno.h> |
| #include <garray.h> |
| #include <ctype.h> /* For tolower() */ |
| |
| #ifdef HAVE_XLOCALE_H |
| /* Needed on BSD/OS X for e.g. strtod_l */ |
| #include <xlocale.h> |
| #endif |
| |
| #ifdef G_OS_WIN32 |
| #include <windows.h> |
| #endif |
| |
| /* do not include <unistd.h> here, it may interfere with g_strsignal() */ |
| |
| #include "gstrfuncs.h" |
| |
| #include "gprintf.h" |
| #include "gprintfint.h" |
| #include "glibintl.h" |
| |
| /** |
| * g_ascii_isalnum: |
| * @c: any character |
| * |
| * Determines whether a character is alphanumeric. |
| * |
| * Unlike the standard C library `isalnum()` function, this only |
| * recognizes standard ASCII letters and ignores the locale, |
| * returning false for all non-ASCII characters. Also, unlike |
| * the standard library function, this takes a `char`, not an `int`, |
| * so don't call it on `EOF`, but no need to cast to `guchar` before |
| * passing a possibly non-ASCII character in. |
| * |
| * Returns: true if @c is an ASCII alphanumeric character |
| */ |
| |
| /** |
| * g_ascii_isalpha: |
| * @c: any character |
| * |
| * Determines whether a character is alphabetic (i.e. a letter). |
| * |
| * Unlike the standard C library `isalpha()` function, this only |
| * recognizes standard ASCII letters and ignores the locale, |
| * returning false for all non-ASCII characters. Also, unlike |
| * the standard library function, this takes a `char`, not an `int`, |
| * so don't call it on `EOF`, but no need to cast to `guchar` before |
| * passing a possibly non-ASCII character in. |
| * |
| * Returns: true if @c is an ASCII alphabetic character |
| */ |
| |
| /** |
| * g_ascii_iscntrl: |
| * @c: any character |
| * |
| * Determines whether a character is a control character. |
| * |
| * Unlike the standard C library `iscntrl()` function, this only |
| * recognizes standard ASCII control characters and ignores the |
| * locale, returning false for all non-ASCII characters. Also, |
| * unlike the standard library function, this takes a `char`, not |
| * an `int`, so don't call it on `EOF`, but no need to cast to `guchar` |
| * before passing a possibly non-ASCII character in. |
| * |
| * Returns: true if @c is an ASCII control character |
| */ |
| |
| /** |
| * g_ascii_isdigit: |
| * @c: any character |
| * |
| * Determines whether a character is digit (0-9). |
| * |
| * Unlike the standard C library `isdigit()` function, this takes |
| * a `char`, not an `int`, so don't call it on `EOF`, but no need to |
| * cast to `guchar` before passing a possibly non-ASCII character in. |
| * |
| * Returns: true if @c is an ASCII digit |
| */ |
| |
| /** |
| * g_ascii_isgraph: |
| * @c: any character |
| * |
| * Determines whether a character is a printing character and not a space. |
| * |
| * Unlike the standard C library `isgraph()` function, this only |
| * recognizes standard ASCII characters and ignores the locale, |
| * returning false for all non-ASCII characters. Also, unlike |
| * the standard library function, this takes a `char`, not an `int`, |
| * so don't call it on `EOF`, but no need to cast to `guchar` before |
| * passing a possibly non-ASCII character in. |
| * |
| * Returns: true if @c is an ASCII printing character other than space |
| */ |
| |
| /** |
| * g_ascii_islower: |
| * @c: any character |
| * |
| * Determines whether a character is an ASCII lower case letter. |
| * |
| * Unlike the standard C library `islower()` function, this only |
| * recognizes standard ASCII letters and ignores the locale, |
| * returning false for all non-ASCII characters. Also, unlike |
| * the standard library function, this takes a `char`, not an `int`, |
| * so don't call it on `EOF`, but no need to worry about casting |
| * to `guchar` before passing a possibly non-ASCII character in. |
| * |
| * Returns: true if @c is an ASCII lower case letter |
| */ |
| |
| /** |
| * g_ascii_isprint: |
| * @c: any character |
| * |
| * Determines whether a character is a printing character. |
| * |
| * Unlike the standard C library `isprint()` function, this only |
| * recognizes standard ASCII characters and ignores the locale, |
| * returning false for all non-ASCII characters. Also, unlike |
| * the standard library function, this takes a `char`, not an `int`, |
| * so don't call it on `EOF`, but no need to cast to `guchar` before |
| * passing a possibly non-ASCII character in. |
| * |
| * Returns: true if @c is an ASCII printing character |
| */ |
| |
| /** |
| * g_ascii_ispunct: |
| * @c: any character |
| * |
| * Determines whether a character is a punctuation character. |
| * |
| * Unlike the standard C library `ispunct()` function, this only |
| * recognizes standard ASCII letters and ignores the locale, |
| * returning false for all non-ASCII characters. Also, unlike |
| * the standard library function, this takes a `char`, not an `int`, |
| * so don't call it on `EOF`, but no need to cast to `guchar` before |
| * passing a possibly non-ASCII character in. |
| * |
| * Returns: true if @c is an ASCII punctuation character |
| */ |
| |
| /** |
| * g_ascii_isspace: |
| * @c: any character |
| * |
| * Determines whether a character is a white-space character. |
| * |
| * Unlike the standard C library `isspace()` function, this only |
| * recognizes standard ASCII white-space and ignores the locale, |
| * returning false for all non-ASCII characters. Also, unlike |
| * the standard library function, this takes a `char`, not an `int`, |
| * so don't call it on `EOF`, but no need to cast to `guchar` before |
| * passing a possibly non-ASCII character in. |
| * |
| * Returns: true if @c is an ASCII white-space character |
| */ |
| |
| /** |
| * g_ascii_isupper: |
| * @c: any character |
| * |
| * Determines whether a character is an ASCII upper case letter. |
| * |
| * Unlike the standard C library `isupper()` function, this only |
| * recognizes standard ASCII letters and ignores the locale, |
| * returning false for all non-ASCII characters. Also, unlike |
| * the standard library function, this takes a `char`, not an `int`, |
| * so don't call it on `EOF`, but no need to worry about casting |
| * to `guchar` before passing a possibly non-ASCII character in. |
| * |
| * Returns: true if @c is an ASCII upper case letter |
| */ |
| |
| /** |
| * g_ascii_isxdigit: |
| * @c: any character |
| * |
| * Determines whether a character is a hexadecimal-digit character. |
| * |
| * Unlike the standard C library `isxdigit()` function, this takes |
| * a `char`, not an `int`, so don't call it on `EOF`, but no need to |
| * cast to `guchar` before passing a possibly non-ASCII character in. |
| * |
| * Returns: true if @c is an ASCII hexadecimal-digit character |
| */ |
| |
| /** |
| * G_ASCII_DTOSTR_BUF_SIZE: |
| * |
| * A good size for a buffer to be passed into [func@GLib.ascii_dtostr]. |
| * It is guaranteed to be enough for all output of that function |
| * on systems with 64bit IEEE-compatible doubles. |
| * |
| * The typical usage would be something like: |
| * ```C |
| * char buf[G_ASCII_DTOSTR_BUF_SIZE]; |
| * |
| * fprintf (out, "value=%s\n", g_ascii_dtostr (buf, sizeof (buf), value)); |
| * ``` |
| */ |
| |
| /** |
| * g_strstrip: |
| * @string: a string to remove the leading and trailing whitespace from |
| * |
| * Removes leading and trailing whitespace from a string. |
| * |
| * See [func@GLib.strchomp] and [func@GLib.strchug]. |
| * |
| * Returns: @string |
| */ |
| |
| /** |
| * G_STR_DELIMITERS: |
| * |
| * The standard delimiters, used in [func@GLib.strdelimit]. |
| */ |
| |
| static const guint16 ascii_table_data[256] = { |
| 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, |
| 0x004, 0x104, 0x104, 0x004, 0x104, 0x104, 0x004, 0x004, |
| 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, |
| 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, |
| 0x140, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, |
| 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, |
| 0x459, 0x459, 0x459, 0x459, 0x459, 0x459, 0x459, 0x459, |
| 0x459, 0x459, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, |
| 0x0d0, 0x653, 0x653, 0x653, 0x653, 0x653, 0x653, 0x253, |
| 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, |
| 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, |
| 0x253, 0x253, 0x253, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, |
| 0x0d0, 0x473, 0x473, 0x473, 0x473, 0x473, 0x473, 0x073, |
| 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, |
| 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, |
| 0x073, 0x073, 0x073, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x004 |
| /* the upper 128 are all zeroes */ |
| }; |
| |
| const guint16 * const g_ascii_table = ascii_table_data; |
| |
| #if defined(HAVE_NEWLOCALE) && \ |
| defined(HAVE_USELOCALE) |
| #define USE_XLOCALE 1 |
| #endif |
| |
| #ifdef USE_XLOCALE |
| static locale_t |
| get_C_locale (void) |
| { |
| static gsize initialized = FALSE; |
| static locale_t C_locale = NULL; |
| |
| if (g_once_init_enter (&initialized)) |
| { |
| C_locale = newlocale (LC_ALL_MASK, "C", NULL); |
| g_once_init_leave (&initialized, TRUE); |
| } |
| |
| return C_locale; |
| } |
| #endif |
| |
| /** |
| * g_strdup: |
| * @str: (nullable): the string to duplicate |
| * |
| * Duplicates a string. If @str is `NULL` it returns `NULL`. |
| * |
| * Returns: a newly-allocated copy of @str |
| */ |
| gchar* |
| (g_strdup) (const gchar *str) |
| { |
| gchar *new_str; |
| gsize length; |
| |
| if G_LIKELY (str) |
| { |
| length = strlen (str) + 1; |
| new_str = g_new (char, length); |
| memcpy (new_str, str, length); |
| } |
| else |
| new_str = NULL; |
| |
| return new_str; |
| } |
| |
| /** |
| * g_memdup: |
| * @mem: the memory to copy |
| * @byte_size: the number of bytes to copy |
| * |
| * Allocates @byte_size bytes of memory, and copies @byte_size bytes into it |
| * from @mem. If @mem is `NULL` it returns `NULL`. |
| * |
| * Returns: (transfer full) (nullable): a pointer to the newly-allocated copy of the memory |
| * |
| * Deprecated: 2.68: Use [func@GLib.memdup2] instead, as it accepts a gsize argument |
| * for @byte_size, avoiding the possibility of overflow in a `gsize` → `guint` |
| * conversion |
| */ |
| gpointer |
| g_memdup (gconstpointer mem, |
| guint byte_size) |
| { |
| gpointer new_mem; |
| |
| if (mem && byte_size != 0) |
| { |
| new_mem = g_malloc (byte_size); |
| memcpy (new_mem, mem, byte_size); |
| } |
| else |
| new_mem = NULL; |
| |
| return new_mem; |
| } |
| |
| /** |
| * g_memdup2: |
| * @mem: (nullable): the memory to copy |
| * @byte_size: the number of bytes to copy |
| * |
| * Allocates @byte_size bytes of memory, and copies @byte_size bytes into it |
| * from @mem. If @mem is `NULL` it returns `NULL`. |
| * |
| * This replaces [func@GLib.memdup], which was prone to integer overflows when |
| * converting the argument from a `gsize` to a `guint`. |
| * |
| * Returns: (transfer full) (nullable): a pointer to the newly-allocated copy of the memory |
| * |
| * Since: 2.68 |
| */ |
| gpointer |
| g_memdup2 (gconstpointer mem, |
| gsize byte_size) |
| { |
| gpointer new_mem; |
| |
| if (mem && byte_size != 0) |
| { |
| new_mem = g_malloc (byte_size); |
| memcpy (new_mem, mem, byte_size); |
| } |
| else |
| new_mem = NULL; |
| |
| return new_mem; |
| } |
| |
| /** |
| * g_strndup: |
| * @str: (nullable): the string to duplicate |
| * @n: the maximum number of bytes to copy from @str |
| * |
| * Duplicates the first @n bytes of a string, returning a newly-allocated |
| * buffer @n + 1 bytes long which will always be nul-terminated. If @str |
| * is less than @n bytes long the buffer is padded with nuls. If @str is |
| * `NULL` it returns `NULL`. |
| * |
| * To copy a number of characters from a UTF-8 encoded string, |
| * use [func@GLib.utf8_strncpy] instead. |
| * |
| * Returns: (nullable): a newly-allocated buffer containing the first |
| * @n bytes of @str |
| */ |
| gchar* |
| g_strndup (const gchar *str, |
| gsize n) |
| { |
| gchar *new_str; |
| |
| if (str) |
| { |
| new_str = g_new (gchar, n + 1); |
| strncpy (new_str, str, n); |
| new_str[n] = '\0'; |
| } |
| else |
| new_str = NULL; |
| |
| return new_str; |
| } |
| |
| /** |
| * g_strnfill: |
| * @length: the length of the new string |
| * @fill_char: the byte to fill the string with |
| * |
| * Creates a new string @length bytes long filled with @fill_char. |
| * |
| * Returns: a newly-allocated string filled with @fill_char |
| */ |
| gchar* |
| g_strnfill (gsize length, |
| gchar fill_char) |
| { |
| gchar *str; |
| |
| str = g_new (gchar, length + 1); |
| memset (str, (guchar)fill_char, length); |
| str[length] = '\0'; |
| |
| return str; |
| } |
| |
| /** |
| * g_stpcpy: |
| * @dest: destination buffer |
| * @src: source string |
| * |
| * Copies a nul-terminated string into the destination buffer, including |
| * the trailing nul byte, and returns a pointer to the trailing nul byte |
| * in `dest`. The return value is useful for concatenating multiple |
| * strings without having to repeatedly scan for the end. |
| * |
| * Returns: a pointer to the trailing nul byte in `dest` |
| **/ |
| gchar * |
| g_stpcpy (gchar *dest, |
| const gchar *src) |
| { |
| #ifdef HAVE_STPCPY |
| g_return_val_if_fail (dest != NULL, NULL); |
| g_return_val_if_fail (src != NULL, NULL); |
| return stpcpy (dest, src); |
| #else |
| gchar *d = dest; |
| const gchar *s = src; |
| |
| g_return_val_if_fail (dest != NULL, NULL); |
| g_return_val_if_fail (src != NULL, NULL); |
| do |
| *d++ = *s; |
| while (*s++ != '\0'); |
| |
| return d - 1; |
| #endif |
| } |
| |
| /** |
| * g_strdup_vprintf: |
| * @format: (not nullable): a standard `printf()` format string, but notice |
| * [string precision pitfalls](string-utils.html#string-precision-pitfalls) |
| * @args: the list of parameters to insert into the format string |
| * |
| * Similar to the standard C `vsprintf()` function but safer, since it |
| * calculates the maximum space required and allocates memory to hold |
| * the result. |
| * |
| * The returned string is guaranteed to be non-NULL, unless @format |
| * contains `%lc` or `%ls` conversions, which can fail if no multibyte |
| * representation is available for the given character. |
| * |
| * See also [func@GLib.vasprintf], which offers the same functionality, but |
| * additionally returns the length of the allocated string. |
| * |
| * Returns: (nullable) (transfer full): a newly-allocated string holding the |
| * result |
| */ |
| gchar* |
| g_strdup_vprintf (const gchar *format, |
| va_list args) |
| { |
| gchar *string = NULL; |
| |
| g_vasprintf (&string, format, args); |
| |
| return string; |
| } |
| |
| /** |
| * g_strdup_printf: |
| * @format: (not nullable): a standard `printf()` format string, but notice |
| * [string precision pitfalls](string-utils.html#string-precision-pitfalls) |
| * @...: the parameters to insert into the format string |
| * |
| * Similar to the standard C `sprintf()` function but safer, since it |
| * calculates the maximum space required and allocates memory to hold |
| * the result. |
| * |
| * The returned string is guaranteed to be non-NULL, unless @format |
| * contains `%lc` or `%ls` conversions, which can fail if no multibyte |
| * representation is available for the given character. |
| * |
| * Returns: (nullable) (transfer full): a newly-allocated string holding the |
| * result |
| */ |
| gchar* |
| g_strdup_printf (const gchar *format, |
| ...) |
| { |
| gchar *buffer; |
| va_list args; |
| |
| va_start (args, format); |
| buffer = g_strdup_vprintf (format, args); |
| va_end (args); |
| |
| return buffer; |
| } |
| |
| /** |
| * g_strconcat: |
| * @string1: the first string to add, which must not be `NULL` |
| * @...: a `NULL`-terminated list of strings to append to the string |
| * |
| * Concatenates all of the given strings into one long string. |
| * |
| * The variable argument list must end with `NULL`. If you forget the `NULL`, |
| * `g_strconcat()` will start appending random memory junk to your string. |
| * |
| * Note that this function is usually not the right function to use to |
| * assemble a translated message from pieces, since proper translation |
| * often requires the pieces to be reordered. |
| * |
| * Returns: a newly-allocated string containing all the string arguments |
| */ |
| gchar* |
| g_strconcat (const gchar *string1, ...) |
| { |
| gsize l; |
| va_list args; |
| gchar *s; |
| gchar *concat; |
| gchar *ptr; |
| |
| if (!string1) |
| return NULL; |
| |
| l = 1 + strlen (string1); |
| va_start (args, string1); |
| s = va_arg (args, gchar*); |
| while (s) |
| { |
| l += strlen (s); |
| s = va_arg (args, gchar*); |
| } |
| va_end (args); |
| |
| concat = g_new (gchar, l); |
| ptr = concat; |
| |
| ptr = g_stpcpy (ptr, string1); |
| va_start (args, string1); |
| s = va_arg (args, gchar*); |
| while (s) |
| { |
| ptr = g_stpcpy (ptr, s); |
| s = va_arg (args, gchar*); |
| } |
| va_end (args); |
| |
| return concat; |
| } |
| |
| /** |
| * g_strtod: |
| * @nptr: the string to convert to a numeric value |
| * @endptr: (out) (transfer none) (optional): if non-`NULL`, it returns the |
| * character after the last character used in the conversion |
| * |
| * Converts a string to a floating point value. |
| * |
| * It calls the standard `strtod()` function to handle the conversion, but |
| * if the string is not completely converted it attempts the conversion |
| * again with [func@GLib.ascii_strtod], and returns the best match. |
| * |
| * This function should seldom be used. The normal situation when reading |
| * numbers not for human consumption is to use [func@GLib.ascii_strtod]. Only when |
| * you know that you must expect both locale formatted and C formatted numbers |
| * should you use this. Make sure that you don't pass strings such as comma |
| * separated lists of values, since the commas may be interpreted as a decimal |
| * point in some locales, causing unexpected results. |
| * |
| * Returns: the converted value |
| **/ |
| gdouble |
| g_strtod (const gchar *nptr, |
| gchar **endptr) |
| { |
| gchar *fail_pos_1; |
| gchar *fail_pos_2; |
| gdouble val_1; |
| gdouble val_2 = 0; |
| |
| g_return_val_if_fail (nptr != NULL, 0); |
| |
| fail_pos_1 = NULL; |
| fail_pos_2 = NULL; |
| |
| val_1 = strtod (nptr, &fail_pos_1); |
| |
| if (fail_pos_1 && fail_pos_1[0] != 0) |
| val_2 = g_ascii_strtod (nptr, &fail_pos_2); |
| |
| if (!fail_pos_1 || fail_pos_1[0] == 0 || fail_pos_1 >= fail_pos_2) |
| { |
| if (endptr) |
| *endptr = fail_pos_1; |
| return val_1; |
| } |
| else |
| { |
| if (endptr) |
| *endptr = fail_pos_2; |
| return val_2; |
| } |
| } |
| |
| /** |
| * g_ascii_strtod: |
| * @nptr: the string to convert to a numeric value |
| * @endptr: (out) (transfer none) (optional): if non-`NULL`, it returns the |
| * character after the last character used in the conversion |
| * |
| * Converts a string to a floating point value. |
| * |
| * This function behaves like the standard `strtod()` function |
| * does in the C locale. It does this without actually changing |
| * the current locale, since that would not be thread-safe. |
| * A limitation of the implementation is that this function |
| * will still accept localized versions of infinities and NANs. |
| * |
| * This function is typically used when reading configuration |
| * files or other non-user input that should be locale independent. |
| * To handle input from the user you should normally use the |
| * locale-sensitive system `strtod()` function. |
| * |
| * To convert from a gdouble to a string in a locale-insensitive |
| * way, use [func@GLib.ascii_dtostr]. |
| * |
| * If the correct value would cause overflow, plus or minus `HUGE_VAL` |
| * is returned (according to the sign of the value), and `ERANGE` is |
| * stored in `errno`. If the correct value would cause underflow, |
| * zero is returned and `ERANGE` is stored in `errno`. |
| * |
| * This function resets `errno` before calling `strtod()` so that |
| * you can reliably detect overflow and underflow. |
| * |
| * Returns: the converted value |
| */ |
| gdouble |
| g_ascii_strtod (const gchar *nptr, |
| gchar **endptr) |
| { |
| #if defined(USE_XLOCALE) && defined(HAVE_STRTOD_L) |
| |
| g_return_val_if_fail (nptr != NULL, 0); |
| |
| errno = 0; |
| |
| return strtod_l (nptr, endptr, get_C_locale ()); |
| |
| #else |
| |
| gchar *fail_pos; |
| gdouble val; |
| #ifndef __BIONIC__ |
| struct lconv *locale_data; |
| #endif |
| const char *decimal_point; |
| gsize decimal_point_len; |
| const char *p, *decimal_point_pos; |
| const char *end = NULL; /* Silence gcc */ |
| int strtod_errno; |
| |
| g_return_val_if_fail (nptr != NULL, 0); |
| |
| fail_pos = NULL; |
| |
| #ifndef __BIONIC__ |
| locale_data = localeconv (); |
| decimal_point = locale_data->decimal_point; |
| decimal_point_len = strlen (decimal_point); |
| #else |
| decimal_point = "."; |
| decimal_point_len = 1; |
| #endif |
| |
| g_assert (decimal_point_len != 0); |
| |
| decimal_point_pos = NULL; |
| end = NULL; |
| |
| if (decimal_point[0] != '.' || |
| decimal_point[1] != 0) |
| { |
| p = nptr; |
| /* Skip leading space */ |
| while (g_ascii_isspace (*p)) |
| p++; |
| |
| /* Skip leading optional sign */ |
| if (*p == '+' || *p == '-') |
| p++; |
| |
| if (p[0] == '0' && |
| (p[1] == 'x' || p[1] == 'X')) |
| { |
| p += 2; |
| /* HEX - find the (optional) decimal point */ |
| |
| while (g_ascii_isxdigit (*p)) |
| p++; |
| |
| if (*p == '.') |
| decimal_point_pos = p++; |
| |
| while (g_ascii_isxdigit (*p)) |
| p++; |
| |
| if (*p == 'p' || *p == 'P') |
| p++; |
| if (*p == '+' || *p == '-') |
| p++; |
| while (g_ascii_isdigit (*p)) |
| p++; |
| |
| end = p; |
| } |
| else if (g_ascii_isdigit (*p) || *p == '.') |
| { |
| while (g_ascii_isdigit (*p)) |
| p++; |
| |
| if (*p == '.') |
| decimal_point_pos = p++; |
| |
| while (g_ascii_isdigit (*p)) |
| p++; |
| |
| if (*p == 'e' || *p == 'E') |
| p++; |
| if (*p == '+' || *p == '-') |
| p++; |
| while (g_ascii_isdigit (*p)) |
| p++; |
| |
| end = p; |
| } |
| /* For the other cases, we need not convert the decimal point */ |
| } |
| |
| if (decimal_point_pos) |
| { |
| char *copy, *c; |
| |
| /* We need to convert the '.' to the locale specific decimal point */ |
| copy = g_malloc (end - nptr + 1 + decimal_point_len); |
| |
| c = copy; |
| memcpy (c, nptr, decimal_point_pos - nptr); |
| c += decimal_point_pos - nptr; |
| memcpy (c, decimal_point, decimal_point_len); |
| c += decimal_point_len; |
| memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1)); |
| c += end - (decimal_point_pos + 1); |
| *c = 0; |
| |
| errno = 0; |
| val = strtod (copy, &fail_pos); |
| strtod_errno = errno; |
| |
| if (fail_pos) |
| { |
| if (fail_pos - copy > decimal_point_pos - nptr) |
| fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1); |
| else |
| fail_pos = (char *)nptr + (fail_pos - copy); |
| } |
| |
| g_free (copy); |
| |
| } |
| else if (end) |
| { |
| char *copy; |
| |
| copy = g_malloc (end - (char *)nptr + 1); |
| memcpy (copy, nptr, end - nptr); |
| *(copy + (end - (char *)nptr)) = 0; |
| |
| errno = 0; |
| val = strtod (copy, &fail_pos); |
| strtod_errno = errno; |
| |
| if (fail_pos) |
| { |
| fail_pos = (char *)nptr + (fail_pos - copy); |
| } |
| |
| g_free (copy); |
| } |
| else |
| { |
| errno = 0; |
| val = strtod (nptr, &fail_pos); |
| strtod_errno = errno; |
| } |
| |
| if (endptr) |
| *endptr = fail_pos; |
| |
| errno = strtod_errno; |
| |
| return val; |
| #endif |
| } |
| |
| |
| /** |
| * g_ascii_dtostr: |
| * @buffer: a buffer to place the resulting string in |
| * @buf_len: the length of the buffer |
| * @d: the value to convert |
| * |
| * Converts a `gdouble` to a string, using the '.' as |
| * decimal point. |
| * |
| * This function generates enough precision that converting |
| * the string back using [func@GLib.ascii_strtod] gives the same machine-number |
| * (on machines with IEEE compatible 64bit doubles). It is |
| * guaranteed that the size of the resulting string will never |
| * be larger than [const@GLib.ASCII_DTOSTR_BUF_SIZE] bytes, including the terminating |
| * nul character, which is always added. |
| * |
| * Returns: the pointer to the buffer with the converted string |
| **/ |
| gchar * |
| g_ascii_dtostr (gchar *buffer, |
| gint buf_len, |
| gdouble d) |
| { |
| return g_ascii_formatd (buffer, buf_len, "%.17g", d); |
| } |
| |
| #pragma GCC diagnostic push |
| #pragma GCC diagnostic ignored "-Wformat-nonliteral" |
| |
| /** |
| * g_ascii_formatd: |
| * @buffer: a buffer to place the resulting string in |
| * @buf_len: the length of the buffer |
| * @format: the `printf()`-style format to use for the |
| * code to use for converting |
| * @d: the value to convert |
| * |
| * Converts a `gdouble` to a string, using the '.' as |
| * decimal point. To format the number you pass in |
| * a `printf()`-style format string. Allowed conversion |
| * specifiers are 'e', 'E', 'f', 'F', 'g' and 'G'. |
| * |
| * The @format must just be a single format specifier |
| * starting with `%`, expecting a `gdouble` argument. |
| * |
| * The returned buffer is guaranteed to be nul-terminated. |
| * |
| * If you just want to want to serialize the value into a |
| * string, use [func@GLib.ascii_dtostr]. |
| * |
| * Returns: the pointer to the buffer with the converted string |
| */ |
| gchar * |
| g_ascii_formatd (gchar *buffer, |
| gint buf_len, |
| const gchar *format, |
| gdouble d) |
| { |
| #ifdef USE_XLOCALE |
| locale_t old_locale; |
| |
| g_return_val_if_fail (buffer != NULL, NULL); |
| g_return_val_if_fail (format[0] == '%', NULL); |
| g_return_val_if_fail (strpbrk (format + 1, "'l%") == NULL, NULL); |
| |
| old_locale = uselocale (get_C_locale ()); |
| _g_snprintf (buffer, buf_len, format, d); |
| uselocale (old_locale); |
| |
| return buffer; |
| #else |
| #ifndef __BIONIC__ |
| struct lconv *locale_data; |
| #endif |
| const char *decimal_point; |
| gsize decimal_point_len; |
| gchar *p; |
| int rest_len; |
| gchar format_char; |
| |
| g_return_val_if_fail (buffer != NULL, NULL); |
| g_return_val_if_fail (format[0] == '%', NULL); |
| g_return_val_if_fail (strpbrk (format + 1, "'l%") == NULL, NULL); |
| |
| format_char = format[strlen (format) - 1]; |
| |
| g_return_val_if_fail (format_char == 'e' || format_char == 'E' || |
| format_char == 'f' || format_char == 'F' || |
| format_char == 'g' || format_char == 'G', |
| NULL); |
| |
| if (format[0] != '%') |
| return NULL; |
| |
| if (strpbrk (format + 1, "'l%")) |
| return NULL; |
| |
| if (!(format_char == 'e' || format_char == 'E' || |
| format_char == 'f' || format_char == 'F' || |
| format_char == 'g' || format_char == 'G')) |
| return NULL; |
| |
| _g_snprintf (buffer, buf_len, format, d); |
| |
| #ifndef __BIONIC__ |
| locale_data = localeconv (); |
| decimal_point = locale_data->decimal_point; |
| decimal_point_len = strlen (decimal_point); |
| #else |
| decimal_point = "."; |
| decimal_point_len = 1; |
| #endif |
| |
| g_assert (decimal_point_len != 0); |
| |
| if (decimal_point[0] != '.' || |
| decimal_point[1] != 0) |
| { |
| p = buffer; |
| |
| while (g_ascii_isspace (*p)) |
| p++; |
| |
| if (*p == '+' || *p == '-') |
| p++; |
| |
| while (isdigit ((guchar)*p)) |
| p++; |
| |
| if (strncmp (p, decimal_point, decimal_point_len) == 0) |
| { |
| *p = '.'; |
| p++; |
| if (decimal_point_len > 1) |
| { |
| rest_len = strlen (p + (decimal_point_len - 1)); |
| memmove (p, p + (decimal_point_len - 1), rest_len); |
| p[rest_len] = 0; |
| } |
| } |
| } |
| |
| return buffer; |
| #endif |
| } |
| #pragma GCC diagnostic pop |
| |
| #define ISSPACE(c) ((c) == ' ' || (c) == '\f' || (c) == '\n' || \ |
| (c) == '\r' || (c) == '\t' || (c) == '\v') |
| #define ISUPPER(c) ((c) >= 'A' && (c) <= 'Z') |
| #define ISLOWER(c) ((c) >= 'a' && (c) <= 'z') |
| #define ISALPHA(c) (ISUPPER (c) || ISLOWER (c)) |
| #define TOUPPER(c) (ISLOWER (c) ? (c) - 'a' + 'A' : (c)) |
| #define TOLOWER(c) (ISUPPER (c) ? (c) - 'A' + 'a' : (c)) |
| |
| #if !defined(USE_XLOCALE) || !defined(HAVE_STRTOULL_L) || !defined(HAVE_STRTOLL_L) |
| |
| static guint64 |
| g_parse_long_long (const gchar *nptr, |
| const gchar **endptr, |
| guint base, |
| gboolean *negative) |
| { |
| /* this code is based on on the strtol(3) code from GNU libc released under |
| * the GNU Lesser General Public License. |
| * |
| * Copyright (C) 1991,92,94,95,96,97,98,99,2000,01,02 |
| * Free Software Foundation, Inc. |
| */ |
| gboolean overflow; |
| guint64 cutoff; |
| guint64 cutlim; |
| guint64 ui64; |
| const gchar *s, *save; |
| guchar c; |
| |
| g_return_val_if_fail (nptr != NULL, 0); |
| |
| *negative = FALSE; |
| if (base == 1 || base > 36) |
| { |
| errno = EINVAL; |
| if (endptr) |
| *endptr = nptr; |
| return 0; |
| } |
| |
| save = s = nptr; |
| |
| /* Skip white space. */ |
| while (ISSPACE (*s)) |
| ++s; |
| |
| if (G_UNLIKELY (!*s)) |
| goto noconv; |
| |
| /* Check for a sign. */ |
| if (*s == '-') |
| { |
| *negative = TRUE; |
| ++s; |
| } |
| else if (*s == '+') |
| ++s; |
| |
| /* Recognize number prefix and if BASE is zero, figure it out ourselves. */ |
| if (*s == '0') |
| { |
| if ((base == 0 || base == 16) && TOUPPER (s[1]) == 'X') |
| { |
| s += 2; |
| base = 16; |
| } |
| else if (base == 0) |
| base = 8; |
| } |
| else if (base == 0) |
| base = 10; |
| |
| /* Save the pointer so we can check later if anything happened. */ |
| save = s; |
| cutoff = G_MAXUINT64 / base; |
| cutlim = G_MAXUINT64 % base; |
| |
| overflow = FALSE; |
| ui64 = 0; |
| c = *s; |
| for (; c; c = *++s) |
| { |
| if (c >= '0' && c <= '9') |
| c -= '0'; |
| else if (ISALPHA (c)) |
| c = TOUPPER (c) - 'A' + 10; |
| else |
| break; |
| if (c >= base) |
| break; |
| /* Check for overflow. */ |
| if (ui64 > cutoff || (ui64 == cutoff && c > cutlim)) |
| overflow = TRUE; |
| else |
| { |
| ui64 *= base; |
| ui64 += c; |
| } |
| } |
| |
| /* Check if anything actually happened. */ |
| if (s == save) |
| goto noconv; |
| |
| /* Store in ENDPTR the address of one character |
| past the last character we converted. */ |
| if (endptr) |
| *endptr = s; |
| |
| if (G_UNLIKELY (overflow)) |
| { |
| errno = ERANGE; |
| return G_MAXUINT64; |
| } |
| |
| return ui64; |
| |
| noconv: |
| /* We must handle a special case here: the base is 0 or 16 and the |
| first two characters are '0' and 'x', but the rest are no |
| hexadecimal digits. This is no error case. We return 0 and |
| ENDPTR points to the `x`. */ |
| if (endptr) |
| { |
| if (save - nptr >= 2 && TOUPPER (save[-1]) == 'X' |
| && save[-2] == '0') |
| *endptr = &save[-1]; |
| else |
| /* There was no number to convert. */ |
| *endptr = nptr; |
| } |
| return 0; |
| } |
| #endif /* !defined(USE_XLOCALE) || !defined(HAVE_STRTOULL_L) || !defined(HAVE_STRTOLL_L) */ |
| |
| /** |
| * g_ascii_strtoull: |
| * @nptr: the string to convert to a numeric value |
| * @endptr: (out) (transfer none) (optional): if non-`NULL`, it returns the |
| * character after the last character used in the conversion |
| * @base: to be used for the conversion, 2..36 or 0 |
| * |
| * Converts a string to a `guint64` value. |
| * |
| * This function behaves like the standard `strtoull()` function |
| * does in the C locale. It does this without actually |
| * changing the current locale, since that would not be |
| * thread-safe. |
| * |
| * Note that input with a leading minus sign (`-`) is accepted, and will return |
| * the negation of the parsed number, unless that would overflow a `guint64`. |
| * Critically, this means you cannot assume that a short fixed length input will |
| * result in a low return value, as the input could have a leading `-`. |
| * |
| * This function is typically used when reading configuration |
| * files or other non-user input that should be locale independent. |
| * To handle input from the user you should normally use the |
| * locale-sensitive system `strtoull()` function. |
| * |
| * If the correct value would cause overflow, [const@GLib.MAXUINT64] |
| * is returned, and `ERANGE` is stored in `errno`. |
| * If the base is outside the valid range, zero is returned, and |
| * `EINVAL` is stored in `errno`. |
| * If the string conversion fails, zero is returned, and @endptr returns |
| * @nptr (if @endptr is non-`NULL`). |
| * |
| * Returns: the converted value, or zero on error |
| * |
| * Since: 2.2 |
| */ |
| guint64 |
| g_ascii_strtoull (const gchar *nptr, |
| gchar **endptr, |
| guint base) |
| { |
| #if defined(USE_XLOCALE) && defined(HAVE_STRTOULL_L) |
| return strtoull_l (nptr, endptr, base, get_C_locale ()); |
| #else |
| gboolean negative; |
| guint64 result; |
| |
| result = g_parse_long_long (nptr, (const gchar **) endptr, base, &negative); |
| |
| /* Return the result of the appropriate sign. */ |
| return negative ? -result : result; |
| #endif |
| } |
| |
| /** |
| * g_ascii_strtoll: |
| * @nptr: the string to convert to a numeric value |
| * @endptr: (out) (transfer none) (optional): if non-`NULL`, it returns the |
| * character after the last character used in the conversion |
| * @base: to be used for the conversion, 2..36 or 0 |
| * |
| * Converts a string to a `gint64` value. |
| * |
| * This function behaves like the standard `strtoll()` function |
| * does in the C locale. It does this without actually |
| * changing the current locale, since that would not be |
| * thread-safe. |
| * |
| * This function is typically used when reading configuration |
| * files or other non-user input that should be locale independent. |
| * To handle input from the user you should normally use the |
| * locale-sensitive system `strtoll()` function. |
| * |
| * If the correct value would cause overflow, [const@GLib.MAXINT64] or |
| * [const@GLib.MININT64] is returned, and `ERANGE` is stored in `errno`. |
| * If the base is outside the valid range, zero is returned, and |
| * `EINVAL` is stored in `errno`. If the |
| * string conversion fails, zero is returned, and @endptr returns @nptr |
| * (if @endptr is non-`NULL`). |
| * |
| * Returns: the converted value, or zero on error |
| * |
| * Since: 2.12 |
| */ |
| gint64 |
| g_ascii_strtoll (const gchar *nptr, |
| gchar **endptr, |
| guint base) |
| { |
| #if defined(USE_XLOCALE) && defined(HAVE_STRTOLL_L) |
| return strtoll_l (nptr, endptr, base, get_C_locale ()); |
| #else |
| gboolean negative; |
| guint64 result; |
| |
| result = g_parse_long_long (nptr, (const gchar **) endptr, base, &negative); |
| |
| if (negative && result > (guint64) G_MININT64) |
| { |
| errno = ERANGE; |
| return G_MININT64; |
| } |
| else if (!negative && result > (guint64) G_MAXINT64) |
| { |
| errno = ERANGE; |
| return G_MAXINT64; |
| } |
| else if (negative) |
| return - (gint64) result; |
| else |
| return (gint64) result; |
| #endif |
| } |
| |
| /** |
| * g_strerror: |
| * @errnum: the system error number. See the standard C `errno` documentation |
| * |
| * Returns a string corresponding to the given error code, e.g. "no |
| * such process". |
| * |
| * Unlike `strerror()`, this always returns a string in |
| * UTF-8 encoding, and the pointer is guaranteed to remain valid for |
| * the lifetime of the process. If the error code is unknown, it returns a |
| * string like “Unknown error <code\>”. |
| * |
| * Note that the string may be translated according to the current locale. |
| * |
| * The value of `errno` will not be changed by this function. However, it may |
| * be changed by intermediate function calls, so you should save its value |
| * as soon as the call returns: |
| * ```C |
| * int saved_errno; |
| * |
| * ret = read (blah); |
| * saved_errno = errno; |
| * |
| * g_strerror (saved_errno); |
| * ``` |
| * |
| * Returns: the string describing the error code |
| */ |
| const gchar * |
| g_strerror (gint errnum) |
| { |
| static GHashTable *errors; |
| G_LOCK_DEFINE_STATIC (errors); |
| const gchar *msg; |
| gint saved_errno = errno; |
| |
| G_LOCK (errors); |
| if (errors) |
| msg = g_hash_table_lookup (errors, GINT_TO_POINTER (errnum)); |
| else |
| { |
| errors = g_hash_table_new (NULL, NULL); |
| msg = NULL; |
| } |
| |
| if (!msg) |
| { |
| gchar buf[1024]; |
| GError *error = NULL; |
| #if defined(HAVE_STRERROR_R) && !defined(STRERROR_R_CHAR_P) |
| int ret; |
| #endif |
| |
| #if defined(G_OS_WIN32) |
| strerror_s (buf, sizeof (buf), errnum); |
| msg = buf; |
| #elif defined(HAVE_STRERROR_R) |
| /* Match the condition in strerror_r(3) for glibc */ |
| # if defined(STRERROR_R_CHAR_P) |
| msg = strerror_r (errnum, buf, sizeof (buf)); |
| # else |
| ret = strerror_r (errnum, buf, sizeof (buf)); |
| if (ret == 0 || ret == EINVAL) |
| msg = buf; |
| # endif /* HAVE_STRERROR_R */ |
| #else |
| g_strlcpy (buf, strerror (errnum), sizeof (buf)); |
| msg = buf; |
| #endif |
| |
| if (!msg) |
| { |
| G_UNLOCK (errors); |
| |
| errno = saved_errno; |
| return NULL; |
| } |
| |
| if (!g_get_console_charset (NULL)) |
| { |
| msg = g_locale_to_utf8 (msg, -1, NULL, NULL, &error); |
| if (error) |
| { |
| g_print ("%s\n", error->message); |
| g_error_free (error); |
| } |
| } |
| else if (msg == (const gchar *)buf) |
| msg = g_strdup (buf); |
| |
| g_hash_table_insert (errors, GINT_TO_POINTER (errnum), (char *) msg); |
| } |
| G_UNLOCK (errors); |
| |
| errno = saved_errno; |
| return msg; |
| } |
| |
| /** |
| * g_strsignal: |
| * @signum: the signal number. See the `signal` documentation |
| * |
| * Returns a string describing the given signal, e.g. "Segmentation fault". |
| * If the signal is unknown, it returns “unknown signal (<signum\>)”. |
| * |
| * You should use this function in preference to `strsignal()`, because it |
| * returns a string in UTF-8 encoding, and since not all platforms support |
| * the `strsignal()` function. |
| * |
| * Returns: the string describing the signal |
| */ |
| const gchar * |
| g_strsignal (gint signum) |
| { |
| gchar *msg; |
| gchar *tofree; |
| const gchar *ret; |
| |
| msg = tofree = NULL; |
| |
| #ifdef HAVE_STRSIGNAL |
| msg = strsignal (signum); |
| if (!g_get_console_charset (NULL)) |
| msg = tofree = g_locale_to_utf8 (msg, -1, NULL, NULL, NULL); |
| #endif |
| |
| if (!msg) |
| msg = tofree = g_strdup_printf ("unknown signal (%d)", signum); |
| ret = g_intern_string (msg); |
| g_free (tofree); |
| |
| return ret; |
| } |
| |
| /* Functions g_strlcpy and g_strlcat were originally developed by |
| * Todd C. Miller <Todd.Miller@courtesan.com> to simplify writing secure code. |
| * See http://www.openbsd.org/cgi-bin/man.cgi?query=strlcpy |
| * for more information. |
| */ |
| |
| #ifdef HAVE_STRLCPY |
| /* Use the native ones, if available; they might be implemented in assembly */ |
| gsize |
| g_strlcpy (gchar *dest, |
| const gchar *src, |
| gsize dest_size) |
| { |
| g_return_val_if_fail (dest != NULL, 0); |
| g_return_val_if_fail (src != NULL, 0); |
| |
| return strlcpy (dest, src, dest_size); |
| } |
| |
| gsize |
| g_strlcat (gchar *dest, |
| const gchar *src, |
| gsize dest_size) |
| { |
| g_return_val_if_fail (dest != NULL, 0); |
| g_return_val_if_fail (src != NULL, 0); |
| |
| return strlcat (dest, src, dest_size); |
| } |
| |
| #else /* ! HAVE_STRLCPY */ |
| /** |
| * g_strlcpy: |
| * @dest: destination buffer |
| * @src: source buffer |
| * @dest_size: length of @dest in bytes |
| * |
| * Portability wrapper that calls `strlcpy()` on systems which have it, |
| * and emulates `strlcpy()` otherwise. Copies @src to @dest; @dest is |
| * guaranteed to be nul-terminated; @src must be nul-terminated; |
| * @dest_size is the buffer size, not the number of bytes to copy. |
| * |
| * At most @dest_size - 1 characters will be copied. Always nul-terminates |
| * (unless @dest_size is 0). This function does not allocate memory. Unlike |
| * `strncpy()`, this function doesn't pad @dest (so it's often faster). It |
| * returns the size of the attempted result, `strlen (src)`, so if |
| * @retval >= @dest_size, truncation occurred. |
| * |
| * Caveat: `strlcpy()` is supposedly more secure than `strcpy()` or `strncpy()`, |
| * but if you really want to avoid screwups, [func@GLib.strdup] is an even better |
| * idea. |
| * |
| * Returns: length of @src |
| */ |
| gsize |
| g_strlcpy (gchar *dest, |
| const gchar *src, |
| gsize dest_size) |
| { |
| gchar *d = dest; |
| const gchar *s = src; |
| gsize n = dest_size; |
| |
| g_return_val_if_fail (dest != NULL, 0); |
| g_return_val_if_fail (src != NULL, 0); |
| |
| /* Copy as many bytes as will fit */ |
| if (n != 0 && --n != 0) |
| do |
| { |
| gchar c = *s++; |
| |
| *d++ = c; |
| if (c == 0) |
| break; |
| } |
| while (--n != 0); |
| |
| /* If not enough room in dest, add NUL and traverse rest of src */ |
| if (n == 0) |
| { |
| if (dest_size != 0) |
| *d = 0; |
| while (*s++) |
| ; |
| } |
| |
| return s - src - 1; /* count does not include NUL */ |
| } |
| |
| /** |
| * g_strlcat: |
| * @dest: destination buffer, already containing one nul-terminated string |
| * @src: source buffer |
| * @dest_size: length of @dest buffer in bytes (not length of existing string |
| * inside @dest) |
| * |
| * Portability wrapper that calls `strlcat()` on systems which have it, |
| * and emulates it otherwise. Appends nul-terminated @src string to @dest, |
| * guaranteeing nul-termination for @dest. The total size of @dest won't |
| * exceed @dest_size. |
| * |
| * At most @dest_size - 1 characters will be copied. Unlike `strncat()`, |
| * @dest_size is the full size of dest, not the space left over. This |
| * function does not allocate memory. It always nul-terminates (unless |
| * @dest_size == 0 or there were no nul characters in the @dest_size |
| * characters of dest to start with). |
| * |
| * Caveat: this is supposedly a more secure alternative to `strcat()` or |
| * `strncat()`, but for real security [func@GLib.strconcat] is harder to mess up. |
| * |
| * Returns: size of attempted result, which is `MIN (dest_size, strlen |
| * (original dest)) + strlen (src)`, so if @retval >= @dest_size, |
| * truncation occurred |
| */ |
| gsize |
| g_strlcat (gchar *dest, |
| const gchar *src, |
| gsize dest_size) |
| { |
| gchar *d = dest; |
| const gchar *s = src; |
| gsize bytes_left = dest_size; |
| gsize dlength; /* Logically, MIN (strlen (d), dest_size) */ |
| |
| g_return_val_if_fail (dest != NULL, 0); |
| g_return_val_if_fail (src != NULL, 0); |
| |
| /* Find the end of dst and adjust bytes left but don't go past end */ |
| while (*d != 0 && bytes_left-- != 0) |
| d++; |
| dlength = d - dest; |
| bytes_left = dest_size - dlength; |
| |
| if (bytes_left == 0) |
| return dlength + strlen (s); |
| |
| while (*s != 0) |
| { |
| if (bytes_left != 1) |
| { |
| *d++ = *s; |
| bytes_left--; |
| } |
| s++; |
| } |
| *d = 0; |
| |
| return dlength + (s - src); /* count does not include NUL */ |
| } |
| #endif /* ! HAVE_STRLCPY */ |
| |
| /** |
| * g_ascii_strdown: |
| * @str: a string |
| * @len: length of @str in bytes, or `-1` if @str is nul-terminated |
| * |
| * Converts all upper case ASCII letters to lower case ASCII letters, with |
| * semantics that exactly match [func@GLib.ascii_tolower]. |
| * |
| * Returns: a newly-allocated string, with all the upper case characters in |
| * @str converted to lower case. (Note that this is unlike the old |
| * [func@GLib.strdown], which modified the string in place.) |
| */ |
| gchar* |
| g_ascii_strdown (const gchar *str, |
| gssize len) |
| { |
| gchar *result, *s; |
| |
| g_return_val_if_fail (str != NULL, NULL); |
| |
| if (len < 0) |
| result = g_strdup (str); |
| else |
| result = g_strndup (str, (gsize) len); |
| |
| for (s = result; *s; s++) |
| *s = g_ascii_tolower (*s); |
| |
| return result; |
| } |
| |
| /** |
| * g_ascii_strup: |
| * @str: a string |
| * @len: length of @str in bytes, or `-1` if @str is nul-terminated |
| * |
| * Converts all lower case ASCII letters to upper case ASCII letters, with |
| * semantics that exactly match [func@GLib.ascii_toupper]. |
| * |
| * Returns: a newly-allocated string, with all the lower case characters |
| * in @str converted to upper case. (Note that this is unlike the old |
| * [func@GLib.strup], which modified the string in place.) |
| */ |
| gchar* |
| g_ascii_strup (const gchar *str, |
| gssize len) |
| { |
| gchar *result, *s; |
| |
| g_return_val_if_fail (str != NULL, NULL); |
| |
| if (len < 0) |
| result = g_strdup (str); |
| else |
| result = g_strndup (str, (gsize) len); |
| |
| for (s = result; *s; s++) |
| *s = g_ascii_toupper (*s); |
| |
| return result; |
| } |
| |
| /** |
| * g_str_is_ascii: |
| * @str: a string |
| * |
| * Determines if a string is pure ASCII. A string is pure ASCII if it |
| * contains no bytes with the high bit set. |
| * |
| * Returns: true if @str is ASCII |
| * |
| * Since: 2.40 |
| */ |
| gboolean |
| g_str_is_ascii (const gchar *str) |
| { |
| gsize i; |
| |
| for (i = 0; str[i]; i++) |
| if (str[i] & 0x80) |
| return FALSE; |
| |
| return TRUE; |
| } |
| |
| /** |
| * g_strdown: |
| * @string: the string to convert |
| * |
| * Converts a string to lower case. |
| * |
| * Returns: the string |
| * |
| * Deprecated: 2.2: This function is totally broken for the reasons discussed |
| * in the [func@GLib.strncasecmp] docs — use [func@GLib.ascii_strdown] or |
| * [func@GLib.utf8_strdown] instead. |
| **/ |
| gchar* |
| g_strdown (gchar *string) |
| { |
| guchar *s; |
| |
| g_return_val_if_fail (string != NULL, NULL); |
| |
| s = (guchar *) string; |
| |
| while (*s) |
| { |
| if (isupper (*s)) |
| *s = tolower (*s); |
| s++; |
| } |
| |
| return (gchar *) string; |
| } |
| |
| /** |
| * g_strup: |
| * @string: the string to convert |
| * |
| * Converts a string to upper case. |
| * |
| * Returns: the string |
| * |
| * Deprecated: 2.2: This function is totally broken for the reasons discussed |
| * in the [func@GLib.strncasecmp] docs — use [func@GLib.ascii_strup] or |
| * [func@GLib.utf8_strup] instead. |
| */ |
| gchar* |
| g_strup (gchar *string) |
| { |
| guchar *s; |
| |
| g_return_val_if_fail (string != NULL, NULL); |
| |
| s = (guchar *) string; |
| |
| while (*s) |
| { |
| if (islower (*s)) |
| *s = toupper (*s); |
| s++; |
| } |
| |
| return (gchar *) string; |
| } |
| |
| /** |
| * g_strreverse: |
| * @string: the string to reverse |
| * |
| * Reverses all of the bytes in a string. For example, |
| * `g_strreverse ("abcdef")` will result in "fedcba". |
| * |
| * Note that `g_strreverse()` doesn't work on UTF-8 strings |
| * containing multibyte characters. For that purpose, use |
| * [func@GLib.utf8_strreverse]. |
| * |
| * Returns: the @string, reversed in place |
| */ |
| gchar* |
| g_strreverse (gchar *string) |
| { |
| g_return_val_if_fail (string != NULL, NULL); |
| |
| if (*string) |
| { |
| gchar *h, *t; |
| |
| h = string; |
| t = string + strlen (string) - 1; |
| |
| while (h < t) |
| { |
| gchar c; |
| |
| c = *h; |
| *h = *t; |
| h++; |
| *t = c; |
| t--; |
| } |
| } |
| |
| return string; |
| } |
| |
| /** |
| * g_ascii_tolower: |
| * @c: any character |
| * |
| * Convert a character to ASCII lower case. If the character is not an |
| * ASCII upper case letter, it is returned unchanged. |
| * |
| * Unlike the standard C library `tolower()` function, this only |
| * recognizes standard ASCII letters and ignores the locale, returning |
| * all non-ASCII characters unchanged, even if they are lower case |
| * letters in a particular character set. Also unlike the standard |
| * library function, this takes and returns a char, not an int, so |
| * don't call it on `EOF` but no need to worry about casting to `guchar` |
| * before passing a possibly non-ASCII character in. |
| * |
| * Returns: the result of the conversion |
| */ |
| gchar |
| g_ascii_tolower (gchar c) |
| { |
| return g_ascii_isupper (c) ? c - 'A' + 'a' : c; |
| } |
| |
| /** |
| * g_ascii_toupper: |
| * @c: any character |
| * |
| * Convert a character to ASCII upper case. If the character is not an |
| * ASCII lower case letter, it is returned unchanged. |
| * |
| * Unlike the standard C library `toupper()` function, this only |
| * recognizes standard ASCII letters and ignores the locale, returning |
| * all non-ASCII characters unchanged, even if they are upper case |
| * letters in a particular character set. Also unlike the standard |
| * library function, this takes and returns a char, not an int, so |
| * don't call it on `EOF` but no need to worry about casting to `guchar` |
| * before passing a possibly non-ASCII character in. |
| * |
| * Returns: the result of the conversion |
| */ |
| gchar |
| g_ascii_toupper (gchar c) |
| { |
| return g_ascii_islower (c) ? c - 'a' + 'A' : c; |
| } |
| |
| /** |
| * g_ascii_digit_value: |
| * @c: an ASCII character |
| * |
| * Determines the numeric value of a character as a decimal digit. If the |
| * character is not a decimal digit according to [func@GLib.ascii_isdigit], |
| * `-1` is returned. |
| * |
| * Differs from [func@GLib.unichar_digit_value] because it takes a char, so |
| * there's no worry about sign extension if characters are signed. |
| * |
| * Returns: the numerical value of @c if it is a decimal digit, `-1` otherwise |
| */ |
| int |
| g_ascii_digit_value (gchar c) |
| { |
| if (g_ascii_isdigit (c)) |
| return c - '0'; |
| return -1; |
| } |
| |
| /** |
| * g_ascii_xdigit_value: |
| * @c: an ASCII character |
| * |
| * Determines the numeric value of a character as a hexadecimal digit. If the |
| * character is not a hex digit according to [func@GLib.ascii_isxdigit], |
| * `-1` is returned. |
| * |
| * Differs from [func@GLib.unichar_xdigit_value] because it takes a char, so |
| * there's no worry about sign extension if characters are signed. |
| * |
| * Differs from [func@GLib.unichar_xdigit_value] because it takes a char, so |
| * there's no worry about sign extension if characters are signed. |
| * |
| * Returns: the numerical value of @c if it is a hex digit, `-1` otherwise |
| */ |
| int |
| g_ascii_xdigit_value (gchar c) |
| { |
| if (c >= 'A' && c <= 'F') |
| return c - 'A' + 10; |
| if (c >= 'a' && c <= 'f') |
| return c - 'a' + 10; |
| return g_ascii_digit_value (c); |
| } |
| |
| /** |
| * g_ascii_strcasecmp: |
| * @s1: string to compare with @s2 |
| * @s2: string to compare with @s1 |
| * |
| * Compare two strings, ignoring the case of ASCII characters. |
| * |
| * Unlike the BSD `strcasecmp()` function, this only recognizes standard |
| * ASCII letters and ignores the locale, treating all non-ASCII |
| * bytes as if they are not letters. |
| * |
| * This function should be used only on strings that are known to be |
| * in encodings where the bytes corresponding to ASCII letters always |
| * represent themselves. This includes UTF-8 and the ISO-8859-* |
| * charsets, but not for instance double-byte encodings like the |
| * Windows Codepage 932, where the trailing bytes of double-byte |
| * characters include all ASCII letters. If you compare two CP932 |
| * strings using this function, you will get false matches. |
| * |
| * Both @s1 and @s2 must be non-`NULL`. |
| * |
| * Returns: 0 if the strings match, a negative value if @s1 < @s2, |
| * or a positive value if @s1 > @s2 |
| */ |
| gint |
| g_ascii_strcasecmp (const gchar *s1, |
| const gchar *s2) |
| { |
| gint c1, c2; |
| |
| g_return_val_if_fail (s1 != NULL, 0); |
| g_return_val_if_fail (s2 != NULL, 0); |
| |
| while (*s1 && *s2) |
| { |
| c1 = (gint)(guchar) TOLOWER (*s1); |
| c2 = (gint)(guchar) TOLOWER (*s2); |
| if (c1 != c2) |
| return (c1 - c2); |
| s1++; s2++; |
| } |
| |
| return (((gint)(guchar) *s1) - ((gint)(guchar) *s2)); |
| } |
| |
| /** |
| * g_ascii_strncasecmp: |
| * @s1: string to compare with @s2 |
| * @s2: string to compare with @s1 |
| * @n: number of characters to compare |
| * |
| * Compare @s1 and @s2, ignoring the case of ASCII characters and any |
| * characters after the first @n in each string. If either string is |
| * less than @n bytes long, comparison will stop at the first nul byte |
| * encountered. |
| * |
| * Unlike the BSD `strncasecmp()` function, this only recognizes standard |
| * ASCII letters and ignores the locale, treating all non-ASCII |
| * characters as if they are not letters. |
| * |
| * The same warning as in [func@GLib.ascii_strcasecmp] applies: Use this |
| * function only on strings known to be in encodings where bytes |
| * corresponding to ASCII letters always represent themselves. |
| * |
| * Returns: 0 if the strings match, a negative value if @s1 < @s2, |
| * or a positive value if @s1 > @s2 |
| */ |
| gint |
| g_ascii_strncasecmp (const gchar *s1, |
| const gchar *s2, |
| gsize n) |
| { |
| gint c1, c2; |
| |
| g_return_val_if_fail (s1 != NULL, 0); |
| g_return_val_if_fail (s2 != NULL, 0); |
| |
| while (n && *s1 && *s2) |
| { |
| n -= 1; |
| c1 = (gint)(guchar) TOLOWER (*s1); |
| c2 = (gint)(guchar) TOLOWER (*s2); |
| if (c1 != c2) |
| return (c1 - c2); |
| s1++; s2++; |
| } |
| |
| if (n) |
| return (((gint) (guchar) *s1) - ((gint) (guchar) *s2)); |
| else |
| return 0; |
| } |
| |
| /** |
| * g_strcasecmp: |
| * @s1: string to compare with @s2 |
| * @s2: string to compare with @s1 |
| * |
| * A case-insensitive string comparison, corresponding to the standard |
| * `strcasecmp()` function on platforms which support it. |
| * |
| * Returns: 0 if the strings match, a negative value if @s1 < @s2, |
| * or a positive value if @s1 > @s2 |
| * |
| * Deprecated: 2.2: See [func@GLib.strncasecmp] for a discussion of why this |
| * function is deprecated and how to replace it. |
| */ |
| gint |
| g_strcasecmp (const gchar *s1, |
| const gchar *s2) |
| { |
| #ifdef HAVE_STRCASECMP |
| g_return_val_if_fail (s1 != NULL, 0); |
| g_return_val_if_fail (s2 != NULL, 0); |
| |
| return strcasecmp (s1, s2); |
| #else |
| gint c1, c2; |
| |
| g_return_val_if_fail (s1 != NULL, 0); |
| g_return_val_if_fail (s2 != NULL, 0); |
| |
| while (*s1 && *s2) |
| { |
| /* According to A. Cox, some platforms have islower's that |
| * don't work right on non-uppercase |
| */ |
| c1 = isupper ((guchar)*s1) ? tolower ((guchar)*s1) : *s1; |
| c2 = isupper ((guchar)*s2) ? tolower ((guchar)*s2) : *s2; |
| if (c1 != c2) |
| return (c1 - c2); |
| s1++; s2++; |
| } |
| |
| return (((gint)(guchar) *s1) - ((gint)(guchar) *s2)); |
| #endif |
| } |
| |
| /** |
| * g_strncasecmp: |
| * @s1: string to compare with @s2 |
| * @s2: string to compare with @s1 |
| * @n: the maximum number of characters to compare |
| * |
| * A case-insensitive string comparison, corresponding to the standard |
| * `strncasecmp()` function on platforms which support it. It is similar |
| * to [func@GLib.strcasecmp] except it only compares the first @n characters of |
| * the strings. |
| * |
| * Returns: 0 if the strings match, a negative value if @s1 < @s2, |
| * or a positive value if @s1 > @s2 |
| * |
| * Deprecated: 2.2: The problem with `g_strncasecmp()` is that it does |
| * the comparison by calling `toupper()`/`tolower()`. These functions |
| * are locale-specific and operate on single bytes. However, it is |
| * impossible to handle things correctly from an internationalization |
| * standpoint by operating on bytes, since characters may be multibyte. |
| * Thus `g_strncasecmp()` is broken if your string is guaranteed to be |
| * ASCII, since it is locale-sensitive, and it's broken if your string |
| * is localized, since it doesn't work on many encodings at all, |
| * including UTF-8, EUC-JP, etc. |
| * |
| * There are therefore two replacement techniques: [func@GLib.ascii_strncasecmp], |
| * which only works on ASCII and is not locale-sensitive, and |
| * [func@GLib.utf8_casefold] followed by `strcmp()` on the resulting strings, |
| * which is good for case-insensitive sorting of UTF-8. |
| */ |
| gint |
| g_strncasecmp (const gchar *s1, |
| const gchar *s2, |
| guint n) |
| { |
| #ifdef HAVE_STRNCASECMP |
| return strncasecmp (s1, s2, n); |
| #else |
| gint c1, c2; |
| |
| g_return_val_if_fail (s1 != NULL, 0); |
| g_return_val_if_fail (s2 != NULL, 0); |
| |
| while (n && *s1 && *s2) |
| { |
| n -= 1; |
| /* According to A. Cox, some platforms have islower's that |
| * don't work right on non-uppercase |
| */ |
| c1 = isupper ((guchar)*s1) ? tolower ((guchar)*s1) : *s1; |
| c2 = isupper ((guchar)*s2) ? tolower ((guchar)*s2) : *s2; |
| if (c1 != c2) |
| return (c1 - c2); |
| s1++; s2++; |
| } |
| |
| if (n) |
| return (((gint) (guchar) *s1) - ((gint) (guchar) *s2)); |
| else |
| return 0; |
| #endif |
| } |
| |
| /** |
| * g_strdelimit: |
| * @string: the string to convert |
| * @delimiters: (nullable): a string containing the current delimiters, or |
| * `NULL` to use the standard delimiters defined in [const@GLib.STR_DELIMITERS] |
| * @new_delimiter: the new delimiter character |
| * |
| * Converts any delimiter characters in @string to @new_delimiter. |
| * |
| * Any characters in @string which are found in @delimiters are |
| * changed to the @new_delimiter character. Modifies @string in place, |
| * and returns @string itself, not a copy. |
| * |
| * The return value is to allow nesting such as: |
| * ```C |
| * g_ascii_strup (g_strdelimit (str, "abc", '?')) |
| * ``` |
| * |
| * In order to modify a copy, you may use [func@GLib.strdup]: |
| * ```C |
| * reformatted = g_strdelimit (g_strdup (const_str), "abc", '?'); |
| * … |
| * g_free (reformatted); |
| * ``` |
| * |
| * Returns: the modified @string |
| */ |
| gchar * |
| g_strdelimit (gchar *string, |
| const gchar *delimiters, |
| gchar new_delim) |
| { |
| gchar *c; |
| |
| g_return_val_if_fail (string != NULL, NULL); |
| |
| if (!delimiters) |
| delimiters = G_STR_DELIMITERS; |
| |
| for (c = string; *c; c++) |
| { |
| if (strchr (delimiters, *c)) |
| *c = new_delim; |
| } |
| |
| return string; |
| } |
| |
| /** |
| * g_strcanon: |
| * @string: a nul-terminated array of bytes |
| * @valid_chars: bytes permitted in @string |
| * @substitutor: replacement character for disallowed bytes |
| * |
| * For each character in @string, if the character is not in @valid_chars, |
| * replaces the character with @substitutor. |
| * |
| * Modifies @string in place, and return @string itself, not a copy. The |
| * return value is to allow nesting such as: |
| * ```C |
| * g_ascii_strup (g_strcanon (str, "abc", '?')) |
| * ``` |
| * |
| * In order to modify a copy, you may use [func@GLib.strdup]: |
| * ```C |
| * reformatted = g_strcanon (g_strdup (const_str), "abc", '?'); |
| * … |
| * g_free (reformatted); |
| * ``` |
| * |
| * Returns: the modified @string |
| */ |
| gchar * |
| g_strcanon (gchar *string, |
| const gchar *valid_chars, |
| gchar substitutor) |
| { |
| gchar *c; |
| |
| g_return_val_if_fail (string != NULL, NULL); |
| g_return_val_if_fail (valid_chars != NULL, NULL); |
| |
| for (c = string; *c; c++) |
| { |
| if (!strchr (valid_chars, *c)) |
| *c = substitutor; |
| } |
| |
| return string; |
| } |
| |
| /** |
| * g_strcompress: |
| * @source: a string to compress |
| * |
| * Replaces all escaped characters with their one byte equivalent. |
| * |
| * This function does the reverse conversion of [func@GLib.strescape]. |
| * |
| * Returns: a newly-allocated copy of @source with all escaped |
| * character compressed |
| */ |
| gchar * |
| g_strcompress (const gchar *source) |
| { |
| const gchar *p = source, *octal; |
| gchar *dest; |
| gchar *q; |
| |
| g_return_val_if_fail (source != NULL, NULL); |
| |
| dest = g_malloc (strlen (source) + 1); |
| q = dest; |
| |
| while (*p) |
| { |
| if (*p == '\\') |
| { |
| p++; |
| switch (*p) |
| { |
| case '\0': |
| g_warning ("g_strcompress: trailing \\"); |
| goto out; |
| case '0': case '1': case '2': case '3': case '4': |
| case '5': case '6': case '7': |
| *q = 0; |
| octal = p; |
| while ((p < octal + 3) && (*p >= '0') && (*p <= '7')) |
| { |
| *q = (*q * 8) + (*p - '0'); |
| p++; |
| } |
| q++; |
| p--; |
| break; |
| case 'b': |
| *q++ = '\b'; |
| break; |
| case 'f': |
| *q++ = '\f'; |
| break; |
| case 'n': |
| *q++ = '\n'; |
| break; |
| case 'r': |
| *q++ = '\r'; |
| break; |
| case 't': |
| *q++ = '\t'; |
| break; |
| case 'v': |
| *q++ = '\v'; |
| break; |
| default: /* Also handles \" and \\ */ |
| *q++ = *p; |
| break; |
| } |
| } |
| else |
| *q++ = *p; |
| p++; |
| } |
| out: |
| *q = 0; |
| |
| return dest; |
| } |
| |
| /** |
| * g_strescape: |
| * @source: a string to escape |
| * @exceptions: (nullable): a string of characters not to escape in @source |
| * |
| * Escapes the special characters '\b', '\f', '\n', '\r', '\t', '\v', '\' |
| * and '"' in the string @source by inserting a '\' before |
| * them. Additionally all characters in the range 0x01-0x1F (everything |
| * below SPACE) and in the range 0x7F-0xFF (all non-ASCII chars) are |
| * replaced with a '\' followed by their octal representation. |
| * Characters supplied in @exceptions are not escaped. |
| * |
| * [func@GLib.strcompress] does the reverse conversion. |
| * |
| * Returns: a newly-allocated copy of @source with special characters escaped |
| */ |
| gchar * |
| g_strescape (const gchar *source, |
| const gchar *exceptions) |
| { |
| const guchar *p; |
| gchar *dest; |
| gchar *q; |
| guchar excmap[256]; |
| |
| g_return_val_if_fail (source != NULL, NULL); |
| |
| p = (guchar *) source; |
| /* Each source byte needs maximally four destination chars (\777) */ |
| q = dest = g_malloc (strlen (source) * 4 + 1); |
| |
| memset (excmap, 0, 256); |
| if (exceptions) |
| { |
| guchar *e = (guchar *) exceptions; |
| |
| while (*e) |
| { |
| excmap[*e] = 1; |
| e++; |
| } |
| } |
| |
| while (*p) |
| { |
| if (excmap[*p]) |
| *q++ = *p; |
| else |
| { |
| switch (*p) |
| { |
| case '\b': |
| *q++ = '\\'; |
| *q++ = 'b'; |
| break; |
| case '\f': |
| *q++ = '\\'; |
| *q++ = 'f'; |
| break; |
| case '\n': |
| *q++ = '\\'; |
| *q++ = 'n'; |
| break; |
| case '\r': |
| *q++ = '\\'; |
| *q++ = 'r'; |
| break; |
| case '\t': |
| *q++ = '\\'; |
| *q++ = 't'; |
| break; |
| case '\v': |
| *q++ = '\\'; |
| *q++ = 'v'; |
| break; |
| case '\\': |
| *q++ = '\\'; |
| *q++ = '\\'; |
| break; |
| case '"': |
| *q++ = '\\'; |
| *q++ = '"'; |
| break; |
| default: |
| if ((*p < ' ') || (*p >= 0177)) |
| { |
| *q++ = '\\'; |
| *q++ = '0' + (((*p) >> 6) & 07); |
| *q++ = '0' + (((*p) >> 3) & 07); |
| *q++ = '0' + ((*p) & 07); |
| } |
| else |
| *q++ = *p; |
| break; |
| } |
| } |
| p++; |
| } |
| *q = 0; |
| return dest; |
| } |
| |
| /** |
| * g_strchug: |
| * @string: a string to remove the leading whitespace from |
| * |
| * Removes leading whitespace from a string, by moving the rest |
| * of the characters forward. |
| * |
| * This function doesn't allocate or reallocate any memory; |
| * it modifies @string in place. Therefore, it cannot be used on |
| * statically allocated strings. |
| * |
| * The pointer to @string is returned to allow the nesting of functions. |
| * |
| * Also see [func@GLib.strchomp] and [func@GLib.strstrip]. |
| * |
| * Returns: the modified @string |
| */ |
| gchar * |
| g_strchug (gchar *string) |
| { |
| guchar *start; |
| |
| g_return_val_if_fail (string != NULL, NULL); |
| |
| for (start = (guchar*) string; *start && g_ascii_isspace (*start); start++) |
| ; |
| |
| memmove (string, start, strlen ((gchar *) start) + 1); |
| |
| return string; |
| } |
| |
| /** |
| * g_strchomp: |
| * @string: a string to remove the trailing whitespace from |
| * |
| * Removes trailing whitespace from a string. |
| * |
| * This function doesn't allocate or reallocate any memory; |
| * it modifies @string in place. Therefore, it cannot be used |
| * on statically allocated strings. |
| * |
| * The pointer to @string is returned to allow the nesting of functions. |
| * |
| * Also see [func@GLib.strchug] and [func@GLib.strstrip]. |
| * |
| * Returns: the modified @string |
| */ |
| gchar * |
| g_strchomp (gchar *string) |
| { |
| gsize len; |
| |
| g_return_val_if_fail (string != NULL, NULL); |
| |
| len = strlen (string); |
| while (len--) |
| { |
| if (g_ascii_isspace ((guchar) string[len])) |
| string[len] = '\0'; |
| else |
| break; |
| } |
| |
| return string; |
| } |
| |
| /** |
| * g_strsplit: |
| * @string: a string to split |
| * @delimiter: a string which specifies the places at which to split |
| * the string. The delimiter is not included in any of the resulting |
| * strings, unless @max_tokens is reached. |
| * @max_tokens: the maximum number of pieces to split @string into |
| * If this is less than 1, the string is split completely |
| * |
| * Splits a string into a maximum of @max_tokens pieces, using the given |
| * @delimiter. If @max_tokens is reached, the remainder of @string is |
| * appended to the last token. |
| * |
| * As an example, the result of `g_strsplit (":a:bc::d:", ":", -1)` is an array |
| * containing the six strings "", "a", "bc", "", "d" and "". |
| * |
| * As a special case, the result of splitting the empty string "" is an empty |
| * array, not an array containing a single string. The reason for this |
| * special case is that being able to represent an empty array is typically |
| * more useful than consistent handling of empty elements. If you do need |
| * to represent empty elements, you'll need to check for the empty string |
| * before calling `g_strsplit()`. |
| * |
| * Returns: (transfer full): a newly-allocated array of strings, freed with |
| * [func@GLib.strfreev] |
| */ |
| gchar** |
| g_strsplit (const gchar *string, |
| const gchar *delimiter, |
| gint max_tokens) |
| { |
| char *s; |
| const gchar *remainder; |
| GPtrArray *string_list; |
| |
| g_return_val_if_fail (string != NULL, NULL); |
| g_return_val_if_fail (delimiter != NULL, NULL); |
| g_return_val_if_fail (delimiter[0] != '\0', NULL); |
| |
| if (max_tokens < 1) |
| { |
| max_tokens = G_MAXINT; |
| string_list = g_ptr_array_new (); |
| } |
| else |
| { |
| string_list = g_ptr_array_new_full (max_tokens + 1, NULL); |
| } |
| |
| remainder = string; |
| s = strstr (remainder, delimiter); |
| if (s) |
| { |
| gsize delimiter_len = strlen (delimiter); |
| |
| while (--max_tokens && s) |
| { |
| gsize len; |
| |
| len = s - remainder; |
| g_ptr_array_add (string_list, g_strndup (remainder, len)); |
| remainder = s + delimiter_len; |
| s = strstr (remainder, delimiter); |
| } |
| } |
| if (*string) |
| g_ptr_array_add (string_list, g_strdup (remainder)); |
| |
| g_ptr_array_add (string_list, NULL); |
| |
| return (char **) g_ptr_array_free (string_list, FALSE); |
| } |
| |
| /** |
| * g_strsplit_set: |
| * @string: a string to split |
| * @delimiters: a string containing characters that are used to split the |
| * string. Can be empty, which will result in no string splitting |
| * @max_tokens: the maximum number of tokens to split @string into. |
| * If this is less than 1, the string is split completely |
| * |
| * Splits @string into a number of tokens not containing any of the characters |
| * in @delimiters. A token is the (possibly empty) longest string that does not |
| * contain any of the characters in @delimiters. If @max_tokens is reached, the |
| * remainder is appended to the last token. |
| * |
| * For example, the result of g_strsplit_set ("abc:def/ghi", ":/", -1) is an |
| * array containing the three strings "abc", "def", and "ghi". |
| * |
| * The result of g_strsplit_set (":def/ghi:", ":/", -1) is an array containing |
| * the four strings "", "def", "ghi", and "". |
| * |
| * As a special case, the result of splitting the empty string "" is an empty |
| * array, not an array containing a single string. The reason for this |
| * special case is that being able to represent an empty array is typically |
| * more useful than consistent handling of empty elements. If you do need |
| * to represent empty elements, you'll need to check for the empty string |
| * before calling `g_strsplit_set()`. |
| * |
| * Note that this function works on bytes not characters, so it can't be used |
| * to delimit UTF-8 strings for anything but ASCII characters. |
| * |
| * Returns: (transfer full): a newly-allocated array of strings. Use |
| * [func@GLib.strfreev] to free it. |
| * |
| * Since: 2.4 |
| **/ |
| gchar ** |
| g_strsplit_set (const gchar *string, |
| const gchar *delimiters, |
| gint max_tokens) |
| { |
| guint8 delim_table[256]; /* 1 = index is a separator; 0 otherwise */ |
| GSList *tokens, *list; |
| gint n_tokens; |
| const gchar *s; |
| const gchar *current; |
| gchar *token; |
| gchar **result; |
| |
| g_return_val_if_fail (string != NULL, NULL); |
| g_return_val_if_fail (delimiters != NULL, NULL); |
| |
| if (max_tokens < 1) |
| max_tokens = G_MAXINT; |
| |
| if (*string == '\0') |
| { |
| result = g_new (char *, 1); |
| result[0] = NULL; |
| return result; |
| } |
| |
| /* Check if each character in @string is a separator, by indexing by the |
| * character value into the @delim_table, which has value 1 stored at an index |
| * if that index is a separator. */ |
| memset (delim_table, FALSE, sizeof (delim_table)); |
| for (s = delimiters; *s != '\0'; ++s) |
| delim_table[*(guchar *)s] = TRUE; |
| |
| tokens = NULL; |
| n_tokens = 0; |
| |
| s = current = string; |
| while (*s != '\0') |
| { |
| if (delim_table[*(guchar *)s] && n_tokens + 1 < max_tokens) |
| { |
| token = g_strndup (current, s - current); |
| tokens = g_slist_prepend (tokens, token); |
| ++n_tokens; |
| |
| current = s + 1; |
| } |
| |
| ++s; |
| } |
| |
| token = g_strndup (current, s - current); |
| tokens = g_slist_prepend (tokens, token); |
| ++n_tokens; |
| |
| result = g_new (gchar *, n_tokens + 1); |
| |
| result[n_tokens] = NULL; |
| for (list = tokens; list != NULL; list = list->next) |
| result[--n_tokens] = list->data; |
| |
| g_slist_free (tokens); |
| |
| return result; |
| } |
| |
| /** |
| * GStrv: |
| * |
| * A typedef alias for gchar**. This is mostly useful when used together with |
| * `g_auto()`. |
| */ |
| |
| /** |
| * g_strfreev: |
| * @str_array: (array zero-terminated=1) (nullable) (transfer full): an |
| * array of strings to free |
| * |
| * Frees an array of strings, as well as each string it contains. |
| * |
| * If @str_array is `NULL`, this function simply returns. |
| */ |
| void |
| g_strfreev (gchar **str_array) |
| { |
| if (str_array) |
| { |
| gsize i; |
| |
| for (i = 0; str_array[i] != NULL; i++) |
| g_free (str_array[i]); |
| |
| g_free (str_array); |
| } |
| } |
| |
| /** |
| * g_strdupv: |
| * @str_array: (array zero-terminated=1) (nullable): an array of strings to copy |
| * |
| * Copies an array of strings. The copy is a deep copy; each string is also |
| * copied. |
| * |
| * If called on a `NULL` value, `g_strdupv()` simply returns `NULL`. |
| * |
| * Returns: (array zero-terminated=1) (nullable) (transfer full): a |
| * newly-allocated array of strings. Use [func@GLib.strfreev] to free it. |
| */ |
| gchar** |
| g_strdupv (gchar **str_array) |
| { |
| if (str_array) |
| { |
| gsize i; |
| gchar **retval; |
| |
| i = 0; |
| while (str_array[i]) |
| ++i; |
| |
| retval = g_new (gchar*, i + 1); |
| |
| i = 0; |
| while (str_array[i]) |
| { |
| retval[i] = g_strdup (str_array[i]); |
| ++i; |
| } |
| retval[i] = NULL; |
| |
| return retval; |
| } |
| else |
| return NULL; |
| } |
| |
| /** |
| * g_strjoinv: |
| * @separator: (nullable): a string to insert between each of the strings |
| * @str_array: (array zero-terminated=1): an array of strings to join |
| * |
| * Joins an array of strings together to form one long string, with the |
| * optional @separator inserted between each of them. |
| * |
| * If @str_array has no items, the return value will be an |
| * empty string. If @str_array contains a single item, @separator will not |
| * appear in the resulting string. |
| * |
| * Returns: a newly-allocated string containing all of the strings joined |
| * together, with @separator between them |
| */ |
| gchar* |
| g_strjoinv (const gchar *separator, |
| gchar **str_array) |
| { |
| gchar *string; |
| gchar *ptr; |
| |
| g_return_val_if_fail (str_array != NULL, NULL); |
| |
| if (separator == NULL) |
| separator = ""; |
| |
| if (*str_array) |
| { |
| gsize i; |
| gsize len; |
| gsize separator_len; |
| |
| separator_len = strlen (separator); |
| /* First part, getting length */ |
| len = 1 + strlen (str_array[0]); |
| for (i = 1; str_array[i] != NULL; i++) |
| len += strlen (str_array[i]); |
| len += separator_len * (i - 1); |
| |
| /* Second part, building string */ |
| string = g_new (gchar, len); |
| ptr = g_stpcpy (string, *str_array); |
| for (i = 1; str_array[i] != NULL; i++) |
| { |
| ptr = g_stpcpy (ptr, separator); |
| ptr = g_stpcpy (ptr, str_array[i]); |
| } |
| } |
| else |
| string = g_strdup (""); |
| |
| return string; |
| } |
| |
| /** |
| * g_strjoin: |
| * @separator: (nullable): a string to insert between each of the strings |
| * @...: a `NULL`-terminated list of strings to join |
| * |
| * Joins a number of strings together to form one long string, with the |
| * optional @separator inserted between each of them. |
| * |
| * Returns: a newly-allocated string containing all of the strings joined |
| * together, with @separator between them |
| */ |
| gchar* |
| g_strjoin (const gchar *separator, |
| ...) |
| { |
| gchar *string, *s; |
| va_list args; |
| gsize len; |
| gsize separator_len; |
| gchar *ptr; |
| |
| if (separator == NULL) |
| separator = ""; |
| |
| separator_len = strlen (separator); |
| |
| va_start (args, separator); |
| |
| s = va_arg (args, gchar*); |
| |
| if (s) |
| { |
| /* First part, getting length */ |
| len = 1 + strlen (s); |
| |
| s = va_arg (args, gchar*); |
| while (s) |
| { |
| len += separator_len + strlen (s); |
| s = va_arg (args, gchar*); |
| } |
| va_end (args); |
| |
| /* Second part, building string */ |
| string = g_new (gchar, len); |
| |
| va_start (args, separator); |
| |
| s = va_arg (args, gchar*); |
| ptr = g_stpcpy (string, s); |
| |
| s = va_arg (args, gchar*); |
| while (s) |
| { |
| ptr = g_stpcpy (ptr, separator); |
| ptr = g_stpcpy (ptr, s); |
| s = va_arg (args, gchar*); |
| } |
| } |
| else |
| string = g_strdup (""); |
| |
| va_end (args); |
| |
| return string; |
| } |
| |
| |
| /** |
| * g_strstr_len: |
| * @haystack: a string to search in |
| * @haystack_len: the maximum length of @haystack in bytes, or `-1` to |
| * search it entirely |
| * @needle: the string to search for |
| * |
| * Searches the string @haystack for the first occurrence |
| * of the string @needle, limiting the length of the search |
| * to @haystack_len or a nul terminator byte (whichever is reached first). |
| * |
| * A length of `-1` can be used to mean “search the entire string”, like |
| * `strstr()`. |
| * |
| * Returns: a pointer to the found occurrence, or `NULL` if not found |
| */ |
| gchar * |
| g_strstr_len (const gchar *haystack, |
| gssize haystack_len, |
| const gchar *needle) |
| { |
| g_return_val_if_fail (haystack != NULL, NULL); |
| g_return_val_if_fail (needle != NULL, NULL); |
| |
| if (haystack_len < 0) |
| return strstr (haystack, needle); |
| else |
| { |
| const gchar *p = haystack; |
| gsize needle_len = strlen (needle); |
| gsize haystack_len_unsigned = haystack_len; |
| const gchar *end; |
| gsize i; |
| |
| if (needle_len == 0) |
| return (gchar *)haystack; |
| |
| if (haystack_len_unsigned < needle_len) |
| return NULL; |
| |
| end = haystack + haystack_len - needle_len; |
| |
| while (p <= end && *p) |
| { |
| for (i = 0; i < needle_len; i++) |
| if (p[i] != needle[i]) |
| goto next; |
| |
| return (gchar *)p; |
| |
| next: |
| p++; |
| } |
| |
| return NULL; |
| } |
| } |
| |
| /** |
| * g_strrstr: |
| * @haystack: a string to search in |
| * @needle: the string to search for |
| * |
| * Searches the string @haystack for the last occurrence |
| * of the string @needle. |
| * |
| * Returns: a pointer to the found occurrence, or `NULL` if not found |
| */ |
| gchar * |
| g_strrstr (const gchar *haystack, |
| const gchar *needle) |
| { |
| gsize i; |
| gsize needle_len; |
| gsize haystack_len; |
| const gchar *p; |
| |
| g_return_val_if_fail (haystack != NULL, NULL); |
| g_return_val_if_fail (needle != NULL, NULL); |
| |
| needle_len = strlen (needle); |
| haystack_len = strlen (haystack); |
| |
| if (needle_len == 0) |
| return (gchar *)haystack; |
| |
| if (haystack_len < needle_len) |
| return NULL; |
| |
| p = haystack + haystack_len - needle_len; |
| |
| while (p >= haystack) |
| { |
| for (i = 0; i < needle_len; i++) |
| if (p[i] != needle[i]) |
| goto next; |
| |
| return (gchar *)p; |
| |
| next: |
| p--; |
| } |
| |
| return NULL; |
| } |
| |
| /** |
| * g_strrstr_len: |
| * @haystack: a string to search in |
| * @haystack_len: the maximum length of @haystack in bytes. A length of `-1` |
| * can be used to mean "search the entire string", like [func@GLib.strrstr] |
| * @needle: the string to search for |
| * |
| * Searches the string @haystack for the last occurrence |
| * of the string @needle, limiting the length of the search |
| * to @haystack_len. |
| * |
| * Returns: a pointer to the found occurrence, or `NULL` if not found |
| */ |
| gchar * |
| g_strrstr_len (const gchar *haystack, |
| gssize haystack_len, |
| const gchar *needle) |
| { |
| g_return_val_if_fail (haystack != NULL, NULL); |
| g_return_val_if_fail (needle != NULL, NULL); |
| |
| if (haystack_len < 0) |
| return g_strrstr (haystack, needle); |
| else |
| { |
| gsize needle_len = strlen (needle); |
| const gchar *haystack_max = haystack + haystack_len; |
| const gchar *p = haystack; |
| gsize i; |
| |
| while (p < haystack_max && *p) |
| p++; |
| |
| if (p < haystack + needle_len) |
| return NULL; |
| |
| p -= needle_len; |
| |
| while (p >= haystack) |
| { |
| for (i = 0; i < needle_len; i++) |
| if (p[i] != needle[i]) |
| goto next; |
| |
| return (gchar *)p; |
| |
| next: |
| p--; |
| } |
| |
| return NULL; |
| } |
| } |
| |
| |
| /** |
| * g_str_has_suffix: |
| * @str: a string to look in |
| * @suffix: the suffix to look for |
| * |
| * Looks whether a string ends with @suffix. |
| * |
| * Returns: true if @str ends with @suffix, false otherwise |
| * |
| * Since: 2.2 |
| */ |
| gboolean (g_str_has_suffix) (const gchar *str, |
| const gchar *suffix) |
| { |
| gsize str_len; |
| gsize suffix_len; |
| |
| g_return_val_if_fail (str != NULL, FALSE); |
| g_return_val_if_fail (suffix != NULL, FALSE); |
| |
| str_len = strlen (str); |
| suffix_len = strlen (suffix); |
| |
| if (str_len < suffix_len) |
| return FALSE; |
| |
| return strcmp (str + str_len - suffix_len, suffix) == 0; |
| } |
| |
| /** |
| * g_str_has_prefix: |
| * @str: a string to look in |
| * @prefix: the prefix to look for |
| * |
| * Looks whether the string @str begins with @prefix. |
| * |
| * Returns: true if @str begins with @prefix, false otherwise |
| * |
| * Since: 2.2 |
| */ |
| gboolean (g_str_has_prefix) (const gchar *str, |
| const gchar *prefix) |
| { |
| g_return_val_if_fail (str != NULL, FALSE); |
| g_return_val_if_fail (prefix != NULL, FALSE); |
| |
| return strncmp (str, prefix, strlen (prefix)) == 0; |
| } |
| |
| /** |
| * g_strv_length: |
| * @str_array: (array zero-terminated=1): an array of strings |
| * |
| * Returns the length of an array of strings. @str_array must not be `NULL`. |
| * |
| * Returns: length of @str_array |
| * |
| * Since: 2.6 |
| */ |
| guint |
| g_strv_length (gchar **str_array) |
| { |
| guint i = 0; |
| |
| g_return_val_if_fail (str_array != NULL, 0); |
| |
| while (str_array[i]) |
| ++i; |
| |
| return i; |
| } |
| |
| static void |
| index_add_folded (GPtrArray *array, |
| const gchar *start, |
| const gchar *end) |
| { |
| gchar *normal; |
| |
| normal = g_utf8_normalize (start, end - start, G_NORMALIZE_ALL_COMPOSE); |
| |
| /* TODO: Invent time machine. Converse with Mustafa Ataturk... */ |
| if (strstr (normal, "ı") || strstr (normal, "İ")) |
| { |
| gchar *s = normal; |
| GString *tmp; |
| |
| tmp = g_string_new (NULL); |
| |
| while (*s) |
| { |
| gchar *i, *I, *e; |
| |
| i = strstr (s, "ı"); |
| I = strstr (s, "İ"); |
| |
| if (!i && !I) |
| break; |
| else if (i && !I) |
| e = i; |
| else if (I && !i) |
| e = I; |
| else if (i < I) |
| e = i; |
| else |
| e = I; |
| |
| g_string_append_len (tmp, s, e - s); |
| g_string_append_c (tmp, 'i'); |
| s = g_utf8_next_char (e); |
| } |
| |
| g_string_append (tmp, s); |
| g_free (normal); |
| normal = g_string_free (tmp, FALSE); |
| } |
| |
| g_ptr_array_add (array, g_utf8_casefold (normal, -1)); |
| g_free (normal); |
| } |
| |
| static gchar ** |
| split_words (const gchar *value) |
| { |
| const gchar *start = NULL; |
| GPtrArray *result; |
| const gchar *s; |
| |
| result = g_ptr_array_new (); |
| |
| for (s = value; *s; s = g_utf8_next_char (s)) |
| { |
| gunichar c = g_utf8_get_char (s); |
| |
| if (start == NULL) |
| { |
| if (g_unichar_isalnum (c) || g_unichar_ismark (c)) |
| start = s; |
| } |
| else |
| { |
| if (!g_unichar_isalnum (c) && !g_unichar_ismark (c)) |
| { |
| index_add_folded (result, start, s); |
| start = NULL; |
| } |
| } |
| } |
| |
| if (start) |
| index_add_folded (result, start, s); |
| |
| g_ptr_array_add (result, NULL); |
| |
| return (gchar **) g_ptr_array_free (result, FALSE); |
| } |
| |
| /** |
| * g_str_tokenize_and_fold: |
| * @string: a string to tokenize |
| * @translit_locale: (nullable): the language code (like 'de' or |
| * 'en_GB') from which @string originates |
| * @ascii_alternates: (out) (optional) (transfer full) (array zero-terminated=1): |
| * a return location for ASCII alternates |
| * |
| * Tokenizes @string and performs folding on each token. |
| * |
| * A token is a non-empty sequence of alphanumeric characters in the |
| * source string, separated by non-alphanumeric characters. An |
| * "alphanumeric" character for this purpose is one that matches |
| * [func@GLib.unichar_isalnum] or [func@GLib.unichar_ismark]. |
| * |
| * Each token is then (Unicode) normalised and case-folded. If |
| * @ascii_alternates is non-`NULL` and some of the returned tokens |
| * contain non-ASCII characters, ASCII alternatives will be generated. |
| * |
| * The number of ASCII alternatives that are generated and the method |
| * for doing so is unspecified, but @translit_locale (if specified) may |
| * improve the transliteration if the language of the source string is |
| * known. |
| * |
| * Returns: (transfer full) (array zero-terminated=1): the folded tokens |
| * |
| * Since: 2.40 |
| **/ |
| gchar ** |
| g_str_tokenize_and_fold (const gchar *string, |
| const gchar *translit_locale, |
| gchar ***ascii_alternates) |
| { |
| gchar **result; |
| |
| g_return_val_if_fail (string != NULL, NULL); |
| |
| if (ascii_alternates && g_str_is_ascii (string)) |
| { |
| *ascii_alternates = g_new0 (gchar *, 0 + 1); |
| ascii_alternates = NULL; |
| } |
| |
| result = split_words (string); |
| |
| if (ascii_alternates) |
| { |
| gint i, j, n; |
| |
| n = g_strv_length (result); |
| *ascii_alternates = g_new (gchar *, n + 1); |
| j = 0; |
| |
| for (i = 0; i < n; i++) |
| { |
| if (!g_str_is_ascii (result[i])) |
| { |
| gchar *composed; |
| gchar *ascii; |
| gint k; |
| |
| composed = g_utf8_normalize (result[i], -1, G_NORMALIZE_ALL_COMPOSE); |
| |
| ascii = g_str_to_ascii (composed, translit_locale); |
| |
| /* Only accept strings that are now entirely alnums */ |
| for (k = 0; ascii[k]; k++) |
| if (!g_ascii_isalnum (ascii[k])) |
| break; |
| |
| if (ascii[k] == '\0') |
| /* Made it to the end... */ |
| (*ascii_alternates)[j++] = ascii; |
| else |
| g_free (ascii); |
| |
| g_free (composed); |
| } |
| } |
| |
| (*ascii_alternates)[j] = NULL; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * g_str_match_string: |
| * @search_term: the search term from the user |
| * @potential_hit: the text that may be a hit |
| * @accept_alternates: if true, ASCII alternates are accepted |
| * |
| * Checks if a search conducted for @search_term should match |
| * @potential_hit. |
| * |
| * This function calls [func@GLib.str_tokenize_and_fold] on both |
| * @search_term and @potential_hit. ASCII alternates are never taken |
| * for @search_term but will be taken for @potential_hit according to |
| * the value of @accept_alternates. |
| * |
| * A hit occurs when each folded token in @search_term is a prefix of a |
| * folded token from @potential_hit. |
| * |
| * Depending on how you're performing the search, it will typically be |
| * faster to call `g_str_tokenize_and_fold()` on each string in |
| * your corpus and build an index on the returned folded tokens, then |
| * call `g_str_tokenize_and_fold()` on the search term and |
| * perform lookups into that index. |
| * |
| * As some examples, searching for ‘fred’ would match the potential hit |
| * ‘Smith, Fred’ and also ‘Frédéric’. Searching for ‘Fréd’ would match |
| * ‘Frédéric’ but not ‘Frederic’ (due to the one-directional nature of |
| * accent matching). Searching ‘fo’ would match ‘Foo’ and ‘Bar Foo |
| * Baz’, but not ‘SFO’ (because no word has ‘fo’ as a prefix). |
| * |
| * Returns: true if @potential_hit is a hit |
| * |
| * Since: 2.40 |
| **/ |
| gboolean |
| g_str_match_string (const gchar *search_term, |
| const gchar *potential_hit, |
| gboolean accept_alternates) |
| { |
| gchar **alternates = NULL; |
| gchar **term_tokens; |
| gchar **hit_tokens; |
| gboolean matched; |
| gint i, j; |
| |
| g_return_val_if_fail (search_term != NULL, FALSE); |
| g_return_val_if_fail (potential_hit != NULL, FALSE); |
| |
| term_tokens = g_str_tokenize_and_fold (search_term, NULL, NULL); |
| hit_tokens = g_str_tokenize_and_fold (potential_hit, NULL, accept_alternates ? &alternates : NULL); |
| |
| matched = TRUE; |
| |
| for (i = 0; term_tokens[i]; i++) |
| { |
| for (j = 0; hit_tokens[j]; j++) |
| if (g_str_has_prefix (hit_tokens[j], term_tokens[i])) |
| goto one_matched; |
| |
| if (accept_alternates) |
| for (j = 0; alternates[j]; j++) |
| if (g_str_has_prefix (alternates[j], term_tokens[i])) |
| goto one_matched; |
| |
| matched = FALSE; |
| break; |
| |
| one_matched: |
| continue; |
| } |
| |
| g_strfreev (term_tokens); |
| g_strfreev (hit_tokens); |
| g_strfreev (alternates); |
| |
| return matched; |
| } |
| |
| /** |
| * g_strv_contains: |
| * @strv: (array zero-terminated=1): an array of strings to search in |
| * @str: the string to search for |
| * |
| * Checks if an array of strings contains the string @str according to |
| * [func@GLib.str_equal]. @strv must not be `NULL`. |
| * |
| * Returns: true if @str is an element of @strv |
| * |
| * Since: 2.44 |
| */ |
| gboolean |
| g_strv_contains (const gchar * const *strv, |
| const gchar *str) |
| { |
| g_return_val_if_fail (strv != NULL, FALSE); |
| g_return_val_if_fail (str != NULL, FALSE); |
| |
| for (; *strv != NULL; strv++) |
| { |
| if (g_str_equal (str, *strv)) |
| return TRUE; |
| } |
| |
| return FALSE; |
| } |
| |
| /** |
| * g_strv_equal: |
| * @strv1: (array zero-terminated=1): an array of strings to compare to @strv2 |
| * @strv2: (array zero-terminated=1): an array of strings to compare to @strv1 |
| * |
| * Checks if two arrays of strings contain exactly the same elements in |
| * exactly the same order. |
| * |
| * Elements are compared using [func@GLib.str_equal]. To match independently |
| * of order, sort the arrays first (using [func@GLib.qsort_with_data] |
| * or similar). |
| * |
| * Elements are compared using [func@GLib.str_equal]. To match independently |
| * of order, sort the arrays first (using [func@GLib.qsort_with_data] |
| * or similar). |
| * |
| * Two empty arrays are considered equal. Neither @strv1 nor @strv2 may be |
| * `NULL`. |
| * |
| * Returns: true if @strv1 and @strv2 are equal |
| * Since: 2.60 |
| */ |
| gboolean |
| g_strv_equal (const gchar * const *strv1, |
| const gchar * const *strv2) |
| { |
| g_return_val_if_fail (strv1 != NULL, FALSE); |
| g_return_val_if_fail (strv2 != NULL, FALSE); |
| |
| if (strv1 == strv2) |
| return TRUE; |
| |
| for (; *strv1 != NULL && *strv2 != NULL; strv1++, strv2++) |
| { |
| if (!g_str_equal (*strv1, *strv2)) |
| return FALSE; |
| } |
| |
| return (*strv1 == NULL && *strv2 == NULL); |
| } |
| |
| static gboolean |
| str_has_sign (const gchar *str) |
| { |
| return str[0] == '-' || str[0] == '+'; |
| } |
| |
| static gboolean |
| str_has_hex_prefix (const gchar *str) |
| { |
| return str[0] == '0' && g_ascii_tolower (str[1]) == 'x'; |
| } |
| |
| /** |
| * g_ascii_string_to_signed: |
| * @str: a string to convert |
| * @base: base of a parsed number |
| * @min: a lower bound (inclusive) |
| * @max: an upper bound (inclusive) |
| * @out_num: (out) (optional): a return location for a number |
| * @error: a return location for #GError |
| * |
| * A convenience function for converting a string to a signed number. |
| * |
| * This function assumes that @str contains only a number of the given |
| * @base that is within inclusive bounds limited by @min and @max. If |
| * this is true, then the converted number is stored in @out_num. An |
| * empty string is not a valid input. A string with leading or |
| * trailing whitespace is also an invalid input. |
| * |
| * @base can be between 2 and 36 inclusive. Hexadecimal numbers must |
| * not be prefixed with "0x" or "0X". Such a problem does not exist |
| * for octal numbers, since they were usually prefixed with a zero |
| * which does not change the value of the parsed number. |
| * |
| * Parsing failures result in an error with the `G_NUMBER_PARSER_ERROR` |
| * domain. If the input is invalid, the error code will be |
| * [error@GLib.NumberParserError.INVALID]. If the parsed number is out of |
| * bounds - [error@GLib.NumberParserError.OUT_OF_BOUNDS]. |
| * |
| * See [func@GLib.ascii_strtoll] if you have more complex needs such as |
| * parsing a string which starts with a number, but then has other |
| * characters. |
| * |
| * Returns: true if @str was a number, false otherwise |
| * |
| * Since: 2.54 |
| */ |
| gboolean |
| g_ascii_string_to_signed (const gchar *str, |
| guint base, |
| gint64 min, |
| gint64 max, |
| gint64 *out_num, |
| GError **error) |
| { |
| gint64 number; |
| const gchar *end_ptr = NULL; |
| gint saved_errno = 0; |
| |
| g_return_val_if_fail (str != NULL, FALSE); |
| g_return_val_if_fail (base >= 2 && base <= 36, FALSE); |
| g_return_val_if_fail (min <= max, FALSE); |
| g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
| |
| if (str[0] == '\0') |
| { |
| g_set_error_literal (error, |
| G_NUMBER_PARSER_ERROR, G_NUMBER_PARSER_ERROR_INVALID, |
| _("Empty string is not a number")); |
| return FALSE; |
| } |
| |
| errno = 0; |
| number = g_ascii_strtoll (str, (gchar **)&end_ptr, base); |
| saved_errno = errno; |
| |
| if (/* We do not allow leading whitespace, but g_ascii_strtoll |
| * accepts it and just skips it, so we need to check for it |
| * ourselves. |
| */ |
| g_ascii_isspace (str[0]) || |
| /* We don't support hexadecimal numbers prefixed with 0x or |
| * 0X. |
| */ |
| (base == 16 && |
| (str_has_sign (str) ? str_has_hex_prefix (str + 1) : str_has_hex_prefix (str))) || |
| (saved_errno != 0 && saved_errno != ERANGE) || |
| end_ptr == NULL || |
| *end_ptr != '\0') |
| { |
| g_set_error (error, |
| G_NUMBER_PARSER_ERROR, G_NUMBER_PARSER_ERROR_INVALID, |
| _("“%s” is not a signed number"), str); |
| return FALSE; |
| } |
| if (saved_errno == ERANGE || number < min || number > max) |
| { |
| gchar *min_str = g_strdup_printf ("%" G_GINT64_FORMAT, min); |
| gchar *max_str = g_strdup_printf ("%" G_GINT64_FORMAT, max); |
| |
| g_set_error (error, |
| G_NUMBER_PARSER_ERROR, G_NUMBER_PARSER_ERROR_OUT_OF_BOUNDS, |
| _("Number “%s” is out of bounds [%s, %s]"), |
| str, min_str, max_str); |
| g_free (min_str); |
| g_free (max_str); |
| return FALSE; |
| } |
| if (out_num != NULL) |
| *out_num = number; |
| return TRUE; |
| } |
| |
| /** |
| * g_ascii_string_to_unsigned: |
| * @str: a string |
| * @base: base of a parsed number |
| * @min: a lower bound (inclusive) |
| * @max: an upper bound (inclusive) |
| * @out_num: (out) (optional): a return location for a number |
| * @error: a return location for #GError |
| * |
| * A convenience function for converting a string to an unsigned number. |
| * |
| * This function assumes that @str contains only a number of the given |
| * @base that is within inclusive bounds limited by @min and @max. If |
| * this is true, then the converted number is stored in @out_num. An |
| * empty string is not a valid input. A string with leading or |
| * trailing whitespace is also an invalid input. A string with a leading sign |
| * (`-` or `+`) is not a valid input for the unsigned parser. |
| * |
| * @base can be between 2 and 36 inclusive. Hexadecimal numbers must |
| * not be prefixed with "0x" or "0X". Such a problem does not exist |
| * for octal numbers, since they were usually prefixed with a zero |
| * which does not change the value of the parsed number. |
| * |
| * Parsing failures result in an error with the `G_NUMBER_PARSER_ERROR` |
| * domain. If the input is invalid, the error code will be |
| * [error@GLib.NumberParserError.INVALID]. If the parsed number is out of |
| * bounds - [error@GLib.NumberParserError.OUT_OF_BOUNDS]. |
| * |
| * See [func@GLib.ascii_strtoull] if you have more complex needs such as |
| * parsing a string which starts with a number, but then has other |
| * characters. |
| * |
| * Returns: true if @str was a number, false otherwise |
| * |
| * Since: 2.54 |
| */ |
| gboolean |
| g_ascii_string_to_unsigned (const gchar *str, |
| guint base, |
| guint64 min, |
| guint64 max, |
| guint64 *out_num, |
| GError **error) |
| { |
| guint64 number; |
| const gchar *end_ptr = NULL; |
| gint saved_errno = 0; |
| |
| g_return_val_if_fail (str != NULL, FALSE); |
| g_return_val_if_fail (base >= 2 && base <= 36, FALSE); |
| g_return_val_if_fail (min <= max, FALSE); |
| g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
| |
| if (str[0] == '\0') |
| { |
| g_set_error_literal (error, |
| G_NUMBER_PARSER_ERROR, G_NUMBER_PARSER_ERROR_INVALID, |
| _("Empty string is not a number")); |
| return FALSE; |
| } |
| |
| errno = 0; |
| number = g_ascii_strtoull (str, (gchar **)&end_ptr, base); |
| saved_errno = errno; |
| |
| if (/* We do not allow leading whitespace, but g_ascii_strtoull |
| * accepts it and just skips it, so we need to check for it |
| * ourselves. |
| */ |
| g_ascii_isspace (str[0]) || |
| /* Unsigned number should have no sign. |
| */ |
| str_has_sign (str) || |
| /* We don't support hexadecimal numbers prefixed with 0x or |
| * 0X. |
| */ |
| (base == 16 && str_has_hex_prefix (str)) || |
| (saved_errno != 0 && saved_errno != ERANGE) || |
| end_ptr == NULL || |
| *end_ptr != '\0') |
| { |
| g_set_error (error, |
| G_NUMBER_PARSER_ERROR, G_NUMBER_PARSER_ERROR_INVALID, |
| _("“%s” is not an unsigned number"), str); |
| return FALSE; |
| } |
| if (saved_errno == ERANGE || number < min || number > max) |
| { |
| gchar *min_str = g_strdup_printf ("%" G_GUINT64_FORMAT, min); |
| gchar *max_str = g_strdup_printf ("%" G_GUINT64_FORMAT, max); |
| |
| g_set_error (error, |
| G_NUMBER_PARSER_ERROR, G_NUMBER_PARSER_ERROR_OUT_OF_BOUNDS, |
| _("Number “%s” is out of bounds [%s, %s]"), |
| str, min_str, max_str); |
| g_free (min_str); |
| g_free (max_str); |
| return FALSE; |
| } |
| if (out_num != NULL) |
| *out_num = number; |
| return TRUE; |
| } |
| |
| G_DEFINE_QUARK (g-number-parser-error-quark, g_number_parser_error) |