Import Upstream version 2.72.4
This commit is contained in:
commit
4ef3ff9793
2003 changed files with 1332420 additions and 0 deletions
104
glib/deprecated/gallocator.c
Normal file
104
glib/deprecated/gallocator.c
Normal 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) { }
|
||||
88
glib/deprecated/gallocator.h
Normal file
88
glib/deprecated/gallocator.h
Normal 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
350
glib/deprecated/gcache.c
Normal 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
75
glib/deprecated/gcache.h
Normal 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__ */
|
||||
503
glib/deprecated/gcompletion.c
Normal file
503
glib/deprecated/gcompletion.c
Normal 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
|
||||
83
glib/deprecated/gcompletion.h
Normal file
83
glib/deprecated/gcompletion.h
Normal 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
135
glib/deprecated/gmain.h
Normal 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
685
glib/deprecated/grel.c
Normal 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
105
glib/deprecated/grel.h
Normal 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__ */
|
||||
1578
glib/deprecated/gthread-deprecated.c
Normal file
1578
glib/deprecated/gthread-deprecated.c
Normal file
File diff suppressed because it is too large
Load diff
293
glib/deprecated/gthread.h
Normal file
293
glib/deprecated/gthread.h
Normal 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
2
glib/dirent/README
Normal 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
19
glib/dirent/dirent-zip
Normal 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
341
glib/dirent/dirent.c
Normal 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
127
glib/dirent/dirent.h
Normal 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
3
glib/dirent/wdirent.c
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#define _UNICODE 1
|
||||
#define UNICODE 1
|
||||
#include "dirent.c"
|
||||
2636
glib/docs.c
Normal file
2636
glib/docs.c
Normal file
File diff suppressed because it is too large
Load diff
145
glib/galloca.h
Normal file
145
glib/galloca.h
Normal 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
381
glib/garcbox.c
Normal 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
2576
glib/garray.c
Normal file
File diff suppressed because it is too large
Load diff
281
glib/garray.h
Normal file
281
glib/garray.h
Normal 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
906
glib/gasyncqueue.c
Normal 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
124
glib/gasyncqueue.h
Normal 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
29
glib/gasyncqueueprivate.h
Normal 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
967
glib/gatomic.c
Normal 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
470
glib/gatomic.h
Normal 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()`. It’s 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
455
glib/gbacktrace.c
Normal 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
72
glib/gbacktrace.h
Normal 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
462
glib/gbase64.c
Normal 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
61
glib/gbase64.h
Normal 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
563
glib/gbitlock.c
Normal 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
76
glib/gbitlock.h
Normal 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
4022
glib/gbookmarkfile.c
Normal file
File diff suppressed because it is too large
Load diff
295
glib/gbookmarkfile.h
Normal file
295
glib/gbookmarkfile.h
Normal 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
299
glib/gbsearcharray.h
Normal 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
612
glib/gbytes.c
Normal 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
97
glib/gbytes.h
Normal 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
838
glib/gcharset.c
Normal 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 can’t 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
47
glib/gcharset.h
Normal 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
34
glib/gcharsetprivate.h
Normal 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
1864
glib/gchecksum.c
Normal file
File diff suppressed because it is too large
Load diff
104
glib/gchecksum.h
Normal file
104
glib/gchecksum.h
Normal 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
159
glib/gconstructor.h
Normal 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
2066
glib/gconvert.c
Normal file
File diff suppressed because it is too large
Load diff
177
glib/gconvert.h
Normal file
177
glib/gconvert.h
Normal 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
40
glib/gconvertprivate.h
Normal 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
1251
glib/gdataset.c
Normal file
File diff suppressed because it is too large
Load diff
150
glib/gdataset.h
Normal file
150
glib/gdataset.h
Normal 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
42
glib/gdatasetprivate.h
Normal 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
2755
glib/gdate.c
Normal file
File diff suppressed because it is too large
Load diff
307
glib/gdate.h
Normal file
307
glib/gdate.h
Normal 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
3527
glib/gdatetime.c
Normal file
File diff suppressed because it is too large
Load diff
273
glib/gdatetime.h
Normal file
273
glib/gdatetime.h
Normal 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
330
glib/gdir.c
Normal 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
52
glib/gdir.h
Normal 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
1552
glib/gen-unicode-tables.pl
Executable file
File diff suppressed because it is too large
Load diff
701
glib/genviron.c
Normal file
701
glib/genviron.c
Normal 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
63
glib/genviron.h
Normal 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
1157
glib/gerror.c
Normal file
File diff suppressed because it is too large
Load diff
261
glib/gerror.h
Normal file
261
glib/gerror.h
Normal 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
2978
glib/gfileutils.c
Normal file
File diff suppressed because it is too large
Load diff
221
glib/gfileutils.h
Normal file
221
glib/gfileutils.h
Normal 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 doesn’t 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
637
glib/ggettext.c
Normal 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 project’s 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 > 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
63
glib/ggettext.h
Normal 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
2533
glib/ghash.c
Normal file
File diff suppressed because it is too large
Load diff
190
glib/ghash.h
Normal file
190
glib/ghash.h
Normal 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
441
glib/ghmac.c
Normal 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
83
glib/ghmac.h
Normal 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
1050
glib/ghook.c
Normal file
File diff suppressed because it is too large
Load diff
202
glib/ghook.h
Normal file
202
glib/ghook.h
Normal 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
888
glib/ghostutils.c
Normal 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. That’s 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
|
||||
*
|
||||
* It’s possible for a hostname to be %-encoded, in which case its decoded
|
||||
* length will be as much as 3× shorter.
|
||||
*
|
||||
* It’s 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. It’s 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
43
glib/ghostutils.h
Normal 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
36
glib/gi18n-lib.h
Normal 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
32
glib/gi18n.h
Normal 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
2581
glib/giochannel.c
Normal file
File diff suppressed because it is too large
Load diff
404
glib/giochannel.h
Normal file
404
glib/giochannel.h
Normal 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
657
glib/giounix.c
Normal 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
2241
glib/giowin32.c
Normal file
File diff suppressed because it is too large
Load diff
4686
glib/gkeyfile.c
Normal file
4686
glib/gkeyfile.c
Normal file
File diff suppressed because it is too large
Load diff
330
glib/gkeyfile.h
Normal file
330
glib/gkeyfile.h
Normal 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
103
glib/glib-autocleanups.h
Normal 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 user’s #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
458
glib/glib-init.c
Normal 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
48
glib/glib-init.h
Normal 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__ */
|
||||
230
glib/glib-mirroring-tab/gen-mirroring-tab.c
Normal file
230
glib/glib-mirroring-tab/gen-mirroring-tab.c
Normal 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;
|
||||
}
|
||||
5
glib/glib-mirroring-tab/meson.build
Normal file
5
glib/glib-mirroring-tab/meson.build
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
gen_mirroring_tab = executable('gen-mirroring-tab',
|
||||
['gen-mirroring-tab.c', 'packtab.c'],
|
||||
dependencies : [libglib_dep],
|
||||
install: false,
|
||||
)
|
||||
422
glib/glib-mirroring-tab/packtab.c
Normal file
422
glib/glib-mirroring-tab/packtab.c
Normal 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 */
|
||||
48
glib/glib-mirroring-tab/packtab.h
Normal file
48
glib/glib-mirroring-tab/packtab.h
Normal 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
44
glib/glib-object.h
Normal 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
62
glib/glib-private.c
Normal 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
204
glib/glib-private.h
Normal 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
43
glib/glib-typeof.h
Normal 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
546
glib/glib-unix.c
Normal 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 doesn’t 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 it’s 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)
|
||||
{
|
||||
/* Can’t 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
123
glib/glib-unix.h
Normal 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
119
glib/glib.h
Normal 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
30
glib/glib.rc.in
Normal 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
645
glib/glib.stp.in
Normal 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
300
glib/glib_gdb.py
Normal 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
50
glib/glib_probes.d
Normal 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
43
glib/glib_trace.h
Normal 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
210
glib/glibconfig.h.in
Normal 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
Loading…
Add table
Add a link
Reference in a new issue