#include <sys/stat.h>
#ifdef G_OS_UNIX
#include <pwd.h>
+#include <sys/utsname.h>
#include <unistd.h>
#endif
#include <sys/types.h>
#ifdef G_OS_WIN32
# include <direct.h>
# include <shlobj.h>
- /* older SDK (e.g. msvc 5.0) does not have these*/
-# ifndef CSIDL_MYMUSIC
-# define CSIDL_MYMUSIC 13
-# endif
-# ifndef CSIDL_MYVIDEO
-# define CSIDL_MYVIDEO 14
-# endif
-# ifndef CSIDL_INTERNET_CACHE
-# define CSIDL_INTERNET_CACHE 32
-# endif
-# ifndef CSIDL_COMMON_APPDATA
-# define CSIDL_COMMON_APPDATA 35
-# endif
-# ifndef CSIDL_MYPICTURES
-# define CSIDL_MYPICTURES 0x27
-# endif
-# ifndef CSIDL_COMMON_DOCUMENTS
-# define CSIDL_COMMON_DOCUMENTS 46
-# endif
-# ifndef CSIDL_PROFILE
-# define CSIDL_PROFILE 40
-# endif
# include <process.h>
#endif
*
* Deprecated:2.32: It is best to avoid g_atexit().
*/
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
void
g_atexit (GVoidFunc func)
{
g_strerror (errsv));
}
}
+G_GNUC_END_IGNORE_DEPRECATIONS
/* Based on execvp() from GNU Libc.
* Some of this code is cut-and-pasted into gspawn.c
* the program is found, the return value contains the full name
* including the type suffix.
*
- * Returns: (type filename): a newly-allocated string with the absolute path,
- * or %NULL
+ * Returns: (type filename) (transfer full) (nullable): a newly-allocated
+ * string with the absolute path, or %NULL
**/
#ifdef G_OS_WIN32
static gchar *
e.user_name = g_strdup (pw->pw_name);
#ifndef __BIONIC__
- if (pw->pw_gecos && *pw->pw_gecos != '\0')
+ if (pw->pw_gecos && *pw->pw_gecos != '\0' && pw->pw_name)
{
gchar **gecos_fields;
gchar **name_parts;
* encoding, or something else, and there is no guarantee that it is even
* consistent on a machine. On Windows, it is always UTF-8.
*
- * Returns: (type filename): the user name of the current user.
+ * Returns: (type filename) (transfer none): the user name of the current user.
*/
const gchar *
g_get_user_name (void)
* real user name cannot be determined, the string "Unknown" is
* returned.
*
- * Returns: (type filename): the user's real name.
+ * Returns: (type filename) (transfer none): the user's real name.
*/
const gchar *
g_get_real_name (void)
* should either directly check the `HOME` environment variable yourself
* or unset it before calling any functions in GLib.
*
- * Returns: (type filename): the current user's home directory
+ * Returns: (type filename) (transfer none): the current user's home directory
*/
const gchar *
g_get_home_dir (void)
* it is always UTF-8. The return value is never %NULL or the empty
* string.
*
- * Returns: (type filename): the directory to use for temporary files.
+ * Returns: (type filename) (transfer none): the directory to use for temporary files.
*/
const gchar *
g_get_tmp_dir (void)
*
* The encoding of the returned string is UTF-8.
*
- * Returns: the host name of the machine.
+ * Returns: (transfer none): the host name of the machine.
*
* Since: 2.8
*/
gchar *utmp;
#ifndef G_OS_WIN32
- gchar *tmp = g_malloc (sizeof (gchar) * 100);
- failed = (gethostname (tmp, sizeof (gchar) * 100) == -1);
+ gsize size;
+ /* The number 256 * 256 is taken from the value of _POSIX_HOST_NAME_MAX,
+ * which is 255. Since we use _POSIX_HOST_NAME_MAX + 1 (= 256) in the
+ * fallback case, we pick 256 * 256 as the size of the larger buffer here.
+ * It should be large enough. It doesn't looks reasonable to name a host
+ * with a string that is longer than 64 KiB.
+ */
+ const gsize size_large = (gsize) 256 * 256;
+ gchar *tmp;
+
+#ifdef _SC_HOST_NAME_MAX
+ {
+ glong max;
+
+ max = sysconf (_SC_HOST_NAME_MAX);
+ if (max > 0 && (gsize) max <= G_MAXSIZE - 1)
+ size = (gsize) max + 1;
+ else
+#ifdef HOST_NAME_MAX
+ size = HOST_NAME_MAX + 1;
+#else
+ size = _POSIX_HOST_NAME_MAX + 1;
+#endif /* HOST_NAME_MAX */
+ }
+#else
+ /* Fallback to some reasonable value */
+ size = 256;
+#endif /* _SC_HOST_NAME_MAX */
+ tmp = g_malloc (size);
+ failed = (gethostname (tmp, size) == -1);
+ if (failed && size < size_large)
+ {
+ /* Try again with a larger buffer if 'size' may be too small. */
+ g_free (tmp);
+ tmp = g_malloc (size_large);
+ failed = (gethostname (tmp, size_large) == -1);
+ }
+
if (failed)
g_clear_pointer (&tmp, g_free);
utmp = tmp;
* #GtkApplication::startup handler. The program name is found by
* taking the last component of @argv[0].
*
- * Returns: (nullable): the name of the program, or %NULL if it has not been
- * set yet. The returned string belongs
- * to GLib and must not be modified or freed.
+ * Returns: (nullable) (transfer none): the name of the program,
+ * or %NULL if it has not been set yet. The returned string belongs
+ * to GLib and must not be modified or freed.
*/
const gchar*
g_get_prgname (void)
gchar* retval;
G_LOCK (g_prgname);
-#ifdef G_OS_WIN32
- if (g_prgname == NULL)
- {
- static gboolean beenhere = FALSE;
-
- if (!beenhere)
- {
- gchar *utf8_buf = NULL;
- wchar_t buf[MAX_PATH+1];
-
- beenhere = TRUE;
- if (GetModuleFileNameW (GetModuleHandle (NULL),
- buf, G_N_ELEMENTS (buf)) > 0)
- utf8_buf = g_utf16_to_utf8 (buf, -1, NULL, NULL, NULL);
-
- if (utf8_buf)
- {
- g_prgname = g_path_get_basename (utf8_buf);
- g_free (utf8_buf);
- }
- }
- }
-#endif
retval = g_prgname;
G_UNLOCK (g_prgname);
* g_get_prgname() (which may be %NULL if g_set_prgname() has also not
* been called).
*
- * Returns: human-readable application name. may return %NULL
+ * Returns: (transfer none) (nullable): human-readable application
+ * name. May return %NULL
*
* Since: 2.2
**/
g_warning ("g_set_application_name() called multiple times");
}
+#ifdef G_OS_WIN32
+/* For the past versions we can just
+ * hardcode all the names.
+ */
+static const struct winver
+{
+ gint major;
+ gint minor;
+ gint sp;
+ const char *version;
+ const char *spversion;
+} versions[] =
+{
+ {6, 2, 0, "8", ""},
+ {6, 1, 1, "7", " SP1"},
+ {6, 1, 0, "7", ""},
+ {6, 0, 2, "Vista", " SP2"},
+ {6, 0, 1, "Vista", " SP1"},
+ {6, 0, 0, "Vista", ""},
+ {5, 1, 3, "XP", " SP3"},
+ {5, 1, 2, "XP", " SP2"},
+ {5, 1, 1, "XP", " SP1"},
+ {5, 1, 0, "XP", ""},
+ {0, 0, 0, NULL, NULL},
+};
+
+static gchar *
+get_registry_str (HKEY root_key, const wchar_t *path, const wchar_t *value_name)
+{
+ HKEY key_handle;
+ DWORD req_value_data_size;
+ DWORD req_value_data_size2;
+ LONG status;
+ DWORD value_type_w;
+ DWORD value_type_w2;
+ char *req_value_data;
+ gchar *result;
+
+ status = RegOpenKeyExW (root_key, path, 0, KEY_READ, &key_handle);
+ if (status != ERROR_SUCCESS)
+ return NULL;
+
+ req_value_data_size = 0;
+ status = RegQueryValueExW (key_handle,
+ value_name,
+ NULL,
+ &value_type_w,
+ NULL,
+ &req_value_data_size);
+
+ if (status != ERROR_MORE_DATA && status != ERROR_SUCCESS)
+ {
+ RegCloseKey (key_handle);
+
+ return NULL;
+ }
+
+ req_value_data = g_malloc (req_value_data_size);
+ req_value_data_size2 = req_value_data_size;
+
+ status = RegQueryValueExW (key_handle,
+ value_name,
+ NULL,
+ &value_type_w2,
+ (gpointer) req_value_data,
+ &req_value_data_size2);
+
+ result = NULL;
+
+ if (status == ERROR_SUCCESS && value_type_w2 == REG_SZ)
+ result = g_utf16_to_utf8 ((gunichar2 *) req_value_data,
+ req_value_data_size / sizeof (gunichar2),
+ NULL,
+ NULL,
+ NULL);
+
+ g_free (req_value_data);
+ RegCloseKey (key_handle);
+
+ return result;
+}
+
+/* Windows 8.1 can be either plain or with Update 1,
+ * depending on its build number (9200 or 9600).
+ */
+static gchar *
+get_windows_8_1_update (void)
+{
+ gchar *current_build;
+ gchar *result = NULL;
+
+ current_build = get_registry_str (HKEY_LOCAL_MACHINE,
+ L"SOFTWARE"
+ L"\\Microsoft"
+ L"\\Windows NT"
+ L"\\CurrentVersion",
+ L"CurrentBuild");
+
+ if (current_build != NULL)
+ {
+ wchar_t *end;
+ long build = wcstol ((const wchar_t *) current_build, &end, 10);
+
+ if (build <= INT_MAX &&
+ build >= INT_MIN &&
+ errno == 0 &&
+ *end == L'\0')
+ {
+ if (build >= 9600)
+ result = g_strdup ("Update 1");
+ }
+ }
+
+ g_clear_pointer (¤t_build, g_free);
+
+ return result;
+}
+
+static gchar *
+get_windows_version (gboolean with_windows)
+{
+ GString *version = g_string_new (NULL);
+
+ if (g_win32_check_windows_version (10, 0, 0, G_WIN32_OS_ANY))
+ {
+ gchar *win10_release;
+
+ g_string_append (version, "10");
+
+ if (!g_win32_check_windows_version (10, 0, 0, G_WIN32_OS_WORKSTATION))
+ g_string_append (version, " Server");
+
+ /* Windows 10 is identified by its release number, such as
+ * 1511, 1607, 1703, 1709, 1803, 1809 or 1903.
+ * The first version of Windows 10 has no release number.
+ */
+ win10_release = get_registry_str (HKEY_LOCAL_MACHINE,
+ L"SOFTWARE"
+ L"\\Microsoft"
+ L"\\Windows NT"
+ L"\\CurrentVersion",
+ L"ReleaseId");
+
+ if (win10_release != NULL)
+ g_string_append_printf (version, " %s", win10_release);
+
+ g_free (win10_release);
+ }
+ else if (g_win32_check_windows_version (6, 3, 0, G_WIN32_OS_ANY))
+ {
+ gchar *win81_update;
+
+ g_string_append (version, "8.1");
+
+ if (!g_win32_check_windows_version (6, 3, 0, G_WIN32_OS_WORKSTATION))
+ g_string_append (version, " Server");
+
+ win81_update = get_windows_8_1_update ();
+
+ if (win81_update != NULL)
+ g_string_append_printf (version, " %s", win81_update);
+
+ g_free (win81_update);
+ }
+ else
+ {
+ gint i;
+
+ for (i = 0; versions[i].major > 0; i++)
+ {
+ if (!g_win32_check_windows_version (versions[i].major, versions[i].minor, versions[i].sp, G_WIN32_OS_ANY))
+ continue;
+
+ g_string_append (version, versions[i].version);
+
+ if (!g_win32_check_windows_version (versions[i].major, versions[i].minor, versions[i].sp, G_WIN32_OS_WORKSTATION))
+ g_string_append (version, " Server");
+
+ g_string_append (version, versions[i].spversion);
+ }
+ }
+
+ if (version->len == 0)
+ {
+ g_string_free (version, TRUE);
+
+ return NULL;
+ }
+
+ if (with_windows)
+ g_string_prepend (version, "Windows ");
+
+ return g_string_free (version, FALSE);
+}
+#endif
+
+#ifdef G_OS_UNIX
+static gchar *
+get_os_info_from_os_release (const gchar *key_name,
+ const gchar *buffer)
+{
+ GStrv lines;
+ gchar *prefix;
+ size_t i;
+ gchar *result = NULL;
+
+ lines = g_strsplit (buffer, "\n", -1);
+ prefix = g_strdup_printf ("%s=", key_name);
+ for (i = 0; lines[i] != NULL; i++)
+ {
+ const gchar *line = lines[i];
+ const gchar *value;
+
+ if (g_str_has_prefix (line, prefix))
+ {
+ value = line + strlen (prefix);
+ result = g_shell_unquote (value, NULL);
+ if (result == NULL)
+ result = g_strdup (value);
+ break;
+ }
+ }
+ g_strfreev (lines);
+ g_free (prefix);
+
+#ifdef __linux__
+ /* Default values in spec */
+ if (result == NULL)
+ {
+ if (g_str_equal (key_name, G_OS_INFO_KEY_NAME))
+ return g_strdup ("Linux");
+ if (g_str_equal (key_name, G_OS_INFO_KEY_ID))
+ return g_strdup ("linux");
+ if (g_str_equal (key_name, G_OS_INFO_KEY_PRETTY_NAME))
+ return g_strdup ("Linux");
+ }
+#endif
+
+ return g_steal_pointer (&result);
+}
+
+static gchar *
+get_os_info_from_uname (const gchar *key_name)
+{
+ struct utsname info;
+
+ if (uname (&info) == -1)
+ return NULL;
+
+ if (strcmp (key_name, G_OS_INFO_KEY_NAME) == 0)
+ return g_strdup (info.sysname);
+ else if (strcmp (key_name, G_OS_INFO_KEY_VERSION) == 0)
+ return g_strdup (info.release);
+ else if (strcmp (key_name, G_OS_INFO_KEY_PRETTY_NAME) == 0)
+ return g_strdup_printf ("%s %s", info.sysname, info.release);
+ else if (strcmp (key_name, G_OS_INFO_KEY_ID) == 0)
+ {
+ gchar *result = g_ascii_strdown (info.sysname, -1);
+
+ g_strcanon (result, "abcdefghijklmnopqrstuvwxyz0123456789_-.", '_');
+ return g_steal_pointer (&result);
+ }
+ else if (strcmp (key_name, G_OS_INFO_KEY_VERSION_ID) == 0)
+ {
+ /* We attempt to convert the version string to the format returned by
+ * config.guess, which is the script used to generate target triplets
+ * in GNU autotools. There are a lot of rules in the script. We only
+ * implement a few rules which are easy to understand here.
+ *
+ * config.guess can be found at https://savannah.gnu.org/projects/config.
+ */
+ gchar *result;
+
+ if (strcmp (info.sysname, "NetBSD") == 0)
+ {
+ /* sed -e 's,[-_].*,,' */
+ gssize len = G_MAXSSIZE;
+ const gchar *c;
+
+ if ((c = strchr (info.release, '-')) != NULL)
+ len = MIN (len, c - info.release);
+ if ((c = strchr (info.release, '_')) != NULL)
+ len = MIN (len, c - info.release);
+ if (len == G_MAXSSIZE)
+ len = -1;
+
+ result = g_ascii_strdown (info.release, len);
+ }
+ else if (strcmp (info.sysname, "GNU") == 0)
+ {
+ /* sed -e 's,/.*$,,' */
+ gssize len = -1;
+ const gchar *c = strchr (info.release, '/');
+
+ if (c != NULL)
+ len = c - info.release;
+
+ result = g_ascii_strdown (info.release, len);
+ }
+ else if (g_str_has_prefix (info.sysname, "GNU/") ||
+ strcmp (info.sysname, "FreeBSD") == 0 ||
+ strcmp (info.sysname, "DragonFly") == 0)
+ {
+ /* sed -e 's,[-(].*,,' */
+ gssize len = G_MAXSSIZE;
+ const gchar *c;
+
+ if ((c = strchr (info.release, '-')) != NULL)
+ len = MIN (len, c - info.release);
+ if ((c = strchr (info.release, '(')) != NULL)
+ len = MIN (len, c - info.release);
+ if (len == G_MAXSSIZE)
+ len = -1;
+
+ result = g_ascii_strdown (info.release, len);
+ }
+ else
+ result = g_ascii_strdown (info.release, -1);
+
+ g_strcanon (result, "abcdefghijklmnopqrstuvwxyz0123456789_-.", '_');
+ return g_steal_pointer (&result);
+ }
+ else
+ return NULL;
+}
+#endif
+
+/**
+ * g_get_os_info:
+ * @key_name: a key for the OS info being requested, for example %G_OS_INFO_KEY_NAME.
+ *
+ * Get information about the operating system.
+ *
+ * On Linux this comes from the `/etc/os-release` file. On other systems, it may
+ * come from a variety of sources. You can either use the standard key names
+ * like %G_OS_INFO_KEY_NAME or pass any UTF-8 string key name. For example,
+ * `/etc/os-release` provides a number of other less commonly used values that may
+ * be useful. No key is guaranteed to be provided, so the caller should always
+ * check if the result is %NULL.
+ *
+ * Returns: (nullable): The associated value for the requested key or %NULL if
+ * this information is not provided.
+ *
+ * Since: 2.64
+ **/
+gchar *
+g_get_os_info (const gchar *key_name)
+{
+#if defined (__APPLE__)
+ if (g_strcmp0 (key_name, G_OS_INFO_KEY_NAME) == 0)
+ return g_strdup ("macOS");
+ else
+ return NULL;
+#elif defined (G_OS_UNIX)
+ const gchar * const os_release_files[] = { "/etc/os-release", "/usr/lib/os-release" };
+ gsize i;
+ gchar *buffer = NULL;
+ gchar *result = NULL;
+
+ g_return_val_if_fail (key_name != NULL, NULL);
+
+ for (i = 0; i < G_N_ELEMENTS (os_release_files); i++)
+ {
+ GError *error = NULL;
+ gboolean file_missing;
+
+ if (g_file_get_contents (os_release_files[i], &buffer, NULL, &error))
+ break;
+
+ file_missing = g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT);
+ g_clear_error (&error);
+
+ if (!file_missing)
+ return NULL;
+ }
+
+ if (buffer != NULL)
+ result = get_os_info_from_os_release (key_name, buffer);
+ else
+ result = get_os_info_from_uname (key_name);
+
+ g_free (buffer);
+ return g_steal_pointer (&result);
+#elif defined (G_OS_WIN32)
+ if (g_strcmp0 (key_name, G_OS_INFO_KEY_NAME) == 0)
+ return g_strdup ("Windows");
+ else if (g_strcmp0 (key_name, G_OS_INFO_KEY_ID) == 0)
+ return g_strdup ("windows");
+ else if (g_strcmp0 (key_name, G_OS_INFO_KEY_PRETTY_NAME) == 0)
+ /* Windows XP SP2 or Windows 10 1903 or Windows 7 Server SP1 */
+ return get_windows_version (TRUE);
+ else if (g_strcmp0 (key_name, G_OS_INFO_KEY_VERSION) == 0)
+ /* XP SP2 or 10 1903 or 7 Server SP1 */
+ return get_windows_version (FALSE);
+ else if (g_strcmp0 (key_name, G_OS_INFO_KEY_VERSION_ID) == 0)
+ {
+ /* xp_sp2 or 10_1903 or 7_server_sp1 */
+ gchar *result;
+ gchar *version = get_windows_version (FALSE);
+
+ if (version == NULL)
+ return NULL;
+
+ result = g_ascii_strdown (version, -1);
+ g_free (version);
+
+ return g_strcanon (result, "abcdefghijklmnopqrstuvwxyz0123456789_-.", '_');
+ }
+ else if (g_strcmp0 (key_name, G_OS_INFO_KEY_HOME_URL) == 0)
+ return g_strdup ("https://microsoft.com/windows/");
+ else if (g_strcmp0 (key_name, G_OS_INFO_KEY_DOCUMENTATION_URL) == 0)
+ return g_strdup ("https://docs.microsoft.com/");
+ else if (g_strcmp0 (key_name, G_OS_INFO_KEY_SUPPORT_URL) == 0)
+ return g_strdup ("https://support.microsoft.com/");
+ else if (g_strcmp0 (key_name, G_OS_INFO_KEY_BUG_REPORT_URL) == 0)
+ return g_strdup ("https://support.microsoft.com/contactus/");
+ else if (g_strcmp0 (key_name, G_OS_INFO_KEY_PRIVACY_POLICY_URL) == 0)
+ return g_strdup ("https://privacy.microsoft.com/");
+ else
+ return NULL;
+#endif
+}
+
/* Set @global_str to a copy of @new_value if it’s currently unset or has a
* different value. If its current value matches @new_value, do nothing. If
* replaced, we have to leak the old value as client code could still have
* Note that in this case on Windows it will be the same
* as what g_get_user_config_dir() returns.
*
- * Returns: (type filename): a string owned by GLib that must not be modified
- * or freed.
+ * Returns: (type filename) (transfer none): a string owned by GLib that must
+ * not be modified or freed.
+ *
* Since: 2.6
**/
const gchar *
* Note that in this case on Windows it will be the same
* as what g_get_user_data_dir() returns.
*
- * Returns: (type filename): a string owned by GLib that must not be modified
- * or freed.
+ * Returns: (type filename) (transfer none): a string owned by GLib that
+ * must not be modified or freed.
* Since: 2.6
**/
const gchar *
* `C:\Documents and Settings\username\Local Settings\Temporary Internet Files`.
* See the [documentation for `CSIDL_INTERNET_CACHE`](https://msdn.microsoft.com/en-us/library/windows/desktop/bb762494%28v=vs.85%29.aspx#csidl_internet_cache).
*
- * Returns: (type filename): a string owned by GLib that must not be modified
- * or freed.
+ * Returns: (type filename) (transfer none): a string owned by GLib that
+ * must not be modified or freed.
* Since: 2.6
**/
const gchar *
wchar_t *wcp;
- p_SHGetKnownFolderPath = (t_SHGetKnownFolderPath) GetProcAddress (GetModuleHandle ("shell32.dll"),
+ p_SHGetKnownFolderPath = (t_SHGetKnownFolderPath) GetProcAddress (GetModuleHandleW (L"shell32.dll"),
"SHGetKnownFolderPath");
g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = get_special_folder (CSIDL_DESKTOPDIRECTORY);
{
/* Holds the g_utils_global lock */
- static gboolean beenhere = FALSE;
- typedef BOOL (WINAPI *t_GetModuleHandleExA) (DWORD, LPCTSTR, HMODULE *);
- static t_GetModuleHandleExA p_GetModuleHandleExA = NULL;
HMODULE hmodule = NULL;
if (!address)
return NULL;
- if (!beenhere)
- {
- p_GetModuleHandleExA =
- (t_GetModuleHandleExA) GetProcAddress (GetModuleHandle ("kernel32.dll"),
- "GetModuleHandleExA");
- beenhere = TRUE;
- }
-
- if (p_GetModuleHandleExA == NULL ||
- !(*p_GetModuleHandleExA) (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
- GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
- address, &hmodule))
+ if (!GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
+ GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ address, &hmodule))
{
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery (address, &mbi, sizeof (mbi));
* See g_format_size_full() for more options about how the size might be
* formatted.
*
- * Returns: a newly-allocated formatted string containing a human readable
- * file size
+ * Returns: (transfer full): a newly-allocated formatted string containing
+ * a human readable file size
*
* Since: 2.30
*/
* This function is similar to g_format_size() but allows for flags
* that modify the output. See #GFormatSizeFlags.
*
- * Returns: a newly-allocated formatted string containing a human
- * readable file size
+ * Returns: (transfer full): a newly-allocated formatted string
+ * containing a human readable file size
*
* Since: 2.30
*/
struct Format
{
guint64 factor;
- char string[9];
+ char string[10];
};
typedef enum
/* Translators: the %s in "%s bits" will always be replaced by a number. */
translated_format = g_dngettext (GETTEXT_PACKAGE, "%s bit", "%s bits", plural_form);
}
- /* XXX: Windows doesn't support the "'" format modifier, so we
- * must not use it there. Instead, just display the number
- * without separation. Bug #655336 is open until a solution is
- * found.
- */
-#ifndef G_OS_WIN32
formatted_number = g_strdup_printf ("%'"G_GUINT64_FORMAT, size);
-#else
- formatted_number = g_strdup_printf ("%"G_GUINT64_FORMAT, size);
-#endif
g_string_append (string, " (");
g_string_append_printf (string, translated_format, formatted_number);
*
* This string should be freed with g_free() when not needed any longer.
*
- * Returns: a newly-allocated formatted string containing a human
- * readable file size
+ * Returns: (transfer full): a newly-allocated formatted string
+ * containing a human readable file size
*
* Since: 2.16
*
{
/* One call to break the debugger */
DebugBreak ();
- /* One call in case CRT does get saner about abort() behaviour */
+ /* One call in case CRT changes its abort() behaviour */
abort ();
/* And one call to bind them all and terminate the program for sure */
ExitProcess (127);