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:
Ray Strode 2021-06-27 18:02:10 -04:00
parent a4b72a282c
commit 3934937c30
11 changed files with 7207 additions and 3 deletions

View File

@ -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) \

View File

@ -268,6 +268,7 @@ glib_init (void)
glib_inited = TRUE;
g_metrics_init ();
g_messages_prefixed_init ();
g_debug_init ();
g_quark_init ();

View File

@ -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;

View File

@ -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>

View File

@ -202,6 +202,8 @@
#include <unistd.h>
#endif
#include <zlib.h>
#ifdef G_OS_WIN32
#include <process.h> /* For getpid() */
#include <io.h>

View File

@ -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

File diff suppressed because it is too large Load Diff

333
glib/gmetrics.h Normal file
View 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

File diff suppressed because it is too large Load Diff

1073
glib/utlist.h Normal file

File diff suppressed because it is too large Load Diff

411
glib/utstring.h Normal file
View 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 */