📄 gstrfuncs.c
字号:
/* GLIB - Library of useful routines for C programming * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * 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 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, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. *//* * 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 */#ifdef HAVE_CONFIG_H#include "glibconfig.h"#endif#define _GNU_SOURCE /* For stpcpy */#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <locale.h>#include <errno.h>#include <ctype.h> /* For tolower() */#if !defined (HAVE_STRSIGNAL) || !defined(NO_SYS_SIGLIST_DECL)#include <signal.h>#endif#include "glib.h"#ifdef G_OS_WIN32#include <windows.h>#endif/* do not include <unistd.h> in this place since it * inteferes with g_strsignal() on some OSes */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 */};#if defined(G_PLATFORM_WIN32) && defined(__GNUC__)__declspec(dllexport)#endifconst guint16 * const g_ascii_table = ascii_table_data;gchar*g_strdup (const gchar *str){ gchar *new_str; if (str) { new_str = g_new (char, strlen (str) + 1); strcpy (new_str, str); } else new_str = NULL; return new_str;}gpointerg_memdup (gconstpointer mem, guint byte_size){ gpointer new_mem; if (mem) { new_mem = g_malloc (byte_size); memcpy (new_mem, mem, byte_size); } else new_mem = NULL; return new_mem;}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;}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 dest buffer, include the * trailing nul, and return a pointer to the trailing nul byte. * This is useful for concatenating multiple strings together * without having to repeatedly scan for the end. * * Return value: a pointer to trailing nul byte. **/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 register gchar *d = dest; register 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}gchar*g_strdup_vprintf (const gchar *format, va_list args1){ gchar *buffer;#ifdef HAVE_VASPRINTF if (vasprintf (&buffer, format, args1) < 0) buffer = NULL; else if (!g_mem_is_system_malloc ()) { gchar *buffer1 = g_strdup (buffer); free (buffer); buffer = buffer1; }#else va_list args2; G_VA_COPY (args2, args1); buffer = g_new (gchar, g_printf_string_upper_bound (format, args1)); vsprintf (buffer, format, args2); va_end (args2);#endif return buffer;}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;}gchar*g_strconcat (const gchar *string1, ...){ gsize l; va_list args; gchar *s; gchar *concat; gchar *ptr; g_return_val_if_fail (string1 != NULL, 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: if non-%NULL, it returns the character after * the last character used in the conversion. * * Converts a string to a #gdouble 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 g_ascii_strtod(), and returns the best match. * * This function should seldomly be used. The normal situation when reading * numbers not for human consumption is to use g_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. * * Return value: the #gdouble value. **/gdoubleg_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: if non-%NULL, it returns the character after * the last character used in the conversion. * * Converts a string to a #gdouble 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. * * 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 string to #gdouble in a locale-insensitive * way, use g_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. * * Return value: the #gdouble value. **/gdoubleg_ascii_strtod (const gchar *nptr, gchar **endptr){ gchar *fail_pos; gdouble val; struct lconv *locale_data; const char *decimal_point; int decimal_point_len; const char *p, *decimal_point_pos; const char *end = NULL; /* Silence gcc */ g_return_val_if_fail (nptr != NULL, 0); fail_pos = NULL; locale_data = localeconv (); decimal_point = locale_data->decimal_point; decimal_point_len = strlen (decimal_point); g_assert (decimal_point_len != 0); decimal_point_pos = 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 { 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 */ } /* Set errno to zero, so that we can distinguish zero results and underflows */ errno = 0; 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; val = strtod (copy, &fail_pos); if (fail_pos) { if (fail_pos > decimal_point_pos) fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1); else fail_pos = (char *)nptr + (fail_pos - copy); } g_free (copy); } else val = strtod (nptr, &fail_pos); if (endptr) *endptr = fail_pos; return val;}/** * g_ascii_dtostr: * @buffer: A buffer to place the resulting string in * @buf_len: The length of the buffer. * @d: The #gdouble to convert * * Converts a #gdouble to a string, using the '.' as * decimal point. * * This functions generates enough precision that converting * the string back using g_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 @G_ASCII_DTOSTR_BUF_SIZE bytes. * * Return value: 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);}/** * 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 #gdouble to convert * * Converts a #gdouble to a string, using the '.' as * decimal point. To format the number you pass in * a printf-style formating string. Allowed conversion * specifiers are 'e', 'E', 'f', 'F', 'g' and 'G'. * * If you just want to want to serialize the value into a * string, use g_ascii_dtostr(). * * Return value: The pointer to the buffer with the converted string. **/gchar *g_ascii_formatd (gchar *buffer, gint buf_len, const gchar *format, gdouble d){ struct lconv *locale_data; const char *decimal_point; int 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); locale_data = localeconv (); decimal_point = locale_data->decimal_point; decimal_point_len = strlen (decimal_point); g_assert (decimal_point_len != 0); if (decimal_point[0] != '.' || decimal_point[1] != 0) { p = buffer; 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));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -