mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 11:26:16 +01:00
Reshuffle some functions between gutils and gfileutils
Move filename-related functions to gfileutils, and move size formatting functions to gutils.
This commit is contained in:
parent
23afdb119e
commit
67bf0083db
@ -2048,263 +2048,6 @@ g_build_filename (const gchar *first_element,
|
||||
return str;
|
||||
}
|
||||
|
||||
#define KILOBYTE_FACTOR (G_GOFFSET_CONSTANT (1000))
|
||||
#define MEGABYTE_FACTOR (KILOBYTE_FACTOR * KILOBYTE_FACTOR)
|
||||
#define GIGABYTE_FACTOR (MEGABYTE_FACTOR * KILOBYTE_FACTOR)
|
||||
#define TERABYTE_FACTOR (GIGABYTE_FACTOR * KILOBYTE_FACTOR)
|
||||
#define PETABYTE_FACTOR (TERABYTE_FACTOR * KILOBYTE_FACTOR)
|
||||
#define EXABYTE_FACTOR (PETABYTE_FACTOR * KILOBYTE_FACTOR)
|
||||
|
||||
#define KIBIBYTE_FACTOR (G_GOFFSET_CONSTANT (1024))
|
||||
#define MEBIBYTE_FACTOR (KIBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
||||
#define GIBIBYTE_FACTOR (MEBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
||||
#define TEBIBYTE_FACTOR (GIBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
||||
#define PEBIBYTE_FACTOR (TEBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
||||
#define EXBIBYTE_FACTOR (PEBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
||||
|
||||
/**
|
||||
* g_format_size:
|
||||
* @size: a size in bytes
|
||||
*
|
||||
* Formats a size (for example the size of a file) into a human readable
|
||||
* string. Sizes are rounded to the nearest size prefix (kB, MB, GB)
|
||||
* and are displayed rounded to the nearest tenth. E.g. the file size
|
||||
* 3292528 bytes will be converted into the string "3.2 MB".
|
||||
*
|
||||
* The prefix units base is 1000 (i.e. 1 kB is 1000 bytes).
|
||||
*
|
||||
* This string should be freed with g_free() when not needed any longer.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Since: 2.30
|
||||
**/
|
||||
gchar *
|
||||
g_format_size (guint64 size)
|
||||
{
|
||||
return g_format_size_full (size, G_FORMAT_SIZE_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_format_size_full:
|
||||
* @size: a size in bytes
|
||||
* @flags: #GFormatSizeFlags to modify the output
|
||||
*
|
||||
* Formats a size.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Since: 2.30
|
||||
**/
|
||||
/**
|
||||
* GFormatSizeFlags:
|
||||
* @G_FORMAT_SIZE_DEFAULT: behave the same as g_format_size()
|
||||
* @G_FORMAT_SIZE_LONG_FORMAT: include the exact number of bytes as part
|
||||
* of the returned string. For example,
|
||||
* "45.6 kB (45,612 bytes)".
|
||||
* @G_FORMAT_SIZE_IEC_UNITS: use IEC (base 1024) units with "KiB"-style
|
||||
* suffixes. IEC units should only be used
|
||||
* for reporting things with a strong "power
|
||||
* of 2" basis, like RAM sizes or RAID stripe
|
||||
* sizes. Network and storage sizes should
|
||||
* be reported in the normal SI units.
|
||||
*
|
||||
* Flags to modify the format of the string returned by
|
||||
* g_format_size_full().
|
||||
**/
|
||||
gchar *
|
||||
g_format_size_full (guint64 size,
|
||||
GFormatSizeFlags flags)
|
||||
{
|
||||
GString *string;
|
||||
|
||||
string = g_string_new (NULL);
|
||||
|
||||
if (flags & G_FORMAT_SIZE_IEC_UNITS)
|
||||
{
|
||||
if (size < KIBIBYTE_FACTOR)
|
||||
{
|
||||
g_string_printf (string,
|
||||
g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes", (guint) size),
|
||||
(guint) size);
|
||||
flags &= ~G_FORMAT_SIZE_LONG_FORMAT;
|
||||
}
|
||||
|
||||
else if (size < MEBIBYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f KiB"), (gdouble) size / (gdouble) KIBIBYTE_FACTOR);
|
||||
|
||||
else if (size < GIBIBYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f MiB"), (gdouble) size / (gdouble) MEBIBYTE_FACTOR);
|
||||
|
||||
else if (size < TEBIBYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f GiB"), (gdouble) size / (gdouble) GIBIBYTE_FACTOR);
|
||||
|
||||
else if (size < PEBIBYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f TiB"), (gdouble) size / (gdouble) TEBIBYTE_FACTOR);
|
||||
|
||||
else if (size < EXBIBYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f PiB"), (gdouble) size / (gdouble) PEBIBYTE_FACTOR);
|
||||
|
||||
else
|
||||
g_string_printf (string, _("%.1f EiB"), (gdouble) size / (gdouble) EXBIBYTE_FACTOR);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (size < KILOBYTE_FACTOR)
|
||||
{
|
||||
g_string_printf (string,
|
||||
g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes", (guint) size),
|
||||
(guint) size);
|
||||
flags &= ~G_FORMAT_SIZE_LONG_FORMAT;
|
||||
}
|
||||
|
||||
else if (size < MEGABYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f kB"), (gdouble) size / (gdouble) KILOBYTE_FACTOR);
|
||||
|
||||
else if (size < GIGABYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f MB"), (gdouble) size / (gdouble) MEGABYTE_FACTOR);
|
||||
|
||||
else if (size < TERABYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f GB"), (gdouble) size / (gdouble) GIGABYTE_FACTOR);
|
||||
|
||||
else if (size < PETABYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f TB"), (gdouble) size / (gdouble) TERABYTE_FACTOR);
|
||||
|
||||
else if (size < EXABYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f PB"), (gdouble) size / (gdouble) PETABYTE_FACTOR);
|
||||
|
||||
else
|
||||
g_string_printf (string, _("%.1f EB"), (gdouble) size / (gdouble) EXABYTE_FACTOR);
|
||||
}
|
||||
|
||||
if (flags & G_FORMAT_SIZE_LONG_FORMAT)
|
||||
{
|
||||
/* First problem: we need to use the number of bytes to decide on
|
||||
* the plural form that is used for display, but the number of
|
||||
* bytes potentially exceeds the size of a guint (which is what
|
||||
* ngettext() takes).
|
||||
*
|
||||
* From a pragmatic standpoint, it seems that all known languages
|
||||
* base plural forms on one or both of the following:
|
||||
*
|
||||
* - the lowest digits of the number
|
||||
*
|
||||
* - if the number if greater than some small value
|
||||
*
|
||||
* Here's how we fake it: Draw an arbitrary line at one thousand.
|
||||
* If the number is below that, then fine. If it is above it,
|
||||
* then we take the modulus of the number by one thousand (in
|
||||
* order to keep the lowest digits) and add one thousand to that
|
||||
* (in order to ensure that 1001 is not treated the same as 1).
|
||||
*/
|
||||
guint plural_form = size < 1000 ? size : size % 1000 + 1000;
|
||||
|
||||
/* Second problem: we need to translate the string "%u byte" and
|
||||
* "%u bytes" for pluralisation, but the correct number format to
|
||||
* use for a gsize is different depending on which architecture
|
||||
* we're on.
|
||||
*
|
||||
* Solution: format the number separately and use "%s bytes" on
|
||||
* all platforms.
|
||||
*/
|
||||
const gchar *translated_format;
|
||||
gchar *formatted_number;
|
||||
|
||||
/* Translators: the %s in "%s bytes" will always be replaced by a number. */
|
||||
translated_format = g_dngettext(GETTEXT_PACKAGE, "%s byte", "%s bytes", 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);
|
||||
g_free (formatted_number);
|
||||
g_string_append (string, ")");
|
||||
}
|
||||
|
||||
return g_string_free (string, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_format_size_for_display:
|
||||
* @size: a size in bytes.
|
||||
*
|
||||
* Formats a size (for example the size of a file) into a human readable string.
|
||||
* Sizes are rounded to the nearest size prefix (KB, MB, GB) and are displayed
|
||||
* rounded to the nearest tenth. E.g. the file size 3292528 bytes will be
|
||||
* converted into the string "3.1 MB".
|
||||
*
|
||||
* The prefix units base is 1024 (i.e. 1 KB is 1024 bytes).
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Deprecated:2.30: This function is broken due to its use of SI
|
||||
* suffixes to denote IEC units. Use g_format_size()
|
||||
* instead.
|
||||
* Since: 2.16
|
||||
**/
|
||||
char *
|
||||
g_format_size_for_display (goffset size)
|
||||
{
|
||||
if (size < (goffset) KIBIBYTE_FACTOR)
|
||||
return g_strdup_printf (g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes",(guint) size), (guint) size);
|
||||
else
|
||||
{
|
||||
gdouble displayed_size;
|
||||
|
||||
if (size < (goffset) MEBIBYTE_FACTOR)
|
||||
{
|
||||
displayed_size = (gdouble) size / (gdouble) KIBIBYTE_FACTOR;
|
||||
return g_strdup_printf (_("%.1f KB"), displayed_size);
|
||||
}
|
||||
else if (size < (goffset) GIBIBYTE_FACTOR)
|
||||
{
|
||||
displayed_size = (gdouble) size / (gdouble) MEBIBYTE_FACTOR;
|
||||
return g_strdup_printf (_("%.1f MB"), displayed_size);
|
||||
}
|
||||
else if (size < (goffset) TEBIBYTE_FACTOR)
|
||||
{
|
||||
displayed_size = (gdouble) size / (gdouble) GIBIBYTE_FACTOR;
|
||||
return g_strdup_printf (_("%.1f GB"), displayed_size);
|
||||
}
|
||||
else if (size < (goffset) PEBIBYTE_FACTOR)
|
||||
{
|
||||
displayed_size = (gdouble) size / (gdouble) TEBIBYTE_FACTOR;
|
||||
return g_strdup_printf (_("%.1f TB"), displayed_size);
|
||||
}
|
||||
else if (size < (goffset) EXBIBYTE_FACTOR)
|
||||
{
|
||||
displayed_size = (gdouble) size / (gdouble) PEBIBYTE_FACTOR;
|
||||
return g_strdup_printf (_("%.1f PB"), displayed_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
displayed_size = (gdouble) size / (gdouble) EXBIBYTE_FACTOR;
|
||||
return g_strdup_printf (_("%.1f EB"), displayed_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* g_file_read_link:
|
||||
* @filename: the symbolic link
|
||||
@ -2369,7 +2112,445 @@ g_file_read_link (const gchar *filename,
|
||||
#endif
|
||||
}
|
||||
|
||||
/* NOTE : Keep this part last to ensure nothing in this file uses the
|
||||
/**
|
||||
* g_path_is_absolute:
|
||||
* @file_name: a file name
|
||||
*
|
||||
* Returns %TRUE if the given @file_name is an absolute file name.
|
||||
* Note that this is a somewhat vague concept on Windows.
|
||||
*
|
||||
* On POSIX systems, an absolute file name is well-defined. It always
|
||||
* starts from the single root directory. For example "/usr/local".
|
||||
*
|
||||
* On Windows, the concepts of current drive and drive-specific
|
||||
* current directory introduce vagueness. This function interprets as
|
||||
* an absolute file name one that either begins with a directory
|
||||
* separator such as "\Users\tml" or begins with the root on a drive,
|
||||
* for example "C:\Windows". The first case also includes UNC paths
|
||||
* such as "\\myserver\docs\foo". In all cases, either slashes or
|
||||
* backslashes are accepted.
|
||||
*
|
||||
* Note that a file name relative to the current drive root does not
|
||||
* truly specify a file uniquely over time and across processes, as
|
||||
* the current drive is a per-process value and can be changed.
|
||||
*
|
||||
* File names relative the current directory on some specific drive,
|
||||
* such as "D:foo/bar", are not interpreted as absolute by this
|
||||
* function, but they obviously are not relative to the normal current
|
||||
* directory as returned by getcwd() or g_get_current_dir()
|
||||
* either. Such paths should be avoided, or need to be handled using
|
||||
* Windows-specific code.
|
||||
*
|
||||
* Returns: %TRUE if @file_name is absolute
|
||||
*/
|
||||
gboolean
|
||||
g_path_is_absolute (const gchar *file_name)
|
||||
{
|
||||
g_return_val_if_fail (file_name != NULL, FALSE);
|
||||
|
||||
if (G_IS_DIR_SEPARATOR (file_name[0]))
|
||||
return TRUE;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
/* Recognize drive letter on native Windows */
|
||||
if (g_ascii_isalpha (file_name[0]) &&
|
||||
file_name[1] == ':' && G_IS_DIR_SEPARATOR (file_name[2]))
|
||||
return TRUE;
|
||||
#endif
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_path_skip_root:
|
||||
* @file_name: a file name
|
||||
*
|
||||
* Returns a pointer into @file_name after the root component,
|
||||
* i.e. after the "/" in UNIX or "C:\" under Windows. If @file_name
|
||||
* is not an absolute path it returns %NULL.
|
||||
*
|
||||
* Returns: a pointer into @file_name after the root component
|
||||
*/
|
||||
const gchar *
|
||||
g_path_skip_root (const gchar *file_name)
|
||||
{
|
||||
g_return_val_if_fail (file_name != NULL, NULL);
|
||||
|
||||
#ifdef G_PLATFORM_WIN32
|
||||
/* Skip \\server\share or //server/share */
|
||||
if (G_IS_DIR_SEPARATOR (file_name[0]) &&
|
||||
G_IS_DIR_SEPARATOR (file_name[1]) &&
|
||||
file_name[2] &&
|
||||
!G_IS_DIR_SEPARATOR (file_name[2]))
|
||||
{
|
||||
gchar *p;
|
||||
p = strchr (file_name + 2, G_DIR_SEPARATOR);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
{
|
||||
gchar *q;
|
||||
|
||||
q = strchr (file_name + 2, '/');
|
||||
if (p == NULL || (q != NULL && q < p))
|
||||
p = q;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (p && p > file_name + 2 && p[1])
|
||||
{
|
||||
file_name = p + 1;
|
||||
|
||||
while (file_name[0] && !G_IS_DIR_SEPARATOR (file_name[0]))
|
||||
file_name++;
|
||||
|
||||
/* Possibly skip a backslash after the share name */
|
||||
if (G_IS_DIR_SEPARATOR (file_name[0]))
|
||||
file_name++;
|
||||
|
||||
return (gchar *)file_name;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Skip initial slashes */
|
||||
if (G_IS_DIR_SEPARATOR (file_name[0]))
|
||||
{
|
||||
while (G_IS_DIR_SEPARATOR (file_name[0]))
|
||||
file_name++;
|
||||
return (gchar *)file_name;
|
||||
}
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
/* Skip X:\ */
|
||||
if (g_ascii_isalpha (file_name[0]) &&
|
||||
file_name[1] == ':' &&
|
||||
G_IS_DIR_SEPARATOR (file_name[2]))
|
||||
return (gchar *)file_name + 3;
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_basename:
|
||||
* @file_name: the name of the file
|
||||
*
|
||||
* Gets the name of the file without any leading directory
|
||||
* components. It returns a pointer into the given file name
|
||||
* string.
|
||||
*
|
||||
* Return value: the name of the file without any leading
|
||||
* directory components
|
||||
*
|
||||
* Deprecated:2.2: Use g_path_get_basename() instead, but notice
|
||||
* that g_path_get_basename() allocates new memory for the
|
||||
* returned string, unlike this function which returns a pointer
|
||||
* into the argument.
|
||||
*/
|
||||
const gchar *
|
||||
g_basename (const gchar *file_name)
|
||||
{
|
||||
gchar *base;
|
||||
|
||||
g_return_val_if_fail (file_name != NULL, NULL);
|
||||
|
||||
base = strrchr (file_name, G_DIR_SEPARATOR);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
{
|
||||
gchar *q;
|
||||
q = strrchr (file_name, '/');
|
||||
if (base == NULL || (q != NULL && q > base))
|
||||
base = q;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (base)
|
||||
return base + 1;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
|
||||
return (gchar*) file_name + 2;
|
||||
#endif
|
||||
|
||||
return (gchar*) file_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_path_get_basename:
|
||||
* @file_name: the name of the file
|
||||
*
|
||||
* Gets the last component of the filename.
|
||||
*
|
||||
* If @file_name ends with a directory separator it gets the component
|
||||
* before the last slash. If @file_name consists only of directory
|
||||
* separators (and on Windows, possibly a drive letter), a single
|
||||
* separator is returned. If @file_name is empty, it gets ".".
|
||||
*
|
||||
* Return value: a newly allocated string containing the last
|
||||
* component of the filename
|
||||
*/
|
||||
gchar *
|
||||
g_path_get_basename (const gchar *file_name)
|
||||
{
|
||||
gssize base;
|
||||
gssize last_nonslash;
|
||||
gsize len;
|
||||
gchar *retval;
|
||||
|
||||
g_return_val_if_fail (file_name != NULL, NULL);
|
||||
|
||||
if (file_name[0] == '\0')
|
||||
return g_strdup (".");
|
||||
|
||||
last_nonslash = strlen (file_name) - 1;
|
||||
|
||||
while (last_nonslash >= 0 && G_IS_DIR_SEPARATOR (file_name [last_nonslash]))
|
||||
last_nonslash--;
|
||||
|
||||
if (last_nonslash == -1)
|
||||
/* string only containing slashes */
|
||||
return g_strdup (G_DIR_SEPARATOR_S);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
if (last_nonslash == 1 &&
|
||||
g_ascii_isalpha (file_name[0]) &&
|
||||
file_name[1] == ':')
|
||||
/* string only containing slashes and a drive */
|
||||
return g_strdup (G_DIR_SEPARATOR_S);
|
||||
#endif
|
||||
base = last_nonslash;
|
||||
|
||||
while (base >=0 && !G_IS_DIR_SEPARATOR (file_name [base]))
|
||||
base--;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
if (base == -1 &&
|
||||
g_ascii_isalpha (file_name[0]) &&
|
||||
file_name[1] == ':')
|
||||
base = 1;
|
||||
#endif /* G_OS_WIN32 */
|
||||
|
||||
len = last_nonslash - base;
|
||||
retval = g_malloc (len + 1);
|
||||
memcpy (retval, file_name + base + 1, len);
|
||||
retval [len] = '\0';
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dirname:
|
||||
* @file_name: the name of the file
|
||||
*
|
||||
* Gets the directory components of a file name.
|
||||
*
|
||||
* If the file name has no directory components "." is returned.
|
||||
* The returned string should be freed when no longer needed.
|
||||
*
|
||||
* Returns: the directory components of the file
|
||||
*
|
||||
* Deprecated: use g_path_get_dirname() instead
|
||||
*/
|
||||
|
||||
/**
|
||||
* g_path_get_dirname:
|
||||
* @file_name: the name of the file
|
||||
*
|
||||
* Gets the directory components of a file name.
|
||||
*
|
||||
* If the file name has no directory components "." is returned.
|
||||
* The returned string should be freed when no longer needed.
|
||||
*
|
||||
* Returns: the directory components of the file
|
||||
*/
|
||||
gchar *
|
||||
g_path_get_dirname (const gchar *file_name)
|
||||
{
|
||||
gchar *base;
|
||||
gsize len;
|
||||
|
||||
g_return_val_if_fail (file_name != NULL, NULL);
|
||||
|
||||
base = strrchr (file_name, G_DIR_SEPARATOR);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
{
|
||||
gchar *q;
|
||||
q = strrchr (file_name, '/');
|
||||
if (base == NULL || (q != NULL && q > base))
|
||||
base = q;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!base)
|
||||
{
|
||||
#ifdef G_OS_WIN32
|
||||
if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
|
||||
{
|
||||
gchar drive_colon_dot[4];
|
||||
|
||||
drive_colon_dot[0] = file_name[0];
|
||||
drive_colon_dot[1] = ':';
|
||||
drive_colon_dot[2] = '.';
|
||||
drive_colon_dot[3] = '\0';
|
||||
|
||||
return g_strdup (drive_colon_dot);
|
||||
}
|
||||
#endif
|
||||
return g_strdup (".");
|
||||
}
|
||||
|
||||
while (base > file_name && G_IS_DIR_SEPARATOR (*base))
|
||||
base--;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
/* base points to the char before the last slash.
|
||||
*
|
||||
* In case file_name is the root of a drive (X:\) or a child of the
|
||||
* root of a drive (X:\foo), include the slash.
|
||||
*
|
||||
* In case file_name is the root share of an UNC path
|
||||
* (\\server\share), add a slash, returning \\server\share\ .
|
||||
*
|
||||
* In case file_name is a direct child of a share in an UNC path
|
||||
* (\\server\share\foo), include the slash after the share name,
|
||||
* returning \\server\share\ .
|
||||
*/
|
||||
if (base == file_name + 1 &&
|
||||
g_ascii_isalpha (file_name[0]) &&
|
||||
file_name[1] == ':')
|
||||
base++;
|
||||
else if (G_IS_DIR_SEPARATOR (file_name[0]) &&
|
||||
G_IS_DIR_SEPARATOR (file_name[1]) &&
|
||||
file_name[2] &&
|
||||
!G_IS_DIR_SEPARATOR (file_name[2]) &&
|
||||
base >= file_name + 2)
|
||||
{
|
||||
const gchar *p = file_name + 2;
|
||||
while (*p && !G_IS_DIR_SEPARATOR (*p))
|
||||
p++;
|
||||
if (p == base + 1)
|
||||
{
|
||||
len = (guint) strlen (file_name) + 1;
|
||||
base = g_new (gchar, len + 1);
|
||||
strcpy (base, file_name);
|
||||
base[len-1] = G_DIR_SEPARATOR;
|
||||
base[len] = 0;
|
||||
return base;
|
||||
}
|
||||
if (G_IS_DIR_SEPARATOR (*p))
|
||||
{
|
||||
p++;
|
||||
while (*p && !G_IS_DIR_SEPARATOR (*p))
|
||||
p++;
|
||||
if (p == base + 1)
|
||||
base++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
len = (guint) 1 + base - file_name;
|
||||
base = g_new (gchar, len + 1);
|
||||
g_memmove (base, file_name, len);
|
||||
base[len] = 0;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
#if defined(MAXPATHLEN)
|
||||
#define G_PATH_LENGTH MAXPATHLEN
|
||||
#elif defined(PATH_MAX)
|
||||
#define G_PATH_LENGTH PATH_MAX
|
||||
#elif defined(_PC_PATH_MAX)
|
||||
#define G_PATH_LENGTH sysconf(_PC_PATH_MAX)
|
||||
#else
|
||||
#define G_PATH_LENGTH 2048
|
||||
#endif
|
||||
|
||||
/**
|
||||
* g_get_current_dir:
|
||||
*
|
||||
* Gets the current directory.
|
||||
*
|
||||
* The returned string should be freed when no longer needed.
|
||||
* The encoding of the returned string is system defined.
|
||||
* On Windows, it is always UTF-8.
|
||||
*
|
||||
* Returns: the current directory
|
||||
*/
|
||||
gchar *
|
||||
g_get_current_dir (void)
|
||||
{
|
||||
#ifdef G_OS_WIN32
|
||||
|
||||
gchar *dir = NULL;
|
||||
wchar_t dummy[2], *wdir;
|
||||
int len;
|
||||
|
||||
len = GetCurrentDirectoryW (2, dummy);
|
||||
wdir = g_new (wchar_t, len);
|
||||
|
||||
if (GetCurrentDirectoryW (len, wdir) == len - 1)
|
||||
dir = g_utf16_to_utf8 (wdir, -1, NULL, NULL, NULL);
|
||||
|
||||
g_free (wdir);
|
||||
|
||||
if (dir == NULL)
|
||||
dir = g_strdup ("\\");
|
||||
|
||||
return dir;
|
||||
|
||||
#else
|
||||
|
||||
gchar *buffer = NULL;
|
||||
gchar *dir = NULL;
|
||||
static gulong max_len = 0;
|
||||
|
||||
if (max_len == 0)
|
||||
max_len = (G_PATH_LENGTH == -1) ? 2048 : G_PATH_LENGTH;
|
||||
|
||||
/* We don't use getcwd(3) on SUNOS, because, it does a popen("pwd")
|
||||
* and, if that wasn't bad enough, hangs in doing so.
|
||||
*/
|
||||
#if (defined (sun) && !defined (__SVR4)) || !defined(HAVE_GETCWD)
|
||||
buffer = g_new (gchar, max_len + 1);
|
||||
*buffer = 0;
|
||||
dir = getwd (buffer);
|
||||
#else
|
||||
while (max_len < G_MAXULONG / 2)
|
||||
{
|
||||
g_free (buffer);
|
||||
buffer = g_new (gchar, max_len + 1);
|
||||
*buffer = 0;
|
||||
dir = getcwd (buffer, max_len);
|
||||
|
||||
if (dir || errno != ERANGE)
|
||||
break;
|
||||
|
||||
max_len *= 2;
|
||||
}
|
||||
#endif /* !sun || !HAVE_GETCWD */
|
||||
|
||||
if (!dir || !*buffer)
|
||||
{
|
||||
/* hm, should we g_error() out here?
|
||||
* this can happen if e.g. "./" has mode \0000
|
||||
*/
|
||||
buffer[0] = G_DIR_SEPARATOR;
|
||||
buffer[1] = 0;
|
||||
}
|
||||
|
||||
dir = g_strdup (buffer);
|
||||
g_free (buffer);
|
||||
|
||||
return dir;
|
||||
|
||||
#endif /* !G_OS_WIN32 */
|
||||
}
|
||||
|
||||
|
||||
/* NOTE : Keep this part last to ensure nothing in this file uses thn
|
||||
* below binary compatibility versions.
|
||||
*/
|
||||
#if defined (G_OS_WIN32) && !defined (_WIN64)
|
||||
@ -2458,4 +2639,16 @@ g_file_open_tmp (const gchar *tmpl,
|
||||
return retval;
|
||||
}
|
||||
|
||||
#undef g_get_current_dir
|
||||
|
||||
gchar *
|
||||
g_get_current_dir (void)
|
||||
{
|
||||
gchar *utf8_dir = g_get_current_dir_utf8 ();
|
||||
gchar *dir = g_locale_from_utf8 (utf8_dir, -1, NULL, NULL, NULL);
|
||||
g_free (utf8_dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -60,7 +60,7 @@ typedef enum
|
||||
G_FILE_ERROR_FAILED
|
||||
} GFileError;
|
||||
|
||||
/* For backward-compat reasons, these are synced to an old
|
||||
/* For backward-compat reasons, these are synced to an old
|
||||
* anonymous enum in libgnome. But don't use that enum
|
||||
* in new code.
|
||||
*/
|
||||
@ -90,14 +90,14 @@ gboolean g_file_test (const gchar *filename,
|
||||
GFileTest test);
|
||||
gboolean g_file_get_contents (const gchar *filename,
|
||||
gchar **contents,
|
||||
gsize *length,
|
||||
gsize *length,
|
||||
GError **error);
|
||||
gboolean g_file_set_contents (const gchar *filename,
|
||||
const gchar *contents,
|
||||
gssize length,
|
||||
GError **error);
|
||||
const gchar *contents,
|
||||
gssize length,
|
||||
GError **error);
|
||||
gchar *g_file_read_link (const gchar *filename,
|
||||
GError **error);
|
||||
GError **error);
|
||||
|
||||
/* Wrapper / workalike for mkdtemp() */
|
||||
gchar *g_mkdtemp (gchar *tmpl);
|
||||
@ -105,46 +105,73 @@ gchar *g_mkdtemp_full (gchar *tmpl,
|
||||
gint mode);
|
||||
|
||||
/* Wrapper / workalike for mkstemp() */
|
||||
gint g_mkstemp (gchar *tmpl);
|
||||
gint g_mkstemp_full (gchar *tmpl,
|
||||
gint flags,
|
||||
gint mode);
|
||||
gint g_mkstemp (gchar *tmpl);
|
||||
gint g_mkstemp_full (gchar *tmpl,
|
||||
gint flags,
|
||||
gint mode);
|
||||
|
||||
/* Wrappers for g_mkstemp and g_mkdtemp() */
|
||||
gint g_file_open_tmp (const gchar *tmpl,
|
||||
gchar **name_used,
|
||||
GError **error);
|
||||
gchar *g_dir_make_tmp (const gchar *tmpl,
|
||||
GError **error);
|
||||
gint g_file_open_tmp (const gchar *tmpl,
|
||||
gchar **name_used,
|
||||
GError **error);
|
||||
gchar *g_dir_make_tmp (const gchar *tmpl,
|
||||
GError **error);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
G_FORMAT_SIZE_DEFAULT = 0,
|
||||
G_FORMAT_SIZE_LONG_FORMAT = 1 << 0,
|
||||
G_FORMAT_SIZE_IEC_UNITS = 1 << 1
|
||||
} GFormatSizeFlags;
|
||||
gchar *g_build_path (const gchar *separator,
|
||||
const gchar *first_element,
|
||||
...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED;
|
||||
gchar *g_build_pathv (const gchar *separator,
|
||||
gchar **args) G_GNUC_MALLOC;
|
||||
|
||||
gchar * g_format_size_full (guint64 size,
|
||||
GFormatSizeFlags flags);
|
||||
gchar * g_format_size (guint64 size);
|
||||
gchar *g_build_filename (const gchar *first_element,
|
||||
...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED;
|
||||
gchar *g_build_filenamev (gchar **args) G_GNUC_MALLOC;
|
||||
|
||||
gint g_mkdir_with_parents (const gchar *pathname,
|
||||
gint mode);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
|
||||
/* On Win32, the canonical directory separator is the backslash, and
|
||||
* the search path separator is the semicolon. Note that also the
|
||||
* (forward) slash works as directory separator.
|
||||
*/
|
||||
#define G_DIR_SEPARATOR '\\'
|
||||
#define G_DIR_SEPARATOR_S "\\"
|
||||
#define G_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR || (c) == '/')
|
||||
#define G_SEARCHPATH_SEPARATOR ';'
|
||||
#define G_SEARCHPATH_SEPARATOR_S ";"
|
||||
|
||||
#else /* !G_OS_WIN32 */
|
||||
|
||||
#define G_DIR_SEPARATOR '/'
|
||||
#define G_DIR_SEPARATOR_S "/"
|
||||
#define G_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR)
|
||||
#define G_SEARCHPATH_SEPARATOR ':'
|
||||
#define G_SEARCHPATH_SEPARATOR_S ":"
|
||||
|
||||
#endif /* !G_OS_WIN32 */
|
||||
|
||||
gboolean g_path_is_absolute (const gchar *file_name);
|
||||
const gchar *g_path_skip_root (const gchar *file_name);
|
||||
|
||||
#ifndef G_DISABLE_DEPRECATED
|
||||
GLIB_DEPRECATED_FOR(g_format_size)
|
||||
char *g_format_size_for_display (goffset size);
|
||||
|
||||
GLIB_DEPRECATED_FOR(g_path_get_basename)
|
||||
const gchar *g_basename (const gchar *file_name);
|
||||
#define g_dirname g_path_get_dirname
|
||||
|
||||
#endif /* G_DISABLE_DEPRECATED */
|
||||
|
||||
#ifndef __GTK_DOC_IGNORE__
|
||||
#ifdef G_OS_WIN32
|
||||
#define g_get_current_dir g_get_current_dir_utf8
|
||||
#endif
|
||||
#endif
|
||||
|
||||
gchar *g_build_path (const gchar *separator,
|
||||
const gchar *first_element,
|
||||
...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED;
|
||||
gchar *g_build_pathv (const gchar *separator,
|
||||
gchar **args) G_GNUC_MALLOC;
|
||||
|
||||
gchar *g_build_filename (const gchar *first_element,
|
||||
...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED;
|
||||
gchar *g_build_filenamev (gchar **args) G_GNUC_MALLOC;
|
||||
|
||||
int g_mkdir_with_parents (const gchar *pathname,
|
||||
int mode);
|
||||
gchar *g_get_current_dir (void);
|
||||
gchar *g_path_get_basename (const gchar *file_name) G_GNUC_MALLOC;
|
||||
gchar *g_path_get_dirname (const gchar *file_name) G_GNUC_MALLOC;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
679
glib/gutils.c
679
glib/gutils.c
@ -88,16 +88,6 @@
|
||||
* These are portable utility functions.
|
||||
*/
|
||||
|
||||
#ifdef MAXPATHLEN
|
||||
#define G_PATH_LENGTH MAXPATHLEN
|
||||
#elif defined (PATH_MAX)
|
||||
#define G_PATH_LENGTH PATH_MAX
|
||||
#elif defined (_PC_PATH_MAX)
|
||||
#define G_PATH_LENGTH sysconf(_PC_PATH_MAX)
|
||||
#else
|
||||
#define G_PATH_LENGTH 2048
|
||||
#endif
|
||||
|
||||
#ifdef G_PLATFORM_WIN32
|
||||
# include <windows.h>
|
||||
# ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
|
||||
@ -548,222 +538,6 @@ g_find_program_in_path (const gchar *program)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_basename:
|
||||
* @file_name: the name of the file.
|
||||
*
|
||||
* Gets the name of the file without any leading directory components.
|
||||
* It returns a pointer into the given file name string.
|
||||
*
|
||||
* Return value: the name of the file without any leading directory components.
|
||||
*
|
||||
* Deprecated:2.2: Use g_path_get_basename() instead, but notice that
|
||||
* g_path_get_basename() allocates new memory for the returned string, unlike
|
||||
* this function which returns a pointer into the argument.
|
||||
**/
|
||||
const gchar *
|
||||
g_basename (const gchar *file_name)
|
||||
{
|
||||
register gchar *base;
|
||||
|
||||
g_return_val_if_fail (file_name != NULL, NULL);
|
||||
|
||||
base = strrchr (file_name, G_DIR_SEPARATOR);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
{
|
||||
gchar *q = strrchr (file_name, '/');
|
||||
if (base == NULL || (q != NULL && q > base))
|
||||
base = q;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (base)
|
||||
return base + 1;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
|
||||
return (gchar*) file_name + 2;
|
||||
#endif /* G_OS_WIN32 */
|
||||
|
||||
return (gchar*) file_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_path_get_basename:
|
||||
* @file_name: the name of the file.
|
||||
*
|
||||
* Gets the last component of the filename. If @file_name ends with a
|
||||
* directory separator it gets the component before the last slash. If
|
||||
* @file_name consists only of directory separators (and on Windows,
|
||||
* possibly a drive letter), a single separator is returned. If
|
||||
* @file_name is empty, it gets ".".
|
||||
*
|
||||
* Return value: a newly allocated string containing the last component of
|
||||
* the filename.
|
||||
*/
|
||||
gchar*
|
||||
g_path_get_basename (const gchar *file_name)
|
||||
{
|
||||
register gssize base;
|
||||
register gssize last_nonslash;
|
||||
gsize len;
|
||||
gchar *retval;
|
||||
|
||||
g_return_val_if_fail (file_name != NULL, NULL);
|
||||
|
||||
if (file_name[0] == '\0')
|
||||
/* empty string */
|
||||
return g_strdup (".");
|
||||
|
||||
last_nonslash = strlen (file_name) - 1;
|
||||
|
||||
while (last_nonslash >= 0 && G_IS_DIR_SEPARATOR (file_name [last_nonslash]))
|
||||
last_nonslash--;
|
||||
|
||||
if (last_nonslash == -1)
|
||||
/* string only containing slashes */
|
||||
return g_strdup (G_DIR_SEPARATOR_S);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
if (last_nonslash == 1 && g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
|
||||
/* string only containing slashes and a drive */
|
||||
return g_strdup (G_DIR_SEPARATOR_S);
|
||||
#endif /* G_OS_WIN32 */
|
||||
|
||||
base = last_nonslash;
|
||||
|
||||
while (base >=0 && !G_IS_DIR_SEPARATOR (file_name [base]))
|
||||
base--;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
if (base == -1 && g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
|
||||
base = 1;
|
||||
#endif /* G_OS_WIN32 */
|
||||
|
||||
len = last_nonslash - base;
|
||||
retval = g_malloc (len + 1);
|
||||
memcpy (retval, file_name + base + 1, len);
|
||||
retval [len] = '\0';
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_path_is_absolute:
|
||||
* @file_name: a file name.
|
||||
*
|
||||
* Returns %TRUE if the given @file_name is an absolute file name.
|
||||
* Note that this is a somewhat vague concept on Windows.
|
||||
*
|
||||
* On POSIX systems, an absolute file name is well-defined. It always
|
||||
* starts from the single root directory. For example "/usr/local".
|
||||
*
|
||||
* On Windows, the concepts of current drive and drive-specific
|
||||
* current directory introduce vagueness. This function interprets as
|
||||
* an absolute file name one that either begins with a directory
|
||||
* separator such as "\Users\tml" or begins with the root on a drive,
|
||||
* for example "C:\Windows". The first case also includes UNC paths
|
||||
* such as "\\myserver\docs\foo". In all cases, either slashes or
|
||||
* backslashes are accepted.
|
||||
*
|
||||
* Note that a file name relative to the current drive root does not
|
||||
* truly specify a file uniquely over time and across processes, as
|
||||
* the current drive is a per-process value and can be changed.
|
||||
*
|
||||
* File names relative the current directory on some specific drive,
|
||||
* such as "D:foo/bar", are not interpreted as absolute by this
|
||||
* function, but they obviously are not relative to the normal current
|
||||
* directory as returned by getcwd() or g_get_current_dir()
|
||||
* either. Such paths should be avoided, or need to be handled using
|
||||
* Windows-specific code.
|
||||
*
|
||||
* Returns: %TRUE if @file_name is absolute.
|
||||
*/
|
||||
gboolean
|
||||
g_path_is_absolute (const gchar *file_name)
|
||||
{
|
||||
g_return_val_if_fail (file_name != NULL, FALSE);
|
||||
|
||||
if (G_IS_DIR_SEPARATOR (file_name[0]))
|
||||
return TRUE;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
/* Recognize drive letter on native Windows */
|
||||
if (g_ascii_isalpha (file_name[0]) &&
|
||||
file_name[1] == ':' && G_IS_DIR_SEPARATOR (file_name[2]))
|
||||
return TRUE;
|
||||
#endif /* G_OS_WIN32 */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_path_skip_root:
|
||||
* @file_name: a file name.
|
||||
*
|
||||
* Returns a pointer into @file_name after the root component, i.e. after
|
||||
* the "/" in UNIX or "C:\" under Windows. If @file_name is not an absolute
|
||||
* path it returns %NULL.
|
||||
*
|
||||
* Returns: a pointer into @file_name after the root component.
|
||||
*/
|
||||
const gchar *
|
||||
g_path_skip_root (const gchar *file_name)
|
||||
{
|
||||
g_return_val_if_fail (file_name != NULL, NULL);
|
||||
|
||||
#ifdef G_PLATFORM_WIN32
|
||||
/* Skip \\server\share or //server/share */
|
||||
if (G_IS_DIR_SEPARATOR (file_name[0]) &&
|
||||
G_IS_DIR_SEPARATOR (file_name[1]) &&
|
||||
file_name[2] &&
|
||||
!G_IS_DIR_SEPARATOR (file_name[2]))
|
||||
{
|
||||
gchar *p;
|
||||
|
||||
p = strchr (file_name + 2, G_DIR_SEPARATOR);
|
||||
#ifdef G_OS_WIN32
|
||||
{
|
||||
gchar *q = strchr (file_name + 2, '/');
|
||||
if (p == NULL || (q != NULL && q < p))
|
||||
p = q;
|
||||
}
|
||||
#endif
|
||||
if (p &&
|
||||
p > file_name + 2 &&
|
||||
p[1])
|
||||
{
|
||||
file_name = p + 1;
|
||||
|
||||
while (file_name[0] && !G_IS_DIR_SEPARATOR (file_name[0]))
|
||||
file_name++;
|
||||
|
||||
/* Possibly skip a backslash after the share name */
|
||||
if (G_IS_DIR_SEPARATOR (file_name[0]))
|
||||
file_name++;
|
||||
|
||||
return (gchar *)file_name;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Skip initial slashes */
|
||||
if (G_IS_DIR_SEPARATOR (file_name[0]))
|
||||
{
|
||||
while (G_IS_DIR_SEPARATOR (file_name[0]))
|
||||
file_name++;
|
||||
return (gchar *)file_name;
|
||||
}
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
/* Skip X:\ */
|
||||
if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':' && G_IS_DIR_SEPARATOR (file_name[2]))
|
||||
return (gchar *)file_name + 3;
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_bit_nth_lsf:
|
||||
* @mask: a #gulong containing flags
|
||||
@ -801,197 +575,6 @@ g_path_skip_root (const gchar *file_name)
|
||||
* Returns: the number of bits used to hold @number
|
||||
*/
|
||||
|
||||
/**
|
||||
* g_dirname:
|
||||
* @file_name: the name of the file
|
||||
*
|
||||
* Gets the directory components of a file name.
|
||||
* If the file name has no directory components "." is returned.
|
||||
* The returned string should be freed when no longer needed.
|
||||
*
|
||||
* Returns: the directory components of the file
|
||||
*
|
||||
* Deprecated: use g_path_get_dirname() instead
|
||||
*/
|
||||
|
||||
/**
|
||||
* g_path_get_dirname:
|
||||
* @file_name: the name of the file.
|
||||
*
|
||||
* Gets the directory components of a file name. If the file name has no
|
||||
* directory components "." is returned. The returned string should be
|
||||
* freed when no longer needed.
|
||||
*
|
||||
* Returns: the directory components of the file.
|
||||
*/
|
||||
gchar*
|
||||
g_path_get_dirname (const gchar *file_name)
|
||||
{
|
||||
register gchar *base;
|
||||
register gsize len;
|
||||
|
||||
g_return_val_if_fail (file_name != NULL, NULL);
|
||||
|
||||
base = strrchr (file_name, G_DIR_SEPARATOR);
|
||||
#ifdef G_OS_WIN32
|
||||
{
|
||||
gchar *q = strrchr (file_name, '/');
|
||||
if (base == NULL || (q != NULL && q > base))
|
||||
base = q;
|
||||
}
|
||||
#endif
|
||||
if (!base)
|
||||
{
|
||||
#ifdef G_OS_WIN32
|
||||
if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
|
||||
{
|
||||
gchar drive_colon_dot[4];
|
||||
|
||||
drive_colon_dot[0] = file_name[0];
|
||||
drive_colon_dot[1] = ':';
|
||||
drive_colon_dot[2] = '.';
|
||||
drive_colon_dot[3] = '\0';
|
||||
|
||||
return g_strdup (drive_colon_dot);
|
||||
}
|
||||
#endif
|
||||
return g_strdup (".");
|
||||
}
|
||||
|
||||
while (base > file_name && G_IS_DIR_SEPARATOR (*base))
|
||||
base--;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
/* base points to the char before the last slash.
|
||||
*
|
||||
* In case file_name is the root of a drive (X:\) or a child of the
|
||||
* root of a drive (X:\foo), include the slash.
|
||||
*
|
||||
* In case file_name is the root share of an UNC path
|
||||
* (\\server\share), add a slash, returning \\server\share\ .
|
||||
*
|
||||
* In case file_name is a direct child of a share in an UNC path
|
||||
* (\\server\share\foo), include the slash after the share name,
|
||||
* returning \\server\share\ .
|
||||
*/
|
||||
if (base == file_name + 1 && g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
|
||||
base++;
|
||||
else if (G_IS_DIR_SEPARATOR (file_name[0]) &&
|
||||
G_IS_DIR_SEPARATOR (file_name[1]) &&
|
||||
file_name[2] &&
|
||||
!G_IS_DIR_SEPARATOR (file_name[2]) &&
|
||||
base >= file_name + 2)
|
||||
{
|
||||
const gchar *p = file_name + 2;
|
||||
while (*p && !G_IS_DIR_SEPARATOR (*p))
|
||||
p++;
|
||||
if (p == base + 1)
|
||||
{
|
||||
len = (guint) strlen (file_name) + 1;
|
||||
base = g_new (gchar, len + 1);
|
||||
strcpy (base, file_name);
|
||||
base[len-1] = G_DIR_SEPARATOR;
|
||||
base[len] = 0;
|
||||
return base;
|
||||
}
|
||||
if (G_IS_DIR_SEPARATOR (*p))
|
||||
{
|
||||
p++;
|
||||
while (*p && !G_IS_DIR_SEPARATOR (*p))
|
||||
p++;
|
||||
if (p == base + 1)
|
||||
base++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
len = (guint) 1 + base - file_name;
|
||||
|
||||
base = g_new (gchar, len + 1);
|
||||
g_memmove (base, file_name, len);
|
||||
base[len] = 0;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_get_current_dir:
|
||||
*
|
||||
* Gets the current directory.
|
||||
* The returned string should be freed when no longer needed. The encoding
|
||||
* of the returned string is system defined. On Windows, it is always UTF-8.
|
||||
*
|
||||
* Returns: the current directory.
|
||||
*/
|
||||
gchar*
|
||||
g_get_current_dir (void)
|
||||
{
|
||||
#ifdef G_OS_WIN32
|
||||
|
||||
gchar *dir = NULL;
|
||||
wchar_t dummy[2], *wdir;
|
||||
int len;
|
||||
|
||||
len = GetCurrentDirectoryW (2, dummy);
|
||||
wdir = g_new (wchar_t, len);
|
||||
|
||||
if (GetCurrentDirectoryW (len, wdir) == len - 1)
|
||||
dir = g_utf16_to_utf8 (wdir, -1, NULL, NULL, NULL);
|
||||
|
||||
g_free (wdir);
|
||||
|
||||
if (dir == NULL)
|
||||
dir = g_strdup ("\\");
|
||||
|
||||
return dir;
|
||||
|
||||
#else
|
||||
|
||||
gchar *buffer = NULL;
|
||||
gchar *dir = NULL;
|
||||
static gulong max_len = 0;
|
||||
|
||||
if (max_len == 0)
|
||||
max_len = (G_PATH_LENGTH == -1) ? 2048 : G_PATH_LENGTH;
|
||||
|
||||
/* We don't use getcwd(3) on SUNOS, because, it does a popen("pwd")
|
||||
* and, if that wasn't bad enough, hangs in doing so.
|
||||
*/
|
||||
#if (defined (sun) && !defined (__SVR4)) || !defined(HAVE_GETCWD)
|
||||
buffer = g_new (gchar, max_len + 1);
|
||||
*buffer = 0;
|
||||
dir = getwd (buffer);
|
||||
#else /* !sun || !HAVE_GETCWD */
|
||||
while (max_len < G_MAXULONG / 2)
|
||||
{
|
||||
g_free (buffer);
|
||||
buffer = g_new (gchar, max_len + 1);
|
||||
*buffer = 0;
|
||||
dir = getcwd (buffer, max_len);
|
||||
|
||||
if (dir || errno != ERANGE)
|
||||
break;
|
||||
|
||||
max_len *= 2;
|
||||
}
|
||||
#endif /* !sun || !HAVE_GETCWD */
|
||||
|
||||
if (!dir || !*buffer)
|
||||
{
|
||||
/* hm, should we g_error() out here?
|
||||
* this can happen if e.g. "./" has mode \0000
|
||||
*/
|
||||
buffer[0] = G_DIR_SEPARATOR;
|
||||
buffer[1] = 0;
|
||||
}
|
||||
|
||||
dir = g_strdup (buffer);
|
||||
g_free (buffer);
|
||||
|
||||
return dir;
|
||||
#endif /* !Win32 */
|
||||
}
|
||||
|
||||
G_LOCK_DEFINE_STATIC (g_utils_global);
|
||||
|
||||
static gchar *g_tmp_dir = NULL;
|
||||
@ -2499,6 +2082,257 @@ g_nullify_pointer (gpointer *nullify_location)
|
||||
*nullify_location = NULL;
|
||||
}
|
||||
|
||||
#define KILOBYTE_FACTOR (G_GOFFSET_CONSTANT (1000))
|
||||
#define MEGABYTE_FACTOR (KILOBYTE_FACTOR * KILOBYTE_FACTOR)
|
||||
#define GIGABYTE_FACTOR (MEGABYTE_FACTOR * KILOBYTE_FACTOR)
|
||||
#define TERABYTE_FACTOR (GIGABYTE_FACTOR * KILOBYTE_FACTOR)
|
||||
#define PETABYTE_FACTOR (TERABYTE_FACTOR * KILOBYTE_FACTOR)
|
||||
#define EXABYTE_FACTOR (PETABYTE_FACTOR * KILOBYTE_FACTOR)
|
||||
|
||||
#define KIBIBYTE_FACTOR (G_GOFFSET_CONSTANT (1024))
|
||||
#define MEBIBYTE_FACTOR (KIBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
||||
#define GIBIBYTE_FACTOR (MEBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
||||
#define TEBIBYTE_FACTOR (GIBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
||||
#define PEBIBYTE_FACTOR (TEBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
||||
#define EXBIBYTE_FACTOR (PEBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
||||
|
||||
/**
|
||||
* g_format_size:
|
||||
* @size: a size in bytes
|
||||
*
|
||||
* Formats a size (for example the size of a file) into a human readable
|
||||
* string. Sizes are rounded to the nearest size prefix (kB, MB, GB)
|
||||
* and are displayed rounded to the nearest tenth. E.g. the file size
|
||||
* 3292528 bytes will be converted into the string "3.2 MB".
|
||||
*
|
||||
* The prefix units base is 1000 (i.e. 1 kB is 1000 bytes).
|
||||
*
|
||||
* This string should be freed with g_free() when not needed any longer.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Since: 2.30
|
||||
*/
|
||||
gchar *
|
||||
g_format_size (guint64 size)
|
||||
{
|
||||
return g_format_size_full (size, G_FORMAT_SIZE_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* GFormatSizeFlags:
|
||||
* @G_FORMAT_SIZE_DEFAULT: behave the same as g_format_size()
|
||||
* @G_FORMAT_SIZE_LONG_FORMAT: include the exact number of bytes as part
|
||||
* of the returned string. For example, "45.6 kB (45,612 bytes)".
|
||||
* @G_FORMAT_SIZE_IEC_UNITS: use IEC (base 1024) units with "KiB"-style
|
||||
* suffixes. IEC units should only be used for reporting things with
|
||||
* a strong "power of 2" basis, like RAM sizes or RAID stripe sizes.
|
||||
* Network and storage sizes should be reported in the normal SI units.
|
||||
*
|
||||
* Flags to modify the format of the string returned by g_format_size_full().
|
||||
*/
|
||||
|
||||
/**
|
||||
* g_format_size_full:
|
||||
* @size: a size in bytes
|
||||
* @flags: #GFormatSizeFlags to modify the output
|
||||
*
|
||||
* Formats a size.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Since: 2.30
|
||||
*/
|
||||
gchar *
|
||||
g_format_size_full (guint64 size,
|
||||
GFormatSizeFlags flags)
|
||||
{
|
||||
GString *string;
|
||||
|
||||
string = g_string_new (NULL);
|
||||
|
||||
if (flags & G_FORMAT_SIZE_IEC_UNITS)
|
||||
{
|
||||
if (size < KIBIBYTE_FACTOR)
|
||||
{
|
||||
g_string_printf (string,
|
||||
g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes", (guint) size),
|
||||
(guint) size);
|
||||
flags &= ~G_FORMAT_SIZE_LONG_FORMAT;
|
||||
}
|
||||
|
||||
else if (size < MEBIBYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f KiB"), (gdouble) size / (gdouble) KIBIBYTE_FACTOR);
|
||||
else if (size < GIBIBYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f MiB"), (gdouble) size / (gdouble) MEBIBYTE_FACTOR);
|
||||
|
||||
else if (size < TEBIBYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f GiB"), (gdouble) size / (gdouble) GIBIBYTE_FACTOR);
|
||||
|
||||
else if (size < PEBIBYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f TiB"), (gdouble) size / (gdouble) TEBIBYTE_FACTOR);
|
||||
|
||||
else if (size < EXBIBYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f PiB"), (gdouble) size / (gdouble) PEBIBYTE_FACTOR);
|
||||
|
||||
else
|
||||
g_string_printf (string, _("%.1f EiB"), (gdouble) size / (gdouble) EXBIBYTE_FACTOR);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (size < KILOBYTE_FACTOR)
|
||||
{
|
||||
g_string_printf (string,
|
||||
g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes", (guint) size),
|
||||
(guint) size);
|
||||
flags &= ~G_FORMAT_SIZE_LONG_FORMAT;
|
||||
}
|
||||
|
||||
else if (size < MEGABYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f kB"), (gdouble) size / (gdouble) KILOBYTE_FACTOR);
|
||||
|
||||
else if (size < GIGABYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f MB"), (gdouble) size / (gdouble) MEGABYTE_FACTOR);
|
||||
|
||||
else if (size < TERABYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f GB"), (gdouble) size / (gdouble) GIGABYTE_FACTOR);
|
||||
else if (size < PETABYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f TB"), (gdouble) size / (gdouble) TERABYTE_FACTOR);
|
||||
|
||||
else if (size < EXABYTE_FACTOR)
|
||||
g_string_printf (string, _("%.1f PB"), (gdouble) size / (gdouble) PETABYTE_FACTOR);
|
||||
|
||||
else
|
||||
g_string_printf (string, _("%.1f EB"), (gdouble) size / (gdouble) EXABYTE_FACTOR);
|
||||
}
|
||||
|
||||
if (flags & G_FORMAT_SIZE_LONG_FORMAT)
|
||||
{
|
||||
/* First problem: we need to use the number of bytes to decide on
|
||||
* the plural form that is used for display, but the number of
|
||||
* bytes potentially exceeds the size of a guint (which is what
|
||||
* ngettext() takes).
|
||||
*
|
||||
* From a pragmatic standpoint, it seems that all known languages
|
||||
* base plural forms on one or both of the following:
|
||||
*
|
||||
* - the lowest digits of the number
|
||||
*
|
||||
* - if the number if greater than some small value
|
||||
*
|
||||
* Here's how we fake it: Draw an arbitrary line at one thousand.
|
||||
* If the number is below that, then fine. If it is above it,
|
||||
* then we take the modulus of the number by one thousand (in
|
||||
* order to keep the lowest digits) and add one thousand to that
|
||||
* (in order to ensure that 1001 is not treated the same as 1).
|
||||
*/
|
||||
guint plural_form = size < 1000 ? size : size % 1000 + 1000;
|
||||
|
||||
/* Second problem: we need to translate the string "%u byte" and
|
||||
* "%u bytes" for pluralisation, but the correct number format to
|
||||
* use for a gsize is different depending on which architecture
|
||||
* we're on.
|
||||
*
|
||||
* Solution: format the number separately and use "%s bytes" on
|
||||
* all platforms.
|
||||
*/
|
||||
const gchar *translated_format;
|
||||
gchar *formatted_number;
|
||||
|
||||
/* Translators: the %s in "%s bytes" will always be replaced by a number. */
|
||||
translated_format = g_dngettext(GETTEXT_PACKAGE, "%s byte", "%s bytes", 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);
|
||||
g_free (formatted_number);
|
||||
g_string_append (string, ")");
|
||||
}
|
||||
|
||||
return g_string_free (string, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_format_size_for_display:
|
||||
* @size: a size in bytes
|
||||
*
|
||||
* Formats a size (for example the size of a file) into a human
|
||||
* readable string. Sizes are rounded to the nearest size prefix
|
||||
* (KB, MB, GB) and are displayed rounded to the nearest tenth.
|
||||
* E.g. the file size 3292528 bytes will be converted into the
|
||||
* string "3.1 MB".
|
||||
*
|
||||
* The prefix units base is 1024 (i.e. 1 KB is 1024 bytes).
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Since: 2.16
|
||||
*
|
||||
* Deprecated:2.30: This function is broken due to its use of SI
|
||||
* suffixes to denote IEC units. Use g_format_size() instead.
|
||||
*/
|
||||
gchar *
|
||||
g_format_size_for_display (goffset size)
|
||||
{
|
||||
if (size < (goffset) KIBIBYTE_FACTOR)
|
||||
return g_strdup_printf (g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes",(guint) size), (guint) size);
|
||||
else
|
||||
{
|
||||
gdouble displayed_size;
|
||||
|
||||
if (size < (goffset) MEBIBYTE_FACTOR)
|
||||
{
|
||||
displayed_size = (gdouble) size / (gdouble) KIBIBYTE_FACTOR;
|
||||
return g_strdup_printf (_("%.1f KB"), displayed_size);
|
||||
}
|
||||
else if (size < (goffset) GIBIBYTE_FACTOR)
|
||||
{
|
||||
displayed_size = (gdouble) size / (gdouble) MEBIBYTE_FACTOR;
|
||||
return g_strdup_printf (_("%.1f MB"), displayed_size);
|
||||
}
|
||||
else if (size < (goffset) TEBIBYTE_FACTOR)
|
||||
{
|
||||
displayed_size = (gdouble) size / (gdouble) GIBIBYTE_FACTOR;
|
||||
return g_strdup_printf (_("%.1f GB"), displayed_size);
|
||||
}
|
||||
else if (size < (goffset) PEBIBYTE_FACTOR)
|
||||
{
|
||||
displayed_size = (gdouble) size / (gdouble) TEBIBYTE_FACTOR;
|
||||
return g_strdup_printf (_("%.1f TB"), displayed_size);
|
||||
}
|
||||
else if (size < (goffset) EXBIBYTE_FACTOR)
|
||||
{
|
||||
displayed_size = (gdouble) size / (gdouble) PEBIBYTE_FACTOR;
|
||||
return g_strdup_printf (_("%.1f PB"), displayed_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
displayed_size = (gdouble) size / (gdouble) EXBIBYTE_FACTOR;
|
||||
return g_strdup_printf (_("%.1f EB"), displayed_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
|
||||
/**
|
||||
@ -2633,17 +2467,6 @@ g_find_program_in_path (const gchar *program)
|
||||
return retval;
|
||||
}
|
||||
|
||||
#undef g_get_current_dir
|
||||
|
||||
gchar*
|
||||
g_get_current_dir (void)
|
||||
{
|
||||
gchar *utf8_dir = g_get_current_dir_utf8 ();
|
||||
gchar *dir = g_locale_from_utf8 (utf8_dir, -1, NULL, NULL, NULL);
|
||||
g_free (utf8_dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
#undef g_get_user_name
|
||||
|
||||
const gchar *
|
||||
|
@ -36,30 +36,6 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
|
||||
/* On Win32, the canonical directory separator is the backslash, and
|
||||
* the search path separator is the semicolon. Note that also the
|
||||
* (forward) slash works as directory separator.
|
||||
*/
|
||||
#define G_DIR_SEPARATOR '\\'
|
||||
#define G_DIR_SEPARATOR_S "\\"
|
||||
#define G_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR || (c) == '/')
|
||||
#define G_SEARCHPATH_SEPARATOR ';'
|
||||
#define G_SEARCHPATH_SEPARATOR_S ";"
|
||||
|
||||
#else /* !G_OS_WIN32 */
|
||||
|
||||
/* Unix */
|
||||
|
||||
#define G_DIR_SEPARATOR '/'
|
||||
#define G_DIR_SEPARATOR_S "/"
|
||||
#define G_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR)
|
||||
#define G_SEARCHPATH_SEPARATOR ':'
|
||||
#define G_SEARCHPATH_SEPARATOR_S ":"
|
||||
|
||||
#endif /* !G_OS_WIN32 */
|
||||
|
||||
/* Define G_VA_COPY() to do the right thing for copying va_list variables.
|
||||
* glibconfig.h may have already defined G_VA_COPY as va_copy or __va_copy.
|
||||
*/
|
||||
@ -222,33 +198,23 @@ gint g_vsnprintf (gchar *string,
|
||||
gchar const *format,
|
||||
va_list args);
|
||||
|
||||
/* Check if a file name is an absolute path */
|
||||
gboolean g_path_is_absolute (const gchar *file_name);
|
||||
void g_nullify_pointer (gpointer *nullify_location);
|
||||
|
||||
/* In case of absolute paths, skip the root part */
|
||||
const gchar * g_path_skip_root (const gchar *file_name);
|
||||
typedef enum
|
||||
{
|
||||
G_FORMAT_SIZE_DEFAULT = 0,
|
||||
G_FORMAT_SIZE_LONG_FORMAT = 1 << 0,
|
||||
G_FORMAT_SIZE_IEC_UNITS = 1 << 1
|
||||
} GFormatSizeFlags;
|
||||
|
||||
gchar *g_format_size_full (guint64 size,
|
||||
GFormatSizeFlags flags);
|
||||
gchar *g_format_size (guint64 size);
|
||||
|
||||
#ifndef G_DISABLE_DEPRECATED
|
||||
|
||||
GLIB_DEPRECATED_FOR(g_path_get_basename)
|
||||
const gchar * g_basename (const gchar *file_name);
|
||||
#define g_dirname g_path_get_dirname
|
||||
|
||||
#endif /* G_DISABLE_DEPRECATED */
|
||||
|
||||
#ifndef __GTK_DOC_IGNORE__
|
||||
#ifdef G_OS_WIN32
|
||||
#define g_get_current_dir g_get_current_dir_utf8
|
||||
GLIB_DEPRECATED_FOR(g_format_size)
|
||||
gchar *g_format_size_for_display (goffset size);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* The returned strings are newly allocated with g_malloc() */
|
||||
gchar* g_get_current_dir (void);
|
||||
gchar* g_path_get_basename (const gchar *file_name) G_GNUC_MALLOC;
|
||||
gchar* g_path_get_dirname (const gchar *file_name) G_GNUC_MALLOC;
|
||||
|
||||
/* Set the pointer at the specified location to NULL */
|
||||
void g_nullify_pointer (gpointer *nullify_location);
|
||||
|
||||
/**
|
||||
* GVoidFunc:
|
||||
|
Loading…
Reference in New Issue
Block a user