mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-23 10:42:11 +01:00
gmetrics: Add debug api for print metrics
In order to get a handle on memory usage it would be good to get reports of various types of object usage over time. This commit provides a little api for generating CSV files to dump the data to.
This commit is contained in:
parent
a4b72a282c
commit
3934937c30
@ -143,6 +143,7 @@ libglib_2_0_la_SOURCES = \
|
||||
gmarkup.c \
|
||||
gmem.c \
|
||||
gmessages.c \
|
||||
gmetrics.c \
|
||||
gmirroringtable.h \
|
||||
gnode.c \
|
||||
goption.c \
|
||||
@ -278,6 +279,7 @@ glibsubinclude_HEADERS = \
|
||||
gmarkup.h \
|
||||
gmem.h \
|
||||
gmessages.h \
|
||||
gmetrics.h \
|
||||
gnode.h \
|
||||
goption.h \
|
||||
gpattern.h \
|
||||
@ -351,8 +353,8 @@ pcre_lib = pcre/libpcre.la
|
||||
pcre_inc =
|
||||
endif
|
||||
|
||||
libglib_2_0_la_CFLAGS = $(AM_CFLAGS) $(GLIB_HIDDEN_VISIBILITY_CFLAGS) $(LIBSYSTEMD_CFLAGS)
|
||||
libglib_2_0_la_LIBADD = libcharset/libcharset.la $(printf_la) @GIO@ @GSPAWN@ @PLATFORMDEP@ @ICONV_LIBS@ @G_LIBS_EXTRA@ $(pcre_lib) $(G_THREAD_LIBS_EXTRA) $(G_THREAD_LIBS_FOR_GTHREAD) $(LIBSYSTEMD_LIBS)
|
||||
libglib_2_0_la_CFLAGS = $(AM_CFLAGS) $(GLIB_HIDDEN_VISIBILITY_CFLAGS) $(LIBSYSTEMD_CFLAGS) $(ZLIB_CFLAGS)
|
||||
libglib_2_0_la_LIBADD = libcharset/libcharset.la $(printf_la) @GIO@ @GSPAWN@ @PLATFORMDEP@ @ICONV_LIBS@ @G_LIBS_EXTRA@ $(pcre_lib) $(G_THREAD_LIBS_EXTRA) $(G_THREAD_LIBS_FOR_GTHREAD) $(LIBSYSTEMD_LIBS) $(ZLIB_LIBS)
|
||||
libglib_2_0_la_DEPENDENCIES = libcharset/libcharset.la $(printf_la) @GIO@ @GSPAWN@ @PLATFORMDEP@ $(glib_win32_res) $(glib_def)
|
||||
|
||||
libglib_2_0_la_LDFLAGS = $(GLIB_LINK_FLAGS) \
|
||||
|
@ -268,6 +268,7 @@ glib_init (void)
|
||||
|
||||
glib_inited = TRUE;
|
||||
|
||||
g_metrics_init ();
|
||||
g_messages_prefixed_init ();
|
||||
g_debug_init ();
|
||||
g_quark_init ();
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define __GLIB_INIT_H__
|
||||
|
||||
#include "gmessages.h"
|
||||
#include "gmetrics.h"
|
||||
|
||||
extern GLogLevelFlags g_log_always_fatal;
|
||||
extern GLogLevelFlags g_log_msg_prefix;
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include <glib/gmarkup.h>
|
||||
#include <glib/gmem.h>
|
||||
#include <glib/gmessages.h>
|
||||
#include <glib/gmetrics.h>
|
||||
#include <glib/gnode.h>
|
||||
#include <glib/goption.h>
|
||||
#include <glib/gpattern.h>
|
||||
|
@ -202,6 +202,8 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#include <process.h> /* For getpid() */
|
||||
#include <io.h>
|
||||
|
@ -618,7 +618,6 @@ GPrintFunc g_set_printerr_handler (GPrintFunc func);
|
||||
return (val); }G_STMT_END
|
||||
|
||||
#endif /* !G_DISABLE_CHECKS */
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_MESSAGES_H__ */
|
||||
|
4243
glib/gmetrics.c
Normal file
4243
glib/gmetrics.c
Normal file
File diff suppressed because it is too large
Load Diff
333
glib/gmetrics.h
Normal file
333
glib/gmetrics.h
Normal file
@ -0,0 +1,333 @@
|
||||
/* 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_METRICS_H__
|
||||
#define __G_METRICS_H__
|
||||
|
||||
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
|
||||
#error "Only <glib.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <glib/gtypes.h>
|
||||
#include <glib/gmacros.h>
|
||||
#include <glib/gmain.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_init (void);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gboolean g_metrics_enabled (void);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gboolean g_metrics_requested (const char *name);
|
||||
|
||||
typedef void (*GMetricsTimeoutFunc) (void);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
int g_metrics_get_timeout_fd (void);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_run_timeout_handlers (void);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gulong g_metrics_get_generation (void);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_start_timeout (GMetricsTimeoutFunc timeout_handler);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
const char *g_metrics_get_log_dir (void);
|
||||
|
||||
typedef struct _GMetricsFile GMetricsFile;
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
GMetricsFile *g_metrics_file_new (const char *name,
|
||||
const char *first_column_name,
|
||||
const char *first_column_format,
|
||||
...);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_file_start_record (GMetricsFile *metrics_file);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_file_add_row_without_cast (GMetricsFile *metrics_file,
|
||||
gconstpointer first_column_value,
|
||||
...);
|
||||
#define g_metrics_file_add_row(_file,_first,_rest...) g_metrics_file_add_row_without_cast ((_file), (gpointer) (_first), _rest)
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_file_end_record (GMetricsFile *metrics_file);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_file_free (GMetricsFile *metrics_file);
|
||||
|
||||
typedef struct _GMetricsTable GMetricsTable;
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
GMetricsTable *g_metrics_table_new (gsize record_size);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_table_set_record (GMetricsTable *metrics_table,
|
||||
const char *name,
|
||||
gpointer record);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gpointer g_metrics_table_get_record (GMetricsTable *metrics_table,
|
||||
const char *name);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_table_remove_record (GMetricsTable *metrics_table,
|
||||
const char *name);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_table_clear (GMetricsTable *metrics_table);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_table_free (GMetricsTable *metrics_table);
|
||||
|
||||
typedef struct _GMetricsTableIter GMetricsTableIter;
|
||||
|
||||
typedef struct _GMetricsTableEntry GMetricsTableEntry;
|
||||
struct _GMetricsTableIter
|
||||
{
|
||||
/*< private >*/
|
||||
GMetricsTableEntry *entry;
|
||||
};
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_table_iter_init (GMetricsTableIter *iter,
|
||||
GMetricsTable *table);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_table_sorted_iter_init (GMetricsTableIter *iter,
|
||||
GMetricsTable *table,
|
||||
GCompareFunc comparison_function);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gboolean g_metrics_table_iter_next_without_cast (GMetricsTableIter *iter,
|
||||
const char **name,
|
||||
gpointer *record);
|
||||
#define g_metrics_table_iter_next(_iter,_name,_record) g_metrics_table_iter_next_without_cast ((_iter), (_name), (gpointer *) (_record))
|
||||
|
||||
struct _GMetricsInstanceCounterMetrics
|
||||
{
|
||||
char comment[64];
|
||||
gsize total_memory_usage;
|
||||
gsize instance_count;
|
||||
gssize instance_change;
|
||||
gsize instance_watermark;
|
||||
gssize average_instance_change;
|
||||
gsize number_of_samples;
|
||||
};
|
||||
typedef struct _GMetricsInstanceCounterMetrics GMetricsInstanceCounterMetrics;
|
||||
|
||||
typedef struct _GMetricsInstanceCounter GMetricsInstanceCounter;
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
GMetricsInstanceCounter *g_metrics_instance_counter_new (void);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_instance_counter_start_record (GMetricsInstanceCounter *counter);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_instance_counter_add_instance (GMetricsInstanceCounter *counter,
|
||||
const char *name,
|
||||
gsize memory_usage);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_instance_counter_add_instances (GMetricsInstanceCounter *counter,
|
||||
const char *name,
|
||||
const char *comment,
|
||||
gsize number_of_instances,
|
||||
gsize total_usage);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_instance_counter_end_record (GMetricsInstanceCounter *counter);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gboolean g_metrics_instance_counter_instance_is_interesting (GMetricsInstanceCounter *counter,
|
||||
const char *name);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_instance_counter_free (GMetricsInstanceCounter *counter);
|
||||
|
||||
typedef struct _GMetricsInstanceCounterIter GMetricsInstanceCounterIter;
|
||||
|
||||
typedef struct _GMetricsInstanceCounterEntry GMetricsInstanceCounterEntry;
|
||||
struct _GMetricsInstanceCounterIter
|
||||
{
|
||||
/*< private >*/
|
||||
gssize table_index;
|
||||
GMetricsTableIter table_iter;
|
||||
};
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_instance_counter_iter_init (GMetricsInstanceCounterIter *iter,
|
||||
GMetricsInstanceCounter *table);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gboolean g_metrics_instance_counter_iter_next (GMetricsInstanceCounterIter *iter,
|
||||
const char **name,
|
||||
GMetricsInstanceCounterMetrics **metrics);
|
||||
|
||||
typedef struct _GMetricsList GMetricsList;
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
GMetricsList *g_metrics_list_new (void);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_list_add_item (GMetricsList *list,
|
||||
gpointer item);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_list_remove_item (GMetricsList *list,
|
||||
gpointer item);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gsize g_metrics_list_get_length (GMetricsList *list);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gpointer g_metrics_list_get_last_item (GMetricsList *list);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_list_remove_last_item (GMetricsList *list);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_list_free (GMetricsList *list);
|
||||
|
||||
typedef struct _GMetricsListIter GMetricsListIter;
|
||||
typedef struct _GMetricsListNode GMetricsListNode;
|
||||
struct _GMetricsListIter
|
||||
{
|
||||
/*< private >*/
|
||||
GMetricsListNode *node;
|
||||
GMetricsListNode *next_node;
|
||||
};
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_list_iter_init (GMetricsListIter *iter,
|
||||
GMetricsList *list);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gboolean g_metrics_list_iter_next_without_cast (GMetricsListIter *iter,
|
||||
gpointer *item);
|
||||
#define g_metrics_list_iter_next(_iter,_item) g_metrics_list_iter_next_without_cast ((_iter), (gpointer *) (_item))
|
||||
|
||||
typedef struct _GMetricsStackTrace GMetricsStackTrace;
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
GMetricsStackTrace *g_metrics_stack_trace_new (int start_frame,
|
||||
int number_of_frames,
|
||||
const char *delimiter);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
const char *g_metrics_stack_trace_get_hash_key (GMetricsStackTrace *stack_trace);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
const char *g_metrics_stack_trace_get_output (GMetricsStackTrace *stack_trace);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_stack_trace_add_annotation (GMetricsStackTrace *stack_trace,
|
||||
const char *annotation);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_stack_trace_free (GMetricsStackTrace *stack_trace);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
char *g_metrics_stack_trace (void);
|
||||
|
||||
typedef struct _GMetricsStackTraceSampler GMetricsStackTraceSampler;
|
||||
typedef struct _GMetricsStackTraceSample GMetricsStackTraceSample;
|
||||
typedef struct _GMetricsStackTraceSamplerIter GMetricsStackTraceSamplerIter;
|
||||
|
||||
struct _GMetricsStackTraceSamplerIter
|
||||
{
|
||||
/*< private >*/
|
||||
GMetricsTableIter table_iter;
|
||||
};
|
||||
|
||||
struct _GMetricsStackTraceSample
|
||||
{
|
||||
char name[64];
|
||||
GMetricsStackTrace *stack_trace;
|
||||
gsize number_of_hits;
|
||||
};
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_stack_trace_sampler_iter_init (GMetricsStackTraceSamplerIter *iter,
|
||||
GMetricsStackTraceSampler *sampler);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gboolean g_metrics_stack_trace_sampler_iter_next (GMetricsStackTraceSamplerIter *iter,
|
||||
GMetricsStackTraceSample **sample);
|
||||
|
||||
typedef gboolean (* GMetricsStackTraceAnnotationHandler) (char *annotation, gsize annotation_size, gpointer user_data);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_set_stack_trace_annotation_handler (GMetricsStackTraceAnnotationHandler handler,
|
||||
gpointer user_data);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
GMetricsStackTraceSampler *g_metrics_stack_trace_sampler_new (void);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_stack_trace_sampler_take_sample (GMetricsStackTraceSampler *sample,
|
||||
const char *name,
|
||||
gpointer instance);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_stack_trace_sampler_remove_sample (GMetricsStackTraceSampler *sampler,
|
||||
gpointer instance);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_stack_trace_sampler_clear (GMetricsStackTraceSampler *sampler);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_stack_trace_sampler_free (GMetricsStackTraceSampler *sampler);
|
||||
|
||||
typedef struct _GMetricsAllocationBlockStore GMetricsAllocationBlockStore;
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
GMetricsAllocationBlockStore *g_metrics_allocation_block_store_new (const char *name,
|
||||
gsize size);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_allocation_block_store_free (GMetricsAllocationBlockStore *block_store);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gpointer g_metrics_allocation_block_store_allocate (GMetricsAllocationBlockStore *block_store,
|
||||
gsize size);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gpointer g_metrics_allocation_block_store_allocate_with_name (GMetricsAllocationBlockStore *block_store,
|
||||
gsize size,
|
||||
const char *name);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gpointer g_metrics_allocation_block_store_reallocate (GMetricsAllocationBlockStore *block_store,
|
||||
gpointer allocation,
|
||||
gsize size);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gpointer g_metrics_allocation_block_store_copy (GMetricsAllocationBlockStore *block_store,
|
||||
gconstpointer allocation,
|
||||
gsize size);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gpointer g_metrics_allocation_block_store_copy_with_name (GMetricsAllocationBlockStore *block_store,
|
||||
gconstpointer allocation,
|
||||
gsize size,
|
||||
const char *name);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_allocation_block_store_deallocate (GMetricsAllocationBlockStore *block_store,
|
||||
gpointer allocation);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_push_default_allocation_block_store (GMetricsAllocationBlockStore *block_store);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_pop_default_allocation_block_store (void);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gpointer g_metrics_allocate (gsize size);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gpointer g_metrics_reallocate (gpointer allocation,
|
||||
gsize size);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gpointer g_metrics_copy (gconstpointer allocation,
|
||||
gsize size);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_metrics_free (gpointer allocation);
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_METRICS_H__ */
|
1138
glib/uthash.h
Normal file
1138
glib/uthash.h
Normal file
File diff suppressed because it is too large
Load Diff
1073
glib/utlist.h
Normal file
1073
glib/utlist.h
Normal file
File diff suppressed because it is too large
Load Diff
411
glib/utstring.h
Normal file
411
glib/utstring.h
Normal file
@ -0,0 +1,411 @@
|
||||
/*
|
||||
Copyright (c) 2008-2021, Troy D. Hanson http://troydhanson.github.io/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
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.
|
||||
*/
|
||||
|
||||
/* a dynamic string implementation using macros
|
||||
*/
|
||||
#ifndef UTSTRING_H
|
||||
#define UTSTRING_H
|
||||
|
||||
#define UTSTRING_VERSION 2.3.0
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define UTSTRING_UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
#define UTSTRING_UNUSED
|
||||
#endif
|
||||
|
||||
#ifdef oom
|
||||
#error "The name of macro 'oom' has been changed to 'utstring_oom'. Please update your code."
|
||||
#define utstring_oom() oom()
|
||||
#endif
|
||||
|
||||
#ifndef utstring_oom
|
||||
#define utstring_oom() exit(-1)
|
||||
#endif
|
||||
|
||||
extern void *__libc_malloc (size_t size);
|
||||
extern void *__libc_realloc (void *ptr, size_t size);
|
||||
extern void __libc_free (void *ptr);
|
||||
|
||||
typedef struct {
|
||||
char *d; /* pointer to allocated buffer */
|
||||
size_t n; /* allocated capacity */
|
||||
size_t i; /* index of first unused byte */
|
||||
} UT_string;
|
||||
|
||||
#define utstring_reserve(s,amt) \
|
||||
do { \
|
||||
if (((s)->n - (s)->i) < (size_t)(amt)) { \
|
||||
char *utstring_tmp = (char*)__libc_realloc( \
|
||||
(s)->d, (s)->n + (amt)); \
|
||||
if (!utstring_tmp) { \
|
||||
utstring_oom(); \
|
||||
} \
|
||||
(s)->d = utstring_tmp; \
|
||||
(s)->n += (amt); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define utstring_init(s) \
|
||||
do { \
|
||||
(s)->n = 0; (s)->i = 0; (s)->d = NULL; \
|
||||
utstring_reserve(s,100); \
|
||||
(s)->d[0] = '\0'; \
|
||||
} while(0)
|
||||
|
||||
#define utstring_done(s) \
|
||||
do { \
|
||||
if ((s)->d != NULL) __libc_free((s)->d); \
|
||||
(s)->n = 0; \
|
||||
} while(0)
|
||||
|
||||
#define utstring_free(s) \
|
||||
do { \
|
||||
utstring_done(s); \
|
||||
__libc_free(s); \
|
||||
} while(0)
|
||||
|
||||
#define utstring_new(s) \
|
||||
do { \
|
||||
(s) = (UT_string*)__libc_malloc(sizeof(UT_string)); \
|
||||
if (!(s)) { \
|
||||
utstring_oom(); \
|
||||
} \
|
||||
utstring_init(s); \
|
||||
} while(0)
|
||||
|
||||
#define utstring_renew(s) \
|
||||
do { \
|
||||
if (s) { \
|
||||
utstring_clear(s); \
|
||||
} else { \
|
||||
utstring_new(s); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define utstring_clear(s) \
|
||||
do { \
|
||||
(s)->i = 0; \
|
||||
(s)->d[0] = '\0'; \
|
||||
} while(0)
|
||||
|
||||
#define utstring_bincpy(s,b,l) \
|
||||
do { \
|
||||
utstring_reserve((s),(l)+1); \
|
||||
if (l) memcpy(&(s)->d[(s)->i], b, l); \
|
||||
(s)->i += (l); \
|
||||
(s)->d[(s)->i]='\0'; \
|
||||
} while(0)
|
||||
|
||||
#define utstring_concat(dst,src) \
|
||||
do { \
|
||||
utstring_reserve((dst),((src)->i)+1); \
|
||||
if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \
|
||||
(dst)->i += (src)->i; \
|
||||
(dst)->d[(dst)->i]='\0'; \
|
||||
} while(0)
|
||||
|
||||
#define utstring_len(s) ((s)->i)
|
||||
|
||||
#define utstring_body(s) ((s)->d)
|
||||
|
||||
UTSTRING_UNUSED static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) {
|
||||
int n;
|
||||
va_list cp;
|
||||
for (;;) {
|
||||
#ifdef _WIN32
|
||||
cp = ap;
|
||||
#else
|
||||
va_copy(cp, ap);
|
||||
#endif
|
||||
n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp);
|
||||
va_end(cp);
|
||||
|
||||
if ((n > -1) && ((size_t) n < (s->n-s->i))) {
|
||||
s->i += n;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Else try again with more space. */
|
||||
if (n > -1) utstring_reserve(s,n+1); /* exact */
|
||||
else utstring_reserve(s,(s->n)*2); /* 2x */
|
||||
}
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
/* support printf format checking (2=the format string, 3=start of varargs) */
|
||||
static void utstring_printf(UT_string *s, const char *fmt, ...)
|
||||
__attribute__ (( format( printf, 2, 3) ));
|
||||
#endif
|
||||
UTSTRING_UNUSED static void utstring_printf(UT_string *s, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap,fmt);
|
||||
utstring_printf_va(s,fmt,ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* begin substring search functions *
|
||||
******************************************************************************/
|
||||
/* Build KMP table from left to right. */
|
||||
UTSTRING_UNUSED static void _utstring_BuildTable(
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen,
|
||||
long *P_KMP_Table)
|
||||
{
|
||||
long i, j;
|
||||
|
||||
i = 0;
|
||||
j = i - 1;
|
||||
P_KMP_Table[i] = j;
|
||||
while (i < (long) P_NeedleLen)
|
||||
{
|
||||
while ( (j > -1) && (P_Needle[i] != P_Needle[j]) )
|
||||
{
|
||||
j = P_KMP_Table[j];
|
||||
}
|
||||
i++;
|
||||
j++;
|
||||
if (i < (long) P_NeedleLen)
|
||||
{
|
||||
if (P_Needle[i] == P_Needle[j])
|
||||
{
|
||||
P_KMP_Table[i] = P_KMP_Table[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
P_KMP_Table[i] = j;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
P_KMP_Table[i] = j;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Build KMP table from right to left. */
|
||||
UTSTRING_UNUSED static void _utstring_BuildTableR(
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen,
|
||||
long *P_KMP_Table)
|
||||
{
|
||||
long i, j;
|
||||
|
||||
i = P_NeedleLen - 1;
|
||||
j = i + 1;
|
||||
P_KMP_Table[i + 1] = j;
|
||||
while (i >= 0)
|
||||
{
|
||||
while ( (j < (long) P_NeedleLen) && (P_Needle[i] != P_Needle[j]) )
|
||||
{
|
||||
j = P_KMP_Table[j + 1];
|
||||
}
|
||||
i--;
|
||||
j--;
|
||||
if (i >= 0)
|
||||
{
|
||||
if (P_Needle[i] == P_Needle[j])
|
||||
{
|
||||
P_KMP_Table[i + 1] = P_KMP_Table[j + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
P_KMP_Table[i + 1] = j;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
P_KMP_Table[i + 1] = j;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Search data from left to right. ( Multiple search mode. ) */
|
||||
UTSTRING_UNUSED static long _utstring_find(
|
||||
const char *P_Haystack,
|
||||
size_t P_HaystackLen,
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen,
|
||||
long *P_KMP_Table)
|
||||
{
|
||||
long i, j;
|
||||
long V_FindPosition = -1;
|
||||
|
||||
/* Search from left to right. */
|
||||
i = j = 0;
|
||||
while ( (j < (int)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen) )
|
||||
{
|
||||
while ( (i > -1) && (P_Needle[i] != P_Haystack[j]) )
|
||||
{
|
||||
i = P_KMP_Table[i];
|
||||
}
|
||||
i++;
|
||||
j++;
|
||||
if (i >= (int)P_NeedleLen)
|
||||
{
|
||||
/* Found. */
|
||||
V_FindPosition = j - i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return V_FindPosition;
|
||||
}
|
||||
|
||||
|
||||
/* Search data from right to left. ( Multiple search mode. ) */
|
||||
UTSTRING_UNUSED static long _utstring_findR(
|
||||
const char *P_Haystack,
|
||||
size_t P_HaystackLen,
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen,
|
||||
long *P_KMP_Table)
|
||||
{
|
||||
long i, j;
|
||||
long V_FindPosition = -1;
|
||||
|
||||
/* Search from right to left. */
|
||||
j = (P_HaystackLen - 1);
|
||||
i = (P_NeedleLen - 1);
|
||||
while ( (j >= 0) && (j >= i) )
|
||||
{
|
||||
while ( (i < (int)P_NeedleLen) && (P_Needle[i] != P_Haystack[j]) )
|
||||
{
|
||||
i = P_KMP_Table[i + 1];
|
||||
}
|
||||
i--;
|
||||
j--;
|
||||
if (i < 0)
|
||||
{
|
||||
/* Found. */
|
||||
V_FindPosition = j + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return V_FindPosition;
|
||||
}
|
||||
|
||||
|
||||
/* Search data from left to right. ( One time search mode. ) */
|
||||
UTSTRING_UNUSED static long utstring_find(
|
||||
UT_string *s,
|
||||
long P_StartPosition, /* Start from 0. -1 means last position. */
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen)
|
||||
{
|
||||
long V_StartPosition;
|
||||
long V_HaystackLen;
|
||||
long *V_KMP_Table;
|
||||
long V_FindPosition = -1;
|
||||
|
||||
if (P_StartPosition < 0)
|
||||
{
|
||||
V_StartPosition = s->i + P_StartPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
V_StartPosition = P_StartPosition;
|
||||
}
|
||||
V_HaystackLen = s->i - V_StartPosition;
|
||||
if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) )
|
||||
{
|
||||
V_KMP_Table = (long *)__libc_malloc(sizeof(long) * (P_NeedleLen + 1));
|
||||
if (V_KMP_Table != NULL)
|
||||
{
|
||||
_utstring_BuildTable(P_Needle, P_NeedleLen, V_KMP_Table);
|
||||
|
||||
V_FindPosition = _utstring_find(s->d + V_StartPosition,
|
||||
V_HaystackLen,
|
||||
P_Needle,
|
||||
P_NeedleLen,
|
||||
V_KMP_Table);
|
||||
if (V_FindPosition >= 0)
|
||||
{
|
||||
V_FindPosition += V_StartPosition;
|
||||
}
|
||||
|
||||
__libc_free(V_KMP_Table);
|
||||
}
|
||||
}
|
||||
|
||||
return V_FindPosition;
|
||||
}
|
||||
|
||||
|
||||
/* Search data from right to left. ( One time search mode. ) */
|
||||
UTSTRING_UNUSED static long utstring_findR(
|
||||
UT_string *s,
|
||||
long P_StartPosition, /* Start from 0. -1 means last position. */
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen)
|
||||
{
|
||||
long V_StartPosition;
|
||||
long V_HaystackLen;
|
||||
long *V_KMP_Table;
|
||||
long V_FindPosition = -1;
|
||||
|
||||
if (P_StartPosition < 0)
|
||||
{
|
||||
V_StartPosition = s->i + P_StartPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
V_StartPosition = P_StartPosition;
|
||||
}
|
||||
V_HaystackLen = V_StartPosition + 1;
|
||||
if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) )
|
||||
{
|
||||
V_KMP_Table = (long *)__libc_malloc(sizeof(long) * (P_NeedleLen + 1));
|
||||
if (V_KMP_Table != NULL)
|
||||
{
|
||||
_utstring_BuildTableR(P_Needle, P_NeedleLen, V_KMP_Table);
|
||||
|
||||
V_FindPosition = _utstring_findR(s->d,
|
||||
V_HaystackLen,
|
||||
P_Needle,
|
||||
P_NeedleLen,
|
||||
V_KMP_Table);
|
||||
|
||||
__libc_free(V_KMP_Table);
|
||||
}
|
||||
}
|
||||
|
||||
return V_FindPosition;
|
||||
}
|
||||
/*******************************************************************************
|
||||
* end substring search functions *
|
||||
******************************************************************************/
|
||||
|
||||
#endif /* UTSTRING_H */
|
Loading…
x
Reference in New Issue
Block a user