Import Upstream version 2.72.4

This commit is contained in:
evinadmin 2023-07-04 11:23:22 +02:00
commit 4ef3ff9793
2003 changed files with 1332420 additions and 0 deletions

View file

@ -0,0 +1,104 @@
/*
* 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/>.
*/
#include "config.h"
/* we know we are deprecated here, no need for warnings */
#ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#endif
#include "gallocator.h"
#include <glib/gmessages.h>
#include <glib/gslice.h>
struct _GMemChunk {
guint alloc_size; /* the size of an atom */
};
GMemChunk*
g_mem_chunk_new (const gchar *name,
gint atom_size,
gsize area_size,
gint type)
{
GMemChunk *mem_chunk;
g_return_val_if_fail (atom_size > 0, NULL);
mem_chunk = g_slice_new (GMemChunk);
mem_chunk->alloc_size = atom_size;
return mem_chunk;
}
void
g_mem_chunk_destroy (GMemChunk *mem_chunk)
{
g_return_if_fail (mem_chunk != NULL);
g_slice_free (GMemChunk, mem_chunk);
}
gpointer
g_mem_chunk_alloc (GMemChunk *mem_chunk)
{
g_return_val_if_fail (mem_chunk != NULL, NULL);
return g_slice_alloc (mem_chunk->alloc_size);
}
gpointer
g_mem_chunk_alloc0 (GMemChunk *mem_chunk)
{
g_return_val_if_fail (mem_chunk != NULL, NULL);
return g_slice_alloc0 (mem_chunk->alloc_size);
}
void
g_mem_chunk_free (GMemChunk *mem_chunk,
gpointer mem)
{
g_return_if_fail (mem_chunk != NULL);
g_slice_free1 (mem_chunk->alloc_size, mem);
}
GAllocator*
g_allocator_new (const gchar *name,
guint n_preallocs)
{
/* some (broken) GAllocator uses depend on non-NULL allocators */
return (void *) 1;
}
void g_allocator_free (GAllocator *allocator) { }
void g_mem_chunk_clean (GMemChunk *mem_chunk) { }
void g_mem_chunk_reset (GMemChunk *mem_chunk) { }
void g_mem_chunk_print (GMemChunk *mem_chunk) { }
void g_mem_chunk_info (void) { }
void g_blow_chunks (void) { }
void g_list_push_allocator (GAllocator *allocator) { }
void g_list_pop_allocator (void) { }
void g_slist_push_allocator (GAllocator *allocator) { }
void g_slist_pop_allocator (void) { }
void g_node_push_allocator (GAllocator *allocator) { }
void g_node_pop_allocator (void) { }

View file

@ -0,0 +1,88 @@
/*
* 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/>.
*/
#ifndef __G_ALLOCATOR_H__
#define __G_ALLOCATOR_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtypes.h>
G_BEGIN_DECLS
typedef struct _GAllocator GAllocator;
typedef struct _GMemChunk GMemChunk;
#define G_ALLOC_ONLY 1
#define G_ALLOC_AND_FREE 2
#define G_ALLOCATOR_LIST 1
#define G_ALLOCATOR_SLIST 2
#define G_ALLOCATOR_NODE 3
#define g_chunk_new(type, chunk) ((type *) g_mem_chunk_alloc (chunk))
#define g_chunk_new0(type, chunk) ((type *) g_mem_chunk_alloc0 (chunk))
#define g_chunk_free(mem, mem_chunk) (g_mem_chunk_free (mem_chunk, mem))
#define g_mem_chunk_create(type, x, y) (g_mem_chunk_new (NULL, sizeof (type), 0, 0))
GLIB_DEPRECATED
GMemChunk * g_mem_chunk_new (const gchar *name,
gint atom_size,
gsize area_size,
gint type);
GLIB_DEPRECATED
void g_mem_chunk_destroy (GMemChunk *mem_chunk);
GLIB_DEPRECATED
gpointer g_mem_chunk_alloc (GMemChunk *mem_chunk);
GLIB_DEPRECATED
gpointer g_mem_chunk_alloc0 (GMemChunk *mem_chunk);
GLIB_DEPRECATED
void g_mem_chunk_free (GMemChunk *mem_chunk,
gpointer mem);
GLIB_DEPRECATED
void g_mem_chunk_clean (GMemChunk *mem_chunk);
GLIB_DEPRECATED
void g_mem_chunk_reset (GMemChunk *mem_chunk);
GLIB_DEPRECATED
void g_mem_chunk_print (GMemChunk *mem_chunk);
GLIB_DEPRECATED
void g_mem_chunk_info (void);
GLIB_DEPRECATED
void g_blow_chunks (void);
GLIB_DEPRECATED
GAllocator * g_allocator_new (const gchar *name,
guint n_preallocs);
GLIB_DEPRECATED
void g_allocator_free (GAllocator *allocator);
GLIB_DEPRECATED
void g_list_push_allocator (GAllocator *allocator);
GLIB_DEPRECATED
void g_list_pop_allocator (void);
GLIB_DEPRECATED
void g_slist_push_allocator (GAllocator *allocator);
GLIB_DEPRECATED
void g_slist_pop_allocator (void);
GLIB_DEPRECATED
void g_node_push_allocator (GAllocator *allocator);
GLIB_DEPRECATED
void g_node_pop_allocator (void);
G_END_DECLS
#endif /* __G_ALLOCATOR_H__ */

350
glib/deprecated/gcache.c Normal file
View file

@ -0,0 +1,350 @@
/* 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.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"
/* we know we are deprecated here, no need for warnings */
#ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#endif
#include "gcache.h"
#include "gslice.h"
#include "ghash.h"
#include "gtestutils.h"
/**
* SECTION:caches
* @title: Caches
* @short_description: caches allow sharing of complex data structures
* to save resources
*
* A #GCache allows sharing of complex data structures, in order to
* save system resources.
*
* GCache uses keys and values. A GCache key describes the properties
* of a particular resource. A GCache value is the actual resource.
*
* GCache has been marked as deprecated, since this API is rarely
* used and not very actively maintained.
*/
typedef struct _GCacheNode GCacheNode;
struct _GCacheNode
{
/* A reference counted node */
gpointer value;
gint ref_count;
};
/**
* GCache:
*
* The #GCache struct is an opaque data structure containing
* information about a #GCache. It should only be accessed via the
* following functions.
*
* Deprecated:2.32: Use a #GHashTable instead
*/
struct _GCache
{
/* Called to create a value from a key */
GCacheNewFunc value_new_func;
/* Called to destroy a value */
GCacheDestroyFunc value_destroy_func;
/* Called to duplicate a key */
GCacheDupFunc key_dup_func;
/* Called to destroy a key */
GCacheDestroyFunc key_destroy_func;
/* Associates keys with nodes */
GHashTable *key_table;
/* Associates nodes with keys */
GHashTable *value_table;
};
static inline GCacheNode*
g_cache_node_new (gpointer value)
{
GCacheNode *node = g_slice_new (GCacheNode);
node->value = value;
node->ref_count = 1;
return node;
}
static inline void
g_cache_node_destroy (GCacheNode *node)
{
g_slice_free (GCacheNode, node);
}
/**
* g_cache_new:
* @value_new_func: a function to create a new object given a key.
* This is called by g_cache_insert() if an object
* with the given key does not already exist
* @value_destroy_func: a function to destroy an object. It is called
* by g_cache_remove() when the object is no
* longer needed (i.e. its reference count drops
* to 0)
* @key_dup_func: a function to copy a key. It is called by
* g_cache_insert() if the key does not already exist in
* the #GCache
* @key_destroy_func: a function to destroy a key. It is called by
* g_cache_remove() when the object is no longer
* needed (i.e. its reference count drops to 0)
* @hash_key_func: a function to create a hash value from a key
* @hash_value_func: a function to create a hash value from a value
* @key_equal_func: a function to compare two keys. It should return
* %TRUE if the two keys are equivalent
*
* Creates a new #GCache.
*
* Returns: a new #GCache
*
* Deprecated:2.32: Use a #GHashTable instead
*/
/**
* GCacheNewFunc:
* @key: a #GCache key
*
* Specifies the type of the @value_new_func function passed to
* g_cache_new(). It is passed a #GCache key and should create the
* value corresponding to the key.
*
* Returns: a new #GCache value corresponding to the key.
*/
/**
* GCacheDestroyFunc:
* @value: the #GCache value to destroy
*
* Specifies the type of the @value_destroy_func and @key_destroy_func
* functions passed to g_cache_new(). The functions are passed a
* pointer to the #GCache key or #GCache value and should free any
* memory and other resources associated with it.
*/
/**
* GCacheDupFunc:
* @value: the #GCache key to destroy (__not__ a
* #GCache value as it seems)
*
* Specifies the type of the @key_dup_func function passed to
* g_cache_new(). The function is passed a key
* (__not__ a value as the prototype implies) and
* should return a duplicate of the key.
*
* Returns: a copy of the #GCache key
*/
GCache*
g_cache_new (GCacheNewFunc value_new_func,
GCacheDestroyFunc value_destroy_func,
GCacheDupFunc key_dup_func,
GCacheDestroyFunc key_destroy_func,
GHashFunc hash_key_func,
GHashFunc hash_value_func,
GEqualFunc key_equal_func)
{
GCache *cache;
g_return_val_if_fail (value_new_func != NULL, NULL);
g_return_val_if_fail (value_destroy_func != NULL, NULL);
g_return_val_if_fail (key_dup_func != NULL, NULL);
g_return_val_if_fail (key_destroy_func != NULL, NULL);
g_return_val_if_fail (hash_key_func != NULL, NULL);
g_return_val_if_fail (hash_value_func != NULL, NULL);
g_return_val_if_fail (key_equal_func != NULL, NULL);
cache = g_slice_new (GCache);
cache->value_new_func = value_new_func;
cache->value_destroy_func = value_destroy_func;
cache->key_dup_func = key_dup_func;
cache->key_destroy_func = key_destroy_func;
cache->key_table = g_hash_table_new (hash_key_func, key_equal_func);
cache->value_table = g_hash_table_new (hash_value_func, NULL);
return cache;
}
/**
* g_cache_destroy:
* @cache: a #GCache
*
* Frees the memory allocated for the #GCache.
*
* Note that it does not destroy the keys and values which were
* contained in the #GCache.
*
* Deprecated:2.32: Use a #GHashTable instead
*/
void
g_cache_destroy (GCache *cache)
{
g_return_if_fail (cache != NULL);
g_hash_table_destroy (cache->key_table);
g_hash_table_destroy (cache->value_table);
g_slice_free (GCache, cache);
}
/**
* g_cache_insert:
* @cache: a #GCache
* @key: a key describing a #GCache object
*
* Gets the value corresponding to the given key, creating it if
* necessary. It first checks if the value already exists in the
* #GCache, by using the @key_equal_func function passed to
* g_cache_new(). If it does already exist it is returned, and its
* reference count is increased by one. If the value does not currently
* exist, if is created by calling the @value_new_func. The key is
* duplicated by calling @key_dup_func and the duplicated key and value
* are inserted into the #GCache.
*
* Returns: a pointer to a #GCache value
*
* Deprecated:2.32: Use a #GHashTable instead
*/
gpointer
g_cache_insert (GCache *cache,
gpointer key)
{
GCacheNode *node;
gpointer value;
g_return_val_if_fail (cache != NULL, NULL);
node = g_hash_table_lookup (cache->key_table, key);
if (node)
{
node->ref_count += 1;
return node->value;
}
key = (* cache->key_dup_func) (key);
value = (* cache->value_new_func) (key);
node = g_cache_node_new (value);
g_hash_table_insert (cache->key_table, key, node);
g_hash_table_insert (cache->value_table, value, key);
return node->value;
}
/**
* g_cache_remove:
* @cache: a #GCache
* @value: the value to remove
*
* Decreases the reference count of the given value. If it drops to 0
* then the value and its corresponding key are destroyed, using the
* @value_destroy_func and @key_destroy_func passed to g_cache_new().
*
* Deprecated:2.32: Use a #GHashTable instead
*/
void
g_cache_remove (GCache *cache,
gconstpointer value)
{
GCacheNode *node;
gpointer key;
g_return_if_fail (cache != NULL);
key = g_hash_table_lookup (cache->value_table, value);
node = g_hash_table_lookup (cache->key_table, key);
g_return_if_fail (node != NULL);
node->ref_count -= 1;
if (node->ref_count == 0)
{
g_hash_table_remove (cache->value_table, value);
g_hash_table_remove (cache->key_table, key);
(* cache->key_destroy_func) (key);
(* cache->value_destroy_func) (node->value);
g_cache_node_destroy (node);
}
}
/**
* g_cache_key_foreach:
* @cache: a #GCache
* @func: the function to call with each #GCache key
* @user_data: user data to pass to the function
*
* Calls the given function for each of the keys in the #GCache.
*
* NOTE @func is passed three parameters, the value and key of a cache
* entry and the @user_data. The order of value and key is different
* from the order in which g_hash_table_foreach() passes key-value
* pairs to its callback function !
*
* Deprecated:2.32: Use a #GHashTable instead
*/
void
g_cache_key_foreach (GCache *cache,
GHFunc func,
gpointer user_data)
{
g_return_if_fail (cache != NULL);
g_return_if_fail (func != NULL);
g_hash_table_foreach (cache->value_table, func, user_data);
}
/**
* g_cache_value_foreach:
* @cache: a #GCache
* @func: the function to call with each #GCache value
* @user_data: user data to pass to the function
*
* Calls the given function for each of the values in the #GCache.
*
* Deprecated:2.10: The reason is that it passes pointers to internal
* data structures to @func; use g_cache_key_foreach() instead
*/
void
g_cache_value_foreach (GCache *cache,
GHFunc func,
gpointer user_data)
{
g_return_if_fail (cache != NULL);
g_return_if_fail (func != NULL);
g_hash_table_foreach (cache->key_table, func, user_data);
}

75
glib/deprecated/gcache.h Normal file
View file

@ -0,0 +1,75 @@
/* 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.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/.
*/
#ifndef __G_CACHE_H__
#define __G_CACHE_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/glist.h>
G_BEGIN_DECLS
typedef struct _GCache GCache GLIB_DEPRECATED_TYPE_IN_2_26_FOR(GHashTable);
typedef gpointer (*GCacheNewFunc) (gpointer key) GLIB_DEPRECATED_TYPE_IN_2_26;
typedef gpointer (*GCacheDupFunc) (gpointer value) GLIB_DEPRECATED_TYPE_IN_2_26;
typedef void (*GCacheDestroyFunc) (gpointer value) GLIB_DEPRECATED_TYPE_IN_2_26;
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/* Caches
*/
GLIB_DEPRECATED
GCache* g_cache_new (GCacheNewFunc value_new_func,
GCacheDestroyFunc value_destroy_func,
GCacheDupFunc key_dup_func,
GCacheDestroyFunc key_destroy_func,
GHashFunc hash_key_func,
GHashFunc hash_value_func,
GEqualFunc key_equal_func);
GLIB_DEPRECATED
void g_cache_destroy (GCache *cache);
GLIB_DEPRECATED
gpointer g_cache_insert (GCache *cache,
gpointer key);
GLIB_DEPRECATED
void g_cache_remove (GCache *cache,
gconstpointer value);
GLIB_DEPRECATED
void g_cache_key_foreach (GCache *cache,
GHFunc func,
gpointer user_data);
GLIB_DEPRECATED
void g_cache_value_foreach (GCache *cache,
GHFunc func,
gpointer user_data);
G_GNUC_END_IGNORE_DEPRECATIONS
G_END_DECLS
#endif /* __G_CACHE_H__ */

View file

@ -0,0 +1,503 @@
/* 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.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"
/* we know we are deprecated here, no need for warnings */
#ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#endif
#include "gcompletion.h"
#include <glib/gstrfuncs.h>
#include <glib/gmessages.h>
#include <glib/gunicode.h>
#include <string.h>
/**
* SECTION:completion
* @title: Automatic String Completion
* @short_description: support for automatic completion using a group
* of target strings
*
* #GCompletion provides support for automatic completion of a string
* using any group of target strings. It is typically used for file
* name completion as is common in many UNIX shells.
*
* A #GCompletion is created using g_completion_new(). Target items are
* added and removed with g_completion_add_items(),
* g_completion_remove_items() and g_completion_clear_items(). A
* completion attempt is requested with g_completion_complete() or
* g_completion_complete_utf8(). When no longer needed, the
* #GCompletion is freed with g_completion_free().
*
* Items in the completion can be simple strings (e.g. filenames), or
* pointers to arbitrary data structures. If data structures are used
* you must provide a #GCompletionFunc in g_completion_new(), which
* retrieves the item's string from the data structure. You can change
* the way in which strings are compared by setting a different
* #GCompletionStrncmpFunc in g_completion_set_compare().
*
* GCompletion has been marked as deprecated, since this API is rarely
* used and not very actively maintained.
**/
/**
* GCompletion:
* @items: list of target items (strings or data structures).
* @func: function which is called to get the string associated with a
* target item. It is %NULL if the target items are strings.
* @prefix: the last prefix passed to g_completion_complete() or
* g_completion_complete_utf8().
* @cache: the list of items which begin with @prefix.
* @strncmp_func: The function to use when comparing strings. Use
* g_completion_set_compare() to modify this function.
*
* The data structure used for automatic completion.
**/
/**
* GCompletionFunc:
* @Param1: the completion item.
*
* Specifies the type of the function passed to g_completion_new(). It
* should return the string corresponding to the given target item.
* This is used when you use data structures as #GCompletion items.
*
* Returns: the string corresponding to the item.
**/
/**
* GCompletionStrncmpFunc:
* @s1: string to compare with @s2.
* @s2: string to compare with @s1.
* @n: maximal number of bytes to compare.
*
* Specifies the type of the function passed to
* g_completion_set_compare(). This is used when you use strings as
* #GCompletion items.
*
* Returns: an integer less than, equal to, or greater than zero if
* the first @n bytes of @s1 is found, respectively, to be
* less than, to match, or to be greater than the first @n
* bytes of @s2.
**/
static void completion_check_cache (GCompletion* cmp,
gchar** new_prefix);
/**
* g_completion_new:
* @func: the function to be called to return the string representing
* an item in the #GCompletion, or %NULL if strings are going to
* be used as the #GCompletion items.
*
* Creates a new #GCompletion.
*
* Returns: the new #GCompletion.
**/
GCompletion*
g_completion_new (GCompletionFunc func)
{
GCompletion* gcomp;
gcomp = g_new (GCompletion, 1);
gcomp->items = NULL;
gcomp->cache = NULL;
gcomp->prefix = NULL;
gcomp->func = func;
gcomp->strncmp_func = strncmp;
return gcomp;
}
/**
* g_completion_add_items:
* @cmp: the #GCompletion.
* @items: (transfer none): the list of items to add.
*
* Adds items to the #GCompletion.
*
* Deprecated: 2.26: Rarely used API
**/
void
g_completion_add_items (GCompletion* cmp,
GList* items)
{
GList* it;
g_return_if_fail (cmp != NULL);
/* optimize adding to cache? */
if (cmp->cache)
{
g_list_free (cmp->cache);
cmp->cache = NULL;
}
if (cmp->prefix)
{
g_free (cmp->prefix);
cmp->prefix = NULL;
}
it = items;
while (it)
{
cmp->items = g_list_prepend (cmp->items, it->data);
it = it->next;
}
}
/**
* g_completion_remove_items:
* @cmp: the #GCompletion.
* @items: (transfer none): the items to remove.
*
* Removes items from a #GCompletion. The items are not freed, so if the memory
* was dynamically allocated, free @items with g_list_free_full() after calling
* this function.
*
* Deprecated: 2.26: Rarely used API
**/
void
g_completion_remove_items (GCompletion* cmp,
GList* items)
{
GList* it;
g_return_if_fail (cmp != NULL);
it = items;
while (cmp->items && it)
{
cmp->items = g_list_remove (cmp->items, it->data);
it = it->next;
}
it = items;
while (cmp->cache && it)
{
cmp->cache = g_list_remove(cmp->cache, it->data);
it = it->next;
}
}
/**
* g_completion_clear_items:
* @cmp: the #GCompletion.
*
* Removes all items from the #GCompletion. The items are not freed, so if the
* memory was dynamically allocated, it should be freed after calling this
* function.
*
* Deprecated: 2.26: Rarely used API
**/
void
g_completion_clear_items (GCompletion* cmp)
{
g_return_if_fail (cmp != NULL);
g_list_free (cmp->items);
cmp->items = NULL;
g_list_free (cmp->cache);
cmp->cache = NULL;
g_free (cmp->prefix);
cmp->prefix = NULL;
}
static void
completion_check_cache (GCompletion* cmp,
gchar** new_prefix)
{
GList* list;
gsize len;
gsize i;
gsize plen;
gchar* postfix;
gchar* s;
if (!new_prefix)
return;
if (!cmp->cache)
{
*new_prefix = NULL;
return;
}
len = strlen(cmp->prefix);
list = cmp->cache;
s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
postfix = s + len;
plen = strlen (postfix);
list = list->next;
while (list && plen)
{
s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
s += len;
for (i = 0; i < plen; ++i)
{
if (postfix[i] != s[i])
break;
}
plen = i;
list = list->next;
}
*new_prefix = g_new0 (gchar, len + plen + 1);
strncpy (*new_prefix, cmp->prefix, len);
strncpy (*new_prefix + len, postfix, plen);
}
/**
* g_completion_complete_utf8:
* @cmp: the #GCompletion
* @prefix: the prefix string, typically used by the user, which is compared
* with each of the items
* @new_prefix: if non-%NULL, returns the longest prefix which is common to all
* items that matched @prefix, or %NULL if no items matched @prefix.
* This string should be freed when no longer needed.
*
* Attempts to complete the string @prefix using the #GCompletion target items.
* In contrast to g_completion_complete(), this function returns the largest common
* prefix that is a valid UTF-8 string, omitting a possible common partial
* character.
*
* You should use this function instead of g_completion_complete() if your
* items are UTF-8 strings.
*
* Returns: (element-type utf8) (transfer none): the list of items whose strings begin with @prefix. This should
* not be changed.
*
* Since: 2.4
*
* Deprecated: 2.26: Rarely used API
**/
GList*
g_completion_complete_utf8 (GCompletion *cmp,
const gchar *prefix,
gchar **new_prefix)
{
GList *list;
gchar *p, *q;
list = g_completion_complete (cmp, prefix, new_prefix);
if (new_prefix && *new_prefix)
{
p = *new_prefix + strlen (*new_prefix);
q = g_utf8_find_prev_char (*new_prefix, p);
switch (g_utf8_get_char_validated (q, p - q))
{
case (gunichar)-2:
case (gunichar)-1:
*q = 0;
break;
default: ;
}
}
return list;
}
/**
* g_completion_complete:
* @cmp: the #GCompletion.
* @prefix: the prefix string, typically typed by the user, which is
* compared with each of the items.
* @new_prefix: if non-%NULL, returns the longest prefix which is
* common to all items that matched @prefix, or %NULL if
* no items matched @prefix. This string should be freed
* when no longer needed.
*
* Attempts to complete the string @prefix using the #GCompletion
* target items.
*
* Returns: (transfer none): the list of items whose strings begin with
* @prefix. This should not be changed.
*
* Deprecated: 2.26: Rarely used API
**/
GList*
g_completion_complete (GCompletion* cmp,
const gchar* prefix,
gchar** new_prefix)
{
gsize plen, len;
gboolean done = FALSE;
GList* list;
g_return_val_if_fail (cmp != NULL, NULL);
g_return_val_if_fail (prefix != NULL, NULL);
len = strlen (prefix);
if (cmp->prefix && cmp->cache)
{
plen = strlen (cmp->prefix);
if (plen <= len && ! cmp->strncmp_func (prefix, cmp->prefix, plen))
{
/* use the cache */
list = cmp->cache;
while (list)
{
GList *next = list->next;
if (cmp->strncmp_func (prefix,
cmp->func ? cmp->func (list->data) : (gchar*) list->data,
len))
cmp->cache = g_list_delete_link (cmp->cache, list);
list = next;
}
done = TRUE;
}
}
if (!done)
{
/* normal code */
g_list_free (cmp->cache);
cmp->cache = NULL;
list = cmp->items;
while (*prefix && list)
{
if (!cmp->strncmp_func (prefix,
cmp->func ? cmp->func (list->data) : (gchar*) list->data,
len))
cmp->cache = g_list_prepend (cmp->cache, list->data);
list = list->next;
}
}
if (cmp->prefix)
{
g_free (cmp->prefix);
cmp->prefix = NULL;
}
if (cmp->cache)
cmp->prefix = g_strdup (prefix);
completion_check_cache (cmp, new_prefix);
return *prefix ? cmp->cache : cmp->items;
}
/**
* g_completion_free:
* @cmp: the #GCompletion.
*
* Frees all memory used by the #GCompletion. The items are not freed, so if
* the memory was dynamically allocated, it should be freed after calling this
* function.
*
* Deprecated: 2.26: Rarely used API
**/
void
g_completion_free (GCompletion* cmp)
{
g_return_if_fail (cmp != NULL);
g_completion_clear_items (cmp);
g_free (cmp);
}
/**
* g_completion_set_compare:
* @cmp: a #GCompletion.
* @strncmp_func: the string comparison function.
*
* Sets the function to use for string comparisons. The default string
* comparison function is strncmp().
*
* Deprecated: 2.26: Rarely used API
**/
void
g_completion_set_compare(GCompletion *cmp,
GCompletionStrncmpFunc strncmp_func)
{
cmp->strncmp_func = strncmp_func;
}
#ifdef TEST_COMPLETION
#include <stdio.h>
int
main (int argc,
char* argv[])
{
FILE *file;
gchar buf[1024];
GList *list;
GList *result;
GList *tmp;
GCompletion *cmp;
gint i;
gchar *longp = NULL;
if (argc < 3)
{
g_warning ("Usage: %s filename prefix1 [prefix2 ...]",
(argc > 0) ? argv[0] : "gcompletion");
return 1;
}
file = fopen (argv[1], "r");
if (!file)
{
g_warning ("Cannot open %s", argv[1]);
return 1;
}
cmp = g_completion_new (NULL);
list = g_list_alloc ();
while (fgets (buf, 1024, file))
{
list->data = g_strdup (buf);
g_completion_add_items (cmp, list);
}
fclose (file);
for (i = 2; i < argc; ++i)
{
printf ("COMPLETING: %s\n", argv[i]);
result = g_completion_complete (cmp, argv[i], &longp);
g_list_foreach (result, (GFunc) printf, NULL);
printf ("LONG MATCH: %s\n", longp);
g_free (longp);
longp = NULL;
}
g_list_foreach (cmp->items, (GFunc) g_free, NULL);
g_completion_free (cmp);
g_list_free (list);
return 0;
}
#endif

View file

@ -0,0 +1,83 @@
/* 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.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/.
*/
#ifndef __G_COMPLETION_H__
#define __G_COMPLETION_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/glist.h>
G_BEGIN_DECLS
typedef struct _GCompletion GCompletion;
typedef gchar* (*GCompletionFunc) (gpointer);
/* GCompletion
*/
typedef gint (*GCompletionStrncmpFunc) (const gchar *s1,
const gchar *s2,
gsize n);
struct _GCompletion
{
GList* items;
GCompletionFunc func;
gchar* prefix;
GList* cache;
GCompletionStrncmpFunc strncmp_func;
};
GLIB_DEPRECATED_IN_2_26
GCompletion* g_completion_new (GCompletionFunc func);
GLIB_DEPRECATED_IN_2_26
void g_completion_add_items (GCompletion* cmp,
GList* items);
GLIB_DEPRECATED_IN_2_26
void g_completion_remove_items (GCompletion* cmp,
GList* items);
GLIB_DEPRECATED_IN_2_26
void g_completion_clear_items (GCompletion* cmp);
GLIB_DEPRECATED_IN_2_26
GList* g_completion_complete (GCompletion* cmp,
const gchar* prefix,
gchar** new_prefix);
GLIB_DEPRECATED_IN_2_26
GList* g_completion_complete_utf8 (GCompletion *cmp,
const gchar* prefix,
gchar** new_prefix);
GLIB_DEPRECATED_IN_2_26
void g_completion_set_compare (GCompletion *cmp,
GCompletionStrncmpFunc strncmp_func);
GLIB_DEPRECATED_IN_2_26
void g_completion_free (GCompletion* cmp);
G_END_DECLS
#endif /* __G_COMPLETION_H__ */

135
glib/deprecated/gmain.h Normal file
View file

@ -0,0 +1,135 @@
/* 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.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/.
*/
#ifndef __G_DEPRECATED_MAIN_H__
#define __G_DEPRECATED_MAIN_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gmain.h>
G_BEGIN_DECLS
/* ============== Compat main loop stuff ================== */
/**
* g_main_new:
* @is_running: set to %TRUE to indicate that the loop is running. This
* is not very important since calling g_main_run() will set this
* to %TRUE anyway.
*
* Creates a new #GMainLoop for th default main context.
*
* Returns: a new #GMainLoop
*
* Deprecated: 2.2: Use g_main_loop_new() instead
*/
#define g_main_new(is_running) g_main_loop_new (NULL, is_running) GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_main_loop_new)
/**
* g_main_run:
* @loop: a #GMainLoop
*
* Runs a main loop until it stops running.
*
* Deprecated: 2.2: Use g_main_loop_run() instead
*/
#define g_main_run(loop) g_main_loop_run(loop) GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_main_loop_run)
/**
* g_main_quit:
* @loop: a #GMainLoop
*
* Stops the #GMainLoop.
* If g_main_run() was called to run the #GMainLoop, it will now return.
*
* Deprecated: 2.2: Use g_main_loop_quit() instead
*/
#define g_main_quit(loop) g_main_loop_quit(loop) GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_main_loop_quit)
/**
* g_main_destroy:
* @loop: a #GMainLoop
*
* Frees the memory allocated for the #GMainLoop.
*
* Deprecated: 2.2: Use g_main_loop_unref() instead
*/
#define g_main_destroy(loop) g_main_loop_unref(loop) GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_main_loop_unref)
/**
* g_main_is_running:
* @loop: a #GMainLoop
*
* Checks if the main loop is running.
*
* Returns: %TRUE if the main loop is running
*
* Deprecated: 2.2: Use g_main_loop_is_running() instead
*/
#define g_main_is_running(loop) g_main_loop_is_running(loop) GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_main_loop_is_running)
/**
* g_main_iteration:
* @may_block: set to %TRUE if it should block (i.e. wait) until an event
* source becomes ready. It will return after an event source has been
* processed. If set to %FALSE it will return immediately if no event
* source is ready to be processed.
*
* Runs a single iteration for the default #GMainContext.
*
* Returns: %TRUE if more events are pending.
*
* Deprecated: 2.2: Use g_main_context_iteration() instead.
*/
#define g_main_iteration(may_block) g_main_context_iteration (NULL, may_block) GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_main_context_iteration)
/**
* g_main_pending:
*
* Checks if any events are pending for the default #GMainContext
* (i.e. ready to be processed).
*
* Returns: %TRUE if any events are pending.
*
* Deprecated: 2.2: Use g_main_context_pending() instead.
*/
#define g_main_pending() g_main_context_pending (NULL) GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_main_context_pending)
/**
* g_main_set_poll_func:
* @func: the function to call to poll all file descriptors
*
* Sets the function to use for the handle polling of file descriptors
* for the default main context.
*
* Deprecated: 2.2: Use g_main_context_set_poll_func() again
*/
#define g_main_set_poll_func(func) g_main_context_set_poll_func (NULL, func) GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_main_context_set_poll_func)
G_END_DECLS
#endif /* __G_DEPRECATED_MAIN_H__ */

685
glib/deprecated/grel.c Normal file
View file

@ -0,0 +1,685 @@
/* 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.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, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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
*/
#include "config.h"
/* we know we are deprecated here, no need for warnings */
#ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#endif
#include "grel.h"
#include <glib/gmessages.h>
#include <glib/gtestutils.h>
#include <glib/gstring.h>
#include <glib/gslice.h>
#include <glib/ghash.h>
#include <stdarg.h>
#include <string.h>
/**
* SECTION:relations
* @title: Relations and Tuples
* @short_description: tables of data which can be indexed on any
* number of fields
*
* A #GRelation is a table of data which can be indexed on any number
* of fields, rather like simple database tables. A #GRelation contains
* a number of records, called tuples. Each record contains a number of
* fields. Records are not ordered, so it is not possible to find the
* record at a particular index.
*
* Note that #GRelation tables are currently limited to 2 fields.
*
* To create a GRelation, use g_relation_new().
*
* To specify which fields should be indexed, use g_relation_index().
* Note that this must be called before any tuples are added to the
* #GRelation.
*
* To add records to a #GRelation use g_relation_insert().
*
* To determine if a given record appears in a #GRelation, use
* g_relation_exists(). Note that fields are compared directly, so
* pointers must point to the exact same position (i.e. different
* copies of the same string will not match.)
*
* To count the number of records which have a particular value in a
* given field, use g_relation_count().
*
* To get all the records which have a particular value in a given
* field, use g_relation_select(). To access fields of the resulting
* records, use g_tuples_index(). To free the resulting records use
* g_tuples_destroy().
*
* To delete all records which have a particular value in a given
* field, use g_relation_delete().
*
* To destroy the #GRelation, use g_relation_destroy().
*
* To help debug #GRelation objects, use g_relation_print().
*
* GRelation has been marked as deprecated, since this API has never
* been fully implemented, is not very actively maintained and rarely
* used.
**/
typedef struct _GRealTuples GRealTuples;
/**
* GRelation:
*
* The #GRelation struct is an opaque data structure to represent a
* [Relation][glib-Relations-and-Tuples]. It should
* only be accessed via the following functions.
**/
struct _GRelation
{
gint fields;
gint current_field;
GHashTable *all_tuples;
GHashTable **hashed_tuple_tables;
gint count;
};
/**
* GTuples:
* @len: the number of records that matched.
*
* The #GTuples struct is used to return records (or tuples) from the
* #GRelation by g_relation_select(). It only contains one public
* member - the number of records that matched. To access the matched
* records, you must use g_tuples_index().
**/
struct _GRealTuples
{
gint len;
gint width;
gpointer *data;
};
static gboolean
tuple_equal_2 (gconstpointer v_a,
gconstpointer v_b)
{
gpointer* a = (gpointer*) v_a;
gpointer* b = (gpointer*) v_b;
return a[0] == b[0] && a[1] == b[1];
}
static guint
tuple_hash_2 (gconstpointer v_a)
{
#if GLIB_SIZEOF_VOID_P > GLIB_SIZEOF_LONG
/* In practise this snippet has been written for 64-bit Windows
* where ints are 32 bits, pointers 64 bits. More exotic platforms
* need more tweaks.
*/
guint* a = (guint*) v_a;
return (a[0] ^ a[1] ^ a[2] ^ a[3]);
#else
gpointer* a = (gpointer*) v_a;
return (gulong)a[0] ^ (gulong)a[1];
#endif
}
static GHashFunc
tuple_hash (gint fields)
{
switch (fields)
{
case 2:
return tuple_hash_2;
default:
g_error ("no tuple hash for %d", fields);
}
return NULL;
}
static GEqualFunc
tuple_equal (gint fields)
{
switch (fields)
{
case 2:
return tuple_equal_2;
default:
g_error ("no tuple equal for %d", fields);
}
return NULL;
}
/**
* g_relation_new:
* @fields: the number of fields.
*
* Creates a new #GRelation with the given number of fields. Note that
* currently the number of fields must be 2.
*
* Returns: a new #GRelation.
*
* Deprecated: 2.26: Rarely used API
**/
GRelation*
g_relation_new (gint fields)
{
GRelation* rel = g_new0 (GRelation, 1);
rel->fields = fields;
rel->all_tuples = g_hash_table_new (tuple_hash (fields), tuple_equal (fields));
rel->hashed_tuple_tables = g_new0 (GHashTable*, fields);
return rel;
}
static void
relation_delete_value_tuple (gpointer tuple_key,
gpointer tuple_value,
gpointer user_data)
{
GRelation *relation = user_data;
gpointer *tuple = tuple_value;
g_slice_free1 (relation->fields * sizeof (gpointer), tuple);
}
static void
g_relation_free_array (gpointer key, gpointer value, gpointer user_data)
{
g_hash_table_destroy ((GHashTable*) value);
}
/**
* g_relation_destroy:
* @relation: a #GRelation.
*
* Destroys the #GRelation, freeing all memory allocated. However, it
* does not free memory allocated for the tuple data, so you should
* free that first if appropriate.
*
* Deprecated: 2.26: Rarely used API
**/
void
g_relation_destroy (GRelation *relation)
{
gint i;
if (relation)
{
for (i = 0; i < relation->fields; i += 1)
{
if (relation->hashed_tuple_tables[i])
{
g_hash_table_foreach (relation->hashed_tuple_tables[i], g_relation_free_array, NULL);
g_hash_table_destroy (relation->hashed_tuple_tables[i]);
}
}
g_hash_table_foreach (relation->all_tuples, relation_delete_value_tuple, relation);
g_hash_table_destroy (relation->all_tuples);
g_free (relation->hashed_tuple_tables);
g_free (relation);
}
}
/**
* g_relation_index:
* @relation: a #GRelation.
* @field: the field to index, counting from 0.
* @hash_func: a function to produce a hash value from the field data.
* @key_equal_func: a function to compare two values of the given field.
*
* Creates an index on the given field. Note that this must be called
* before any records are added to the #GRelation.
*
* Deprecated: 2.26: Rarely used API
**/
void
g_relation_index (GRelation *relation,
gint field,
GHashFunc hash_func,
GEqualFunc key_equal_func)
{
g_return_if_fail (relation != NULL);
g_return_if_fail (relation->count == 0 && relation->hashed_tuple_tables[field] == NULL);
relation->hashed_tuple_tables[field] = g_hash_table_new (hash_func, key_equal_func);
}
/**
* g_relation_insert:
* @relation: a #GRelation.
* @...: the fields of the record to add. These must match the
* number of fields in the #GRelation, and of type #gpointer
* or #gconstpointer.
*
* Inserts a record into a #GRelation.
*
* Deprecated: 2.26: Rarely used API
**/
void
g_relation_insert (GRelation *relation,
...)
{
gpointer* tuple = g_slice_alloc (relation->fields * sizeof (gpointer));
va_list args;
gint i;
va_start (args, relation);
for (i = 0; i < relation->fields; i += 1)
tuple[i] = va_arg (args, gpointer);
va_end (args);
g_hash_table_insert (relation->all_tuples, tuple, tuple);
relation->count += 1;
for (i = 0; i < relation->fields; i += 1)
{
GHashTable *table;
gpointer key;
GHashTable *per_key_table;
table = relation->hashed_tuple_tables[i];
if (table == NULL)
continue;
key = tuple[i];
per_key_table = g_hash_table_lookup (table, key);
if (per_key_table == NULL)
{
per_key_table = g_hash_table_new (tuple_hash (relation->fields), tuple_equal (relation->fields));
g_hash_table_insert (table, key, per_key_table);
}
g_hash_table_insert (per_key_table, tuple, tuple);
}
}
static void
g_relation_delete_tuple (gpointer tuple_key,
gpointer tuple_value,
gpointer user_data)
{
gpointer *tuple = (gpointer*) tuple_value;
GRelation *relation = (GRelation *) user_data;
gint j;
g_assert (tuple_key == tuple_value);
for (j = 0; j < relation->fields; j += 1)
{
GHashTable *one_table = relation->hashed_tuple_tables[j];
gpointer one_key;
GHashTable *per_key_table;
if (one_table == NULL)
continue;
if (j == relation->current_field)
/* can't delete from the table we're foreaching in */
continue;
one_key = tuple[j];
per_key_table = g_hash_table_lookup (one_table, one_key);
g_hash_table_remove (per_key_table, tuple);
}
if (g_hash_table_remove (relation->all_tuples, tuple))
g_slice_free1 (relation->fields * sizeof (gpointer), tuple);
relation->count -= 1;
}
/**
* g_relation_delete:
* @relation: a #GRelation.
* @key: the value to compare with.
* @field: the field of each record to match.
*
* Deletes any records from a #GRelation that have the given key value
* in the given field.
*
* Returns: the number of records deleted.
*
* Deprecated: 2.26: Rarely used API
**/
gint
g_relation_delete (GRelation *relation,
gconstpointer key,
gint field)
{
GHashTable *table;
GHashTable *key_table;
gint count;
g_return_val_if_fail (relation != NULL, 0);
table = relation->hashed_tuple_tables[field];
count = relation->count;
g_return_val_if_fail (table != NULL, 0);
key_table = g_hash_table_lookup (table, key);
if (!key_table)
return 0;
relation->current_field = field;
g_hash_table_foreach (key_table, g_relation_delete_tuple, relation);
g_hash_table_remove (table, key);
g_hash_table_destroy (key_table);
/* @@@ FIXME: Remove empty hash tables. */
return count - relation->count;
}
static void
g_relation_select_tuple (gpointer tuple_key,
gpointer tuple_value,
gpointer user_data)
{
gpointer *tuple = (gpointer*) tuple_value;
GRealTuples *tuples = (GRealTuples*) user_data;
gint stride = sizeof (gpointer) * tuples->width;
g_assert (tuple_key == tuple_value);
memcpy (tuples->data + (tuples->len * tuples->width),
tuple,
stride);
tuples->len += 1;
}
/**
* g_relation_select:
* @relation: a #GRelation.
* @key: the value to compare with.
* @field: the field of each record to match.
*
* Returns all of the tuples which have the given key in the given
* field. Use g_tuples_index() to access the returned records. The
* returned records should be freed with g_tuples_destroy().
*
* Returns: the records (tuples) that matched.
*
* Deprecated: 2.26: Rarely used API
**/
GTuples*
g_relation_select (GRelation *relation,
gconstpointer key,
gint field)
{
GHashTable *table;
GHashTable *key_table;
GRealTuples *tuples;
gint count;
g_return_val_if_fail (relation != NULL, NULL);
table = relation->hashed_tuple_tables[field];
g_return_val_if_fail (table != NULL, NULL);
tuples = g_new0 (GRealTuples, 1);
key_table = g_hash_table_lookup (table, key);
if (!key_table)
return (GTuples*)tuples;
count = g_relation_count (relation, key, field);
tuples->data = g_malloc (sizeof (gpointer) * relation->fields * count);
tuples->width = relation->fields;
g_hash_table_foreach (key_table, g_relation_select_tuple, tuples);
g_assert (count == tuples->len);
return (GTuples*)tuples;
}
/**
* g_relation_count:
* @relation: a #GRelation.
* @key: the value to compare with.
* @field: the field of each record to match.
*
* Returns the number of tuples in a #GRelation that have the given
* value in the given field.
*
* Returns: the number of matches.
*
* Deprecated: 2.26: Rarely used API
**/
gint
g_relation_count (GRelation *relation,
gconstpointer key,
gint field)
{
GHashTable *table;
GHashTable *key_table;
g_return_val_if_fail (relation != NULL, 0);
table = relation->hashed_tuple_tables[field];
g_return_val_if_fail (table != NULL, 0);
key_table = g_hash_table_lookup (table, key);
if (!key_table)
return 0;
return g_hash_table_size (key_table);
}
/**
* g_relation_exists:
* @relation: a #GRelation.
* @...: the fields of the record to compare. The number must match
* the number of fields in the #GRelation.
*
* Returns %TRUE if a record with the given values exists in a
* #GRelation. Note that the values are compared directly, so that, for
* example, two copies of the same string will not match.
*
* Returns: %TRUE if a record matches.
*
* Deprecated: 2.26: Rarely used API
**/
gboolean
g_relation_exists (GRelation *relation, ...)
{
gpointer *tuple = g_slice_alloc (relation->fields * sizeof (gpointer));
va_list args;
gint i;
gboolean result;
va_start(args, relation);
for (i = 0; i < relation->fields; i += 1)
tuple[i] = va_arg(args, gpointer);
va_end(args);
result = g_hash_table_lookup (relation->all_tuples, tuple) != NULL;
g_slice_free1 (relation->fields * sizeof (gpointer), tuple);
return result;
}
/**
* g_tuples_destroy:
* @tuples: the tuple data to free.
*
* Frees the records which were returned by g_relation_select(). This
* should always be called after g_relation_select() when you are
* finished with the records. The records are not removed from the
* #GRelation.
*
* Deprecated: 2.26: Rarely used API
**/
void
g_tuples_destroy (GTuples *tuples0)
{
GRealTuples *tuples = (GRealTuples*) tuples0;
if (tuples)
{
g_free (tuples->data);
g_free (tuples);
}
}
/**
* g_tuples_index:
* @tuples: the tuple data, returned by g_relation_select().
* @index_: the index of the record.
* @field: the field to return.
*
* Gets a field from the records returned by g_relation_select(). It
* returns the given field of the record at the given index. The
* returned value should not be changed.
*
* Returns: the field of the record.
*
* Deprecated: 2.26: Rarely used API
**/
gpointer
g_tuples_index (GTuples *tuples0,
gint index,
gint field)
{
GRealTuples *tuples = (GRealTuples*) tuples0;
g_return_val_if_fail (tuples0 != NULL, NULL);
g_return_val_if_fail (field < tuples->width, NULL);
return tuples->data[index * tuples->width + field];
}
/* Print
*/
static void
g_relation_print_one (gpointer tuple_key,
gpointer tuple_value,
gpointer user_data)
{
gint i;
GString *gstring;
GRelation* rel = (GRelation*) user_data;
gpointer* tuples = (gpointer*) tuple_value;
gstring = g_string_new ("[");
for (i = 0; i < rel->fields; i += 1)
{
g_string_append_printf (gstring, "%p", tuples[i]);
if (i < (rel->fields - 1))
g_string_append (gstring, ",");
}
g_string_append (gstring, "]");
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "%s", gstring->str);
g_string_free (gstring, TRUE);
}
static void
g_relation_print_index (gpointer tuple_key,
gpointer tuple_value,
gpointer user_data)
{
GRelation* rel = (GRelation*) user_data;
GHashTable* table = (GHashTable*) tuple_value;
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "*** key %p", tuple_key);
g_hash_table_foreach (table,
g_relation_print_one,
rel);
}
/**
* g_relation_print:
* @relation: a #GRelation.
*
* Outputs information about all records in a #GRelation, as well as
* the indexes. It is for debugging.
*
* Deprecated: 2.26: Rarely used API
**/
void
g_relation_print (GRelation *relation)
{
gint i;
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "*** all tuples (%d)", relation->count);
g_hash_table_foreach (relation->all_tuples,
g_relation_print_one,
relation);
for (i = 0; i < relation->fields; i += 1)
{
if (relation->hashed_tuple_tables[i] == NULL)
continue;
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "*** index %d", i);
g_hash_table_foreach (relation->hashed_tuple_tables[i],
g_relation_print_index,
relation);
}
}

105
glib/deprecated/grel.h Normal file
View file

@ -0,0 +1,105 @@
/* 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.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/.
*/
#ifndef __G_REL_H__
#define __G_REL_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtypes.h>
G_BEGIN_DECLS
typedef struct _GRelation GRelation;
typedef struct _GTuples GTuples;
struct _GTuples
{
guint len;
};
/* GRelation
*
* Indexed Relations. Imagine a really simple table in a
* database. Relations are not ordered. This data type is meant for
* maintaining a N-way mapping.
*
* g_relation_new() creates a relation with FIELDS fields
*
* g_relation_destroy() frees all resources
* g_tuples_destroy() frees the result of g_relation_select()
*
* g_relation_index() indexes relation FIELD with the provided
* equality and hash functions. this must be done before any
* calls to insert are made.
*
* g_relation_insert() inserts a new tuple. you are expected to
* provide the right number of fields.
*
* g_relation_delete() deletes all relations with KEY in FIELD
* g_relation_select() returns ...
* g_relation_count() counts ...
*/
GLIB_DEPRECATED_IN_2_26
GRelation* g_relation_new (gint fields);
GLIB_DEPRECATED_IN_2_26
void g_relation_destroy (GRelation *relation);
GLIB_DEPRECATED_IN_2_26
void g_relation_index (GRelation *relation,
gint field,
GHashFunc hash_func,
GEqualFunc key_equal_func);
GLIB_DEPRECATED_IN_2_26
void g_relation_insert (GRelation *relation,
...);
GLIB_DEPRECATED_IN_2_26
gint g_relation_delete (GRelation *relation,
gconstpointer key,
gint field);
GLIB_DEPRECATED_IN_2_26
GTuples* g_relation_select (GRelation *relation,
gconstpointer key,
gint field);
GLIB_DEPRECATED_IN_2_26
gint g_relation_count (GRelation *relation,
gconstpointer key,
gint field);
GLIB_DEPRECATED_IN_2_26
gboolean g_relation_exists (GRelation *relation,
...);
GLIB_DEPRECATED_IN_2_26
void g_relation_print (GRelation *relation);
GLIB_DEPRECATED_IN_2_26
void g_tuples_destroy (GTuples *tuples);
GLIB_DEPRECATED_IN_2_26
gpointer g_tuples_index (GTuples *tuples,
gint index_,
gint field);
G_END_DECLS
#endif /* __G_REL_H__ */

File diff suppressed because it is too large Load diff

293
glib/deprecated/gthread.h Normal file
View file

@ -0,0 +1,293 @@
/* 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.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/.
*/
#ifndef __G_DEPRECATED_THREAD_H__
#define __G_DEPRECATED_THREAD_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gthread.h>
G_BEGIN_DECLS
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
typedef enum
{
G_THREAD_PRIORITY_LOW,
G_THREAD_PRIORITY_NORMAL,
G_THREAD_PRIORITY_HIGH,
G_THREAD_PRIORITY_URGENT
} GThreadPriority GLIB_DEPRECATED_TYPE_IN_2_32;
struct _GThread
{
/*< private >*/
GThreadFunc func;
gpointer data;
gboolean joinable;
GThreadPriority priority;
};
typedef struct _GThreadFunctions GThreadFunctions GLIB_DEPRECATED_TYPE_IN_2_32;
struct _GThreadFunctions
{
GMutex* (*mutex_new) (void);
void (*mutex_lock) (GMutex *mutex);
gboolean (*mutex_trylock) (GMutex *mutex);
void (*mutex_unlock) (GMutex *mutex);
void (*mutex_free) (GMutex *mutex);
GCond* (*cond_new) (void);
void (*cond_signal) (GCond *cond);
void (*cond_broadcast) (GCond *cond);
void (*cond_wait) (GCond *cond,
GMutex *mutex);
gboolean (*cond_timed_wait) (GCond *cond,
GMutex *mutex,
GTimeVal *end_time);
void (*cond_free) (GCond *cond);
GPrivate* (*private_new) (GDestroyNotify destructor);
gpointer (*private_get) (GPrivate *private_key);
void (*private_set) (GPrivate *private_key,
gpointer data);
void (*thread_create) (GThreadFunc func,
gpointer data,
gulong stack_size,
gboolean joinable,
gboolean bound,
GThreadPriority priority,
gpointer thread,
GError **error);
void (*thread_yield) (void);
void (*thread_join) (gpointer thread);
void (*thread_exit) (void);
void (*thread_set_priority)(gpointer thread,
GThreadPriority priority);
void (*thread_self) (gpointer thread);
gboolean (*thread_equal) (gpointer thread1,
gpointer thread2);
} GLIB_DEPRECATED_TYPE_IN_2_32;
GLIB_VAR GThreadFunctions g_thread_functions_for_glib_use;
GLIB_VAR gboolean g_thread_use_default_impl;
GLIB_VAR guint64 (*g_thread_gettime) (void);
GLIB_DEPRECATED_IN_2_32_FOR(g_thread_new)
GThread *g_thread_create (GThreadFunc func,
gpointer data,
gboolean joinable,
GError **error);
GLIB_DEPRECATED_IN_2_32_FOR(g_thread_new)
GThread *g_thread_create_full (GThreadFunc func,
gpointer data,
gulong stack_size,
gboolean joinable,
gboolean bound,
GThreadPriority priority,
GError **error);
GLIB_DEPRECATED_IN_2_32
void g_thread_set_priority (GThread *thread,
GThreadPriority priority);
GLIB_DEPRECATED_IN_2_32
void g_thread_foreach (GFunc thread_func,
gpointer user_data);
#ifndef G_OS_WIN32
#include <sys/types.h>
#include <pthread.h>
#endif
#define g_static_mutex_get_mutex g_static_mutex_get_mutex_impl GLIB_DEPRECATED_MACRO_IN_2_32
#ifndef G_OS_WIN32
#define G_STATIC_MUTEX_INIT { NULL, PTHREAD_MUTEX_INITIALIZER } GLIB_DEPRECATED_MACRO_IN_2_32_FOR(g_mutex_init)
#else
#define G_STATIC_MUTEX_INIT { NULL } GLIB_DEPRECATED_MACRO_IN_2_32_FOR(g_mutex_init)
#endif
typedef struct
{
GMutex *mutex;
#ifndef G_OS_WIN32
/* only for ABI compatibility reasons */
pthread_mutex_t unused;
#endif
} GStaticMutex GLIB_DEPRECATED_TYPE_IN_2_32_FOR(GMutex);
#define g_static_mutex_lock(mutex) \
g_mutex_lock (g_static_mutex_get_mutex (mutex)) GLIB_DEPRECATED_MACRO_IN_2_32_FOR(g_mutex_lock)
#define g_static_mutex_trylock(mutex) \
g_mutex_trylock (g_static_mutex_get_mutex (mutex)) GLIB_DEPRECATED_MACRO_IN_2_32_FOR(g_mutex_trylock)
#define g_static_mutex_unlock(mutex) \
g_mutex_unlock (g_static_mutex_get_mutex (mutex)) GLIB_DEPRECATED_MACRO_IN_2_32_FOR(g_mutex_unlock)
GLIB_DEPRECATED_IN_2_32_FOR(g_mutex_init)
void g_static_mutex_init (GStaticMutex *mutex);
GLIB_DEPRECATED_IN_2_32_FOR(g_mutex_clear)
void g_static_mutex_free (GStaticMutex *mutex);
GLIB_DEPRECATED_IN_2_32_FOR(GMutex)
GMutex *g_static_mutex_get_mutex_impl (GStaticMutex *mutex);
typedef struct _GStaticRecMutex GStaticRecMutex GLIB_DEPRECATED_TYPE_IN_2_32_FOR(GRecMutex);
struct _GStaticRecMutex
{
/*< private >*/
GStaticMutex mutex;
guint depth;
/* ABI compat only */
union {
#ifdef G_OS_WIN32
void *owner;
#else
pthread_t owner;
#endif
gdouble dummy;
} unused;
} GLIB_DEPRECATED_TYPE_IN_2_32_FOR(GRecMutex);
#define G_STATIC_REC_MUTEX_INIT { G_STATIC_MUTEX_INIT, 0, { 0 } } GLIB_DEPRECATED_MACRO_IN_2_32_FOR(g_rec_mutex_init)
GLIB_DEPRECATED_IN_2_32_FOR(g_rec_mutex_init)
void g_static_rec_mutex_init (GStaticRecMutex *mutex);
GLIB_DEPRECATED_IN_2_32_FOR(g_rec_mutex_lock)
void g_static_rec_mutex_lock (GStaticRecMutex *mutex);
GLIB_DEPRECATED_IN_2_32_FOR(g_rec_mutex_try_lock)
gboolean g_static_rec_mutex_trylock (GStaticRecMutex *mutex);
GLIB_DEPRECATED_IN_2_32_FOR(g_rec_mutex_unlock)
void g_static_rec_mutex_unlock (GStaticRecMutex *mutex);
GLIB_DEPRECATED_IN_2_32
void g_static_rec_mutex_lock_full (GStaticRecMutex *mutex,
guint depth);
GLIB_DEPRECATED_IN_2_32
guint g_static_rec_mutex_unlock_full (GStaticRecMutex *mutex);
GLIB_DEPRECATED_IN_2_32_FOR(g_rec_mutex_free)
void g_static_rec_mutex_free (GStaticRecMutex *mutex);
typedef struct _GStaticRWLock GStaticRWLock GLIB_DEPRECATED_TYPE_IN_2_32_FOR(GRWLock);
struct _GStaticRWLock
{
/*< private >*/
GStaticMutex mutex;
GCond *read_cond;
GCond *write_cond;
guint read_counter;
gboolean have_writer;
guint want_to_read;
guint want_to_write;
} GLIB_DEPRECATED_TYPE_IN_2_32_FOR(GRWLock);
#define G_STATIC_RW_LOCK_INIT { G_STATIC_MUTEX_INIT, NULL, NULL, 0, FALSE, 0, 0 } GLIB_DEPRECATED_MACRO_IN_2_32_FOR(g_rw_lock_init)
GLIB_DEPRECATED_IN_2_32_FOR(g_rw_lock_init)
void g_static_rw_lock_init (GStaticRWLock *lock);
GLIB_DEPRECATED_IN_2_32_FOR(g_rw_lock_reader_lock)
void g_static_rw_lock_reader_lock (GStaticRWLock *lock);
GLIB_DEPRECATED_IN_2_32_FOR(g_rw_lock_reader_trylock)
gboolean g_static_rw_lock_reader_trylock (GStaticRWLock *lock);
GLIB_DEPRECATED_IN_2_32_FOR(g_rw_lock_reader_unlock)
void g_static_rw_lock_reader_unlock (GStaticRWLock *lock);
GLIB_DEPRECATED_IN_2_32_FOR(g_rw_lock_writer_lock)
void g_static_rw_lock_writer_lock (GStaticRWLock *lock);
GLIB_DEPRECATED_IN_2_32_FOR(g_rw_lock_writer_trylock)
gboolean g_static_rw_lock_writer_trylock (GStaticRWLock *lock);
GLIB_DEPRECATED_IN_2_32_FOR(g_rw_lock_writer_unlock)
void g_static_rw_lock_writer_unlock (GStaticRWLock *lock);
GLIB_DEPRECATED_IN_2_32_FOR(g_rw_lock_free)
void g_static_rw_lock_free (GStaticRWLock *lock);
GLIB_DEPRECATED_IN_2_32
GPrivate * g_private_new (GDestroyNotify notify);
typedef struct _GStaticPrivate GStaticPrivate GLIB_DEPRECATED_TYPE_IN_2_32_FOR(GPrivate);
struct _GStaticPrivate
{
/*< private >*/
guint index;
} GLIB_DEPRECATED_TYPE_IN_2_32_FOR(GPrivate);
#define G_STATIC_PRIVATE_INIT { 0 } GLIB_DEPRECATED_MACRO_IN_2_32_FOR(G_PRIVATE_INIT)
GLIB_DEPRECATED_IN_2_32
void g_static_private_init (GStaticPrivate *private_key);
GLIB_DEPRECATED_IN_2_32_FOR(g_private_get)
gpointer g_static_private_get (GStaticPrivate *private_key);
GLIB_DEPRECATED_IN_2_32_FOR(g_private_set)
void g_static_private_set (GStaticPrivate *private_key,
gpointer data,
GDestroyNotify notify);
GLIB_DEPRECATED_IN_2_32
void g_static_private_free (GStaticPrivate *private_key);
GLIB_DEPRECATED_IN_2_32
gboolean g_once_init_enter_impl (volatile gsize *location);
GLIB_DEPRECATED_IN_2_32
void g_thread_init (gpointer vtable);
GLIB_DEPRECATED_IN_2_32
void g_thread_init_with_errorcheck_mutexes (gpointer vtable);
GLIB_DEPRECATED_IN_2_32
gboolean g_thread_get_initialized (void);
GLIB_VAR gboolean g_threads_got_initialized;
#define g_thread_supported() (1) GLIB_DEPRECATED_MACRO_IN_2_32
GLIB_DEPRECATED_IN_2_32
GMutex * g_mutex_new (void);
GLIB_DEPRECATED_IN_2_32
void g_mutex_free (GMutex *mutex);
GLIB_DEPRECATED_IN_2_32
GCond * g_cond_new (void);
GLIB_DEPRECATED_IN_2_32
void g_cond_free (GCond *cond);
GLIB_DEPRECATED_IN_2_32
gboolean g_cond_timed_wait (GCond *cond,
GMutex *mutex,
GTimeVal *timeval);
G_GNUC_END_IGNORE_DEPRECATIONS
G_END_DECLS
#endif /* __G_DEPRECATED_THREAD_H__ */

2
glib/dirent/README Normal file
View file

@ -0,0 +1,2 @@
This is dirent from mingw-runtime-3.3, separated for MSVC user's
benefit.

19
glib/dirent/dirent-zip Normal file
View file

@ -0,0 +1,19 @@
#!/bin/sh
# Build developer package for the dirent library.
ZIP=/tmp/dirent.zip
mkdir -p dist/include dist/lib
cp dirent.h dist/include
cp dirent.lib dist/lib
(cd dist
rm $ZIP
zip $ZIP -@ <<EOF
include/dirent.h
lib/dirent.lib
EOF
)
rm -rf dist

341
glib/dirent/dirent.c Normal file
View file

@ -0,0 +1,341 @@
/*
* dirent.c
* This file has no copyright assigned and is placed in the Public Domain.
* This file is a part of the mingw-runtime package.
* No warranty is given; refer to the file DISCLAIMER within the package.
*
* Derived from DIRLIB.C by Matt J. Weinstein
* This note appears in the DIRLIB.H
* DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89
*
* Updated by Jeremy Bettis <jeremy@hksys.com>
* Significantly revised and rewinddir, seekdir and telldir added by Colin
* Peters <colin@fu.is.saga-u.ac.jp>
*
*/
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <io.h>
#include <direct.h>
#include "dirent.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h> /* for GetFileAttributes */
#include <tchar.h>
#ifdef _UNICODE
#define _tdirent _wdirent
#define _TDIR _WDIR
#define _topendir _wopendir
#define _tclosedir _wclosedir
#define _treaddir _wreaddir
#define _trewinddir _wrewinddir
#define _ttelldir _wtelldir
#define _tseekdir _wseekdir
#else
#define _tdirent dirent
#define _TDIR DIR
#define _topendir opendir
#define _tclosedir closedir
#define _treaddir readdir
#define _trewinddir rewinddir
#define _ttelldir telldir
#define _tseekdir seekdir
#endif
#define SUFFIX _T("*")
#define SLASH _T("\\")
/*
* opendir
*
* Returns a pointer to a DIR structure appropriately filled in to begin
* searching a directory.
*/
_TDIR *
_topendir (const _TCHAR *szPath)
{
_TDIR *nd;
unsigned int rc;
_TCHAR szFullPath[MAX_PATH];
errno = 0;
if (!szPath)
{
errno = EFAULT;
return (_TDIR *) 0;
}
if (szPath[0] == _T('\0'))
{
errno = ENOTDIR;
return (_TDIR *) 0;
}
/* Attempt to determine if the given path really is a directory. */
rc = GetFileAttributes (szPath);
if (rc == (unsigned int)-1)
{
/* call GetLastError for more error info */
errno = ENOENT;
return (_TDIR *) 0;
}
if (!(rc & FILE_ATTRIBUTE_DIRECTORY))
{
/* Error, entry exists but not a directory. */
errno = ENOTDIR;
return (_TDIR *) 0;
}
/* Make an absolute pathname. */
_tfullpath (szFullPath, szPath, MAX_PATH);
/* Allocate enough space to store DIR structure and the complete
* directory path given. */
nd = (_TDIR *) malloc (sizeof (_TDIR) + (_tcslen(szFullPath) + _tcslen (SLASH) +
_tcslen(SUFFIX) + 1) * sizeof(_TCHAR));
if (!nd)
{
/* Error, out of memory. */
errno = ENOMEM;
return (_TDIR *) 0;
}
/* Create the search expression. */
_tcscpy (nd->dd_name, szFullPath);
/* Add on a slash if the path does not end with one. */
if (nd->dd_name[0] != _T('\0') &&
nd->dd_name[_tcslen (nd->dd_name) - 1] != _T('/') &&
nd->dd_name[_tcslen (nd->dd_name) - 1] != _T('\\'))
{
_tcscat (nd->dd_name, SLASH);
}
/* Add on the search pattern */
_tcscat (nd->dd_name, SUFFIX);
/* Initialize handle to -1 so that a premature closedir doesn't try
* to call _findclose on it. */
nd->dd_handle = -1;
/* Initialize the status. */
nd->dd_stat = 0;
/* Initialize the dirent structure. ino and reclen are invalid under
* Win32, and name simply points at the appropriate part of the
* findfirst_t structure. */
nd->dd_dir.d_ino = 0;
nd->dd_dir.d_reclen = 0;
nd->dd_dir.d_namlen = 0;
memset (nd->dd_dir.d_name, 0, sizeof (nd->dd_dir.d_name));
return nd;
}
/*
* readdir
*
* Return a pointer to a dirent structure filled with the information on the
* next entry in the directory.
*/
struct _tdirent *
_treaddir (_TDIR * dirp)
{
errno = 0;
/* Check for valid DIR struct. */
if (!dirp)
{
errno = EFAULT;
return (struct _tdirent *) 0;
}
if (dirp->dd_stat < 0)
{
/* We have already returned all files in the directory
* (or the structure has an invalid dd_stat). */
return (struct _tdirent *) 0;
}
else if (dirp->dd_stat == 0)
{
/* We haven't started the search yet. */
/* Start the search */
dirp->dd_handle = _tfindfirst (dirp->dd_name, &(dirp->dd_dta));
if (dirp->dd_handle == -1)
{
/* Whoops! Seems there are no files in that
* directory. */
dirp->dd_stat = -1;
}
else
{
dirp->dd_stat = 1;
}
}
else
{
/* Get the next search entry. */
if (_tfindnext (dirp->dd_handle, &(dirp->dd_dta)))
{
/* We are off the end or otherwise error.
_findnext sets errno to ENOENT if no more file
Undo this. */
DWORD winerr = GetLastError();
if (winerr == ERROR_NO_MORE_FILES)
errno = 0;
_findclose (dirp->dd_handle);
dirp->dd_handle = -1;
dirp->dd_stat = -1;
}
else
{
/* Update the status to indicate the correct
* number. */
dirp->dd_stat++;
}
}
if (dirp->dd_stat > 0)
{
/* Successfully got an entry. Everything about the file is
* already appropriately filled in except the length of the
* file name. */
dirp->dd_dir.d_namlen = _tcslen (dirp->dd_dta.name);
_tcscpy (dirp->dd_dir.d_name, dirp->dd_dta.name);
return &dirp->dd_dir;
}
return (struct _tdirent *) 0;
}
/*
* closedir
*
* Frees up resources allocated by opendir.
*/
int
_tclosedir (_TDIR * dirp)
{
int rc;
errno = 0;
rc = 0;
if (!dirp)
{
errno = EFAULT;
return -1;
}
if (dirp->dd_handle != -1)
{
rc = _findclose (dirp->dd_handle);
}
/* Delete the dir structure. */
free (dirp);
return rc;
}
/*
* rewinddir
*
* Return to the beginning of the directory "stream". We simply call findclose
* and then reset things like an opendir.
*/
void
_trewinddir (_TDIR * dirp)
{
errno = 0;
if (!dirp)
{
errno = EFAULT;
return;
}
if (dirp->dd_handle != -1)
{
_findclose (dirp->dd_handle);
}
dirp->dd_handle = -1;
dirp->dd_stat = 0;
}
/*
* telldir
*
* Returns the "position" in the "directory stream" which can be used with
* seekdir to go back to an old entry. We simply return the value in stat.
*/
long
_ttelldir (_TDIR * dirp)
{
errno = 0;
if (!dirp)
{
errno = EFAULT;
return -1;
}
return dirp->dd_stat;
}
/*
* seekdir
*
* Seek to an entry previously returned by telldir. We rewind the directory
* and call readdir repeatedly until either dd_stat is the position number
* or -1 (off the end). This is not perfect, in that the directory may
* have changed while we weren't looking. But that is probably the case with
* any such system.
*/
void
_tseekdir (_TDIR * dirp, long lPos)
{
errno = 0;
if (!dirp)
{
errno = EFAULT;
return;
}
if (lPos < -1)
{
/* Seeking to an invalid position. */
errno = EINVAL;
return;
}
else if (lPos == -1)
{
/* Seek past end. */
if (dirp->dd_handle != -1)
{
_findclose (dirp->dd_handle);
}
dirp->dd_handle = -1;
dirp->dd_stat = -1;
}
else
{
/* Rewind and read forward to the appropriate index. */
_trewinddir (dirp);
while ((dirp->dd_stat < lPos) && _treaddir (dirp))
;
}
}

127
glib/dirent/dirent.h Normal file
View file

@ -0,0 +1,127 @@
/*
* DIRENT.H (formerly DIRLIB.H)
* This file has no copyright assigned and is placed in the Public Domain.
* This file is a part of the mingw-runtime package.
* No warranty is given; refer to the file DISCLAIMER within the package.
*
*/
#ifndef _DIRENT_H_
#define _DIRENT_H_
#include <stdio.h>
#include <io.h>
#ifndef RC_INVOKED
#ifdef __cplusplus
extern "C" {
#endif
struct dirent
{
long d_ino; /* Always zero. */
unsigned short d_reclen; /* Always zero. */
unsigned short d_namlen; /* Length of name in d_name. */
char d_name[FILENAME_MAX+1]; /* File name plus nul delimiter. */
};
#ifdef _WIN64
#define INTPTR __int64
#else
#define INTPTR long
#endif
/*
* This is an internal data structure. Good programmers will not use it
* except as an argument to one of the functions below.
* dd_stat field is now int (was short in older versions).
*/
typedef struct
{
/* disk transfer area for this dir */
struct _finddata_t dd_dta;
/* dirent struct to return from dir (NOTE: this makes this thread
* safe as long as only one thread uses a particular DIR struct at
* a time) */
struct dirent dd_dir;
/* _findnext handle */
INTPTR dd_handle;
/*
* Status of search:
* 0 = not started yet (next entry to read is first entry)
* -1 = off the end
* positive = 0 based index of next entry
*/
int dd_stat;
/* given path for dir with search pattern (struct is extended) */
char dd_name[1];
} DIR;
DIR* __cdecl opendir (const char*);
struct dirent* __cdecl readdir (DIR*);
int __cdecl closedir (DIR*);
void __cdecl rewinddir (DIR*);
long __cdecl telldir (DIR*);
void __cdecl seekdir (DIR*, long);
/* wide char versions */
struct _wdirent
{
long d_ino; /* Always zero. */
unsigned short d_reclen; /* Always zero. */
unsigned short d_namlen; /* Length of name in d_name. */
wchar_t d_name[FILENAME_MAX+1]; /* File name plus nul delimiter. */
};
/*
* This is an internal data structure. Good programmers will not use it
* except as an argument to one of the functions below.
*/
typedef struct
{
/* disk transfer area for this dir */
struct _wfinddata_t dd_dta;
/* dirent struct to return from dir (NOTE: this makes this thread
* safe as long as only one thread uses a particular DIR struct at
* a time) */
struct _wdirent dd_dir;
/* _findnext handle */
INTPTR dd_handle;
/*
* Status of search:
* 0 = not started yet (next entry to read is first entry)
* -1 = off the end
* positive = 0 based index of next entry
*/
int dd_stat;
/* given path for dir with search pattern (struct is extended) */
wchar_t dd_name[1];
} _WDIR;
_WDIR* __cdecl _wopendir (const wchar_t*);
struct _wdirent* __cdecl _wreaddir (_WDIR*);
int __cdecl _wclosedir (_WDIR*);
void __cdecl _wrewinddir (_WDIR*);
long __cdecl _wtelldir (_WDIR*);
void __cdecl _wseekdir (_WDIR*, long);
#ifdef __cplusplus
}
#endif
#endif /* Not RC_INVOKED */
#endif /* Not _DIRENT_H_ */

3
glib/dirent/wdirent.c Normal file
View file

@ -0,0 +1,3 @@
#define _UNICODE 1
#define UNICODE 1
#include "dirent.c"

2636
glib/docs.c Normal file

File diff suppressed because it is too large Load diff

145
glib/galloca.h Normal file
View file

@ -0,0 +1,145 @@
/* 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.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/.
*/
#ifndef __G_ALLOCA_H__
#define __G_ALLOCA_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtypes.h>
#include <string.h>
#if defined(__BIONIC__) && defined (GLIB_HAVE_ALLOCA_H)
# include <alloca.h>
#elif defined(__GNUC__)
/* GCC does the right thing */
# undef alloca
# define alloca(size) __builtin_alloca (size)
#elif defined (GLIB_HAVE_ALLOCA_H)
/* a native and working alloca.h is there */
# include <alloca.h>
#else /* !__GNUC__ && !GLIB_HAVE_ALLOCA_H */
# if defined(_MSC_VER) || defined(__DMC__)
# include <malloc.h>
# define alloca _alloca
# else /* !_MSC_VER && !__DMC__ */
# ifdef _AIX
# pragma alloca
# else /* !_AIX */
# ifndef alloca /* predefined by HP cc +Olibcalls */
G_BEGIN_DECLS
char *alloca ();
G_END_DECLS
# endif /* !alloca */
# endif /* !_AIX */
# endif /* !_MSC_VER && !__DMC__ */
#endif /* !__GNUC__ && !GLIB_HAVE_ALLOCA_H */
/**
* g_alloca:
* @size: number of bytes to allocate.
*
* Allocates @size bytes on the stack; these bytes will be freed when the current
* stack frame is cleaned up. This macro essentially just wraps the alloca()
* function present on most UNIX variants.
* Thus it provides the same advantages and pitfalls as alloca():
*
* - alloca() is very fast, as on most systems it's implemented by just adjusting
* the stack pointer register.
*
* - It doesn't cause any memory fragmentation, within its scope, separate alloca()
* blocks just build up and are released together at function end.
*
* - Allocation sizes have to fit into the current stack frame. For instance in a
* threaded environment on Linux, the per-thread stack size is limited to 2 Megabytes,
* so be sparse with alloca() uses.
*
* - Allocation failure due to insufficient stack space is not indicated with a %NULL
* return like e.g. with malloc(). Instead, most systems probably handle it the same
* way as out of stack space situations from infinite function recursion, i.e.
* with a segmentation fault.
*
* - Allowing @size to be specified by an untrusted party would allow for them
* to trigger a segmentation fault by specifying a large size, leading to a
* denial of service vulnerability. @size must always be entirely under the
* control of the program.
*
* - Special care has to be taken when mixing alloca() with GNU C variable sized arrays.
* Stack space allocated with alloca() in the same scope as a variable sized array
* will be freed together with the variable sized array upon exit of that scope, and
* not upon exit of the enclosing function scope.
*
* Returns: space for @size bytes, allocated on the stack
*/
#define g_alloca(size) alloca (size)
/**
* g_alloca0:
* @size: number of bytes to allocate.
*
* Wraps g_alloca() and initializes allocated memory to zeroes.
* If @size is `0` it returns %NULL.
*
* Note that the @size argument will be evaluated multiple times.
*
* Returns: (nullable) (transfer full): space for @size bytes, allocated on the stack
*
* Since: 2.72
*/
#define g_alloca0(size) ((size) == 0 ? NULL : memset (g_alloca (size), 0, (size)))
/**
* g_newa:
* @struct_type: Type of memory chunks to be allocated
* @n_structs: Number of chunks to be allocated
*
* Wraps g_alloca() in a more typesafe manner.
*
* As mentioned in the documentation for g_alloca(), @n_structs must always be
* entirely under the control of the program, or you may introduce a denial of
* service vulnerability. In addition, the multiplication of @struct_type by
* @n_structs is not checked, so an overflow may lead to a remote code execution
* vulnerability.
*
* Returns: Pointer to stack space for @n_structs chunks of type @struct_type
*/
#define g_newa(struct_type, n_structs) ((struct_type*) g_alloca (sizeof (struct_type) * (gsize) (n_structs)))
/**
* g_newa0:
* @struct_type: the type of the elements to allocate.
* @n_structs: the number of elements to allocate.
*
* Wraps g_alloca0() in a more typesafe manner.
*
* Returns: (nullable) (transfer full): Pointer to stack space for @n_structs
* chunks of type @struct_type
*
* Since: 2.72
*/
#define g_newa0(struct_type, n_structs) ((struct_type*) g_alloca0 (sizeof (struct_type) * (gsize) (n_structs)))
#endif /* __G_ALLOCA_H__ */

381
glib/garcbox.c Normal file
View file

@ -0,0 +1,381 @@
/* garcbox.c: Atomically reference counted data
*
* Copyright 2018 Emmanuele Bassi
*
* 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/>.
*/
#include "config.h"
#include "grcboxprivate.h"
#include "gmessages.h"
#include "grefcount.h"
#ifdef ENABLE_VALGRIND
#include "valgrind.h"
#endif
#include "glib_trace.h"
#include <string.h>
#define G_ARC_BOX(p) (GArcBox *) (((char *) (p)) - G_ARC_BOX_SIZE)
/**
* SECTION:arcbox
* @Title: Atomically reference counted data
* @Short_description: Allocated memory with atomic reference counting semantics
*
* An "atomically reference counted box", or "ArcBox", is an opaque wrapper
* data type that is guaranteed to be as big as the size of a given data type,
* and which augments the given data type with thread safe reference counting
* semantics for its memory management.
*
* ArcBox is useful if you have a plain old data type, like a structure
* typically placed on the stack, and you wish to provide additional API
* to use it on the heap; or if you want to implement a new type to be
* passed around by reference without necessarily implementing copy/free
* semantics or your own reference counting.
*
* The typical use is:
*
* |[<!-- language="C" -->
* typedef struct {
* char *name;
* char *address;
* char *city;
* char *state;
* int age;
* } Person;
*
* Person *
* person_new (void)
* {
* return g_atomic_rc_box_new0 (Person);
* }
* ]|
*
* Every time you wish to acquire a reference on the memory, you should
* call g_atomic_rc_box_acquire(); similarly, when you wish to release a reference
* you should call g_atomic_rc_box_release():
*
* |[<!-- language="C" -->
* // Add a Person to the Database; the Database acquires ownership
* // of the Person instance
* void
* add_person_to_database (Database *db, Person *p)
* {
* db->persons = g_list_prepend (db->persons, g_atomic_rc_box_acquire (p));
* }
*
* // Removes a Person from the Database; the reference acquired by
* // add_person_to_database() is released here
* void
* remove_person_from_database (Database *db, Person *p)
* {
* db->persons = g_list_remove (db->persons, p);
* g_atomic_rc_box_release (p);
* }
* ]|
*
* If you have additional memory allocated inside the structure, you can
* use g_atomic_rc_box_release_full(), which takes a function pointer, which
* will be called if the reference released was the last:
*
* |[<!-- language="C" -->
* void
* person_clear (Person *p)
* {
* g_free (p->name);
* g_free (p->address);
* g_free (p->city);
* g_free (p->state);
* }
*
* void
* remove_person_from_database (Database *db, Person *p)
* {
* db->persons = g_list_remove (db->persons, p);
* g_atomic_rc_box_release_full (p, (GDestroyNotify) person_clear);
* }
* ]|
*
* If you wish to transfer the ownership of a reference counted data
* type without increasing the reference count, you can use g_steal_pointer():
*
* |[<!-- language="C" -->
* Person *p = g_atomic_rc_box_new (Person);
*
* fill_person_details (p);
*
* add_person_to_database (db, g_steal_pointer (&p));
* ]|
*
* ## Thread safety
*
* The reference counting operations on data allocated using g_atomic_rc_box_alloc(),
* g_atomic_rc_box_new(), and g_atomic_rc_box_dup() are guaranteed to be atomic, and thus
* can be safely be performed by different threads. It is important to note that
* only the reference acquisition and release are atomic; changes to the content
* of the data are your responsibility.
*
* ## Automatic pointer clean up
*
* If you want to add g_autoptr() support to your plain old data type through
* reference counting, you can use the G_DEFINE_AUTOPTR_CLEANUP_FUNC() and
* g_atomic_rc_box_release():
*
* |[<!-- language="C" -->
* G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, g_atomic_rc_box_release)
* ]|
*
* If you need to clear the contents of the data, you will need to use an
* ancillary function that calls g_rc_box_release_full():
*
* |[<!-- language="C" -->
* static void
* my_data_struct_release (MyDataStruct *data)
* {
* // my_data_struct_clear() is defined elsewhere
* g_atomic_rc_box_release_full (data, (GDestroyNotify) my_data_struct_clear);
* }
*
* G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, my_data_struct_release)
* ]|
*
* Since: 2.58
*/
/**
* g_atomic_rc_box_alloc:
* @block_size: the size of the allocation, must be greater than 0
*
* Allocates @block_size bytes of memory, and adds atomic
* reference counting semantics to it.
*
* The data will be freed when its reference count drops to
* zero.
*
* The allocated data is guaranteed to be suitably aligned for any
* built-in type.
*
* Returns: (transfer full) (not nullable): a pointer to the allocated memory
*
* Since: 2.58
*/
gpointer
g_atomic_rc_box_alloc (gsize block_size)
{
g_return_val_if_fail (block_size > 0, NULL);
return g_rc_box_alloc_full (block_size, STRUCT_ALIGNMENT, TRUE, FALSE);
}
/**
* g_atomic_rc_box_alloc0:
* @block_size: the size of the allocation, must be greater than 0
*
* Allocates @block_size bytes of memory, and adds atomic
* reference counting semantics to it.
*
* The contents of the returned data is set to zero.
*
* The data will be freed when its reference count drops to
* zero.
*
* The allocated data is guaranteed to be suitably aligned for any
* built-in type.
*
* Returns: (transfer full) (not nullable): a pointer to the allocated memory
*
* Since: 2.58
*/
gpointer
g_atomic_rc_box_alloc0 (gsize block_size)
{
g_return_val_if_fail (block_size > 0, NULL);
return g_rc_box_alloc_full (block_size, STRUCT_ALIGNMENT, TRUE, TRUE);
}
/**
* g_atomic_rc_box_new:
* @type: the type to allocate, typically a structure name
*
* A convenience macro to allocate atomically reference counted
* data with the size of the given @type.
*
* This macro calls g_atomic_rc_box_alloc() with `sizeof (@type)` and
* casts the returned pointer to a pointer of the given @type,
* avoiding a type cast in the source code.
*
* Returns: (transfer full) (not nullable): a pointer to the allocated
* memory, cast to a pointer for the given @type
*
* Since: 2.58
*/
/**
* g_atomic_rc_box_new0:
* @type: the type to allocate, typically a structure name
*
* A convenience macro to allocate atomically reference counted
* data with the size of the given @type, and set its contents
* to zero.
*
* This macro calls g_atomic_rc_box_alloc0() with `sizeof (@type)` and
* casts the returned pointer to a pointer of the given @type,
* avoiding a type cast in the source code.
*
* Returns: (transfer full) (not nullable): a pointer to the allocated
* memory, cast to a pointer for the given @type
*
* Since: 2.58
*/
/**
* g_atomic_rc_box_dup:
* @block_size: the number of bytes to copy, must be greater than 0
* @mem_block: (not nullable): the memory to copy
*
* Allocates a new block of data with atomic reference counting
* semantics, and copies @block_size bytes of @mem_block
* into it.
*
* Returns: (transfer full) (not nullable): a pointer to the allocated
* memory
*
* Since: 2.58
*/
gpointer
(g_atomic_rc_box_dup) (gsize block_size,
gconstpointer mem_block)
{
gpointer res;
g_return_val_if_fail (block_size > 0, NULL);
g_return_val_if_fail (mem_block != NULL, NULL);
res = g_rc_box_alloc_full (block_size, STRUCT_ALIGNMENT, TRUE, FALSE);
memcpy (res, mem_block, block_size);
return res;
}
/**
* g_atomic_rc_box_acquire:
* @mem_block: (not nullable): a pointer to reference counted data
*
* Atomically acquires a reference on the data pointed by @mem_block.
*
* Returns: (transfer full) (not nullable): a pointer to the data,
* with its reference count increased
*
* Since: 2.58
*/
gpointer
(g_atomic_rc_box_acquire) (gpointer mem_block)
{
GArcBox *real_box = G_ARC_BOX (mem_block);
g_return_val_if_fail (mem_block != NULL, NULL);
#ifndef G_DISABLE_ASSERT
g_return_val_if_fail (real_box->magic == G_BOX_MAGIC, NULL);
#endif
g_atomic_ref_count_inc (&real_box->ref_count);
TRACE (GLIB_RCBOX_ACQUIRE (mem_block, 1));
return mem_block;
}
/**
* g_atomic_rc_box_release:
* @mem_block: (transfer full) (not nullable): a pointer to reference counted data
*
* Atomically releases a reference on the data pointed by @mem_block.
*
* If the reference was the last one, it will free the
* resources allocated for @mem_block.
*
* Since: 2.58
*/
void
g_atomic_rc_box_release (gpointer mem_block)
{
g_atomic_rc_box_release_full (mem_block, NULL);
}
/**
* g_atomic_rc_box_release_full:
* @mem_block: (transfer full) (not nullable): a pointer to reference counted data
* @clear_func: (not nullable): a function to call when clearing the data
*
* Atomically releases a reference on the data pointed by @mem_block.
*
* If the reference was the last one, it will call @clear_func
* to clear the contents of @mem_block, and then will free the
* resources allocated for @mem_block.
*
* Since: 2.58
*/
void
g_atomic_rc_box_release_full (gpointer mem_block,
GDestroyNotify clear_func)
{
GArcBox *real_box = G_ARC_BOX (mem_block);
g_return_if_fail (mem_block != NULL);
#ifndef G_DISABLE_ASSERT
g_return_if_fail (real_box->magic == G_BOX_MAGIC);
#endif
if (g_atomic_ref_count_dec (&real_box->ref_count))
{
char *real_mem = (char *) real_box - real_box->private_offset;
TRACE (GLIB_RCBOX_RELEASE (mem_block, 1));
if (clear_func != NULL)
clear_func (mem_block);
TRACE (GLIB_RCBOX_FREE (mem_block));
g_free (real_mem);
}
}
/**
* g_atomic_rc_box_get_size:
* @mem_block: (not nullable): a pointer to reference counted data
*
* Retrieves the size of the reference counted data pointed by @mem_block.
*
* Returns: the size of the data, in bytes
*
* Since: 2.58
*/
gsize
g_atomic_rc_box_get_size (gpointer mem_block)
{
GArcBox *real_box = G_ARC_BOX (mem_block);
g_return_val_if_fail (mem_block != NULL, 0);
#ifndef G_DISABLE_ASSERT
g_return_val_if_fail (real_box->magic == G_BOX_MAGIC, 0);
#endif
return real_box->mem_size;
}

2576
glib/garray.c Normal file

File diff suppressed because it is too large Load diff

281
glib/garray.h Normal file
View file

@ -0,0 +1,281 @@
/* 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.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/.
*/
#ifndef __G_ARRAY_H__
#define __G_ARRAY_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtypes.h>
G_BEGIN_DECLS
typedef struct _GBytes GBytes;
typedef struct _GArray GArray;
typedef struct _GByteArray GByteArray;
typedef struct _GPtrArray GPtrArray;
struct _GArray
{
gchar *data;
guint len;
};
struct _GByteArray
{
guint8 *data;
guint len;
};
struct _GPtrArray
{
gpointer *pdata;
guint len;
};
/* Resizable arrays. remove fills any cleared spot and shortens the
* array, while preserving the order. remove_fast will distort the
* order by moving the last element to the position of the removed.
*/
#define g_array_append_val(a,v) g_array_append_vals (a, &(v), 1)
#define g_array_prepend_val(a,v) g_array_prepend_vals (a, &(v), 1)
#define g_array_insert_val(a,i,v) g_array_insert_vals (a, i, &(v), 1)
#define g_array_index(a,t,i) (((t*) (void *) (a)->data) [(i)])
GLIB_AVAILABLE_IN_ALL
GArray* g_array_new (gboolean zero_terminated,
gboolean clear_,
guint element_size);
GLIB_AVAILABLE_IN_2_64
gpointer g_array_steal (GArray *array,
gsize *len);
GLIB_AVAILABLE_IN_ALL
GArray* g_array_sized_new (gboolean zero_terminated,
gboolean clear_,
guint element_size,
guint reserved_size);
GLIB_AVAILABLE_IN_2_62
GArray* g_array_copy (GArray *array);
GLIB_AVAILABLE_IN_ALL
gchar* g_array_free (GArray *array,
gboolean free_segment);
GLIB_AVAILABLE_IN_ALL
GArray *g_array_ref (GArray *array);
GLIB_AVAILABLE_IN_ALL
void g_array_unref (GArray *array);
GLIB_AVAILABLE_IN_ALL
guint g_array_get_element_size (GArray *array);
GLIB_AVAILABLE_IN_ALL
GArray* g_array_append_vals (GArray *array,
gconstpointer data,
guint len);
GLIB_AVAILABLE_IN_ALL
GArray* g_array_prepend_vals (GArray *array,
gconstpointer data,
guint len);
GLIB_AVAILABLE_IN_ALL
GArray* g_array_insert_vals (GArray *array,
guint index_,
gconstpointer data,
guint len);
GLIB_AVAILABLE_IN_ALL
GArray* g_array_set_size (GArray *array,
guint length);
GLIB_AVAILABLE_IN_ALL
GArray* g_array_remove_index (GArray *array,
guint index_);
GLIB_AVAILABLE_IN_ALL
GArray* g_array_remove_index_fast (GArray *array,
guint index_);
GLIB_AVAILABLE_IN_ALL
GArray* g_array_remove_range (GArray *array,
guint index_,
guint length);
GLIB_AVAILABLE_IN_ALL
void g_array_sort (GArray *array,
GCompareFunc compare_func);
GLIB_AVAILABLE_IN_ALL
void g_array_sort_with_data (GArray *array,
GCompareDataFunc compare_func,
gpointer user_data);
GLIB_AVAILABLE_IN_2_62
gboolean g_array_binary_search (GArray *array,
gconstpointer target,
GCompareFunc compare_func,
guint *out_match_index);
GLIB_AVAILABLE_IN_ALL
void g_array_set_clear_func (GArray *array,
GDestroyNotify clear_func);
/* Resizable pointer array. This interface is much less complicated
* than the above. Add appends a pointer. Remove fills any cleared
* spot and shortens the array. remove_fast will again distort order.
*/
#define g_ptr_array_index(array,index_) ((array)->pdata)[index_]
GLIB_AVAILABLE_IN_ALL
GPtrArray* g_ptr_array_new (void);
GLIB_AVAILABLE_IN_ALL
GPtrArray* g_ptr_array_new_with_free_func (GDestroyNotify element_free_func);
GLIB_AVAILABLE_IN_2_64
gpointer* g_ptr_array_steal (GPtrArray *array,
gsize *len);
GLIB_AVAILABLE_IN_2_62
GPtrArray *g_ptr_array_copy (GPtrArray *array,
GCopyFunc func,
gpointer user_data);
GLIB_AVAILABLE_IN_ALL
GPtrArray* g_ptr_array_sized_new (guint reserved_size);
GLIB_AVAILABLE_IN_ALL
GPtrArray* g_ptr_array_new_full (guint reserved_size,
GDestroyNotify element_free_func);
GLIB_AVAILABLE_IN_ALL
gpointer* g_ptr_array_free (GPtrArray *array,
gboolean free_seg);
GLIB_AVAILABLE_IN_ALL
GPtrArray* g_ptr_array_ref (GPtrArray *array);
GLIB_AVAILABLE_IN_ALL
void g_ptr_array_unref (GPtrArray *array);
GLIB_AVAILABLE_IN_ALL
void g_ptr_array_set_free_func (GPtrArray *array,
GDestroyNotify element_free_func);
GLIB_AVAILABLE_IN_ALL
void g_ptr_array_set_size (GPtrArray *array,
gint length);
GLIB_AVAILABLE_IN_ALL
gpointer g_ptr_array_remove_index (GPtrArray *array,
guint index_);
GLIB_AVAILABLE_IN_ALL
gpointer g_ptr_array_remove_index_fast (GPtrArray *array,
guint index_);
GLIB_AVAILABLE_IN_2_58
gpointer g_ptr_array_steal_index (GPtrArray *array,
guint index_);
GLIB_AVAILABLE_IN_2_58
gpointer g_ptr_array_steal_index_fast (GPtrArray *array,
guint index_);
GLIB_AVAILABLE_IN_ALL
gboolean g_ptr_array_remove (GPtrArray *array,
gpointer data);
GLIB_AVAILABLE_IN_ALL
gboolean g_ptr_array_remove_fast (GPtrArray *array,
gpointer data);
GLIB_AVAILABLE_IN_ALL
GPtrArray *g_ptr_array_remove_range (GPtrArray *array,
guint index_,
guint length);
GLIB_AVAILABLE_IN_ALL
void g_ptr_array_add (GPtrArray *array,
gpointer data);
GLIB_AVAILABLE_IN_2_62
void g_ptr_array_extend (GPtrArray *array_to_extend,
GPtrArray *array,
GCopyFunc func,
gpointer user_data);
GLIB_AVAILABLE_IN_2_62
void g_ptr_array_extend_and_steal (GPtrArray *array_to_extend,
GPtrArray *array);
GLIB_AVAILABLE_IN_2_40
void g_ptr_array_insert (GPtrArray *array,
gint index_,
gpointer data);
GLIB_AVAILABLE_IN_ALL
void g_ptr_array_sort (GPtrArray *array,
GCompareFunc compare_func);
GLIB_AVAILABLE_IN_ALL
void g_ptr_array_sort_with_data (GPtrArray *array,
GCompareDataFunc compare_func,
gpointer user_data);
GLIB_AVAILABLE_IN_ALL
void g_ptr_array_foreach (GPtrArray *array,
GFunc func,
gpointer user_data);
GLIB_AVAILABLE_IN_2_54
gboolean g_ptr_array_find (GPtrArray *haystack,
gconstpointer needle,
guint *index_);
GLIB_AVAILABLE_IN_2_54
gboolean g_ptr_array_find_with_equal_func (GPtrArray *haystack,
gconstpointer needle,
GEqualFunc equal_func,
guint *index_);
/* Byte arrays, an array of guint8. Implemented as a GArray,
* but type-safe.
*/
GLIB_AVAILABLE_IN_ALL
GByteArray* g_byte_array_new (void);
GLIB_AVAILABLE_IN_ALL
GByteArray* g_byte_array_new_take (guint8 *data,
gsize len);
GLIB_AVAILABLE_IN_2_64
guint8* g_byte_array_steal (GByteArray *array,
gsize *len);
GLIB_AVAILABLE_IN_ALL
GByteArray* g_byte_array_sized_new (guint reserved_size);
GLIB_AVAILABLE_IN_ALL
guint8* g_byte_array_free (GByteArray *array,
gboolean free_segment);
GLIB_AVAILABLE_IN_ALL
GBytes* g_byte_array_free_to_bytes (GByteArray *array);
GLIB_AVAILABLE_IN_ALL
GByteArray *g_byte_array_ref (GByteArray *array);
GLIB_AVAILABLE_IN_ALL
void g_byte_array_unref (GByteArray *array);
GLIB_AVAILABLE_IN_ALL
GByteArray* g_byte_array_append (GByteArray *array,
const guint8 *data,
guint len);
GLIB_AVAILABLE_IN_ALL
GByteArray* g_byte_array_prepend (GByteArray *array,
const guint8 *data,
guint len);
GLIB_AVAILABLE_IN_ALL
GByteArray* g_byte_array_set_size (GByteArray *array,
guint length);
GLIB_AVAILABLE_IN_ALL
GByteArray* g_byte_array_remove_index (GByteArray *array,
guint index_);
GLIB_AVAILABLE_IN_ALL
GByteArray* g_byte_array_remove_index_fast (GByteArray *array,
guint index_);
GLIB_AVAILABLE_IN_ALL
GByteArray* g_byte_array_remove_range (GByteArray *array,
guint index_,
guint length);
GLIB_AVAILABLE_IN_ALL
void g_byte_array_sort (GByteArray *array,
GCompareFunc compare_func);
GLIB_AVAILABLE_IN_ALL
void g_byte_array_sort_with_data (GByteArray *array,
GCompareDataFunc compare_func,
gpointer user_data);
G_END_DECLS
#endif /* __G_ARRAY_H__ */

906
glib/gasyncqueue.c Normal file
View file

@ -0,0 +1,906 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* GAsyncQueue: asynchronous queue implementation, based on GQueue.
* Copyright (C) 2000 Sebastian Wilhelmi; University of Karlsruhe
*
* 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/>.
*/
/*
* MT safe
*/
#include "config.h"
#include "gasyncqueue.h"
#include "gasyncqueueprivate.h"
#include "gmain.h"
#include "gmem.h"
#include "gqueue.h"
#include "gtestutils.h"
#include "gtimer.h"
#include "gthread.h"
#include "deprecated/gthread.h"
/**
* SECTION:async_queues
* @title: Asynchronous Queues
* @short_description: asynchronous communication between threads
* @see_also: #GThreadPool
*
* Often you need to communicate between different threads. In general
* it's safer not to do this by shared memory, but by explicit message
* passing. These messages only make sense asynchronously for
* multi-threaded applications though, as a synchronous operation could
* as well be done in the same thread.
*
* Asynchronous queues are an exception from most other GLib data
* structures, as they can be used simultaneously from multiple threads
* without explicit locking and they bring their own builtin reference
* counting. This is because the nature of an asynchronous queue is that
* it will always be used by at least 2 concurrent threads.
*
* For using an asynchronous queue you first have to create one with
* g_async_queue_new(). #GAsyncQueue structs are reference counted,
* use g_async_queue_ref() and g_async_queue_unref() to manage your
* references.
*
* A thread which wants to send a message to that queue simply calls
* g_async_queue_push() to push the message to the queue.
*
* A thread which is expecting messages from an asynchronous queue
* simply calls g_async_queue_pop() for that queue. If no message is
* available in the queue at that point, the thread is now put to sleep
* until a message arrives. The message will be removed from the queue
* and returned. The functions g_async_queue_try_pop() and
* g_async_queue_timeout_pop() can be used to only check for the presence
* of messages or to only wait a certain time for messages respectively.
*
* For almost every function there exist two variants, one that locks
* the queue and one that doesn't. That way you can hold the queue lock
* (acquire it with g_async_queue_lock() and release it with
* g_async_queue_unlock()) over multiple queue accessing instructions.
* This can be necessary to ensure the integrity of the queue, but should
* only be used when really necessary, as it can make your life harder
* if used unwisely. Normally you should only use the locking function
* variants (those without the _unlocked suffix).
*
* In many cases, it may be more convenient to use #GThreadPool when
* you need to distribute work to a set of worker threads instead of
* using #GAsyncQueue manually. #GThreadPool uses a GAsyncQueue
* internally.
*/
/**
* GAsyncQueue:
*
* An opaque data structure which represents an asynchronous queue.
*
* It should only be accessed through the `g_async_queue_*` functions.
*/
struct _GAsyncQueue
{
GMutex mutex;
GCond cond;
GQueue queue;
GDestroyNotify item_free_func;
guint waiting_threads;
gint ref_count;
};
typedef struct
{
GCompareDataFunc func;
gpointer user_data;
} SortData;
/**
* g_async_queue_new:
*
* Creates a new asynchronous queue.
*
* Returns: a new #GAsyncQueue. Free with g_async_queue_unref()
*/
GAsyncQueue *
g_async_queue_new (void)
{
return g_async_queue_new_full (NULL);
}
/**
* g_async_queue_new_full:
* @item_free_func: (nullable): function to free queue elements
*
* Creates a new asynchronous queue and sets up a destroy notify
* function that is used to free any remaining queue items when
* the queue is destroyed after the final unref.
*
* Returns: a new #GAsyncQueue. Free with g_async_queue_unref()
*
* Since: 2.16
*/
GAsyncQueue *
g_async_queue_new_full (GDestroyNotify item_free_func)
{
GAsyncQueue *queue;
queue = g_new (GAsyncQueue, 1);
g_mutex_init (&queue->mutex);
g_cond_init (&queue->cond);
g_queue_init (&queue->queue);
queue->waiting_threads = 0;
queue->ref_count = 1;
queue->item_free_func = item_free_func;
return queue;
}
/**
* g_async_queue_ref:
* @queue: a #GAsyncQueue
*
* Increases the reference count of the asynchronous @queue by 1.
* You do not need to hold the lock to call this function.
*
* Returns: the @queue that was passed in (since 2.6)
*/
GAsyncQueue *
g_async_queue_ref (GAsyncQueue *queue)
{
g_return_val_if_fail (queue, NULL);
g_atomic_int_inc (&queue->ref_count);
return queue;
}
/**
* g_async_queue_ref_unlocked:
* @queue: a #GAsyncQueue
*
* Increases the reference count of the asynchronous @queue by 1.
*
* Deprecated: 2.8: Reference counting is done atomically.
* so g_async_queue_ref() can be used regardless of the @queue's
* lock.
*/
void
g_async_queue_ref_unlocked (GAsyncQueue *queue)
{
g_return_if_fail (queue);
g_atomic_int_inc (&queue->ref_count);
}
/**
* g_async_queue_unref_and_unlock:
* @queue: a #GAsyncQueue
*
* Decreases the reference count of the asynchronous @queue by 1
* and releases the lock. This function must be called while holding
* the @queue's lock. If the reference count went to 0, the @queue
* will be destroyed and the memory allocated will be freed.
*
* Deprecated: 2.8: Reference counting is done atomically.
* so g_async_queue_unref() can be used regardless of the @queue's
* lock.
*/
void
g_async_queue_unref_and_unlock (GAsyncQueue *queue)
{
g_return_if_fail (queue);
g_mutex_unlock (&queue->mutex);
g_async_queue_unref (queue);
}
/**
* g_async_queue_unref:
* @queue: a #GAsyncQueue.
*
* Decreases the reference count of the asynchronous @queue by 1.
*
* If the reference count went to 0, the @queue will be destroyed
* and the memory allocated will be freed. So you are not allowed
* to use the @queue afterwards, as it might have disappeared.
* You do not need to hold the lock to call this function.
*/
void
g_async_queue_unref (GAsyncQueue *queue)
{
g_return_if_fail (queue);
if (g_atomic_int_dec_and_test (&queue->ref_count))
{
g_return_if_fail (queue->waiting_threads == 0);
g_mutex_clear (&queue->mutex);
g_cond_clear (&queue->cond);
if (queue->item_free_func)
g_queue_foreach (&queue->queue, (GFunc) queue->item_free_func, NULL);
g_queue_clear (&queue->queue);
g_free (queue);
}
}
/**
* g_async_queue_lock:
* @queue: a #GAsyncQueue
*
* Acquires the @queue's lock. If another thread is already
* holding the lock, this call will block until the lock
* becomes available.
*
* Call g_async_queue_unlock() to drop the lock again.
*
* While holding the lock, you can only call the
* g_async_queue_*_unlocked() functions on @queue. Otherwise,
* deadlock may occur.
*/
void
g_async_queue_lock (GAsyncQueue *queue)
{
g_return_if_fail (queue);
g_mutex_lock (&queue->mutex);
}
/**
* g_async_queue_unlock:
* @queue: a #GAsyncQueue
*
* Releases the queue's lock.
*
* Calling this function when you have not acquired
* the with g_async_queue_lock() leads to undefined
* behaviour.
*/
void
g_async_queue_unlock (GAsyncQueue *queue)
{
g_return_if_fail (queue);
g_mutex_unlock (&queue->mutex);
}
/**
* g_async_queue_push:
* @queue: a #GAsyncQueue
* @data: @data to push into the @queue
*
* Pushes the @data into the @queue. @data must not be %NULL.
*/
void
g_async_queue_push (GAsyncQueue *queue,
gpointer data)
{
g_return_if_fail (queue);
g_return_if_fail (data);
g_mutex_lock (&queue->mutex);
g_async_queue_push_unlocked (queue, data);
g_mutex_unlock (&queue->mutex);
}
/**
* g_async_queue_push_unlocked:
* @queue: a #GAsyncQueue
* @data: @data to push into the @queue
*
* Pushes the @data into the @queue. @data must not be %NULL.
*
* This function must be called while holding the @queue's lock.
*/
void
g_async_queue_push_unlocked (GAsyncQueue *queue,
gpointer data)
{
g_return_if_fail (queue);
g_return_if_fail (data);
g_queue_push_head (&queue->queue, data);
if (queue->waiting_threads > 0)
g_cond_signal (&queue->cond);
}
/**
* g_async_queue_push_sorted:
* @queue: a #GAsyncQueue
* @data: the @data to push into the @queue
* @func: the #GCompareDataFunc is used to sort @queue
* @user_data: user data passed to @func.
*
* Inserts @data into @queue using @func to determine the new
* position.
*
* This function requires that the @queue is sorted before pushing on
* new elements, see g_async_queue_sort().
*
* This function will lock @queue before it sorts the queue and unlock
* it when it is finished.
*
* For an example of @func see g_async_queue_sort().
*
* Since: 2.10
*/
void
g_async_queue_push_sorted (GAsyncQueue *queue,
gpointer data,
GCompareDataFunc func,
gpointer user_data)
{
g_return_if_fail (queue != NULL);
g_mutex_lock (&queue->mutex);
g_async_queue_push_sorted_unlocked (queue, data, func, user_data);
g_mutex_unlock (&queue->mutex);
}
static gint
g_async_queue_invert_compare (gpointer v1,
gpointer v2,
SortData *sd)
{
return -sd->func (v1, v2, sd->user_data);
}
/**
* g_async_queue_push_sorted_unlocked:
* @queue: a #GAsyncQueue
* @data: the @data to push into the @queue
* @func: the #GCompareDataFunc is used to sort @queue
* @user_data: user data passed to @func.
*
* Inserts @data into @queue using @func to determine the new
* position.
*
* The sort function @func is passed two elements of the @queue.
* It should return 0 if they are equal, a negative value if the
* first element should be higher in the @queue or a positive value
* if the first element should be lower in the @queue than the second
* element.
*
* This function requires that the @queue is sorted before pushing on
* new elements, see g_async_queue_sort().
*
* This function must be called while holding the @queue's lock.
*
* For an example of @func see g_async_queue_sort().
*
* Since: 2.10
*/
void
g_async_queue_push_sorted_unlocked (GAsyncQueue *queue,
gpointer data,
GCompareDataFunc func,
gpointer user_data)
{
SortData sd;
g_return_if_fail (queue != NULL);
sd.func = func;
sd.user_data = user_data;
g_queue_insert_sorted (&queue->queue,
data,
(GCompareDataFunc)g_async_queue_invert_compare,
&sd);
if (queue->waiting_threads > 0)
g_cond_signal (&queue->cond);
}
static gpointer
g_async_queue_pop_intern_unlocked (GAsyncQueue *queue,
gboolean wait,
gint64 end_time)
{
gpointer retval;
if (!g_queue_peek_tail_link (&queue->queue) && wait)
{
queue->waiting_threads++;
while (!g_queue_peek_tail_link (&queue->queue))
{
if (end_time == -1)
g_cond_wait (&queue->cond, &queue->mutex);
else
{
if (!g_cond_wait_until (&queue->cond, &queue->mutex, end_time))
break;
}
}
queue->waiting_threads--;
}
retval = g_queue_pop_tail (&queue->queue);
g_assert (retval || !wait || end_time > 0);
return retval;
}
/**
* g_async_queue_pop:
* @queue: a #GAsyncQueue
*
* Pops data from the @queue. If @queue is empty, this function
* blocks until data becomes available.
*
* Returns: data from the queue
*/
gpointer
g_async_queue_pop (GAsyncQueue *queue)
{
gpointer retval;
g_return_val_if_fail (queue, NULL);
g_mutex_lock (&queue->mutex);
retval = g_async_queue_pop_intern_unlocked (queue, TRUE, -1);
g_mutex_unlock (&queue->mutex);
return retval;
}
/**
* g_async_queue_pop_unlocked:
* @queue: a #GAsyncQueue
*
* Pops data from the @queue. If @queue is empty, this function
* blocks until data becomes available.
*
* This function must be called while holding the @queue's lock.
*
* Returns: data from the queue.
*/
gpointer
g_async_queue_pop_unlocked (GAsyncQueue *queue)
{
g_return_val_if_fail (queue, NULL);
return g_async_queue_pop_intern_unlocked (queue, TRUE, -1);
}
/**
* g_async_queue_try_pop:
* @queue: a #GAsyncQueue
*
* Tries to pop data from the @queue. If no data is available,
* %NULL is returned.
*
* Returns: (nullable): data from the queue or %NULL, when no data is
* available immediately.
*/
gpointer
g_async_queue_try_pop (GAsyncQueue *queue)
{
gpointer retval;
g_return_val_if_fail (queue, NULL);
g_mutex_lock (&queue->mutex);
retval = g_async_queue_pop_intern_unlocked (queue, FALSE, -1);
g_mutex_unlock (&queue->mutex);
return retval;
}
/**
* g_async_queue_try_pop_unlocked:
* @queue: a #GAsyncQueue
*
* Tries to pop data from the @queue. If no data is available,
* %NULL is returned.
*
* This function must be called while holding the @queue's lock.
*
* Returns: (nullable): data from the queue or %NULL, when no data is
* available immediately.
*/
gpointer
g_async_queue_try_pop_unlocked (GAsyncQueue *queue)
{
g_return_val_if_fail (queue, NULL);
return g_async_queue_pop_intern_unlocked (queue, FALSE, -1);
}
/**
* g_async_queue_timeout_pop:
* @queue: a #GAsyncQueue
* @timeout: the number of microseconds to wait
*
* Pops data from the @queue. If the queue is empty, blocks for
* @timeout microseconds, or until data becomes available.
*
* If no data is received before the timeout, %NULL is returned.
*
* Returns: (nullable): data from the queue or %NULL, when no data is
* received before the timeout.
*/
gpointer
g_async_queue_timeout_pop (GAsyncQueue *queue,
guint64 timeout)
{
gint64 end_time = g_get_monotonic_time () + timeout;
gpointer retval;
g_return_val_if_fail (queue != NULL, NULL);
g_mutex_lock (&queue->mutex);
retval = g_async_queue_pop_intern_unlocked (queue, TRUE, end_time);
g_mutex_unlock (&queue->mutex);
return retval;
}
/**
* g_async_queue_timeout_pop_unlocked:
* @queue: a #GAsyncQueue
* @timeout: the number of microseconds to wait
*
* Pops data from the @queue. If the queue is empty, blocks for
* @timeout microseconds, or until data becomes available.
*
* If no data is received before the timeout, %NULL is returned.
*
* This function must be called while holding the @queue's lock.
*
* Returns: (nullable): data from the queue or %NULL, when no data is
* received before the timeout.
*/
gpointer
g_async_queue_timeout_pop_unlocked (GAsyncQueue *queue,
guint64 timeout)
{
gint64 end_time = g_get_monotonic_time () + timeout;
g_return_val_if_fail (queue != NULL, NULL);
return g_async_queue_pop_intern_unlocked (queue, TRUE, end_time);
}
/**
* g_async_queue_timed_pop:
* @queue: a #GAsyncQueue
* @end_time: a #GTimeVal, determining the final time
*
* Pops data from the @queue. If the queue is empty, blocks until
* @end_time or until data becomes available.
*
* If no data is received before @end_time, %NULL is returned.
*
* To easily calculate @end_time, a combination of g_get_real_time()
* and g_time_val_add() can be used.
*
* Returns: (nullable): data from the queue or %NULL, when no data is
* received before @end_time.
*
* Deprecated: use g_async_queue_timeout_pop().
*/
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gpointer
g_async_queue_timed_pop (GAsyncQueue *queue,
GTimeVal *end_time)
{
gint64 m_end_time;
gpointer retval;
g_return_val_if_fail (queue, NULL);
if (end_time != NULL)
{
m_end_time = g_get_monotonic_time () +
((gint64) end_time->tv_sec * G_USEC_PER_SEC + end_time->tv_usec - g_get_real_time ());
}
else
m_end_time = -1;
g_mutex_lock (&queue->mutex);
retval = g_async_queue_pop_intern_unlocked (queue, TRUE, m_end_time);
g_mutex_unlock (&queue->mutex);
return retval;
}
G_GNUC_END_IGNORE_DEPRECATIONS
/**
* g_async_queue_timed_pop_unlocked:
* @queue: a #GAsyncQueue
* @end_time: a #GTimeVal, determining the final time
*
* Pops data from the @queue. If the queue is empty, blocks until
* @end_time or until data becomes available.
*
* If no data is received before @end_time, %NULL is returned.
*
* To easily calculate @end_time, a combination of g_get_real_time()
* and g_time_val_add() can be used.
*
* This function must be called while holding the @queue's lock.
*
* Returns: (nullable): data from the queue or %NULL, when no data is
* received before @end_time.
*
* Deprecated: use g_async_queue_timeout_pop_unlocked().
*/
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gpointer
g_async_queue_timed_pop_unlocked (GAsyncQueue *queue,
GTimeVal *end_time)
{
gint64 m_end_time;
g_return_val_if_fail (queue, NULL);
if (end_time != NULL)
{
m_end_time = g_get_monotonic_time () +
((gint64) end_time->tv_sec * G_USEC_PER_SEC + end_time->tv_usec - g_get_real_time ());
}
else
m_end_time = -1;
return g_async_queue_pop_intern_unlocked (queue, TRUE, m_end_time);
}
G_GNUC_END_IGNORE_DEPRECATIONS
/**
* g_async_queue_length:
* @queue: a #GAsyncQueue.
*
* Returns the length of the queue.
*
* Actually this function returns the number of data items in
* the queue minus the number of waiting threads, so a negative
* value means waiting threads, and a positive value means available
* entries in the @queue. A return value of 0 could mean n entries
* in the queue and n threads waiting. This can happen due to locking
* of the queue or due to scheduling.
*
* Returns: the length of the @queue
*/
gint
g_async_queue_length (GAsyncQueue *queue)
{
gint retval;
g_return_val_if_fail (queue, 0);
g_mutex_lock (&queue->mutex);
retval = queue->queue.length - queue->waiting_threads;
g_mutex_unlock (&queue->mutex);
return retval;
}
/**
* g_async_queue_length_unlocked:
* @queue: a #GAsyncQueue
*
* Returns the length of the queue.
*
* Actually this function returns the number of data items in
* the queue minus the number of waiting threads, so a negative
* value means waiting threads, and a positive value means available
* entries in the @queue. A return value of 0 could mean n entries
* in the queue and n threads waiting. This can happen due to locking
* of the queue or due to scheduling.
*
* This function must be called while holding the @queue's lock.
*
* Returns: the length of the @queue.
*/
gint
g_async_queue_length_unlocked (GAsyncQueue *queue)
{
g_return_val_if_fail (queue, 0);
return queue->queue.length - queue->waiting_threads;
}
/**
* g_async_queue_sort:
* @queue: a #GAsyncQueue
* @func: the #GCompareDataFunc is used to sort @queue
* @user_data: user data passed to @func
*
* Sorts @queue using @func.
*
* The sort function @func is passed two elements of the @queue.
* It should return 0 if they are equal, a negative value if the
* first element should be higher in the @queue or a positive value
* if the first element should be lower in the @queue than the second
* element.
*
* This function will lock @queue before it sorts the queue and unlock
* it when it is finished.
*
* If you were sorting a list of priority numbers to make sure the
* lowest priority would be at the top of the queue, you could use:
* |[<!-- language="C" -->
* gint32 id1;
* gint32 id2;
*
* id1 = GPOINTER_TO_INT (element1);
* id2 = GPOINTER_TO_INT (element2);
*
* return (id1 > id2 ? +1 : id1 == id2 ? 0 : -1);
* ]|
*
* Since: 2.10
*/
void
g_async_queue_sort (GAsyncQueue *queue,
GCompareDataFunc func,
gpointer user_data)
{
g_return_if_fail (queue != NULL);
g_return_if_fail (func != NULL);
g_mutex_lock (&queue->mutex);
g_async_queue_sort_unlocked (queue, func, user_data);
g_mutex_unlock (&queue->mutex);
}
/**
* g_async_queue_sort_unlocked:
* @queue: a #GAsyncQueue
* @func: the #GCompareDataFunc is used to sort @queue
* @user_data: user data passed to @func
*
* Sorts @queue using @func.
*
* The sort function @func is passed two elements of the @queue.
* It should return 0 if they are equal, a negative value if the
* first element should be higher in the @queue or a positive value
* if the first element should be lower in the @queue than the second
* element.
*
* This function must be called while holding the @queue's lock.
*
* Since: 2.10
*/
void
g_async_queue_sort_unlocked (GAsyncQueue *queue,
GCompareDataFunc func,
gpointer user_data)
{
SortData sd;
g_return_if_fail (queue != NULL);
g_return_if_fail (func != NULL);
sd.func = func;
sd.user_data = user_data;
g_queue_sort (&queue->queue,
(GCompareDataFunc)g_async_queue_invert_compare,
&sd);
}
/**
* g_async_queue_remove:
* @queue: a #GAsyncQueue
* @item: the data to remove from the @queue
*
* Remove an item from the queue.
*
* Returns: %TRUE if the item was removed
*
* Since: 2.46
*/
gboolean
g_async_queue_remove (GAsyncQueue *queue,
gpointer item)
{
gboolean ret;
g_return_val_if_fail (queue != NULL, FALSE);
g_return_val_if_fail (item != NULL, FALSE);
g_mutex_lock (&queue->mutex);
ret = g_async_queue_remove_unlocked (queue, item);
g_mutex_unlock (&queue->mutex);
return ret;
}
/**
* g_async_queue_remove_unlocked:
* @queue: a #GAsyncQueue
* @item: the data to remove from the @queue
*
* Remove an item from the queue.
*
* This function must be called while holding the @queue's lock.
*
* Returns: %TRUE if the item was removed
*
* Since: 2.46
*/
gboolean
g_async_queue_remove_unlocked (GAsyncQueue *queue,
gpointer item)
{
g_return_val_if_fail (queue != NULL, FALSE);
g_return_val_if_fail (item != NULL, FALSE);
return g_queue_remove (&queue->queue, item);
}
/**
* g_async_queue_push_front:
* @queue: a #GAsyncQueue
* @item: data to push into the @queue
*
* Pushes the @item into the @queue. @item must not be %NULL.
* In contrast to g_async_queue_push(), this function
* pushes the new item ahead of the items already in the queue,
* so that it will be the next one to be popped off the queue.
*
* Since: 2.46
*/
void
g_async_queue_push_front (GAsyncQueue *queue,
gpointer item)
{
g_return_if_fail (queue != NULL);
g_return_if_fail (item != NULL);
g_mutex_lock (&queue->mutex);
g_async_queue_push_front_unlocked (queue, item);
g_mutex_unlock (&queue->mutex);
}
/**
* g_async_queue_push_front_unlocked:
* @queue: a #GAsyncQueue
* @item: data to push into the @queue
*
* Pushes the @item into the @queue. @item must not be %NULL.
* In contrast to g_async_queue_push_unlocked(), this function
* pushes the new item ahead of the items already in the queue,
* so that it will be the next one to be popped off the queue.
*
* This function must be called while holding the @queue's lock.
*
* Since: 2.46
*/
void
g_async_queue_push_front_unlocked (GAsyncQueue *queue,
gpointer item)
{
g_return_if_fail (queue != NULL);
g_return_if_fail (item != NULL);
g_queue_push_tail (&queue->queue, item);
if (queue->waiting_threads > 0)
g_cond_signal (&queue->cond);
}
/*
* Private API
*/
GMutex *
_g_async_queue_get_mutex (GAsyncQueue *queue)
{
g_return_val_if_fail (queue, NULL);
return &queue->mutex;
}

124
glib/gasyncqueue.h Normal file
View file

@ -0,0 +1,124 @@
/* 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.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/.
*/
#ifndef __G_ASYNCQUEUE_H__
#define __G_ASYNCQUEUE_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gthread.h>
G_BEGIN_DECLS
typedef struct _GAsyncQueue GAsyncQueue;
GLIB_AVAILABLE_IN_ALL
GAsyncQueue *g_async_queue_new (void);
GLIB_AVAILABLE_IN_ALL
GAsyncQueue *g_async_queue_new_full (GDestroyNotify item_free_func);
GLIB_AVAILABLE_IN_ALL
void g_async_queue_lock (GAsyncQueue *queue);
GLIB_AVAILABLE_IN_ALL
void g_async_queue_unlock (GAsyncQueue *queue);
GLIB_AVAILABLE_IN_ALL
GAsyncQueue *g_async_queue_ref (GAsyncQueue *queue);
GLIB_AVAILABLE_IN_ALL
void g_async_queue_unref (GAsyncQueue *queue);
GLIB_DEPRECATED_FOR(g_async_queue_ref)
void g_async_queue_ref_unlocked (GAsyncQueue *queue);
GLIB_DEPRECATED_FOR(g_async_queue_unref)
void g_async_queue_unref_and_unlock (GAsyncQueue *queue);
GLIB_AVAILABLE_IN_ALL
void g_async_queue_push (GAsyncQueue *queue,
gpointer data);
GLIB_AVAILABLE_IN_ALL
void g_async_queue_push_unlocked (GAsyncQueue *queue,
gpointer data);
GLIB_AVAILABLE_IN_ALL
void g_async_queue_push_sorted (GAsyncQueue *queue,
gpointer data,
GCompareDataFunc func,
gpointer user_data);
GLIB_AVAILABLE_IN_ALL
void g_async_queue_push_sorted_unlocked (GAsyncQueue *queue,
gpointer data,
GCompareDataFunc func,
gpointer user_data);
GLIB_AVAILABLE_IN_ALL
gpointer g_async_queue_pop (GAsyncQueue *queue);
GLIB_AVAILABLE_IN_ALL
gpointer g_async_queue_pop_unlocked (GAsyncQueue *queue);
GLIB_AVAILABLE_IN_ALL
gpointer g_async_queue_try_pop (GAsyncQueue *queue);
GLIB_AVAILABLE_IN_ALL
gpointer g_async_queue_try_pop_unlocked (GAsyncQueue *queue);
GLIB_AVAILABLE_IN_ALL
gpointer g_async_queue_timeout_pop (GAsyncQueue *queue,
guint64 timeout);
GLIB_AVAILABLE_IN_ALL
gpointer g_async_queue_timeout_pop_unlocked (GAsyncQueue *queue,
guint64 timeout);
GLIB_AVAILABLE_IN_ALL
gint g_async_queue_length (GAsyncQueue *queue);
GLIB_AVAILABLE_IN_ALL
gint g_async_queue_length_unlocked (GAsyncQueue *queue);
GLIB_AVAILABLE_IN_ALL
void g_async_queue_sort (GAsyncQueue *queue,
GCompareDataFunc func,
gpointer user_data);
GLIB_AVAILABLE_IN_ALL
void g_async_queue_sort_unlocked (GAsyncQueue *queue,
GCompareDataFunc func,
gpointer user_data);
GLIB_AVAILABLE_IN_2_46
gboolean g_async_queue_remove (GAsyncQueue *queue,
gpointer item);
GLIB_AVAILABLE_IN_2_46
gboolean g_async_queue_remove_unlocked (GAsyncQueue *queue,
gpointer item);
GLIB_AVAILABLE_IN_2_46
void g_async_queue_push_front (GAsyncQueue *queue,
gpointer item);
GLIB_AVAILABLE_IN_2_46
void g_async_queue_push_front_unlocked (GAsyncQueue *queue,
gpointer item);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
GLIB_DEPRECATED_FOR(g_async_queue_timeout_pop)
gpointer g_async_queue_timed_pop (GAsyncQueue *queue,
GTimeVal *end_time);
GLIB_DEPRECATED_FOR(g_async_queue_timeout_pop_unlocked)
gpointer g_async_queue_timed_pop_unlocked (GAsyncQueue *queue,
GTimeVal *end_time);
G_GNUC_END_IGNORE_DEPRECATIONS
G_END_DECLS
#endif /* __G_ASYNCQUEUE_H__ */

29
glib/gasyncqueueprivate.h Normal file
View file

@ -0,0 +1,29 @@
/* 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.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/>.
*/
#ifndef __G_ASYNCQUEUEPRIVATE_H__
#define __G_ASYNCQUEUEPRIVATE_H__
#include "gasyncqueue.h"
G_BEGIN_DECLS
GMutex *_g_async_queue_get_mutex (GAsyncQueue *queue);
G_END_DECLS
#endif /* __G_ASYNCQUEUEPRIVATE_H__ */

967
glib/gatomic.c Normal file
View file

@ -0,0 +1,967 @@
/*
* Copyright © 2011 Ryan Lortie
*
* 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/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#include "config.h"
#include "gatomic.h"
/**
* SECTION:atomic_operations
* @title: Atomic Operations
* @short_description: basic atomic integer and pointer operations
* @see_also: #GMutex
*
* The following is a collection of compiler macros to provide atomic
* access to integer and pointer-sized values.
*
* The macros that have 'int' in the name will operate on pointers to
* #gint and #guint. The macros with 'pointer' in the name will operate
* on pointers to any pointer-sized value, including #gsize. There is
* no support for 64bit operations on platforms with 32bit pointers
* because it is not generally possible to perform these operations
* atomically.
*
* The get, set and exchange operations for integers and pointers
* nominally operate on #gint and #gpointer, respectively. Of the
* arithmetic operations, the 'add' operation operates on (and returns)
* signed integer values (#gint and #gssize) and the 'and', 'or', and
* 'xor' operations operate on (and return) unsigned integer values
* (#guint and #gsize).
*
* All of the operations act as a full compiler and (where appropriate)
* hardware memory barrier. Acquire and release or producer and
* consumer barrier semantics are not available through this API.
*
* It is very important that all accesses to a particular integer or
* pointer be performed using only this API and that different sizes of
* operation are not mixed or used on overlapping memory regions. Never
* read or assign directly from or to a value -- always use this API.
*
* For simple reference counting purposes you should use
* g_atomic_int_inc() and g_atomic_int_dec_and_test(). Other uses that
* fall outside of simple reference counting patterns are prone to
* subtle bugs and occasionally undefined behaviour. It is also worth
* noting that since all of these operations require global
* synchronisation of the entire machine, they can be quite slow. In
* the case of performing multiple atomic operations it can often be
* faster to simply acquire a mutex lock around the critical area,
* perform the operations normally and then release the lock.
**/
/**
* G_ATOMIC_LOCK_FREE:
*
* This macro is defined if the atomic operations of GLib are
* implemented using real hardware atomic operations. This means that
* the GLib atomic API can be used between processes and safely mixed
* with other (hardware) atomic APIs.
*
* If this macro is not defined, the atomic operations may be
* emulated using a mutex. In that case, the GLib atomic operations are
* only atomic relative to themselves and within a single process.
**/
/* NOTE CAREFULLY:
*
* This file is the lowest-level part of GLib.
*
* Other lowlevel parts of GLib (threads, slice allocator, g_malloc,
* messages, etc) call into these functions and macros to get work done.
*
* As such, these functions can not call back into any part of GLib
* without risking recursion.
*/
#ifdef G_ATOMIC_LOCK_FREE
/* if G_ATOMIC_LOCK_FREE was defined by `meson configure` then we MUST
* implement the atomic operations in a lock-free manner.
*/
#if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
/**
* g_atomic_int_get:
* @atomic: a pointer to a #gint or #guint
*
* Gets the current value of @atomic.
*
* This call acts as a full compiler and hardware
* memory barrier (before the get).
*
* While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`.
*
* Returns: the value of the integer
*
* Since: 2.4
**/
gint
(g_atomic_int_get) (const volatile gint *atomic)
{
return g_atomic_int_get (atomic);
}
/**
* g_atomic_int_set:
* @atomic: a pointer to a #gint or #guint
* @newval: a new value to store
*
* Sets the value of @atomic to @newval.
*
* This call acts as a full compiler and hardware
* memory barrier (after the set).
*
* While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`.
*
* Since: 2.4
*/
void
(g_atomic_int_set) (volatile gint *atomic,
gint newval)
{
g_atomic_int_set (atomic, newval);
}
/**
* g_atomic_int_inc:
* @atomic: a pointer to a #gint or #guint
*
* Increments the value of @atomic by 1.
*
* Think of this operation as an atomic version of `{ *atomic += 1; }`.
*
* This call acts as a full compiler and hardware memory barrier.
*
* While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`.
*
* Since: 2.4
**/
void
(g_atomic_int_inc) (volatile gint *atomic)
{
g_atomic_int_inc (atomic);
}
/**
* g_atomic_int_dec_and_test:
* @atomic: a pointer to a #gint or #guint
*
* Decrements the value of @atomic by 1.
*
* Think of this operation as an atomic version of
* `{ *atomic -= 1; return (*atomic == 0); }`.
*
* This call acts as a full compiler and hardware memory barrier.
*
* While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`.
*
* Returns: %TRUE if the resultant value is zero
*
* Since: 2.4
**/
gboolean
(g_atomic_int_dec_and_test) (volatile gint *atomic)
{
return g_atomic_int_dec_and_test (atomic);
}
/**
* g_atomic_int_compare_and_exchange:
* @atomic: a pointer to a #gint or #guint
* @oldval: the value to compare with
* @newval: the value to conditionally replace with
*
* Compares @atomic to @oldval and, if equal, sets it to @newval.
* If @atomic was not equal to @oldval then no change occurs.
*
* This compare and exchange is done atomically.
*
* Think of this operation as an atomic version of
* `{ if (*atomic == oldval) { *atomic = newval; return TRUE; } else return FALSE; }`.
*
* This call acts as a full compiler and hardware memory barrier.
*
* While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`.
*
* Returns: %TRUE if the exchange took place
*
* Since: 2.4
**/
gboolean
(g_atomic_int_compare_and_exchange) (volatile gint *atomic,
gint oldval,
gint newval)
{
return g_atomic_int_compare_and_exchange (atomic, oldval, newval);
}
/**
* g_atomic_int_add:
* @atomic: a pointer to a #gint or #guint
* @val: the value to add
*
* Atomically adds @val to the value of @atomic.
*
* Think of this operation as an atomic version of
* `{ tmp = *atomic; *atomic += val; return tmp; }`.
*
* This call acts as a full compiler and hardware memory barrier.
*
* Before version 2.30, this function did not return a value
* (but g_atomic_int_exchange_and_add() did, and had the same meaning).
*
* While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`.
*
* Returns: the value of @atomic before the add, signed
*
* Since: 2.4
**/
gint
(g_atomic_int_add) (volatile gint *atomic,
gint val)
{
return g_atomic_int_add (atomic, val);
}
/**
* g_atomic_int_and:
* @atomic: a pointer to a #gint or #guint
* @val: the value to 'and'
*
* Performs an atomic bitwise 'and' of the value of @atomic and @val,
* storing the result back in @atomic.
*
* This call acts as a full compiler and hardware memory barrier.
*
* Think of this operation as an atomic version of
* `{ tmp = *atomic; *atomic &= val; return tmp; }`.
*
* While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`.
*
* Returns: the value of @atomic before the operation, unsigned
*
* Since: 2.30
**/
guint
(g_atomic_int_and) (volatile guint *atomic,
guint val)
{
return g_atomic_int_and (atomic, val);
}
/**
* g_atomic_int_or:
* @atomic: a pointer to a #gint or #guint
* @val: the value to 'or'
*
* Performs an atomic bitwise 'or' of the value of @atomic and @val,
* storing the result back in @atomic.
*
* Think of this operation as an atomic version of
* `{ tmp = *atomic; *atomic |= val; return tmp; }`.
*
* This call acts as a full compiler and hardware memory barrier.
*
* While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`.
*
* Returns: the value of @atomic before the operation, unsigned
*
* Since: 2.30
**/
guint
(g_atomic_int_or) (volatile guint *atomic,
guint val)
{
return g_atomic_int_or (atomic, val);
}
/**
* g_atomic_int_xor:
* @atomic: a pointer to a #gint or #guint
* @val: the value to 'xor'
*
* Performs an atomic bitwise 'xor' of the value of @atomic and @val,
* storing the result back in @atomic.
*
* Think of this operation as an atomic version of
* `{ tmp = *atomic; *atomic ^= val; return tmp; }`.
*
* This call acts as a full compiler and hardware memory barrier.
*
* While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`.
*
* Returns: the value of @atomic before the operation, unsigned
*
* Since: 2.30
**/
guint
(g_atomic_int_xor) (volatile guint *atomic,
guint val)
{
return g_atomic_int_xor (atomic, val);
}
/**
* g_atomic_pointer_get:
* @atomic: (not nullable): a pointer to a #gpointer-sized value
*
* Gets the current value of @atomic.
*
* This call acts as a full compiler and hardware
* memory barrier (before the get).
*
* While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`.
*
* Returns: the value of the pointer
*
* Since: 2.4
**/
gpointer
(g_atomic_pointer_get) (const volatile void *atomic)
{
return g_atomic_pointer_get ((gpointer *) atomic);
}
/**
* g_atomic_pointer_set:
* @atomic: (not nullable): a pointer to a #gpointer-sized value
* @newval: a new value to store
*
* Sets the value of @atomic to @newval.
*
* This call acts as a full compiler and hardware
* memory barrier (after the set).
*
* While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`.
*
* Since: 2.4
**/
void
(g_atomic_pointer_set) (volatile void *atomic,
gpointer newval)
{
g_atomic_pointer_set ((gpointer *) atomic, newval);
}
/**
* g_atomic_pointer_compare_and_exchange:
* @atomic: (not nullable): a pointer to a #gpointer-sized value
* @oldval: the value to compare with
* @newval: the value to conditionally replace with
*
* Compares @atomic to @oldval and, if equal, sets it to @newval.
* If @atomic was not equal to @oldval then no change occurs.
*
* This compare and exchange is done atomically.
*
* Think of this operation as an atomic version of
* `{ if (*atomic == oldval) { *atomic = newval; return TRUE; } else return FALSE; }`.
*
* This call acts as a full compiler and hardware memory barrier.
*
* While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`.
*
* Returns: %TRUE if the exchange took place
*
* Since: 2.4
**/
gboolean
(g_atomic_pointer_compare_and_exchange) (volatile void *atomic,
gpointer oldval,
gpointer newval)
{
return g_atomic_pointer_compare_and_exchange ((gpointer *) atomic,
oldval, newval);
}
/**
* g_atomic_pointer_add:
* @atomic: (not nullable): a pointer to a #gpointer-sized value
* @val: the value to add
*
* Atomically adds @val to the value of @atomic.
*
* Think of this operation as an atomic version of
* `{ tmp = *atomic; *atomic += val; return tmp; }`.
*
* This call acts as a full compiler and hardware memory barrier.
*
* While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`.
*
* Returns: the value of @atomic before the add, signed
*
* Since: 2.30
**/
gssize
(g_atomic_pointer_add) (volatile void *atomic,
gssize val)
{
return g_atomic_pointer_add ((gpointer *) atomic, val);
}
/**
* g_atomic_pointer_and:
* @atomic: (not nullable): a pointer to a #gpointer-sized value
* @val: the value to 'and'
*
* Performs an atomic bitwise 'and' of the value of @atomic and @val,
* storing the result back in @atomic.
*
* Think of this operation as an atomic version of
* `{ tmp = *atomic; *atomic &= val; return tmp; }`.
*
* This call acts as a full compiler and hardware memory barrier.
*
* While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`.
*
* Returns: the value of @atomic before the operation, unsigned
*
* Since: 2.30
**/
gsize
(g_atomic_pointer_and) (volatile void *atomic,
gsize val)
{
return g_atomic_pointer_and ((gpointer *) atomic, val);
}
/**
* g_atomic_pointer_or:
* @atomic: (not nullable): a pointer to a #gpointer-sized value
* @val: the value to 'or'
*
* Performs an atomic bitwise 'or' of the value of @atomic and @val,
* storing the result back in @atomic.
*
* Think of this operation as an atomic version of
* `{ tmp = *atomic; *atomic |= val; return tmp; }`.
*
* This call acts as a full compiler and hardware memory barrier.
*
* While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`.
*
* Returns: the value of @atomic before the operation, unsigned
*
* Since: 2.30
**/
gsize
(g_atomic_pointer_or) (volatile void *atomic,
gsize val)
{
return g_atomic_pointer_or ((gpointer *) atomic, val);
}
/**
* g_atomic_pointer_xor:
* @atomic: (not nullable): a pointer to a #gpointer-sized value
* @val: the value to 'xor'
*
* Performs an atomic bitwise 'xor' of the value of @atomic and @val,
* storing the result back in @atomic.
*
* Think of this operation as an atomic version of
* `{ tmp = *atomic; *atomic ^= val; return tmp; }`.
*
* This call acts as a full compiler and hardware memory barrier.
*
* While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`.
*
* Returns: the value of @atomic before the operation, unsigned
*
* Since: 2.30
**/
gsize
(g_atomic_pointer_xor) (volatile void *atomic,
gsize val)
{
return g_atomic_pointer_xor ((gpointer *) atomic, val);
}
#elif defined (G_PLATFORM_WIN32)
#include <windows.h>
#if !defined(_M_AMD64) && !defined (_M_IA64) && !defined(_M_X64) && !(defined _MSC_VER && _MSC_VER <= 1200)
#define InterlockedAnd _InterlockedAnd
#define InterlockedOr _InterlockedOr
#define InterlockedXor _InterlockedXor
#endif
#if !defined (_MSC_VER) || _MSC_VER <= 1200
#include "gmessages.h"
/* Inlined versions for older compiler */
static LONG
_gInterlockedAnd (volatile guint *atomic,
guint val)
{
LONG i, j;
j = *atomic;
do {
i = j;
j = InterlockedCompareExchange(atomic, i & val, i);
} while (i != j);
return j;
}
#define InterlockedAnd(a,b) _gInterlockedAnd(a,b)
static LONG
_gInterlockedOr (volatile guint *atomic,
guint val)
{
LONG i, j;
j = *atomic;
do {
i = j;
j = InterlockedCompareExchange(atomic, i | val, i);
} while (i != j);
return j;
}
#define InterlockedOr(a,b) _gInterlockedOr(a,b)
static LONG
_gInterlockedXor (volatile guint *atomic,
guint val)
{
LONG i, j;
j = *atomic;
do {
i = j;
j = InterlockedCompareExchange(atomic, i ^ val, i);
} while (i != j);
return j;
}
#define InterlockedXor(a,b) _gInterlockedXor(a,b)
#endif
/*
* http://msdn.microsoft.com/en-us/library/ms684122(v=vs.85).aspx
*/
gint
(g_atomic_int_get) (const volatile gint *atomic)
{
MemoryBarrier ();
return *atomic;
}
void
(g_atomic_int_set) (volatile gint *atomic,
gint newval)
{
*atomic = newval;
MemoryBarrier ();
}
void
(g_atomic_int_inc) (volatile gint *atomic)
{
InterlockedIncrement (atomic);
}
gboolean
(g_atomic_int_dec_and_test) (volatile gint *atomic)
{
return InterlockedDecrement (atomic) == 0;
}
gboolean
(g_atomic_int_compare_and_exchange) (volatile gint *atomic,
gint oldval,
gint newval)
{
return InterlockedCompareExchange (atomic, newval, oldval) == oldval;
}
gint
(g_atomic_int_add) (volatile gint *atomic,
gint val)
{
return InterlockedExchangeAdd (atomic, val);
}
guint
(g_atomic_int_and) (volatile guint *atomic,
guint val)
{
return InterlockedAnd (atomic, val);
}
guint
(g_atomic_int_or) (volatile guint *atomic,
guint val)
{
return InterlockedOr (atomic, val);
}
guint
(g_atomic_int_xor) (volatile guint *atomic,
guint val)
{
return InterlockedXor (atomic, val);
}
gpointer
(g_atomic_pointer_get) (const volatile void *atomic)
{
const gpointer *ptr = atomic;
MemoryBarrier ();
return *ptr;
}
void
(g_atomic_pointer_set) (volatile void *atomic,
gpointer newval)
{
gpointer *ptr = atomic;
*ptr = newval;
MemoryBarrier ();
}
gboolean
(g_atomic_pointer_compare_and_exchange) (volatile void *atomic,
gpointer oldval,
gpointer newval)
{
return InterlockedCompareExchangePointer (atomic, newval, oldval) == oldval;
}
gssize
(g_atomic_pointer_add) (volatile void *atomic,
gssize val)
{
#if GLIB_SIZEOF_VOID_P == 8
return InterlockedExchangeAdd64 (atomic, val);
#else
return InterlockedExchangeAdd (atomic, val);
#endif
}
gsize
(g_atomic_pointer_and) (volatile void *atomic,
gsize val)
{
#if GLIB_SIZEOF_VOID_P == 8
return InterlockedAnd64 (atomic, val);
#else
return InterlockedAnd (atomic, val);
#endif
}
gsize
(g_atomic_pointer_or) (volatile void *atomic,
gsize val)
{
#if GLIB_SIZEOF_VOID_P == 8
return InterlockedOr64 (atomic, val);
#else
return InterlockedOr (atomic, val);
#endif
}
gsize
(g_atomic_pointer_xor) (volatile void *atomic,
gsize val)
{
#if GLIB_SIZEOF_VOID_P == 8
return InterlockedXor64 (atomic, val);
#else
return InterlockedXor (atomic, val);
#endif
}
#else
/* This error occurs when `meson configure` decided that we should be capable
* of lock-free atomics but we find at compile-time that we are not.
*/
#error G_ATOMIC_LOCK_FREE defined, but incapable of lock-free atomics.
#endif /* defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) */
#else /* G_ATOMIC_LOCK_FREE */
/* We are not permitted to call into any GLib functions from here, so we
* can not use GMutex.
*
* Fortunately, we already take care of the Windows case above, and all
* non-Windows platforms on which glib runs have pthreads. Use those.
*/
#include <pthread.h>
static pthread_mutex_t g_atomic_lock = PTHREAD_MUTEX_INITIALIZER;
gint
(g_atomic_int_get) (const volatile gint *atomic)
{
gint value;
pthread_mutex_lock (&g_atomic_lock);
value = *atomic;
pthread_mutex_unlock (&g_atomic_lock);
return value;
}
void
(g_atomic_int_set) (volatile gint *atomic,
gint value)
{
pthread_mutex_lock (&g_atomic_lock);
*atomic = value;
pthread_mutex_unlock (&g_atomic_lock);
}
void
(g_atomic_int_inc) (volatile gint *atomic)
{
pthread_mutex_lock (&g_atomic_lock);
(*atomic)++;
pthread_mutex_unlock (&g_atomic_lock);
}
gboolean
(g_atomic_int_dec_and_test) (volatile gint *atomic)
{
gboolean is_zero;
pthread_mutex_lock (&g_atomic_lock);
is_zero = --(*atomic) == 0;
pthread_mutex_unlock (&g_atomic_lock);
return is_zero;
}
gboolean
(g_atomic_int_compare_and_exchange) (volatile gint *atomic,
gint oldval,
gint newval)
{
gboolean success;
pthread_mutex_lock (&g_atomic_lock);
if ((success = (*atomic == oldval)))
*atomic = newval;
pthread_mutex_unlock (&g_atomic_lock);
return success;
}
gint
(g_atomic_int_add) (volatile gint *atomic,
gint val)
{
gint oldval;
pthread_mutex_lock (&g_atomic_lock);
oldval = *atomic;
*atomic = oldval + val;
pthread_mutex_unlock (&g_atomic_lock);
return oldval;
}
guint
(g_atomic_int_and) (volatile guint *atomic,
guint val)
{
guint oldval;
pthread_mutex_lock (&g_atomic_lock);
oldval = *atomic;
*atomic = oldval & val;
pthread_mutex_unlock (&g_atomic_lock);
return oldval;
}
guint
(g_atomic_int_or) (volatile guint *atomic,
guint val)
{
guint oldval;
pthread_mutex_lock (&g_atomic_lock);
oldval = *atomic;
*atomic = oldval | val;
pthread_mutex_unlock (&g_atomic_lock);
return oldval;
}
guint
(g_atomic_int_xor) (volatile guint *atomic,
guint val)
{
guint oldval;
pthread_mutex_lock (&g_atomic_lock);
oldval = *atomic;
*atomic = oldval ^ val;
pthread_mutex_unlock (&g_atomic_lock);
return oldval;
}
gpointer
(g_atomic_pointer_get) (const volatile void *atomic)
{
const gpointer *ptr = atomic;
gpointer value;
pthread_mutex_lock (&g_atomic_lock);
value = *ptr;
pthread_mutex_unlock (&g_atomic_lock);
return value;
}
void
(g_atomic_pointer_set) (volatile void *atomic,
gpointer newval)
{
gpointer *ptr = atomic;
pthread_mutex_lock (&g_atomic_lock);
*ptr = newval;
pthread_mutex_unlock (&g_atomic_lock);
}
gboolean
(g_atomic_pointer_compare_and_exchange) (volatile void *atomic,
gpointer oldval,
gpointer newval)
{
gpointer *ptr = atomic;
gboolean success;
pthread_mutex_lock (&g_atomic_lock);
if ((success = (*ptr == oldval)))
*ptr = newval;
pthread_mutex_unlock (&g_atomic_lock);
return success;
}
gssize
(g_atomic_pointer_add) (volatile void *atomic,
gssize val)
{
gssize *ptr = atomic;
gssize oldval;
pthread_mutex_lock (&g_atomic_lock);
oldval = *ptr;
*ptr = oldval + val;
pthread_mutex_unlock (&g_atomic_lock);
return oldval;
}
gsize
(g_atomic_pointer_and) (volatile void *atomic,
gsize val)
{
gsize *ptr = atomic;
gsize oldval;
pthread_mutex_lock (&g_atomic_lock);
oldval = *ptr;
*ptr = oldval & val;
pthread_mutex_unlock (&g_atomic_lock);
return oldval;
}
gsize
(g_atomic_pointer_or) (volatile void *atomic,
gsize val)
{
gsize *ptr = atomic;
gsize oldval;
pthread_mutex_lock (&g_atomic_lock);
oldval = *ptr;
*ptr = oldval | val;
pthread_mutex_unlock (&g_atomic_lock);
return oldval;
}
gsize
(g_atomic_pointer_xor) (volatile void *atomic,
gsize val)
{
gsize *ptr = atomic;
gsize oldval;
pthread_mutex_lock (&g_atomic_lock);
oldval = *ptr;
*ptr = oldval ^ val;
pthread_mutex_unlock (&g_atomic_lock);
return oldval;
}
#endif
/**
* g_atomic_int_exchange_and_add:
* @atomic: a pointer to a #gint
* @val: the value to add
*
* This function existed before g_atomic_int_add() returned the prior
* value of the integer (which it now does). It is retained only for
* compatibility reasons. Don't use this function in new code.
*
* Returns: the value of @atomic before the add, signed
* Since: 2.4
* Deprecated: 2.30: Use g_atomic_int_add() instead.
**/
gint
g_atomic_int_exchange_and_add (volatile gint *atomic,
gint val)
{
return (g_atomic_int_add) ((gint *) atomic, val);
}

470
glib/gatomic.h Normal file
View file

@ -0,0 +1,470 @@
/*
* Copyright © 2011 Ryan Lortie
*
* 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/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __G_ATOMIC_H__
#define __G_ATOMIC_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtypes.h>
#include <glib/glib-typeof.h>
G_BEGIN_DECLS
GLIB_AVAILABLE_IN_ALL
gint g_atomic_int_get (const volatile gint *atomic);
GLIB_AVAILABLE_IN_ALL
void g_atomic_int_set (volatile gint *atomic,
gint newval);
GLIB_AVAILABLE_IN_ALL
void g_atomic_int_inc (volatile gint *atomic);
GLIB_AVAILABLE_IN_ALL
gboolean g_atomic_int_dec_and_test (volatile gint *atomic);
GLIB_AVAILABLE_IN_ALL
gboolean g_atomic_int_compare_and_exchange (volatile gint *atomic,
gint oldval,
gint newval);
GLIB_AVAILABLE_IN_ALL
gint g_atomic_int_add (volatile gint *atomic,
gint val);
GLIB_AVAILABLE_IN_2_30
guint g_atomic_int_and (volatile guint *atomic,
guint val);
GLIB_AVAILABLE_IN_2_30
guint g_atomic_int_or (volatile guint *atomic,
guint val);
GLIB_AVAILABLE_IN_ALL
guint g_atomic_int_xor (volatile guint *atomic,
guint val);
GLIB_AVAILABLE_IN_ALL
gpointer g_atomic_pointer_get (const volatile void *atomic);
GLIB_AVAILABLE_IN_ALL
void g_atomic_pointer_set (volatile void *atomic,
gpointer newval);
GLIB_AVAILABLE_IN_ALL
gboolean g_atomic_pointer_compare_and_exchange (volatile void *atomic,
gpointer oldval,
gpointer newval);
GLIB_AVAILABLE_IN_ALL
gssize g_atomic_pointer_add (volatile void *atomic,
gssize val);
GLIB_AVAILABLE_IN_2_30
gsize g_atomic_pointer_and (volatile void *atomic,
gsize val);
GLIB_AVAILABLE_IN_2_30
gsize g_atomic_pointer_or (volatile void *atomic,
gsize val);
GLIB_AVAILABLE_IN_ALL
gsize g_atomic_pointer_xor (volatile void *atomic,
gsize val);
GLIB_DEPRECATED_IN_2_30_FOR(g_atomic_int_add)
gint g_atomic_int_exchange_and_add (volatile gint *atomic,
gint val);
G_END_DECLS
#if defined(G_ATOMIC_LOCK_FREE) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
/* We prefer the new C11-style atomic extension of GCC if available */
#if defined(__ATOMIC_SEQ_CST)
#define g_atomic_int_get(atomic) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
gint gaig_temp; \
(void) (0 ? *(atomic) ^ *(atomic) : 1); \
__atomic_load ((gint *)(atomic), &gaig_temp, __ATOMIC_SEQ_CST); \
(gint) gaig_temp; \
}))
#define g_atomic_int_set(atomic, newval) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
gint gais_temp = (gint) (newval); \
(void) (0 ? *(atomic) ^ (newval) : 1); \
__atomic_store ((gint *)(atomic), &gais_temp, __ATOMIC_SEQ_CST); \
}))
#if defined(glib_typeof)
#define g_atomic_pointer_get(atomic) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
glib_typeof (*(atomic)) gapg_temp_newval; \
glib_typeof ((atomic)) gapg_temp_atomic = (atomic); \
__atomic_load (gapg_temp_atomic, &gapg_temp_newval, __ATOMIC_SEQ_CST); \
gapg_temp_newval; \
}))
#define g_atomic_pointer_set(atomic, newval) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
glib_typeof ((atomic)) gaps_temp_atomic = (atomic); \
glib_typeof (*(atomic)) gaps_temp_newval = (newval); \
(void) (0 ? (gpointer) * (atomic) : NULL); \
__atomic_store (gaps_temp_atomic, &gaps_temp_newval, __ATOMIC_SEQ_CST); \
}))
#else /* if !(defined(glib_typeof) */
#define g_atomic_pointer_get(atomic) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
gpointer gapg_temp_newval; \
gpointer *gapg_temp_atomic = (gpointer *)(atomic); \
__atomic_load (gapg_temp_atomic, &gapg_temp_newval, __ATOMIC_SEQ_CST); \
gapg_temp_newval; \
}))
#define g_atomic_pointer_set(atomic, newval) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
gpointer *gaps_temp_atomic = (gpointer *)(atomic); \
gpointer gaps_temp_newval = (gpointer)(newval); \
(void) (0 ? (gpointer) *(atomic) : NULL); \
__atomic_store (gaps_temp_atomic, &gaps_temp_newval, __ATOMIC_SEQ_CST); \
}))
#endif /* if defined(glib_typeof) */
#define g_atomic_int_inc(atomic) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ *(atomic) : 1); \
(void) __atomic_fetch_add ((atomic), 1, __ATOMIC_SEQ_CST); \
}))
#define g_atomic_int_dec_and_test(atomic) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ *(atomic) : 1); \
__atomic_fetch_sub ((atomic), 1, __ATOMIC_SEQ_CST) == 1; \
}))
#if defined(glib_typeof) && defined(__cplusplus) && __cplusplus >= 201103L
/* See comments below about equivalent g_atomic_pointer_compare_and_exchange()
* shenanigans for type-safety when compiling in C++ mode. */
#define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
(G_GNUC_EXTENSION ({ \
glib_typeof (*(atomic)) gaicae_oldval = (oldval); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ (newval) ^ (oldval) : 1); \
__atomic_compare_exchange_n ((atomic), &gaicae_oldval, (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
}))
#else /* if !(defined(glib_typeof) && defined(__cplusplus) && __cplusplus >= 201103L) */
#define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
(G_GNUC_EXTENSION ({ \
gint gaicae_oldval = (oldval); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ (newval) ^ (oldval) : 1); \
__atomic_compare_exchange_n ((atomic), (void *) (&(gaicae_oldval)), (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
}))
#endif /* defined(glib_typeof) */
#define g_atomic_int_add(atomic, val) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ (val) : 1); \
(gint) __atomic_fetch_add ((atomic), (val), __ATOMIC_SEQ_CST); \
}))
#define g_atomic_int_and(atomic, val) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ (val) : 1); \
(guint) __atomic_fetch_and ((atomic), (val), __ATOMIC_SEQ_CST); \
}))
#define g_atomic_int_or(atomic, val) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ (val) : 1); \
(guint) __atomic_fetch_or ((atomic), (val), __ATOMIC_SEQ_CST); \
}))
#define g_atomic_int_xor(atomic, val) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ (val) : 1); \
(guint) __atomic_fetch_xor ((atomic), (val), __ATOMIC_SEQ_CST); \
}))
#if defined(glib_typeof) && defined(__cplusplus) && __cplusplus >= 201103L
/* This is typesafe because we check we can assign oldval to the type of
* (*atomic). Unfortunately it can only be done in C++ because gcc/clang warn
* when atomic is volatile and not oldval, or when atomic is gsize* and oldval
* is NULL. Note that clang++ force us to be typesafe because it is an error if the 2nd
* argument of __atomic_compare_exchange_n() has a different type than the
* first.
* https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1919
* https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1715#note_1024120. */
#define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof (oldval) == sizeof (gpointer)); \
glib_typeof (*(atomic)) gapcae_oldval = (oldval); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \
__atomic_compare_exchange_n ((atomic), &gapcae_oldval, (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
}))
#else /* if !(defined(glib_typeof) && defined(__cplusplus) && __cplusplus >= 201103L) */
#define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof (oldval) == sizeof (gpointer)); \
gpointer gapcae_oldval = (gpointer)(oldval); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \
__atomic_compare_exchange_n ((atomic), (void *) (&(gapcae_oldval)), (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
}))
#endif /* defined(glib_typeof) */
#define g_atomic_pointer_add(atomic, val) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \
(void) (0 ? (val) ^ (val) : 1); \
(gssize) __atomic_fetch_add ((atomic), (val), __ATOMIC_SEQ_CST); \
}))
#define g_atomic_pointer_and(atomic, val) \
(G_GNUC_EXTENSION ({ \
gsize *gapa_atomic = (gsize *) (atomic); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gsize)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \
(void) (0 ? (val) ^ (val) : 1); \
(gsize) __atomic_fetch_and (gapa_atomic, (val), __ATOMIC_SEQ_CST); \
}))
#define g_atomic_pointer_or(atomic, val) \
(G_GNUC_EXTENSION ({ \
gsize *gapo_atomic = (gsize *) (atomic); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gsize)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \
(void) (0 ? (val) ^ (val) : 1); \
(gsize) __atomic_fetch_or (gapo_atomic, (val), __ATOMIC_SEQ_CST); \
}))
#define g_atomic_pointer_xor(atomic, val) \
(G_GNUC_EXTENSION ({ \
gsize *gapx_atomic = (gsize *) (atomic); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gsize)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \
(void) (0 ? (val) ^ (val) : 1); \
(gsize) __atomic_fetch_xor (gapx_atomic, (val), __ATOMIC_SEQ_CST); \
}))
#else /* defined(__ATOMIC_SEQ_CST) */
/* We want to achieve __ATOMIC_SEQ_CST semantics here. See
* https://en.cppreference.com/w/c/atomic/memory_order#Constants. For load
* operations, that means performing an *acquire*:
* > A load operation with this memory order performs the acquire operation on
* > the affected memory location: no reads or writes in the current thread can
* > be reordered before this load. All writes in other threads that release
* > the same atomic variable are visible in the current thread.
*
* no reads or writes in the current thread can be reordered before this load
* is implemented using a compiler barrier (a no-op `__asm__` section) to
* prevent instruction reordering. Writes in other threads are synchronised
* using `__sync_synchronize()`. Its unclear from the GCC documentation whether
* `__sync_synchronize()` acts as a compiler barrier, hence our explicit use of
* one.
*
* For store operations, `__ATOMIC_SEQ_CST` means performing a *release*:
* > A store operation with this memory order performs the release operation:
* > no reads or writes in the current thread can be reordered after this store.
* > All writes in the current thread are visible in other threads that acquire
* > the same atomic variable (see Release-Acquire ordering below) and writes
* > that carry a dependency into the atomic variable become visible in other
* > threads that consume the same atomic (see Release-Consume ordering below).
*
* no reads or writes in the current thread can be reordered after this store
* is implemented using a compiler barrier to prevent instruction reordering.
* All writes in the current thread are visible in other threads is implemented
* using `__sync_synchronize()`; similarly for writes that carry a dependency.
*/
#define g_atomic_int_get(atomic) \
(G_GNUC_EXTENSION ({ \
gint gaig_result; \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ *(atomic) : 1); \
gaig_result = (gint) *(atomic); \
__sync_synchronize (); \
__asm__ __volatile__ ("" : : : "memory"); \
gaig_result; \
}))
#define g_atomic_int_set(atomic, newval) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ (newval) : 1); \
__sync_synchronize (); \
__asm__ __volatile__ ("" : : : "memory"); \
*(atomic) = (newval); \
}))
#define g_atomic_pointer_get(atomic) \
(G_GNUC_EXTENSION ({ \
gpointer gapg_result; \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
gapg_result = (gpointer) *(atomic); \
__sync_synchronize (); \
__asm__ __volatile__ ("" : : : "memory"); \
gapg_result; \
}))
#if defined(glib_typeof)
#define g_atomic_pointer_set(atomic, newval) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \
__sync_synchronize (); \
__asm__ __volatile__ ("" : : : "memory"); \
*(atomic) = (glib_typeof (*(atomic))) (gsize) (newval); \
}))
#else /* if !(defined(glib_typeof) */
#define g_atomic_pointer_set(atomic, newval) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \
__sync_synchronize (); \
__asm__ __volatile__ ("" : : : "memory"); \
*(atomic) = (gpointer) (gsize) (newval); \
}))
#endif /* if defined(glib_typeof) */
#define g_atomic_int_inc(atomic) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ *(atomic) : 1); \
(void) __sync_fetch_and_add ((atomic), 1); \
}))
#define g_atomic_int_dec_and_test(atomic) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ *(atomic) : 1); \
__sync_fetch_and_sub ((atomic), 1) == 1; \
}))
#define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ (newval) ^ (oldval) : 1); \
__sync_bool_compare_and_swap ((atomic), (oldval), (newval)) ? TRUE : FALSE; \
}))
#define g_atomic_int_add(atomic, val) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ (val) : 1); \
(gint) __sync_fetch_and_add ((atomic), (val)); \
}))
#define g_atomic_int_and(atomic, val) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ (val) : 1); \
(guint) __sync_fetch_and_and ((atomic), (val)); \
}))
#define g_atomic_int_or(atomic, val) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ (val) : 1); \
(guint) __sync_fetch_and_or ((atomic), (val)); \
}))
#define g_atomic_int_xor(atomic, val) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
(void) (0 ? *(atomic) ^ (val) : 1); \
(guint) __sync_fetch_and_xor ((atomic), (val)); \
}))
#define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \
__sync_bool_compare_and_swap ((atomic), (oldval), (newval)) ? TRUE : FALSE; \
}))
#define g_atomic_pointer_add(atomic, val) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \
(void) (0 ? (val) ^ (val) : 1); \
(gssize) __sync_fetch_and_add ((atomic), (val)); \
}))
#define g_atomic_pointer_and(atomic, val) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \
(void) (0 ? (val) ^ (val) : 1); \
(gsize) __sync_fetch_and_and ((atomic), (val)); \
}))
#define g_atomic_pointer_or(atomic, val) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \
(void) (0 ? (val) ^ (val) : 1); \
(gsize) __sync_fetch_and_or ((atomic), (val)); \
}))
#define g_atomic_pointer_xor(atomic, val) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \
(void) (0 ? (val) ^ (val) : 1); \
(gsize) __sync_fetch_and_xor ((atomic), (val)); \
}))
#endif /* !defined(__ATOMIC_SEQ_CST) */
#else /* defined(G_ATOMIC_LOCK_FREE) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) */
#define g_atomic_int_get(atomic) \
(g_atomic_int_get ((gint *) (atomic)))
#define g_atomic_int_set(atomic, newval) \
(g_atomic_int_set ((gint *) (atomic), (gint) (newval)))
#define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
(g_atomic_int_compare_and_exchange ((gint *) (atomic), (oldval), (newval)))
#define g_atomic_int_add(atomic, val) \
(g_atomic_int_add ((gint *) (atomic), (val)))
#define g_atomic_int_and(atomic, val) \
(g_atomic_int_and ((guint *) (atomic), (val)))
#define g_atomic_int_or(atomic, val) \
(g_atomic_int_or ((guint *) (atomic), (val)))
#define g_atomic_int_xor(atomic, val) \
(g_atomic_int_xor ((guint *) (atomic), (val)))
#define g_atomic_int_inc(atomic) \
(g_atomic_int_inc ((gint *) (atomic)))
#define g_atomic_int_dec_and_test(atomic) \
(g_atomic_int_dec_and_test ((gint *) (atomic)))
#if defined(glib_typeof)
/* The (void *) cast in the middle *looks* redundant, because
* g_atomic_pointer_get returns void * already, but it's to silence
* -Werror=bad-function-cast when we're doing something like:
* guintptr a, b; ...; a = g_atomic_pointer_get (&b);
* which would otherwise be assigning the void * result of
* g_atomic_pointer_get directly to the pointer-sized but
* non-pointer-typed result. */
#define g_atomic_pointer_get(atomic) \
(glib_typeof (*(atomic))) (void *) ((g_atomic_pointer_get) ((void *) atomic))
#else /* !(defined(glib_typeof) */
#define g_atomic_pointer_get(atomic) \
(g_atomic_pointer_get (atomic))
#endif
#define g_atomic_pointer_set(atomic, newval) \
(g_atomic_pointer_set ((atomic), (gpointer) (newval)))
#define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
(g_atomic_pointer_compare_and_exchange ((atomic), (gpointer) (oldval), (gpointer) (newval)))
#define g_atomic_pointer_add(atomic, val) \
(g_atomic_pointer_add ((atomic), (gssize) (val)))
#define g_atomic_pointer_and(atomic, val) \
(g_atomic_pointer_and ((atomic), (gsize) (val)))
#define g_atomic_pointer_or(atomic, val) \
(g_atomic_pointer_or ((atomic), (gsize) (val)))
#define g_atomic_pointer_xor(atomic, val) \
(g_atomic_pointer_xor ((atomic), (gsize) (val)))
#endif /* defined(G_ATOMIC_LOCK_FREE) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) */
#endif /* __G_ATOMIC_H__ */

455
glib/gbacktrace.c Normal file
View file

@ -0,0 +1,455 @@
/* 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.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 ; except for g_on_error_stack_trace, but who wants thread safety
* then
*/
#include "config.h"
#include "glibconfig.h"
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <sys/types.h>
#include <time.h>
#ifdef G_OS_UNIX
#include <unistd.h>
#include <sys/wait.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif /* HAVE_SYS_SELECT_H */
#endif
#include <string.h>
#ifdef G_OS_WIN32
# define STRICT /* Strict typing, please */
# define _WIN32_WINDOWS 0x0401 /* to get IsDebuggerPresent */
# include <windows.h>
# undef STRICT
#else
# include <fcntl.h>
#endif
#include "gbacktrace.h"
#include "gtypes.h"
#include "gmain.h"
#include "gprintfint.h"
#include "gunicode.h"
#include "gutils.h"
#ifndef G_OS_WIN32
static void stack_trace (const char * const *args);
#endif
/* Default to using LLDB for backtraces on macOS. */
#ifdef __APPLE__
#define USE_LLDB
#endif
#ifdef USE_LLDB
#define DEBUGGER "lldb"
#else
#define DEBUGGER "gdb"
#endif
/* People want to hit this from their debugger... */
GLIB_AVAILABLE_IN_ALL volatile gboolean glib_on_error_halt;
volatile gboolean glib_on_error_halt = TRUE;
/**
* g_on_error_query:
* @prg_name: the program name, needed by gdb for the "[S]tack trace"
* option. If @prg_name is %NULL, g_get_prgname() is called to get
* the program name (which will work correctly if gdk_init() or
* gtk_init() has been called)
*
* Prompts the user with
* `[E]xit, [H]alt, show [S]tack trace or [P]roceed`.
* This function is intended to be used for debugging use only.
* The following example shows how it can be used together with
* the g_log() functions.
*
* |[<!-- language="C" -->
* #include <glib.h>
*
* static void
* log_handler (const gchar *log_domain,
* GLogLevelFlags log_level,
* const gchar *message,
* gpointer user_data)
* {
* g_log_default_handler (log_domain, log_level, message, user_data);
*
* g_on_error_query (MY_PROGRAM_NAME);
* }
*
* int
* main (int argc, char *argv[])
* {
* g_log_set_handler (MY_LOG_DOMAIN,
* G_LOG_LEVEL_WARNING |
* G_LOG_LEVEL_ERROR |
* G_LOG_LEVEL_CRITICAL,
* log_handler,
* NULL);
* ...
* ]|
*
* If "[E]xit" is selected, the application terminates with a call
* to _exit(0).
*
* If "[S]tack" trace is selected, g_on_error_stack_trace() is called.
* This invokes gdb, which attaches to the current process and shows
* a stack trace. The prompt is then shown again.
*
* If "[P]roceed" is selected, the function returns.
*
* This function may cause different actions on non-UNIX platforms.
*
* On Windows consider using the `G_DEBUGGER` environment
* variable (see [Running GLib Applications](glib-running.html)) and
* calling g_on_error_stack_trace() instead.
*/
void
g_on_error_query (const gchar *prg_name)
{
#ifndef G_OS_WIN32
static const gchar * const query1 = "[E]xit, [H]alt";
static const gchar * const query2 = ", show [S]tack trace";
static const gchar * const query3 = " or [P]roceed";
gchar buf[16];
if (!prg_name)
prg_name = g_get_prgname ();
retry:
if (prg_name)
_g_fprintf (stdout,
"%s (pid:%u): %s%s%s: ",
prg_name,
(guint) getpid (),
query1,
query2,
query3);
else
_g_fprintf (stdout,
"(process:%u): %s%s: ",
(guint) getpid (),
query1,
query3);
fflush (stdout);
if (isatty(0) && isatty(1))
fgets (buf, 8, stdin);
else
strcpy (buf, "E\n");
if ((buf[0] == 'E' || buf[0] == 'e')
&& buf[1] == '\n')
_exit (0);
else if ((buf[0] == 'P' || buf[0] == 'p')
&& buf[1] == '\n')
return;
else if (prg_name
&& (buf[0] == 'S' || buf[0] == 's')
&& buf[1] == '\n')
{
g_on_error_stack_trace (prg_name);
goto retry;
}
else if ((buf[0] == 'H' || buf[0] == 'h')
&& buf[1] == '\n')
{
while (glib_on_error_halt)
;
glib_on_error_halt = TRUE;
return;
}
else
goto retry;
#else
if (!prg_name)
prg_name = g_get_prgname ();
/* MessageBox is allowed on UWP apps only when building against
* the debug CRT, which will set -D_DEBUG */
#if defined(_DEBUG) || !defined(G_WINAPI_ONLY_APP)
{
WCHAR *caption = NULL;
if (prg_name && *prg_name)
{
caption = g_utf8_to_utf16 (prg_name, -1, NULL, NULL, NULL);
}
MessageBoxW (NULL, L"g_on_error_query called, program terminating",
caption,
MB_OK|MB_ICONERROR);
g_free (caption);
}
#else
printf ("g_on_error_query called, program '%s' terminating\n",
(prg_name && *prg_name) ? prg_name : "(null)");
#endif
_exit(0);
#endif
}
/**
* g_on_error_stack_trace:
* @prg_name: the program name, needed by gdb for the "[S]tack trace"
* option
*
* Invokes gdb, which attaches to the current process and shows a
* stack trace. Called by g_on_error_query() when the "[S]tack trace"
* option is selected. You can get the current process's program name
* with g_get_prgname(), assuming that you have called gtk_init() or
* gdk_init().
*
* This function may cause different actions on non-UNIX platforms.
*
* When running on Windows, this function is *not* called by
* g_on_error_query(). If called directly, it will raise an
* exception, which will crash the program. If the `G_DEBUGGER` environment
* variable is set, a debugger will be invoked to attach and
* handle that exception (see [Running GLib Applications](glib-running.html)).
*/
void
g_on_error_stack_trace (const gchar *prg_name)
{
#if defined(G_OS_UNIX)
pid_t pid;
gchar buf[16];
const gchar *args[5] = { DEBUGGER, NULL, NULL, NULL, NULL };
int status;
if (!prg_name)
return;
_g_sprintf (buf, "%u", (guint) getpid ());
#ifdef USE_LLDB
args[1] = prg_name;
args[2] = "-p";
args[3] = buf;
#else
args[1] = prg_name;
args[2] = buf;
#endif
pid = fork ();
if (pid == 0)
{
stack_trace (args);
_exit (0);
}
else if (pid == (pid_t) -1)
{
perror ("unable to fork " DEBUGGER);
return;
}
/* Wait until the child really terminates. On Mac OS X waitpid ()
* will also return when the child is being stopped due to tracing.
*/
while (1)
{
pid_t retval = waitpid (pid, &status, 0);
if (WIFEXITED (retval) || WIFSIGNALED (retval))
break;
}
#else
if (IsDebuggerPresent ())
G_BREAKPOINT ();
else
g_abort ();
#endif
}
#ifndef G_OS_WIN32
static gboolean stack_trace_done = FALSE;
static void
stack_trace_sigchld (int signum)
{
stack_trace_done = TRUE;
}
#define BUFSIZE 1024
static void
stack_trace (const char * const *args)
{
pid_t pid;
int in_fd[2];
int out_fd[2];
fd_set fdset;
fd_set readset;
struct timeval tv;
int sel, idx, state;
#ifdef USE_LLDB
int line_idx;
#endif
char buffer[BUFSIZE];
char c;
stack_trace_done = FALSE;
signal (SIGCHLD, stack_trace_sigchld);
if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1))
{
perror ("unable to open pipe");
_exit (0);
}
pid = fork ();
if (pid == 0)
{
/* Save stderr for printing failure below */
int old_err = dup (2);
if (old_err != -1)
{
int getfd = fcntl (old_err, F_GETFD);
if (getfd != -1)
(void) fcntl (old_err, F_SETFD, getfd | FD_CLOEXEC);
}
close (0); dup (in_fd[0]); /* set the stdin to the in pipe */
close (1); dup (out_fd[1]); /* set the stdout to the out pipe */
close (2); dup (out_fd[1]); /* set the stderr to the out pipe */
execvp (args[0], (char **) args); /* exec gdb */
/* Print failure to original stderr */
if (old_err != -1)
{
close (2);
dup (old_err);
}
perror ("exec " DEBUGGER " failed");
_exit (0);
}
else if (pid == (pid_t) -1)
{
perror ("unable to fork");
_exit (0);
}
FD_ZERO (&fdset);
FD_SET (out_fd[0], &fdset);
#ifdef USE_LLDB
write (in_fd[1], "bt\n", 3);
write (in_fd[1], "p x = 0\n", 8);
write (in_fd[1], "process detach\n", 15);
write (in_fd[1], "quit\n", 5);
#else
write (in_fd[1], "backtrace\n", 10);
write (in_fd[1], "p x = 0\n", 8);
write (in_fd[1], "quit\n", 5);
#endif
idx = 0;
#ifdef USE_LLDB
line_idx = 0;
#endif
state = 0;
while (1)
{
readset = fdset;
tv.tv_sec = 1;
tv.tv_usec = 0;
sel = select (FD_SETSIZE, &readset, NULL, NULL, &tv);
if (sel == -1)
break;
if ((sel > 0) && (FD_ISSET (out_fd[0], &readset)))
{
if (read (out_fd[0], &c, 1))
{
#ifdef USE_LLDB
line_idx += 1;
#endif
switch (state)
{
case 0:
#ifdef USE_LLDB
if (c == '*' || (c == ' ' && line_idx == 1))
#else
if (c == '#')
#endif
{
state = 1;
idx = 0;
buffer[idx++] = c;
}
break;
case 1:
if (idx < BUFSIZE)
buffer[idx++] = c;
if ((c == '\n') || (c == '\r'))
{
buffer[idx] = 0;
_g_fprintf (stdout, "%s", buffer);
state = 0;
idx = 0;
#ifdef USE_LLDB
line_idx = 0;
#endif
}
break;
default:
break;
}
}
}
else if (stack_trace_done)
break;
}
close (in_fd[0]);
close (in_fd[1]);
close (out_fd[0]);
close (out_fd[1]);
_exit (0);
}
#endif /* !G_OS_WIN32 */

72
glib/gbacktrace.h Normal file
View file

@ -0,0 +1,72 @@
/* 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.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/.
*/
#ifndef __G_BACKTRACE_H__
#define __G_BACKTRACE_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtypes.h>
#ifdef __sun__
#include <sys/select.h>
#endif
#include <signal.h>
G_BEGIN_DECLS
GLIB_AVAILABLE_IN_ALL
void g_on_error_query (const gchar *prg_name);
GLIB_AVAILABLE_IN_ALL
void g_on_error_stack_trace (const gchar *prg_name);
/**
* G_BREAKPOINT:
*
* Inserts a breakpoint instruction into the code.
*
* On architectures which support it, this is implemented as a soft interrupt
* and on other architectures it raises a `SIGTRAP` signal.
*
* `SIGTRAP` is used rather than abort() to allow breakpoints to be skipped past
* in a debugger if they are not the desired target of debugging.
*/
#if (defined (__i386__) || defined (__x86_64__)) && defined (__GNUC__) && __GNUC__ >= 2
# define G_BREAKPOINT() G_STMT_START{ __asm__ __volatile__ ("int $03"); }G_STMT_END
#elif (defined (_MSC_VER) || defined (__DMC__)) && defined (_M_IX86)
# define G_BREAKPOINT() G_STMT_START{ __asm int 3h }G_STMT_END
#elif defined (_MSC_VER)
# define G_BREAKPOINT() G_STMT_START{ __debugbreak(); }G_STMT_END
#elif defined (__alpha__) && !defined(__osf__) && defined (__GNUC__) && __GNUC__ >= 2
# define G_BREAKPOINT() G_STMT_START{ __asm__ __volatile__ ("bpt"); }G_STMT_END
#elif defined (__APPLE__) || (defined(_WIN32) && (defined(__clang__) || defined(__GNUC__)))
# define G_BREAKPOINT() G_STMT_START{ __builtin_trap(); }G_STMT_END
#else /* !__i386__ && !__alpha__ */
# define G_BREAKPOINT() G_STMT_START{ raise (SIGTRAP); }G_STMT_END
#endif /* __i386__ */
G_END_DECLS
#endif /* __G_BACKTRACE_H__ */

462
glib/gbase64.c Normal file
View file

@ -0,0 +1,462 @@
/* gbase64.c - Base64 encoding/decoding
*
* Copyright (C) 2006 Alexander Larsson <alexl@redhat.com>
* Copyright (C) 2000-2003 Ximian Inc.
*
* 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/>.
*
* This is based on code in camel, written by:
* Michael Zucchi <notzed@ximian.com>
* Jeffrey Stedfast <fejj@ximian.com>
*/
#include "config.h"
#include <string.h>
#include "gbase64.h"
#include "gtestutils.h"
#include "glibintl.h"
/**
* SECTION:base64
* @title: Base64 Encoding
* @short_description: encodes and decodes data in Base64 format
*
* Base64 is an encoding that allows a sequence of arbitrary bytes to be
* encoded as a sequence of printable ASCII characters. For the definition
* of Base64, see
* [RFC 1421](http://www.ietf.org/rfc/rfc1421.txt)
* or
* [RFC 2045](http://www.ietf.org/rfc/rfc2045.txt).
* Base64 is most commonly used as a MIME transfer encoding
* for email.
*
* GLib supports incremental encoding using g_base64_encode_step() and
* g_base64_encode_close(). Incremental decoding can be done with
* g_base64_decode_step(). To encode or decode data in one go, use
* g_base64_encode() or g_base64_decode(). To avoid memory allocation when
* decoding, you can use g_base64_decode_inplace().
*
* Support for Base64 encoding has been added in GLib 2.12.
*/
static const char base64_alphabet[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* g_base64_encode_step:
* @in: (array length=len) (element-type guint8): the binary data to encode
* @len: the length of @in
* @break_lines: whether to break long lines
* @out: (out) (array) (element-type guint8): pointer to destination buffer
* @state: (inout): Saved state between steps, initialize to 0
* @save: (inout): Saved state between steps, initialize to 0
*
* Incrementally encode a sequence of binary data into its Base-64 stringified
* representation. By calling this function multiple times you can convert
* data in chunks to avoid having to have the full encoded data in memory.
*
* When all of the data has been converted you must call
* g_base64_encode_close() to flush the saved state.
*
* The output buffer must be large enough to fit all the data that will
* be written to it. Due to the way base64 encodes you will need
* at least: (@len / 3 + 1) * 4 + 4 bytes (+ 4 may be needed in case of
* non-zero state). If you enable line-breaking you will need at least:
* ((@len / 3 + 1) * 4 + 4) / 76 + 1 bytes of extra space.
*
* @break_lines is typically used when putting base64-encoded data in emails.
* It breaks the lines at 76 columns instead of putting all of the text on
* the same line. This avoids problems with long lines in the email system.
* Note however that it breaks the lines with `LF` characters, not
* `CR LF` sequences, so the result cannot be passed directly to SMTP
* or certain other protocols.
*
* Returns: The number of bytes of output that was written
*
* Since: 2.12
*/
gsize
g_base64_encode_step (const guchar *in,
gsize len,
gboolean break_lines,
gchar *out,
gint *state,
gint *save)
{
char *outptr;
const guchar *inptr;
g_return_val_if_fail (in != NULL || len == 0, 0);
g_return_val_if_fail (out != NULL, 0);
g_return_val_if_fail (state != NULL, 0);
g_return_val_if_fail (save != NULL, 0);
if (len == 0)
return 0;
inptr = in;
outptr = out;
if (len + ((char *) save) [0] > 2)
{
const guchar *inend = in+len-2;
int c1, c2, c3;
int already;
already = *state;
switch (((char *) save) [0])
{
case 1:
c1 = ((unsigned char *) save) [1];
goto skip1;
case 2:
c1 = ((unsigned char *) save) [1];
c2 = ((unsigned char *) save) [2];
goto skip2;
}
/*
* yes, we jump into the loop, no i'm not going to change it,
* it's beautiful!
*/
while (inptr < inend)
{
c1 = *inptr++;
skip1:
c2 = *inptr++;
skip2:
c3 = *inptr++;
*outptr++ = base64_alphabet [ c1 >> 2 ];
*outptr++ = base64_alphabet [ c2 >> 4 |
((c1&0x3) << 4) ];
*outptr++ = base64_alphabet [ ((c2 &0x0f) << 2) |
(c3 >> 6) ];
*outptr++ = base64_alphabet [ c3 & 0x3f ];
/* this is a bit ugly ... */
if (break_lines && (++already) >= 19)
{
*outptr++ = '\n';
already = 0;
}
}
((char *)save)[0] = 0;
len = 2 - (inptr - inend);
*state = already;
}
g_assert (len == 0 || len == 1 || len == 2);
{
char *saveout;
/* points to the slot for the next char to save */
saveout = & (((char *)save)[1]) + ((char *)save)[0];
/* len can only be 0 1 or 2 */
switch(len)
{
case 2:
*saveout++ = *inptr++;
G_GNUC_FALLTHROUGH;
case 1:
*saveout++ = *inptr++;
}
((char *)save)[0] += len;
}
return outptr - out;
}
/**
* g_base64_encode_close:
* @break_lines: whether to break long lines
* @out: (out) (array) (element-type guint8): pointer to destination buffer
* @state: (inout): Saved state from g_base64_encode_step()
* @save: (inout): Saved state from g_base64_encode_step()
*
* Flush the status from a sequence of calls to g_base64_encode_step().
*
* The output buffer must be large enough to fit all the data that will
* be written to it. It will need up to 4 bytes, or up to 5 bytes if
* line-breaking is enabled.
*
* The @out array will not be automatically nul-terminated.
*
* Returns: The number of bytes of output that was written
*
* Since: 2.12
*/
gsize
g_base64_encode_close (gboolean break_lines,
gchar *out,
gint *state,
gint *save)
{
int c1, c2;
char *outptr = out;
g_return_val_if_fail (out != NULL, 0);
g_return_val_if_fail (state != NULL, 0);
g_return_val_if_fail (save != NULL, 0);
c1 = ((unsigned char *) save) [1];
c2 = ((unsigned char *) save) [2];
switch (((char *) save) [0])
{
case 2:
outptr [2] = base64_alphabet[ ( (c2 &0x0f) << 2 ) ];
g_assert (outptr [2] != 0);
goto skip;
case 1:
outptr[2] = '=';
c2 = 0; /* saved state here is not relevant */
skip:
outptr [0] = base64_alphabet [ c1 >> 2 ];
outptr [1] = base64_alphabet [ c2 >> 4 | ( (c1&0x3) << 4 )];
outptr [3] = '=';
outptr += 4;
break;
}
if (break_lines)
*outptr++ = '\n';
*save = 0;
*state = 0;
return outptr - out;
}
/**
* g_base64_encode:
* @data: (array length=len) (element-type guint8) (nullable): the binary data to encode
* @len: the length of @data
*
* Encode a sequence of binary data into its Base-64 stringified
* representation.
*
* Returns: (transfer full): a newly allocated, zero-terminated Base-64
* encoded string representing @data. The returned string must
* be freed with g_free().
*
* Since: 2.12
*/
gchar *
g_base64_encode (const guchar *data,
gsize len)
{
gchar *out;
gint state = 0, outlen;
gint save = 0;
g_return_val_if_fail (data != NULL || len == 0, NULL);
/* We can use a smaller limit here, since we know the saved state is 0,
+1 is needed for trailing \0, also check for unlikely integer overflow */
g_return_val_if_fail (len < ((G_MAXSIZE - 1) / 4 - 1) * 3, NULL);
out = g_malloc ((len / 3 + 1) * 4 + 1);
outlen = g_base64_encode_step (data, len, FALSE, out, &state, &save);
outlen += g_base64_encode_close (FALSE, out + outlen, &state, &save);
out[outlen] = '\0';
return (gchar *) out;
}
static const unsigned char mime_base64_rank[256] = {
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255,
255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
};
/**
* g_base64_decode_step: (skip)
* @in: (array length=len) (element-type guint8): binary input data
* @len: max length of @in data to decode
* @out: (out caller-allocates) (array) (element-type guint8): output buffer
* @state: (inout): Saved state between steps, initialize to 0
* @save: (inout): Saved state between steps, initialize to 0
*
* Incrementally decode a sequence of binary data from its Base-64 stringified
* representation. By calling this function multiple times you can convert
* data in chunks to avoid having to have the full encoded data in memory.
*
* The output buffer must be large enough to fit all the data that will
* be written to it. Since base64 encodes 3 bytes in 4 chars you need
* at least: (@len / 4) * 3 + 3 bytes (+ 3 may be needed in case of non-zero
* state).
*
* Returns: The number of bytes of output that was written
*
* Since: 2.12
**/
gsize
g_base64_decode_step (const gchar *in,
gsize len,
guchar *out,
gint *state,
guint *save)
{
const guchar *inptr;
guchar *outptr;
const guchar *inend;
guchar c, rank;
guchar last[2];
unsigned int v;
int i;
g_return_val_if_fail (in != NULL || len == 0, 0);
g_return_val_if_fail (out != NULL, 0);
g_return_val_if_fail (state != NULL, 0);
g_return_val_if_fail (save != NULL, 0);
if (len == 0)
return 0;
inend = (const guchar *)in+len;
outptr = out;
/* convert 4 base64 bytes to 3 normal bytes */
v=*save;
i=*state;
last[0] = last[1] = 0;
/* we use the sign in the state to determine if we got a padding character
in the previous sequence */
if (i < 0)
{
i = -i;
last[0] = '=';
}
inptr = (const guchar *)in;
while (inptr < inend)
{
c = *inptr++;
rank = mime_base64_rank [c];
if (rank != 0xff)
{
last[1] = last[0];
last[0] = c;
v = (v<<6) | rank;
i++;
if (i==4)
{
*outptr++ = v>>16;
if (last[1] != '=')
*outptr++ = v>>8;
if (last[0] != '=')
*outptr++ = v;
i=0;
}
}
}
*save = v;
*state = last[0] == '=' ? -i : i;
return outptr - out;
}
/**
* g_base64_decode:
* @text: (not nullable): zero-terminated string with base64 text to decode
* @out_len: (out): The length of the decoded data is written here
*
* Decode a sequence of Base-64 encoded text into binary data. Note
* that the returned binary data is not necessarily zero-terminated,
* so it should not be used as a character string.
*
* Returns: (transfer full) (array length=out_len) (element-type guint8):
* newly allocated buffer containing the binary data
* that @text represents. The returned buffer must
* be freed with g_free().
*
* Since: 2.12
*/
guchar *
g_base64_decode (const gchar *text,
gsize *out_len)
{
guchar *ret;
gsize input_length;
gint state = 0;
guint save = 0;
g_return_val_if_fail (text != NULL, NULL);
g_return_val_if_fail (out_len != NULL, NULL);
input_length = strlen (text);
/* We can use a smaller limit here, since we know the saved state is 0,
+1 used to avoid calling g_malloc0(0), and hence returning NULL */
ret = g_malloc0 ((input_length / 4) * 3 + 1);
*out_len = g_base64_decode_step (text, input_length, ret, &state, &save);
return ret;
}
/**
* g_base64_decode_inplace:
* @text: (inout) (array length=out_len) (element-type guint8): zero-terminated
* string with base64 text to decode
* @out_len: (inout): The length of the decoded data is written here
*
* Decode a sequence of Base-64 encoded text into binary data
* by overwriting the input data.
*
* Returns: (transfer none): The binary data that @text responds. This pointer
* is the same as the input @text.
*
* Since: 2.20
*/
guchar *
g_base64_decode_inplace (gchar *text,
gsize *out_len)
{
gint input_length, state = 0;
guint save = 0;
g_return_val_if_fail (text != NULL, NULL);
g_return_val_if_fail (out_len != NULL, NULL);
input_length = strlen (text);
g_return_val_if_fail (input_length > 1, NULL);
*out_len = g_base64_decode_step (text, input_length, (guchar *) text, &state, &save);
return (guchar *) text;
}

61
glib/gbase64.h Normal file
View file

@ -0,0 +1,61 @@
/* gbase64.h - Base64 coding functions
*
* Copyright (C) 2005 Alexander Larsson <alexl@redhat.com>
*
* 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/>.
*/
#ifndef __G_BASE64_H__
#define __G_BASE64_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtypes.h>
G_BEGIN_DECLS
GLIB_AVAILABLE_IN_ALL
gsize g_base64_encode_step (const guchar *in,
gsize len,
gboolean break_lines,
gchar *out,
gint *state,
gint *save);
GLIB_AVAILABLE_IN_ALL
gsize g_base64_encode_close (gboolean break_lines,
gchar *out,
gint *state,
gint *save);
GLIB_AVAILABLE_IN_ALL
gchar* g_base64_encode (const guchar *data,
gsize len) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
gsize g_base64_decode_step (const gchar *in,
gsize len,
guchar *out,
gint *state,
guint *save);
GLIB_AVAILABLE_IN_ALL
guchar *g_base64_decode (const gchar *text,
gsize *out_len) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
guchar *g_base64_decode_inplace (gchar *text,
gsize *out_len);
G_END_DECLS
#endif /* __G_BASE64_H__ */

563
glib/gbitlock.c Normal file
View file

@ -0,0 +1,563 @@
/*
* Copyright © 2008 Ryan Lortie
* Copyright © 2010 Codethink Limited
*
* 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/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#include "config.h"
#include "gbitlock.h"
#include <glib/gmacros.h>
#include <glib/gmessages.h>
#include <glib/gatomic.h>
#include <glib/gslist.h>
#include <glib/gthread.h>
#include <glib/gslice.h>
#include "gthreadprivate.h"
#ifdef G_BIT_LOCK_FORCE_FUTEX_EMULATION
#undef HAVE_FUTEX
#endif
#ifndef HAVE_FUTEX
static GMutex g_futex_mutex;
static GSList *g_futex_address_list = NULL;
#endif
#ifdef HAVE_FUTEX
/*
* We have headers for futex(2) on the build machine. This does not
* imply that every system that ever runs the resulting glib will have
* kernel support for futex, but you'd have to have a pretty old
* kernel in order for that not to be the case.
*
* If anyone actually gets bit by this, please file a bug. :)
*/
#include <linux/futex.h>
#include <sys/syscall.h>
#include <unistd.h>
#ifndef FUTEX_WAIT_PRIVATE
#define FUTEX_WAIT_PRIVATE FUTEX_WAIT
#define FUTEX_WAKE_PRIVATE FUTEX_WAKE
#endif
/* < private >
* g_futex_wait:
* @address: a pointer to an integer
* @value: the value that should be at @address
*
* Atomically checks that the value stored at @address is equal to
* @value and then blocks. If the value stored at @address is not
* equal to @value then this function returns immediately.
*
* To unblock, call g_futex_wake() on @address.
*
* This call may spuriously unblock (for example, in response to the
* process receiving a signal) but this is not guaranteed. Unlike the
* Linux system call of a similar name, there is no guarantee that a
* waiting process will unblock due to a g_futex_wake() call in a
* separate process.
*/
static void
g_futex_wait (const gint *address,
gint value)
{
syscall (__NR_futex, address, (gsize) FUTEX_WAIT_PRIVATE, (gsize) value, NULL);
}
/* < private >
* g_futex_wake:
* @address: a pointer to an integer
*
* Nominally, wakes one thread that is blocked in g_futex_wait() on
* @address (if any thread is currently waiting).
*
* As mentioned in the documentation for g_futex_wait(), spurious
* wakeups may occur. As such, this call may result in more than one
* thread being woken up.
*/
static void
g_futex_wake (const gint *address)
{
syscall (__NR_futex, address, (gsize) FUTEX_WAKE_PRIVATE, (gsize) 1, NULL);
}
#else
/* emulate futex(2) */
typedef struct
{
const gint *address;
gint ref_count;
GCond wait_queue;
} WaitAddress;
static WaitAddress *
g_futex_find_address (const gint *address)
{
GSList *node;
for (node = g_futex_address_list; node; node = node->next)
{
WaitAddress *waiter = node->data;
if (waiter->address == address)
return waiter;
}
return NULL;
}
static void
g_futex_wait (const gint *address,
gint value)
{
g_mutex_lock (&g_futex_mutex);
if G_LIKELY (g_atomic_int_get (address) == value)
{
WaitAddress *waiter;
if ((waiter = g_futex_find_address (address)) == NULL)
{
waiter = g_slice_new (WaitAddress);
waiter->address = address;
g_cond_init (&waiter->wait_queue);
waiter->ref_count = 0;
g_futex_address_list =
g_slist_prepend (g_futex_address_list, waiter);
}
waiter->ref_count++;
g_cond_wait (&waiter->wait_queue, &g_futex_mutex);
if (!--waiter->ref_count)
{
g_futex_address_list =
g_slist_remove (g_futex_address_list, waiter);
g_cond_clear (&waiter->wait_queue);
g_slice_free (WaitAddress, waiter);
}
}
g_mutex_unlock (&g_futex_mutex);
}
static void
g_futex_wake (const gint *address)
{
WaitAddress *waiter;
/* need to lock here for two reasons:
* 1) need to acquire/release lock to ensure waiter is not in
* the process of registering a wait
* 2) need to -stay- locked until the end to ensure a wake()
* in another thread doesn't cause 'waiter' to stop existing
*/
g_mutex_lock (&g_futex_mutex);
if ((waiter = g_futex_find_address (address)))
g_cond_signal (&waiter->wait_queue);
g_mutex_unlock (&g_futex_mutex);
}
#endif
#define CONTENTION_CLASSES 11
static gint g_bit_lock_contended[CONTENTION_CLASSES]; /* (atomic) */
#if (defined (i386) || defined (__amd64__))
#if G_GNUC_CHECK_VERSION(4, 5)
#define USE_ASM_GOTO 1
#endif
#endif
/**
* g_bit_lock:
* @address: a pointer to an integer
* @lock_bit: a bit value between 0 and 31
*
* Sets the indicated @lock_bit in @address. If the bit is already
* set, this call will block until g_bit_unlock() unsets the
* corresponding bit.
*
* Attempting to lock on two different bits within the same integer is
* not supported and will very probably cause deadlocks.
*
* The value of the bit that is set is (1u << @bit). If @bit is not
* between 0 and 31 then the result is undefined.
*
* This function accesses @address atomically. All other accesses to
* @address must be atomic in order for this function to work
* reliably. While @address has a `volatile` qualifier, this is a historical
* artifact and the argument passed to it should not be `volatile`.
*
* Since: 2.24
**/
void
g_bit_lock (volatile gint *address,
gint lock_bit)
{
gint *address_nonvolatile = (gint *) address;
#ifdef USE_ASM_GOTO
retry:
__asm__ volatile goto ("lock bts %1, (%0)\n"
"jc %l[contended]"
: /* no output */
: "r" (address), "r" (lock_bit)
: "cc", "memory"
: contended);
return;
contended:
{
guint mask = 1u << lock_bit;
guint v;
v = (guint) g_atomic_int_get (address_nonvolatile);
if (v & mask)
{
guint class = ((gsize) address_nonvolatile) % G_N_ELEMENTS (g_bit_lock_contended);
g_atomic_int_add (&g_bit_lock_contended[class], +1);
g_futex_wait (address_nonvolatile, v);
g_atomic_int_add (&g_bit_lock_contended[class], -1);
}
}
goto retry;
#else
guint mask = 1u << lock_bit;
guint v;
retry:
v = g_atomic_int_or (address_nonvolatile, mask);
if (v & mask)
/* already locked */
{
guint class = ((gsize) address_nonvolatile) % G_N_ELEMENTS (g_bit_lock_contended);
g_atomic_int_add (&g_bit_lock_contended[class], +1);
g_futex_wait (address_nonvolatile, v);
g_atomic_int_add (&g_bit_lock_contended[class], -1);
goto retry;
}
#endif
}
/**
* g_bit_trylock:
* @address: a pointer to an integer
* @lock_bit: a bit value between 0 and 31
*
* Sets the indicated @lock_bit in @address, returning %TRUE if
* successful. If the bit is already set, returns %FALSE immediately.
*
* Attempting to lock on two different bits within the same integer is
* not supported.
*
* The value of the bit that is set is (1u << @bit). If @bit is not
* between 0 and 31 then the result is undefined.
*
* This function accesses @address atomically. All other accesses to
* @address must be atomic in order for this function to work
* reliably. While @address has a `volatile` qualifier, this is a historical
* artifact and the argument passed to it should not be `volatile`.
*
* Returns: %TRUE if the lock was acquired
*
* Since: 2.24
**/
gboolean
g_bit_trylock (volatile gint *address,
gint lock_bit)
{
#ifdef USE_ASM_GOTO
gboolean result;
__asm__ volatile ("lock bts %2, (%1)\n"
"setnc %%al\n"
"movzx %%al, %0"
: "=r" (result)
: "r" (address), "r" (lock_bit)
: "cc", "memory");
return result;
#else
gint *address_nonvolatile = (gint *) address;
guint mask = 1u << lock_bit;
guint v;
v = g_atomic_int_or (address_nonvolatile, mask);
return ~v & mask;
#endif
}
/**
* g_bit_unlock:
* @address: a pointer to an integer
* @lock_bit: a bit value between 0 and 31
*
* Clears the indicated @lock_bit in @address. If another thread is
* currently blocked in g_bit_lock() on this same bit then it will be
* woken up.
*
* This function accesses @address atomically. All other accesses to
* @address must be atomic in order for this function to work
* reliably. While @address has a `volatile` qualifier, this is a historical
* artifact and the argument passed to it should not be `volatile`.
*
* Since: 2.24
**/
void
g_bit_unlock (volatile gint *address,
gint lock_bit)
{
gint *address_nonvolatile = (gint *) address;
#ifdef USE_ASM_GOTO
__asm__ volatile ("lock btr %1, (%0)"
: /* no output */
: "r" (address), "r" (lock_bit)
: "cc", "memory");
#else
guint mask = 1u << lock_bit;
g_atomic_int_and (address_nonvolatile, ~mask);
#endif
{
guint class = ((gsize) address_nonvolatile) % G_N_ELEMENTS (g_bit_lock_contended);
if (g_atomic_int_get (&g_bit_lock_contended[class]))
g_futex_wake (address_nonvolatile);
}
}
/* We emulate pointer-sized futex(2) because the kernel API only
* supports integers.
*
* We assume that the 'interesting' part is always the lower order bits.
* This assumption holds because pointer bitlocks are restricted to
* using the low order bits of the pointer as the lock.
*
* On 32 bits, there is nothing to do since the pointer size is equal to
* the integer size. On little endian the lower-order bits don't move,
* so do nothing. Only on 64bit big endian do we need to do a bit of
* pointer arithmetic: the low order bits are shifted by 4 bytes. We
* have a helper function that always does the right thing here.
*
* Since we always consider the low-order bits of the integer value, a
* simple cast from (gsize) to (guint) always takes care of that.
*
* After that, pointer-sized futex becomes as simple as:
*
* g_futex_wait (g_futex_int_address (address), (guint) value);
*
* and
*
* g_futex_wake (g_futex_int_address (int_address));
*/
static const gint *
g_futex_int_address (const void *address)
{
const gint *int_address = address;
/* this implementation makes these (reasonable) assumptions: */
G_STATIC_ASSERT (G_BYTE_ORDER == G_LITTLE_ENDIAN ||
(G_BYTE_ORDER == G_BIG_ENDIAN &&
sizeof (int) == 4 &&
(sizeof (gpointer) == 4 || sizeof (gpointer) == 8)));
#if G_BYTE_ORDER == G_BIG_ENDIAN && GLIB_SIZEOF_VOID_P == 8
int_address++;
#endif
return int_address;
}
/**
* g_pointer_bit_lock:
* @address: (not nullable): a pointer to a #gpointer-sized value
* @lock_bit: a bit value between 0 and 31
*
* This is equivalent to g_bit_lock, but working on pointers (or other
* pointer-sized values).
*
* For portability reasons, you may only lock on the bottom 32 bits of
* the pointer.
*
* While @address has a `volatile` qualifier, this is a historical
* artifact and the argument passed to it should not be `volatile`.
*
* Since: 2.30
**/
void
(g_pointer_bit_lock) (volatile void *address,
gint lock_bit)
{
void *address_nonvolatile = (void *) address;
g_return_if_fail (lock_bit < 32);
{
#ifdef USE_ASM_GOTO
retry:
__asm__ volatile goto ("lock bts %1, (%0)\n"
"jc %l[contended]"
: /* no output */
: "r" (address), "r" ((gsize) lock_bit)
: "cc", "memory"
: contended);
return;
contended:
{
gsize *pointer_address = address_nonvolatile;
gsize mask = 1u << lock_bit;
gsize v;
v = (gsize) g_atomic_pointer_get (pointer_address);
if (v & mask)
{
guint class = ((gsize) address_nonvolatile) % G_N_ELEMENTS (g_bit_lock_contended);
g_atomic_int_add (&g_bit_lock_contended[class], +1);
g_futex_wait (g_futex_int_address (address_nonvolatile), v);
g_atomic_int_add (&g_bit_lock_contended[class], -1);
}
}
goto retry;
#else
gsize *pointer_address = address_nonvolatile;
gsize mask = 1u << lock_bit;
gsize v;
retry:
v = g_atomic_pointer_or (pointer_address, mask);
if (v & mask)
/* already locked */
{
guint class = ((gsize) address_nonvolatile) % G_N_ELEMENTS (g_bit_lock_contended);
g_atomic_int_add (&g_bit_lock_contended[class], +1);
g_futex_wait (g_futex_int_address (address_nonvolatile), (guint) v);
g_atomic_int_add (&g_bit_lock_contended[class], -1);
goto retry;
}
#endif
}
}
/**
* g_pointer_bit_trylock:
* @address: (not nullable): a pointer to a #gpointer-sized value
* @lock_bit: a bit value between 0 and 31
*
* This is equivalent to g_bit_trylock(), but working on pointers (or
* other pointer-sized values).
*
* For portability reasons, you may only lock on the bottom 32 bits of
* the pointer.
*
* While @address has a `volatile` qualifier, this is a historical
* artifact and the argument passed to it should not be `volatile`.
*
* Returns: %TRUE if the lock was acquired
*
* Since: 2.30
**/
gboolean
(g_pointer_bit_trylock) (volatile void *address,
gint lock_bit)
{
g_return_val_if_fail (lock_bit < 32, FALSE);
{
#ifdef USE_ASM_GOTO
gboolean result;
__asm__ volatile ("lock bts %2, (%1)\n"
"setnc %%al\n"
"movzx %%al, %0"
: "=r" (result)
: "r" (address), "r" ((gsize) lock_bit)
: "cc", "memory");
return result;
#else
void *address_nonvolatile = (void *) address;
gsize *pointer_address = address_nonvolatile;
gsize mask = 1u << lock_bit;
gsize v;
g_return_val_if_fail (lock_bit < 32, FALSE);
v = g_atomic_pointer_or (pointer_address, mask);
return ~v & mask;
#endif
}
}
/**
* g_pointer_bit_unlock:
* @address: (not nullable): a pointer to a #gpointer-sized value
* @lock_bit: a bit value between 0 and 31
*
* This is equivalent to g_bit_unlock, but working on pointers (or other
* pointer-sized values).
*
* For portability reasons, you may only lock on the bottom 32 bits of
* the pointer.
*
* While @address has a `volatile` qualifier, this is a historical
* artifact and the argument passed to it should not be `volatile`.
*
* Since: 2.30
**/
void
(g_pointer_bit_unlock) (volatile void *address,
gint lock_bit)
{
void *address_nonvolatile = (void *) address;
g_return_if_fail (lock_bit < 32);
{
#ifdef USE_ASM_GOTO
__asm__ volatile ("lock btr %1, (%0)"
: /* no output */
: "r" (address), "r" ((gsize) lock_bit)
: "cc", "memory");
#else
gsize *pointer_address = address_nonvolatile;
gsize mask = 1u << lock_bit;
g_atomic_pointer_and (pointer_address, ~mask);
#endif
{
guint class = ((gsize) address_nonvolatile) % G_N_ELEMENTS (g_bit_lock_contended);
if (g_atomic_int_get (&g_bit_lock_contended[class]))
g_futex_wake (g_futex_int_address (address_nonvolatile));
}
}
}

76
glib/gbitlock.h Normal file
View file

@ -0,0 +1,76 @@
/*
* Copyright © 2008 Ryan Lortie
* Copyright © 2010 Codethink Limited
*
* 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/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __G_BITLOCK_H__
#define __G_BITLOCK_H__
#include <glib/gtypes.h>
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
G_BEGIN_DECLS
GLIB_AVAILABLE_IN_ALL
void g_bit_lock (volatile gint *address,
gint lock_bit);
GLIB_AVAILABLE_IN_ALL
gboolean g_bit_trylock (volatile gint *address,
gint lock_bit);
GLIB_AVAILABLE_IN_ALL
void g_bit_unlock (volatile gint *address,
gint lock_bit);
GLIB_AVAILABLE_IN_ALL
void g_pointer_bit_lock (volatile void *address,
gint lock_bit);
GLIB_AVAILABLE_IN_ALL
gboolean g_pointer_bit_trylock (volatile void *address,
gint lock_bit);
GLIB_AVAILABLE_IN_ALL
void g_pointer_bit_unlock (volatile void *address,
gint lock_bit);
#ifdef __GNUC__
#define g_pointer_bit_lock(address, lock_bit) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(address) == sizeof (gpointer)); \
g_pointer_bit_lock ((address), (lock_bit)); \
}))
#define g_pointer_bit_trylock(address, lock_bit) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(address) == sizeof (gpointer)); \
g_pointer_bit_trylock ((address), (lock_bit)); \
}))
#define g_pointer_bit_unlock(address, lock_bit) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(address) == sizeof (gpointer)); \
g_pointer_bit_unlock ((address), (lock_bit)); \
}))
#endif
G_END_DECLS
#endif /* __G_BITLOCK_H_ */

4022
glib/gbookmarkfile.c Normal file

File diff suppressed because it is too large Load diff

295
glib/gbookmarkfile.h Normal file
View file

@ -0,0 +1,295 @@
/* gbookmarkfile.h: parsing and building desktop bookmarks
*
* Copyright (C) 2005-2006 Emmanuele Bassi
*
* 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/>.
*/
#ifndef __G_BOOKMARK_FILE_H__
#define __G_BOOKMARK_FILE_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gdatetime.h>
#include <glib/gerror.h>
#include <time.h>
G_BEGIN_DECLS
/**
* G_BOOKMARK_FILE_ERROR:
*
* Error domain for bookmark file parsing.
*
* Errors in this domain will be from the #GBookmarkFileError
* enumeration. See #GError for information on error domains.
*/
#define G_BOOKMARK_FILE_ERROR (g_bookmark_file_error_quark ())
/**
* GBookmarkFileError:
* @G_BOOKMARK_FILE_ERROR_INVALID_URI: URI was ill-formed
* @G_BOOKMARK_FILE_ERROR_INVALID_VALUE: a requested field was not found
* @G_BOOKMARK_FILE_ERROR_APP_NOT_REGISTERED: a requested application did
* not register a bookmark
* @G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND: a requested URI was not found
* @G_BOOKMARK_FILE_ERROR_READ: document was ill formed
* @G_BOOKMARK_FILE_ERROR_UNKNOWN_ENCODING: the text being parsed was
* in an unknown encoding
* @G_BOOKMARK_FILE_ERROR_WRITE: an error occurred while writing
* @G_BOOKMARK_FILE_ERROR_FILE_NOT_FOUND: requested file was not found
*
* Error codes returned by bookmark file parsing.
*/
typedef enum
{
G_BOOKMARK_FILE_ERROR_INVALID_URI,
G_BOOKMARK_FILE_ERROR_INVALID_VALUE,
G_BOOKMARK_FILE_ERROR_APP_NOT_REGISTERED,
G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND,
G_BOOKMARK_FILE_ERROR_READ,
G_BOOKMARK_FILE_ERROR_UNKNOWN_ENCODING,
G_BOOKMARK_FILE_ERROR_WRITE,
G_BOOKMARK_FILE_ERROR_FILE_NOT_FOUND
} GBookmarkFileError;
GLIB_AVAILABLE_IN_ALL
GQuark g_bookmark_file_error_quark (void);
/**
* GBookmarkFile:
*
* An opaque data structure representing a set of bookmarks.
*/
typedef struct _GBookmarkFile GBookmarkFile;
GLIB_AVAILABLE_IN_ALL
GBookmarkFile *g_bookmark_file_new (void);
GLIB_AVAILABLE_IN_ALL
void g_bookmark_file_free (GBookmarkFile *bookmark);
GLIB_AVAILABLE_IN_ALL
gboolean g_bookmark_file_load_from_file (GBookmarkFile *bookmark,
const gchar *filename,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_bookmark_file_load_from_data (GBookmarkFile *bookmark,
const gchar *data,
gsize length,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_bookmark_file_load_from_data_dirs (GBookmarkFile *bookmark,
const gchar *file,
gchar **full_path,
GError **error);
GLIB_AVAILABLE_IN_ALL
gchar * g_bookmark_file_to_data (GBookmarkFile *bookmark,
gsize *length,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
gboolean g_bookmark_file_to_file (GBookmarkFile *bookmark,
const gchar *filename,
GError **error);
GLIB_AVAILABLE_IN_ALL
void g_bookmark_file_set_title (GBookmarkFile *bookmark,
const gchar *uri,
const gchar *title);
GLIB_AVAILABLE_IN_ALL
gchar * g_bookmark_file_get_title (GBookmarkFile *bookmark,
const gchar *uri,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
void g_bookmark_file_set_description (GBookmarkFile *bookmark,
const gchar *uri,
const gchar *description);
GLIB_AVAILABLE_IN_ALL
gchar * g_bookmark_file_get_description (GBookmarkFile *bookmark,
const gchar *uri,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
void g_bookmark_file_set_mime_type (GBookmarkFile *bookmark,
const gchar *uri,
const gchar *mime_type);
GLIB_AVAILABLE_IN_ALL
gchar * g_bookmark_file_get_mime_type (GBookmarkFile *bookmark,
const gchar *uri,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
void g_bookmark_file_set_groups (GBookmarkFile *bookmark,
const gchar *uri,
const gchar **groups,
gsize length);
GLIB_AVAILABLE_IN_ALL
void g_bookmark_file_add_group (GBookmarkFile *bookmark,
const gchar *uri,
const gchar *group);
GLIB_AVAILABLE_IN_ALL
gboolean g_bookmark_file_has_group (GBookmarkFile *bookmark,
const gchar *uri,
const gchar *group,
GError **error);
GLIB_AVAILABLE_IN_ALL
gchar ** g_bookmark_file_get_groups (GBookmarkFile *bookmark,
const gchar *uri,
gsize *length,
GError **error);
GLIB_AVAILABLE_IN_ALL
void g_bookmark_file_add_application (GBookmarkFile *bookmark,
const gchar *uri,
const gchar *name,
const gchar *exec);
GLIB_AVAILABLE_IN_ALL
gboolean g_bookmark_file_has_application (GBookmarkFile *bookmark,
const gchar *uri,
const gchar *name,
GError **error);
GLIB_AVAILABLE_IN_ALL
gchar ** g_bookmark_file_get_applications (GBookmarkFile *bookmark,
const gchar *uri,
gsize *length,
GError **error);
GLIB_DEPRECATED_IN_2_66_FOR(g_bookmark_file_set_application_info)
gboolean g_bookmark_file_set_app_info (GBookmarkFile *bookmark,
const gchar *uri,
const gchar *name,
const gchar *exec,
gint count,
time_t stamp,
GError **error);
GLIB_AVAILABLE_IN_2_66
gboolean g_bookmark_file_set_application_info (GBookmarkFile *bookmark,
const char *uri,
const char *name,
const char *exec,
int count,
GDateTime *stamp,
GError **error);
GLIB_DEPRECATED_IN_2_66_FOR(g_bookmark_file_get_application_info)
gboolean g_bookmark_file_get_app_info (GBookmarkFile *bookmark,
const gchar *uri,
const gchar *name,
gchar **exec,
guint *count,
time_t *stamp,
GError **error);
GLIB_AVAILABLE_IN_2_66
gboolean g_bookmark_file_get_application_info (GBookmarkFile *bookmark,
const char *uri,
const char *name,
char **exec,
unsigned int *count,
GDateTime **stamp,
GError **error);
GLIB_AVAILABLE_IN_ALL
void g_bookmark_file_set_is_private (GBookmarkFile *bookmark,
const gchar *uri,
gboolean is_private);
GLIB_AVAILABLE_IN_ALL
gboolean g_bookmark_file_get_is_private (GBookmarkFile *bookmark,
const gchar *uri,
GError **error);
GLIB_AVAILABLE_IN_ALL
void g_bookmark_file_set_icon (GBookmarkFile *bookmark,
const gchar *uri,
const gchar *href,
const gchar *mime_type);
GLIB_AVAILABLE_IN_ALL
gboolean g_bookmark_file_get_icon (GBookmarkFile *bookmark,
const gchar *uri,
gchar **href,
gchar **mime_type,
GError **error);
GLIB_DEPRECATED_IN_2_66_FOR(g_bookmark_file_set_added_date_time)
void g_bookmark_file_set_added (GBookmarkFile *bookmark,
const gchar *uri,
time_t added);
GLIB_AVAILABLE_IN_2_66
void g_bookmark_file_set_added_date_time (GBookmarkFile *bookmark,
const char *uri,
GDateTime *added);
GLIB_DEPRECATED_IN_2_66_FOR(g_bookmark_file_get_added_date_time)
time_t g_bookmark_file_get_added (GBookmarkFile *bookmark,
const gchar *uri,
GError **error);
GLIB_AVAILABLE_IN_2_66
GDateTime *g_bookmark_file_get_added_date_time (GBookmarkFile *bookmark,
const char *uri,
GError **error);
GLIB_DEPRECATED_IN_2_66_FOR(g_bookmark_file_set_modified_date_time)
void g_bookmark_file_set_modified (GBookmarkFile *bookmark,
const gchar *uri,
time_t modified);
GLIB_AVAILABLE_IN_2_66
void g_bookmark_file_set_modified_date_time (GBookmarkFile *bookmark,
const char *uri,
GDateTime *modified);
GLIB_DEPRECATED_IN_2_66_FOR(g_bookmark_file_get_modified_date_time)
time_t g_bookmark_file_get_modified (GBookmarkFile *bookmark,
const gchar *uri,
GError **error);
GLIB_AVAILABLE_IN_2_66
GDateTime *g_bookmark_file_get_modified_date_time (GBookmarkFile *bookmark,
const char *uri,
GError **error);
GLIB_DEPRECATED_IN_2_66_FOR(g_bookmark_file_set_visited_date_time)
void g_bookmark_file_set_visited (GBookmarkFile *bookmark,
const gchar *uri,
time_t visited);
GLIB_AVAILABLE_IN_2_66
void g_bookmark_file_set_visited_date_time (GBookmarkFile *bookmark,
const char *uri,
GDateTime *visited);
GLIB_DEPRECATED_IN_2_66_FOR(g_bookmark_file_get_visited_date_time)
time_t g_bookmark_file_get_visited (GBookmarkFile *bookmark,
const gchar *uri,
GError **error);
GLIB_AVAILABLE_IN_2_66
GDateTime *g_bookmark_file_get_visited_date_time (GBookmarkFile *bookmark,
const char *uri,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_bookmark_file_has_item (GBookmarkFile *bookmark,
const gchar *uri);
GLIB_AVAILABLE_IN_ALL
gint g_bookmark_file_get_size (GBookmarkFile *bookmark);
GLIB_AVAILABLE_IN_ALL
gchar ** g_bookmark_file_get_uris (GBookmarkFile *bookmark,
gsize *length);
GLIB_AVAILABLE_IN_ALL
gboolean g_bookmark_file_remove_group (GBookmarkFile *bookmark,
const gchar *uri,
const gchar *group,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_bookmark_file_remove_application (GBookmarkFile *bookmark,
const gchar *uri,
const gchar *name,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_bookmark_file_remove_item (GBookmarkFile *bookmark,
const gchar *uri,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_bookmark_file_move_item (GBookmarkFile *bookmark,
const gchar *old_uri,
const gchar *new_uri,
GError **error);
G_END_DECLS
#endif /* __G_BOOKMARK_FILE_H__ */

299
glib/gbsearcharray.h Normal file
View file

@ -0,0 +1,299 @@
/* GBSearchArray - Binary Searchable Array implementation
* Copyright (C) 2000-2003 Tim Janik
*
* This software is provided "as is"; redistribution and modification
* is permitted, provided that the following disclaimer is retained.
*
* This software 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.
* In no event shall the authors or contributors be liable for any
* direct, indirect, incidental, special, exemplary, or consequential
* damages (including, but not limited to, procurement of substitute
* goods or services; loss of use, data, or profits; or business
* interruption) however caused and on any theory of liability, whether
* in contract, strict liability, or tort (including negligence or
* otherwise) arising in any way out of the use of this software, even
* if advised of the possibility of such damage.
*/
#ifndef __G_BSEARCH_ARRAY_H__
#define __G_BSEARCH_ARRAY_H__
#include <glib.h>
#include <string.h>
G_BEGIN_DECLS /* c++ guards */
/* this implementation is intended to be usable in third-party code
* simply by pasting the contents of this file. as such, the
* implementation needs to be self-contained within this file.
*/
/* convenience macro to avoid signed overflow for value comparisons */
#define G_BSEARCH_ARRAY_CMP(v1,v2) ((v1) > (v2) ? +1 : (v1) == (v2) ? 0 : -1)
/* --- typedefs --- */
typedef gint (*GBSearchCompareFunc) (gconstpointer bsearch_node1, /* key */
gconstpointer bsearch_node2);
typedef enum
{
G_BSEARCH_ARRAY_ALIGN_POWER2 = 1 << 0, /* align memory to power2 sizes */
G_BSEARCH_ARRAY_AUTO_SHRINK = 1 << 1 /* shrink array upon removal */
} GBSearchArrayFlags;
/* --- structures --- */
typedef struct
{
guint sizeof_node;
GBSearchCompareFunc cmp_nodes;
guint flags;
} GBSearchConfig;
typedef union
{
guint n_nodes;
/*< private >*/
gpointer alignment_dummy1;
glong alignment_dummy2;
gdouble alignment_dummy3;
} GBSearchArray;
/* --- public API --- */
static inline GBSearchArray* g_bsearch_array_create (const GBSearchConfig *bconfig);
static inline gpointer g_bsearch_array_get_nth (GBSearchArray *barray,
const GBSearchConfig *bconfig,
guint nth);
static inline guint g_bsearch_array_get_index (GBSearchArray *barray,
const GBSearchConfig *bconfig,
gconstpointer node_in_array);
static inline GBSearchArray* g_bsearch_array_remove (GBSearchArray *barray,
const GBSearchConfig *bconfig,
guint index_);
/* provide uninitialized space at index for node insertion */
static inline GBSearchArray* g_bsearch_array_grow (GBSearchArray *barray,
const GBSearchConfig *bconfig,
guint index);
/* insert key_node into array if it does not exist, otherwise do nothing */
static inline GBSearchArray* g_bsearch_array_insert (GBSearchArray *barray,
const GBSearchConfig *bconfig,
gconstpointer key_node);
/* insert key_node into array if it does not exist,
* otherwise replace the existing node's contents with key_node
*/
static inline GBSearchArray* g_bsearch_array_replace (GBSearchArray *barray,
const GBSearchConfig *bconfig,
gconstpointer key_node);
static inline void g_bsearch_array_free (GBSearchArray *barray,
const GBSearchConfig *bconfig);
#define g_bsearch_array_get_n_nodes(barray) (((GBSearchArray*) (barray))->n_nodes)
/* g_bsearch_array_lookup():
* return NULL or exact match node
*/
#define g_bsearch_array_lookup(barray, bconfig, key_node) \
g_bsearch_array_lookup_fuzzy ((barray), (bconfig), (key_node), 0)
/* g_bsearch_array_lookup_sibling():
* return NULL for barray->n_nodes==0, otherwise return the
* exact match node, or, if there's no such node, return the
* node last visited, which is pretty close to an exact match
* (will be one off into either direction).
*/
#define g_bsearch_array_lookup_sibling(barray, bconfig, key_node) \
g_bsearch_array_lookup_fuzzy ((barray), (bconfig), (key_node), 1)
/* g_bsearch_array_lookup_insertion():
* return NULL for barray->n_nodes==0 or exact match, otherwise
* return the node where key_node should be inserted (may be one
* after end, i.e. g_bsearch_array_get_index(result) <= barray->n_nodes).
*/
#define g_bsearch_array_lookup_insertion(barray, bconfig, key_node) \
g_bsearch_array_lookup_fuzzy ((barray), (bconfig), (key_node), 2)
/* --- implementation --- */
/* helper macro to cut down realloc()s */
#define G_BSEARCH_UPPER_POWER2(n) ((n) ? 1 << g_bit_storage ((n) - 1) : 0)
#define G_BSEARCH_ARRAY_NODES(barray) (((guint8*) (barray)) + sizeof (GBSearchArray))
static inline GBSearchArray*
g_bsearch_array_create (const GBSearchConfig *bconfig)
{
GBSearchArray *barray;
guint size;
g_return_val_if_fail (bconfig != NULL, NULL);
size = sizeof (GBSearchArray) + bconfig->sizeof_node;
if (bconfig->flags & G_BSEARCH_ARRAY_ALIGN_POWER2)
size = G_BSEARCH_UPPER_POWER2 (size);
barray = (GBSearchArray *) g_malloc (size);
memset (barray, 0, sizeof (GBSearchArray));
return barray;
}
static inline gpointer
g_bsearch_array_lookup_fuzzy (GBSearchArray *barray,
const GBSearchConfig *bconfig,
gconstpointer key_node,
const guint sibling_or_after);
static inline gpointer
g_bsearch_array_lookup_fuzzy (GBSearchArray *barray,
const GBSearchConfig *bconfig,
gconstpointer key_node,
const guint sibling_or_after)
{
GBSearchCompareFunc cmp_nodes = bconfig->cmp_nodes;
guint8 *check = NULL, *nodes = G_BSEARCH_ARRAY_NODES (barray);
guint n_nodes = barray->n_nodes, offs = 0;
guint sizeof_node = bconfig->sizeof_node;
gint cmp = 0;
while (offs < n_nodes)
{
guint i = (offs + n_nodes) >> 1;
check = nodes + i * sizeof_node;
cmp = cmp_nodes (key_node, check);
if (cmp == 0)
return sibling_or_after > 1 ? NULL : check;
else if (cmp < 0)
n_nodes = i;
else /* (cmp > 0) */
offs = i + 1;
}
/* check is last mismatch, cmp > 0 indicates greater key */
return G_LIKELY (!sibling_or_after) ? NULL : (sibling_or_after > 1 && cmp > 0) ? check + sizeof_node : check;
}
static inline gpointer
g_bsearch_array_get_nth (GBSearchArray *barray,
const GBSearchConfig *bconfig,
guint nth)
{
return (G_LIKELY (nth < barray->n_nodes) ?
G_BSEARCH_ARRAY_NODES (barray) + nth * bconfig->sizeof_node :
NULL);
}
static inline guint
g_bsearch_array_get_index (GBSearchArray *barray,
const GBSearchConfig *bconfig,
gconstpointer node_in_array)
{
guint distance = ((guint8*) node_in_array) - G_BSEARCH_ARRAY_NODES (barray);
g_return_val_if_fail (node_in_array != NULL, barray->n_nodes);
distance /= bconfig->sizeof_node;
return MIN (distance, barray->n_nodes + 1); /* may return one after end */
}
static inline GBSearchArray*
g_bsearch_array_grow (GBSearchArray *barray,
const GBSearchConfig *bconfig,
guint index_)
{
guint old_size = barray->n_nodes * bconfig->sizeof_node;
guint new_size = old_size + bconfig->sizeof_node;
guint8 *node;
g_return_val_if_fail (index_ <= barray->n_nodes, NULL);
if (G_UNLIKELY (bconfig->flags & G_BSEARCH_ARRAY_ALIGN_POWER2))
{
new_size = G_BSEARCH_UPPER_POWER2 (sizeof (GBSearchArray) + new_size);
old_size = G_BSEARCH_UPPER_POWER2 (sizeof (GBSearchArray) + old_size);
if (old_size != new_size)
barray = (GBSearchArray *) g_realloc (barray, new_size);
}
else
barray = (GBSearchArray *) g_realloc (barray, sizeof (GBSearchArray) + new_size);
node = G_BSEARCH_ARRAY_NODES (barray) + index_ * bconfig->sizeof_node;
memmove (node + bconfig->sizeof_node, node, (barray->n_nodes - index_) * bconfig->sizeof_node);
barray->n_nodes += 1;
return barray;
}
static inline GBSearchArray*
g_bsearch_array_insert (GBSearchArray *barray,
const GBSearchConfig *bconfig,
gconstpointer key_node)
{
guint8 *node;
if (G_UNLIKELY (!barray->n_nodes))
{
barray = g_bsearch_array_grow (barray, bconfig, 0);
node = G_BSEARCH_ARRAY_NODES (barray);
}
else
{
node = (guint8 *) g_bsearch_array_lookup_insertion (barray, bconfig, key_node);
if (G_LIKELY (node))
{
guint index_ = g_bsearch_array_get_index (barray, bconfig, node);
/* grow and insert */
barray = g_bsearch_array_grow (barray, bconfig, index_);
node = G_BSEARCH_ARRAY_NODES (barray) + index_ * bconfig->sizeof_node;
}
else /* no insertion needed, node already there */
return barray;
}
memcpy (node, key_node, bconfig->sizeof_node);
return barray;
}
static inline GBSearchArray*
g_bsearch_array_replace (GBSearchArray *barray,
const GBSearchConfig *bconfig,
gconstpointer key_node)
{
guint8 *node = (guint8 *) g_bsearch_array_lookup (barray, bconfig, key_node);
if (G_LIKELY (node)) /* expected path */
memcpy (node, key_node, bconfig->sizeof_node);
else /* revert to insertion */
barray = g_bsearch_array_insert (barray, bconfig, key_node);
return barray;
}
static inline GBSearchArray*
g_bsearch_array_remove (GBSearchArray *barray,
const GBSearchConfig *bconfig,
guint index_)
{
guint8 *node;
g_return_val_if_fail (index_ < barray->n_nodes, NULL);
barray->n_nodes -= 1;
node = G_BSEARCH_ARRAY_NODES (barray) + index_ * bconfig->sizeof_node;
memmove (node, node + bconfig->sizeof_node, (barray->n_nodes - index_) * bconfig->sizeof_node);
if (G_UNLIKELY (bconfig->flags & G_BSEARCH_ARRAY_AUTO_SHRINK))
{
guint new_size = barray->n_nodes * bconfig->sizeof_node;
guint old_size = new_size + bconfig->sizeof_node;
if (G_UNLIKELY (bconfig->flags & G_BSEARCH_ARRAY_ALIGN_POWER2))
{
new_size = G_BSEARCH_UPPER_POWER2 (sizeof (GBSearchArray) + new_size);
old_size = G_BSEARCH_UPPER_POWER2 (sizeof (GBSearchArray) + old_size);
if (old_size != new_size)
barray = (GBSearchArray *) g_realloc (barray, new_size);
}
else
barray = (GBSearchArray *) g_realloc (barray, sizeof (GBSearchArray) + new_size);
}
return barray;
}
static inline void
g_bsearch_array_free (GBSearchArray *barray,
const GBSearchConfig *bconfig)
{
g_return_if_fail (barray != NULL);
g_free (barray);
}
G_END_DECLS /* c++ guards */
#endif /* !__G_BSEARCH_ARRAY_H__ */

612
glib/gbytes.c Normal file
View file

@ -0,0 +1,612 @@
/*
* Copyright © 2009, 2010 Codethink Limited
* Copyright © 2011 Collabora Ltd.
*
* 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/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
* Stef Walter <stefw@collabora.co.uk>
*/
#include "config.h"
#include "gbytes.h"
#include <glib/garray.h>
#include <glib/gstrfuncs.h>
#include <glib/gatomic.h>
#include <glib/gslice.h>
#include <glib/gtestutils.h>
#include <glib/gmem.h>
#include <glib/gmessages.h>
#include <glib/grefcount.h>
#include <string.h>
/**
* GBytes:
*
* A simple refcounted data type representing an immutable sequence of zero or
* more bytes from an unspecified origin.
*
* The purpose of a #GBytes is to keep the memory region that it holds
* alive for as long as anyone holds a reference to the bytes. When
* the last reference count is dropped, the memory is released. Multiple
* unrelated callers can use byte data in the #GBytes without coordinating
* their activities, resting assured that the byte data will not change or
* move while they hold a reference.
*
* A #GBytes can come from many different origins that may have
* different procedures for freeing the memory region. Examples are
* memory from g_malloc(), from memory slices, from a #GMappedFile or
* memory from other allocators.
*
* #GBytes work well as keys in #GHashTable. Use g_bytes_equal() and
* g_bytes_hash() as parameters to g_hash_table_new() or g_hash_table_new_full().
* #GBytes can also be used as keys in a #GTree by passing the g_bytes_compare()
* function to g_tree_new().
*
* The data pointed to by this bytes must not be modified. For a mutable
* array of bytes see #GByteArray. Use g_bytes_unref_to_array() to create a
* mutable array for a #GBytes sequence. To create an immutable #GBytes from
* a mutable #GByteArray, use the g_byte_array_free_to_bytes() function.
*
* Since: 2.32
**/
/* Keep in sync with glib/tests/bytes.c */
struct _GBytes
{
gconstpointer data; /* may be NULL iff (size == 0) */
gsize size; /* may be 0 */
gatomicrefcount ref_count;
GDestroyNotify free_func;
gpointer user_data;
};
/**
* g_bytes_new:
* @data: (transfer none) (array length=size) (element-type guint8) (nullable):
* the data to be used for the bytes
* @size: the size of @data
*
* Creates a new #GBytes from @data.
*
* @data is copied. If @size is 0, @data may be %NULL.
*
* Returns: (transfer full): a new #GBytes
*
* Since: 2.32
*/
GBytes *
g_bytes_new (gconstpointer data,
gsize size)
{
g_return_val_if_fail (data != NULL || size == 0, NULL);
return g_bytes_new_take (g_memdup2 (data, size), size);
}
/**
* g_bytes_new_take:
* @data: (transfer full) (array length=size) (element-type guint8) (nullable):
* the data to be used for the bytes
* @size: the size of @data
*
* Creates a new #GBytes from @data.
*
* After this call, @data belongs to the bytes and may no longer be
* modified by the caller. g_free() will be called on @data when the
* bytes is no longer in use. Because of this @data must have been created by
* a call to g_malloc(), g_malloc0() or g_realloc() or by one of the many
* functions that wrap these calls (such as g_new(), g_strdup(), etc).
*
* For creating #GBytes with memory from other allocators, see
* g_bytes_new_with_free_func().
*
* @data may be %NULL if @size is 0.
*
* Returns: (transfer full): a new #GBytes
*
* Since: 2.32
*/
GBytes *
g_bytes_new_take (gpointer data,
gsize size)
{
return g_bytes_new_with_free_func (data, size, g_free, data);
}
/**
* g_bytes_new_static: (skip)
* @data: (transfer full) (array length=size) (element-type guint8) (nullable):
* the data to be used for the bytes
* @size: the size of @data
*
* Creates a new #GBytes from static data.
*
* @data must be static (ie: never modified or freed). It may be %NULL if @size
* is 0.
*
* Returns: (transfer full): a new #GBytes
*
* Since: 2.32
*/
GBytes *
g_bytes_new_static (gconstpointer data,
gsize size)
{
return g_bytes_new_with_free_func (data, size, NULL, NULL);
}
/**
* g_bytes_new_with_free_func: (skip)
* @data: (array length=size) (element-type guint8) (nullable):
* the data to be used for the bytes
* @size: the size of @data
* @free_func: the function to call to release the data
* @user_data: data to pass to @free_func
*
* Creates a #GBytes from @data.
*
* When the last reference is dropped, @free_func will be called with the
* @user_data argument.
*
* @data must not be modified after this call is made until @free_func has
* been called to indicate that the bytes is no longer in use.
*
* @data may be %NULL if @size is 0.
*
* Returns: (transfer full): a new #GBytes
*
* Since: 2.32
*/
GBytes *
g_bytes_new_with_free_func (gconstpointer data,
gsize size,
GDestroyNotify free_func,
gpointer user_data)
{
GBytes *bytes;
g_return_val_if_fail (data != NULL || size == 0, NULL);
bytes = g_slice_new (GBytes);
bytes->data = data;
bytes->size = size;
bytes->free_func = free_func;
bytes->user_data = user_data;
g_atomic_ref_count_init (&bytes->ref_count);
return (GBytes *)bytes;
}
/**
* g_bytes_new_from_bytes:
* @bytes: a #GBytes
* @offset: offset which subsection starts at
* @length: length of subsection
*
* Creates a #GBytes which is a subsection of another #GBytes. The @offset +
* @length may not be longer than the size of @bytes.
*
* A reference to @bytes will be held by the newly created #GBytes until
* the byte data is no longer needed.
*
* Since 2.56, if @offset is 0 and @length matches the size of @bytes, then
* @bytes will be returned with the reference count incremented by 1. If @bytes
* is a slice of another #GBytes, then the resulting #GBytes will reference
* the same #GBytes instead of @bytes. This allows consumers to simplify the
* usage of #GBytes when asynchronously writing to streams.
*
* Returns: (transfer full): a new #GBytes
*
* Since: 2.32
*/
GBytes *
g_bytes_new_from_bytes (GBytes *bytes,
gsize offset,
gsize length)
{
gchar *base;
/* Note that length may be 0. */
g_return_val_if_fail (bytes != NULL, NULL);
g_return_val_if_fail (offset <= bytes->size, NULL);
g_return_val_if_fail (offset + length <= bytes->size, NULL);
/* Avoid an extra GBytes if all bytes were requested */
if (offset == 0 && length == bytes->size)
return g_bytes_ref (bytes);
base = (gchar *)bytes->data + offset;
/* Avoid referencing intermediate GBytes. In practice, this should
* only loop once.
*/
while (bytes->free_func == (gpointer)g_bytes_unref)
bytes = bytes->user_data;
g_return_val_if_fail (bytes != NULL, NULL);
g_return_val_if_fail (base >= (gchar *)bytes->data, NULL);
g_return_val_if_fail (base <= (gchar *)bytes->data + bytes->size, NULL);
g_return_val_if_fail (base + length <= (gchar *)bytes->data + bytes->size, NULL);
return g_bytes_new_with_free_func (base, length,
(GDestroyNotify)g_bytes_unref, g_bytes_ref (bytes));
}
/**
* g_bytes_get_data:
* @bytes: a #GBytes
* @size: (out) (optional): location to return size of byte data
*
* Get the byte data in the #GBytes. This data should not be modified.
*
* This function will always return the same pointer for a given #GBytes.
*
* %NULL may be returned if @size is 0. This is not guaranteed, as the #GBytes
* may represent an empty string with @data non-%NULL and @size as 0. %NULL will
* not be returned if @size is non-zero.
*
* Returns: (transfer none) (array length=size) (element-type guint8) (nullable):
* a pointer to the byte data, or %NULL
*
* Since: 2.32
*/
gconstpointer
g_bytes_get_data (GBytes *bytes,
gsize *size)
{
g_return_val_if_fail (bytes != NULL, NULL);
if (size)
*size = bytes->size;
return bytes->data;
}
/**
* g_bytes_get_size:
* @bytes: a #GBytes
*
* Get the size of the byte data in the #GBytes.
*
* This function will always return the same value for a given #GBytes.
*
* Returns: the size
*
* Since: 2.32
*/
gsize
g_bytes_get_size (GBytes *bytes)
{
g_return_val_if_fail (bytes != NULL, 0);
return bytes->size;
}
/**
* g_bytes_ref:
* @bytes: a #GBytes
*
* Increase the reference count on @bytes.
*
* Returns: the #GBytes
*
* Since: 2.32
*/
GBytes *
g_bytes_ref (GBytes *bytes)
{
g_return_val_if_fail (bytes != NULL, NULL);
g_atomic_ref_count_inc (&bytes->ref_count);
return bytes;
}
/**
* g_bytes_unref:
* @bytes: (nullable): a #GBytes
*
* Releases a reference on @bytes. This may result in the bytes being
* freed. If @bytes is %NULL, it will return immediately.
*
* Since: 2.32
*/
void
g_bytes_unref (GBytes *bytes)
{
if (bytes == NULL)
return;
if (g_atomic_ref_count_dec (&bytes->ref_count))
{
if (bytes->free_func != NULL)
bytes->free_func (bytes->user_data);
g_slice_free (GBytes, bytes);
}
}
/**
* g_bytes_equal:
* @bytes1: (type GLib.Bytes): a pointer to a #GBytes
* @bytes2: (type GLib.Bytes): a pointer to a #GBytes to compare with @bytes1
*
* Compares the two #GBytes values being pointed to and returns
* %TRUE if they are equal.
*
* This function can be passed to g_hash_table_new() as the @key_equal_func
* parameter, when using non-%NULL #GBytes pointers as keys in a #GHashTable.
*
* Returns: %TRUE if the two keys match.
*
* Since: 2.32
*/
gboolean
g_bytes_equal (gconstpointer bytes1,
gconstpointer bytes2)
{
const GBytes *b1 = bytes1;
const GBytes *b2 = bytes2;
g_return_val_if_fail (bytes1 != NULL, FALSE);
g_return_val_if_fail (bytes2 != NULL, FALSE);
return b1->size == b2->size &&
(b1->size == 0 || memcmp (b1->data, b2->data, b1->size) == 0);
}
/**
* g_bytes_hash:
* @bytes: (type GLib.Bytes): a pointer to a #GBytes key
*
* Creates an integer hash code for the byte data in the #GBytes.
*
* This function can be passed to g_hash_table_new() as the @key_hash_func
* parameter, when using non-%NULL #GBytes pointers as keys in a #GHashTable.
*
* Returns: a hash value corresponding to the key.
*
* Since: 2.32
*/
guint
g_bytes_hash (gconstpointer bytes)
{
const GBytes *a = bytes;
const signed char *p, *e;
guint32 h = 5381;
g_return_val_if_fail (bytes != NULL, 0);
for (p = (signed char *)a->data, e = (signed char *)a->data + a->size; p != e; p++)
h = (h << 5) + h + *p;
return h;
}
/**
* g_bytes_compare:
* @bytes1: (type GLib.Bytes): a pointer to a #GBytes
* @bytes2: (type GLib.Bytes): a pointer to a #GBytes to compare with @bytes1
*
* Compares the two #GBytes values.
*
* This function can be used to sort GBytes instances in lexicographical order.
*
* If @bytes1 and @bytes2 have different length but the shorter one is a
* prefix of the longer one then the shorter one is considered to be less than
* the longer one. Otherwise the first byte where both differ is used for
* comparison. If @bytes1 has a smaller value at that position it is
* considered less, otherwise greater than @bytes2.
*
* Returns: a negative value if @bytes1 is less than @bytes2, a positive value
* if @bytes1 is greater than @bytes2, and zero if @bytes1 is equal to
* @bytes2
*
*
* Since: 2.32
*/
gint
g_bytes_compare (gconstpointer bytes1,
gconstpointer bytes2)
{
const GBytes *b1 = bytes1;
const GBytes *b2 = bytes2;
gint ret;
g_return_val_if_fail (bytes1 != NULL, 0);
g_return_val_if_fail (bytes2 != NULL, 0);
ret = memcmp (b1->data, b2->data, MIN (b1->size, b2->size));
if (ret == 0 && b1->size != b2->size)
ret = b1->size < b2->size ? -1 : 1;
return ret;
}
static gpointer
try_steal_and_unref (GBytes *bytes,
GDestroyNotify free_func,
gsize *size)
{
gpointer result;
if (bytes->free_func != free_func || bytes->data == NULL ||
bytes->user_data != bytes->data)
return NULL;
/* Are we the only reference? */
if (g_atomic_ref_count_compare (&bytes->ref_count, 1))
{
*size = bytes->size;
result = (gpointer)bytes->data;
g_slice_free (GBytes, bytes);
return result;
}
return NULL;
}
/**
* g_bytes_unref_to_data:
* @bytes: (transfer full): a #GBytes
* @size: (out): location to place the length of the returned data
*
* Unreferences the bytes, and returns a pointer the same byte data
* contents.
*
* As an optimization, the byte data is returned without copying if this was
* the last reference to bytes and bytes was created with g_bytes_new(),
* g_bytes_new_take() or g_byte_array_free_to_bytes(). In all other cases the
* data is copied.
*
* Returns: (transfer full) (array length=size) (element-type guint8)
* (not nullable): a pointer to the same byte data, which should be
* freed with g_free()
*
* Since: 2.32
*/
gpointer
g_bytes_unref_to_data (GBytes *bytes,
gsize *size)
{
gpointer result;
g_return_val_if_fail (bytes != NULL, NULL);
g_return_val_if_fail (size != NULL, NULL);
/*
* Optimal path: if this is was the last reference, then we can return
* the data from this GBytes without copying.
*/
result = try_steal_and_unref (bytes, g_free, size);
if (result == NULL)
{
/*
* Copy: Non g_malloc (or compatible) allocator, or static memory,
* so we have to copy, and then unref.
*/
result = g_memdup2 (bytes->data, bytes->size);
*size = bytes->size;
g_bytes_unref (bytes);
}
return result;
}
/**
* g_bytes_unref_to_array:
* @bytes: (transfer full): a #GBytes
*
* Unreferences the bytes, and returns a new mutable #GByteArray containing
* the same byte data.
*
* As an optimization, the byte data is transferred to the array without copying
* if this was the last reference to bytes and bytes was created with
* g_bytes_new(), g_bytes_new_take() or g_byte_array_free_to_bytes(). In all
* other cases the data is copied.
*
* Do not use it if @bytes contains more than %G_MAXUINT
* bytes. #GByteArray stores the length of its data in #guint, which
* may be shorter than #gsize, that @bytes is using.
*
* Returns: (transfer full): a new mutable #GByteArray containing the same byte data
*
* Since: 2.32
*/
GByteArray *
g_bytes_unref_to_array (GBytes *bytes)
{
gpointer data;
gsize size;
g_return_val_if_fail (bytes != NULL, NULL);
data = g_bytes_unref_to_data (bytes, &size);
return g_byte_array_new_take (data, size);
}
/**
* g_bytes_get_region:
* @bytes: a #GBytes
* @element_size: a non-zero element size
* @offset: an offset to the start of the region within the @bytes
* @n_elements: the number of elements in the region
*
* Gets a pointer to a region in @bytes.
*
* The region starts at @offset many bytes from the start of the data
* and contains @n_elements many elements of @element_size size.
*
* @n_elements may be zero, but @element_size must always be non-zero.
* Ideally, @element_size is a static constant (eg: sizeof a struct).
*
* This function does careful bounds checking (including checking for
* arithmetic overflows) and returns a non-%NULL pointer if the
* specified region lies entirely within the @bytes. If the region is
* in some way out of range, or if an overflow has occurred, then %NULL
* is returned.
*
* Note: it is possible to have a valid zero-size region. In this case,
* the returned pointer will be equal to the base pointer of the data of
* @bytes, plus @offset. This will be non-%NULL except for the case
* where @bytes itself was a zero-sized region. Since it is unlikely
* that you will be using this function to check for a zero-sized region
* in a zero-sized @bytes, %NULL effectively always means "error".
*
* Returns: (nullable): the requested region, or %NULL in case of an error
*
* Since: 2.70
*/
gconstpointer
g_bytes_get_region (GBytes *bytes,
gsize element_size,
gsize offset,
gsize n_elements)
{
gsize total_size;
gsize end_offset;
g_return_val_if_fail (element_size > 0, NULL);
/* No other assertion checks here. If something is wrong then we will
* simply crash (via NULL dereference or divide-by-zero).
*/
if (!g_size_checked_mul (&total_size, element_size, n_elements))
return NULL;
if (!g_size_checked_add (&end_offset, offset, total_size))
return NULL;
/* We now have:
*
* 0 <= offset <= end_offset
*
* So we need only check that end_offset is within the range of the
* size of @bytes and we're good to go.
*/
if (end_offset > bytes->size)
return NULL;
/* We now have:
*
* 0 <= offset <= end_offset <= bytes->size
*/
return ((guchar *) bytes->data) + offset;
}

97
glib/gbytes.h Normal file
View file

@ -0,0 +1,97 @@
/*
* Copyright © 2009, 2010 Codethink Limited
* Copyright © 2011 Collabora Ltd.
*
* 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/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
* Stef Walter <stefw@collabora.co.uk>
*/
#ifndef __G_BYTES_H__
#define __G_BYTES_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtypes.h>
#include <glib/garray.h>
G_BEGIN_DECLS
GLIB_AVAILABLE_IN_ALL
GBytes * g_bytes_new (gconstpointer data,
gsize size);
GLIB_AVAILABLE_IN_ALL
GBytes * g_bytes_new_take (gpointer data,
gsize size);
GLIB_AVAILABLE_IN_ALL
GBytes * g_bytes_new_static (gconstpointer data,
gsize size);
GLIB_AVAILABLE_IN_ALL
GBytes * g_bytes_new_with_free_func (gconstpointer data,
gsize size,
GDestroyNotify free_func,
gpointer user_data);
GLIB_AVAILABLE_IN_ALL
GBytes * g_bytes_new_from_bytes (GBytes *bytes,
gsize offset,
gsize length);
GLIB_AVAILABLE_IN_ALL
gconstpointer g_bytes_get_data (GBytes *bytes,
gsize *size);
GLIB_AVAILABLE_IN_ALL
gsize g_bytes_get_size (GBytes *bytes);
GLIB_AVAILABLE_IN_ALL
GBytes * g_bytes_ref (GBytes *bytes);
GLIB_AVAILABLE_IN_ALL
void g_bytes_unref (GBytes *bytes);
GLIB_AVAILABLE_IN_ALL
gpointer g_bytes_unref_to_data (GBytes *bytes,
gsize *size);
GLIB_AVAILABLE_IN_ALL
GByteArray * g_bytes_unref_to_array (GBytes *bytes);
GLIB_AVAILABLE_IN_ALL
guint g_bytes_hash (gconstpointer bytes);
GLIB_AVAILABLE_IN_ALL
gboolean g_bytes_equal (gconstpointer bytes1,
gconstpointer bytes2);
GLIB_AVAILABLE_IN_ALL
gint g_bytes_compare (gconstpointer bytes1,
gconstpointer bytes2);
GLIB_AVAILABLE_IN_2_70
gconstpointer g_bytes_get_region (GBytes *bytes,
gsize element_size,
gsize offset,
gsize n_elements);
G_END_DECLS
#endif /* __G_BYTES_H__ */

838
glib/gcharset.c Normal file
View file

@ -0,0 +1,838 @@
/* gcharset.c - Charset information
*
* Copyright (C) 2011 Red Hat, Inc.
*
* 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/>.
*/
#include "config.h"
#include "gcharset.h"
#include "gcharsetprivate.h"
#include "garray.h"
#include "genviron.h"
#include "ghash.h"
#include "gmessages.h"
#include "gstrfuncs.h"
#include "gthread.h"
#include "gthreadprivate.h"
#ifdef G_OS_WIN32
#include "gwin32.h"
#endif
#include "libcharset/libcharset.h"
#include <string.h>
#include <stdio.h>
#if (HAVE_LANGINFO_TIME_CODESET || HAVE_LANGINFO_CODESET)
#include <langinfo.h>
#endif
#include <locale.h>
#ifdef G_OS_WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
G_LOCK_DEFINE_STATIC (aliases);
static GHashTable *
get_alias_hash (void)
{
static GHashTable *alias_hash = NULL;
const char *aliases;
G_LOCK (aliases);
if (!alias_hash)
{
alias_hash = g_hash_table_new (g_str_hash, g_str_equal);
aliases = _g_locale_get_charset_aliases ();
while (*aliases != '\0')
{
const char *canonical;
const char *alias;
const char **alias_array;
int count = 0;
alias = aliases;
aliases += strlen (aliases) + 1;
canonical = aliases;
aliases += strlen (aliases) + 1;
alias_array = g_hash_table_lookup (alias_hash, canonical);
if (alias_array)
{
while (alias_array[count])
count++;
}
alias_array = g_renew (const char *, alias_array, count + 2);
alias_array[count] = alias;
alias_array[count + 1] = NULL;
g_hash_table_insert (alias_hash, (char *)canonical, alias_array);
}
}
G_UNLOCK (aliases);
return alias_hash;
}
/* As an abuse of the alias table, the following routines gets
* the charsets that are aliases for the canonical name.
*/
const char **
_g_charset_get_aliases (const char *canonical_name)
{
GHashTable *alias_hash = get_alias_hash ();
return g_hash_table_lookup (alias_hash, canonical_name);
}
static gboolean
g_utf8_get_charset_internal (const char *raw_data,
const char **a)
{
/* Allow CHARSET to override the charset of any locale category. Users should
* probably never be setting this instead, just add the charset after a `.`
* in `LANGUAGE`/`LC_ALL`/`LC_*`/`LANG`. I cant find any reference (in
* `git log`, code comments, or man pages) to this environment variable being
* standardised or documented or even used anywhere outside GLib. Perhaps it
* should eventually be removed. */
const char *charset = g_getenv ("CHARSET");
if (charset && *charset)
{
*a = charset;
if (charset && strstr (charset, "UTF-8"))
return TRUE;
else
return FALSE;
}
/* The libcharset code tries to be thread-safe without
* a lock, but has a memory leak and a missing memory
* barrier, so we lock for it
*/
G_LOCK (aliases);
charset = _g_locale_charset_unalias (raw_data);
G_UNLOCK (aliases);
if (charset && *charset)
{
*a = charset;
if (charset && strstr (charset, "UTF-8"))
return TRUE;
else
return FALSE;
}
/* Assume this for compatibility at present. */
*a = "US-ASCII";
return FALSE;
}
typedef struct _GCharsetCache GCharsetCache;
struct _GCharsetCache {
gboolean is_utf8;
gchar *raw;
gchar *charset;
};
static void
charset_cache_free (gpointer data)
{
GCharsetCache *cache = data;
g_free (cache->raw);
g_free (cache->charset);
g_free (cache);
}
/**
* g_get_charset:
* @charset: (out) (optional) (transfer none): return location for character set
* name, or %NULL.
*
* Obtains the character set for the [current locale][setlocale]; you
* might use this character set as an argument to g_convert(), to convert
* from the current locale's encoding to some other encoding. (Frequently
* g_locale_to_utf8() and g_locale_from_utf8() are nice shortcuts, though.)
*
* On Windows the character set returned by this function is the
* so-called system default ANSI code-page. That is the character set
* used by the "narrow" versions of C library and Win32 functions that
* handle file names. It might be different from the character set
* used by the C library's current locale.
*
* On Linux, the character set is found by consulting nl_langinfo() if
* available. If not, the environment variables `LC_ALL`, `LC_CTYPE`, `LANG`
* and `CHARSET` are queried in order.
*
* The return value is %TRUE if the locale's encoding is UTF-8, in that
* case you can perhaps avoid calling g_convert().
*
* The string returned in @charset is not allocated, and should not be
* freed.
*
* Returns: %TRUE if the returned charset is UTF-8
*/
gboolean
g_get_charset (const char **charset)
{
static GPrivate cache_private = G_PRIVATE_INIT (charset_cache_free);
GCharsetCache *cache = g_private_get (&cache_private);
const gchar *raw;
if (!cache)
cache = g_private_set_alloc0 (&cache_private, sizeof (GCharsetCache));
G_LOCK (aliases);
raw = _g_locale_charset_raw ();
G_UNLOCK (aliases);
if (cache->raw == NULL || strcmp (cache->raw, raw) != 0)
{
const gchar *new_charset;
g_free (cache->raw);
g_free (cache->charset);
cache->raw = g_strdup (raw);
cache->is_utf8 = g_utf8_get_charset_internal (raw, &new_charset);
cache->charset = g_strdup (new_charset);
}
if (charset)
*charset = cache->charset;
return cache->is_utf8;
}
/*
* Do the same as g_get_charset() but it temporarily set locale (LC_ALL to
* LC_TIME) to correctly check for charset about time conversion relatives.
*
* Returns: %TRUE if the returned charset is UTF-8
*/
gboolean
_g_get_time_charset (const char **charset)
{
static GPrivate cache_private = G_PRIVATE_INIT (charset_cache_free);
GCharsetCache *cache = g_private_get (&cache_private);
const gchar *raw;
if (!cache)
cache = g_private_set_alloc0 (&cache_private, sizeof (GCharsetCache));
#ifdef HAVE_LANGINFO_TIME_CODESET
raw = nl_langinfo (_NL_TIME_CODESET);
#else
G_LOCK (aliases);
raw = _g_locale_charset_raw ();
G_UNLOCK (aliases);
#endif
if (cache->raw == NULL || strcmp (cache->raw, raw) != 0)
{
const gchar *new_charset;
g_free (cache->raw);
g_free (cache->charset);
cache->raw = g_strdup (raw);
cache->is_utf8 = g_utf8_get_charset_internal (raw, &new_charset);
cache->charset = g_strdup (new_charset);
}
if (charset)
*charset = cache->charset;
return cache->is_utf8;
}
/*
* Do the same as g_get_charset() but it temporarily set locale (LC_ALL to
* LC_CTYPE) to correctly check for charset about CTYPE conversion relatives.
*
* Returns: %TRUE if the returned charset is UTF-8
*/
gboolean
_g_get_ctype_charset (const char **charset)
{
static GPrivate cache_private = G_PRIVATE_INIT (charset_cache_free);
GCharsetCache *cache = g_private_get (&cache_private);
const gchar *raw;
if (!cache)
cache = g_private_set_alloc0 (&cache_private, sizeof (GCharsetCache));
#ifdef HAVE_LANGINFO_CODESET
raw = nl_langinfo (CODESET);
#else
G_LOCK (aliases);
raw = _g_locale_charset_raw ();
G_UNLOCK (aliases);
#endif
if (cache->raw == NULL || strcmp (cache->raw, raw) != 0)
{
const gchar *new_charset;
g_free (cache->raw);
g_free (cache->charset);
cache->raw = g_strdup (raw);
cache->is_utf8 = g_utf8_get_charset_internal (raw, &new_charset);
cache->charset = g_strdup (new_charset);
}
if (charset)
*charset = cache->charset;
return cache->is_utf8;
}
/**
* g_get_codeset:
*
* Gets the character set for the current locale.
*
* Returns: a newly allocated string containing the name
* of the character set. This string must be freed with g_free().
*/
gchar *
g_get_codeset (void)
{
const gchar *charset;
g_get_charset (&charset);
return g_strdup (charset);
}
/**
* g_get_console_charset:
* @charset: (out) (optional) (transfer none): return location for character set
* name, or %NULL.
*
* Obtains the character set used by the console attached to the process,
* which is suitable for printing output to the terminal.
*
* Usually this matches the result returned by g_get_charset(), but in
* environments where the locale's character set does not match the encoding
* of the console this function tries to guess a more suitable value instead.
*
* On Windows the character set returned by this function is the
* output code page used by the console associated with the calling process.
* If the codepage can't be determined (for example because there is no
* console attached) UTF-8 is assumed.
*
* The return value is %TRUE if the locale's encoding is UTF-8, in that
* case you can perhaps avoid calling g_convert().
*
* The string returned in @charset is not allocated, and should not be
* freed.
*
* Returns: %TRUE if the returned charset is UTF-8
*
* Since: 2.62
*/
gboolean
g_get_console_charset (const char **charset)
{
#ifdef G_OS_WIN32
static GPrivate cache_private = G_PRIVATE_INIT (charset_cache_free);
GCharsetCache *cache = g_private_get (&cache_private);
const gchar *locale;
unsigned int cp;
char buf[2 + 20 + 1]; /* "CP" + G_MAXUINT64 (to be safe) in decimal form (20 bytes) + "\0" */
const gchar *raw = NULL;
if (!cache)
cache = g_private_set_alloc0 (&cache_private, sizeof (GCharsetCache));
/* first try to query $LANG (works for Cygwin/MSYS/MSYS2 and others using mintty) */
locale = g_getenv ("LANG");
if (locale != NULL && locale[0] != '\0')
{
/* If the locale name contains an encoding after the dot, return it. */
const char *dot = strchr (locale, '.');
if (dot != NULL)
{
const char *modifier;
dot++;
/* Look for the possible @... trailer and remove it, if any. */
modifier = strchr (dot, '@');
if (modifier == NULL)
raw = dot;
else if ((gsize) (modifier - dot) < sizeof (buf))
{
memcpy (buf, dot, modifier - dot);
buf[modifier - dot] = '\0';
raw = buf;
}
}
}
/* next try querying console codepage using native win32 API */
if (raw == NULL)
{
cp = GetConsoleOutputCP ();
if (cp)
{
sprintf (buf, "CP%u", cp);
raw = buf;
}
else if (GetLastError () != ERROR_INVALID_HANDLE)
{
gchar *emsg = g_win32_error_message (GetLastError ());
g_warning ("Failed to determine console output code page: %s. "
"Falling back to UTF-8", emsg);
g_free (emsg);
}
}
/* fall-back to UTF-8 if the rest failed (it's a universal default) */
if (raw == NULL)
raw = "UTF-8";
if (cache->raw == NULL || strcmp (cache->raw, raw) != 0)
{
const gchar *new_charset;
g_free (cache->raw);
g_free (cache->charset);
cache->raw = g_strdup (raw);
cache->is_utf8 = g_utf8_get_charset_internal (raw, &new_charset);
cache->charset = g_strdup (new_charset);
}
if (charset)
*charset = cache->charset;
return cache->is_utf8;
#else
/* assume the locale settings match the console encoding on non-Windows OSs */
return g_get_charset (charset);
#endif
}
#ifndef G_OS_WIN32
/* read an alias file for the locales */
static void
read_aliases (const gchar *file,
GHashTable *alias_table)
{
FILE *fp;
char buf[256];
fp = fopen (file,"r");
if (!fp)
return;
while (fgets (buf, 256, fp))
{
char *p, *q;
g_strstrip (buf);
/* Line is a comment */
if ((buf[0] == '#') || (buf[0] == '\0'))
continue;
/* Reads first column */
for (p = buf, q = NULL; *p; p++) {
if ((*p == '\t') || (*p == ' ') || (*p == ':')) {
*p = '\0';
q = p+1;
while ((*q == '\t') || (*q == ' ')) {
q++;
}
break;
}
}
/* The line only had one column */
if (!q || *q == '\0')
continue;
/* Read second column */
for (p = q; *p; p++) {
if ((*p == '\t') || (*p == ' ')) {
*p = '\0';
break;
}
}
/* Add to alias table if necessary */
if (!g_hash_table_lookup (alias_table, buf)) {
g_hash_table_insert (alias_table, g_strdup (buf), g_strdup (q));
}
}
fclose (fp);
}
#endif
static char *
unalias_lang (char *lang)
{
#ifndef G_OS_WIN32
static GHashTable *alias_table = NULL;
char *p;
int i;
if (g_once_init_enter (&alias_table))
{
GHashTable *table = g_hash_table_new (g_str_hash, g_str_equal);
read_aliases ("/usr/share/locale/locale.alias", table);
g_once_init_leave (&alias_table, table);
}
i = 0;
while ((p = g_hash_table_lookup (alias_table, lang)) && (strcmp (p, lang) != 0))
{
lang = p;
if (i++ == 30)
{
static gboolean said_before = FALSE;
if (!said_before)
g_warning ("Too many alias levels for a locale, "
"may indicate a loop");
said_before = TRUE;
return lang;
}
}
#endif
return lang;
}
/* Mask for components of locale spec. The ordering here is from
* least significant to most significant
*/
enum
{
COMPONENT_CODESET = 1 << 0,
COMPONENT_TERRITORY = 1 << 1,
COMPONENT_MODIFIER = 1 << 2
};
/* Break an X/Open style locale specification into components
*/
static guint
explode_locale (const gchar *locale,
gchar **language,
gchar **territory,
gchar **codeset,
gchar **modifier)
{
const gchar *uscore_pos;
const gchar *at_pos;
const gchar *dot_pos;
guint mask = 0;
uscore_pos = strchr (locale, '_');
dot_pos = strchr (uscore_pos ? uscore_pos : locale, '.');
at_pos = strchr (dot_pos ? dot_pos : (uscore_pos ? uscore_pos : locale), '@');
if (at_pos)
{
mask |= COMPONENT_MODIFIER;
*modifier = g_strdup (at_pos);
}
else
at_pos = locale + strlen (locale);
if (dot_pos)
{
mask |= COMPONENT_CODESET;
*codeset = g_strndup (dot_pos, at_pos - dot_pos);
}
else
dot_pos = at_pos;
if (uscore_pos)
{
mask |= COMPONENT_TERRITORY;
*territory = g_strndup (uscore_pos, dot_pos - uscore_pos);
}
else
uscore_pos = dot_pos;
*language = g_strndup (locale, uscore_pos - locale);
return mask;
}
/*
* Compute all interesting variants for a given locale name -
* by stripping off different components of the value.
*
* For simplicity, we assume that the locale is in
* X/Open format: language[_territory][.codeset][@modifier]
*
* TODO: Extend this to handle the CEN format (see the GNUlibc docs)
* as well. We could just copy the code from glibc wholesale
* but it is big, ugly, and complicated, so I'm reluctant
* to do so when this should handle 99% of the time...
*/
static void
append_locale_variants (GPtrArray *array,
const gchar *locale)
{
gchar *language = NULL;
gchar *territory = NULL;
gchar *codeset = NULL;
gchar *modifier = NULL;
guint mask;
guint i, j;
g_return_if_fail (locale != NULL);
mask = explode_locale (locale, &language, &territory, &codeset, &modifier);
/* Iterate through all possible combinations, from least attractive
* to most attractive.
*/
for (j = 0; j <= mask; ++j)
{
i = mask - j;
if ((i & ~mask) == 0)
{
gchar *val = g_strconcat (language,
(i & COMPONENT_TERRITORY) ? territory : "",
(i & COMPONENT_CODESET) ? codeset : "",
(i & COMPONENT_MODIFIER) ? modifier : "",
NULL);
g_ptr_array_add (array, val);
}
}
g_free (language);
if (mask & COMPONENT_CODESET)
g_free (codeset);
if (mask & COMPONENT_TERRITORY)
g_free (territory);
if (mask & COMPONENT_MODIFIER)
g_free (modifier);
}
/**
* g_get_locale_variants:
* @locale: a locale identifier
*
* Returns a list of derived variants of @locale, which can be used to
* e.g. construct locale-dependent filenames or search paths. The returned
* list is sorted from most desirable to least desirable.
* This function handles territory, charset and extra locale modifiers. See
* [`setlocale(3)`](man:setlocale) for information about locales and their format.
*
* @locale itself is guaranteed to be returned in the output.
*
* For example, if @locale is `fr_BE`, then the returned list
* is `fr_BE`, `fr`. If @locale is `en_GB.UTF-8@euro`, then the returned list
* is `en_GB.UTF-8@euro`, `en_GB.UTF-8`, `en_GB@euro`, `en_GB`, `en.UTF-8@euro`,
* `en.UTF-8`, `en@euro`, `en`.
*
* If you need the list of variants for the current locale,
* use g_get_language_names().
*
* Returns: (transfer full) (array zero-terminated=1) (element-type utf8): a newly
* allocated array of newly allocated strings with the locale variants. Free with
* g_strfreev().
*
* Since: 2.28
*/
gchar **
g_get_locale_variants (const gchar *locale)
{
GPtrArray *array;
g_return_val_if_fail (locale != NULL, NULL);
array = g_ptr_array_sized_new (8);
append_locale_variants (array, locale);
g_ptr_array_add (array, NULL);
return (gchar **) g_ptr_array_free (array, FALSE);
}
/* The following is (partly) taken from the gettext package.
Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. */
static const gchar *
guess_category_value (const gchar *category_name)
{
const gchar *retval;
/* The highest priority value is the 'LANGUAGE' environment
variable. This is a GNU extension. */
retval = g_getenv ("LANGUAGE");
if ((retval != NULL) && (retval[0] != '\0'))
return retval;
/* 'LANGUAGE' is not set. So we have to proceed with the POSIX
methods of looking to 'LC_ALL', 'LC_xxx', and 'LANG'. On some
systems this can be done by the 'setlocale' function itself. */
/* Setting of LC_ALL overwrites all other. */
retval = g_getenv ("LC_ALL");
if ((retval != NULL) && (retval[0] != '\0'))
return retval;
/* Next comes the name of the desired category. */
retval = g_getenv (category_name);
if ((retval != NULL) && (retval[0] != '\0'))
return retval;
/* Last possibility is the LANG environment variable. */
retval = g_getenv ("LANG");
if ((retval != NULL) && (retval[0] != '\0'))
return retval;
#ifdef G_PLATFORM_WIN32
/* g_win32_getlocale() first checks for LC_ALL, LC_MESSAGES and
* LANG, which we already did above. Oh well. The main point of
* calling g_win32_getlocale() is to get the thread's locale as used
* by Windows and the Microsoft C runtime (in the "English_United
* States" format) translated into the Unixish format.
*/
{
char *locale = g_win32_getlocale ();
retval = g_intern_string (locale);
g_free (locale);
return retval;
}
#endif
return NULL;
}
typedef struct _GLanguageNamesCache GLanguageNamesCache;
struct _GLanguageNamesCache {
gchar *languages;
gchar **language_names;
};
static void
language_names_cache_free (gpointer data)
{
GLanguageNamesCache *cache = data;
g_free (cache->languages);
g_strfreev (cache->language_names);
g_free (cache);
}
/**
* g_get_language_names:
*
* Computes a list of applicable locale names, which can be used to
* e.g. construct locale-dependent filenames or search paths. The returned
* list is sorted from most desirable to least desirable and always contains
* the default locale "C".
*
* For example, if LANGUAGE=de:en_US, then the returned list is
* "de", "en_US", "en", "C".
*
* This function consults the environment variables `LANGUAGE`, `LC_ALL`,
* `LC_MESSAGES` and `LANG` to find the list of locales specified by the
* user.
*
* Returns: (array zero-terminated=1) (transfer none): a %NULL-terminated array of strings owned by GLib
* that must not be modified or freed.
*
* Since: 2.6
*/
const gchar * const *
g_get_language_names (void)
{
return g_get_language_names_with_category ("LC_MESSAGES");
}
/**
* g_get_language_names_with_category:
* @category_name: a locale category name
*
* Computes a list of applicable locale names with a locale category name,
* which can be used to construct the fallback locale-dependent filenames
* or search paths. The returned list is sorted from most desirable to
* least desirable and always contains the default locale "C".
*
* This function consults the environment variables `LANGUAGE`, `LC_ALL`,
* @category_name, and `LANG` to find the list of locales specified by the
* user.
*
* g_get_language_names() returns g_get_language_names_with_category("LC_MESSAGES").
*
* Returns: (array zero-terminated=1) (transfer none): a %NULL-terminated array of strings owned by
* the thread g_get_language_names_with_category was called from.
* It must not be modified or freed. It must be copied if planned to be used in another thread.
*
* Since: 2.58
*/
const gchar * const *
g_get_language_names_with_category (const gchar *category_name)
{
static GPrivate cache_private = G_PRIVATE_INIT ((void (*)(gpointer)) g_hash_table_unref);
GHashTable *cache = g_private_get (&cache_private);
const gchar *languages;
GLanguageNamesCache *name_cache;
g_return_val_if_fail (category_name != NULL, NULL);
if (!cache)
{
cache = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, language_names_cache_free);
g_private_set (&cache_private, cache);
}
languages = guess_category_value (category_name);
if (!languages)
languages = "C";
name_cache = (GLanguageNamesCache *) g_hash_table_lookup (cache, category_name);
if (!(name_cache && name_cache->languages &&
strcmp (name_cache->languages, languages) == 0))
{
GPtrArray *array;
gchar **alist, **a;
g_hash_table_remove (cache, category_name);
array = g_ptr_array_sized_new (8);
alist = g_strsplit (languages, ":", 0);
for (a = alist; *a; a++)
append_locale_variants (array, unalias_lang (*a));
g_strfreev (alist);
g_ptr_array_add (array, g_strdup ("C"));
g_ptr_array_add (array, NULL);
name_cache = g_new0 (GLanguageNamesCache, 1);
name_cache->languages = g_strdup (languages);
name_cache->language_names = (gchar **) g_ptr_array_free (array, FALSE);
g_hash_table_insert (cache, g_strdup (category_name), name_cache);
}
return (const gchar * const *) name_cache->language_names;
}

47
glib/gcharset.h Normal file
View file

@ -0,0 +1,47 @@
/* gcharset.h - Charset functions
*
* Copyright (C) 2011 Red Hat, Inc.
*
* 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/>.
*/
#ifndef __G_CHARSET_H__
#define __G_CHARSET_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtypes.h>
G_BEGIN_DECLS
GLIB_AVAILABLE_IN_ALL
gboolean g_get_charset (const char **charset);
GLIB_AVAILABLE_IN_ALL
gchar * g_get_codeset (void);
GLIB_AVAILABLE_IN_2_62
gboolean g_get_console_charset (const char **charset);
GLIB_AVAILABLE_IN_ALL
const gchar * const * g_get_language_names (void);
GLIB_AVAILABLE_IN_2_58
const gchar * const * g_get_language_names_with_category
(const gchar *category_name);
GLIB_AVAILABLE_IN_ALL
gchar ** g_get_locale_variants (const gchar *locale);
G_END_DECLS
#endif /* __G_CHARSET_H__ */

34
glib/gcharsetprivate.h Normal file
View file

@ -0,0 +1,34 @@
/* gunicodeprivate.h
*
* Copyright (C) 2012 Red Hat, Inc.
*
* 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/>.
*/
#ifndef __G_CHARSET_PRIVATE_H__
#define __G_CHARSET_PRIVATE_H__
#include "gcharset.h"
G_BEGIN_DECLS
const char ** _g_charset_get_aliases (const char *canonical_name);
gboolean _g_get_time_charset (const char **charset);
gboolean _g_get_ctype_charset (const char **charset);
G_END_DECLS
#endif

1864
glib/gchecksum.c Normal file

File diff suppressed because it is too large Load diff

104
glib/gchecksum.h Normal file
View file

@ -0,0 +1,104 @@
/* gchecksum.h - data hashing functions
*
* Copyright (C) 2007 Emmanuele Bassi <ebassi@gnome.org>
*
* 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/>.
*/
#ifndef __G_CHECKSUM_H__
#define __G_CHECKSUM_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtypes.h>
#include <glib/gbytes.h>
G_BEGIN_DECLS
/**
* GChecksumType:
* @G_CHECKSUM_MD5: Use the MD5 hashing algorithm
* @G_CHECKSUM_SHA1: Use the SHA-1 hashing algorithm
* @G_CHECKSUM_SHA256: Use the SHA-256 hashing algorithm
* @G_CHECKSUM_SHA384: Use the SHA-384 hashing algorithm (Since: 2.51)
* @G_CHECKSUM_SHA512: Use the SHA-512 hashing algorithm (Since: 2.36)
*
* The hashing algorithm to be used by #GChecksum when performing the
* digest of some data.
*
* Note that the #GChecksumType enumeration may be extended at a later
* date to include new hashing algorithm types.
*
* Since: 2.16
*/
typedef enum {
G_CHECKSUM_MD5,
G_CHECKSUM_SHA1,
G_CHECKSUM_SHA256,
G_CHECKSUM_SHA512,
G_CHECKSUM_SHA384
} GChecksumType;
/**
* GChecksum:
*
* An opaque structure representing a checksumming operation.
*
* To create a new GChecksum, use g_checksum_new(). To free
* a GChecksum, use g_checksum_free().
*
* Since: 2.16
*/
typedef struct _GChecksum GChecksum;
GLIB_AVAILABLE_IN_ALL
gssize g_checksum_type_get_length (GChecksumType checksum_type);
GLIB_AVAILABLE_IN_ALL
GChecksum * g_checksum_new (GChecksumType checksum_type);
GLIB_AVAILABLE_IN_ALL
void g_checksum_reset (GChecksum *checksum);
GLIB_AVAILABLE_IN_ALL
GChecksum * g_checksum_copy (const GChecksum *checksum);
GLIB_AVAILABLE_IN_ALL
void g_checksum_free (GChecksum *checksum);
GLIB_AVAILABLE_IN_ALL
void g_checksum_update (GChecksum *checksum,
const guchar *data,
gssize length);
GLIB_AVAILABLE_IN_ALL
const gchar * g_checksum_get_string (GChecksum *checksum);
GLIB_AVAILABLE_IN_ALL
void g_checksum_get_digest (GChecksum *checksum,
guint8 *buffer,
gsize *digest_len);
GLIB_AVAILABLE_IN_ALL
gchar *g_compute_checksum_for_data (GChecksumType checksum_type,
const guchar *data,
gsize length);
GLIB_AVAILABLE_IN_ALL
gchar *g_compute_checksum_for_string (GChecksumType checksum_type,
const gchar *str,
gssize length);
GLIB_AVAILABLE_IN_2_34
gchar *g_compute_checksum_for_bytes (GChecksumType checksum_type,
GBytes *data);
G_END_DECLS
#endif /* __G_CHECKSUM_H__ */

159
glib/gconstructor.h Normal file
View file

@ -0,0 +1,159 @@
/* 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.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/.
*/
#ifndef __G_CONSTRUCTOR_H__
#define __G_CONSTRUCTOR_H__
/*
If G_HAS_CONSTRUCTORS is true then the compiler support *both* constructors and
destructors, in a usable way, including e.g. on library unload. If not you're on
your own.
Some compilers need #pragma to handle this, which does not work with macros,
so the way you need to use this is (for constructors):
#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(my_constructor)
#endif
G_DEFINE_CONSTRUCTOR(my_constructor)
static void my_constructor(void) {
...
}
*/
#ifndef __GTK_DOC_IGNORE__
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
#define G_HAS_CONSTRUCTORS 1
#define G_DEFINE_CONSTRUCTOR(_func) static void __attribute__((constructor)) _func (void);
#define G_DEFINE_DESTRUCTOR(_func) static void __attribute__((destructor)) _func (void);
#elif defined (_MSC_VER) && (_MSC_VER >= 1500)
/* Visual studio 2008 and later has _Pragma */
/*
* Only try to include gslist.h if not already included via glib.h,
* so that items using gconstructor.h outside of GLib (such as
* GResources) continue to build properly.
*/
#ifndef __G_LIB_H__
#include "gslist.h"
#endif
#include <stdlib.h>
#define G_HAS_CONSTRUCTORS 1
/* We do some weird things to avoid the constructors being optimized
* away on VS2015 if WholeProgramOptimization is enabled. First we
* make a reference to the array from the wrapper to make sure its
* references. Then we use a pragma to make sure the wrapper function
* symbol is always included at the link stage. Also, the symbols
* need to be extern (but not dllexport), even though they are not
* really used from another object file.
*/
/* We need to account for differences between the mangling of symbols
* for x86 and x64/ARM/ARM64 programs, as symbols on x86 are prefixed
* with an underscore but symbols on x64/ARM/ARM64 are not.
*/
#ifdef _M_IX86
#define G_MSVC_SYMBOL_PREFIX "_"
#else
#define G_MSVC_SYMBOL_PREFIX ""
#endif
#define G_DEFINE_CONSTRUCTOR(_func) G_MSVC_CTOR (_func, G_MSVC_SYMBOL_PREFIX)
#define G_DEFINE_DESTRUCTOR(_func) G_MSVC_DTOR (_func, G_MSVC_SYMBOL_PREFIX)
#define G_MSVC_CTOR(_func,_sym_prefix) \
static void _func(void); \
extern int (* _array ## _func)(void); \
int _func ## _wrapper(void) { _func(); g_slist_find (NULL, _array ## _func); return 0; } \
__pragma(comment(linker,"/include:" _sym_prefix # _func "_wrapper")) \
__pragma(section(".CRT$XCU",read)) \
__declspec(allocate(".CRT$XCU")) int (* _array ## _func)(void) = _func ## _wrapper;
#define G_MSVC_DTOR(_func,_sym_prefix) \
static void _func(void); \
extern int (* _array ## _func)(void); \
int _func ## _constructor(void) { atexit (_func); g_slist_find (NULL, _array ## _func); return 0; } \
__pragma(comment(linker,"/include:" _sym_prefix # _func "_constructor")) \
__pragma(section(".CRT$XCU",read)) \
__declspec(allocate(".CRT$XCU")) int (* _array ## _func)(void) = _func ## _constructor;
#elif defined (_MSC_VER)
#define G_HAS_CONSTRUCTORS 1
/* Pre Visual studio 2008 must use #pragma section */
#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1
#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1
#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \
section(".CRT$XCU",read)
#define G_DEFINE_CONSTRUCTOR(_func) \
static void _func(void); \
static int _func ## _wrapper(void) { _func(); return 0; } \
__declspec(allocate(".CRT$XCU")) static int (*p)(void) = _func ## _wrapper;
#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \
section(".CRT$XCU",read)
#define G_DEFINE_DESTRUCTOR(_func) \
static void _func(void); \
static int _func ## _constructor(void) { atexit (_func); return 0; } \
__declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor;
#elif defined(__SUNPRO_C)
/* This is not tested, but i believe it should work, based on:
* http://opensource.apple.com/source/OpenSSL098/OpenSSL098-35/src/fips/fips_premain.c
*/
#define G_HAS_CONSTRUCTORS 1
#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1
#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1
#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \
init(_func)
#define G_DEFINE_CONSTRUCTOR(_func) \
static void _func(void);
#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \
fini(_func)
#define G_DEFINE_DESTRUCTOR(_func) \
static void _func(void);
#else
/* constructors not supported for this compiler */
#endif
#endif /* __GTK_DOC_IGNORE__ */
#endif /* __G_CONSTRUCTOR_H__ */

2066
glib/gconvert.c Normal file

File diff suppressed because it is too large Load diff

177
glib/gconvert.h Normal file
View file

@ -0,0 +1,177 @@
/* 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.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/.
*/
#ifndef __G_CONVERT_H__
#define __G_CONVERT_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gerror.h>
G_BEGIN_DECLS
/**
* GConvertError:
* @G_CONVERT_ERROR_NO_CONVERSION: Conversion between the requested character
* sets is not supported.
* @G_CONVERT_ERROR_ILLEGAL_SEQUENCE: Invalid byte sequence in conversion input;
* or the character sequence could not be represented in the target
* character set.
* @G_CONVERT_ERROR_FAILED: Conversion failed for some reason.
* @G_CONVERT_ERROR_PARTIAL_INPUT: Partial character sequence at end of input.
* @G_CONVERT_ERROR_BAD_URI: URI is invalid.
* @G_CONVERT_ERROR_NOT_ABSOLUTE_PATH: Pathname is not an absolute path.
* @G_CONVERT_ERROR_NO_MEMORY: No memory available. Since: 2.40
* @G_CONVERT_ERROR_EMBEDDED_NUL: An embedded NUL character is present in
* conversion output where a NUL-terminated string is expected.
* Since: 2.56
*
* Error codes returned by character set conversion routines.
*/
typedef enum
{
G_CONVERT_ERROR_NO_CONVERSION,
G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
G_CONVERT_ERROR_FAILED,
G_CONVERT_ERROR_PARTIAL_INPUT,
G_CONVERT_ERROR_BAD_URI,
G_CONVERT_ERROR_NOT_ABSOLUTE_PATH,
G_CONVERT_ERROR_NO_MEMORY,
G_CONVERT_ERROR_EMBEDDED_NUL
} GConvertError;
/**
* G_CONVERT_ERROR:
*
* Error domain for character set conversions. Errors in this domain will
* be from the #GConvertError enumeration. See #GError for information on
* error domains.
*/
#define G_CONVERT_ERROR g_convert_error_quark()
GLIB_AVAILABLE_IN_ALL
GQuark g_convert_error_quark (void);
/**
* GIConv: (skip)
*
* The GIConv struct wraps an iconv() conversion descriptor. It contains
* private data and should only be accessed using the following functions.
*/
typedef struct _GIConv *GIConv;
GLIB_AVAILABLE_IN_ALL
GIConv g_iconv_open (const gchar *to_codeset,
const gchar *from_codeset);
GLIB_AVAILABLE_IN_ALL
gsize g_iconv (GIConv converter,
gchar **inbuf,
gsize *inbytes_left,
gchar **outbuf,
gsize *outbytes_left);
GLIB_AVAILABLE_IN_ALL
gint g_iconv_close (GIConv converter);
GLIB_AVAILABLE_IN_ALL
gchar* g_convert (const gchar *str,
gssize len,
const gchar *to_codeset,
const gchar *from_codeset,
gsize *bytes_read,
gsize *bytes_written,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
gchar* g_convert_with_iconv (const gchar *str,
gssize len,
GIConv converter,
gsize *bytes_read,
gsize *bytes_written,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
gchar* g_convert_with_fallback (const gchar *str,
gssize len,
const gchar *to_codeset,
const gchar *from_codeset,
const gchar *fallback,
gsize *bytes_read,
gsize *bytes_written,
GError **error) G_GNUC_MALLOC;
/* Convert between libc's idea of strings and UTF-8.
*/
GLIB_AVAILABLE_IN_ALL
gchar* g_locale_to_utf8 (const gchar *opsysstring,
gssize len,
gsize *bytes_read,
gsize *bytes_written,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
gchar* g_locale_from_utf8 (const gchar *utf8string,
gssize len,
gsize *bytes_read,
gsize *bytes_written,
GError **error) G_GNUC_MALLOC;
/* Convert between the operating system (or C runtime)
* representation of file names and UTF-8.
*/
GLIB_AVAILABLE_IN_ALL
gchar* g_filename_to_utf8 (const gchar *opsysstring,
gssize len,
gsize *bytes_read,
gsize *bytes_written,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
gchar* g_filename_from_utf8 (const gchar *utf8string,
gssize len,
gsize *bytes_read,
gsize *bytes_written,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
gchar *g_filename_from_uri (const gchar *uri,
gchar **hostname,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
gchar *g_filename_to_uri (const gchar *filename,
const gchar *hostname,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
gchar *g_filename_display_name (const gchar *filename) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
gboolean g_get_filename_charsets (const gchar ***filename_charsets);
GLIB_AVAILABLE_IN_ALL
gchar *g_filename_display_basename (const gchar *filename) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
gchar **g_uri_list_extract_uris (const gchar *uri_list);
G_END_DECLS
#endif /* __G_CONVERT_H__ */

40
glib/gconvertprivate.h Normal file
View file

@ -0,0 +1,40 @@
/* gconvertprivate.h - Private GLib gconvert functions
*
* Copyright 2020 Frederic Martinsons
*
* 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/>.
*/
#ifndef __G_CONVERTPRIVATE_H__
#define __G_CONVERTPRIVATE_H__
G_BEGIN_DECLS
#include "glib.h"
gchar *_g_time_locale_to_utf8 (const gchar *opsysstring,
gssize len,
gsize *bytes_read,
gsize *bytes_written,
GError **error) G_GNUC_MALLOC;
gchar *_g_ctype_locale_to_utf8 (const gchar *opsysstring,
gssize len,
gsize *bytes_read,
gsize *bytes_written,
GError **error) G_GNUC_MALLOC;
G_END_DECLS
#endif /* __G_CONVERTPRIVATE_H__ */

1251
glib/gdataset.c Normal file

File diff suppressed because it is too large Load diff

150
glib/gdataset.h Normal file
View file

@ -0,0 +1,150 @@
/* 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.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/.
*/
#ifndef __G_DATASET_H__
#define __G_DATASET_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gquark.h>
G_BEGIN_DECLS
typedef struct _GData GData;
typedef void (*GDataForeachFunc) (GQuark key_id,
gpointer data,
gpointer user_data);
/* Keyed Data List
*/
GLIB_AVAILABLE_IN_ALL
void g_datalist_init (GData **datalist);
GLIB_AVAILABLE_IN_ALL
void g_datalist_clear (GData **datalist);
GLIB_AVAILABLE_IN_ALL
gpointer g_datalist_id_get_data (GData **datalist,
GQuark key_id);
GLIB_AVAILABLE_IN_ALL
void g_datalist_id_set_data_full (GData **datalist,
GQuark key_id,
gpointer data,
GDestroyNotify destroy_func);
typedef gpointer (*GDuplicateFunc) (gpointer data, gpointer user_data);
GLIB_AVAILABLE_IN_2_34
gpointer g_datalist_id_dup_data (GData **datalist,
GQuark key_id,
GDuplicateFunc dup_func,
gpointer user_data);
GLIB_AVAILABLE_IN_2_34
gboolean g_datalist_id_replace_data (GData **datalist,
GQuark key_id,
gpointer oldval,
gpointer newval,
GDestroyNotify destroy,
GDestroyNotify *old_destroy);
GLIB_AVAILABLE_IN_ALL
gpointer g_datalist_id_remove_no_notify (GData **datalist,
GQuark key_id);
GLIB_AVAILABLE_IN_ALL
void g_datalist_foreach (GData **datalist,
GDataForeachFunc func,
gpointer user_data);
/**
* G_DATALIST_FLAGS_MASK:
*
* A bitmask that restricts the possible flags passed to
* g_datalist_set_flags(). Passing a flags value where
* flags & ~G_DATALIST_FLAGS_MASK != 0 is an error.
*/
#define G_DATALIST_FLAGS_MASK 0x3
GLIB_AVAILABLE_IN_ALL
void g_datalist_set_flags (GData **datalist,
guint flags);
GLIB_AVAILABLE_IN_ALL
void g_datalist_unset_flags (GData **datalist,
guint flags);
GLIB_AVAILABLE_IN_ALL
guint g_datalist_get_flags (GData **datalist);
#define g_datalist_id_set_data(dl, q, d) \
g_datalist_id_set_data_full ((dl), (q), (d), NULL)
#define g_datalist_id_remove_data(dl, q) \
g_datalist_id_set_data ((dl), (q), NULL)
#define g_datalist_set_data_full(dl, k, d, f) \
g_datalist_id_set_data_full ((dl), g_quark_from_string (k), (d), (f))
#define g_datalist_remove_no_notify(dl, k) \
g_datalist_id_remove_no_notify ((dl), g_quark_try_string (k))
#define g_datalist_set_data(dl, k, d) \
g_datalist_set_data_full ((dl), (k), (d), NULL)
#define g_datalist_remove_data(dl, k) \
g_datalist_id_set_data ((dl), g_quark_try_string (k), NULL)
/* Location Associated Keyed Data
*/
GLIB_AVAILABLE_IN_ALL
void g_dataset_destroy (gconstpointer dataset_location);
GLIB_AVAILABLE_IN_ALL
gpointer g_dataset_id_get_data (gconstpointer dataset_location,
GQuark key_id);
GLIB_AVAILABLE_IN_ALL
gpointer g_datalist_get_data (GData **datalist,
const gchar *key);
GLIB_AVAILABLE_IN_ALL
void g_dataset_id_set_data_full (gconstpointer dataset_location,
GQuark key_id,
gpointer data,
GDestroyNotify destroy_func);
GLIB_AVAILABLE_IN_ALL
gpointer g_dataset_id_remove_no_notify (gconstpointer dataset_location,
GQuark key_id);
GLIB_AVAILABLE_IN_ALL
void g_dataset_foreach (gconstpointer dataset_location,
GDataForeachFunc func,
gpointer user_data);
#define g_dataset_id_set_data(l, k, d) \
g_dataset_id_set_data_full ((l), (k), (d), NULL)
#define g_dataset_id_remove_data(l, k) \
g_dataset_id_set_data ((l), (k), NULL)
#define g_dataset_get_data(l, k) \
(g_dataset_id_get_data ((l), g_quark_try_string (k)))
#define g_dataset_set_data_full(l, k, d, f) \
g_dataset_id_set_data_full ((l), g_quark_from_string (k), (d), (f))
#define g_dataset_remove_no_notify(l, k) \
g_dataset_id_remove_no_notify ((l), g_quark_try_string (k))
#define g_dataset_set_data(l, k, d) \
g_dataset_set_data_full ((l), (k), (d), NULL)
#define g_dataset_remove_data(l, k) \
g_dataset_id_set_data ((l), g_quark_try_string (k), NULL)
G_END_DECLS
#endif /* __G_DATASET_H__ */

42
glib/gdatasetprivate.h Normal file
View file

@ -0,0 +1,42 @@
/* GLIB - Library of useful routines for C programming
* gdataset-private.h: Internal macros for accessing dataset values
* Copyright (C) 2005 Red Hat
*
* 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/.
*/
#ifndef __G_DATASETPRIVATE_H__
#define __G_DATASETPRIVATE_H__
#include <gatomic.h>
G_BEGIN_DECLS
/* GET_FLAGS is implemented via atomic pointer access, to allow memory
* barriers to take effect without acquiring the global dataset mutex.
*/
#define G_DATALIST_GET_FLAGS(datalist) \
((gsize) g_atomic_pointer_get (datalist) & G_DATALIST_FLAGS_MASK)
G_END_DECLS
#endif /* __G_DATASETPRIVATE_H__ */

2755
glib/gdate.c Normal file

File diff suppressed because it is too large Load diff

307
glib/gdate.h Normal file
View file

@ -0,0 +1,307 @@
/* 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.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/.
*/
#ifndef __G_DATE_H__
#define __G_DATE_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <time.h>
#include <glib/gtypes.h>
#include <glib/gquark.h>
G_BEGIN_DECLS
/* GDate
*
* Date calculations (not time for now, to be resolved). These are a
* mutant combination of Steffen Beyer's DateCalc routines
* (http://www.perl.com/CPAN/authors/id/STBEY/) and Jon Trowbridge's
* date routines (written for in-house software). Written by Havoc
* Pennington <hp@pobox.com>
*/
typedef gint32 GTime GLIB_DEPRECATED_TYPE_IN_2_62_FOR(GDateTime);
typedef guint16 GDateYear;
typedef guint8 GDateDay; /* day of the month */
typedef struct _GDate GDate;
/* enum used to specify order of appearance in parsed date strings */
typedef enum
{
G_DATE_DAY = 0,
G_DATE_MONTH = 1,
G_DATE_YEAR = 2
} GDateDMY;
/* actual week and month values */
typedef enum
{
G_DATE_BAD_WEEKDAY = 0,
G_DATE_MONDAY = 1,
G_DATE_TUESDAY = 2,
G_DATE_WEDNESDAY = 3,
G_DATE_THURSDAY = 4,
G_DATE_FRIDAY = 5,
G_DATE_SATURDAY = 6,
G_DATE_SUNDAY = 7
} GDateWeekday;
typedef enum
{
G_DATE_BAD_MONTH = 0,
G_DATE_JANUARY = 1,
G_DATE_FEBRUARY = 2,
G_DATE_MARCH = 3,
G_DATE_APRIL = 4,
G_DATE_MAY = 5,
G_DATE_JUNE = 6,
G_DATE_JULY = 7,
G_DATE_AUGUST = 8,
G_DATE_SEPTEMBER = 9,
G_DATE_OCTOBER = 10,
G_DATE_NOVEMBER = 11,
G_DATE_DECEMBER = 12
} GDateMonth;
#define G_DATE_BAD_JULIAN 0U
#define G_DATE_BAD_DAY 0U
#define G_DATE_BAD_YEAR 0U
/* Note: directly manipulating structs is generally a bad idea, but
* in this case it's an *incredibly* bad idea, because all or part
* of this struct can be invalid at any given time. Use the functions,
* or you will get hosed, I promise.
*/
struct _GDate
{
guint julian_days : 32; /* julian days representation - we use a
* bitfield hoping that 64 bit platforms
* will pack this whole struct in one big
* int
*/
guint julian : 1; /* julian is valid */
guint dmy : 1; /* dmy is valid */
/* DMY representation */
guint day : 6;
guint month : 4;
guint year : 16;
};
/* g_date_new() returns an invalid date, you then have to _set() stuff
* to get a usable object. You can also allocate a GDate statically,
* then call g_date_clear() to initialize.
*/
GLIB_AVAILABLE_IN_ALL
GDate* g_date_new (void);
GLIB_AVAILABLE_IN_ALL
GDate* g_date_new_dmy (GDateDay day,
GDateMonth month,
GDateYear year);
GLIB_AVAILABLE_IN_ALL
GDate* g_date_new_julian (guint32 julian_day);
GLIB_AVAILABLE_IN_ALL
void g_date_free (GDate *date);
GLIB_AVAILABLE_IN_2_56
GDate* g_date_copy (const GDate *date);
/* check g_date_valid() after doing an operation that might fail, like
* _parse. Almost all g_date operations are undefined on invalid
* dates (the exceptions are the mutators, since you need those to
* return to validity).
*/
GLIB_AVAILABLE_IN_ALL
gboolean g_date_valid (const GDate *date);
GLIB_AVAILABLE_IN_ALL
gboolean g_date_valid_day (GDateDay day) G_GNUC_CONST;
GLIB_AVAILABLE_IN_ALL
gboolean g_date_valid_month (GDateMonth month) G_GNUC_CONST;
GLIB_AVAILABLE_IN_ALL
gboolean g_date_valid_year (GDateYear year) G_GNUC_CONST;
GLIB_AVAILABLE_IN_ALL
gboolean g_date_valid_weekday (GDateWeekday weekday) G_GNUC_CONST;
GLIB_AVAILABLE_IN_ALL
gboolean g_date_valid_julian (guint32 julian_date) G_GNUC_CONST;
GLIB_AVAILABLE_IN_ALL
gboolean g_date_valid_dmy (GDateDay day,
GDateMonth month,
GDateYear year) G_GNUC_CONST;
GLIB_AVAILABLE_IN_ALL
GDateWeekday g_date_get_weekday (const GDate *date);
GLIB_AVAILABLE_IN_ALL
GDateMonth g_date_get_month (const GDate *date);
GLIB_AVAILABLE_IN_ALL
GDateYear g_date_get_year (const GDate *date);
GLIB_AVAILABLE_IN_ALL
GDateDay g_date_get_day (const GDate *date);
GLIB_AVAILABLE_IN_ALL
guint32 g_date_get_julian (const GDate *date);
GLIB_AVAILABLE_IN_ALL
guint g_date_get_day_of_year (const GDate *date);
/* First monday/sunday is the start of week 1; if we haven't reached
* that day, return 0. These are not ISO weeks of the year; that
* routine needs to be added.
* these functions return the number of weeks, starting on the
* corrsponding day
*/
GLIB_AVAILABLE_IN_ALL
guint g_date_get_monday_week_of_year (const GDate *date);
GLIB_AVAILABLE_IN_ALL
guint g_date_get_sunday_week_of_year (const GDate *date);
GLIB_AVAILABLE_IN_ALL
guint g_date_get_iso8601_week_of_year (const GDate *date);
/* If you create a static date struct you need to clear it to get it
* in a safe state before use. You can clear a whole array at
* once with the ndates argument.
*/
GLIB_AVAILABLE_IN_ALL
void g_date_clear (GDate *date,
guint n_dates);
/* The parse routine is meant for dates typed in by a user, so it
* permits many formats but tries to catch common typos. If your data
* needs to be strictly validated, it is not an appropriate function.
*/
GLIB_AVAILABLE_IN_ALL
void g_date_set_parse (GDate *date,
const gchar *str);
GLIB_AVAILABLE_IN_ALL
void g_date_set_time_t (GDate *date,
time_t timet);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
GLIB_DEPRECATED_IN_2_62_FOR(g_date_set_time_t)
void g_date_set_time_val (GDate *date,
GTimeVal *timeval);
GLIB_DEPRECATED_FOR(g_date_set_time_t)
void g_date_set_time (GDate *date,
GTime time_);
G_GNUC_END_IGNORE_DEPRECATIONS
GLIB_AVAILABLE_IN_ALL
void g_date_set_month (GDate *date,
GDateMonth month);
GLIB_AVAILABLE_IN_ALL
void g_date_set_day (GDate *date,
GDateDay day);
GLIB_AVAILABLE_IN_ALL
void g_date_set_year (GDate *date,
GDateYear year);
GLIB_AVAILABLE_IN_ALL
void g_date_set_dmy (GDate *date,
GDateDay day,
GDateMonth month,
GDateYear y);
GLIB_AVAILABLE_IN_ALL
void g_date_set_julian (GDate *date,
guint32 julian_date);
GLIB_AVAILABLE_IN_ALL
gboolean g_date_is_first_of_month (const GDate *date);
GLIB_AVAILABLE_IN_ALL
gboolean g_date_is_last_of_month (const GDate *date);
/* To go forward by some number of weeks just go forward weeks*7 days */
GLIB_AVAILABLE_IN_ALL
void g_date_add_days (GDate *date,
guint n_days);
GLIB_AVAILABLE_IN_ALL
void g_date_subtract_days (GDate *date,
guint n_days);
/* If you add/sub months while day > 28, the day might change */
GLIB_AVAILABLE_IN_ALL
void g_date_add_months (GDate *date,
guint n_months);
GLIB_AVAILABLE_IN_ALL
void g_date_subtract_months (GDate *date,
guint n_months);
/* If it's feb 29, changing years can move you to the 28th */
GLIB_AVAILABLE_IN_ALL
void g_date_add_years (GDate *date,
guint n_years);
GLIB_AVAILABLE_IN_ALL
void g_date_subtract_years (GDate *date,
guint n_years);
GLIB_AVAILABLE_IN_ALL
gboolean g_date_is_leap_year (GDateYear year) G_GNUC_CONST;
GLIB_AVAILABLE_IN_ALL
guint8 g_date_get_days_in_month (GDateMonth month,
GDateYear year) G_GNUC_CONST;
GLIB_AVAILABLE_IN_ALL
guint8 g_date_get_monday_weeks_in_year (GDateYear year) G_GNUC_CONST;
GLIB_AVAILABLE_IN_ALL
guint8 g_date_get_sunday_weeks_in_year (GDateYear year) G_GNUC_CONST;
/* Returns the number of days between the two dates. If date2 comes
before date1, a negative value is return. */
GLIB_AVAILABLE_IN_ALL
gint g_date_days_between (const GDate *date1,
const GDate *date2);
/* qsort-friendly (with a cast...) */
GLIB_AVAILABLE_IN_ALL
gint g_date_compare (const GDate *lhs,
const GDate *rhs);
GLIB_AVAILABLE_IN_ALL
void g_date_to_struct_tm (const GDate *date,
struct tm *tm);
GLIB_AVAILABLE_IN_ALL
void g_date_clamp (GDate *date,
const GDate *min_date,
const GDate *max_date);
/* Swap date1 and date2's values if date1 > date2. */
GLIB_AVAILABLE_IN_ALL
void g_date_order (GDate *date1, GDate *date2);
/* Just like strftime() except you can only use date-related formats.
* Using a time format is undefined.
*/
GLIB_AVAILABLE_IN_ALL
gsize g_date_strftime (gchar *s,
gsize slen,
const gchar *format,
const GDate *date);
#define g_date_weekday g_date_get_weekday GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_date_get_weekday)
#define g_date_month g_date_get_month GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_date_get_month)
#define g_date_year g_date_get_year GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_date_get_year)
#define g_date_day g_date_get_day GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_date_get_day)
#define g_date_julian g_date_get_julian GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_date_get_julian)
#define g_date_day_of_year g_date_get_day_of_year GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_date_get_day_of_year)
#define g_date_monday_week_of_year g_date_get_monday_week_of_year GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_date_get_monday_week_of_year)
#define g_date_sunday_week_of_year g_date_get_sunday_week_of_year GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_date_get_sunday_week_of_year)
#define g_date_days_in_month g_date_get_days_in_month GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_date_get_days_in_month)
#define g_date_monday_weeks_in_year g_date_get_monday_weeks_in_year GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_date_get_monday_weeks_in_year)
#define g_date_sunday_weeks_in_year g_date_get_sunday_weeks_in_year GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_date_get_sunday_weeks_in_year)
G_END_DECLS
#endif /* __G_DATE_H__ */

3527
glib/gdatetime.c Normal file

File diff suppressed because it is too large Load diff

273
glib/gdatetime.h Normal file
View file

@ -0,0 +1,273 @@
/*
* Copyright (C) 2009-2010 Christian Hergert <chris@dronelabs.com>
* Copyright © 2010 Codethink Limited
*
* 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
* licence, or (at your option) any later version.
*
* This 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/>.
*
* Authors: Christian Hergert <chris@dronelabs.com>
* Thiago Santos <thiago.sousa.santos@collabora.co.uk>
* Emmanuele Bassi <ebassi@linux.intel.com>
* Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __G_DATE_TIME_H__
#define __G_DATE_TIME_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtimezone.h>
G_BEGIN_DECLS
/**
* G_TIME_SPAN_DAY:
*
* Evaluates to a time span of one day.
*
* Since: 2.26
*/
#define G_TIME_SPAN_DAY (G_GINT64_CONSTANT (86400000000))
/**
* G_TIME_SPAN_HOUR:
*
* Evaluates to a time span of one hour.
*
* Since: 2.26
*/
#define G_TIME_SPAN_HOUR (G_GINT64_CONSTANT (3600000000))
/**
* G_TIME_SPAN_MINUTE:
*
* Evaluates to a time span of one minute.
*
* Since: 2.26
*/
#define G_TIME_SPAN_MINUTE (G_GINT64_CONSTANT (60000000))
/**
* G_TIME_SPAN_SECOND:
*
* Evaluates to a time span of one second.
*
* Since: 2.26
*/
#define G_TIME_SPAN_SECOND (G_GINT64_CONSTANT (1000000))
/**
* G_TIME_SPAN_MILLISECOND:
*
* Evaluates to a time span of one millisecond.
*
* Since: 2.26
*/
#define G_TIME_SPAN_MILLISECOND (G_GINT64_CONSTANT (1000))
/**
* GTimeSpan:
*
* A value representing an interval of time, in microseconds.
*
* Since: 2.26
*/
typedef gint64 GTimeSpan;
/**
* GDateTime:
*
* An opaque structure that represents a date and time, including a time zone.
*
* Since: 2.26
*/
typedef struct _GDateTime GDateTime;
GLIB_AVAILABLE_IN_ALL
void g_date_time_unref (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
GDateTime * g_date_time_ref (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
GDateTime * g_date_time_new_now (GTimeZone *tz);
GLIB_AVAILABLE_IN_ALL
GDateTime * g_date_time_new_now_local (void);
GLIB_AVAILABLE_IN_ALL
GDateTime * g_date_time_new_now_utc (void);
GLIB_AVAILABLE_IN_ALL
GDateTime * g_date_time_new_from_unix_local (gint64 t);
GLIB_AVAILABLE_IN_ALL
GDateTime * g_date_time_new_from_unix_utc (gint64 t);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
GLIB_DEPRECATED_IN_2_62_FOR(g_date_time_new_from_unix_local)
GDateTime * g_date_time_new_from_timeval_local (const GTimeVal *tv);
GLIB_DEPRECATED_IN_2_62_FOR(g_date_time_new_from_unix_utc)
GDateTime * g_date_time_new_from_timeval_utc (const GTimeVal *tv);
G_GNUC_END_IGNORE_DEPRECATIONS
GLIB_AVAILABLE_IN_2_56
GDateTime * g_date_time_new_from_iso8601 (const gchar *text,
GTimeZone *default_tz);
GLIB_AVAILABLE_IN_ALL
GDateTime * g_date_time_new (GTimeZone *tz,
gint year,
gint month,
gint day,
gint hour,
gint minute,
gdouble seconds);
GLIB_AVAILABLE_IN_ALL
GDateTime * g_date_time_new_local (gint year,
gint month,
gint day,
gint hour,
gint minute,
gdouble seconds);
GLIB_AVAILABLE_IN_ALL
GDateTime * g_date_time_new_utc (gint year,
gint month,
gint day,
gint hour,
gint minute,
gdouble seconds);
GLIB_AVAILABLE_IN_ALL
G_GNUC_WARN_UNUSED_RESULT
GDateTime * g_date_time_add (GDateTime *datetime,
GTimeSpan timespan);
GLIB_AVAILABLE_IN_ALL
G_GNUC_WARN_UNUSED_RESULT
GDateTime * g_date_time_add_years (GDateTime *datetime,
gint years);
GLIB_AVAILABLE_IN_ALL
G_GNUC_WARN_UNUSED_RESULT
GDateTime * g_date_time_add_months (GDateTime *datetime,
gint months);
GLIB_AVAILABLE_IN_ALL
G_GNUC_WARN_UNUSED_RESULT
GDateTime * g_date_time_add_weeks (GDateTime *datetime,
gint weeks);
GLIB_AVAILABLE_IN_ALL
G_GNUC_WARN_UNUSED_RESULT
GDateTime * g_date_time_add_days (GDateTime *datetime,
gint days);
GLIB_AVAILABLE_IN_ALL
G_GNUC_WARN_UNUSED_RESULT
GDateTime * g_date_time_add_hours (GDateTime *datetime,
gint hours);
GLIB_AVAILABLE_IN_ALL
G_GNUC_WARN_UNUSED_RESULT
GDateTime * g_date_time_add_minutes (GDateTime *datetime,
gint minutes);
GLIB_AVAILABLE_IN_ALL
G_GNUC_WARN_UNUSED_RESULT
GDateTime * g_date_time_add_seconds (GDateTime *datetime,
gdouble seconds);
GLIB_AVAILABLE_IN_ALL
G_GNUC_WARN_UNUSED_RESULT
GDateTime * g_date_time_add_full (GDateTime *datetime,
gint years,
gint months,
gint days,
gint hours,
gint minutes,
gdouble seconds);
GLIB_AVAILABLE_IN_ALL
gint g_date_time_compare (gconstpointer dt1,
gconstpointer dt2);
GLIB_AVAILABLE_IN_ALL
GTimeSpan g_date_time_difference (GDateTime *end,
GDateTime *begin);
GLIB_AVAILABLE_IN_ALL
guint g_date_time_hash (gconstpointer datetime);
GLIB_AVAILABLE_IN_ALL
gboolean g_date_time_equal (gconstpointer dt1,
gconstpointer dt2);
GLIB_AVAILABLE_IN_ALL
void g_date_time_get_ymd (GDateTime *datetime,
gint *year,
gint *month,
gint *day);
GLIB_AVAILABLE_IN_ALL
gint g_date_time_get_year (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
gint g_date_time_get_month (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
gint g_date_time_get_day_of_month (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
gint g_date_time_get_week_numbering_year (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
gint g_date_time_get_week_of_year (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
gint g_date_time_get_day_of_week (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
gint g_date_time_get_day_of_year (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
gint g_date_time_get_hour (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
gint g_date_time_get_minute (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
gint g_date_time_get_second (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
gint g_date_time_get_microsecond (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
gdouble g_date_time_get_seconds (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
gint64 g_date_time_to_unix (GDateTime *datetime);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
GLIB_DEPRECATED_IN_2_62_FOR(g_date_time_to_unix)
gboolean g_date_time_to_timeval (GDateTime *datetime,
GTimeVal *tv);
G_GNUC_END_IGNORE_DEPRECATIONS
GLIB_AVAILABLE_IN_ALL
GTimeSpan g_date_time_get_utc_offset (GDateTime *datetime);
GLIB_AVAILABLE_IN_2_58
GTimeZone * g_date_time_get_timezone (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
const gchar * g_date_time_get_timezone_abbreviation (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
gboolean g_date_time_is_daylight_savings (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
GDateTime * g_date_time_to_timezone (GDateTime *datetime,
GTimeZone *tz);
GLIB_AVAILABLE_IN_ALL
GDateTime * g_date_time_to_local (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
GDateTime * g_date_time_to_utc (GDateTime *datetime);
GLIB_AVAILABLE_IN_ALL
gchar * g_date_time_format (GDateTime *datetime,
const gchar *format) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_2_62
gchar * g_date_time_format_iso8601 (GDateTime *datetime) G_GNUC_MALLOC;
G_END_DECLS
#endif /* __G_DATE_TIME_H__ */

330
glib/gdir.c Normal file
View file

@ -0,0 +1,330 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* gdir.c: Simplified wrapper around the DIRENT functions.
*
* Copyright 2001 Hans Breuer
* Copyright 2004 Tor Lillqvist
*
* 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/>.
*/
#include "config.h"
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>
#ifdef HAVE_DIRENT_H
#include <sys/types.h>
#include <dirent.h>
#endif
#include "gdir.h"
#include "gconvert.h"
#include "gfileutils.h"
#include "gstrfuncs.h"
#include "gtestutils.h"
#include "glibintl.h"
#if defined (_MSC_VER) && !defined (HAVE_DIRENT_H)
#include "dirent/dirent.h"
#endif
#include "glib-private.h" /* g_dir_open_with_errno, g_dir_new_from_dirp */
/**
* GDir:
*
* An opaque structure representing an opened directory.
*/
struct _GDir
{
#ifdef G_OS_WIN32
_WDIR *wdirp;
#else
DIR *dirp;
#endif
#ifdef G_OS_WIN32
/* maximum encoding of FILENAME_MAX UTF-8 characters, plus a nul terminator
* (FILENAME_MAX is not guaranteed to include one) */
gchar utf8_buf[FILENAME_MAX*4 + 1];
#endif
};
/*< private >
* g_dir_open_with_errno:
* @path: the path to the directory you are interested in.
* @flags: Currently must be set to 0. Reserved for future use.
*
* Opens a directory for reading.
*
* This function is equivalent to g_dir_open() except in the error case,
* errno will be set accordingly.
*
* This is useful if you want to construct your own error message.
*
* Returns: a newly allocated #GDir on success, or %NULL on failure,
* with errno set accordingly.
*
* Since: 2.38
*/
GDir *
g_dir_open_with_errno (const gchar *path,
guint flags)
{
GDir dir;
#ifdef G_OS_WIN32
gint saved_errno;
wchar_t *wpath;
#endif
g_return_val_if_fail (path != NULL, NULL);
#ifdef G_OS_WIN32
wpath = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
g_return_val_if_fail (wpath != NULL, NULL);
dir.wdirp = _wopendir (wpath);
saved_errno = errno;
g_free (wpath);
errno = saved_errno;
if (dir.wdirp == NULL)
return NULL;
#else
dir.dirp = opendir (path);
if (dir.dirp == NULL)
return NULL;
#endif
return g_memdup2 (&dir, sizeof dir);
}
/**
* g_dir_open:
* @path: the path to the directory you are interested in. On Unix
* in the on-disk encoding. On Windows in UTF-8
* @flags: Currently must be set to 0. Reserved for future use.
* @error: return location for a #GError, or %NULL.
* If non-%NULL, an error will be set if and only if
* g_dir_open() fails.
*
* Opens a directory for reading. The names of the files in the
* directory can then be retrieved using g_dir_read_name(). Note
* that the ordering is not defined.
*
* Returns: a newly allocated #GDir on success, %NULL on failure.
* If non-%NULL, you must free the result with g_dir_close()
* when you are finished with it.
**/
GDir *
g_dir_open (const gchar *path,
guint flags,
GError **error)
{
gint saved_errno;
GDir *dir;
dir = g_dir_open_with_errno (path, flags);
if (dir == NULL)
{
gchar *utf8_path;
saved_errno = errno;
utf8_path = g_filename_to_utf8 (path, -1, NULL, NULL, NULL);
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno),
_("Error opening directory “%s”: %s"), utf8_path, g_strerror (saved_errno));
g_free (utf8_path);
}
return dir;
}
/*< private >
* g_dir_new_from_dirp:
* @dirp: a #DIR* created by opendir() or fdopendir()
*
* Creates a #GDir object from the DIR object that is created using
* opendir() or fdopendir(). The created #GDir assumes ownership of the
* passed-in #DIR pointer.
*
* @dirp must not be %NULL.
*
* This function never fails.
*
* Returns: a newly allocated #GDir, which should be closed using
* g_dir_close().
*
* Since: 2.38
**/
GDir *
g_dir_new_from_dirp (gpointer dirp)
{
#ifdef G_OS_UNIX
GDir *dir;
g_return_val_if_fail (dirp != NULL, NULL);
dir = g_new (GDir, 1);
dir->dirp = dirp;
return dir;
#else
g_assert_not_reached ();
return NULL;
#endif
}
/**
* g_dir_read_name:
* @dir: a #GDir* created by g_dir_open()
*
* Retrieves the name of another entry in the directory, or %NULL.
* The order of entries returned from this function is not defined,
* and may vary by file system or other operating-system dependent
* factors.
*
* %NULL may also be returned in case of errors. On Unix, you can
* check `errno` to find out if %NULL was returned because of an error.
*
* On Unix, the '.' and '..' entries are omitted, and the returned
* name is in the on-disk encoding.
*
* On Windows, as is true of all GLib functions which operate on
* filenames, the returned name is in UTF-8.
*
* Returns: (type filename): The entry's name or %NULL if there are no
* more entries. The return value is owned by GLib and
* must not be modified or freed.
**/
const gchar *
g_dir_read_name (GDir *dir)
{
#ifdef G_OS_WIN32
gchar *utf8_name;
struct _wdirent *wentry;
#else
struct dirent *entry;
#endif
g_return_val_if_fail (dir != NULL, NULL);
#ifdef G_OS_WIN32
while (1)
{
wentry = _wreaddir (dir->wdirp);
while (wentry
&& (0 == wcscmp (wentry->d_name, L".") ||
0 == wcscmp (wentry->d_name, L"..")))
wentry = _wreaddir (dir->wdirp);
if (wentry == NULL)
return NULL;
utf8_name = g_utf16_to_utf8 (wentry->d_name, -1, NULL, NULL, NULL);
if (utf8_name == NULL)
continue; /* Huh, impossible? Skip it anyway */
strcpy (dir->utf8_buf, utf8_name);
g_free (utf8_name);
return dir->utf8_buf;
}
#else
entry = readdir (dir->dirp);
while (entry
&& (0 == strcmp (entry->d_name, ".") ||
0 == strcmp (entry->d_name, "..")))
entry = readdir (dir->dirp);
if (entry)
return entry->d_name;
else
return NULL;
#endif
}
/**
* g_dir_rewind:
* @dir: a #GDir* created by g_dir_open()
*
* Resets the given directory. The next call to g_dir_read_name()
* will return the first entry again.
**/
void
g_dir_rewind (GDir *dir)
{
g_return_if_fail (dir != NULL);
#ifdef G_OS_WIN32
_wrewinddir (dir->wdirp);
#else
rewinddir (dir->dirp);
#endif
}
/**
* g_dir_close:
* @dir: a #GDir* created by g_dir_open()
*
* Closes the directory and deallocates all related resources.
**/
void
g_dir_close (GDir *dir)
{
g_return_if_fail (dir != NULL);
#ifdef G_OS_WIN32
_wclosedir (dir->wdirp);
#else
closedir (dir->dirp);
#endif
g_free (dir);
}
#ifdef G_OS_WIN32
/* Binary compatibility versions. Not for newly compiled code. */
_GLIB_EXTERN GDir *g_dir_open_utf8 (const gchar *path,
guint flags,
GError **error);
_GLIB_EXTERN const gchar *g_dir_read_name_utf8 (GDir *dir);
GDir *
g_dir_open_utf8 (const gchar *path,
guint flags,
GError **error)
{
return g_dir_open (path, flags, error);
}
const gchar *
g_dir_read_name_utf8 (GDir *dir)
{
return g_dir_read_name (dir);
}
#endif

52
glib/gdir.h Normal file
View file

@ -0,0 +1,52 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* gdir.c: Simplified wrapper around the DIRENT functions.
*
* Copyright 2001 Hans Breuer
*
* 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/>.
*/
#ifndef __G_DIR_H__
#define __G_DIR_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gerror.h>
#ifdef G_OS_UNIX
#include <dirent.h>
#endif
G_BEGIN_DECLS
typedef struct _GDir GDir;
GLIB_AVAILABLE_IN_ALL
GDir * g_dir_open (const gchar *path,
guint flags,
GError **error);
GLIB_AVAILABLE_IN_ALL
const gchar * g_dir_read_name (GDir *dir);
GLIB_AVAILABLE_IN_ALL
void g_dir_rewind (GDir *dir);
GLIB_AVAILABLE_IN_ALL
void g_dir_close (GDir *dir);
G_END_DECLS
#endif /* __G_DIR_H__ */

1552
glib/gen-unicode-tables.pl Executable file

File diff suppressed because it is too large Load diff

701
glib/genviron.c Normal file
View file

@ -0,0 +1,701 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1998 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.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/.
*/
#include "config.h"
#include "genviron.h"
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_CRT_EXTERNS_H
#include <crt_externs.h> /* for _NSGetEnviron */
#endif
#ifdef G_OS_WIN32
#include <windows.h>
#endif
#include "glib-private.h"
#include "gmem.h"
#include "gmessages.h"
#include "gstrfuncs.h"
#include "gunicode.h"
#include "gconvert.h"
#include "gquark.h"
#include "gthreadprivate.h"
/* Environ array functions {{{1 */
static gboolean
g_environ_matches (const gchar *env, const gchar *variable, gsize len)
{
#ifdef G_OS_WIN32
/* TODO handle Unicode environment variable names */
/* Like filesystem paths, environment variables are case-insensitive. */
return g_ascii_strncasecmp (env, variable, len) == 0 && env[len] == '=';
#else
return strncmp (env, variable, len) == 0 && env[len] == '=';
#endif
}
static gint
g_environ_find (gchar **envp,
const gchar *variable)
{
gsize len;
gint i;
if (envp == NULL)
return -1;
len = strlen (variable);
for (i = 0; envp[i]; i++)
{
if (g_environ_matches (envp[i], variable, len))
return i;
}
return -1;
}
/**
* g_environ_getenv:
* @envp: (nullable) (array zero-terminated=1) (transfer none) (element-type filename):
* an environment list (eg, as returned from g_get_environ()), or %NULL
* for an empty environment list
* @variable: (type filename): the environment variable to get
*
* Returns the value of the environment variable @variable in the
* provided list @envp.
*
* Returns: (type filename) (nullable): the value of the environment variable, or %NULL if
* the environment variable is not set in @envp. The returned
* string is owned by @envp, and will be freed if @variable is
* set or unset again.
*
* Since: 2.32
*/
const gchar *
g_environ_getenv (gchar **envp,
const gchar *variable)
{
gint index;
g_return_val_if_fail (variable != NULL, NULL);
index = g_environ_find (envp, variable);
if (index != -1)
return envp[index] + strlen (variable) + 1;
else
return NULL;
}
/**
* g_environ_setenv:
* @envp: (nullable) (array zero-terminated=1) (element-type filename) (transfer full):
* an environment list that can be freed using g_strfreev() (e.g., as
* returned from g_get_environ()), or %NULL for an empty
* environment list
* @variable: (type filename): the environment variable to set, must not
* contain '='
* @value: (type filename): the value for to set the variable to
* @overwrite: whether to change the variable if it already exists
*
* Sets the environment variable @variable in the provided list
* @envp to @value.
*
* Returns: (array zero-terminated=1) (element-type filename) (transfer full):
* the updated environment list. Free it using g_strfreev().
*
* Since: 2.32
*/
gchar **
g_environ_setenv (gchar **envp,
const gchar *variable,
const gchar *value,
gboolean overwrite)
{
gint index;
g_return_val_if_fail (variable != NULL, NULL);
g_return_val_if_fail (strchr (variable, '=') == NULL, NULL);
g_return_val_if_fail (value != NULL, NULL);
index = g_environ_find (envp, variable);
if (index != -1)
{
if (overwrite)
{
g_free (envp[index]);
envp[index] = g_strdup_printf ("%s=%s", variable, value);
}
}
else
{
gint length;
length = envp ? g_strv_length (envp) : 0;
envp = g_renew (gchar *, envp, length + 2);
envp[length] = g_strdup_printf ("%s=%s", variable, value);
envp[length + 1] = NULL;
}
return envp;
}
static gchar **
g_environ_unsetenv_internal (gchar **envp,
const gchar *variable,
gboolean free_value)
{
gsize len;
gchar **e, **f;
len = strlen (variable);
/* Note that we remove *all* environment entries for
* the variable name, not just the first.
*/
e = f = envp;
while (*e != NULL)
{
if (!g_environ_matches (*e, variable, len))
{
*f = *e;
f++;
}
else
{
if (free_value)
g_free (*e);
}
e++;
}
*f = NULL;
return envp;
}
/**
* g_environ_unsetenv:
* @envp: (nullable) (array zero-terminated=1) (element-type filename) (transfer full):
* an environment list that can be freed using g_strfreev() (e.g., as
* returned from g_get_environ()), or %NULL for an empty environment list
* @variable: (type filename): the environment variable to remove, must not
* contain '='
*
* Removes the environment variable @variable from the provided
* environment @envp.
*
* Returns: (array zero-terminated=1) (element-type filename) (transfer full):
* the updated environment list. Free it using g_strfreev().
*
* Since: 2.32
*/
gchar **
g_environ_unsetenv (gchar **envp,
const gchar *variable)
{
g_return_val_if_fail (variable != NULL, NULL);
g_return_val_if_fail (strchr (variable, '=') == NULL, NULL);
if (envp == NULL)
return NULL;
return g_environ_unsetenv_internal (envp, variable, TRUE);
}
/* UNIX implementation {{{1 */
#ifndef G_OS_WIN32
/**
* g_getenv:
* @variable: (type filename): the environment variable to get
*
* Returns the value of an environment variable.
*
* On UNIX, the name and value are byte strings which might or might not
* be in some consistent character set and encoding. On Windows, they are
* in UTF-8.
* On Windows, in case the environment variable's value contains
* references to other environment variables, they are expanded.
*
* Returns: (type filename) (nullable): the value of the environment variable, or %NULL if
* the environment variable is not found. The returned string
* may be overwritten by the next call to g_getenv(), g_setenv()
* or g_unsetenv().
*/
const gchar *
g_getenv (const gchar *variable)
{
g_return_val_if_fail (variable != NULL, NULL);
return getenv (variable);
}
/**
* g_setenv:
* @variable: (type filename): the environment variable to set, must not
* contain '='.
* @value: (type filename): the value for to set the variable to.
* @overwrite: whether to change the variable if it already exists.
*
* Sets an environment variable. On UNIX, both the variable's name and
* value can be arbitrary byte strings, except that the variable's name
* cannot contain '='. On Windows, they should be in UTF-8.
*
* Note that on some systems, when variables are overwritten, the memory
* used for the previous variables and its value isn't reclaimed.
*
* You should be mindful of the fact that environment variable handling
* in UNIX is not thread-safe, and your program may crash if one thread
* calls g_setenv() while another thread is calling getenv(). (And note
* that many functions, such as gettext(), call getenv() internally.)
* This function is only safe to use at the very start of your program,
* before creating any other threads (or creating objects that create
* worker threads of their own).
*
* If you need to set up the environment for a child process, you can
* use g_get_environ() to get an environment array, modify that with
* g_environ_setenv() and g_environ_unsetenv(), and then pass that
* array directly to execvpe(), g_spawn_async(), or the like.
*
* Returns: %FALSE if the environment variable couldn't be set.
*
* Since: 2.4
*/
gboolean
g_setenv (const gchar *variable,
const gchar *value,
gboolean overwrite)
{
gint result;
#ifndef HAVE_SETENV
gchar *string;
#endif
g_return_val_if_fail (variable != NULL, FALSE);
g_return_val_if_fail (strchr (variable, '=') == NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
#ifndef G_DISABLE_CHECKS
/* FIXME: This will be upgraded to a g_warning() in a future release of GLib.
* See https://gitlab.gnome.org/GNOME/glib/issues/715 */
if (g_thread_n_created () > 0)
g_debug ("setenv()/putenv() are not thread-safe and should not be used after threads are created");
#endif
#ifdef HAVE_SETENV
result = setenv (variable, value, overwrite);
#else
if (!overwrite && getenv (variable) != NULL)
return TRUE;
/* This results in a leak when you overwrite existing
* settings. It would be fairly easy to fix this by keeping
* our own parallel array or hash table.
*/
string = g_strconcat (variable, "=", value, NULL);
result = putenv (string);
#endif
return result == 0;
}
#ifdef HAVE__NSGETENVIRON
#define environ (*_NSGetEnviron())
#else
/* According to the Single Unix Specification, environ is not
* in any system header, although unistd.h often declares it.
*/
extern char **environ;
#endif
/**
* g_unsetenv:
* @variable: (type filename): the environment variable to remove, must
* not contain '='
*
* Removes an environment variable from the environment.
*
* Note that on some systems, when variables are overwritten, the
* memory used for the previous variables and its value isn't reclaimed.
*
* You should be mindful of the fact that environment variable handling
* in UNIX is not thread-safe, and your program may crash if one thread
* calls g_unsetenv() while another thread is calling getenv(). (And note
* that many functions, such as gettext(), call getenv() internally.) This
* function is only safe to use at the very start of your program, before
* creating any other threads (or creating objects that create worker
* threads of their own).
*
* If you need to set up the environment for a child process, you can
* use g_get_environ() to get an environment array, modify that with
* g_environ_setenv() and g_environ_unsetenv(), and then pass that
* array directly to execvpe(), g_spawn_async(), or the like.
*
* Since: 2.4
*/
void
g_unsetenv (const gchar *variable)
{
g_return_if_fail (variable != NULL);
g_return_if_fail (strchr (variable, '=') == NULL);
#ifndef G_DISABLE_CHECKS
/* FIXME: This will be upgraded to a g_warning() in a future release of GLib.
* See https://gitlab.gnome.org/GNOME/glib/issues/715 */
if (g_thread_n_created () > 0)
g_debug ("unsetenv() is not thread-safe and should not be used after threads are created");
#endif
#ifdef HAVE_UNSETENV
unsetenv (variable);
#else /* !HAVE_UNSETENV */
/* Mess directly with the environ array.
* This seems to be the only portable way to do this.
*/
g_environ_unsetenv_internal (environ, variable, FALSE);
#endif /* !HAVE_UNSETENV */
}
/**
* g_listenv:
*
* Gets the names of all variables set in the environment.
*
* Programs that want to be portable to Windows should typically use
* this function and g_getenv() instead of using the environ array
* from the C library directly. On Windows, the strings in the environ
* array are in system codepage encoding, while in most of the typical
* use cases for environment variables in GLib-using programs you want
* the UTF-8 encoding that this function and g_getenv() provide.
*
* Returns: (array zero-terminated=1) (element-type filename) (transfer full):
* a %NULL-terminated list of strings which must be freed with
* g_strfreev().
*
* Since: 2.8
*/
gchar **
g_listenv (void)
{
gchar **result, *eq;
gint len, i, j;
len = g_strv_length (environ);
result = g_new0 (gchar *, len + 1);
j = 0;
for (i = 0; i < len; i++)
{
eq = strchr (environ[i], '=');
if (eq)
result[j++] = g_strndup (environ[i], eq - environ[i]);
}
result[j] = NULL;
return result;
}
/**
* g_get_environ:
*
* Gets the list of environment variables for the current process.
*
* The list is %NULL terminated and each item in the list is of the
* form 'NAME=VALUE'.
*
* This is equivalent to direct access to the 'environ' global variable,
* except portable.
*
* The return value is freshly allocated and it should be freed with
* g_strfreev() when it is no longer needed.
*
* Returns: (array zero-terminated=1) (element-type filename) (transfer full):
* the list of environment variables
*
* Since: 2.28
*/
gchar **
g_get_environ (void)
{
return g_strdupv (environ);
}
/* Win32 implementation {{{1 */
#else /* G_OS_WIN32 */
const gchar *
g_getenv (const gchar *variable)
{
GQuark quark;
gchar *value;
wchar_t dummy[2], *wname, *wvalue;
DWORD len;
g_return_val_if_fail (variable != NULL, NULL);
g_return_val_if_fail (g_utf8_validate (variable, -1, NULL), NULL);
/* On Windows NT, it is relatively typical that environment
* variables contain references to other environment variables. If
* so, use ExpandEnvironmentStrings(). (In an ideal world, such
* environment variables would be stored in the Registry as
* REG_EXPAND_SZ type values, and would then get automatically
* expanded before a program sees them. But there is broken software
* that stores environment variables as REG_SZ values even if they
* contain references to other environment variables.)
*/
wname = g_utf8_to_utf16 (variable, -1, NULL, NULL, NULL);
len = GetEnvironmentVariableW (wname, dummy, 2);
if (len == 0)
{
g_free (wname);
if (GetLastError () == ERROR_ENVVAR_NOT_FOUND)
return NULL;
quark = g_quark_from_static_string ("");
return g_quark_to_string (quark);
}
else if (len == 1)
len = 2;
wvalue = g_new (wchar_t, len);
if (GetEnvironmentVariableW (wname, wvalue, len) != len - 1)
{
g_free (wname);
g_free (wvalue);
return NULL;
}
if (wcschr (wvalue, L'%') != NULL)
{
wchar_t *tem = wvalue;
len = ExpandEnvironmentStringsW (wvalue, dummy, 2);
if (len > 0)
{
wvalue = g_new (wchar_t, len);
if (ExpandEnvironmentStringsW (tem, wvalue, len) != len)
{
g_free (wvalue);
wvalue = tem;
}
else
g_free (tem);
}
}
value = g_utf16_to_utf8 (wvalue, -1, NULL, NULL, NULL);
g_free (wname);
g_free (wvalue);
quark = g_quark_from_string (value);
g_free (value);
return g_quark_to_string (quark);
}
gboolean
g_setenv (const gchar *variable,
const gchar *value,
gboolean overwrite)
{
gboolean retval;
wchar_t *wname, *wvalue, *wassignment;
gchar *tem;
g_return_val_if_fail (variable != NULL, FALSE);
g_return_val_if_fail (strchr (variable, '=') == NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
g_return_val_if_fail (g_utf8_validate (variable, -1, NULL), FALSE);
g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
if (!overwrite && g_getenv (variable) != NULL)
return TRUE;
/* We want to (if possible) set both the environment variable copy
* kept by the C runtime and the one kept by the system.
*
* We can't use only the C runtime's putenv or _wputenv() as that
* won't work for arbitrary Unicode strings in a "non-Unicode" app
* (with main() and not wmain()). In a "main()" app the C runtime
* initializes the C runtime's environment table by converting the
* real (wide char) environment variables to system codepage, thus
* breaking those that aren't representable in the system codepage.
*
* As the C runtime's putenv() will also set the system copy, we do
* the putenv() first, then call SetEnvironmentValueW ourselves.
*/
wname = g_utf8_to_utf16 (variable, -1, NULL, NULL, NULL);
wvalue = g_utf8_to_utf16 (value, -1, NULL, NULL, NULL);
tem = g_strconcat (variable, "=", value, NULL);
wassignment = g_utf8_to_utf16 (tem, -1, NULL, NULL, NULL);
g_free (tem);
_wputenv (wassignment);
g_free (wassignment);
retval = (SetEnvironmentVariableW (wname, wvalue) != 0);
g_free (wname);
g_free (wvalue);
return retval;
}
void
g_unsetenv (const gchar *variable)
{
wchar_t *wname, *wassignment;
gchar *tem;
g_return_if_fail (variable != NULL);
g_return_if_fail (strchr (variable, '=') == NULL);
g_return_if_fail (g_utf8_validate (variable, -1, NULL));
wname = g_utf8_to_utf16 (variable, -1, NULL, NULL, NULL);
tem = g_strconcat (variable, "=", NULL);
wassignment = g_utf8_to_utf16 (tem, -1, NULL, NULL, NULL);
g_free (tem);
_wputenv (wassignment);
g_free (wassignment);
SetEnvironmentVariableW (wname, NULL);
g_free (wname);
}
gchar **
g_listenv (void)
{
gchar **result, *eq;
gint len = 0, j;
wchar_t *p, *q;
p = (wchar_t *) GetEnvironmentStringsW ();
if (p != NULL)
{
q = p;
while (*q)
{
q += wcslen (q) + 1;
len++;
}
}
result = g_new0 (gchar *, len + 1);
j = 0;
q = p;
while (*q)
{
result[j] = g_utf16_to_utf8 (q, -1, NULL, NULL, NULL);
if (result[j] != NULL)
{
eq = strchr (result[j], '=');
if (eq && eq > result[j])
{
*eq = '\0';
j++;
}
else
g_free (result[j]);
}
q += wcslen (q) + 1;
}
result[j] = NULL;
FreeEnvironmentStringsW (p);
return result;
}
gchar **
g_get_environ (void)
{
gunichar2 *strings;
gchar **result;
gint i, n;
strings = GetEnvironmentStringsW ();
for (n = 0, i = 0; strings[n]; i++)
n += wcslen (strings + n) + 1;
result = g_new (char *, i + 1);
for (n = 0, i = 0; strings[n]; i++)
{
result[i] = g_utf16_to_utf8 (strings + n, -1, NULL, NULL, NULL);
n += wcslen (strings + n) + 1;
}
FreeEnvironmentStringsW (strings);
result[i] = NULL;
return result;
}
#endif /* G_OS_WIN32 */
#ifdef G_OS_WIN32
/* Binary compatibility versions. Not for newly compiled code. */
_GLIB_EXTERN const gchar *g_getenv_utf8 (const gchar *variable);
_GLIB_EXTERN gboolean g_setenv_utf8 (const gchar *variable,
const gchar *value,
gboolean overwrite);
_GLIB_EXTERN void g_unsetenv_utf8 (const gchar *variable);
const gchar *
g_getenv_utf8 (const gchar *variable)
{
return g_getenv (variable);
}
gboolean
g_setenv_utf8 (const gchar *variable,
const gchar *value,
gboolean overwrite)
{
return g_setenv (variable, value, overwrite);
}
void
g_unsetenv_utf8 (const gchar *variable)
{
g_unsetenv (variable);
}
#endif
/* Epilogue {{{1 */
/* vim: set foldmethod=marker: */

63
glib/genviron.h Normal file
View file

@ -0,0 +1,63 @@
/* 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.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/.
*/
#ifndef __G_ENVIRON_H__
#define __G_ENVIRON_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtypes.h>
G_BEGIN_DECLS
GLIB_AVAILABLE_IN_ALL
const gchar * g_getenv (const gchar *variable);
GLIB_AVAILABLE_IN_ALL
gboolean g_setenv (const gchar *variable,
const gchar *value,
gboolean overwrite);
GLIB_AVAILABLE_IN_ALL
void g_unsetenv (const gchar *variable);
GLIB_AVAILABLE_IN_ALL
gchar ** g_listenv (void);
GLIB_AVAILABLE_IN_ALL
gchar ** g_get_environ (void);
GLIB_AVAILABLE_IN_ALL
const gchar * g_environ_getenv (gchar **envp,
const gchar *variable);
GLIB_AVAILABLE_IN_ALL
gchar ** g_environ_setenv (gchar **envp,
const gchar *variable,
const gchar *value,
gboolean overwrite) G_GNUC_WARN_UNUSED_RESULT;
GLIB_AVAILABLE_IN_ALL
gchar ** g_environ_unsetenv (gchar **envp,
const gchar *variable) G_GNUC_WARN_UNUSED_RESULT;
G_END_DECLS
#endif /* __G_ENVIRON_H__ */

1157
glib/gerror.c Normal file

File diff suppressed because it is too large Load diff

261
glib/gerror.h Normal file
View file

@ -0,0 +1,261 @@
/* gerror.h - Error reporting system
*
* Copyright 2000 Red Hat, Inc.
*
* 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/>.
*/
#ifndef __G_ERROR_H__
#define __G_ERROR_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <stdarg.h>
#include <glib/gquark.h>
G_BEGIN_DECLS
/**
* GError:
* @domain: error domain, e.g. %G_FILE_ERROR
* @code: error code, e.g. %G_FILE_ERROR_NOENT
* @message: human-readable informative error message
*
* The `GError` structure contains information about
* an error that has occurred.
*/
typedef struct _GError GError;
struct _GError
{
GQuark domain;
gint code;
gchar *message;
};
/**
* G_DEFINE_EXTENDED_ERROR:
* @ErrorType: name to return a #GQuark for
* @error_type: prefix for the function name
*
* A convenience macro which defines two functions. First, returning
* the #GQuark for the extended error type @ErrorType; it is called
* `error_type_quark()`. Second, returning the private data from a
* passed #GError; it is called `error_type_get_private()`.
*
* For this macro to work, a type named `ErrorTypePrivate` should be
* defined, `error_type_private_init()`, `error_type_private_copy()`
* and `error_type_private_clear()` functions need to be either
* declared or defined. The functions should be similar to
* #GErrorInitFunc, #GErrorCopyFunc and #GErrorClearFunc,
* respectively, but they should receive the private data type instead
* of #GError.
*
* See [Extended #GError Domains][gerror-extended-domains] for an example.
*
* Since: 2.68
*/
#define G_DEFINE_EXTENDED_ERROR(ErrorType, error_type) \
static inline ErrorType ## Private * \
error_type ## _get_private (const GError *error) \
{ \
/* Copied from gtype.c (STRUCT_ALIGNMENT and ALIGN_STRUCT macros). */ \
const gsize sa = 2 * sizeof (gsize); \
const gsize as = (sizeof (ErrorType ## Private) + (sa - 1)) & -sa; \
g_return_val_if_fail (error != NULL, NULL); \
g_return_val_if_fail (error->domain == error_type ## _quark (), NULL); \
return (ErrorType ## Private *) (((guint8 *)error) - as); \
} \
\
static void \
g_error_with_ ## error_type ## _private_init (GError *error) \
{ \
ErrorType ## Private *priv = error_type ## _get_private (error); \
error_type ## _private_init (priv); \
} \
\
static void \
g_error_with_ ## error_type ## _private_copy (const GError *src_error, \
GError *dest_error) \
{ \
const ErrorType ## Private *src_priv = error_type ## _get_private (src_error); \
ErrorType ## Private *dest_priv = error_type ## _get_private (dest_error); \
error_type ## _private_copy (src_priv, dest_priv); \
} \
\
static void \
g_error_with_ ## error_type ## _private_clear (GError *error) \
{ \
ErrorType ## Private *priv = error_type ## _get_private (error); \
error_type ## _private_clear (priv); \
} \
\
GQuark \
error_type ## _quark (void) \
{ \
static GQuark q; \
static gsize initialized = 0; \
\
if (g_once_init_enter (&initialized)) \
{ \
q = g_error_domain_register_static (#ErrorType, \
sizeof (ErrorType ## Private), \
g_error_with_ ## error_type ## _private_init, \
g_error_with_ ## error_type ## _private_copy, \
g_error_with_ ## error_type ## _private_clear); \
g_once_init_leave (&initialized, 1); \
} \
\
return q; \
}
/**
* GErrorInitFunc:
* @error: extended error
*
* Specifies the type of function which is called just after an
* extended error instance is created and its fields filled. It should
* only initialize the fields in the private data, which can be
* received with the generated `*_get_private()` function.
*
* Normally, it is better to use G_DEFINE_EXTENDED_ERROR(), as it
* already takes care of getting the private data from @error.
*
* Since: 2.68
*/
typedef void (*GErrorInitFunc) (GError *error);
/**
* GErrorCopyFunc:
* @src_error: source extended error
* @dest_error: destination extended error
*
* Specifies the type of function which is called when an extended
* error instance is copied. It is passed the pointer to the
* destination error and source error, and should copy only the fields
* of the private data from @src_error to @dest_error.
*
* Normally, it is better to use G_DEFINE_EXTENDED_ERROR(), as it
* already takes care of getting the private data from @src_error and
* @dest_error.
*
* Since: 2.68
*/
typedef void (*GErrorCopyFunc) (const GError *src_error, GError *dest_error);
/**
* GErrorClearFunc:
* @error: extended error to clear
*
* Specifies the type of function which is called when an extended
* error instance is freed. It is passed the error pointer about to be
* freed, and should free the error's private data fields.
*
* Normally, it is better to use G_DEFINE_EXTENDED_ERROR(), as it
* already takes care of getting the private data from @error.
*
* Since: 2.68
*/
typedef void (*GErrorClearFunc) (GError *error);
GLIB_AVAILABLE_IN_2_68
GQuark g_error_domain_register_static (const char *error_type_name,
gsize error_type_private_size,
GErrorInitFunc error_type_init,
GErrorCopyFunc error_type_copy,
GErrorClearFunc error_type_clear);
GLIB_AVAILABLE_IN_2_68
GQuark g_error_domain_register (const char *error_type_name,
gsize error_type_private_size,
GErrorInitFunc error_type_init,
GErrorCopyFunc error_type_copy,
GErrorClearFunc error_type_clear);
GLIB_AVAILABLE_IN_ALL
GError* g_error_new (GQuark domain,
gint code,
const gchar *format,
...) G_GNUC_PRINTF (3, 4);
GLIB_AVAILABLE_IN_ALL
GError* g_error_new_literal (GQuark domain,
gint code,
const gchar *message);
GLIB_AVAILABLE_IN_ALL
GError* g_error_new_valist (GQuark domain,
gint code,
const gchar *format,
va_list args) G_GNUC_PRINTF(3, 0);
GLIB_AVAILABLE_IN_ALL
void g_error_free (GError *error);
GLIB_AVAILABLE_IN_ALL
GError* g_error_copy (const GError *error);
GLIB_AVAILABLE_IN_ALL
gboolean g_error_matches (const GError *error,
GQuark domain,
gint code);
/* if (err) *err = g_error_new(domain, code, format, ...), also has
* some sanity checks.
*/
GLIB_AVAILABLE_IN_ALL
void g_set_error (GError **err,
GQuark domain,
gint code,
const gchar *format,
...) G_GNUC_PRINTF (4, 5);
GLIB_AVAILABLE_IN_ALL
void g_set_error_literal (GError **err,
GQuark domain,
gint code,
const gchar *message);
/* if (dest) *dest = src; also has some sanity checks.
*/
GLIB_AVAILABLE_IN_ALL
void g_propagate_error (GError **dest,
GError *src);
/* if (err && *err) { g_error_free(*err); *err = NULL; } */
GLIB_AVAILABLE_IN_ALL
void g_clear_error (GError **err);
/* if (err) prefix the formatted string to the ->message */
GLIB_AVAILABLE_IN_ALL
void g_prefix_error (GError **err,
const gchar *format,
...) G_GNUC_PRINTF (2, 3);
/* if (err) prefix the string to the ->message */
GLIB_AVAILABLE_IN_2_70
void g_prefix_error_literal (GError **err,
const gchar *prefix);
/* g_propagate_error then g_error_prefix on dest */
GLIB_AVAILABLE_IN_ALL
void g_propagate_prefixed_error (GError **dest,
GError *src,
const gchar *format,
...) G_GNUC_PRINTF (3, 4);
G_END_DECLS
#endif /* __G_ERROR_H__ */

2978
glib/gfileutils.c Normal file

File diff suppressed because it is too large Load diff

221
glib/gfileutils.h Normal file
View file

@ -0,0 +1,221 @@
/* gfileutils.h - File utility functions
*
* Copyright 2000 Red Hat, Inc.
*
* 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/>.
*/
#ifndef __G_FILEUTILS_H__
#define __G_FILEUTILS_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glibconfig.h>
#include <glib/gerror.h>
G_BEGIN_DECLS
#define G_FILE_ERROR g_file_error_quark ()
typedef enum
{
G_FILE_ERROR_EXIST,
G_FILE_ERROR_ISDIR,
G_FILE_ERROR_ACCES,
G_FILE_ERROR_NAMETOOLONG,
G_FILE_ERROR_NOENT,
G_FILE_ERROR_NOTDIR,
G_FILE_ERROR_NXIO,
G_FILE_ERROR_NODEV,
G_FILE_ERROR_ROFS,
G_FILE_ERROR_TXTBSY,
G_FILE_ERROR_FAULT,
G_FILE_ERROR_LOOP,
G_FILE_ERROR_NOSPC,
G_FILE_ERROR_NOMEM,
G_FILE_ERROR_MFILE,
G_FILE_ERROR_NFILE,
G_FILE_ERROR_BADF,
G_FILE_ERROR_INVAL,
G_FILE_ERROR_PIPE,
G_FILE_ERROR_AGAIN,
G_FILE_ERROR_INTR,
G_FILE_ERROR_IO,
G_FILE_ERROR_PERM,
G_FILE_ERROR_NOSYS,
G_FILE_ERROR_FAILED
} GFileError;
/* For backward-compat reasons, these are synced to an old
* anonymous enum in libgnome. But don't use that enum
* in new code.
*/
typedef enum
{
G_FILE_TEST_IS_REGULAR = 1 << 0,
G_FILE_TEST_IS_SYMLINK = 1 << 1,
G_FILE_TEST_IS_DIR = 1 << 2,
G_FILE_TEST_IS_EXECUTABLE = 1 << 3,
G_FILE_TEST_EXISTS = 1 << 4
} GFileTest;
/**
* GFileSetContentsFlags:
* @G_FILE_SET_CONTENTS_NONE: No guarantees about file consistency or durability.
* The most dangerous setting, which is slightly faster than other settings.
* @G_FILE_SET_CONTENTS_CONSISTENT: Guarantee file consistency: after a crash,
* either the old version of the file or the new version of the file will be
* available, but not a mixture. On Unix systems this equates to an `fsync()`
* on the file and use of an atomic `rename()` of the new version of the file
* over the old.
* @G_FILE_SET_CONTENTS_DURABLE: Guarantee file durability: after a crash, the
* new version of the file will be available. On Unix systems this equates to
* an `fsync()` on the file (if %G_FILE_SET_CONTENTS_CONSISTENT is unset), or
* the effects of %G_FILE_SET_CONTENTS_CONSISTENT plus an `fsync()` on the
* directory containing the file after calling `rename()`.
* @G_FILE_SET_CONTENTS_ONLY_EXISTING: Only apply consistency and durability
* guarantees if the file already exists. This may speed up file operations
* if the file doesnt currently exist, but may result in a corrupted version
* of the new file if the system crashes while writing it.
*
* Flags to pass to g_file_set_contents_full() to affect its safety and
* performance.
*
* Since: 2.66
*/
typedef enum
{
G_FILE_SET_CONTENTS_NONE = 0,
G_FILE_SET_CONTENTS_CONSISTENT = 1 << 0,
G_FILE_SET_CONTENTS_DURABLE = 1 << 1,
G_FILE_SET_CONTENTS_ONLY_EXISTING = 1 << 2
} GFileSetContentsFlags
GLIB_AVAILABLE_ENUMERATOR_IN_2_66;
GLIB_AVAILABLE_IN_ALL
GQuark g_file_error_quark (void);
/* So other code can generate a GFileError */
GLIB_AVAILABLE_IN_ALL
GFileError g_file_error_from_errno (gint err_no);
GLIB_AVAILABLE_IN_ALL
gboolean g_file_test (const gchar *filename,
GFileTest test);
GLIB_AVAILABLE_IN_ALL
gboolean g_file_get_contents (const gchar *filename,
gchar **contents,
gsize *length,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_file_set_contents (const gchar *filename,
const gchar *contents,
gssize length,
GError **error);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
GLIB_AVAILABLE_IN_2_66
gboolean g_file_set_contents_full (const gchar *filename,
const gchar *contents,
gssize length,
GFileSetContentsFlags flags,
int mode,
GError **error);
G_GNUC_END_IGNORE_DEPRECATIONS
GLIB_AVAILABLE_IN_ALL
gchar *g_file_read_link (const gchar *filename,
GError **error);
/* Wrapper / workalike for mkdtemp() */
GLIB_AVAILABLE_IN_2_30
gchar *g_mkdtemp (gchar *tmpl);
GLIB_AVAILABLE_IN_2_30
gchar *g_mkdtemp_full (gchar *tmpl,
gint mode);
/* Wrapper / workalike for mkstemp() */
GLIB_AVAILABLE_IN_ALL
gint g_mkstemp (gchar *tmpl);
GLIB_AVAILABLE_IN_ALL
gint g_mkstemp_full (gchar *tmpl,
gint flags,
gint mode);
/* Wrappers for g_mkstemp and g_mkdtemp() */
GLIB_AVAILABLE_IN_ALL
gint g_file_open_tmp (const gchar *tmpl,
gchar **name_used,
GError **error);
GLIB_AVAILABLE_IN_2_30
gchar *g_dir_make_tmp (const gchar *tmpl,
GError **error);
GLIB_AVAILABLE_IN_ALL
gchar *g_build_path (const gchar *separator,
const gchar *first_element,
...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED;
GLIB_AVAILABLE_IN_ALL
gchar *g_build_pathv (const gchar *separator,
gchar **args) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
gchar *g_build_filename (const gchar *first_element,
...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED;
GLIB_AVAILABLE_IN_ALL
gchar *g_build_filenamev (gchar **args) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_2_56
gchar *g_build_filename_valist (const gchar *first_element,
va_list *args) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
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_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR || (c) == '/')
#else /* !G_OS_WIN32 */
#define G_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR)
#endif /* !G_OS_WIN32 */
GLIB_AVAILABLE_IN_ALL
gboolean g_path_is_absolute (const gchar *file_name);
GLIB_AVAILABLE_IN_ALL
const gchar *g_path_skip_root (const gchar *file_name);
GLIB_DEPRECATED_FOR(g_path_get_basename)
const gchar *g_basename (const gchar *file_name);
#define g_dirname g_path_get_dirname GLIB_DEPRECATED_MACRO_IN_2_26_FOR(g_path_get_dirname)
GLIB_AVAILABLE_IN_ALL
gchar *g_get_current_dir (void);
GLIB_AVAILABLE_IN_ALL
gchar *g_path_get_basename (const gchar *file_name) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
gchar *g_path_get_dirname (const gchar *file_name) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_2_58
gchar *g_canonicalize_filename (const gchar *filename,
const gchar *relative_to) G_GNUC_MALLOC;
G_END_DECLS
#endif /* __G_FILEUTILS_H__ */

637
glib/ggettext.c Normal file
View file

@ -0,0 +1,637 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1998 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.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/.
*/
#include "config.h"
#include "ggettext.h"
#include "glibintl.h"
#include "glib-private.h"
#include "galloca.h"
#include "gthread.h"
#include "gmem.h"
#ifdef G_OS_WIN32
#include "gwin32.h"
#include "gfileutils.h"
#include "gstrfuncs.h"
#include "glib-init.h"
#endif
#include <string.h>
#include <locale.h>
#include <libintl.h>
#ifdef G_OS_WIN32
/**
* _glib_get_locale_dir:
*
* Return the path to the share\locale or lib\locale subfolder of the
* GLib installation folder. The path is in the system codepage. We
* have to use system codepage as bindtextdomain() doesn't have a
* UTF-8 interface.
*/
gchar *
_glib_get_locale_dir (void)
{
gchar *install_dir = NULL, *locale_dir;
gchar *retval = NULL;
if (glib_dll != NULL)
install_dir = g_win32_get_package_installation_directory_of_module (glib_dll);
if (install_dir)
{
/*
* Append "/share/locale" or "/lib/locale" depending on whether
* autoconfigury detected GNU gettext or not.
*/
const char *p = GLIB_LOCALE_DIR + strlen (GLIB_LOCALE_DIR);
while (*--p != '/')
;
while (*--p != '/')
;
locale_dir = g_build_filename (install_dir, p, NULL);
retval = g_win32_locale_filename_from_utf8 (locale_dir);
g_free (install_dir);
g_free (locale_dir);
}
if (retval)
return retval;
else
return g_strdup ("");
}
#undef GLIB_LOCALE_DIR
#endif /* G_OS_WIN32 */
static void
ensure_gettext_initialized (void)
{
static gsize initialised;
if (g_once_init_enter (&initialised))
{
#ifdef G_OS_WIN32
gchar *tmp = _glib_get_locale_dir ();
bindtextdomain (GETTEXT_PACKAGE, tmp);
g_free (tmp);
#else
bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
#endif
# ifdef HAVE_BIND_TEXTDOMAIN_CODESET
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
# endif
g_once_init_leave (&initialised, TRUE);
}
}
/**
* glib_gettext:
* @str: The string to be translated
*
* Returns the translated string from the glib translations.
* This is an internal function and should only be used by
* the internals of glib (such as libgio).
*
* Returns: the translation of @str to the current locale
*/
const gchar *
glib_gettext (const gchar *str)
{
ensure_gettext_initialized ();
return g_dgettext (GETTEXT_PACKAGE, str);
}
/**
* glib_pgettext:
* @msgctxtid: a combined message context and message id, separated
* by a \004 character
* @msgidoffset: the offset of the message id in @msgctxid
*
* This function is a variant of glib_gettext() which supports
* a disambiguating message context. See g_dpgettext() for full
* details.
*
* This is an internal function and should only be used by
* the internals of glib (such as libgio).
*
* Returns: the translation of @str to the current locale
*/
const gchar *
glib_pgettext (const gchar *msgctxtid,
gsize msgidoffset)
{
ensure_gettext_initialized ();
return g_dpgettext (GETTEXT_PACKAGE, msgctxtid, msgidoffset);
}
/**
* g_strip_context:
* @msgid: a string
* @msgval: another string
*
* An auxiliary function for gettext() support (see Q_()).
*
* Returns: @msgval, unless @msgval is identical to @msgid
* and contains a '|' character, in which case a pointer to
* the substring of msgid after the first '|' character is returned.
*
* Since: 2.4
*/
const gchar *
g_strip_context (const gchar *msgid,
const gchar *msgval)
{
if (msgval == msgid)
{
const char *c = strchr (msgid, '|');
if (c != NULL)
return c + 1;
}
return msgval;
}
/**
* g_dpgettext:
* @domain: (nullable): the translation domain to use, or %NULL to use
* the domain set with textdomain()
* @msgctxtid: a combined message context and message id, separated
* by a \004 character
* @msgidoffset: the offset of the message id in @msgctxid
*
* This function is a variant of g_dgettext() which supports
* a disambiguating message context. GNU gettext uses the
* '\004' character to separate the message context and
* message id in @msgctxtid.
* If 0 is passed as @msgidoffset, this function will fall back to
* trying to use the deprecated convention of using "|" as a separation
* character.
*
* This uses g_dgettext() internally. See that functions for differences
* with dgettext() proper.
*
* Applications should normally not use this function directly,
* but use the C_() macro for translations with context.
*
* Returns: The translated string
*
* Since: 2.16
*/
const gchar *
g_dpgettext (const gchar *domain,
const gchar *msgctxtid,
gsize msgidoffset)
{
const gchar *translation;
gchar *sep;
translation = g_dgettext (domain, msgctxtid);
if (translation == msgctxtid)
{
if (msgidoffset > 0)
return msgctxtid + msgidoffset;
sep = strchr (msgctxtid, '|');
if (sep)
{
/* try with '\004' instead of '|', in case
* xgettext -kQ_:1g was used
*/
gchar *tmp = g_alloca (strlen (msgctxtid) + 1);
strcpy (tmp, msgctxtid);
tmp[sep - msgctxtid] = '\004';
translation = g_dgettext (domain, tmp);
if (translation == tmp)
return sep + 1;
}
}
return translation;
}
/* This function is taken from gettext.h
* GNU gettext uses '\004' to separate context and msgid in .mo files.
*/
/**
* g_dpgettext2:
* @domain: (nullable): the translation domain to use, or %NULL to use
* the domain set with textdomain()
* @context: the message context
* @msgid: the message
*
* This function is a variant of g_dgettext() which supports
* a disambiguating message context. GNU gettext uses the
* '\004' character to separate the message context and
* message id in @msgctxtid.
*
* This uses g_dgettext() internally. See that functions for differences
* with dgettext() proper.
*
* This function differs from C_() in that it is not a macro and
* thus you may use non-string-literals as context and msgid arguments.
*
* Returns: The translated string
*
* Since: 2.18
*/
const gchar *
g_dpgettext2 (const gchar *domain,
const gchar *msgctxt,
const gchar *msgid)
{
size_t msgctxt_len = strlen (msgctxt) + 1;
size_t msgid_len = strlen (msgid) + 1;
const char *translation;
char* msg_ctxt_id;
msg_ctxt_id = g_alloca (msgctxt_len + msgid_len);
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
msg_ctxt_id[msgctxt_len - 1] = '\004';
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
translation = g_dgettext (domain, msg_ctxt_id);
if (translation == msg_ctxt_id)
{
/* try the old way of doing message contexts, too */
msg_ctxt_id[msgctxt_len - 1] = '|';
translation = g_dgettext (domain, msg_ctxt_id);
if (translation == msg_ctxt_id)
return msgid;
}
return translation;
}
static gboolean
_g_dgettext_should_translate (void)
{
static gsize translate = 0;
enum {
SHOULD_TRANSLATE = 1,
SHOULD_NOT_TRANSLATE = 2
};
if (G_UNLIKELY (g_once_init_enter (&translate)))
{
gboolean should_translate = TRUE;
const char *default_domain = textdomain (NULL);
const char *translator_comment = gettext ("");
#ifndef G_OS_WIN32
const char *translate_locale = setlocale (LC_MESSAGES, NULL);
#else
const char *translate_locale = g_win32_getlocale ();
#endif
/* We should NOT translate only if all the following hold:
* - user has called textdomain() and set textdomain to non-default
* - default domain has no translations
* - locale does not start with "en_" and is not "C"
*
* Rationale:
* - If text domain is still the default domain, maybe user calls
* it later. Continue with old behavior of translating.
* - If locale starts with "en_", we can continue using the
* translations even if the app doesn't have translations for
* this locale. That is, en_UK and en_CA for example.
* - If locale is "C", maybe user calls setlocale(LC_ALL,"") later.
* Continue with old behavior of translating.
*/
if (!default_domain || !translator_comment || !translate_locale ||
(0 != strcmp (default_domain, "messages") &&
'\0' == *translator_comment &&
0 != strncmp (translate_locale, "en_", 3) &&
0 != strcmp (translate_locale, "C")))
should_translate = FALSE;
g_once_init_leave (&translate,
should_translate ?
SHOULD_TRANSLATE :
SHOULD_NOT_TRANSLATE);
}
return translate == SHOULD_TRANSLATE;
}
/**
* g_dgettext:
* @domain: (nullable): the translation domain to use, or %NULL to use
* the domain set with textdomain()
* @msgid: message to translate
*
* This function is a wrapper of dgettext() which does not translate
* the message if the default domain as set with textdomain() has no
* translations for the current locale.
*
* The advantage of using this function over dgettext() proper is that
* libraries using this function (like GTK+) will not use translations
* if the application using the library does not have translations for
* the current locale. This results in a consistent English-only
* interface instead of one having partial translations. For this
* feature to work, the call to textdomain() and setlocale() should
* precede any g_dgettext() invocations. For GTK+, it means calling
* textdomain() before gtk_init or its variants.
*
* This function disables translations if and only if upon its first
* call all the following conditions hold:
*
* - @domain is not %NULL
*
* - textdomain() has been called to set a default text domain
*
* - there is no translations available for the default text domain
* and the current locale
*
* - current locale is not "C" or any English locales (those
* starting with "en_")
*
* Note that this behavior may not be desired for example if an application
* has its untranslated messages in a language other than English. In those
* cases the application should call textdomain() after initializing GTK+.
*
* Applications should normally not use this function directly,
* but use the _() macro for translations.
*
* Returns: The translated string
*
* Since: 2.18
*/
const gchar *
g_dgettext (const gchar *domain,
const gchar *msgid)
{
if (domain && G_UNLIKELY (!_g_dgettext_should_translate ()))
return msgid;
return dgettext (domain, msgid);
}
/**
* g_dcgettext:
* @domain: (nullable): the translation domain to use, or %NULL to use
* the domain set with textdomain()
* @msgid: message to translate
* @category: a locale category
*
* This is a variant of g_dgettext() that allows specifying a locale
* category instead of always using `LC_MESSAGES`. See g_dgettext() for
* more information about how this functions differs from calling
* dcgettext() directly.
*
* Returns: the translated string for the given locale category
*
* Since: 2.26
*/
const gchar *
g_dcgettext (const gchar *domain,
const gchar *msgid,
gint category)
{
if (domain && G_UNLIKELY (!_g_dgettext_should_translate ()))
return msgid;
return dcgettext (domain, msgid, category);
}
/**
* g_dngettext:
* @domain: (nullable): the translation domain to use, or %NULL to use
* the domain set with textdomain()
* @msgid: message to translate
* @msgid_plural: plural form of the message
* @n: the quantity for which translation is needed
*
* This function is a wrapper of dngettext() which does not translate
* the message if the default domain as set with textdomain() has no
* translations for the current locale.
*
* See g_dgettext() for details of how this differs from dngettext()
* proper.
*
* Returns: The translated string
*
* Since: 2.18
*/
const gchar *
g_dngettext (const gchar *domain,
const gchar *msgid,
const gchar *msgid_plural,
gulong n)
{
if (domain && G_UNLIKELY (!_g_dgettext_should_translate ()))
return n == 1 ? msgid : msgid_plural;
return dngettext (domain, msgid, msgid_plural, n);
}
/**
* SECTION:i18n
* @title: Internationalization
* @short_description: gettext support macros
* @see_also: the gettext manual
*
* GLib doesn't force any particular localization method upon its users.
* But since GLib itself is localized using the gettext() mechanism, it seems
* natural to offer the de-facto standard gettext() support macros in an
* easy-to-use form.
*
* In order to use these macros in an application, you must include
* `<glib/gi18n.h>`. For use in a library, you must include
* `<glib/gi18n-lib.h>`
* after defining the %GETTEXT_PACKAGE macro suitably for your library:
* |[<!-- language="C" -->
* #define GETTEXT_PACKAGE "gtk20"
* #include <glib/gi18n-lib.h>
* ]|
* For an application, note that you also have to call bindtextdomain(),
* bind_textdomain_codeset(), textdomain() and setlocale() early on in your
* main() to make gettext() work. For example:
* |[<!-- language="C" -->
* #include <glib/gi18n.h>
* #include <locale.h>
*
* int
* main (int argc, char **argv)
* {
* setlocale (LC_ALL, "");
* bindtextdomain (GETTEXT_PACKAGE, DATADIR "/locale");
* bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
* textdomain (GETTEXT_PACKAGE);
*
* // Rest of your application.
* }
* ]|
* where `DATADIR` is as typically provided by automake or Meson.
*
* For a library, you only have to call bindtextdomain() and
* bind_textdomain_codeset() in your initialization function. If your library
* doesn't have an initialization function, you can call the functions before
* the first translated message.
*
* The
* [gettext manual](http://www.gnu.org/software/gettext/manual/gettext.html#Maintainers)
* covers details of how to integrate gettext into a projects build system and
* workflow.
*/
/**
* _:
* @String: the string to be translated
*
* Marks a string for translation, gets replaced with the translated string
* at runtime.
*
* Since: 2.4
*/
/**
* Q_:
* @String: the string to be translated, with a '|'-separated prefix
* which must not be translated
*
* Like _(), but handles context in message ids. This has the advantage
* that the string can be adorned with a prefix to guarantee uniqueness
* and provide context to the translator.
*
* One use case given in the gettext manual is GUI translation, where one
* could e.g. disambiguate two "Open" menu entries as "File|Open" and
* "Printer|Open". Another use case is the string "Russian" which may
* have to be translated differently depending on whether it's the name
* of a character set or a language. This could be solved by using
* "charset|Russian" and "language|Russian".
*
* See the C_() macro for a different way to mark up translatable strings
* with context.
*
* If you are using the Q_() macro, you need to make sure that you pass
* `--keyword=Q_` to xgettext when extracting messages.
* If you are using GNU gettext >= 0.15, you can also use
* `--keyword=Q_:1g` to let xgettext split the context
* string off into a msgctxt line in the po file.
*
* Returns: the translated message
*
* Since: 2.4
*/
/**
* C_:
* @Context: a message context, must be a string literal
* @String: a message id, must be a string literal
*
* Uses gettext to get the translation for @String. @Context is
* used as a context. This is mainly useful for short strings which
* may need different translations, depending on the context in which
* they are used.
* |[<!-- language="C" -->
* label1 = C_("Navigation", "Back");
* label2 = C_("Body part", "Back");
* ]|
*
* If you are using the C_() macro, you need to make sure that you pass
* `--keyword=C_:1c,2` to xgettext when extracting messages.
* Note that this only works with GNU gettext >= 0.15.
*
* Returns: the translated message
*
* Since: 2.16
*/
/**
* N_:
* @String: the string to be translated
*
* Only marks a string for translation. This is useful in situations
* where the translated strings can't be directly used, e.g. in string
* array initializers. To get the translated string, call gettext()
* at runtime.
* |[<!-- language="C" -->
* {
* static const char *messages[] = {
* N_("some very meaningful message"),
* N_("and another one")
* };
* const char *string;
* ...
* string
* = index &gt; 1 ? _("a default message") : gettext (messages[index]);
*
* fputs (string);
* ...
* }
* ]|
*
* Since: 2.4
*/
/**
* NC_:
* @Context: a message context, must be a string literal
* @String: a message id, must be a string literal
*
* Only marks a string for translation, with context.
* This is useful in situations where the translated strings can't
* be directly used, e.g. in string array initializers. To get the
* translated string, you should call g_dpgettext2() at runtime.
*
* |[<!-- language="C" -->
* {
* static const char *messages[] = {
* NC_("some context", "some very meaningful message"),
* NC_("some context", "and another one")
* };
* const char *string;
* ...
* string
* = index > 1 ? g_dpgettext2 (NULL, "some context", "a default message")
* : g_dpgettext2 (NULL, "some context", messages[index]);
*
* fputs (string);
* ...
* }
* ]|
*
* If you are using the NC_() macro, you need to make sure that you pass
* `--keyword=NC_:1c,2` to xgettext when extracting messages.
* Note that this only works with GNU gettext >= 0.15. Intltool has support
* for the NC_() macro since version 0.40.1.
*
* Since: 2.18
*/

63
glib/ggettext.h Normal file
View file

@ -0,0 +1,63 @@
/* 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.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/.
*/
#ifndef __G_GETTEXT_H__
#define __G_GETTEXT_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtypes.h>
G_BEGIN_DECLS
GLIB_AVAILABLE_IN_ALL
const gchar *g_strip_context (const gchar *msgid,
const gchar *msgval) G_GNUC_FORMAT(1);
GLIB_AVAILABLE_IN_ALL
const gchar *g_dgettext (const gchar *domain,
const gchar *msgid) G_GNUC_FORMAT(2);
GLIB_AVAILABLE_IN_ALL
const gchar *g_dcgettext (const gchar *domain,
const gchar *msgid,
gint category) G_GNUC_FORMAT(2);
GLIB_AVAILABLE_IN_ALL
const gchar *g_dngettext (const gchar *domain,
const gchar *msgid,
const gchar *msgid_plural,
gulong n) G_GNUC_FORMAT(3);
GLIB_AVAILABLE_IN_ALL
const gchar *g_dpgettext (const gchar *domain,
const gchar *msgctxtid,
gsize msgidoffset) G_GNUC_FORMAT(2);
GLIB_AVAILABLE_IN_ALL
const gchar *g_dpgettext2 (const gchar *domain,
const gchar *context,
const gchar *msgid) G_GNUC_FORMAT(3);
G_END_DECLS
#endif /* __G_GETTEXT_H__ */

2533
glib/ghash.c Normal file

File diff suppressed because it is too large Load diff

190
glib/ghash.h Normal file
View file

@ -0,0 +1,190 @@
/* 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.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/.
*/
#ifndef __G_HASH_H__
#define __G_HASH_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtypes.h>
#include <glib/glist.h>
G_BEGIN_DECLS
typedef struct _GHashTable GHashTable;
typedef gboolean (*GHRFunc) (gpointer key,
gpointer value,
gpointer user_data);
typedef struct _GHashTableIter GHashTableIter;
struct _GHashTableIter
{
/*< private >*/
gpointer dummy1;
gpointer dummy2;
gpointer dummy3;
int dummy4;
gboolean dummy5;
gpointer dummy6;
};
GLIB_AVAILABLE_IN_ALL
GHashTable* g_hash_table_new (GHashFunc hash_func,
GEqualFunc key_equal_func);
GLIB_AVAILABLE_IN_ALL
GHashTable* g_hash_table_new_full (GHashFunc hash_func,
GEqualFunc key_equal_func,
GDestroyNotify key_destroy_func,
GDestroyNotify value_destroy_func);
GLIB_AVAILABLE_IN_2_72
GHashTable *g_hash_table_new_similar (GHashTable *other_hash_table);
GLIB_AVAILABLE_IN_ALL
void g_hash_table_destroy (GHashTable *hash_table);
GLIB_AVAILABLE_IN_ALL
gboolean g_hash_table_insert (GHashTable *hash_table,
gpointer key,
gpointer value);
GLIB_AVAILABLE_IN_ALL
gboolean g_hash_table_replace (GHashTable *hash_table,
gpointer key,
gpointer value);
GLIB_AVAILABLE_IN_ALL
gboolean g_hash_table_add (GHashTable *hash_table,
gpointer key);
GLIB_AVAILABLE_IN_ALL
gboolean g_hash_table_remove (GHashTable *hash_table,
gconstpointer key);
GLIB_AVAILABLE_IN_ALL
void g_hash_table_remove_all (GHashTable *hash_table);
GLIB_AVAILABLE_IN_ALL
gboolean g_hash_table_steal (GHashTable *hash_table,
gconstpointer key);
GLIB_AVAILABLE_IN_2_58
gboolean g_hash_table_steal_extended (GHashTable *hash_table,
gconstpointer lookup_key,
gpointer *stolen_key,
gpointer *stolen_value);
GLIB_AVAILABLE_IN_ALL
void g_hash_table_steal_all (GHashTable *hash_table);
GLIB_AVAILABLE_IN_ALL
gpointer g_hash_table_lookup (GHashTable *hash_table,
gconstpointer key);
GLIB_AVAILABLE_IN_ALL
gboolean g_hash_table_contains (GHashTable *hash_table,
gconstpointer key);
GLIB_AVAILABLE_IN_ALL
gboolean g_hash_table_lookup_extended (GHashTable *hash_table,
gconstpointer lookup_key,
gpointer *orig_key,
gpointer *value);
GLIB_AVAILABLE_IN_ALL
void g_hash_table_foreach (GHashTable *hash_table,
GHFunc func,
gpointer user_data);
GLIB_AVAILABLE_IN_ALL
gpointer g_hash_table_find (GHashTable *hash_table,
GHRFunc predicate,
gpointer user_data);
GLIB_AVAILABLE_IN_ALL
guint g_hash_table_foreach_remove (GHashTable *hash_table,
GHRFunc func,
gpointer user_data);
GLIB_AVAILABLE_IN_ALL
guint g_hash_table_foreach_steal (GHashTable *hash_table,
GHRFunc func,
gpointer user_data);
GLIB_AVAILABLE_IN_ALL
guint g_hash_table_size (GHashTable *hash_table);
GLIB_AVAILABLE_IN_ALL
GList * g_hash_table_get_keys (GHashTable *hash_table);
GLIB_AVAILABLE_IN_ALL
GList * g_hash_table_get_values (GHashTable *hash_table);
GLIB_AVAILABLE_IN_2_40
gpointer * g_hash_table_get_keys_as_array (GHashTable *hash_table,
guint *length);
GLIB_AVAILABLE_IN_ALL
void g_hash_table_iter_init (GHashTableIter *iter,
GHashTable *hash_table);
GLIB_AVAILABLE_IN_ALL
gboolean g_hash_table_iter_next (GHashTableIter *iter,
gpointer *key,
gpointer *value);
GLIB_AVAILABLE_IN_ALL
GHashTable* g_hash_table_iter_get_hash_table (GHashTableIter *iter);
GLIB_AVAILABLE_IN_ALL
void g_hash_table_iter_remove (GHashTableIter *iter);
GLIB_AVAILABLE_IN_2_30
void g_hash_table_iter_replace (GHashTableIter *iter,
gpointer value);
GLIB_AVAILABLE_IN_ALL
void g_hash_table_iter_steal (GHashTableIter *iter);
GLIB_AVAILABLE_IN_ALL
GHashTable* g_hash_table_ref (GHashTable *hash_table);
GLIB_AVAILABLE_IN_ALL
void g_hash_table_unref (GHashTable *hash_table);
#define g_hash_table_freeze(hash_table) ((void)0) GLIB_DEPRECATED_MACRO_IN_2_26
#define g_hash_table_thaw(hash_table) ((void)0) GLIB_DEPRECATED_MACRO_IN_2_26
/* Hash Functions
*/
GLIB_AVAILABLE_IN_ALL
gboolean g_str_equal (gconstpointer v1,
gconstpointer v2);
GLIB_AVAILABLE_IN_ALL
guint g_str_hash (gconstpointer v);
GLIB_AVAILABLE_IN_ALL
gboolean g_int_equal (gconstpointer v1,
gconstpointer v2);
GLIB_AVAILABLE_IN_ALL
guint g_int_hash (gconstpointer v);
GLIB_AVAILABLE_IN_ALL
gboolean g_int64_equal (gconstpointer v1,
gconstpointer v2);
GLIB_AVAILABLE_IN_ALL
guint g_int64_hash (gconstpointer v);
GLIB_AVAILABLE_IN_ALL
gboolean g_double_equal (gconstpointer v1,
gconstpointer v2);
GLIB_AVAILABLE_IN_ALL
guint g_double_hash (gconstpointer v);
GLIB_AVAILABLE_IN_ALL
guint g_direct_hash (gconstpointer v) G_GNUC_CONST;
GLIB_AVAILABLE_IN_ALL
gboolean g_direct_equal (gconstpointer v1,
gconstpointer v2) G_GNUC_CONST;
G_END_DECLS
#endif /* __G_HASH_H__ */

441
glib/ghmac.c Normal file
View file

@ -0,0 +1,441 @@
/* ghmac.h - data hashing functions
*
* Copyright (C) 2011 Collabora Ltd.
*
* 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/>.
*
* Author: Stef Walter <stefw@collabora.co.uk>
*/
#include "config.h"
#include <string.h>
#include "ghmac.h"
#include "glib/galloca.h"
#include "gatomic.h"
#include "gslice.h"
#include "gmem.h"
#include "gstrfuncs.h"
#include "gtestutils.h"
#include "gtypes.h"
#include "glibintl.h"
/**
* SECTION:hmac
* @title: Secure HMAC Digests
* @short_description: computes the HMAC for data
*
* HMACs should be used when producing a cookie or hash based on data
* and a key. Simple mechanisms for using SHA1 and other algorithms to
* digest a key and data together are vulnerable to various security
* issues.
* [HMAC](http://en.wikipedia.org/wiki/HMAC)
* uses algorithms like SHA1 in a secure way to produce a digest of a
* key and data.
*
* Both the key and data are arbitrary byte arrays of bytes or characters.
*
* Support for HMAC Digests has been added in GLib 2.30, and support for SHA-512
* in GLib 2.42. Support for SHA-384 was added in GLib 2.52.
*/
struct _GHmac
{
int ref_count;
GChecksumType digest_type;
GChecksum *digesti;
GChecksum *digesto;
};
/**
* g_hmac_new:
* @digest_type: the desired type of digest
* @key: (array length=key_len): the key for the HMAC
* @key_len: the length of the keys
*
* Creates a new #GHmac, using the digest algorithm @digest_type.
* If the @digest_type is not known, %NULL is returned.
* A #GHmac can be used to compute the HMAC of a key and an
* arbitrary binary blob, using different hashing algorithms.
*
* A #GHmac works by feeding a binary blob through g_hmac_update()
* until the data is complete; the digest can then be extracted
* using g_hmac_get_string(), which will return the checksum as a
* hexadecimal string; or g_hmac_get_digest(), which will return a
* array of raw bytes. Once either g_hmac_get_string() or
* g_hmac_get_digest() have been called on a #GHmac, the HMAC
* will be closed and it won't be possible to call g_hmac_update()
* on it anymore.
*
* Support for digests of type %G_CHECKSUM_SHA512 has been added in GLib 2.42.
* Support for %G_CHECKSUM_SHA384 was added in GLib 2.52.
*
* Returns: the newly created #GHmac, or %NULL.
* Use g_hmac_unref() to free the memory allocated by it.
*
* Since: 2.30
*/
GHmac *
g_hmac_new (GChecksumType digest_type,
const guchar *key,
gsize key_len)
{
GChecksum *checksum;
GHmac *hmac;
guchar *buffer;
guchar *pad;
gsize i, len;
gsize block_size;
checksum = g_checksum_new (digest_type);
g_return_val_if_fail (checksum != NULL, NULL);
switch (digest_type)
{
case G_CHECKSUM_MD5:
case G_CHECKSUM_SHA1:
block_size = 64; /* RFC 2104 */
break;
case G_CHECKSUM_SHA256:
block_size = 64; /* RFC 4868 */
break;
case G_CHECKSUM_SHA384:
case G_CHECKSUM_SHA512:
block_size = 128; /* RFC 4868 */
break;
default:
g_return_val_if_reached (NULL);
}
hmac = g_slice_new0 (GHmac);
hmac->ref_count = 1;
hmac->digest_type = digest_type;
hmac->digesti = checksum;
hmac->digesto = g_checksum_new (digest_type);
buffer = g_alloca0 (block_size);
pad = g_alloca (block_size);
/* If the key is too long, hash it */
if (key_len > block_size)
{
len = block_size;
g_checksum_update (hmac->digesti, key, key_len);
g_checksum_get_digest (hmac->digesti, buffer, &len);
g_checksum_reset (hmac->digesti);
}
/* Otherwise pad it with zeros */
else
{
memcpy (buffer, key, key_len);
}
/* First pad */
for (i = 0; i < block_size; i++)
pad[i] = 0x36 ^ buffer[i]; /* ipad value */
g_checksum_update (hmac->digesti, pad, block_size);
/* Second pad */
for (i = 0; i < block_size; i++)
pad[i] = 0x5c ^ buffer[i]; /* opad value */
g_checksum_update (hmac->digesto, pad, block_size);
return hmac;
}
/**
* g_hmac_copy:
* @hmac: the #GHmac to copy
*
* Copies a #GHmac. If @hmac has been closed, by calling
* g_hmac_get_string() or g_hmac_get_digest(), the copied
* HMAC will be closed as well.
*
* Returns: the copy of the passed #GHmac. Use g_hmac_unref()
* when finished using it.
*
* Since: 2.30
*/
GHmac *
g_hmac_copy (const GHmac *hmac)
{
GHmac *copy;
g_return_val_if_fail (hmac != NULL, NULL);
copy = g_slice_new (GHmac);
copy->ref_count = 1;
copy->digest_type = hmac->digest_type;
copy->digesti = g_checksum_copy (hmac->digesti);
copy->digesto = g_checksum_copy (hmac->digesto);
return copy;
}
/**
* g_hmac_ref:
* @hmac: a valid #GHmac
*
* Atomically increments the reference count of @hmac by one.
*
* This function is MT-safe and may be called from any thread.
*
* Returns: the passed in #GHmac.
*
* Since: 2.30
**/
GHmac *
g_hmac_ref (GHmac *hmac)
{
g_return_val_if_fail (hmac != NULL, NULL);
g_atomic_int_inc (&hmac->ref_count);
return hmac;
}
/**
* g_hmac_unref:
* @hmac: a #GHmac
*
* Atomically decrements the reference count of @hmac by one.
*
* If the reference count drops to 0, all keys and values will be
* destroyed, and all memory allocated by the hash table is released.
* This function is MT-safe and may be called from any thread.
* Frees the memory allocated for @hmac.
*
* Since: 2.30
*/
void
g_hmac_unref (GHmac *hmac)
{
g_return_if_fail (hmac != NULL);
if (g_atomic_int_dec_and_test (&hmac->ref_count))
{
g_checksum_free (hmac->digesti);
g_checksum_free (hmac->digesto);
g_slice_free (GHmac, hmac);
}
}
/**
* g_hmac_update:
* @hmac: a #GHmac
* @data: (array length=length): buffer used to compute the checksum
* @length: size of the buffer, or -1 if it is a nul-terminated string
*
* Feeds @data into an existing #GHmac.
*
* The HMAC must still be open, that is g_hmac_get_string() or
* g_hmac_get_digest() must not have been called on @hmac.
*
* Since: 2.30
*/
void
g_hmac_update (GHmac *hmac,
const guchar *data,
gssize length)
{
g_return_if_fail (hmac != NULL);
g_return_if_fail (length == 0 || data != NULL);
g_checksum_update (hmac->digesti, data, length);
}
/**
* g_hmac_get_string:
* @hmac: a #GHmac
*
* Gets the HMAC as a hexadecimal string.
*
* Once this function has been called the #GHmac can no longer be
* updated with g_hmac_update().
*
* The hexadecimal characters will be lower case.
*
* Returns: the hexadecimal representation of the HMAC. The
* returned string is owned by the HMAC and should not be modified
* or freed.
*
* Since: 2.30
*/
const gchar *
g_hmac_get_string (GHmac *hmac)
{
guint8 *buffer;
gsize digest_len;
g_return_val_if_fail (hmac != NULL, NULL);
digest_len = g_checksum_type_get_length (hmac->digest_type);
buffer = g_alloca (digest_len);
/* This is only called for its side-effect of updating hmac->digesto... */
g_hmac_get_digest (hmac, buffer, &digest_len);
/* ... because we get the string from the checksum rather than
* stringifying buffer ourselves
*/
return g_checksum_get_string (hmac->digesto);
}
/**
* g_hmac_get_digest:
* @hmac: a #GHmac
* @buffer: (array length=digest_len): output buffer
* @digest_len: (inout): an inout parameter. The caller initializes it to the
* size of @buffer. After the call it contains the length of the digest
*
* Gets the digest from @checksum as a raw binary array and places it
* into @buffer. The size of the digest depends on the type of checksum.
*
* Once this function has been called, the #GHmac is closed and can
* no longer be updated with g_checksum_update().
*
* Since: 2.30
*/
void
g_hmac_get_digest (GHmac *hmac,
guint8 *buffer,
gsize *digest_len)
{
gsize len;
g_return_if_fail (hmac != NULL);
len = g_checksum_type_get_length (hmac->digest_type);
g_return_if_fail (*digest_len >= len);
/* Use the same buffer, because we can :) */
g_checksum_get_digest (hmac->digesti, buffer, &len);
g_checksum_update (hmac->digesto, buffer, len);
g_checksum_get_digest (hmac->digesto, buffer, digest_len);
}
/**
* g_compute_hmac_for_data:
* @digest_type: a #GChecksumType to use for the HMAC
* @key: (array length=key_len): the key to use in the HMAC
* @key_len: the length of the key
* @data: (array length=length): binary blob to compute the HMAC of
* @length: length of @data
*
* Computes the HMAC for a binary @data of @length. This is a
* convenience wrapper for g_hmac_new(), g_hmac_get_string()
* and g_hmac_unref().
*
* The hexadecimal string returned will be in lower case.
*
* Returns: the HMAC of the binary data as a string in hexadecimal.
* The returned string should be freed with g_free() when done using it.
*
* Since: 2.30
*/
gchar *
g_compute_hmac_for_data (GChecksumType digest_type,
const guchar *key,
gsize key_len,
const guchar *data,
gsize length)
{
GHmac *hmac;
gchar *retval;
g_return_val_if_fail (length == 0 || data != NULL, NULL);
hmac = g_hmac_new (digest_type, key, key_len);
if (!hmac)
return NULL;
g_hmac_update (hmac, data, length);
retval = g_strdup (g_hmac_get_string (hmac));
g_hmac_unref (hmac);
return retval;
}
/**
* g_compute_hmac_for_bytes:
* @digest_type: a #GChecksumType to use for the HMAC
* @key: the key to use in the HMAC
* @data: binary blob to compute the HMAC of
*
* Computes the HMAC for a binary @data. This is a
* convenience wrapper for g_hmac_new(), g_hmac_get_string()
* and g_hmac_unref().
*
* The hexadecimal string returned will be in lower case.
*
* Returns: the HMAC of the binary data as a string in hexadecimal.
* The returned string should be freed with g_free() when done using it.
*
* Since: 2.50
*/
gchar *
g_compute_hmac_for_bytes (GChecksumType digest_type,
GBytes *key,
GBytes *data)
{
gconstpointer byte_data;
gsize length;
gconstpointer key_data;
gsize key_len;
g_return_val_if_fail (data != NULL, NULL);
g_return_val_if_fail (key != NULL, NULL);
byte_data = g_bytes_get_data (data, &length);
key_data = g_bytes_get_data (key, &key_len);
return g_compute_hmac_for_data (digest_type, key_data, key_len, byte_data, length);
}
/**
* g_compute_hmac_for_string:
* @digest_type: a #GChecksumType to use for the HMAC
* @key: (array length=key_len): the key to use in the HMAC
* @key_len: the length of the key
* @str: the string to compute the HMAC for
* @length: the length of the string, or -1 if the string is nul-terminated
*
* Computes the HMAC for a string.
*
* The hexadecimal string returned will be in lower case.
*
* Returns: the HMAC as a hexadecimal string.
* The returned string should be freed with g_free()
* when done using it.
*
* Since: 2.30
*/
gchar *
g_compute_hmac_for_string (GChecksumType digest_type,
const guchar *key,
gsize key_len,
const gchar *str,
gssize length)
{
g_return_val_if_fail (length == 0 || str != NULL, NULL);
if (length < 0)
length = strlen (str);
return g_compute_hmac_for_data (digest_type, key, key_len,
(const guchar *) str, length);
}

83
glib/ghmac.h Normal file
View file

@ -0,0 +1,83 @@
/* ghmac.h - secure data hashing
*
* Copyright (C) 2011 Stef Walter <stefw@collabora.co.uk>
*
* 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/>.
*/
#ifndef __G_HMAC_H__
#define __G_HMAC_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtypes.h>
#include "gchecksum.h"
G_BEGIN_DECLS
/**
* GHmac:
*
* An opaque structure representing a HMAC operation.
* To create a new GHmac, use g_hmac_new(). To free
* a GHmac, use g_hmac_unref().
*
* Since: 2.30
*/
typedef struct _GHmac GHmac;
GLIB_AVAILABLE_IN_2_30
GHmac * g_hmac_new (GChecksumType digest_type,
const guchar *key,
gsize key_len);
GLIB_AVAILABLE_IN_2_30
GHmac * g_hmac_copy (const GHmac *hmac);
GLIB_AVAILABLE_IN_2_30
GHmac * g_hmac_ref (GHmac *hmac);
GLIB_AVAILABLE_IN_2_30
void g_hmac_unref (GHmac *hmac);
GLIB_AVAILABLE_IN_2_30
void g_hmac_update (GHmac *hmac,
const guchar *data,
gssize length);
GLIB_AVAILABLE_IN_2_30
const gchar * g_hmac_get_string (GHmac *hmac);
GLIB_AVAILABLE_IN_2_30
void g_hmac_get_digest (GHmac *hmac,
guint8 *buffer,
gsize *digest_len);
GLIB_AVAILABLE_IN_2_30
gchar *g_compute_hmac_for_data (GChecksumType digest_type,
const guchar *key,
gsize key_len,
const guchar *data,
gsize length);
GLIB_AVAILABLE_IN_2_30
gchar *g_compute_hmac_for_string (GChecksumType digest_type,
const guchar *key,
gsize key_len,
const gchar *str,
gssize length);
GLIB_AVAILABLE_IN_2_50
gchar *g_compute_hmac_for_bytes (GChecksumType digest_type,
GBytes *key,
GBytes *data);
G_END_DECLS
#endif /* __G_CHECKSUM_H__ */

1050
glib/ghook.c Normal file

File diff suppressed because it is too large Load diff

202
glib/ghook.h Normal file
View file

@ -0,0 +1,202 @@
/* 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.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/.
*/
#ifndef __G_HOOK_H__
#define __G_HOOK_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gmem.h>
G_BEGIN_DECLS
/* --- typedefs --- */
typedef struct _GHook GHook;
typedef struct _GHookList GHookList;
typedef gint (*GHookCompareFunc) (GHook *new_hook,
GHook *sibling);
typedef gboolean (*GHookFindFunc) (GHook *hook,
gpointer data);
typedef void (*GHookMarshaller) (GHook *hook,
gpointer marshal_data);
typedef gboolean (*GHookCheckMarshaller) (GHook *hook,
gpointer marshal_data);
typedef void (*GHookFunc) (gpointer data);
typedef gboolean (*GHookCheckFunc) (gpointer data);
typedef void (*GHookFinalizeFunc) (GHookList *hook_list,
GHook *hook);
typedef enum
{
G_HOOK_FLAG_ACTIVE = 1 << 0,
G_HOOK_FLAG_IN_CALL = 1 << 1,
G_HOOK_FLAG_MASK = 0x0f
} GHookFlagMask;
#define G_HOOK_FLAG_USER_SHIFT (4)
/* --- structures --- */
struct _GHookList
{
gulong seq_id;
guint hook_size : 16;
guint is_setup : 1;
GHook *hooks;
gpointer dummy3;
GHookFinalizeFunc finalize_hook;
gpointer dummy[2];
};
struct _GHook
{
gpointer data;
GHook *next;
GHook *prev;
guint ref_count;
gulong hook_id;
guint flags;
gpointer func;
GDestroyNotify destroy;
};
/* --- macros --- */
#define G_HOOK(hook) ((GHook*) (hook))
#define G_HOOK_FLAGS(hook) (G_HOOK (hook)->flags)
#define G_HOOK_ACTIVE(hook) ((G_HOOK_FLAGS (hook) & \
G_HOOK_FLAG_ACTIVE) != 0)
#define G_HOOK_IN_CALL(hook) ((G_HOOK_FLAGS (hook) & \
G_HOOK_FLAG_IN_CALL) != 0)
#define G_HOOK_IS_VALID(hook) (G_HOOK (hook)->hook_id != 0 && \
(G_HOOK_FLAGS (hook) & \
G_HOOK_FLAG_ACTIVE))
#define G_HOOK_IS_UNLINKED(hook) (G_HOOK (hook)->next == NULL && \
G_HOOK (hook)->prev == NULL && \
G_HOOK (hook)->hook_id == 0 && \
G_HOOK (hook)->ref_count == 0)
/* --- prototypes --- */
/* callback maintenance functions */
GLIB_AVAILABLE_IN_ALL
void g_hook_list_init (GHookList *hook_list,
guint hook_size);
GLIB_AVAILABLE_IN_ALL
void g_hook_list_clear (GHookList *hook_list);
GLIB_AVAILABLE_IN_ALL
GHook* g_hook_alloc (GHookList *hook_list);
GLIB_AVAILABLE_IN_ALL
void g_hook_free (GHookList *hook_list,
GHook *hook);
GLIB_AVAILABLE_IN_ALL
GHook * g_hook_ref (GHookList *hook_list,
GHook *hook);
GLIB_AVAILABLE_IN_ALL
void g_hook_unref (GHookList *hook_list,
GHook *hook);
GLIB_AVAILABLE_IN_ALL
gboolean g_hook_destroy (GHookList *hook_list,
gulong hook_id);
GLIB_AVAILABLE_IN_ALL
void g_hook_destroy_link (GHookList *hook_list,
GHook *hook);
GLIB_AVAILABLE_IN_ALL
void g_hook_prepend (GHookList *hook_list,
GHook *hook);
GLIB_AVAILABLE_IN_ALL
void g_hook_insert_before (GHookList *hook_list,
GHook *sibling,
GHook *hook);
GLIB_AVAILABLE_IN_ALL
void g_hook_insert_sorted (GHookList *hook_list,
GHook *hook,
GHookCompareFunc func);
GLIB_AVAILABLE_IN_ALL
GHook* g_hook_get (GHookList *hook_list,
gulong hook_id);
GLIB_AVAILABLE_IN_ALL
GHook* g_hook_find (GHookList *hook_list,
gboolean need_valids,
GHookFindFunc func,
gpointer data);
GLIB_AVAILABLE_IN_ALL
GHook* g_hook_find_data (GHookList *hook_list,
gboolean need_valids,
gpointer data);
GLIB_AVAILABLE_IN_ALL
GHook* g_hook_find_func (GHookList *hook_list,
gboolean need_valids,
gpointer func);
GLIB_AVAILABLE_IN_ALL
GHook* g_hook_find_func_data (GHookList *hook_list,
gboolean need_valids,
gpointer func,
gpointer data);
/* return the first valid hook, and increment its reference count */
GLIB_AVAILABLE_IN_ALL
GHook* g_hook_first_valid (GHookList *hook_list,
gboolean may_be_in_call);
/* return the next valid hook with incremented reference count, and
* decrement the reference count of the original hook
*/
GLIB_AVAILABLE_IN_ALL
GHook* g_hook_next_valid (GHookList *hook_list,
GHook *hook,
gboolean may_be_in_call);
/* GHookCompareFunc implementation to insert hooks sorted by their id */
GLIB_AVAILABLE_IN_ALL
gint g_hook_compare_ids (GHook *new_hook,
GHook *sibling);
/* convenience macros */
#define g_hook_append( hook_list, hook ) \
g_hook_insert_before ((hook_list), NULL, (hook))
/* invoke all valid hooks with the (*GHookFunc) signature.
*/
GLIB_AVAILABLE_IN_ALL
void g_hook_list_invoke (GHookList *hook_list,
gboolean may_recurse);
/* invoke all valid hooks with the (*GHookCheckFunc) signature,
* and destroy the hook if FALSE is returned.
*/
GLIB_AVAILABLE_IN_ALL
void g_hook_list_invoke_check (GHookList *hook_list,
gboolean may_recurse);
/* invoke a marshaller on all valid hooks.
*/
GLIB_AVAILABLE_IN_ALL
void g_hook_list_marshal (GHookList *hook_list,
gboolean may_recurse,
GHookMarshaller marshaller,
gpointer marshal_data);
GLIB_AVAILABLE_IN_ALL
void g_hook_list_marshal_check (GHookList *hook_list,
gboolean may_recurse,
GHookCheckMarshaller marshaller,
gpointer marshal_data);
G_END_DECLS
#endif /* __G_HOOK_H__ */

888
glib/ghostutils.c Normal file
View file

@ -0,0 +1,888 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* GLIB - Library of useful routines for C programming
* Copyright (C) 2008 Red Hat, Inc.
*
* 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/>.
*/
#include "config.h"
#include "glibconfig.h"
#include <string.h>
#ifdef G_OS_UNIX
#include <unistd.h>
#endif
#include "ghostutils.h"
#include "garray.h"
#include "gmem.h"
#include "gstring.h"
#include "gstrfuncs.h"
#include "glibintl.h"
#ifdef G_PLATFORM_WIN32
#include <windows.h>
#endif
/**
* SECTION:ghostutils
* @short_description: Internet hostname utilities
*
* Functions for manipulating internet hostnames; in particular, for
* converting between Unicode and ASCII-encoded forms of
* Internationalized Domain Names (IDNs).
*
* The
* [Internationalized Domain Names for Applications (IDNA)](http://www.ietf.org/rfc/rfc3490.txt)
* standards allow for the use
* of Unicode domain names in applications, while providing
* backward-compatibility with the old ASCII-only DNS, by defining an
* ASCII-Compatible Encoding of any given Unicode name, which can be
* used with non-IDN-aware applications and protocols. (For example,
* "Παν語.org" maps to "xn--4wa8awb4637h.org".)
**/
#define IDNA_ACE_PREFIX "xn--"
#define IDNA_ACE_PREFIX_LEN 4
/* Punycode constants, from RFC 3492. */
#define PUNYCODE_BASE 36
#define PUNYCODE_TMIN 1
#define PUNYCODE_TMAX 26
#define PUNYCODE_SKEW 38
#define PUNYCODE_DAMP 700
#define PUNYCODE_INITIAL_BIAS 72
#define PUNYCODE_INITIAL_N 0x80
#define PUNYCODE_IS_BASIC(cp) ((guint)(cp) < 0x80)
/* Encode/decode a single base-36 digit */
static inline gchar
encode_digit (guint dig)
{
if (dig < 26)
return dig + 'a';
else
return dig - 26 + '0';
}
static inline guint
decode_digit (gchar dig)
{
if (dig >= 'A' && dig <= 'Z')
return dig - 'A';
else if (dig >= 'a' && dig <= 'z')
return dig - 'a';
else if (dig >= '0' && dig <= '9')
return dig - '0' + 26;
else
return G_MAXUINT;
}
/* Punycode bias adaptation algorithm, RFC 3492 section 6.1 */
static guint
adapt (guint delta,
guint numpoints,
gboolean firsttime)
{
guint k;
delta = firsttime ? delta / PUNYCODE_DAMP : delta / 2;
delta += delta / numpoints;
k = 0;
while (delta > ((PUNYCODE_BASE - PUNYCODE_TMIN) * PUNYCODE_TMAX) / 2)
{
delta /= PUNYCODE_BASE - PUNYCODE_TMIN;
k += PUNYCODE_BASE;
}
return k + ((PUNYCODE_BASE - PUNYCODE_TMIN + 1) * delta /
(delta + PUNYCODE_SKEW));
}
/* Punycode encoder, RFC 3492 section 6.3. The algorithm is
* sufficiently bizarre that it's not really worth trying to explain
* here.
*/
static gboolean
punycode_encode (const gchar *input_utf8,
gsize input_utf8_length,
GString *output)
{
guint delta, handled_chars, num_basic_chars, bias, j, q, k, t, digit;
gunichar n, m, *input;
glong written_chars;
gsize input_length;
gboolean success = FALSE;
/* Convert from UTF-8 to Unicode code points */
input = g_utf8_to_ucs4 (input_utf8, input_utf8_length, NULL,
&written_chars, NULL);
if (!input)
return FALSE;
input_length = (gsize) (written_chars > 0 ? written_chars : 0);
/* Copy basic chars */
for (j = num_basic_chars = 0; j < input_length; j++)
{
if (PUNYCODE_IS_BASIC (input[j]))
{
g_string_append_c (output, g_ascii_tolower (input[j]));
num_basic_chars++;
}
}
if (num_basic_chars)
g_string_append_c (output, '-');
handled_chars = num_basic_chars;
/* Encode non-basic chars */
delta = 0;
bias = PUNYCODE_INITIAL_BIAS;
n = PUNYCODE_INITIAL_N;
while (handled_chars < input_length)
{
/* let m = the minimum {non-basic} code point >= n in the input */
for (m = G_MAXUINT, j = 0; j < input_length; j++)
{
if (input[j] >= n && input[j] < m)
m = input[j];
}
if (m - n > (G_MAXUINT - delta) / (handled_chars + 1))
goto fail;
delta += (m - n) * (handled_chars + 1);
n = m;
for (j = 0; j < input_length; j++)
{
if (input[j] < n)
{
if (++delta == 0)
goto fail;
}
else if (input[j] == n)
{
q = delta;
for (k = PUNYCODE_BASE; ; k += PUNYCODE_BASE)
{
if (k <= bias)
t = PUNYCODE_TMIN;
else if (k >= bias + PUNYCODE_TMAX)
t = PUNYCODE_TMAX;
else
t = k - bias;
if (q < t)
break;
digit = t + (q - t) % (PUNYCODE_BASE - t);
g_string_append_c (output, encode_digit (digit));
q = (q - t) / (PUNYCODE_BASE - t);
}
g_string_append_c (output, encode_digit (q));
bias = adapt (delta, handled_chars + 1, handled_chars == num_basic_chars);
delta = 0;
handled_chars++;
}
}
delta++;
n++;
}
success = TRUE;
fail:
g_free (input);
return success;
}
/* From RFC 3454, Table B.1 */
#define idna_is_junk(ch) ((ch) == 0x00AD || (ch) == 0x1806 || (ch) == 0x200B || (ch) == 0x2060 || (ch) == 0xFEFF || (ch) == 0x034F || (ch) == 0x180B || (ch) == 0x180C || (ch) == 0x180D || (ch) == 0x200C || (ch) == 0x200D || ((ch) >= 0xFE00 && (ch) <= 0xFE0F))
/* Scan @str for "junk" and return a cleaned-up string if any junk
* is found. Else return %NULL.
*/
static gchar *
remove_junk (const gchar *str,
gint len)
{
GString *cleaned = NULL;
const gchar *p;
gunichar ch;
for (p = str; len == -1 ? *p : p < str + len; p = g_utf8_next_char (p))
{
ch = g_utf8_get_char (p);
if (idna_is_junk (ch))
{
if (!cleaned)
{
cleaned = g_string_new (NULL);
g_string_append_len (cleaned, str, p - str);
}
}
else if (cleaned)
g_string_append_unichar (cleaned, ch);
}
if (cleaned)
return g_string_free (cleaned, FALSE);
else
return NULL;
}
static inline gboolean
contains_uppercase_letters (const gchar *str,
gint len)
{
const gchar *p;
for (p = str; len == -1 ? *p : p < str + len; p = g_utf8_next_char (p))
{
if (g_unichar_isupper (g_utf8_get_char (p)))
return TRUE;
}
return FALSE;
}
static inline gboolean
contains_non_ascii (const gchar *str,
gint len)
{
const gchar *p;
for (p = str; len == -1 ? *p : p < str + len; p++)
{
if ((guchar)*p > 0x80)
return TRUE;
}
return FALSE;
}
/* RFC 3454, Appendix C. ish. */
static inline gboolean
idna_is_prohibited (gunichar ch)
{
switch (g_unichar_type (ch))
{
case G_UNICODE_CONTROL:
case G_UNICODE_FORMAT:
case G_UNICODE_UNASSIGNED:
case G_UNICODE_PRIVATE_USE:
case G_UNICODE_SURROGATE:
case G_UNICODE_LINE_SEPARATOR:
case G_UNICODE_PARAGRAPH_SEPARATOR:
case G_UNICODE_SPACE_SEPARATOR:
return TRUE;
case G_UNICODE_OTHER_SYMBOL:
if (ch == 0xFFFC || ch == 0xFFFD ||
(ch >= 0x2FF0 && ch <= 0x2FFB))
return TRUE;
return FALSE;
case G_UNICODE_NON_SPACING_MARK:
if (ch == 0x0340 || ch == 0x0341)
return TRUE;
return FALSE;
default:
return FALSE;
}
}
/* RFC 3491 IDN cleanup algorithm. */
static gchar *
nameprep (const gchar *hostname,
gint len,
gboolean *is_unicode)
{
gchar *name, *tmp = NULL, *p;
/* It would be nice if we could do this without repeatedly
* allocating strings and converting back and forth between
* gunichars and UTF-8... The code does at least avoid doing most of
* the sub-operations when they would just be equivalent to a
* g_strdup().
*/
/* Remove presentation-only characters */
name = remove_junk (hostname, len);
if (name)
{
tmp = name;
len = -1;
}
else
name = (gchar *)hostname;
/* Convert to lowercase */
if (contains_uppercase_letters (name, len))
{
name = g_utf8_strdown (name, len);
g_free (tmp);
tmp = name;
len = -1;
}
/* If there are no UTF8 characters, we're done. */
if (!contains_non_ascii (name, len))
{
*is_unicode = FALSE;
if (name == (gchar *)hostname)
return len == -1 ? g_strdup (hostname) : g_strndup (hostname, len);
else
return name;
}
*is_unicode = TRUE;
/* Normalize */
name = g_utf8_normalize (name, len, G_NORMALIZE_NFKC);
g_free (tmp);
tmp = name;
if (!name)
return NULL;
/* KC normalization may have created more capital letters (eg,
* angstrom -> capital A with ring). So we have to lowercasify a
* second time. (This is more-or-less how the nameprep algorithm
* does it. If tolower(nfkc(tolower(X))) is guaranteed to be the
* same as tolower(nfkc(X)), then we could skip the first tolower,
* but I'm not sure it is.)
*/
if (contains_uppercase_letters (name, -1))
{
name = g_utf8_strdown (name, -1);
g_free (tmp);
tmp = name;
}
/* Check for prohibited characters */
for (p = name; *p; p = g_utf8_next_char (p))
{
if (idna_is_prohibited (g_utf8_get_char (p)))
{
name = NULL;
g_free (tmp);
goto done;
}
}
/* FIXME: We're supposed to verify certain constraints on bidi
* characters, but glib does not appear to have that information.
*/
done:
return name;
}
/* RFC 3490, section 3.1 says '.', 0x3002, 0xFF0E, and 0xFF61 count as
* label-separating dots. @str must be '\0'-terminated.
*/
#define idna_is_dot(str) ( \
((guchar)(str)[0] == '.') || \
((guchar)(str)[0] == 0xE3 && (guchar)(str)[1] == 0x80 && (guchar)(str)[2] == 0x82) || \
((guchar)(str)[0] == 0xEF && (guchar)(str)[1] == 0xBC && (guchar)(str)[2] == 0x8E) || \
((guchar)(str)[0] == 0xEF && (guchar)(str)[1] == 0xBD && (guchar)(str)[2] == 0xA1) )
static const gchar *
idna_end_of_label (const gchar *str)
{
for (; *str; str = g_utf8_next_char (str))
{
if (idna_is_dot (str))
return str;
}
return str;
}
static gsize
get_hostname_max_length_bytes (void)
{
#if defined(G_OS_WIN32)
wchar_t tmp[MAX_COMPUTERNAME_LENGTH];
return sizeof (tmp) / sizeof (tmp[0]);
#elif defined(_SC_HOST_NAME_MAX)
glong max = sysconf (_SC_HOST_NAME_MAX);
if (max > 0)
return (gsize) max;
#ifdef HOST_NAME_MAX
return HOST_NAME_MAX;
#else
return _POSIX_HOST_NAME_MAX;
#endif /* HOST_NAME_MAX */
#else
/* Fallback to some reasonable value
* See https://stackoverflow.com/questions/8724954/what-is-the-maximum-number-of-characters-for-a-host-name-in-unix/28918017#28918017 */
return 255;
#endif
}
/* Returns %TRUE if `strlen (str) > comparison_length`, but without actually
* running `strlen(str)`, as that would take a very long time for long
* (untrusted) input strings. */
static gboolean
strlen_greater_than (const gchar *str,
gsize comparison_length)
{
gsize i;
for (i = 0; str[i] != '\0'; i++)
if (i > comparison_length)
return TRUE;
return FALSE;
}
/**
* g_hostname_to_ascii:
* @hostname: a valid UTF-8 or ASCII hostname
*
* Converts @hostname to its canonical ASCII form; an ASCII-only
* string containing no uppercase letters and not ending with a
* trailing dot.
*
* Returns: (nullable) (transfer full): an ASCII hostname, which must be freed,
* or %NULL if @hostname is in some way invalid.
*
* Since: 2.22
**/
gchar *
g_hostname_to_ascii (const gchar *hostname)
{
gchar *name, *label, *p;
GString *out;
gssize llen, oldlen;
gboolean unicode;
gsize hostname_max_length_bytes = get_hostname_max_length_bytes ();
/* Do an initial check on the hostname length, as overlong hostnames take a
* long time in the IDN cleanup algorithm in nameprep(). The ultimate
* restriction is that the IDN-decoded (i.e. pure ASCII) hostname cannot be
* longer than 255 bytes. Thats the least restrictive limit on hostname
* length of all the ways hostnames can be interpreted. Typically, the
* hostname will be an FQDN, which is limited to 253 bytes long. POSIX
* hostnames are limited to `get_hostname_max_length_bytes()` (typically 255
* bytes).
*
* See https://stackoverflow.com/a/28918017/2931197
*
* Its possible for a hostname to be %-encoded, in which case its decoded
* length will be as much as 3× shorter.
*
* Its also possible for a hostname to use overlong UTF-8 encodings, in which
* case its decoded length will be as much as 4× shorter.
*
* Note: This check is not intended as an absolute guarantee that a hostname
* is the right length and will be accepted by other systems. Its intended to
* stop wildly-invalid hostnames from taking forever in nameprep().
*/
if (hostname_max_length_bytes <= G_MAXSIZE / 4 &&
strlen_greater_than (hostname, 4 * MAX (255, hostname_max_length_bytes)))
return NULL;
label = name = nameprep (hostname, -1, &unicode);
if (!name || !unicode)
return name;
out = g_string_new (NULL);
do
{
unicode = FALSE;
for (p = label; *p && !idna_is_dot (p); p++)
{
if ((guchar)*p > 0x80)
unicode = TRUE;
}
oldlen = out->len;
llen = p - label;
if (unicode)
{
if (!strncmp (label, IDNA_ACE_PREFIX, IDNA_ACE_PREFIX_LEN))
goto fail;
g_string_append (out, IDNA_ACE_PREFIX);
if (!punycode_encode (label, llen, out))
goto fail;
}
else
g_string_append_len (out, label, llen);
if (out->len - oldlen > 63)
goto fail;
label += llen;
if (*label)
label = g_utf8_next_char (label);
if (*label)
g_string_append_c (out, '.');
}
while (*label);
g_free (name);
return g_string_free (out, FALSE);
fail:
g_free (name);
g_string_free (out, TRUE);
return NULL;
}
/**
* g_hostname_is_non_ascii:
* @hostname: a hostname
*
* Tests if @hostname contains Unicode characters. If this returns
* %TRUE, you need to encode the hostname with g_hostname_to_ascii()
* before using it in non-IDN-aware contexts.
*
* Note that a hostname might contain a mix of encoded and unencoded
* segments, and so it is possible for g_hostname_is_non_ascii() and
* g_hostname_is_ascii_encoded() to both return %TRUE for a name.
*
* Returns: %TRUE if @hostname contains any non-ASCII characters
*
* Since: 2.22
**/
gboolean
g_hostname_is_non_ascii (const gchar *hostname)
{
return contains_non_ascii (hostname, -1);
}
/* Punycode decoder, RFC 3492 section 6.2. As with punycode_encode(),
* read the RFC if you want to understand what this is actually doing.
*/
static gboolean
punycode_decode (const gchar *input,
gsize input_length,
GString *output)
{
GArray *output_chars;
gunichar n;
guint i, bias;
guint oldi, w, k, digit, t;
const gchar *split;
n = PUNYCODE_INITIAL_N;
i = 0;
bias = PUNYCODE_INITIAL_BIAS;
split = input + input_length - 1;
while (split > input && *split != '-')
split--;
if (split > input)
{
output_chars = g_array_sized_new (FALSE, FALSE, sizeof (gunichar),
split - input);
input_length -= (split - input) + 1;
while (input < split)
{
gunichar ch = (gunichar)*input++;
if (!PUNYCODE_IS_BASIC (ch))
goto fail;
g_array_append_val (output_chars, ch);
}
input++;
}
else
output_chars = g_array_new (FALSE, FALSE, sizeof (gunichar));
while (input_length)
{
oldi = i;
w = 1;
for (k = PUNYCODE_BASE; ; k += PUNYCODE_BASE)
{
if (!input_length--)
goto fail;
digit = decode_digit (*input++);
if (digit >= PUNYCODE_BASE)
goto fail;
if (digit > (G_MAXUINT - i) / w)
goto fail;
i += digit * w;
if (k <= bias)
t = PUNYCODE_TMIN;
else if (k >= bias + PUNYCODE_TMAX)
t = PUNYCODE_TMAX;
else
t = k - bias;
if (digit < t)
break;
if (w > G_MAXUINT / (PUNYCODE_BASE - t))
goto fail;
w *= (PUNYCODE_BASE - t);
}
bias = adapt (i - oldi, output_chars->len + 1, oldi == 0);
if (i / (output_chars->len + 1) > G_MAXUINT - n)
goto fail;
n += i / (output_chars->len + 1);
i %= (output_chars->len + 1);
g_array_insert_val (output_chars, i++, n);
}
for (i = 0; i < output_chars->len; i++)
g_string_append_unichar (output, g_array_index (output_chars, gunichar, i));
g_array_free (output_chars, TRUE);
return TRUE;
fail:
g_array_free (output_chars, TRUE);
return FALSE;
}
/**
* g_hostname_to_unicode:
* @hostname: a valid UTF-8 or ASCII hostname
*
* Converts @hostname to its canonical presentation form; a UTF-8
* string in Unicode normalization form C, containing no uppercase
* letters, no forbidden characters, and no ASCII-encoded segments,
* and not ending with a trailing dot.
*
* Of course if @hostname is not an internationalized hostname, then
* the canonical presentation form will be entirely ASCII.
*
* Returns: (nullable) (transfer full): a UTF-8 hostname, which must be freed,
* or %NULL if @hostname is in some way invalid.
*
* Since: 2.22
**/
gchar *
g_hostname_to_unicode (const gchar *hostname)
{
GString *out;
gssize llen;
gsize hostname_max_length_bytes = get_hostname_max_length_bytes ();
/* See the comment at the top of g_hostname_to_ascii(). */
if (hostname_max_length_bytes <= G_MAXSIZE / 4 &&
strlen_greater_than (hostname, 4 * MAX (255, hostname_max_length_bytes)))
return NULL;
out = g_string_new (NULL);
do
{
llen = idna_end_of_label (hostname) - hostname;
if (!g_ascii_strncasecmp (hostname, IDNA_ACE_PREFIX, IDNA_ACE_PREFIX_LEN))
{
hostname += IDNA_ACE_PREFIX_LEN;
llen -= IDNA_ACE_PREFIX_LEN;
if (!punycode_decode (hostname, llen, out))
{
g_string_free (out, TRUE);
return NULL;
}
}
else
{
gboolean unicode;
gchar *canonicalized = nameprep (hostname, llen, &unicode);
if (!canonicalized)
{
g_string_free (out, TRUE);
return NULL;
}
g_string_append (out, canonicalized);
g_free (canonicalized);
}
hostname += llen;
if (*hostname)
hostname = g_utf8_next_char (hostname);
if (*hostname)
g_string_append_c (out, '.');
}
while (*hostname);
return g_string_free (out, FALSE);
}
/**
* g_hostname_is_ascii_encoded:
* @hostname: a hostname
*
* Tests if @hostname contains segments with an ASCII-compatible
* encoding of an Internationalized Domain Name. If this returns
* %TRUE, you should decode the hostname with g_hostname_to_unicode()
* before displaying it to the user.
*
* Note that a hostname might contain a mix of encoded and unencoded
* segments, and so it is possible for g_hostname_is_non_ascii() and
* g_hostname_is_ascii_encoded() to both return %TRUE for a name.
*
* Returns: %TRUE if @hostname contains any ASCII-encoded
* segments.
*
* Since: 2.22
**/
gboolean
g_hostname_is_ascii_encoded (const gchar *hostname)
{
while (1)
{
if (!g_ascii_strncasecmp (hostname, IDNA_ACE_PREFIX, IDNA_ACE_PREFIX_LEN))
return TRUE;
hostname = idna_end_of_label (hostname);
if (*hostname)
hostname = g_utf8_next_char (hostname);
if (!*hostname)
return FALSE;
}
}
/**
* g_hostname_is_ip_address:
* @hostname: a hostname (or IP address in string form)
*
* Tests if @hostname is the string form of an IPv4 or IPv6 address.
* (Eg, "192.168.0.1".)
*
* Since 2.66, IPv6 addresses with a zone-id are accepted (RFC6874).
*
* Returns: %TRUE if @hostname is an IP address
*
* Since: 2.22
**/
gboolean
g_hostname_is_ip_address (const gchar *hostname)
{
gchar *p, *end;
gint nsegments, octet;
/* On Linux we could implement this using inet_pton, but the Windows
* equivalent of that requires linking against winsock, so we just
* figure this out ourselves. Tested by tests/hostutils.c.
*/
p = (char *)hostname;
if (strchr (p, ':'))
{
gboolean skipped;
/* If it contains a ':', it's an IPv6 address (assuming it's an
* IP address at all). This consists of eight ':'-separated
* segments, each containing a 1-4 digit hex number, except that
* optionally: (a) the last two segments can be replaced by an
* IPv4 address, and (b) a single span of 1 to 8 "0000" segments
* can be replaced with just "::".
*/
nsegments = 0;
skipped = FALSE;
while (*p && *p != '%' && nsegments < 8)
{
/* Each segment after the first must be preceded by a ':'.
* (We also handle half of the "string starts with ::" case
* here.)
*/
if (p != (char *)hostname || (p[0] == ':' && p[1] == ':'))
{
if (*p != ':')
return FALSE;
p++;
}
/* If there's another ':', it means we're skipping some segments */
if (*p == ':' && !skipped)
{
skipped = TRUE;
nsegments++;
/* Handle the "string ends with ::" case */
if (!p[1])
p++;
continue;
}
/* Read the segment, make sure it's valid. */
for (end = p; g_ascii_isxdigit (*end); end++)
;
if (end == p || end > p + 4)
return FALSE;
if (*end == '.')
{
if ((nsegments == 6 && !skipped) || (nsegments <= 6 && skipped))
goto parse_ipv4;
else
return FALSE;
}
nsegments++;
p = end;
}
return (!*p || (p[0] == '%' && p[1])) && (nsegments == 8 || skipped);
}
parse_ipv4:
/* Parse IPv4: N.N.N.N, where each N <= 255 and doesn't have leading 0s. */
for (nsegments = 0; nsegments < 4; nsegments++)
{
if (nsegments != 0)
{
if (*p != '.')
return FALSE;
p++;
}
/* Check the segment; a little tricker than the IPv6 case since
* we can't allow extra leading 0s, and we can't assume that all
* strings of valid length are within range.
*/
octet = 0;
if (*p == '0')
end = p + 1;
else
{
for (end = p; g_ascii_isdigit (*end); end++)
{
octet = 10 * octet + (*end - '0');
if (octet > 255)
break;
}
}
if (end == p || end > p + 3 || octet > 255)
return FALSE;
p = end;
}
/* If there's nothing left to parse, then it's ok. */
return !*p;
}

43
glib/ghostutils.h Normal file
View file

@ -0,0 +1,43 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 2008 Red Hat, Inc.
*
* 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/>.
*/
#ifndef __G_HOST_UTILS_H__
#define __G_HOST_UTILS_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gtypes.h>
G_BEGIN_DECLS
GLIB_AVAILABLE_IN_ALL
gboolean g_hostname_is_non_ascii (const gchar *hostname);
GLIB_AVAILABLE_IN_ALL
gboolean g_hostname_is_ascii_encoded (const gchar *hostname);
GLIB_AVAILABLE_IN_ALL
gboolean g_hostname_is_ip_address (const gchar *hostname);
GLIB_AVAILABLE_IN_ALL
gchar *g_hostname_to_ascii (const gchar *hostname);
GLIB_AVAILABLE_IN_ALL
gchar *g_hostname_to_unicode (const gchar *hostname);
G_END_DECLS
#endif /* __G_HOST_UTILS_H__ */

36
glib/gi18n-lib.h Normal file
View file

@ -0,0 +1,36 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997, 2002 Peter Mattis, Red Hat, Inc.
*
* 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/>.
*/
#ifndef __G_I18N_LIB_H__
#define __G_I18N_LIB_H__
#include <glib.h>
#include <libintl.h>
#include <string.h>
#ifndef GETTEXT_PACKAGE
#error You must define GETTEXT_PACKAGE before including gi18n-lib.h. Did you forget to include config.h?
#endif
#define _(String) ((char *) g_dgettext (GETTEXT_PACKAGE, String))
#define Q_(String) g_dpgettext (GETTEXT_PACKAGE, String, 0)
#define N_(String) (String)
#define C_(Context,String) g_dpgettext (GETTEXT_PACKAGE, Context "\004" String, strlen (Context) + 1)
#define NC_(Context, String) (String)
#endif /* __G_I18N_LIB_H__ */

32
glib/gi18n.h Normal file
View file

@ -0,0 +1,32 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997, 2002 Peter Mattis, Red Hat, Inc.
*
* 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/>.
*/
#ifndef __G_I18N_H__
#define __G_I18N_H__
#include <glib.h>
#include <libintl.h>
#include <string.h>
#define _(String) gettext (String)
#define Q_(String) g_dpgettext (NULL, String, 0)
#define N_(String) (String)
#define C_(Context,String) g_dpgettext (NULL, Context "\004" String, strlen (Context) + 1)
#define NC_(Context, String) (String)
#endif /* __G_I18N_H__ */

2581
glib/giochannel.c Normal file

File diff suppressed because it is too large Load diff

404
glib/giochannel.h Normal file
View file

@ -0,0 +1,404 @@
/* 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.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/.
*/
#ifndef __G_IOCHANNEL_H__
#define __G_IOCHANNEL_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gconvert.h>
#include <glib/gmain.h>
#include <glib/gstring.h>
G_BEGIN_DECLS
/* GIOChannel
*/
typedef struct _GIOChannel GIOChannel;
typedef struct _GIOFuncs GIOFuncs;
typedef enum
{
G_IO_ERROR_NONE,
G_IO_ERROR_AGAIN,
G_IO_ERROR_INVAL,
G_IO_ERROR_UNKNOWN
} GIOError;
#define G_IO_CHANNEL_ERROR g_io_channel_error_quark()
typedef enum
{
/* Derived from errno */
G_IO_CHANNEL_ERROR_FBIG,
G_IO_CHANNEL_ERROR_INVAL,
G_IO_CHANNEL_ERROR_IO,
G_IO_CHANNEL_ERROR_ISDIR,
G_IO_CHANNEL_ERROR_NOSPC,
G_IO_CHANNEL_ERROR_NXIO,
G_IO_CHANNEL_ERROR_OVERFLOW,
G_IO_CHANNEL_ERROR_PIPE,
/* Other */
G_IO_CHANNEL_ERROR_FAILED
} GIOChannelError;
typedef enum
{
G_IO_STATUS_ERROR,
G_IO_STATUS_NORMAL,
G_IO_STATUS_EOF,
G_IO_STATUS_AGAIN
} GIOStatus;
typedef enum
{
G_SEEK_CUR,
G_SEEK_SET,
G_SEEK_END
} GSeekType;
typedef enum
{
G_IO_FLAG_APPEND = 1 << 0,
G_IO_FLAG_NONBLOCK = 1 << 1,
G_IO_FLAG_IS_READABLE = 1 << 2, /* Read only flag */
G_IO_FLAG_IS_WRITABLE = 1 << 3, /* Read only flag */
G_IO_FLAG_IS_WRITEABLE = 1 << 3, /* Misspelling in 2.29.10 and earlier */
G_IO_FLAG_IS_SEEKABLE = 1 << 4, /* Read only flag */
G_IO_FLAG_MASK = (1 << 5) - 1,
G_IO_FLAG_GET_MASK = G_IO_FLAG_MASK,
G_IO_FLAG_SET_MASK = G_IO_FLAG_APPEND | G_IO_FLAG_NONBLOCK
} GIOFlags;
struct _GIOChannel
{
/*< private >*/
gint ref_count;
GIOFuncs *funcs;
gchar *encoding;
GIConv read_cd;
GIConv write_cd;
gchar *line_term; /* String which indicates the end of a line of text */
guint line_term_len; /* So we can have null in the line term */
gsize buf_size;
GString *read_buf; /* Raw data from the channel */
GString *encoded_read_buf; /* Channel data converted to UTF-8 */
GString *write_buf; /* Data ready to be written to the file */
gchar partial_write_buf[6]; /* UTF-8 partial characters, null terminated */
/* Group the flags together, immediately after partial_write_buf, to save memory */
guint use_buffer : 1; /* The encoding uses the buffers */
guint do_encode : 1; /* The encoding uses the GIConv coverters */
guint close_on_unref : 1; /* Close the channel on final unref */
guint is_readable : 1; /* Cached GIOFlag */
guint is_writeable : 1; /* ditto */
guint is_seekable : 1; /* ditto */
gpointer reserved1;
gpointer reserved2;
};
typedef gboolean (*GIOFunc) (GIOChannel *source,
GIOCondition condition,
gpointer data);
struct _GIOFuncs
{
GIOStatus (*io_read) (GIOChannel *channel,
gchar *buf,
gsize count,
gsize *bytes_read,
GError **err);
GIOStatus (*io_write) (GIOChannel *channel,
const gchar *buf,
gsize count,
gsize *bytes_written,
GError **err);
GIOStatus (*io_seek) (GIOChannel *channel,
gint64 offset,
GSeekType type,
GError **err);
GIOStatus (*io_close) (GIOChannel *channel,
GError **err);
GSource* (*io_create_watch) (GIOChannel *channel,
GIOCondition condition);
void (*io_free) (GIOChannel *channel);
GIOStatus (*io_set_flags) (GIOChannel *channel,
GIOFlags flags,
GError **err);
GIOFlags (*io_get_flags) (GIOChannel *channel);
};
GLIB_AVAILABLE_IN_ALL
void g_io_channel_init (GIOChannel *channel);
GLIB_AVAILABLE_IN_ALL
GIOChannel *g_io_channel_ref (GIOChannel *channel);
GLIB_AVAILABLE_IN_ALL
void g_io_channel_unref (GIOChannel *channel);
GLIB_DEPRECATED_FOR(g_io_channel_read_chars)
GIOError g_io_channel_read (GIOChannel *channel,
gchar *buf,
gsize count,
gsize *bytes_read);
GLIB_DEPRECATED_FOR(g_io_channel_write_chars)
GIOError g_io_channel_write (GIOChannel *channel,
const gchar *buf,
gsize count,
gsize *bytes_written);
GLIB_DEPRECATED_FOR(g_io_channel_seek_position)
GIOError g_io_channel_seek (GIOChannel *channel,
gint64 offset,
GSeekType type);
GLIB_DEPRECATED_FOR(g_io_channel_shutdown)
void g_io_channel_close (GIOChannel *channel);
GLIB_AVAILABLE_IN_ALL
GIOStatus g_io_channel_shutdown (GIOChannel *channel,
gboolean flush,
GError **err);
GLIB_AVAILABLE_IN_ALL
guint g_io_add_watch_full (GIOChannel *channel,
gint priority,
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify);
GLIB_AVAILABLE_IN_ALL
GSource * g_io_create_watch (GIOChannel *channel,
GIOCondition condition);
GLIB_AVAILABLE_IN_ALL
guint g_io_add_watch (GIOChannel *channel,
GIOCondition condition,
GIOFunc func,
gpointer user_data);
/* character encoding conversion involved functions.
*/
GLIB_AVAILABLE_IN_ALL
void g_io_channel_set_buffer_size (GIOChannel *channel,
gsize size);
GLIB_AVAILABLE_IN_ALL
gsize g_io_channel_get_buffer_size (GIOChannel *channel);
GLIB_AVAILABLE_IN_ALL
GIOCondition g_io_channel_get_buffer_condition (GIOChannel *channel);
GLIB_AVAILABLE_IN_ALL
GIOStatus g_io_channel_set_flags (GIOChannel *channel,
GIOFlags flags,
GError **error);
GLIB_AVAILABLE_IN_ALL
GIOFlags g_io_channel_get_flags (GIOChannel *channel);
GLIB_AVAILABLE_IN_ALL
void g_io_channel_set_line_term (GIOChannel *channel,
const gchar *line_term,
gint length);
GLIB_AVAILABLE_IN_ALL
const gchar * g_io_channel_get_line_term (GIOChannel *channel,
gint *length);
GLIB_AVAILABLE_IN_ALL
void g_io_channel_set_buffered (GIOChannel *channel,
gboolean buffered);
GLIB_AVAILABLE_IN_ALL
gboolean g_io_channel_get_buffered (GIOChannel *channel);
GLIB_AVAILABLE_IN_ALL
GIOStatus g_io_channel_set_encoding (GIOChannel *channel,
const gchar *encoding,
GError **error);
GLIB_AVAILABLE_IN_ALL
const gchar * g_io_channel_get_encoding (GIOChannel *channel);
GLIB_AVAILABLE_IN_ALL
void g_io_channel_set_close_on_unref (GIOChannel *channel,
gboolean do_close);
GLIB_AVAILABLE_IN_ALL
gboolean g_io_channel_get_close_on_unref (GIOChannel *channel);
GLIB_AVAILABLE_IN_ALL
GIOStatus g_io_channel_flush (GIOChannel *channel,
GError **error);
GLIB_AVAILABLE_IN_ALL
GIOStatus g_io_channel_read_line (GIOChannel *channel,
gchar **str_return,
gsize *length,
gsize *terminator_pos,
GError **error);
GLIB_AVAILABLE_IN_ALL
GIOStatus g_io_channel_read_line_string (GIOChannel *channel,
GString *buffer,
gsize *terminator_pos,
GError **error);
GLIB_AVAILABLE_IN_ALL
GIOStatus g_io_channel_read_to_end (GIOChannel *channel,
gchar **str_return,
gsize *length,
GError **error);
GLIB_AVAILABLE_IN_ALL
GIOStatus g_io_channel_read_chars (GIOChannel *channel,
gchar *buf,
gsize count,
gsize *bytes_read,
GError **error);
GLIB_AVAILABLE_IN_ALL
GIOStatus g_io_channel_read_unichar (GIOChannel *channel,
gunichar *thechar,
GError **error);
GLIB_AVAILABLE_IN_ALL
GIOStatus g_io_channel_write_chars (GIOChannel *channel,
const gchar *buf,
gssize count,
gsize *bytes_written,
GError **error);
GLIB_AVAILABLE_IN_ALL
GIOStatus g_io_channel_write_unichar (GIOChannel *channel,
gunichar thechar,
GError **error);
GLIB_AVAILABLE_IN_ALL
GIOStatus g_io_channel_seek_position (GIOChannel *channel,
gint64 offset,
GSeekType type,
GError **error);
GLIB_AVAILABLE_IN_ALL
GIOChannel* g_io_channel_new_file (const gchar *filename,
const gchar *mode,
GError **error);
/* Error handling */
GLIB_AVAILABLE_IN_ALL
GQuark g_io_channel_error_quark (void);
GLIB_AVAILABLE_IN_ALL
GIOChannelError g_io_channel_error_from_errno (gint en);
/* On Unix, IO channels created with this function for any file
* descriptor or socket.
*
* On Win32, this can be used either for files opened with the MSVCRT
* (the Microsoft run-time C library) _open() or _pipe, including file
* descriptors 0, 1 and 2 (corresponding to stdin, stdout and stderr),
* or for Winsock SOCKETs. If the parameter is a legal file
* descriptor, it is assumed to be such, otherwise it should be a
* SOCKET. This relies on SOCKETs and file descriptors not
* overlapping. If you want to be certain, call either
* g_io_channel_win32_new_fd() or g_io_channel_win32_new_socket()
* instead as appropriate.
*
* The term file descriptor as used in the context of Win32 refers to
* the emulated Unix-like file descriptors MSVCRT provides. The native
* corresponding concept is file HANDLE. There isn't as of yet a way to
* get GIOChannels for Win32 file HANDLEs.
*/
GLIB_AVAILABLE_IN_ALL
GIOChannel* g_io_channel_unix_new (int fd);
GLIB_AVAILABLE_IN_ALL
gint g_io_channel_unix_get_fd (GIOChannel *channel);
/* Hook for GClosure / GSource integration. Don't touch */
GLIB_VAR GSourceFuncs g_io_watch_funcs;
#ifdef G_OS_WIN32
/* You can use this "pseudo file descriptor" in a GPollFD to add
* polling for Windows messages. GTK applications should not do that.
*/
#define G_WIN32_MSG_HANDLE 19981206
/* Use this to get a GPollFD from a GIOChannel, so that you can call
* g_io_channel_win32_poll(). After calling this you should only use
* g_io_channel_read() to read from the GIOChannel, i.e. never read()
* from the underlying file descriptor. For SOCKETs, it is possible to call
* recv().
*/
GLIB_AVAILABLE_IN_ALL
void g_io_channel_win32_make_pollfd (GIOChannel *channel,
GIOCondition condition,
GPollFD *fd);
/* This can be used to wait until at least one of the channels is readable.
* On Unix you would do a select() on the file descriptors of the channels.
*/
GLIB_AVAILABLE_IN_ALL
gint g_io_channel_win32_poll (GPollFD *fds,
gint n_fds,
gint timeout_);
/* Create an IO channel for Windows messages for window handle hwnd. */
#if GLIB_SIZEOF_VOID_P == 8
/* We use gsize here so that it is still an integer type and not a
* pointer, like the guint in the traditional prototype. We can't use
* intptr_t as that is not portable enough.
*/
GLIB_AVAILABLE_IN_ALL
GIOChannel *g_io_channel_win32_new_messages (gsize hwnd);
#else
GLIB_AVAILABLE_IN_ALL
GIOChannel *g_io_channel_win32_new_messages (guint hwnd);
#endif
/* Create an IO channel for C runtime (emulated Unix-like) file
* descriptors. After calling g_io_add_watch() on a IO channel
* returned by this function, you shouldn't call read() on the file
* descriptor. This is because adding polling for a file descriptor is
* implemented on Win32 by starting a thread that sits blocked in a
* read() from the file descriptor most of the time. All reads from
* the file descriptor should be done by this internal GLib
* thread. Your code should call only g_io_channel_read_chars().
*/
GLIB_AVAILABLE_IN_ALL
GIOChannel* g_io_channel_win32_new_fd (gint fd);
/* Get the C runtime file descriptor of a channel. */
GLIB_AVAILABLE_IN_ALL
gint g_io_channel_win32_get_fd (GIOChannel *channel);
/* Create an IO channel for a winsock socket. The parameter should be
* a SOCKET. Contrary to IO channels for file descriptors (on *Win32),
* you can use normal recv() or recvfrom() on sockets even if GLib
* is polling them.
*/
GLIB_AVAILABLE_IN_ALL
GIOChannel *g_io_channel_win32_new_socket (gint socket);
GLIB_DEPRECATED_FOR(g_io_channel_win32_new_socket)
GIOChannel *g_io_channel_win32_new_stream_socket (gint socket);
GLIB_AVAILABLE_IN_ALL
void g_io_channel_win32_set_debug (GIOChannel *channel,
gboolean flag);
#endif
G_END_DECLS
#endif /* __G_IOCHANNEL_H__ */

657
glib/giounix.c Normal file
View file

@ -0,0 +1,657 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* giounix.c: IO Channels using unix file descriptors
* Copyright 1998 Owen Taylor
*
* 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"
#define _POSIX_SOURCE /* for SSIZE_MAX */
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <glib/gstdio.h>
#include "giochannel.h"
#include "gerror.h"
#include "gfileutils.h"
#include "gstrfuncs.h"
#include "gtestutils.h"
/*
* Unix IO Channels
*/
typedef struct _GIOUnixChannel GIOUnixChannel;
typedef struct _GIOUnixWatch GIOUnixWatch;
struct _GIOUnixChannel
{
GIOChannel channel;
gint fd;
};
struct _GIOUnixWatch
{
GSource source;
GPollFD pollfd;
GIOChannel *channel;
GIOCondition condition;
};
static GIOStatus g_io_unix_read (GIOChannel *channel,
gchar *buf,
gsize count,
gsize *bytes_read,
GError **err);
static GIOStatus g_io_unix_write (GIOChannel *channel,
const gchar *buf,
gsize count,
gsize *bytes_written,
GError **err);
static GIOStatus g_io_unix_seek (GIOChannel *channel,
gint64 offset,
GSeekType type,
GError **err);
static GIOStatus g_io_unix_close (GIOChannel *channel,
GError **err);
static void g_io_unix_free (GIOChannel *channel);
static GSource* g_io_unix_create_watch (GIOChannel *channel,
GIOCondition condition);
static GIOStatus g_io_unix_set_flags (GIOChannel *channel,
GIOFlags flags,
GError **err);
static GIOFlags g_io_unix_get_flags (GIOChannel *channel);
static gboolean g_io_unix_prepare (GSource *source,
gint *timeout);
static gboolean g_io_unix_check (GSource *source);
static gboolean g_io_unix_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data);
static void g_io_unix_finalize (GSource *source);
GSourceFuncs g_io_watch_funcs = {
g_io_unix_prepare,
g_io_unix_check,
g_io_unix_dispatch,
g_io_unix_finalize,
NULL, NULL
};
static GIOFuncs unix_channel_funcs = {
g_io_unix_read,
g_io_unix_write,
g_io_unix_seek,
g_io_unix_close,
g_io_unix_create_watch,
g_io_unix_free,
g_io_unix_set_flags,
g_io_unix_get_flags,
};
static gboolean
g_io_unix_prepare (GSource *source,
gint *timeout)
{
GIOUnixWatch *watch = (GIOUnixWatch *)source;
GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
*timeout = -1;
/* Only return TRUE here if _all_ bits in watch->condition will be set
*/
return ((watch->condition & buffer_condition) == watch->condition);
}
static gboolean
g_io_unix_check (GSource *source)
{
GIOUnixWatch *watch = (GIOUnixWatch *)source;
GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
GIOCondition poll_condition = watch->pollfd.revents;
return ((poll_condition | buffer_condition) & watch->condition);
}
static gboolean
g_io_unix_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
GIOFunc func = (GIOFunc)callback;
GIOUnixWatch *watch = (GIOUnixWatch *)source;
GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
if (!func)
{
g_warning ("IO watch dispatched without callback. "
"You must call g_source_connect().");
return FALSE;
}
return (*func) (watch->channel,
(watch->pollfd.revents | buffer_condition) & watch->condition,
user_data);
}
static void
g_io_unix_finalize (GSource *source)
{
GIOUnixWatch *watch = (GIOUnixWatch *)source;
g_io_channel_unref (watch->channel);
}
static GIOStatus
g_io_unix_read (GIOChannel *channel,
gchar *buf,
gsize count,
gsize *bytes_read,
GError **err)
{
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
gssize result;
if (count > SSIZE_MAX) /* At least according to the Debian manpage for read */
count = SSIZE_MAX;
retry:
result = read (unix_channel->fd, buf, count);
if (result < 0)
{
int errsv = errno;
*bytes_read = 0;
switch (errsv)
{
#ifdef EINTR
case EINTR:
goto retry;
#endif
#ifdef EAGAIN
case EAGAIN:
return G_IO_STATUS_AGAIN;
#endif
default:
g_set_error_literal (err, G_IO_CHANNEL_ERROR,
g_io_channel_error_from_errno (errsv),
g_strerror (errsv));
return G_IO_STATUS_ERROR;
}
}
*bytes_read = result;
return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
}
static GIOStatus
g_io_unix_write (GIOChannel *channel,
const gchar *buf,
gsize count,
gsize *bytes_written,
GError **err)
{
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
gssize result;
retry:
result = write (unix_channel->fd, buf, count);
if (result < 0)
{
int errsv = errno;
*bytes_written = 0;
switch (errsv)
{
#ifdef EINTR
case EINTR:
goto retry;
#endif
#ifdef EAGAIN
case EAGAIN:
return G_IO_STATUS_AGAIN;
#endif
default:
g_set_error_literal (err, G_IO_CHANNEL_ERROR,
g_io_channel_error_from_errno (errsv),
g_strerror (errsv));
return G_IO_STATUS_ERROR;
}
}
*bytes_written = result;
return G_IO_STATUS_NORMAL;
}
static GIOStatus
g_io_unix_seek (GIOChannel *channel,
gint64 offset,
GSeekType type,
GError **err)
{
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
int whence;
off_t tmp_offset;
off_t result;
switch (type)
{
case G_SEEK_SET:
whence = SEEK_SET;
break;
case G_SEEK_CUR:
whence = SEEK_CUR;
break;
case G_SEEK_END:
whence = SEEK_END;
break;
default:
whence = -1; /* Shut the compiler up */
g_assert_not_reached ();
}
tmp_offset = offset;
if (tmp_offset != offset)
{
g_set_error_literal (err, G_IO_CHANNEL_ERROR,
g_io_channel_error_from_errno (EINVAL),
g_strerror (EINVAL));
return G_IO_STATUS_ERROR;
}
result = lseek (unix_channel->fd, tmp_offset, whence);
if (result < 0)
{
int errsv = errno;
g_set_error_literal (err, G_IO_CHANNEL_ERROR,
g_io_channel_error_from_errno (errsv),
g_strerror (errsv));
return G_IO_STATUS_ERROR;
}
return G_IO_STATUS_NORMAL;
}
static GIOStatus
g_io_unix_close (GIOChannel *channel,
GError **err)
{
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
if (close (unix_channel->fd) < 0)
{
int errsv = errno;
g_set_error_literal (err, G_IO_CHANNEL_ERROR,
g_io_channel_error_from_errno (errsv),
g_strerror (errsv));
return G_IO_STATUS_ERROR;
}
return G_IO_STATUS_NORMAL;
}
static void
g_io_unix_free (GIOChannel *channel)
{
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
g_free (unix_channel);
}
static GSource *
g_io_unix_create_watch (GIOChannel *channel,
GIOCondition condition)
{
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
GSource *source;
GIOUnixWatch *watch;
source = g_source_new (&g_io_watch_funcs, sizeof (GIOUnixWatch));
g_source_set_static_name (source, "GIOChannel (Unix)");
watch = (GIOUnixWatch *)source;
watch->channel = channel;
g_io_channel_ref (channel);
watch->condition = condition;
watch->pollfd.fd = unix_channel->fd;
watch->pollfd.events = condition;
g_source_add_poll (source, &watch->pollfd);
return source;
}
static GIOStatus
g_io_unix_set_flags (GIOChannel *channel,
GIOFlags flags,
GError **err)
{
glong fcntl_flags;
GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
fcntl_flags = 0;
if (flags & G_IO_FLAG_APPEND)
fcntl_flags |= O_APPEND;
if (flags & G_IO_FLAG_NONBLOCK)
#ifdef O_NONBLOCK
fcntl_flags |= O_NONBLOCK;
#else
fcntl_flags |= O_NDELAY;
#endif
if (fcntl (unix_channel->fd, F_SETFL, fcntl_flags) == -1)
{
int errsv = errno;
g_set_error_literal (err, G_IO_CHANNEL_ERROR,
g_io_channel_error_from_errno (errsv),
g_strerror (errsv));
return G_IO_STATUS_ERROR;
}
return G_IO_STATUS_NORMAL;
}
static GIOFlags
g_io_unix_get_flags (GIOChannel *channel)
{
GIOFlags flags = 0;
glong fcntl_flags;
GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
fcntl_flags = fcntl (unix_channel->fd, F_GETFL);
if (fcntl_flags == -1)
{
int err = errno;
g_warning (G_STRLOC "Error while getting flags for FD: %s (%d)",
g_strerror (err), err);
return 0;
}
if (fcntl_flags & O_APPEND)
flags |= G_IO_FLAG_APPEND;
#ifdef O_NONBLOCK
if (fcntl_flags & O_NONBLOCK)
#else
if (fcntl_flags & O_NDELAY)
#endif
flags |= G_IO_FLAG_NONBLOCK;
switch (fcntl_flags & (O_RDONLY | O_WRONLY | O_RDWR))
{
case O_RDONLY:
channel->is_readable = TRUE;
channel->is_writeable = FALSE;
break;
case O_WRONLY:
channel->is_readable = FALSE;
channel->is_writeable = TRUE;
break;
case O_RDWR:
channel->is_readable = TRUE;
channel->is_writeable = TRUE;
break;
default:
g_assert_not_reached ();
}
return flags;
}
GIOChannel *
g_io_channel_new_file (const gchar *filename,
const gchar *mode,
GError **error)
{
int fid, flags;
mode_t create_mode;
GIOChannel *channel;
enum { /* Cheesy hack */
MODE_R = 1 << 0,
MODE_W = 1 << 1,
MODE_A = 1 << 2,
MODE_PLUS = 1 << 3,
MODE_R_PLUS = MODE_R | MODE_PLUS,
MODE_W_PLUS = MODE_W | MODE_PLUS,
MODE_A_PLUS = MODE_A | MODE_PLUS
} mode_num;
struct stat buffer;
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (mode != NULL, NULL);
g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
switch (mode[0])
{
case 'r':
mode_num = MODE_R;
break;
case 'w':
mode_num = MODE_W;
break;
case 'a':
mode_num = MODE_A;
break;
default:
g_warning ("Invalid GIOFileMode %s.", mode);
return NULL;
}
switch (mode[1])
{
case '\0':
break;
case '+':
if (mode[2] == '\0')
{
mode_num |= MODE_PLUS;
break;
}
G_GNUC_FALLTHROUGH;
default:
g_warning ("Invalid GIOFileMode %s.", mode);
return NULL;
}
switch (mode_num)
{
case MODE_R:
flags = O_RDONLY;
break;
case MODE_W:
flags = O_WRONLY | O_TRUNC | O_CREAT;
break;
case MODE_A:
flags = O_WRONLY | O_APPEND | O_CREAT;
break;
case MODE_R_PLUS:
flags = O_RDWR;
break;
case MODE_W_PLUS:
flags = O_RDWR | O_TRUNC | O_CREAT;
break;
case MODE_A_PLUS:
flags = O_RDWR | O_APPEND | O_CREAT;
break;
case MODE_PLUS:
default:
g_assert_not_reached ();
flags = 0;
}
create_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
fid = g_open (filename, flags, create_mode);
if (fid == -1)
{
int err = errno;
g_set_error_literal (error, G_FILE_ERROR,
g_file_error_from_errno (err),
g_strerror (err));
return (GIOChannel *)NULL;
}
if (fstat (fid, &buffer) == -1) /* In case someone opens a FIFO */
{
int err = errno;
close (fid);
g_set_error_literal (error, G_FILE_ERROR,
g_file_error_from_errno (err),
g_strerror (err));
return (GIOChannel *)NULL;
}
channel = (GIOChannel *) g_new (GIOUnixChannel, 1);
channel->is_seekable = S_ISREG (buffer.st_mode) || S_ISCHR (buffer.st_mode)
|| S_ISBLK (buffer.st_mode);
switch (mode_num)
{
case MODE_R:
channel->is_readable = TRUE;
channel->is_writeable = FALSE;
break;
case MODE_W:
case MODE_A:
channel->is_readable = FALSE;
channel->is_writeable = TRUE;
break;
case MODE_R_PLUS:
case MODE_W_PLUS:
case MODE_A_PLUS:
channel->is_readable = TRUE;
channel->is_writeable = TRUE;
break;
case MODE_PLUS:
default:
g_assert_not_reached ();
}
g_io_channel_init (channel);
channel->close_on_unref = TRUE; /* must be after g_io_channel_init () */
channel->funcs = &unix_channel_funcs;
((GIOUnixChannel *) channel)->fd = fid;
return channel;
}
/**
* g_io_channel_unix_new:
* @fd: a file descriptor.
*
* Creates a new #GIOChannel given a file descriptor. On UNIX systems
* this works for plain files, pipes, and sockets.
*
* The returned #GIOChannel has a reference count of 1.
*
* The default encoding for #GIOChannel is UTF-8. If your application
* is reading output from a command using via pipe, you may need to set
* the encoding to the encoding of the current locale (see
* g_get_charset()) with the g_io_channel_set_encoding() function.
* By default, the fd passed will not be closed when the final reference
* to the #GIOChannel data structure is dropped.
*
* If you want to read raw binary data without interpretation, then
* call the g_io_channel_set_encoding() function with %NULL for the
* encoding argument.
*
* This function is available in GLib on Windows, too, but you should
* avoid using it on Windows. The domain of file descriptors and
* sockets overlap. There is no way for GLib to know which one you mean
* in case the argument you pass to this function happens to be both a
* valid file descriptor and socket. If that happens a warning is
* issued, and GLib assumes that it is the file descriptor you mean.
*
* Returns: a new #GIOChannel.
**/
GIOChannel *
g_io_channel_unix_new (gint fd)
{
struct stat buffer;
GIOUnixChannel *unix_channel = g_new (GIOUnixChannel, 1);
GIOChannel *channel = (GIOChannel *)unix_channel;
g_io_channel_init (channel);
channel->funcs = &unix_channel_funcs;
unix_channel->fd = fd;
/* I'm not sure if fstat on a non-file (e.g., socket) works
* it should be safe to say if it fails, the fd isn't seekable.
*/
/* Newer UNIX versions support S_ISSOCK(), fstat() will probably
* succeed in most cases.
*/
if (fstat (unix_channel->fd, &buffer) == 0)
channel->is_seekable = S_ISREG (buffer.st_mode) || S_ISCHR (buffer.st_mode)
|| S_ISBLK (buffer.st_mode);
else /* Assume not seekable */
channel->is_seekable = FALSE;
g_io_unix_get_flags (channel); /* Sets is_readable, is_writeable */
return channel;
}
/**
* g_io_channel_unix_get_fd:
* @channel: a #GIOChannel, created with g_io_channel_unix_new().
*
* Returns the file descriptor of the #GIOChannel.
*
* On Windows this function returns the file descriptor or socket of
* the #GIOChannel.
*
* Returns: the file descriptor of the #GIOChannel.
**/
gint
g_io_channel_unix_get_fd (GIOChannel *channel)
{
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
return unix_channel->fd;
}

2241
glib/giowin32.c Normal file

File diff suppressed because it is too large Load diff

4686
glib/gkeyfile.c Normal file

File diff suppressed because it is too large Load diff

330
glib/gkeyfile.h Normal file
View file

@ -0,0 +1,330 @@
/* gkeyfile.h - desktop entry file parser
*
* Copyright 2004 Red Hat, Inc.
*
* Ray Strode <halfline@hawaii.rr.com>
*
* 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/>.
*/
#ifndef __G_KEY_FILE_H__
#define __G_KEY_FILE_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gbytes.h>
#include <glib/gerror.h>
G_BEGIN_DECLS
typedef enum
{
G_KEY_FILE_ERROR_UNKNOWN_ENCODING,
G_KEY_FILE_ERROR_PARSE,
G_KEY_FILE_ERROR_NOT_FOUND,
G_KEY_FILE_ERROR_KEY_NOT_FOUND,
G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
G_KEY_FILE_ERROR_INVALID_VALUE
} GKeyFileError;
#define G_KEY_FILE_ERROR g_key_file_error_quark()
GLIB_AVAILABLE_IN_ALL
GQuark g_key_file_error_quark (void);
typedef struct _GKeyFile GKeyFile;
typedef enum
{
G_KEY_FILE_NONE = 0,
G_KEY_FILE_KEEP_COMMENTS = 1 << 0,
G_KEY_FILE_KEEP_TRANSLATIONS = 1 << 1
} GKeyFileFlags;
GLIB_AVAILABLE_IN_ALL
GKeyFile *g_key_file_new (void);
GLIB_AVAILABLE_IN_ALL
GKeyFile *g_key_file_ref (GKeyFile *key_file);
GLIB_AVAILABLE_IN_ALL
void g_key_file_unref (GKeyFile *key_file);
GLIB_AVAILABLE_IN_ALL
void g_key_file_free (GKeyFile *key_file);
GLIB_AVAILABLE_IN_ALL
void g_key_file_set_list_separator (GKeyFile *key_file,
gchar separator);
GLIB_AVAILABLE_IN_ALL
gboolean g_key_file_load_from_file (GKeyFile *key_file,
const gchar *file,
GKeyFileFlags flags,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_key_file_load_from_data (GKeyFile *key_file,
const gchar *data,
gsize length,
GKeyFileFlags flags,
GError **error);
GLIB_AVAILABLE_IN_2_50
gboolean g_key_file_load_from_bytes (GKeyFile *key_file,
GBytes *bytes,
GKeyFileFlags flags,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_key_file_load_from_dirs (GKeyFile *key_file,
const gchar *file,
const gchar **search_dirs,
gchar **full_path,
GKeyFileFlags flags,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_key_file_load_from_data_dirs (GKeyFile *key_file,
const gchar *file,
gchar **full_path,
GKeyFileFlags flags,
GError **error);
GLIB_AVAILABLE_IN_ALL
gchar *g_key_file_to_data (GKeyFile *key_file,
gsize *length,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_2_40
gboolean g_key_file_save_to_file (GKeyFile *key_file,
const gchar *filename,
GError **error);
GLIB_AVAILABLE_IN_ALL
gchar *g_key_file_get_start_group (GKeyFile *key_file) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
gchar **g_key_file_get_groups (GKeyFile *key_file,
gsize *length);
GLIB_AVAILABLE_IN_ALL
gchar **g_key_file_get_keys (GKeyFile *key_file,
const gchar *group_name,
gsize *length,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_key_file_has_group (GKeyFile *key_file,
const gchar *group_name);
GLIB_AVAILABLE_IN_ALL
gboolean g_key_file_has_key (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
GError **error);
GLIB_AVAILABLE_IN_ALL
gchar *g_key_file_get_value (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
void g_key_file_set_value (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
const gchar *value);
GLIB_AVAILABLE_IN_ALL
gchar *g_key_file_get_string (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
void g_key_file_set_string (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
const gchar *string);
GLIB_AVAILABLE_IN_ALL
gchar *g_key_file_get_locale_string (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
const gchar *locale,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_2_56
gchar *g_key_file_get_locale_for_key (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
const gchar *locale) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
void g_key_file_set_locale_string (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
const gchar *locale,
const gchar *string);
GLIB_AVAILABLE_IN_ALL
gboolean g_key_file_get_boolean (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
GError **error);
GLIB_AVAILABLE_IN_ALL
void g_key_file_set_boolean (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
gboolean value);
GLIB_AVAILABLE_IN_ALL
gint g_key_file_get_integer (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
GError **error);
GLIB_AVAILABLE_IN_ALL
void g_key_file_set_integer (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
gint value);
GLIB_AVAILABLE_IN_ALL
gint64 g_key_file_get_int64 (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
GError **error);
GLIB_AVAILABLE_IN_ALL
void g_key_file_set_int64 (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
gint64 value);
GLIB_AVAILABLE_IN_ALL
guint64 g_key_file_get_uint64 (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
GError **error);
GLIB_AVAILABLE_IN_ALL
void g_key_file_set_uint64 (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
guint64 value);
GLIB_AVAILABLE_IN_ALL
gdouble g_key_file_get_double (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
GError **error);
GLIB_AVAILABLE_IN_ALL
void g_key_file_set_double (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
gdouble value);
GLIB_AVAILABLE_IN_ALL
gchar **g_key_file_get_string_list (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
gsize *length,
GError **error);
GLIB_AVAILABLE_IN_ALL
void g_key_file_set_string_list (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
const gchar * const list[],
gsize length);
GLIB_AVAILABLE_IN_ALL
gchar **g_key_file_get_locale_string_list (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
const gchar *locale,
gsize *length,
GError **error);
GLIB_AVAILABLE_IN_ALL
void g_key_file_set_locale_string_list (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
const gchar *locale,
const gchar * const list[],
gsize length);
GLIB_AVAILABLE_IN_ALL
gboolean *g_key_file_get_boolean_list (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
gsize *length,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
void g_key_file_set_boolean_list (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
gboolean list[],
gsize length);
GLIB_AVAILABLE_IN_ALL
gint *g_key_file_get_integer_list (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
gsize *length,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
void g_key_file_set_double_list (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
gdouble list[],
gsize length);
GLIB_AVAILABLE_IN_ALL
gdouble *g_key_file_get_double_list (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
gsize *length,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
void g_key_file_set_integer_list (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
gint list[],
gsize length);
GLIB_AVAILABLE_IN_ALL
gboolean g_key_file_set_comment (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
const gchar *comment,
GError **error);
GLIB_AVAILABLE_IN_ALL
gchar *g_key_file_get_comment (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
GError **error) G_GNUC_MALLOC;
GLIB_AVAILABLE_IN_ALL
gboolean g_key_file_remove_comment (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_key_file_remove_key (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_key_file_remove_group (GKeyFile *key_file,
const gchar *group_name,
GError **error);
/* Defines for handling freedesktop.org Desktop files */
#define G_KEY_FILE_DESKTOP_GROUP "Desktop Entry"
#define G_KEY_FILE_DESKTOP_KEY_TYPE "Type"
#define G_KEY_FILE_DESKTOP_KEY_VERSION "Version"
#define G_KEY_FILE_DESKTOP_KEY_NAME "Name"
#define G_KEY_FILE_DESKTOP_KEY_GENERIC_NAME "GenericName"
#define G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY "NoDisplay"
#define G_KEY_FILE_DESKTOP_KEY_COMMENT "Comment"
#define G_KEY_FILE_DESKTOP_KEY_ICON "Icon"
#define G_KEY_FILE_DESKTOP_KEY_HIDDEN "Hidden"
#define G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN "OnlyShowIn"
#define G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN "NotShowIn"
#define G_KEY_FILE_DESKTOP_KEY_TRY_EXEC "TryExec"
#define G_KEY_FILE_DESKTOP_KEY_EXEC "Exec"
#define G_KEY_FILE_DESKTOP_KEY_PATH "Path"
#define G_KEY_FILE_DESKTOP_KEY_TERMINAL "Terminal"
#define G_KEY_FILE_DESKTOP_KEY_MIME_TYPE "MimeType"
#define G_KEY_FILE_DESKTOP_KEY_CATEGORIES "Categories"
#define G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY "StartupNotify"
#define G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS "StartupWMClass"
#define G_KEY_FILE_DESKTOP_KEY_URL "URL"
#define G_KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE "DBusActivatable"
#define G_KEY_FILE_DESKTOP_KEY_ACTIONS "Actions"
#define G_KEY_FILE_DESKTOP_TYPE_APPLICATION "Application"
#define G_KEY_FILE_DESKTOP_TYPE_LINK "Link"
#define G_KEY_FILE_DESKTOP_TYPE_DIRECTORY "Directory"
G_END_DECLS
#endif /* __G_KEY_FILE_H__ */

103
glib/glib-autocleanups.h Normal file
View file

@ -0,0 +1,103 @@
/*
* Copyright © 2015 Canonical Limited
*
* 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/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
static inline void
g_autoptr_cleanup_generic_gfree (void *p)
{
void **pp = (void**)p;
g_free (*pp);
}
static inline void
g_autoptr_cleanup_gstring_free (GString *string)
{
if (string)
g_string_free (string, TRUE);
}
/* Ignore deprecations in case we refer to a type which was added in a more
* recent GLib version than the users #GLIB_VERSION_MAX_ALLOWED definition. */
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/* If adding a cleanup here, please also add a test case to
* glib/tests/autoptr.c
*/
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GAsyncQueue, g_async_queue_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GBookmarkFile, g_bookmark_file_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GBytes, g_bytes_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GChecksum, g_checksum_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDateTime, g_date_time_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDate, g_date_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDir, g_dir_close)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GError, g_error_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GHashTable, g_hash_table_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GHmac, g_hmac_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GIOChannel, g_io_channel_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GKeyFile, g_key_file_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GList, g_list_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GArray, g_array_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GPtrArray, g_ptr_array_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GByteArray, g_byte_array_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMainContext, g_main_context_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMainContextPusher, g_main_context_pusher_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMainLoop, g_main_loop_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSource, g_source_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMappedFile, g_mapped_file_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMarkupParseContext, g_markup_parse_context_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GNode, g_node_destroy)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GOptionContext, g_option_context_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GOptionGroup, g_option_group_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GPatternSpec, g_pattern_spec_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GQueue, g_queue_free)
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GQueue, g_queue_clear)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GRand, g_rand_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GRegex, g_regex_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMatchInfo, g_match_info_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GScanner, g_scanner_destroy)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSequence, g_sequence_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSList, g_slist_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GString, g_autoptr_cleanup_gstring_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GStringChunk, g_string_chunk_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GStrvBuilder, g_strv_builder_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GThread, g_thread_unref)
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GMutex, g_mutex_clear)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMutexLocker, g_mutex_locker_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GRecMutexLocker, g_rec_mutex_locker_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GRWLockWriterLocker, g_rw_lock_writer_locker_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GRWLockReaderLocker, g_rw_lock_reader_locker_free)
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GCond, g_cond_clear)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTimer, g_timer_destroy)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTimeZone, g_time_zone_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTree, g_tree_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariant, g_variant_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantBuilder, g_variant_builder_unref)
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GVariantBuilder, g_variant_builder_clear)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantIter, g_variant_iter_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantDict, g_variant_dict_unref)
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GVariantDict, g_variant_dict_clear)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantType, g_variant_type_free)
G_DEFINE_AUTO_CLEANUP_FREE_FUNC(GStrv, g_strfreev, NULL)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GRefString, g_ref_string_release)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUri, g_uri_unref)
G_GNUC_END_IGNORE_DEPRECATIONS

458
glib/glib-init.c Normal file
View file

@ -0,0 +1,458 @@
/*
* Copyright © 2011 Canonical Limited
*
* 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/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#include "config.h"
#include "glib-init.h"
#include "gmacros.h"
#include "gtypes.h"
#include "gutils.h" /* for GDebugKey */
#include "gconstructor.h"
#include "gmem.h" /* for g_mem_gc_friendly */
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
/* Deliberately not checking HAVE_STDINT_H here: we officially require a
* C99 toolchain, which implies <stdint.h>, int8_t and so on. If your
* toolchain does not have this, now would be a good time to upgrade. */
#include <stdint.h>
/* This seems as good a place as any to make static assertions about platform
* assumptions we make throughout GLib. */
/* We do not support 36-bit bytes or other historical curiosities. */
G_STATIC_ASSERT (CHAR_BIT == 8);
/* We assume that data pointers are the same size as function pointers... */
G_STATIC_ASSERT (sizeof (gpointer) == sizeof (GFunc));
G_STATIC_ASSERT (G_ALIGNOF (gpointer) == G_ALIGNOF (GFunc));
/* ... and that all function pointers are the same size. */
G_STATIC_ASSERT (sizeof (GFunc) == sizeof (GCompareDataFunc));
G_STATIC_ASSERT (G_ALIGNOF (GFunc) == G_ALIGNOF (GCompareDataFunc));
/* We assume that "small" enums (those where all values fit in INT32_MIN
* to INT32_MAX) are exactly int-sized. In particular, we assume that if
* an enum has no members that exceed the range of char/short, the
* compiler will make it int-sized anyway, so adding a member later that
* *does* exceed the range of char/short is not an ABI break. */
typedef enum {
TEST_CHAR_0 = 0
} TestChar;
typedef enum {
TEST_SHORT_0 = 0,
TEST_SHORT_256 = 256
} TestShort;
typedef enum {
TEST_INT32_MIN = G_MININT32,
TEST_INT32_MAX = G_MAXINT32
} TestInt;
G_STATIC_ASSERT (sizeof (TestChar) == sizeof (int));
G_STATIC_ASSERT (sizeof (TestShort) == sizeof (int));
G_STATIC_ASSERT (sizeof (TestInt) == sizeof (int));
G_STATIC_ASSERT (G_ALIGNOF (TestChar) == G_ALIGNOF (int));
G_STATIC_ASSERT (G_ALIGNOF (TestShort) == G_ALIGNOF (int));
G_STATIC_ASSERT (G_ALIGNOF (TestInt) == G_ALIGNOF (int));
G_STATIC_ASSERT (sizeof (gchar) == 1);
G_STATIC_ASSERT (sizeof (guchar) == 1);
G_STATIC_ASSERT (sizeof (gint8) * CHAR_BIT == 8);
G_STATIC_ASSERT (sizeof (guint8) * CHAR_BIT == 8);
G_STATIC_ASSERT (sizeof (gint16) * CHAR_BIT == 16);
G_STATIC_ASSERT (sizeof (guint16) * CHAR_BIT == 16);
G_STATIC_ASSERT (sizeof (gint32) * CHAR_BIT == 32);
G_STATIC_ASSERT (sizeof (guint32) * CHAR_BIT == 32);
G_STATIC_ASSERT (sizeof (gint64) * CHAR_BIT == 64);
G_STATIC_ASSERT (sizeof (guint64) * CHAR_BIT == 64);
G_STATIC_ASSERT (sizeof (void *) == GLIB_SIZEOF_VOID_P);
G_STATIC_ASSERT (sizeof (gintptr) == sizeof (void *));
G_STATIC_ASSERT (sizeof (guintptr) == sizeof (void *));
G_STATIC_ASSERT (sizeof (long) == GLIB_SIZEOF_LONG);
G_STATIC_ASSERT (G_HAVE_GINT64 == 1);
G_STATIC_ASSERT (sizeof (size_t) == GLIB_SIZEOF_SIZE_T);
/* Not a typo: ssize_t is POSIX, not Standard C, but if it exists then
* it's the same size as size_t. */
G_STATIC_ASSERT (sizeof (size_t) == GLIB_SIZEOF_SSIZE_T);
G_STATIC_ASSERT (sizeof (gsize) == GLIB_SIZEOF_SSIZE_T);
G_STATIC_ASSERT (sizeof (gsize) == sizeof (size_t));
/* Again this is size_t not ssize_t, because ssize_t is POSIX, not C99 */
G_STATIC_ASSERT (sizeof (gssize) == sizeof (size_t));
G_STATIC_ASSERT (G_ALIGNOF (gsize) == G_ALIGNOF (size_t));
G_STATIC_ASSERT (G_ALIGNOF (gssize) == G_ALIGNOF (size_t));
/* goffset is always 64-bit, even if off_t is only 32-bit
* (compiling without large-file-support on 32-bit) */
G_STATIC_ASSERT (sizeof (goffset) == sizeof (gint64));
G_STATIC_ASSERT (G_ALIGNOF (goffset) == G_ALIGNOF (gint64));
G_STATIC_ASSERT (sizeof (gfloat) == sizeof (float));
G_STATIC_ASSERT (G_ALIGNOF (gfloat) == G_ALIGNOF (float));
G_STATIC_ASSERT (sizeof (gdouble) == sizeof (double));
G_STATIC_ASSERT (G_ALIGNOF (gdouble) == G_ALIGNOF (double));
G_STATIC_ASSERT (sizeof (gintptr) == sizeof (intptr_t));
G_STATIC_ASSERT (sizeof (guintptr) == sizeof (uintptr_t));
G_STATIC_ASSERT (G_ALIGNOF (gintptr) == G_ALIGNOF (intptr_t));
G_STATIC_ASSERT (G_ALIGNOF (guintptr) == G_ALIGNOF (uintptr_t));
G_STATIC_ASSERT (sizeof (gint8) == sizeof (int8_t));
G_STATIC_ASSERT (sizeof (guint8) == sizeof (uint8_t));
G_STATIC_ASSERT (G_ALIGNOF (gint8) == G_ALIGNOF (int8_t));
G_STATIC_ASSERT (G_ALIGNOF (guint8) == G_ALIGNOF (uint8_t));
G_STATIC_ASSERT (sizeof (gint16) == sizeof (int16_t));
G_STATIC_ASSERT (sizeof (guint16) == sizeof (uint16_t));
G_STATIC_ASSERT (G_ALIGNOF (gint16) == G_ALIGNOF (int16_t));
G_STATIC_ASSERT (G_ALIGNOF (guint16) == G_ALIGNOF (uint16_t));
G_STATIC_ASSERT (sizeof (gint32) == sizeof (int32_t));
G_STATIC_ASSERT (sizeof (guint32) == sizeof (uint32_t));
G_STATIC_ASSERT (G_ALIGNOF (gint32) == G_ALIGNOF (int32_t));
G_STATIC_ASSERT (G_ALIGNOF (guint32) == G_ALIGNOF (uint32_t));
G_STATIC_ASSERT (sizeof (gint64) == sizeof (int64_t));
G_STATIC_ASSERT (sizeof (guint64) == sizeof (uint64_t));
G_STATIC_ASSERT (G_ALIGNOF (gint64) == G_ALIGNOF (int64_t));
G_STATIC_ASSERT (G_ALIGNOF (guint64) == G_ALIGNOF (uint64_t));
/**
* g_mem_gc_friendly:
*
* This variable is %TRUE if the `G_DEBUG` environment variable
* includes the key `gc-friendly`.
*/
gboolean g_mem_gc_friendly = FALSE;
GLogLevelFlags g_log_msg_prefix = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING |
G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG;
GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
static gboolean
debug_key_matches (const gchar *key,
const gchar *token,
guint length)
{
/* may not call GLib functions: see note in g_parse_debug_string() */
for (; length; length--, key++, token++)
{
char k = (*key == '_') ? '-' : tolower (*key );
char t = (*token == '_') ? '-' : tolower (*token);
if (k != t)
return FALSE;
}
return *key == '\0';
}
/* The GVariant documentation indirectly says that int is at least 32 bits
* (by saying that b, y, n, q, i, u, h are promoted to int). On any
* reasonable platform, int is in fact *exactly* 32 bits long, because
* otherwise, {signed char, short, int} wouldn't be sufficient to provide
* {int8_t, int16_t, int32_t}. */
G_STATIC_ASSERT (sizeof (int) == sizeof (gint32));
/**
* g_parse_debug_string:
* @string: (nullable): a list of debug options separated by colons, spaces, or
* commas, or %NULL.
* @keys: (array length=nkeys): pointer to an array of #GDebugKey which associate
* strings with bit flags.
* @nkeys: the number of #GDebugKeys in the array.
*
* Parses a string containing debugging options
* into a %guint containing bit flags. This is used
* within GDK and GTK+ to parse the debug options passed on the
* command line or through environment variables.
*
* If @string is equal to "all", all flags are set. Any flags
* specified along with "all" in @string are inverted; thus,
* "all,foo,bar" or "foo,bar,all" sets all flags except those
* corresponding to "foo" and "bar".
*
* If @string is equal to "help", all the available keys in @keys
* are printed out to standard error.
*
* Returns: the combined set of bit flags.
*/
guint
g_parse_debug_string (const gchar *string,
const GDebugKey *keys,
guint nkeys)
{
guint i;
guint result = 0;
if (string == NULL)
return 0;
/* this function is used during the initialisation of gmessages, gmem
* and gslice, so it may not do anything that causes memory to be
* allocated or risks messages being emitted.
*
* this means, more or less, that this code may not call anything
* inside GLib.
*/
if (!strcasecmp (string, "help"))
{
/* using stdio directly for the reason stated above */
fprintf (stderr, "Supported debug values:");
for (i = 0; i < nkeys; i++)
fprintf (stderr, " %s", keys[i].key);
fprintf (stderr, " all help\n");
}
else
{
const gchar *p = string;
const gchar *q;
gboolean invert = FALSE;
while (*p)
{
q = strpbrk (p, ":;, \t");
if (!q)
q = p + strlen (p);
if (debug_key_matches ("all", p, q - p))
{
invert = TRUE;
}
else
{
for (i = 0; i < nkeys; i++)
if (debug_key_matches (keys[i].key, p, q - p))
result |= keys[i].value;
}
p = q;
if (*p)
p++;
}
if (invert)
{
guint all_flags = 0;
for (i = 0; i < nkeys; i++)
all_flags |= keys[i].value;
result = all_flags & (~result);
}
}
return result;
}
static guint
g_parse_debug_envvar (const gchar *envvar,
const GDebugKey *keys,
gint n_keys,
guint default_value)
{
const gchar *value;
#ifdef OS_WIN32
/* "fatal-warnings,fatal-criticals,all,help" is pretty short */
gchar buffer[100];
if (GetEnvironmentVariable (envvar, buffer, 100) < 100)
value = buffer;
else
return 0;
#else
value = getenv (envvar);
#endif
if (value == NULL)
return default_value;
return g_parse_debug_string (value, keys, n_keys);
}
static void
g_messages_prefixed_init (void)
{
const GDebugKey keys[] = {
{ "error", G_LOG_LEVEL_ERROR },
{ "critical", G_LOG_LEVEL_CRITICAL },
{ "warning", G_LOG_LEVEL_WARNING },
{ "message", G_LOG_LEVEL_MESSAGE },
{ "info", G_LOG_LEVEL_INFO },
{ "debug", G_LOG_LEVEL_DEBUG }
};
g_log_msg_prefix = g_parse_debug_envvar ("G_MESSAGES_PREFIXED", keys, G_N_ELEMENTS (keys), g_log_msg_prefix);
}
static void
g_debug_init (void)
{
const GDebugKey keys[] = {
{ "gc-friendly", 1 },
{"fatal-warnings", G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL },
{"fatal-criticals", G_LOG_LEVEL_CRITICAL }
};
GLogLevelFlags flags;
flags = g_parse_debug_envvar ("G_DEBUG", keys, G_N_ELEMENTS (keys), 0);
g_log_always_fatal |= flags & G_LOG_LEVEL_MASK;
g_mem_gc_friendly = flags & 1;
}
void
glib_init (void)
{
static gboolean glib_inited;
if (glib_inited)
return;
glib_inited = TRUE;
g_messages_prefixed_init ();
g_debug_init ();
g_quark_init ();
g_error_init ();
}
#ifdef G_PLATFORM_WIN32
HMODULE glib_dll = NULL;
void glib_win32_init (void);
void
glib_win32_init (void)
{
/* May be called more than once in static compilation mode */
static gboolean win32_already_init = FALSE;
if (!win32_already_init)
{
win32_already_init = TRUE;
g_crash_handler_win32_init ();
#ifdef THREADS_WIN32
g_thread_win32_init ();
#endif
g_clock_win32_init ();
glib_init ();
/* must go after glib_init */
g_console_win32_init ();
}
}
static void
glib_win32_deinit (gboolean detach_thread)
{
#ifdef THREADS_WIN32
if (detach_thread)
g_thread_win32_process_detach ();
#endif
g_crash_handler_win32_deinit ();
}
#ifndef GLIB_STATIC_COMPILATION
BOOL WINAPI DllMain (HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved);
BOOL WINAPI
DllMain (HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
glib_dll = hinstDLL;
glib_win32_init ();
break;
case DLL_THREAD_DETACH:
#ifdef THREADS_WIN32
g_thread_win32_thread_detach ();
#endif
break;
case DLL_PROCESS_DETACH:
glib_win32_deinit (lpvReserved == NULL);
break;
default:
/* do nothing */
;
}
return TRUE;
}
#elif defined(G_HAS_CONSTRUCTORS) /* && G_PLATFORM_WIN32 && GLIB_STATIC_COMPILATION */
#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(glib_init_ctor)
#endif
#ifdef G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA
#pragma G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(glib_init_dtor)
#endif
G_DEFINE_CONSTRUCTOR (glib_init_ctor)
static void
glib_init_ctor (void)
{
glib_win32_init ();
}
G_DEFINE_DESTRUCTOR (glib_init_dtor)
static void
glib_init_dtor (void)
{
glib_win32_deinit (FALSE);
}
#else /* G_PLATFORM_WIN32 && GLIB_STATIC_COMPILATION && !G_HAS_CONSTRUCTORS */
#error Your platform/compiler is missing constructor support
#endif /* GLIB_STATIC_COMPILATION */
#elif defined(G_HAS_CONSTRUCTORS) /* && !G_PLATFORM_WIN32 */
#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(glib_init_ctor)
#endif
G_DEFINE_CONSTRUCTOR(glib_init_ctor)
static void
glib_init_ctor (void)
{
glib_init ();
}
#else /* !G_PLATFORM_WIN32 && !G_HAS_CONSTRUCTORS */
# error Your platform/compiler is missing constructor support
#endif /* G_PLATFORM_WIN32 */

48
glib/glib-init.h Normal file
View file

@ -0,0 +1,48 @@
/*
* Copyright © 2011 Canonical Limited
*
* 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/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __GLIB_INIT_H__
#define __GLIB_INIT_H__
#include "gmessages.h"
extern GLogLevelFlags g_log_always_fatal;
extern GLogLevelFlags g_log_msg_prefix;
void glib_init (void);
void g_quark_init (void);
void g_error_init (void);
#ifdef G_OS_WIN32
#include <windows.h>
void g_thread_win32_process_detach (void);
void g_thread_win32_thread_detach (void);
void g_thread_win32_init (void);
void g_console_win32_init (void);
void g_clock_win32_init (void);
void g_crash_handler_win32_init (void);
void g_crash_handler_win32_deinit (void);
gboolean _g_win32_call_rtl_version (OSVERSIONINFOEXW *info);
extern HMODULE glib_dll;
gchar *g_win32_find_helper_executable_path (const gchar *process_name, void *dll_handle);
#endif
#endif /* __GLIB_INIT_H__ */

View file

@ -0,0 +1,230 @@
/* gen-mirroring-tab.c - generate gmirroringtable.h for glib
* copied from FriBidi.
*
* $Id$
* $Author$
* $Date$
* $Revision$
* $Source$
*
* Author:
* Behdad Esfahbod, 2001, 2002, 2004
*
* Copyright (C) 2004 Sharif FarsiWeb, Inc
* Copyright (C) 2001,2002,2004 Behdad Esfahbod
*
* 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/>.
*
* For licensing issues, contact <license@farsiweb.info>.
*/
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "packtab.h"
#define appname "gen-mirroring-tab"
#define outputname "gmirroringtable.h"
static void
die (
const char *msg
)
{
fprintf (stderr, appname ": %s\n", msg);
exit (1);
}
static void
die2 (
const char *fmt,
const char *p
)
{
fprintf (stderr, appname ": ");
fprintf (stderr, fmt, p);
fprintf (stderr, "\n");
exit (1);
}
static void
die4 (
const char *fmt,
unsigned long l,
unsigned long p,
unsigned long q
)
{
fprintf (stderr, appname ": ");
fprintf (stderr, fmt, l, p, q);
fprintf (stderr, "\n");
exit (1);
}
#define table_name "Mir"
#define macro_name "GLIB_GET_MIRRORING"
#define UNICODE_CHARS 0x110000
static signed int table[UNICODE_CHARS];
static char buf[4000];
static signed long max_dist;
static void
init (
void
)
{
max_dist = 0;
}
static void
clear_tab (
void
)
{
register gunichar c;
for (c = 0; c < UNICODE_CHARS; c++)
table[c] = 0;
}
static void
init_tab_mirroring_txt (
void
)
{
clear_tab ();
}
static void
read_bidi_mirroring_txt (
FILE *f
)
{
unsigned long l;
init_tab_mirroring_txt ();
l = 0;
while (fgets (buf, sizeof buf, f))
{
unsigned long i, j;
signed long dist;
int k;
const char *s = buf;
l++;
while (*s == ' ')
s++;
if (s[0] == '#' || s[0] == '\0' || s[0] == '\n')
continue;
k = sscanf (s, "%lx; %lx", &i, &j);
if (k != 2 || i >= UNICODE_CHARS || j >= UNICODE_CHARS)
die4 ("invalid pair in input at line %lu: %04lX, %04lX", l, i, j);
dist = ((signed long) j - (signed long) i);
table[i] = dist;
if (dist > max_dist)
max_dist = dist;
else if (-dist > max_dist)
max_dist = -dist;
}
}
static void
read_data (
const char *data_file_type,
const char *data_file_name
)
{
FILE *f;
fprintf (stderr, "Reading '%s'\n", data_file_name);
if (!(f = fopen (data_file_name, "rt")))
die2 ("error: cannot open '%s' for reading", data_file_name);
if (!strcmp (data_file_type, "BidiMirroring.txt"))
read_bidi_mirroring_txt (f);
else
die2 ("error: unknown data-file-type %s", data_file_type);
fclose (f);
}
static void
gen_mirroring_tab (
int max_depth,
const char *data_file_type
)
{
int key_bytes;
const char *key_type;
fprintf (stderr,
"Generating '" outputname "', it may take up to a few minutes\n");
printf ("/* " outputname "\n * generated by " appname " "
"\n" " * from the file %s of */\n\n", data_file_type);
printf ("#define PACKTAB_UINT8 guint8\n"
"#define PACKTAB_UINT16 guint16\n"
"#define PACKTAB_UINT32 guint32\n\n");
key_bytes = max_dist <= 0x7f ? 1 : max_dist < 0x7fff ? 2 : 4;
key_type = key_bytes == 1 ? "gint8" : key_bytes == 2 ?
"gint16" : "gint32";
if (!pack_table
(table, UNICODE_CHARS, key_bytes, 0, max_depth, 1, NULL,
key_type, table_name, macro_name "_DELTA", stdout))
die ("error: insufficient memory, decrease max_depth");
printf ("#undef PACKTAB_UINT8\n"
"#undef PACKTAB_UINT16\n" "#undef PACKTAB_UINT32\n\n");
printf ("#define " macro_name "(x) ((x) + " macro_name "_DELTA(x))\n\n");
printf ("/* End of generated " outputname " */\n");
}
int
main (
int argc,
const char **argv
)
{
const char *data_file_type = "BidiMirroring.txt";
if (argc < 3)
die2 ("usage:\n " appname " max-lookups /path/to/%s [junk...]",
data_file_type);
{
int max_depth = atoi (argv[1]);
const char *data_file_name = argv[2];
if (max_depth < 2)
die ("invalid depth");
init ();
read_data (data_file_type, data_file_name);
gen_mirroring_tab (max_depth, data_file_type);
}
return 0;
}

View file

@ -0,0 +1,5 @@
gen_mirroring_tab = executable('gen-mirroring-tab',
['gen-mirroring-tab.c', 'packtab.c'],
dependencies : [libglib_dep],
install: false,
)

View file

@ -0,0 +1,422 @@
/* PackTab - Pack a static table
* Copyright (C) 2001 Behdad Esfahbod.
*
* 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/>.
*
* For licensing issues, contact <fwpg@sharif.edu>.
*/
/*
8 <= N <= 2^21
int key
1 <= max_depth <= 21
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "packtab.h"
typedef signed int uni_table[1024 * 1024 * 2];
static int n, a, max_depth, digits, tab_width, per_row;
static long N;
signed int def_key;
static uni_table temp, x, perm, *tab;
static long pow[22], cluster, cmpcluster;
static const char *const *name, *key_type_name, *table_name, *macro_name;
static FILE *f;
static long
most_binary (
long min,
long max
)
{
/* min should be less than max */
register int i, ii;
if (min == max)
return max;
for (i = 21; max < pow[i]; i--)
;
ii = i;
while (i && !((min ^ max) & pow[i]))
i--;
if (ii == i)
{
/* min is less than half of max */
for (i = 21 - 1; min < pow[i]; i--)
;
i++;
return pow[i];
}
return max & (pow[i] - 1);
}
static void
init (
const signed int *table
)
{
register int i;
/* initialize powers of two */
pow[0] = 1;
for (i = 1; i <= 21; i++)
pow[i] = pow[i - 1] << 1;
/* reduce number of elements to get a more binary number */
{
long essen;
/* find number of essential items */
essen = N - 1;
while (essen && table[essen] == def_key)
essen--;
essen++;
N = most_binary (essen, N);
}
for (n = 21; N % pow[n]; n--)
;
digits = (n + 3) / 4;
for (i = 6; i; i--)
if (pow[i] * (tab_width + 1) < 80)
break;
per_row = pow[i];
}
static int
compare (
const void *r,
const void *s
)
{
int i;
for (i = 0; i < cmpcluster; i++)
if (((int *) r)[i] != ((int *) s)[i])
return ((int *) r)[i] - ((int *) s)[i];
return 0;
}
static int lev, best_lev, p[22], best_p[22], nn;
static long c[22], best_c[22], s, best_s;
static long t[22], best_t[22], clusters[22], best_cluster[22];
static void
found (
void
)
{
int i;
if (s < best_s)
{
best_s = s;
best_lev = lev;
for (i = 0; i <= lev; i++)
{
best_p[i] = p[i];
best_c[i] = c[i];
best_t[i] = t[i];
best_cluster[i] = clusters[i];
}
}
}
static void
bt (
int node_size
)
{
long i, j, k, y, sbak;
long key_bytes;
if (t[lev] == 1)
{
found ();
return;
}
if (lev == max_depth)
return;
for (i = 1 - t[lev] % 2; i <= nn + (t[lev] >> nn) % 2; i++)
{
nn -= (p[lev] = i);
clusters[lev] = cluster = (i && nn >= 0) ? pow[i] : t[lev];
cmpcluster = cluster + 1;
t[lev + 1] = (t[lev] - 1) / cluster + 1;
for (j = 0; j < t[lev + 1]; j++)
{
memmove (temp + j * cmpcluster, tab[lev] + j * cluster,
cluster * sizeof (tab[lev][0]));
temp[j * cmpcluster + cluster] = j;
}
qsort (temp, t[lev + 1], cmpcluster * sizeof (temp[0]), compare);
for (j = 0; j < t[lev + 1]; j++)
{
perm[j] = temp[j * cmpcluster + cluster];
temp[j * cmpcluster + cluster] = 0;
}
k = 1;
y = 0;
tab[lev + 1][perm[0]] = perm[0];
for (j = 1; j < t[lev + 1]; j++)
{
if (compare (temp + y, temp + y + cmpcluster))
{
k++;
tab[lev + 1][perm[j]] = perm[j];
}
else
tab[lev + 1][perm[j]] = tab[lev + 1][perm[j - 1]];
y += cmpcluster;
}
sbak = s;
s += k * node_size * cluster;
c[lev] = k;
if (s >= best_s)
{
s = sbak;
nn += i;
return;
}
key_bytes = k * cluster;
key_bytes = key_bytes < 0xff ? 1 : key_bytes < 0xffff ? 2 : 4;
lev++;
bt (key_bytes);
lev--;
s = sbak;
nn += i;
}
}
static void
solve (
void
)
{
best_lev = max_depth + 2;
best_s = N * a * 2;
lev = 0;
s = 0;
nn = n;
t[0] = N;
bt (a);
}
static void
write_array (
long max_key
)
{
int i, j, k, y, ii, ofs;
const char *key_type;
if (best_t[lev] == 1)
return;
nn -= (i = best_p[lev]);
cluster = best_cluster[lev];
cmpcluster = cluster + 1;
t[lev + 1] = best_t[lev + 1];
for (j = 0; j < t[lev + 1]; j++)
{
memmove (temp + j * cmpcluster, tab[lev] + j * cluster,
cluster * sizeof (tab[lev][0]));
temp[j * cmpcluster + cluster] = j;
}
qsort (temp, t[lev + 1], cmpcluster * sizeof (temp[0]), compare);
for (j = 0; j < t[lev + 1]; j++)
{
perm[j] = temp[j * cmpcluster + cluster];
temp[j * cmpcluster + cluster] = 0;
}
k = 1;
y = 0;
tab[lev + 1][perm[0]] = x[0] = perm[0];
for (j = 1; j < t[lev + 1]; j++)
{
if (compare (temp + y, temp + y + cmpcluster))
{
x[k] = perm[j];
tab[lev + 1][perm[j]] = x[k];
k++;
}
else
tab[lev + 1][perm[j]] = tab[lev + 1][perm[j - 1]];
y += cmpcluster;
}
i = 0;
for (ii = 1; ii < k; ii++)
if (x[ii] < x[i])
i = ii;
key_type = !lev ? key_type_name :
max_key <= 0xff ? "PACKTAB_UINT8" :
max_key <= 0xffff ? "PACKTAB_UINT16" : "PACKTAB_UINT32";
fprintf (f, "static const %s %sLev%d[%ld*%d] = {", key_type, table_name,
best_lev - lev - 1, cluster, k);
ofs = 0;
for (ii = 0; ii < k; ii++)
{
int kk, jj;
fprintf (f, "\n#define %sLev%d_%0*lX 0x%0X", table_name,
best_lev - lev - 1, digits, x[i] * pow[n - nn], ofs);
kk = x[i] * cluster;
if (!lev)
if (name)
for (j = 0; j < cluster; j++)
{
if (!(j % per_row) && j != cluster - 1)
fprintf (f, "\n ");
fprintf (f, "%*s,", tab_width, name[tab[lev][kk++]]);
}
else
for (j = 0; j < cluster; j++)
{
if (!(j % per_row) && j != cluster - 1)
fprintf (f, "\n ");
fprintf (f, "%*d,", tab_width, tab[lev][kk++]);
}
else
for (j = 0; j < cluster; j++, kk++)
fprintf (f, "\n %sLev%d_%0*lX, /* %0*lX..%0*lX */", table_name,
best_lev - lev, digits,
tab[lev][kk] * pow[n - nn - best_p[lev]], digits,
x[i] * pow[n - nn] + j * pow[n - nn - best_p[lev]], digits,
x[i] * pow[n - nn] + (j + 1) * pow[n - nn - best_p[lev]] -
1);
ofs += cluster;
jj = i;
for (j = 0; j < k; j++)
if (x[j] > x[i] && (x[j] < x[jj] || jj == i))
jj = j;
i = jj;
}
fprintf (f, "\n};\n\n");
lev++;
write_array (cluster * k);
lev--;
}
static void
write_source (
void
)
{
int i, j;
lev = 0;
s = 0;
nn = n;
t[0] = N;
fprintf (f, "\n" "/* *IND" "ENT-OFF* */\n\n");
write_array (0);
fprintf (f, "/* *IND" "ENT-ON* */\n\n");
fprintf (f, "#define %s(x) \\\n", macro_name);
fprintf (f, "\t((x) >= 0x%lx ? ", N);
if (name)
fprintf (f, "%s", name[def_key]);
else
fprintf (f, "%d", def_key);
fprintf (f, " : ");
j = 0;
for (i = best_lev - 1; i >= 0; i--)
{
fprintf (f, " \\\n\t%sLev%d[((x)", table_name, i);
if (j != 0)
fprintf (f, " >> %d", j);
if (i)
fprintf (f, " & 0x%02lx) +", pow[best_p[best_lev - 1 - i]] - 1);
j += best_p[best_lev - 1 - i];
}
fprintf (f, ")");
for (i = 0; i < best_lev; i++)
fprintf (f, "]");
fprintf (f, ")\n\n");
}
static void
write_out (
void
)
{
int i;
fprintf (f, "/*\n"
" generated by packtab.c version %d\n\n"
" use %s(key) to access your table\n\n"
" assumed sizeof(%s): %d\n"
" required memory: %ld\n"
" lookups: %d\n"
" partition shape: %s",
packtab_version, macro_name, key_type_name, a, best_s, best_lev,
table_name);
for (i = best_lev - 1; i >= 0; i--)
fprintf (f, "[%ld]", best_cluster[i]);
fprintf (f, "\n" " different table entries:");
for (i = best_lev - 1; i >= 0; i--)
fprintf (f, " %ld", best_c[i]);
fprintf (f, "\n*/\n");
write_source ();
}
int
pack_table (
const signed int *base,
long key_num,
int key_size,
signed int default_key,
int p_max_depth,
int p_tab_width,
const char *const *p_name,
const char *p_key_type_name,
const char *p_table_name,
const char *p_macro_name,
FILE *out
)
{
N = key_num;
a = key_size;
def_key = default_key;
max_depth = p_max_depth;
tab_width = p_tab_width;
name = p_name;
key_type_name = p_key_type_name;
table_name = p_table_name;
macro_name = p_macro_name;
f = out;
init (base);
if (!(tab = malloc ((n + 1) * sizeof (tab[0]))))
return 0;
memmove (tab[0], base, N * sizeof (base[0]));
solve ();
write_out ();
free (tab);
return 1;
}
/* End of packtab.c */

View file

@ -0,0 +1,48 @@
/* PackTab - Pack a static table
* Copyright (C) 2001 Behdad Esfahbod.
*
* 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/>.
*
* For licensing issues, contact <fwpg@sharif.edu>.
*/
#ifndef PACKTAB_H
#define PACKTAB_H
#ifdef __cplusplus
extern "C"
{
#endif
#define packtab_version 3
int pack_table (
const signed int *base,
long key_num,
int key_size,
signed int default_key,
int max_depth,
int tab_width,
const char *const *name,
const char *key_type_name,
const char *table_name,
const char *macro_name,
FILE *out
);
#ifdef __cplusplus
}
#endif
#endif /* PACKTAB_H */

44
glib/glib-object.h Normal file
View file

@ -0,0 +1,44 @@
/* GObject - GLib Type, Object, Parameter and Signal Library
* Copyright (C) 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
*
* 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/>.
*/
#ifndef __GLIB_GOBJECT_H__
#define __GLIB_GOBJECT_H__
#define __GLIB_GOBJECT_H_INSIDE__
#include <gobject/gbinding.h>
#include <gobject/gbindinggroup.h>
#include <gobject/gboxed.h>
#include <gobject/genums.h>
#include <gobject/glib-enumtypes.h>
#include <gobject/gobject.h>
#include <gobject/gparam.h>
#include <gobject/gparamspecs.h>
#include <gobject/gsignal.h>
#include <gobject/gsignalgroup.h>
#include <gobject/gsourceclosure.h>
#include <gobject/gtype.h>
#include <gobject/gtypemodule.h>
#include <gobject/gtypeplugin.h>
#include <gobject/gvaluearray.h>
#include <gobject/gvalue.h>
#include <gobject/gvaluetypes.h>
#include <gobject/gobject-autocleanups.h>
#undef __GLIB_GOBJECT_H_INSIDE__
#endif /* __GLIB_GOBJECT_H__ */

62
glib/glib-private.c Normal file
View file

@ -0,0 +1,62 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 2011 Red Hat, Inc.
*
* 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/>.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include "glib-private.h"
#include "glib-init.h"
/**
* glib__private__:
* @arg: Do not use this argument
*
* Do not call this function; it is used to share private
* API between glib, gobject, and gio.
*/
GLibPrivateVTable *
glib__private__ (void)
{
static GLibPrivateVTable table = {
g_wakeup_new,
g_wakeup_free,
g_wakeup_get_pollfd,
g_wakeup_signal,
g_wakeup_acknowledge,
g_get_worker_context,
g_check_setuid,
g_main_context_new_with_next_id,
g_dir_open_with_errno,
g_dir_new_from_dirp,
glib_init,
#ifdef G_OS_WIN32
g_win32_stat_utf8,
g_win32_lstat_utf8,
g_win32_readlink_utf8,
g_win32_fstat,
g_win32_find_helper_executable_path,
#endif
};
return &table;
}

204
glib/glib-private.h Normal file
View file

@ -0,0 +1,204 @@
/* glib-private.h - GLib-internal private API, shared between glib, gobject, gio
* Copyright (C) 2011 Red Hat, Inc.
*
* 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/>.
*/
#ifndef __GLIB_PRIVATE_H__
#define __GLIB_PRIVATE_H__
#include <glib.h>
#include "gwakeup.h"
#include "gstdioprivate.h"
/* gcc defines __SANITIZE_ADDRESS__, clang sets the address_sanitizer
* feature flag.
*
* MSVC defines __SANITIZE_ADDRESS__ as well when AddressSanitizer
* is enabled but __lsan_ignore_object() equivalent method is not supported
* See also
* https://docs.microsoft.com/en-us/cpp/sanitizers/asan-building?view=msvc-160
*/
#if !defined(_MSC_VER) && (defined(__SANITIZE_ADDRESS__) || g_macro__has_feature(address_sanitizer))
/*
* %_GLIB_ADDRESS_SANITIZER:
*
* Private macro defined if the AddressSanitizer is in use.
*/
#define _GLIB_ADDRESS_SANITIZER
#include <sanitizer/lsan_interface.h>
#endif
/*
* g_ignore_leak:
* @p: any pointer
*
* Tell AddressSanitizer and similar tools that if the object pointed to
* by @p is leaked, it is not a problem. Use this to suppress memory leak
* reports when a potentially unreachable pointer is deliberately not
* going to be deallocated.
*/
static inline void
g_ignore_leak (gconstpointer p)
{
#ifdef _GLIB_ADDRESS_SANITIZER
if (p != NULL)
__lsan_ignore_object (p);
#endif
}
/*
* g_ignore_strv_leak:
* @strv: (nullable) (array zero-terminated=1): an array of strings
*
* The same as g_ignore_leak(), but for the memory pointed to by @strv,
* and for each element of @strv.
*/
static inline void
g_ignore_strv_leak (GStrv strv)
{
#ifdef _GLIB_ADDRESS_SANITIZER
gchar **item;
if (strv)
{
g_ignore_leak (strv);
for (item = strv; *item != NULL; item++)
g_ignore_leak (*item);
}
#endif
}
/*
* g_begin_ignore_leaks:
*
* Tell AddressSanitizer and similar tools to ignore all leaks from this point
* onwards, until g_end_ignore_leaks() is called.
*
* Try to use g_ignore_leak() where possible to target deliberate leaks more
* specifically.
*/
static inline void
g_begin_ignore_leaks (void)
{
#ifdef _GLIB_ADDRESS_SANITIZER
__lsan_disable ();
#endif
}
/*
* g_end_ignore_leaks:
*
* Start ignoring leaks again; this must be paired with a previous call to
* g_begin_ignore_leaks().
*/
static inline void
g_end_ignore_leaks (void)
{
#ifdef _GLIB_ADDRESS_SANITIZER
__lsan_enable ();
#endif
}
GMainContext * g_get_worker_context (void);
gboolean g_check_setuid (void);
GMainContext * g_main_context_new_with_next_id (guint next_id);
#ifdef G_OS_WIN32
GLIB_AVAILABLE_IN_ALL
gchar *_glib_get_locale_dir (void);
#endif
GDir * g_dir_open_with_errno (const gchar *path, guint flags);
GDir * g_dir_new_from_dirp (gpointer dirp);
#define GLIB_PRIVATE_CALL(symbol) (glib__private__()->symbol)
typedef struct {
/* See gwakeup.c */
GWakeup * (* g_wakeup_new) (void);
void (* g_wakeup_free) (GWakeup *wakeup);
void (* g_wakeup_get_pollfd) (GWakeup *wakeup,
GPollFD *poll_fd);
void (* g_wakeup_signal) (GWakeup *wakeup);
void (* g_wakeup_acknowledge) (GWakeup *wakeup);
/* See gmain.c */
GMainContext * (* g_get_worker_context) (void);
gboolean (* g_check_setuid) (void);
GMainContext * (* g_main_context_new_with_next_id) (guint next_id);
GDir * (* g_dir_open_with_errno) (const gchar *path,
guint flags);
GDir * (* g_dir_new_from_dirp) (gpointer dirp);
/* See glib-init.c */
void (* glib_init) (void);
/* See gstdio.c */
#ifdef G_OS_WIN32
int (* g_win32_stat_utf8) (const gchar *filename,
GWin32PrivateStat *buf);
int (* g_win32_lstat_utf8) (const gchar *filename,
GWin32PrivateStat *buf);
int (* g_win32_readlink_utf8) (const gchar *filename,
gchar *buf,
gsize buf_size,
gchar **alloc_buf,
gboolean terminate);
int (* g_win32_fstat) (int fd,
GWin32PrivateStat *buf);
/* See gwin32.c */
gchar *(*g_win32_find_helper_executable_path) (const gchar *process_name,
void *dll_handle);
#endif
/* Add other private functions here, initialize them in glib-private.c */
} GLibPrivateVTable;
GLIB_AVAILABLE_IN_ALL
GLibPrivateVTable *glib__private__ (void);
/* Please see following for the use of ".ACP" over ""
* on Windows, although both are accepted at compile-time
* but "" renders translated console messages unreadable if
* built with Visual Studio 2012 and later (this is, unfortunately,
* undocumented):
*
* https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale
* https://gitlab.gnome.org/GNOME/glib/merge_requests/895#note_525881
* https://gitlab.gnome.org/GNOME/glib/merge_requests/895#note_525900
*
* Additional related items:
* https://stackoverflow.com/questions/22604329/php-5-5-setlocale-not-working-in-cli-on-windows
* https://bugs.php.net/bug.php?id=66265
*/
#ifdef G_OS_WIN32
# define GLIB_DEFAULT_LOCALE ".ACP"
#else
# define GLIB_DEFAULT_LOCALE ""
#endif
#endif /* __GLIB_PRIVATE_H__ */

43
glib/glib-typeof.h Normal file
View file

@ -0,0 +1,43 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 2021 Iain Lane, Xavier Claessens
*
* 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/>.
*/
#ifndef __GLIB_TYPEOF_H__
#define __GLIB_TYPEOF_H__
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gversionmacros.h>
/*
* We can only use __typeof__ on GCC >= 4.8, and not when compiling C++. Since
* __typeof__ is used in a few places in GLib, provide a pre-processor symbol
* to factor the check out from callers.
*
* This symbol is private.
*/
#undef glib_typeof
#if !defined(__cplusplus) && (G_GNUC_CHECK_VERSION(4, 8) || defined(__clang__))
#define glib_typeof(t) __typeof__ (t)
#elif defined(__cplusplus) && __cplusplus >= 201103L && GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_68
/* C++11 decltype() is close enough for our usage */
#include <type_traits>
#define glib_typeof(t) typename std::remove_reference<decltype (t)>::type
#endif
#endif /* __GLIB_TYPEOF_H__ */

546
glib/glib-unix.c Normal file
View file

@ -0,0 +1,546 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 2011 Red Hat, Inc.
*
* glib-unix.c: UNIX specific API wrappers and convenience functions
*
* 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/>.
*
* Authors: Colin Walters <walters@verbum.org>
*/
#include "config.h"
/* To make bionic export pipe2() */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include "glib-unix.h"
#include "gmain-internal.h"
#include <string.h>
#include <sys/types.h>
#include <pwd.h>
G_STATIC_ASSERT (sizeof (ssize_t) == GLIB_SIZEOF_SSIZE_T);
G_STATIC_ASSERT (G_ALIGNOF (gssize) == G_ALIGNOF (ssize_t));
G_STATIC_ASSERT (sizeof (GPid) == sizeof (pid_t));
G_STATIC_ASSERT (G_ALIGNOF (GPid) == G_ALIGNOF (pid_t));
/**
* SECTION:gunix
* @title: UNIX-specific utilities and integration
* @short_description: pipes, signal handling
* @include: glib-unix.h
*
* Most of GLib is intended to be portable; in contrast, this set of
* functions is designed for programs which explicitly target UNIX,
* or are using it to build higher level abstractions which would be
* conditionally compiled if the platform matches %G_OS_UNIX.
*
* To use these functions, you must explicitly include the
* "glib-unix.h" header.
*/
G_DEFINE_QUARK (g-unix-error-quark, g_unix_error)
static gboolean
g_unix_set_error_from_errno (GError **error,
gint saved_errno)
{
g_set_error_literal (error,
G_UNIX_ERROR,
0,
g_strerror (saved_errno));
errno = saved_errno;
return FALSE;
}
/**
* g_unix_open_pipe:
* @fds: (array fixed-size=2): Array of two integers
* @flags: Bitfield of file descriptor flags, as for fcntl()
* @error: a #GError
*
* Similar to the UNIX pipe() call, but on modern systems like Linux
* uses the pipe2() system call, which atomically creates a pipe with
* the configured flags. The only supported flag currently is
* %FD_CLOEXEC. If for example you want to configure %O_NONBLOCK, that
* must still be done separately with fcntl().
*
* This function does not take %O_CLOEXEC, it takes %FD_CLOEXEC as if
* for fcntl(); these are different on Linux/glibc.
*
* Returns: %TRUE on success, %FALSE if not (and errno will be set).
*
* Since: 2.30
*/
gboolean
g_unix_open_pipe (int *fds,
int flags,
GError **error)
{
int ecode;
/* We only support FD_CLOEXEC */
g_return_val_if_fail ((flags & (FD_CLOEXEC)) == flags, FALSE);
#ifdef HAVE_PIPE2
{
int pipe2_flags = 0;
if (flags & FD_CLOEXEC)
pipe2_flags |= O_CLOEXEC;
/* Atomic */
ecode = pipe2 (fds, pipe2_flags);
if (ecode == -1 && errno != ENOSYS)
return g_unix_set_error_from_errno (error, errno);
else if (ecode == 0)
return TRUE;
/* Fall through on -ENOSYS, we must be running on an old kernel */
}
#endif
ecode = pipe (fds);
if (ecode == -1)
return g_unix_set_error_from_errno (error, errno);
if (flags == 0)
return TRUE;
ecode = fcntl (fds[0], F_SETFD, flags);
if (ecode == -1)
{
int saved_errno = errno;
close (fds[0]);
close (fds[1]);
return g_unix_set_error_from_errno (error, saved_errno);
}
ecode = fcntl (fds[1], F_SETFD, flags);
if (ecode == -1)
{
int saved_errno = errno;
close (fds[0]);
close (fds[1]);
return g_unix_set_error_from_errno (error, saved_errno);
}
return TRUE;
}
/**
* g_unix_set_fd_nonblocking:
* @fd: A file descriptor
* @nonblock: If %TRUE, set the descriptor to be non-blocking
* @error: a #GError
*
* Control the non-blocking state of the given file descriptor,
* according to @nonblock. On most systems this uses %O_NONBLOCK, but
* on some older ones may use %O_NDELAY.
*
* Returns: %TRUE if successful
*
* Since: 2.30
*/
gboolean
g_unix_set_fd_nonblocking (gint fd,
gboolean nonblock,
GError **error)
{
#ifdef F_GETFL
glong fcntl_flags;
fcntl_flags = fcntl (fd, F_GETFL);
if (fcntl_flags == -1)
return g_unix_set_error_from_errno (error, errno);
if (nonblock)
{
#ifdef O_NONBLOCK
fcntl_flags |= O_NONBLOCK;
#else
fcntl_flags |= O_NDELAY;
#endif
}
else
{
#ifdef O_NONBLOCK
fcntl_flags &= ~O_NONBLOCK;
#else
fcntl_flags &= ~O_NDELAY;
#endif
}
if (fcntl (fd, F_SETFL, fcntl_flags) == -1)
return g_unix_set_error_from_errno (error, errno);
return TRUE;
#else
return g_unix_set_error_from_errno (error, EINVAL);
#endif
}
/**
* g_unix_signal_source_new:
* @signum: A signal number
*
* Create a #GSource that will be dispatched upon delivery of the UNIX
* signal @signum. In GLib versions before 2.36, only `SIGHUP`, `SIGINT`,
* `SIGTERM` can be monitored. In GLib 2.36, `SIGUSR1` and `SIGUSR2`
* were added. In GLib 2.54, `SIGWINCH` was added.
*
* Note that unlike the UNIX default, all sources which have created a
* watch will be dispatched, regardless of which underlying thread
* invoked g_unix_signal_source_new().
*
* For example, an effective use of this function is to handle `SIGTERM`
* cleanly; flushing any outstanding files, and then calling
* g_main_loop_quit(). It is not safe to do any of this from a regular
* UNIX signal handler; such a handler may be invoked while malloc() or
* another library function is running, causing reentrancy issues if the
* handler attempts to use those functions. None of the GLib/GObject
* API is safe against this kind of reentrancy.
*
* The interaction of this source when combined with native UNIX
* functions like sigprocmask() is not defined.
*
* The source will not initially be associated with any #GMainContext
* and must be added to one with g_source_attach() before it will be
* executed.
*
* Returns: A newly created #GSource
*
* Since: 2.30
*/
GSource *
g_unix_signal_source_new (int signum)
{
g_return_val_if_fail (signum == SIGHUP || signum == SIGINT || signum == SIGTERM ||
signum == SIGUSR1 || signum == SIGUSR2 || signum == SIGWINCH,
NULL);
return _g_main_create_unix_signal_watch (signum);
}
/**
* g_unix_signal_add_full: (rename-to g_unix_signal_add)
* @priority: the priority of the signal source. Typically this will be in
* the range between %G_PRIORITY_DEFAULT and %G_PRIORITY_HIGH.
* @signum: Signal number
* @handler: Callback
* @user_data: Data for @handler
* @notify: #GDestroyNotify for @handler
*
* A convenience function for g_unix_signal_source_new(), which
* attaches to the default #GMainContext. You can remove the watch
* using g_source_remove().
*
* Returns: An ID (greater than 0) for the event source
*
* Since: 2.30
*/
guint
g_unix_signal_add_full (int priority,
int signum,
GSourceFunc handler,
gpointer user_data,
GDestroyNotify notify)
{
guint id;
GSource *source;
source = g_unix_signal_source_new (signum);
if (priority != G_PRIORITY_DEFAULT)
g_source_set_priority (source, priority);
g_source_set_callback (source, handler, user_data, notify);
id = g_source_attach (source, NULL);
g_source_unref (source);
return id;
}
/**
* g_unix_signal_add:
* @signum: Signal number
* @handler: Callback
* @user_data: Data for @handler
*
* A convenience function for g_unix_signal_source_new(), which
* attaches to the default #GMainContext. You can remove the watch
* using g_source_remove().
*
* Returns: An ID (greater than 0) for the event source
*
* Since: 2.30
*/
guint
g_unix_signal_add (int signum,
GSourceFunc handler,
gpointer user_data)
{
return g_unix_signal_add_full (G_PRIORITY_DEFAULT, signum, handler, user_data, NULL);
}
typedef struct
{
GSource source;
gint fd;
gpointer tag;
} GUnixFDSource;
static gboolean
g_unix_fd_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
GUnixFDSource *fd_source = (GUnixFDSource *) source;
GUnixFDSourceFunc func = (GUnixFDSourceFunc) callback;
if (!callback)
{
g_warning ("GUnixFDSource dispatched without callback. "
"You must call g_source_set_callback().");
return FALSE;
}
return (* func) (fd_source->fd, g_source_query_unix_fd (source, fd_source->tag), user_data);
}
GSourceFuncs g_unix_fd_source_funcs = {
NULL, NULL, g_unix_fd_source_dispatch, NULL, NULL, NULL
};
/**
* g_unix_fd_source_new:
* @fd: a file descriptor
* @condition: IO conditions to watch for on @fd
*
* Creates a #GSource to watch for a particular IO condition on a file
* descriptor.
*
* The source will never close the fd -- you must do it yourself.
*
* Returns: the newly created #GSource
*
* Since: 2.36
**/
GSource *
g_unix_fd_source_new (gint fd,
GIOCondition condition)
{
GUnixFDSource *fd_source;
GSource *source;
source = g_source_new (&g_unix_fd_source_funcs, sizeof (GUnixFDSource));
fd_source = (GUnixFDSource *) source;
fd_source->fd = fd;
fd_source->tag = g_source_add_unix_fd (source, fd, condition);
return source;
}
/**
* g_unix_fd_add_full:
* @priority: the priority of the source
* @fd: a file descriptor
* @condition: IO conditions to watch for on @fd
* @function: a #GUnixFDSourceFunc
* @user_data: data to pass to @function
* @notify: function to call when the idle is removed, or %NULL
*
* Sets a function to be called when the IO condition, as specified by
* @condition becomes true for @fd.
*
* This is the same as g_unix_fd_add(), except that it allows you to
* specify a non-default priority and a provide a #GDestroyNotify for
* @user_data.
*
* Returns: the ID (greater than 0) of the event source
*
* Since: 2.36
**/
guint
g_unix_fd_add_full (gint priority,
gint fd,
GIOCondition condition,
GUnixFDSourceFunc function,
gpointer user_data,
GDestroyNotify notify)
{
GSource *source;
guint id;
g_return_val_if_fail (function != NULL, 0);
source = g_unix_fd_source_new (fd, condition);
if (priority != G_PRIORITY_DEFAULT)
g_source_set_priority (source, priority);
g_source_set_callback (source, (GSourceFunc) function, user_data, notify);
id = g_source_attach (source, NULL);
g_source_unref (source);
return id;
}
/**
* g_unix_fd_add:
* @fd: a file descriptor
* @condition: IO conditions to watch for on @fd
* @function: a #GUnixFDSourceFunc
* @user_data: data to pass to @function
*
* Sets a function to be called when the IO condition, as specified by
* @condition becomes true for @fd.
*
* @function will be called when the specified IO condition becomes
* %TRUE. The function is expected to clear whatever event caused the
* IO condition to become true and return %TRUE in order to be notified
* when it happens again. If @function returns %FALSE then the watch
* will be cancelled.
*
* The return value of this function can be passed to g_source_remove()
* to cancel the watch at any time that it exists.
*
* The source will never close the fd -- you must do it yourself.
*
* Returns: the ID (greater than 0) of the event source
*
* Since: 2.36
**/
guint
g_unix_fd_add (gint fd,
GIOCondition condition,
GUnixFDSourceFunc function,
gpointer user_data)
{
return g_unix_fd_add_full (G_PRIORITY_DEFAULT, fd, condition, function, user_data, NULL);
}
/**
* g_unix_get_passwd_entry:
* @user_name: the username to get the passwd file entry for
* @error: return location for a #GError, or %NULL
*
* Get the `passwd` file entry for the given @user_name using `getpwnam_r()`.
* This can fail if the given @user_name doesnt exist.
*
* The returned `struct passwd` has been allocated using g_malloc() and should
* be freed using g_free(). The strings referenced by the returned struct are
* included in the same allocation, so are valid until the `struct passwd` is
* freed.
*
* This function is safe to call from multiple threads concurrently.
*
* You will need to include `pwd.h` to get the definition of `struct passwd`.
*
* Returns: (transfer full): passwd entry, or %NULL on error; free the returned
* value with g_free()
* Since: 2.64
*/
struct passwd *
g_unix_get_passwd_entry (const gchar *user_name,
GError **error)
{
struct passwd *passwd_file_entry;
struct
{
struct passwd pwd;
char string_buffer[];
} *buffer = NULL;
gsize string_buffer_size = 0;
GError *local_error = NULL;
g_return_val_if_fail (user_name != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
#ifdef _SC_GETPW_R_SIZE_MAX
{
/* Get the recommended buffer size */
glong string_buffer_size_long = sysconf (_SC_GETPW_R_SIZE_MAX);
if (string_buffer_size_long > 0)
string_buffer_size = string_buffer_size_long;
}
#endif /* _SC_GETPW_R_SIZE_MAX */
/* Default starting size. */
if (string_buffer_size == 0)
string_buffer_size = 64;
do
{
int retval;
g_free (buffer);
/* Allocate space for the `struct passwd`, and then a buffer for all its
* strings (whose size is @string_buffer_size, which increases in this
* loop until its big enough). Add 6 extra bytes to work around a bug in
* macOS < 10.3. See #156446.
*/
buffer = g_malloc0 (sizeof (*buffer) + string_buffer_size + 6);
retval = getpwnam_r (user_name, &buffer->pwd, buffer->string_buffer,
string_buffer_size, &passwd_file_entry);
/* Bail out if: the lookup was successful, or if the user id can't be
* found (should be pretty rare case actually), or if the buffer should be
* big enough and yet lookups are still not successful.
*/
if (passwd_file_entry != NULL)
{
/* Success. */
break;
}
else if (retval == 0 ||
retval == ENOENT || retval == ESRCH ||
retval == EBADF || retval == EPERM)
{
/* Username not found. */
g_unix_set_error_from_errno (&local_error, retval);
break;
}
else if (retval == ERANGE)
{
/* Cant allocate enough string buffer space. */
if (string_buffer_size > 32 * 1024)
{
g_unix_set_error_from_errno (&local_error, retval);
break;
}
string_buffer_size *= 2;
continue;
}
else
{
g_unix_set_error_from_errno (&local_error, retval);
break;
}
}
while (passwd_file_entry == NULL);
g_assert (passwd_file_entry == NULL ||
(gpointer) passwd_file_entry == (gpointer) buffer);
/* Success or error. */
if (local_error != NULL)
{
g_clear_pointer (&buffer, g_free);
g_propagate_error (error, g_steal_pointer (&local_error));
}
return (struct passwd *) g_steal_pointer (&buffer);
}

123
glib/glib-unix.h Normal file
View file

@ -0,0 +1,123 @@
/* glib-unix.h - Unix specific integration
* Copyright (C) 2011 Red Hat, Inc.
*
* 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/>.
*/
#ifndef __G_UNIX_H__
#define __G_UNIX_H__
/* We need to include the UNIX headers needed to use the APIs below,
* but we also take this opportunity to include a wide selection of
* other UNIX headers. If one of the headers below is broken on some
* system, work around it here (or better, fix the system or tell
* people to use a better one).
*/
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <fcntl.h>
#include <glib.h>
#ifndef G_OS_UNIX
#error "This header may only be used on UNIX"
#endif
G_BEGIN_DECLS
/**
* G_UNIX_ERROR:
*
* Error domain for API in the g_unix_ namespace. Note that there is no
* exported enumeration mapping %errno. Instead, all functions ensure that
* %errno is relevant. The code for all %G_UNIX_ERROR is always 0, and the
* error message is always generated via g_strerror().
*
* It is expected that most code will not look at %errno from these APIs.
* Important cases where one would want to differentiate between errors are
* already covered by existing cross-platform GLib API, such as e.g. #GFile
* wrapping `ENOENT`. However, it is provided for completeness, at least.
*/
#define G_UNIX_ERROR (g_unix_error_quark())
GLIB_AVAILABLE_IN_2_30
GQuark g_unix_error_quark (void);
GLIB_AVAILABLE_IN_2_30
gboolean g_unix_open_pipe (gint *fds,
gint flags,
GError **error);
GLIB_AVAILABLE_IN_2_30
gboolean g_unix_set_fd_nonblocking (gint fd,
gboolean nonblock,
GError **error);
GLIB_AVAILABLE_IN_2_30
GSource *g_unix_signal_source_new (gint signum);
GLIB_AVAILABLE_IN_2_30
guint g_unix_signal_add_full (gint priority,
gint signum,
GSourceFunc handler,
gpointer user_data,
GDestroyNotify notify);
GLIB_AVAILABLE_IN_2_30
guint g_unix_signal_add (gint signum,
GSourceFunc handler,
gpointer user_data);
/**
* GUnixFDSourceFunc:
* @fd: the fd that triggered the event
* @condition: the IO conditions reported on @fd
* @user_data: user data passed to g_unix_fd_add()
*
* The type of functions to be called when a UNIX fd watch source
* triggers.
*
* Returns: %FALSE if the source should be removed
**/
typedef gboolean (*GUnixFDSourceFunc) (gint fd,
GIOCondition condition,
gpointer user_data);
GLIB_AVAILABLE_IN_2_36
GSource *g_unix_fd_source_new (gint fd,
GIOCondition condition);
GLIB_AVAILABLE_IN_2_36
guint g_unix_fd_add_full (gint priority,
gint fd,
GIOCondition condition,
GUnixFDSourceFunc function,
gpointer user_data,
GDestroyNotify notify);
GLIB_AVAILABLE_IN_2_36
guint g_unix_fd_add (gint fd,
GIOCondition condition,
GUnixFDSourceFunc function,
gpointer user_data);
GLIB_AVAILABLE_IN_2_64
struct passwd *g_unix_get_passwd_entry (const gchar *user_name,
GError **error);
G_END_DECLS
#endif /* __G_UNIX_H__ */

119
glib/glib.h Normal file
View file

@ -0,0 +1,119 @@
/* 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.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/.
*/
#ifndef __G_LIB_H__
#define __G_LIB_H__
#define __GLIB_H_INSIDE__
#include <glib/galloca.h>
#include <glib/garray.h>
#include <glib/gasyncqueue.h>
#include <glib/gatomic.h>
#include <glib/gbacktrace.h>
#include <glib/gbase64.h>
#include <glib/gbitlock.h>
#include <glib/gbookmarkfile.h>
#include <glib/gbytes.h>
#include <glib/gcharset.h>
#include <glib/gchecksum.h>
#include <glib/gconvert.h>
#include <glib/gdataset.h>
#include <glib/gdate.h>
#include <glib/gdatetime.h>
#include <glib/gdir.h>
#include <glib/genviron.h>
#include <glib/gerror.h>
#include <glib/gfileutils.h>
#include <glib/ggettext.h>
#include <glib/ghash.h>
#include <glib/ghmac.h>
#include <glib/ghook.h>
#include <glib/ghostutils.h>
#include <glib/giochannel.h>
#include <glib/gkeyfile.h>
#include <glib/glist.h>
#include <glib/gmacros.h>
#include <glib/gmain.h>
#include <glib/gmappedfile.h>
#include <glib/gmarkup.h>
#include <glib/gmem.h>
#include <glib/gmessages.h>
#include <glib/gnode.h>
#include <glib/goption.h>
#include <glib/gpattern.h>
#include <glib/gpoll.h>
#include <glib/gprimes.h>
#include <glib/gqsort.h>
#include <glib/gquark.h>
#include <glib/gqueue.h>
#include <glib/grand.h>
#include <glib/grcbox.h>
#include <glib/grefcount.h>
#include <glib/grefstring.h>
#include <glib/gregex.h>
#include <glib/gscanner.h>
#include <glib/gsequence.h>
#include <glib/gshell.h>
#include <glib/gslice.h>
#include <glib/gslist.h>
#include <glib/gspawn.h>
#include <glib/gstrfuncs.h>
#include <glib/gstringchunk.h>
#include <glib/gstring.h>
#include <glib/gstrvbuilder.h>
#include <glib/gtestutils.h>
#include <glib/gthread.h>
#include <glib/gthreadpool.h>
#include <glib/gtimer.h>
#include <glib/gtimezone.h>
#include <glib/gtrashstack.h>
#include <glib/gtree.h>
#include <glib/gtypes.h>
#include <glib/gunicode.h>
#include <glib/guri.h>
#include <glib/gutils.h>
#include <glib/guuid.h>
#include <glib/gvariant.h>
#include <glib/gvarianttype.h>
#include <glib/gversion.h>
#include <glib/gversionmacros.h>
#ifdef G_PLATFORM_WIN32
#include <glib/gwin32.h>
#endif
#include <glib/deprecated/gallocator.h>
#include <glib/deprecated/gcache.h>
#include <glib/deprecated/gcompletion.h>
#include <glib/deprecated/gmain.h>
#include <glib/deprecated/grel.h>
#include <glib/deprecated/gthread.h>
#include <glib/glib-autocleanups.h>
#include <glib/glib-typeof.h>
#undef __GLIB_H_INSIDE__
#endif /* __G_LIB_H__ */

30
glib/glib.rc.in Normal file
View file

@ -0,0 +1,30 @@
#include <winver.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION @GLIB_MAJOR_VERSION@,@GLIB_MINOR_VERSION@,@GLIB_MICRO_VERSION@,0
PRODUCTVERSION @GLIB_MAJOR_VERSION@,@GLIB_MINOR_VERSION@,@GLIB_MICRO_VERSION@,0
FILEFLAGSMASK 0
FILEFLAGS 0
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0"
BEGIN
VALUE "CompanyName", "The GLib developer community"
VALUE "FileDescription", "GLib"
VALUE "FileVersion", "@GLIB_VERSION@.0"
VALUE "InternalName", "libglib-2.0-@LT_CURRENT_MINUS_AGE@"
VALUE "LegalCopyright", "Copyright 1995-2011 Peter Mattis, Spencer Kimball, Josh MacDonald and others."
VALUE "OriginalFilename", "libglib-2.0-@LT_CURRENT_MINUS_AGE@.dll"
VALUE "ProductName", "GLib"
VALUE "ProductVersion", "@GLIB_VERSION@"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

645
glib/glib.stp.in Normal file
View file

@ -0,0 +1,645 @@
global glib_quarks_2_0_@LT_CURRENT@_@LT_REVISION@
/* This is needed to keep track of gquark for use in other probes.*/
probe process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("quark__new")
{
glib_quarks_2_0_@LT_CURRENT@_@LT_REVISION@[pid(), $arg2] = user_string($arg1)
}
/**
* probe glib.quark_new - Called when a #GQuark is initially created
* @quark: integer value for the quark
* @str: string form of the quark
*/
probe glib.quark_new = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("quark__new")
{
str = user_string ($arg1);
quark = $arg2;
probestr = sprintf("glib.quark_new(%s) -> %d", str, quark);
}
/**
* probe glib.mem_alloc - Called when a malloc block is initially requested
* @mem: Raw memory pointer returned
* @n_bytes: number of bytes
* @zeroed: Boolean value, %TRUE if this block was filled with NUL bytes
* @failable: Boolean value, %TRUE if program execution can continue on allocation failure
*/
probe glib.mem_alloc = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("mem__alloc")
{
mem = $arg1;
n_bytes = $arg2;
zeroed = $arg3;
failable = $arg4;
probestr = sprintf("glib.mem_alloc(n_bytes=%d) -> %p", n_bytes, mem);
}
/**
* probe glib.mem_free - Called when a malloc block freed
*/
probe glib.mem_free = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("mem__free")
{
mem = $arg1; /* ARG: @mem: Raw memory pointer */
probestr = sprintf("glib.mem_free(mem=%p)", mem);
}
/**
* probe glib.mem_realloc - Called when a malloc block is resized
* @mem: Raw memory pointer returned
* @old_mem: Original memory pointer
* @n_bytes: number of bytes
* @failable: Boolean value, %TRUE if program execution can continue on allocation failure
*/
probe glib.mem_realloc = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("mem__realloc")
{
mem = $arg1;
old_mem = $arg2;
n_bytes = $arg3;
failable = $arg4;
probestr = sprintf("glib.mem_realloc(old_mem=%p, n_bytes=%d) -> %p", old_mem, n_bytes, mem);
}
/**
* probe glib.slice_alloc - Called when g_slice_alloc() is used
* @mem: Raw memory pointer returned
* @n_bytes: number of bytes
*/
probe glib.slice_alloc = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("slice__alloc")
{
mem = $arg1;
n_bytes = $arg2;
probestr = sprintf("glib.slice_alloc(n_bytes=%d) -> %p", n_bytes, mem);
}
/**
* probe glib.slice_free - Called when memory slice is freed
* @mem: Raw memory pointer returned
* @n_bytes: Number of bytes
*/
probe glib.slice_free = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("slice__free")
{
mem = $arg1;
n_bytes = $arg2;
probestr = sprintf("glib.slice_free(n_bytes=%d) -> %p", n_bytes, mem);
}
/**
* probe glib.main_after_prepare - Called after preparing a GSource
* @source: source pointer
* @prepare: prepare function pointer
* @source_timeout: callback function pointer
*/
probe glib.main_after_prepare = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__after_prepare")
{
source = $arg1;
prepare = $arg2;
source_timeout = $arg3;
probestr = sprintf("glib.main_after_prepare(source=%p, prepare=%p) -> %u", source, prepare, source_timeout);
}
/**
* probe glib.main_after_check - Called after checking a GSource
* @source: source pointer
* @check: check function pointer
* @result: result of the check call
*/
probe glib.main_after_check = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__after_check")
{
source = $arg1;
check = $arg2;
result = $arg3;
probestr = sprintf("glib.main_after_check(source=%p, check=%p) -> %u", source, check, result);
}
/**
* probe glib.main_before_dispatch - Called before dispatching a GSource
* @source: name of the source
* @source_ptr: source pointer
* @dispatch: dispatch function pointer
* @callback: callback function pointer
* @user_data: user data for @callback
*/
probe glib.main_before_dispatch = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__before_dispatch")
{
source = user_string2($arg1, "unnamed");
source_ptr = $arg2;
dispatch = $arg3;
callback = $arg4;
user_data = $arg5;
probestr = sprintf("glib.main_before_dispatch(source=%s(%p), dispatch=%p, callback=%p, user_data=%p)", source, source_ptr, dispatch, callback, user_data);
}
/**
* probe glib.main_after_dispatch - Called after dispatching a GSource
* @source: name of the source
* @source_ptr: source pointer
* @dispatch: dispatch function pointer
* @need_destroy: whether the source should be destroyed
*/
probe glib.main_after_dispatch = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__after_dispatch")
{
source = user_string2($arg1, "unnamed");
source_ptr = $arg2;
dispatch = $arg3;
need_destroy = $arg4;
probestr = sprintf("glib.main_after_dispatch(source=%s(%p), dispatch=%p) -> %u", source, source_ptr, dispatch, need_destroy);
}
/**
* probe glib.main_source_attach - Called when a #GSource is attached to a #GMainContext
* @source: name of the source
* @source_ptr: the #GSource
* @context: the #GMainContext the source is being attached to
* @id: the ID of the #GSource in the context
*/
probe glib.main_source_attach = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__source_attach")
{
source = user_string2($arg1, "unnamed");
source_ptr = $arg2;
context = $arg3;
id = $arg4;
probestr = sprintf("glib.main_source_attach(source=%s(%p), context=%p) -> %u", source, source_ptr, context, id);
}
/**
* probe glib.main_source_destroy - Called when a #GSource is destroyed from a #GMainContext
* @source: name of the source
* @source_ptr: the #GSource
* @context: the #GMainContext the source is being destroyed from
*/
probe glib.main_source_destroy = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__source_destroy")
{
source = user_string2($arg1, "unnamed");
source_ptr = $arg2;
context = $arg3;
probestr = sprintf("glib.main_source_destroy(source=%s(%p), context=%p)", source, source_ptr, context);
}
/*
* probe glib.main_context_default - Called when the default #GMainContext is created
* @context: pointer to the new default #GMainContext
*/
probe glib.main_context_default = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_default")
{
context = $arg1;
probestr = sprintf("glib.main_context_default() -> %p", context);
}
/**
* probe glib.main_context_new - Called when a #GMainContext is initially created
* @context: pointer to the new #GMainContext
*/
probe glib.main_context_new = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_new")
{
context = $arg1;
probestr = sprintf("glib.main_context_new() -> %p", context);
}
/**
* probe glib.main_context_acquire - Called when a thread tries to acquire a #GMainContext
* @context: the #GMainContext
* @success: TRUE if acquisition was successful; FALSE if there was contention
*/
probe glib.main_context_acquire = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_acquire")
{
context = $arg1;
success = $arg2;
probestr = sprintf("glib.main_context_acquire(context=%p) -> %u", context, success);
}
/**
* probe glib.main_context_release - Called when a thread releases a #GMainContext
* @context: the #GMainContext
*/
probe glib.main_context_release = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_release")
{
context = $arg1;
probestr = sprintf("glib.main_context_release(context=%p)", context);
}
/**
* probe glib.main_context_free - Called when a #GMainContext is freed
* @context: pointer to the #GMainContext to be freed
*/
probe glib.main_context_free = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_free")
{
context = $arg1;
probestr = sprintf("glib.main_context_free(context=%p)", context);
}
/**
* probe glib.main_context_push_thread_default - Called when a #GMainContext is pushed onto the thread default stack
* @context: a #GMainContext
*/
probe glib.main_context_push_thread_default = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_push_thread_default")
{
context = $arg1;
probestr = sprintf("glib.main_context_push_thread_default(context=%p)", context);
}
/**
* probe glib.main_context_pop_thread_default - Called when a #GMainContext is popped off the thread default stack
* @context: a #GMainContext
*/
probe glib.main_context_pop_thread_default = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_pop_thread_default")
{
context = $arg1;
probestr = sprintf("glib.main_context_pop_thread_default(context=%p)", context);
}
/**
* probe glib.main_context_before_prepare - Called before a #GMainContext calls prepare on all its #GSources
* @context: a #GMainContext
*/
probe glib.main_context_before_prepare = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_before_prepare")
{
context = $arg1;
probestr = sprintf("glib.main_context_before_prepare(context=%p)", context);
}
/**
* probe glib.main_context_after_prepare - Called after a #GMainContext calls prepare on all its #GSources
* @context: a #GMainContext
* @priority: priority of the highest priority ready #GSource
* @n_ready: number of #GSources ready
*/
probe glib.main_context_after_prepare = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_after_prepare")
{
context = $arg1;
priority = $arg2;
n_ready = $arg3;
probestr = sprintf("glib.main_context_after_prepare(context=%p) -> priority=%i,n_ready=%u", context, priority, n_ready);
}
/**
* probe glib.main_context_before_query - Called before a #GMainContext calls query on all its #GSources
* @context: a #GMainContext
* @max_priority: maximum priority #GSource to check
*/
probe glib.main_context_before_query = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_before_query")
{
context = $arg1;
max_priority = $arg2;
probestr = sprintf("glib.main_context_before_query(context=%p, max_priority=%i)", context, max_priority);
}
/**
* probe glib.main_context_after_query - Called after a #GMainContext calls query on all its #GSources
* @context: a #GMainContext
* @timeout: poll timeout to use
* @fds: array of FDs ready to be polled, of length @n_fds
* @n_fds: number of FDs ready to be polled
*/
probe glib.main_context_after_query = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_after_query")
{
context = $arg1;
timeout = $arg2;
fds = $arg3;
n_fds = $arg4;
probestr = sprintf("glib.main_context_after_query(context=%p) -> timeout=%u,fds=%p,n_fds=%u", context, timeout, fds, n_fds);
}
/**
* probe glib.main_context_before_check - Called before a #GMainContext calls check on all its #GSources
* @context: a #GMainContext
* @max_priority: maximum priority #GSource to check
* @fds: array of FDs to check, of length @n_fds
* @n_fds: number of FDs to check
*/
probe glib.main_context_before_check = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_before_check")
{
context = $arg1;
max_priority = $arg2;
fds = $arg3;
n_fds = $arg4;
probestr = sprintf("glib.main_context_before_check(context=%p, max_priority=%i, fds=%p, n_fds=%u)", context, max_priority, fds, n_fds);
}
/**
* probe glib.main_context_after_check - Called after a #GMainContext calls check on all its #GSources
* @context: a #GMainContext
* @n_ready: number of sources ready to be dispatched
*/
probe glib.main_context_after_check = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_after_check")
{
context = $arg1;
n_ready = $arg2;
probestr = sprintf("glib.main_context_after_check(context=%p) -> %u", context, n_ready);
}
/**
* probe glib.main_context_before_dispatch - Called before a #GMainContext calls dispatch on all its #GSources
* @context: a #GMainContext
*/
probe glib.main_context_before_dispatch = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_before_dispatch")
{
context = $arg1;
probestr = sprintf("glib.main_context_before_dispatch(context=%p)", context);
}
/**
* probe glib.main_context_after_dispatch - Called after a #GMainContext calls dispatch on all its #GSources
* @context: a #GMainContext
*/
probe glib.main_context_after_dispatch = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_after_dispatch")
{
context = $arg1;
probestr = sprintf("glib.main_context_after_dispatch(context=%p)", context);
}
/**
* probe glib.main_context_wakeup - Called when a wakeup call is made for a #GMainContext
* @context: a #GMainContext
*/
probe glib.main_context_wakeup = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_wakeup")
{
context = $arg1;
probestr = sprintf("glib.main_context_wakeup(context=%p)", context);
}
/**
* probe glib.main_context_wakeup_acknowledge - Called when a wakeup call is acknowledged by a #GMainContext
* @context: a #GMainContext
*/
probe glib.main_context_wakeup_acknowledge = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__context_wakeup_acknowledge")
{
context = $arg1;
probestr = sprintf("glib.main_context_wakeup_acknowledge(context=%p)", context);
}
/**
* probe glib.main_loop_new - Called when a #GMainLoop is initially created
* @loop: pointer to the new #GMainLoop
* @context: pointer to the parent #GMainContext
*/
probe glib.main_loop_new = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__loop_new")
{
loop = $arg1;
context = $arg2;
probestr = sprintf("glib.main_loop_new(%p) -> %p", context, loop);
}
/**
* probe glib.main_context_quit - Called when a #GMainLoop is quit
* @loop: pointer to the #GMainLoop to be quit
*/
probe glib.main_loop_quit = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("main__loop_quit")
{
loop = $arg1;
probestr = sprintf("glib.main_loop_quit(%p)", loop);
}
/**
* probe glib.idle_add - Called when g_idle_add() or g_idle_add_full() is called
* @source: the newly created idle #GSource
* @context: the #GMainContext the idle source was added to
* @id: the ID of the #GSource in the main context
* @priority: the priority of the idle source
* @func: the idle callback function
* @data: data to pass to the callback function
*/
probe glib.idle_add = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("idle__add")
{
source = $arg1;
context = $arg2;
id = $arg3;
priority = $arg4;
func = $arg5;
data = $arg6;
probestr = sprintf("glib.idle_add(%d, %p, %p) -> %p, %p, %u", priority, func, data, source, context, id);
}
/**
* probe glib.idle_dispatch - Called when an idle #GSource is dispatched
* @source: the idle #GSource
* @context: the #GMainContext the idle source was in
* @func: the idle callback function
* @data: data passed to the callback function
* @again: 1 if the idle function is to be scheduled again, 0 otherwise
*/
probe glib.idle_dispatch = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("idle__dispatch")
{
source = $arg1;
context = $arg2;
func = $arg3;
data = $arg4;
again = $arg5;
probestr = sprintf("glib.idle_dispatch(%p) -> %p, %p, %p, %u", source, context, func, data, again);
}
/**
* probe glib.timeout_add - Called when g_timeout_add() or g_timeout_add_full() is called
* @source: the newly created timeout #GSource
* @context: the #GMainContext the timeout source was added to
* @id: the ID of the #GSource in the main context
* @priority: the priority of the timeout source
* @interval: the time between dispatches of the source, in milliseconds
* @func: the timeout callback function
* @data: data to pass to the callback function
*/
probe glib.timeout_add = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("timeout__add")
{
source = $arg1;
context = $arg2;
id = $arg3;
priority = $arg4;
interval = $arg5;
func = $arg6;
data = $arg7;
probestr = sprintf("glib.timeout_add(%d, %u, %p, %p) -> %p, %p, %u", priority, interval, func, data, source, context, id);
}
/**
* probe glib.timeout_dispatch - Called when a timeout #GSource is dispatched
* @source: the timeout #GSource
* @context: the #GMainContext the timeout source was in
* @func: the timeout callback function
* @data: data passed to the callback function
* @again: 1 if the timeout is to be scheduled again, 0 otherwise
*/
probe glib.timeout_dispatch = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("timeout__dispatch")
{
source = $arg1;
context = $arg2;
func = $arg3;
data = $arg4;
again = $arg5;
probestr = sprintf("glib.timeout_dispatch(%p) -> %p, %p, %p, %u", source, context, func, data, again);
}
/**
* probe glib.source_new - Called when a new #GSource is created
* @source: the new #GSource
* @prepare: the prepare function for the #GSource
* @check: the check function for the #GSource
* @dispatch: the dispatch function for the #GSource
* @finalize: the finalize function for the #GSource
* @struct_size: the size of #GSource structure to allocate
*/
probe glib.source_new = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("source__new")
{
source = $arg1;
prepare = $arg2;
check = $arg3;
dispatch = $arg4;
finalize = $arg5;
struct_size = $arg6;
probestr = sprintf("glib.source_new(%p, %p, %p, %p, %u) -> %p", prepare, check, dispatch, finalize, struct_size, source);
}
/**
* probe glib.source_set_callback - Called when the callback on a #GSource is set
* @source: the #GSource
* @func: the new callback function for the source
* @data: data to pass to @func
* @notify: notify handler for @data
*/
probe glib.source_set_callback = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("source__set_callback")
{
source = $arg1;
func = $arg2;
data = $arg3;
notify = $arg4;
probestr = sprintf("glib.source_set_callback(%p, %p, %p, %p)", source, func, data, notify);
}
/**
* probe glib.source_set_callback_indirect - Called when an indirect callback on a #GSource is set
* @source: the #GSource
* @callback_data: data for @callback_funcs
* @ref: the indirect callback ref function
* @unref: the indirect callback unref function
* @get: the indirect callback getter function
*/
probe glib.source_set_callback_indirect = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("source__set_callback_indirect")
{
source = $arg1;
callback_data = $arg2;
ref = $arg3;
unref = $arg4;
get = $arg5;
probestr = sprintf("glib.source_set_callback_indirect(%p, %p, %p, %p, %p)", source, callback_data, ref, unref, get);
}
/**
* probe glib.source_set_ready_time - Called when the ready time is set on a #GSource
* @source: the #GSource
* @ready_time: the new ready time
*/
probe glib.source_set_ready_time = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("source__set_ready_time")
{
source = $arg1;
ready_time = $arg2;
probestr = sprintf("glib.source_set_ready_time(%p, %i)", source, ready_time);
}
/**
* probe glib.source_set_priority - Called when the priority is set on a #GSource
* @source: the #GSource
* @context: the context the source is attached to
* @priority: the new priority
*/
probe glib.source_set_priority = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("source__set_priority")
{
source = $arg1;
context = $arg2;
priority = $arg3;
probestr = sprintf("glib.source_set_priority(%p, %p, %i)", source, context, priority);
}
/**
* probe glib.source_add_child_source - Called when a child #GSource is added to another
* @source: the parent #GSource
* @child_source: the child #GSource
*/
probe glib.source_add_child_source = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("source__add_child_source")
{
source = $arg1;
child_source = $arg2;
probestr = sprintf("glib.source_add_child_source(%p, %p)", source, child_source);
}
/**
* probe glib.source_set_name - Called when the name is set for a #GSource
* @source: the #GSource
* @name: the new name
*/
probe glib.source_set_name = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("source__set_name")
{
source = $arg1;
name = user_string($arg2);
probestr = sprintf("glib.source_set_name(%p, %s)", source, name);
}
/**
* probe glib.source_before_free - Called before a #GSource is finalised
* @source: the #GSource
* @context: the context the #GSource is attached to, if any
* @finalize: the finalize function about to be called
*/
probe glib.source_before_free = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("source__before_free")
{
source = $arg1;
context = $arg2;
finalize = $arg3;
probestr = sprintf("glib.source_before_free(%p, %p, %p)", source, context, finalize);
}
/**
* probe glib.thread_spawned - Called from a newly spawned GThread, before the thread function is called
* @func: the #GThreadFunc about to be executed
* @data: data to be passed to @func
* @name: (nullable): the thread name
*/
probe glib.thread_spawned = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("thread__spawned")
{
func = $arg1;
data = $arg2;
name = user_string($arg3);
probestr = sprintf("glib.thread_spawned(%p, %p, %s)", func, data, name);
}
/**
* probe glib.rcbox_alloc - Called when a refcounted block is initially requested
* @mem: Raw memory pointer returned
* @n_bytes: number of bytes
* @atomic: Boolean value, %TRUE if this block is atomically refcounted
* @zeroed: Boolean value, %TRUE if this block was filled with NUL bytes
*/
probe glib.rcbox_alloc = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("rcbox__alloc")
{
mem = $arg1;
n_bytes = $arg2;
atomic = $arg3;
zeroed = $arg4;
probestr = sprintf("glib.rcbox_alloc(n_bytes=%d) -> %p", n_bytes, mem);
}
/**
* probe glib.rcbox_acquire - Called when a refcounted block acquires a ref
*/
probe glib.rcbox_acquire = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("rcbox__acquire")
{
mem = $arg1; /* ARG: @mem: Raw memory pointer */
atomic = $arg2; /* ARG: @atomic: Boolean value, %TRUE if the reference was acquired atomically */
probestr = sprintf("glib.rcbox_acquire(mem=%p)", mem);
}
/**
* probe glib.rcbox_release - Called when a refcounted block acquires a ref
*/
probe glib.rcbox_acquire = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("rcbox__release")
{
mem = $arg1; /* ARG: @mem: Raw memory pointer */
atomic = $arg2; /* ARG: @atomic: Boolean value, %TRUE if the reference was released atomically */
probestr = sprintf("glib.rcbox_release(mem=%p)", mem);
}
/**
* probe glib.rcbox_free - Called when a refcounted block is freed
*/
probe glib.rcbox_free = process("@ABS_GLIB_RUNTIME_LIBDIR@/libglib-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("rcbox__free")
{
mem = $arg1; /* ARG: @mem: Raw memory pointer */
probestr = sprintf("glib.rcbox_free(mem=%p)", mem);
}

300
glib/glib_gdb.py Normal file
View file

@ -0,0 +1,300 @@
import gdb
import sys
if sys.version_info[0] >= 3:
long = int
# This is not quite right, as local vars may override symname
def read_global_var(symname):
return gdb.selected_frame().read_var(symname)
def g_quark_to_string(quark):
if quark is None:
return None
quark = long(quark)
if quark == 0:
return None
try:
val = read_global_var("quarks")
max_q = long(read_global_var("quark_seq_id"))
except Exception:
try:
val = read_global_var("g_quarks")
max_q = long(read_global_var("g_quark_seq_id"))
except Exception:
return None
if quark < max_q:
return val[quark].string()
return None
# We override the node printers too, so that node->next is not expanded
class GListNodePrinter:
"Prints a GList node"
def __init__(self, val):
self.val = val
def to_string(self):
return "{data=%s, next=0x%x, prev=0x%x}" % (
str(self.val["data"]),
long(self.val["next"]),
long(self.val["prev"]),
)
class GSListNodePrinter:
"Prints a GSList node"
def __init__(self, val):
self.val = val
def to_string(self):
return "{data=%s, next=0x%x}" % (str(self.val["data"]), long(self.val["next"]))
class GListPrinter:
"Prints a GList"
class _iterator:
def __init__(self, head, listtype):
self.link = head
self.listtype = listtype
self.count = 0
def __iter__(self):
return self
def next(self):
if self.link == 0:
raise StopIteration
data = self.link["data"]
self.link = self.link["next"]
count = self.count
self.count = self.count + 1
return ("[%d]" % count, data)
__next__ = next
def __init__(self, val, listtype):
self.val = val
self.listtype = listtype
def children(self):
return self._iterator(self.val, self.listtype)
def to_string(self):
return "0x%x" % (long(self.val))
def display_hint(self):
return "array"
class GHashPrinter:
"Prints a GHashTable"
class _iterator:
class _pointer_array:
def __init__(self, ptr, big_items):
self._big_items = big_items
self._gpointer_type = gdb.lookup_type("gpointer")
item_type = (
self._gpointer_type if self._big_items else gdb.lookup_type("guint")
)
self._items = ptr.cast(item_type.pointer())
def __getitem__(self, item):
item = self._items[item]
if not self._big_items:
item = item.cast(self._gpointer_type)
return item
def __init__(self, ht, keys_are_strings):
self.ht = ht
if ht != 0:
self.keys = self._pointer_array(ht["keys"], ht["have_big_keys"])
self.values = self._pointer_array(ht["values"], ht["have_big_values"])
self.hashes = ht["hashes"]
self.size = ht["size"]
self.pos = 0
self.keys_are_strings = keys_are_strings
self.value = None
def __iter__(self):
return self
def next(self):
if self.ht == 0:
raise StopIteration
if self.value is not None:
v = self.value
self.value = None
return v
while long(self.pos) < long(self.size):
if long(self.hashes[self.pos]) >= 2:
key = self.keys[self.pos]
val = self.values[self.pos]
if self.keys_are_strings:
key = key.cast(gdb.lookup_type("char").pointer())
# Queue value for next result
self.value = ("[%dv]" % (self.pos), val)
# Increment pos and return key
key = ("[%dk]" % (self.pos), key)
self.pos += 1
return key
self.pos += 1
raise StopIteration
__next__ = next
def __init__(self, val):
self.val = val
self.keys_are_strings = False
try:
string_hash = read_global_var("g_str_hash")
except Exception:
string_hash = None
if (
self.val != 0
and string_hash is not None
and self.val["hash_func"] == string_hash
):
self.keys_are_strings = True
def children(self):
return self._iterator(self.val, self.keys_are_strings)
def to_string(self):
return "0x%x" % (long(self.val))
def display_hint(self):
return "map"
def pretty_printer_lookup(val):
# None yet, want things like hash table and list
type = val.type.unqualified()
# If it points to a reference, get the reference.
if type.code == gdb.TYPE_CODE_REF:
type = type.target()
if type.code == gdb.TYPE_CODE_PTR:
type = type.target().unqualified()
t = str(type)
if t == "GList":
return GListPrinter(val, "GList")
if t == "GSList":
return GListPrinter(val, "GSList")
if t == "GHashTable":
return GHashPrinter(val)
else:
t = str(type)
if t == "GList":
return GListNodePrinter(val)
if t == "GSList *":
return GListPrinter(val, "GSList")
return None
def register(obj):
if obj is None:
obj = gdb
obj.pretty_printers.append(pretty_printer_lookup)
class ForeachCommand(gdb.Command):
"""Foreach on list"""
def __init__(self):
super(ForeachCommand, self).__init__(
"gforeach", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL
)
def valid_name(self, name):
if not name[0].isalpha():
return False
return True
def parse_args(self, arg):
i = arg.find(" ")
if i <= 0:
raise Exception("No var specified")
var = arg[:i]
if not self.valid_name(var):
raise Exception("Invalid variable name")
while i < len(arg) and arg[i].isspace():
i = i + 1
if arg[i : i + 2] != "in":
raise Exception("Invalid syntax, missing in")
i = i + 2
while i < len(arg) and arg[i].isspace():
i = i + 1
colon = arg.find(":", i)
if colon == -1:
raise Exception("Invalid syntax, missing colon")
val = arg[i:colon]
colon = colon + 1
while colon < len(arg) and arg[colon].isspace():
colon = colon + 1
command = arg[colon:]
return (var, val, command)
def do_iter(self, arg, item, command):
item = item.cast(gdb.lookup_type("void").pointer())
item = long(item)
to_eval = "set $%s = (void *)0x%x\n" % (arg, item)
gdb.execute(to_eval)
gdb.execute(command)
def slist_iterator(self, arg, container, command):
list_element = container.cast(gdb.lookup_type("GSList").pointer())
while long(list_element) != 0:
self.do_iter(arg, list_element["data"], command)
list_element = list_element["next"]
def list_iterator(self, arg, container, command):
list_element = container.cast(gdb.lookup_type("GList").pointer())
while long(list_element) != 0:
self.do_iter(arg, list_element["data"], command)
list_element = list_element["next"]
def pick_iterator(self, container):
t = container.type.unqualified()
if t.code == gdb.TYPE_CODE_PTR:
t = t.target().unqualified()
t = str(t)
if t == "GSList":
return self.slist_iterator
if t == "GList":
return self.list_iterator
raise Exception("Invalid container type %s" % (str(container.type)))
def invoke(self, arg, from_tty):
(var, container, command) = self.parse_args(arg)
container = gdb.parse_and_eval(container)
func = self.pick_iterator(container)
func(var, container, command)
ForeachCommand()

50
glib/glib_probes.d Normal file
View file

@ -0,0 +1,50 @@
provider glib {
probe mem__alloc(void*, unsigned int, unsigned int, unsigned int);
probe mem__realloc(void*, void *, unsigned int, unsigned int);
probe mem__free(void*);
probe slice__alloc(void*, unsigned int);
probe slice__free(void*, unsigned int);
probe quark__new(const char *, unsigned int);
probe main__after_prepare(void*, void*, unsigned int);
probe main__after_check(void*, void*, unsigned int);
probe main__before_dispatch(const char*, void*, void*, void*, void*);
probe main__after_dispatch(const char*, void*, void*, unsigned int);
probe main__source_attach(const char*, void*, void*, unsigned int);
probe main__source_destroy(const char*, void*, void*);
probe main__context_default(void*);
probe main__context_new(void*);
probe main__context_acquire(void*, int);
probe main__context_release(void*);
probe main__context_free(void*);
probe main__context_push_thread_default(void*);
probe main__context_pop_thread_default(void*);
probe main__context_before_prepare(void*);
probe main__context_after_prepare(void*, int, unsigned int);
probe main__context_before_query(void*, int);
probe main__context_after_query(void*, unsigned int, void*, unsigned int);
probe main__context_before_check(void*, int, void*, unsigned int);
probe main__context_after_check(void*, unsigned int);
probe main__context_before_dispatch(void*);
probe main__context_after_dispatch(void*);
probe main__context_wakeup(void*);
probe main__context_wakeup_acknowledge(void*);
probe main__loop_new(void*, void*);
probe main__loop_quit(void*);
probe idle__add(void*, void*, unsigned int, int, void*, void*);
probe idle__dispatch(void*, void*, void*, void*, unsigned int);
probe timeout__add(void*, void*, unsigned int, int, unsigned int, void*, void*);
probe timeout__dispatch(void*, void*, void*, void*, unsigned int);
probe source__new(void*, void*, void*, void*, void*, size_t);
probe source__set_callback(void*, void*, void*, void*);
probe source__set_callback_indirect(void*, void*, void*, void*, void*);
probe source__set_ready_time(void*, unsigned int);
probe source__set_priority(void*, void*, unsigned int);
probe source__add_child_source(void*, void*);
probe source__set_name(void*, const char*);
probe source__before_free(void*, void*, void*);
probe thread__spawned(void*, void*, char*);
probe rcbox__alloc(void*, unsigned int, unsigned int, unsigned int);
probe rcbox__acquire(void*, unsigned int);
probe rcbox__release(void*, unsigned int);
probe rcbox__free(void*);
};

43
glib/glib_trace.h Normal file
View file

@ -0,0 +1,43 @@
/* GLIB - Library of useful routines for C programming
*
* Copyright (C) 2009,2010 Red Hat, Inc.
*
* 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/>.
*
* Author: Alexander Larsson <alexl@redhat.com>
*/
#ifndef __GLIBTRACE_H__
#define __GLIBTRACE_H__
#ifndef SIZEOF_CHAR
#error "config.h must be included prior to glib_trace.h"
#endif
/* Ignore probes when doing static analysis, as they do weird things which
* confuses the analyser. */
#if defined(HAVE_DTRACE) && !defined(__clang_analyzer__)
/* include the generated probes header and put markers in code */
#include "glib_probes.h"
#define TRACE(probe) probe
#else
/* Wrap the probe to allow it to be removed when no systemtap available */
#define TRACE(probe)
#endif
#endif /* __GLIBTRACE_H__ */

210
glib/glibconfig.h.in Normal file
View file

@ -0,0 +1,210 @@
/* glibconfig.h
*
* This is a generated file. Please modify 'glibconfig.h.in'
*/
#ifndef __GLIBCONFIG_H__
#define __GLIBCONFIG_H__
#include <glib/gmacros.h>
#include <limits.h>
#include <float.h>
#mesondefine GLIB_HAVE_ALLOCA_H
/* Specifies that GLib's g_print*() functions wrap the
* system printf functions. This is useful to know, for example,
* when using glibc's register_printf_function().
*/
#mesondefine GLIB_USING_SYSTEM_PRINTF
#mesondefine GLIB_STATIC_COMPILATION
#mesondefine GOBJECT_STATIC_COMPILATION
#mesondefine G_INTL_STATIC_COMPILATION
#mesondefine FFI_STATIC_BUILD
G_BEGIN_DECLS
#define G_MINFLOAT FLT_MIN
#define G_MAXFLOAT FLT_MAX
#define G_MINDOUBLE DBL_MIN
#define G_MAXDOUBLE DBL_MAX
#define G_MINSHORT SHRT_MIN
#define G_MAXSHORT SHRT_MAX
#define G_MAXUSHORT USHRT_MAX
#define G_MININT INT_MIN
#define G_MAXINT INT_MAX
#define G_MAXUINT UINT_MAX
#define G_MINLONG LONG_MIN
#define G_MAXLONG LONG_MAX
#define G_MAXULONG ULONG_MAX
typedef signed char gint8;
typedef unsigned char guint8;
typedef signed @gint16@ gint16;
typedef unsigned @gint16@ guint16;
#define G_GINT16_MODIFIER @gint16_modifier@
#define G_GINT16_FORMAT @gint16_format@
#define G_GUINT16_FORMAT @guint16_format@
typedef signed @gint32@ gint32;
typedef unsigned @gint32@ guint32;
#define G_GINT32_MODIFIER @gint32_modifier@
#define G_GINT32_FORMAT @gint32_format@
#define G_GUINT32_FORMAT @guint32_format@
#define G_HAVE_GINT64 1 /* deprecated, always true */
@glib_extension@typedef signed @gint64@ gint64;
@glib_extension@typedef unsigned @gint64@ guint64;
#define G_GINT64_CONSTANT(val) @gint64_constant@
#define G_GUINT64_CONSTANT(val) @guint64_constant@
#define G_GINT64_MODIFIER @gint64_modifier@
#define G_GINT64_FORMAT @gint64_format@
#define G_GUINT64_FORMAT @guint64_format@
#define GLIB_SIZEOF_VOID_P @glib_void_p@
#define GLIB_SIZEOF_LONG @glib_long@
#define GLIB_SIZEOF_SIZE_T @glib_size_t@
#define GLIB_SIZEOF_SSIZE_T @glib_ssize_t@
typedef signed @glib_size_type_define@ gssize;
typedef unsigned @glib_size_type_define@ gsize;
#define G_GSIZE_MODIFIER @gsize_modifier@
#define G_GSSIZE_MODIFIER @gssize_modifier@
#define G_GSIZE_FORMAT @gsize_format@
#define G_GSSIZE_FORMAT @gssize_format@
#define G_MAXSIZE G_MAXU@glib_msize_type@
#define G_MINSSIZE G_MIN@glib_msize_type@
#define G_MAXSSIZE G_MAX@glib_msize_type@
typedef gint64 goffset;
#define G_MINOFFSET G_MININT64
#define G_MAXOFFSET G_MAXINT64
#define G_GOFFSET_MODIFIER G_GINT64_MODIFIER
#define G_GOFFSET_FORMAT G_GINT64_FORMAT
#define G_GOFFSET_CONSTANT(val) G_GINT64_CONSTANT(val)
#define G_POLLFD_FORMAT @g_pollfd_format@
#define GPOINTER_TO_INT(p) ((gint) @glib_gpi_cast@ (p))
#define GPOINTER_TO_UINT(p) ((guint) @glib_gpui_cast@ (p))
#define GINT_TO_POINTER(i) ((gpointer) @glib_gpi_cast@ (i))
#define GUINT_TO_POINTER(u) ((gpointer) @glib_gpui_cast@ (u))
typedef signed @glib_intptr_type_define@ gintptr;
typedef unsigned @glib_intptr_type_define@ guintptr;
#define G_GINTPTR_MODIFIER @gintptr_modifier@
#define G_GINTPTR_FORMAT @gintptr_format@
#define G_GUINTPTR_FORMAT @guintptr_format@
#define GLIB_MAJOR_VERSION @GLIB_MAJOR_VERSION@
#define GLIB_MINOR_VERSION @GLIB_MINOR_VERSION@
#define GLIB_MICRO_VERSION @GLIB_MICRO_VERSION@
@glib_os@
@glib_vacopy@
@g_have_iso_c_varargs@
@g_have_iso_cxx_varargs@
/* gcc-2.95.x supports both gnu style and ISO varargs, but if -ansi
* is passed ISO vararg support is turned off, and there is no work
* around to turn it on, so we unconditionally turn it off.
*/
#if __GNUC__ == 2 && __GNUC_MINOR__ == 95
# undef G_HAVE_ISO_VARARGS
#endif
#mesondefine G_HAVE_GROWING_STACK
#mesondefine G_HAVE_GNUC_VISIBILITY
#ifndef _MSC_VER
# define G_HAVE_GNUC_VARARGS 1
#endif
#if defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
#define G_GNUC_INTERNAL __attribute__((visibility("hidden")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
#define G_GNUC_INTERNAL __hidden
#elif defined (__GNUC__) && defined (G_HAVE_GNUC_VISIBILITY)
#define G_GNUC_INTERNAL __attribute__((visibility("hidden")))
#else
#define G_GNUC_INTERNAL
#endif
#define G_THREADS_ENABLED
#define G_THREADS_IMPL_@g_threads_impl_def@
#mesondefine G_ATOMIC_LOCK_FREE
#define GINT16_TO_@g_bs_native@(val) ((gint16) (val))
#define GUINT16_TO_@g_bs_native@(val) ((guint16) (val))
#define GINT16_TO_@g_bs_alien@(val) ((gint16) GUINT16_SWAP_LE_BE (val))
#define GUINT16_TO_@g_bs_alien@(val) (GUINT16_SWAP_LE_BE (val))
#define GINT32_TO_@g_bs_native@(val) ((gint32) (val))
#define GUINT32_TO_@g_bs_native@(val) ((guint32) (val))
#define GINT32_TO_@g_bs_alien@(val) ((gint32) GUINT32_SWAP_LE_BE (val))
#define GUINT32_TO_@g_bs_alien@(val) (GUINT32_SWAP_LE_BE (val))
#define GINT64_TO_@g_bs_native@(val) ((gint64) (val))
#define GUINT64_TO_@g_bs_native@(val) ((guint64) (val))
#define GINT64_TO_@g_bs_alien@(val) ((gint64) GUINT64_SWAP_LE_BE (val))
#define GUINT64_TO_@g_bs_alien@(val) (GUINT64_SWAP_LE_BE (val))
#define GLONG_TO_LE(val) ((glong) GINT@glongbits@_TO_LE (val))
#define GULONG_TO_LE(val) ((gulong) GUINT@glongbits@_TO_LE (val))
#define GLONG_TO_BE(val) ((glong) GINT@glongbits@_TO_BE (val))
#define GULONG_TO_BE(val) ((gulong) GUINT@glongbits@_TO_BE (val))
#define GINT_TO_LE(val) ((gint) GINT@gintbits@_TO_LE (val))
#define GUINT_TO_LE(val) ((guint) GUINT@gintbits@_TO_LE (val))
#define GINT_TO_BE(val) ((gint) GINT@gintbits@_TO_BE (val))
#define GUINT_TO_BE(val) ((guint) GUINT@gintbits@_TO_BE (val))
#define GSIZE_TO_LE(val) ((gsize) GUINT@gsizebits@_TO_LE (val))
#define GSSIZE_TO_LE(val) ((gssize) GINT@gsizebits@_TO_LE (val))
#define GSIZE_TO_BE(val) ((gsize) GUINT@gsizebits@_TO_BE (val))
#define GSSIZE_TO_BE(val) ((gssize) GINT@gsizebits@_TO_BE (val))
#define G_BYTE_ORDER @g_byte_order@
#define GLIB_SYSDEF_POLLIN =@g_pollin@
#define GLIB_SYSDEF_POLLOUT =@g_pollout@
#define GLIB_SYSDEF_POLLPRI =@g_pollpri@
#define GLIB_SYSDEF_POLLHUP =@g_pollhup@
#define GLIB_SYSDEF_POLLERR =@g_pollerr@
#define GLIB_SYSDEF_POLLNVAL =@g_pollnval@
#define G_MODULE_SUFFIX "@g_module_suffix@"
typedef @g_pid_type@ GPid;
#define G_PID_FORMAT @g_pid_format@
#define GLIB_SYSDEF_AF_UNIX @g_af_unix@
#define GLIB_SYSDEF_AF_INET @g_af_inet@
#define GLIB_SYSDEF_AF_INET6 @g_af_inet6@
#define GLIB_SYSDEF_MSG_OOB @g_msg_oob@
#define GLIB_SYSDEF_MSG_PEEK @g_msg_peek@
#define GLIB_SYSDEF_MSG_DONTROUTE @g_msg_dontroute@
#define G_DIR_SEPARATOR '@g_dir_separator@'
#define G_DIR_SEPARATOR_S "@g_dir_separator@"
#define G_SEARCHPATH_SEPARATOR '@g_searchpath_separator@'
#define G_SEARCHPATH_SEPARATOR_S "@g_searchpath_separator@"
G_END_DECLS
#endif /* __GLIBCONFIG_H__ */

Some files were not shown because too many files have changed in this diff Show more