diff options
author | Jaikumar Ganesh <jaikumar@google.com> | 2009-06-04 16:14:32 -0700 |
---|---|---|
committer | Jaikumar Ganesh <jaikumar@google.com> | 2009-06-04 16:47:29 -0700 |
commit | bb28d819383d1cbebb355153d2f53c858288835f (patch) | |
tree | 20e23fdc7346b18789e28927cda9c366b8b2e432 | |
parent | 3c3776dce32610185914957072ca66cfff34d7bb (diff) | |
download | glib-bb28d819383d1cbebb355153d2f53c858288835f.tar.gz |
Android specific changes.
Added Android.mk fies, delete files.
119 files changed, 115 insertions, 67781 deletions
diff --git a/Android.mk b/Android.mk new file mode 100755 index 000000000..456efddcd --- /dev/null +++ b/Android.mk @@ -0,0 +1,20 @@ +# +# Copyright (C) 2008 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +ifneq ($(TARGET_SIMULATOR),true) +ifeq ($(BOARD_HAVE_BLUETOOTH),true) + include $(all-subdir-makefiles) +endif +endif diff --git a/glib/Android.mk b/glib/Android.mk new file mode 100755 index 000000000..975fe1e2b --- /dev/null +++ b/glib/Android.mk @@ -0,0 +1,45 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + gdir.c \ + gerror.c \ + giochannel.c \ + gkeyfile.c \ + gmain.c \ + gmem.c \ + goption.c \ + gslice.c \ + gslist.c \ + gstring.c \ + gstrfuncs.c \ + gtimer.c \ + giounix.c \ + gmessages.c \ + gutf8.c \ + gfileutils.c \ + gconvert.c \ + gdataset.c \ + gtestutils.c \ + ghash.c \ + glist.c \ + gthread.c \ + garray.c \ + gutils.c \ + gatomic.c \ + gprintf.c \ + gpattern.c \ + guniprop.c \ + gpoll.c \ + grand.c \ + gunidecomp.c \ + gqsort.c \ + gstdio.c + +LOCAL_C_INCLUDES:= \ + $(LOCAL_PATH)/../ \ + $(LOCAL_PATH) + +LOCAL_MODULE:=libglib_static + +include $(BUILD_STATIC_LIBRARY) diff --git a/glib/abicheck.sh b/glib/abicheck.sh deleted file mode 100755 index ce9a96672..000000000 --- a/glib/abicheck.sh +++ /dev/null @@ -1,13 +0,0 @@ -#! /bin/sh - -egrep '^#([^i]|if).*[^\]$' "${top_builddir:-..}/glibconfig.h" > glibconfig.cpp - -INCLUDES="-include ${top_builddir:-..}/config.h" -INCLUDES="$INCLUDES -include glibconfig.cpp $GLIB_DEBUG_FLAGS" - -cpp -P -DINCLUDE_INTERNAL_SYMBOLS -DINCLUDE_VARIABLES -DG_STDIO_NO_WRAP_ON_UNIX -DALL_FILES $INCLUDES "${srcdir:-.}/glib.symbols" | sed -e '/^$/d' -e 's/ G_GNUC.*$//' -e 's/ PRIVATE$//' | sort > expected-abi -rm -f glibconfig.cpp - -nm -D -g --defined-only .libs/libglib-2.0.so | cut -d ' ' -f 3 | sort > actual-abi - -diff -u expected-abi actual-abi && rm -f expected-abi actual-abi diff --git a/glib/gasyncqueue.c b/glib/gasyncqueue.c deleted file mode 100644 index 65e95a8de..000000000 --- a/glib/gasyncqueue.c +++ /dev/null @@ -1,666 +0,0 @@ -/* 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * MT safe - */ - -#include "config.h" - -#include "glib.h" -#include "galias.h" - - -struct _GAsyncQueue -{ - GMutex *mutex; - GCond *cond; - GQueue *queue; - GDestroyNotify item_free_func; - guint waiting_threads; - gint32 ref_count; -}; - -typedef struct { - GCompareDataFunc func; - gpointer user_data; -} SortData; - -/** - * g_async_queue_new: - * - * Creates a new asynchronous queue with the initial reference count of 1. - * - * Return value: the new #GAsyncQueue. - **/ -GAsyncQueue* -g_async_queue_new (void) -{ - GAsyncQueue* retval = g_new (GAsyncQueue, 1); - retval->mutex = g_mutex_new (); - retval->cond = NULL; - retval->queue = g_queue_new (); - retval->waiting_threads = 0; - retval->ref_count = 1; - retval->item_free_func = NULL; - return retval; -} - -/** - * g_async_queue_new_full: - * @item_free_func: function to free queue elements - * - * Creates a new asynchronous queue with an initial reference count of 1 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. - * - * Return value: the new #GAsyncQueue. - * - * Since: 2.16 - **/ -GAsyncQueue* -g_async_queue_new_full (GDestroyNotify item_free_func) -{ - GAsyncQueue *async_queue = g_async_queue_new (); - async_queue->item_free_func = item_free_func; - return async_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_return_val_if_fail (g_atomic_int_get (&queue->ref_count) > 0, 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: Since 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_return_if_fail (g_atomic_int_get (&queue->ref_count) > 0); - - 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: Since 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_return_if_fail (g_atomic_int_get (&queue->ref_count) > 0); - - 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); - g_return_if_fail (g_atomic_int_get (&queue->ref_count) > 0); - - if (g_atomic_int_dec_and_test (&queue->ref_count)) - { - g_return_if_fail (queue->waiting_threads == 0); - g_mutex_free (queue->mutex); - if (queue->cond) - g_cond_free (queue->cond); - if (queue->item_free_func) - g_queue_foreach (queue->queue, (GFunc) queue->item_free_func, NULL); - g_queue_free (queue->queue); - g_free (queue); - } -} - -/** - * g_async_queue_lock: - * @queue: a #GAsyncQueue. - * - * Acquires the @queue's lock. After that you can only call the - * <function>g_async_queue_*_unlocked()</function> function variants on that - * @queue. Otherwise it will deadlock. - **/ -void -g_async_queue_lock (GAsyncQueue *queue) -{ - g_return_if_fail (queue); - g_return_if_fail (g_atomic_int_get (&queue->ref_count) > 0); - - g_mutex_lock (queue->mutex); -} - -/** - * g_async_queue_unlock: - * @queue: a #GAsyncQueue. - * - * Releases the queue's lock. - **/ -void -g_async_queue_unlock (GAsyncQueue *queue) -{ - g_return_if_fail (queue); - g_return_if_fail (g_atomic_int_get (&queue->ref_count) > 0); - - 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 (g_atomic_int_get (&queue->ref_count) > 0); - 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 (g_atomic_int_get (&queue->ref_count) > 0); - 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. This function - * is passed two elements of the @queue. The function 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. - * @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. - * - * 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. This function - * is passed two elements of the @queue. The function 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. - * @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. - * - * This function is 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 try, - GTimeVal *end_time) -{ - gpointer retval; - - if (!g_queue_peek_tail_link (queue->queue)) - { - if (try) - return NULL; - - if (!queue->cond) - queue->cond = g_cond_new (); - - if (!end_time) - { - queue->waiting_threads++; - while (!g_queue_peek_tail_link (queue->queue)) - g_cond_wait (queue->cond, queue->mutex); - queue->waiting_threads--; - } - else - { - queue->waiting_threads++; - while (!g_queue_peek_tail_link (queue->queue)) - if (!g_cond_timed_wait (queue->cond, queue->mutex, end_time)) - break; - queue->waiting_threads--; - if (!g_queue_peek_tail_link (queue->queue)) - return NULL; - } - } - - retval = g_queue_pop_tail (queue->queue); - - g_assert (retval); - - return retval; -} - -/** - * g_async_queue_pop: - * @queue: a #GAsyncQueue. - * - * Pops data from the @queue. This function blocks until data become - * available. - * - * Return value: data from the queue. - **/ -gpointer -g_async_queue_pop (GAsyncQueue* queue) -{ - gpointer retval; - - g_return_val_if_fail (queue, NULL); - g_return_val_if_fail (g_atomic_int_get (&queue->ref_count) > 0, NULL); - - g_mutex_lock (queue->mutex); - retval = g_async_queue_pop_intern_unlocked (queue, FALSE, NULL); - g_mutex_unlock (queue->mutex); - - return retval; -} - -/** - * g_async_queue_pop_unlocked: - * @queue: a #GAsyncQueue. - * - * Pops data from the @queue. This function blocks until data become - * available. This function must be called while holding the @queue's - * lock. - * - * Return value: data from the queue. - **/ -gpointer -g_async_queue_pop_unlocked (GAsyncQueue* queue) -{ - g_return_val_if_fail (queue, NULL); - g_return_val_if_fail (g_atomic_int_get (&queue->ref_count) > 0, NULL); - - return g_async_queue_pop_intern_unlocked (queue, FALSE, NULL); -} - -/** - * g_async_queue_try_pop: - * @queue: a #GAsyncQueue. - * - * Tries to pop data from the @queue. If no data is available, %NULL is - * returned. - * - * Return value: 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_return_val_if_fail (g_atomic_int_get (&queue->ref_count) > 0, NULL); - - g_mutex_lock (queue->mutex); - retval = g_async_queue_pop_intern_unlocked (queue, TRUE, NULL); - 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. - * - * Return value: 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); - g_return_val_if_fail (g_atomic_int_get (&queue->ref_count) > 0, NULL); - - return g_async_queue_pop_intern_unlocked (queue, TRUE, NULL); -} - -/** - * g_async_queue_timed_pop: - * @queue: a #GAsyncQueue. - * @end_time: a #GTimeVal, determining the final time. - * - * Pops data from the @queue. If no data is received before @end_time, - * %NULL is returned. - * - * To easily calculate @end_time a combination of g_get_current_time() - * and g_time_val_add() can be used. - * - * Return value: data from the queue or %NULL, when no data is - * received before @end_time. - **/ -gpointer -g_async_queue_timed_pop (GAsyncQueue* queue, GTimeVal *end_time) -{ - gpointer retval; - - g_return_val_if_fail (queue, NULL); - g_return_val_if_fail (g_atomic_int_get (&queue->ref_count) > 0, NULL); - - g_mutex_lock (queue->mutex); - retval = g_async_queue_pop_intern_unlocked (queue, FALSE, end_time); - g_mutex_unlock (queue->mutex); - - return retval; -} - -/** - * g_async_queue_timed_pop_unlocked: - * @queue: a #GAsyncQueue. - * @end_time: a #GTimeVal, determining the final time. - * - * Pops data from the @queue. If no data is received before @end_time, - * %NULL is returned. This function must be called while holding the - * @queue's lock. - * - * To easily calculate @end_time a combination of g_get_current_time() - * and g_time_val_add() can be used. - * - * Return value: data from the queue or %NULL, when no data is - * received before @end_time. - **/ -gpointer -g_async_queue_timed_pop_unlocked (GAsyncQueue* queue, GTimeVal *end_time) -{ - g_return_val_if_fail (queue, NULL); - g_return_val_if_fail (g_atomic_int_get (&queue->ref_count) > 0, NULL); - - return g_async_queue_pop_intern_unlocked (queue, FALSE, end_time); -} - -/** - * g_async_queue_length: - * @queue: a #GAsyncQueue. - * - * Returns the length of the queue, negative values mean waiting - * threads, positive values mean available entries in the - * @queue. Actually this function returns the number of data items in - * the queue minus the number of waiting threads. Thus a return value - * of 0 could mean 'n' entries in the queue and 'n' thread waiting. - * That can happen due to locking of the queue or due to - * scheduling. - * - * Return value: the length of the @queue. - **/ -gint -g_async_queue_length (GAsyncQueue* queue) -{ - gint retval; - - g_return_val_if_fail (queue, 0); - g_return_val_if_fail (g_atomic_int_get (&queue->ref_count) > 0, 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, negative values mean waiting - * threads, positive values mean available entries in the - * @queue. Actually this function returns the number of data items in - * the queue minus the number of waiting threads. Thus a return value - * of 0 could mean 'n' entries in the queue and 'n' thread waiting. - * That can happen due to locking of the queue or due to - * scheduling. This function must be called while holding the @queue's - * lock. - * - * Return value: the length of the @queue. - **/ -gint -g_async_queue_length_unlocked (GAsyncQueue* queue) -{ - g_return_val_if_fail (queue, 0); - g_return_val_if_fail (g_atomic_int_get (&queue->ref_count) > 0, 0); - - return queue->queue->length - queue->waiting_threads; -} - -/** - * g_async_queue_sort: - * @queue: a #GAsyncQueue - * @func: the #GCompareDataFunc is used to sort @queue. This - * function is passed two elements of the @queue. The function - * 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. - * @user_data: user data passed to @func - * - * Sorts @queue using @func. - * - * 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: - * |[ - * 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. This - * function is passed two elements of the @queue. The function - * 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. - * @user_data: user data passed to @func - * - * Sorts @queue using @func. - * - * This function is 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); -} - -/* - * Private API - */ - -GMutex* -_g_async_queue_get_mutex (GAsyncQueue* queue) -{ - g_return_val_if_fail (queue, NULL); - g_return_val_if_fail (g_atomic_int_get (&queue->ref_count) > 0, NULL); - - return queue->mutex; -} - -#define __G_ASYNCQUEUE_C__ -#include "galiasdef.c" diff --git a/glib/gbacktrace.c b/glib/gbacktrace.c deleted file mode 100644 index 238d9cf97..000000000 --- a/glib/gbacktrace.c +++ /dev/null @@ -1,308 +0,0 @@ -/* 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, 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 ; except for g_on_error_stack_trace, but who wants thread safety - * then - */ - -#include "config.h" - -#include <signal.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include "glib.h" -#include "gprintfint.h" - -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef HAVE_SYS_TIMES_H -#include <sys/times.h> -#endif -#include <sys/types.h> -#ifdef HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif - -#include <time.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#ifdef HAVE_SYS_SELECT_H -#include <sys/select.h> -#endif /* HAVE_SYS_SELECT_H */ - -#include <string.h> /* for bzero on BSD systems */ - -#ifdef G_OS_WIN32 -# define STRICT /* Strict typing, please */ -# define _WIN32_WINDOWS 0x0401 /* to get IsDebuggerPresent */ -# include <windows.h> -# undef STRICT -#endif - -#ifndef NO_FD_SET -# define SELECT_MASK fd_set -#else -# if defined(_IBMR2) -# define SELECT_MASK void -# else -# define SELECT_MASK int -# endif -#endif - -#include "galias.h" - -#ifndef G_OS_WIN32 -static void stack_trace (char **args); -#endif - -extern volatile gboolean glib_on_error_halt; -volatile gboolean glib_on_error_halt = TRUE; - -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 (NULL, "g_on_error_query called, program terminating", - (prg_name && *prg_name) ? prg_name : NULL, - MB_OK|MB_ICONERROR); - _exit(0); -#endif -} - -void -g_on_error_stack_trace (const gchar *prg_name) -{ -#if defined(G_OS_UNIX) || defined(G_OS_BEOS) - pid_t pid; - gchar buf[16]; - gchar *args[4] = { "gdb", NULL, NULL, NULL }; - int status; - - if (!prg_name) - return; - - _g_sprintf (buf, "%u", (guint) getpid ()); - - args[1] = (gchar*) prg_name; - args[2] = buf; - - pid = fork (); - if (pid == 0) - { - stack_trace (args); - _exit (0); - } - else if (pid == (pid_t) -1) - { - perror ("unable to fork gdb"); - return; - } - - waitpid (pid, &status, 0); -#else - if (IsDebuggerPresent ()) - G_BREAKPOINT (); - else - abort (); -#endif -} - -#ifndef G_OS_WIN32 - -static gboolean stack_trace_done = FALSE; - -static void -stack_trace_sigchld (int signum) -{ - stack_trace_done = TRUE; -} - -static void -stack_trace (char **args) -{ - pid_t pid; - int in_fd[2]; - int out_fd[2]; - SELECT_MASK fdset; - SELECT_MASK readset; - struct timeval tv; - int sel, idx, state; - char buffer[256]; - 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) - { - 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], args); /* exec gdb */ - perror ("exec failed"); - _exit (0); - } - else if (pid == (pid_t) -1) - { - perror ("unable to fork"); - _exit (0); - } - - FD_ZERO (&fdset); - FD_SET (out_fd[0], &fdset); - - write (in_fd[1], "backtrace\n", 10); - write (in_fd[1], "p x = 0\n", 8); - write (in_fd[1], "quit\n", 5); - - idx = 0; - 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)) - { - switch (state) - { - case 0: - if (c == '#') - { - state = 1; - idx = 0; - buffer[idx++] = c; - } - break; - case 1: - buffer[idx++] = c; - if ((c == '\n') || (c == '\r')) - { - buffer[idx] = 0; - _g_fprintf (stdout, "%s", buffer); - state = 0; - idx = 0; - } - 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 */ - -#define __G_BACKTRACE_C__ -#include "galiasdef.c" diff --git a/glib/gbase64.c b/glib/gbase64.c deleted file mode 100644 index bfdc76aa5..000000000 --- a/glib/gbase64.c +++ /dev/null @@ -1,423 +0,0 @@ -/* 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 Library General Public - * License as published by the Free Software Foundation; either - * version 2 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * 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 "glib.h" -#include "glibintl.h" - -#include "galias.h" - -static const char base64_alphabet[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -/** - * g_base64_encode_step: - * @in: the binary data to encode - * @len: the length of @in - * @break_lines: whether to break long lines - * @out: pointer to destination buffer - * @state: Saved state between steps, initialize to 0 - * @save: 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) / 72 + 1 bytes of extra space. - * - * @break_lines is typically used when putting base64-encoded data in emails. - * It breaks the lines at 72 columns instead of putting all of the text on - * the same line. This avoids problems with long lines in the email system. - * - * Return value: 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, 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; - } - - if (len>0) - { - 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++; - case 1: *saveout++ = *inptr++; - } - ((char *)save)[0] += len; - } - - return outptr - out; -} - -/** - * g_base64_encode_close: - * @break_lines: whether to break long lines - * @out: pointer to destination buffer - * @state: Saved state from g_base64_encode_step() - * @save: Saved state from g_base64_encode_step() - * - * Flush the status from a sequence of calls to g_base64_encode_step(). - * - * Return value: 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] = '='; - 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: the binary data to encode - * @len: the length of @data - * - * Encode a sequence of binary data into its Base-64 stringified - * representation. - * - * Return value: 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, NULL); - g_return_val_if_fail (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 */ - if (len >= ((G_MAXSIZE - 1) / 4 - 1) * 3) - g_error("%s: input too large for Base64 encoding (%"G_GSIZE_FORMAT" chars)", - G_STRLOC, len); - - 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: - * @in: binary input data - * @len: max length of @in data to decode - * @out: output buffer - * @state: Saved state between steps, initialize to 0 - * @save: 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). - * - * Return value: 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, 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; - inptr = (const guchar *)in; - last[0] = last[1] = 0; - 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 = i; - - return outptr - out; -} - -/** - * g_base64_decode: - * @text: zero-terminated string with base64 text to decode - * @out_len: The length of the decoded data is written here - * - * Decode a sequence of Base-64 encoded text into binary data - * - * Return value: a 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); - - g_return_val_if_fail (input_length > 1, NULL); - - /* 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 retruning 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: zero-terminated string with base64 text to decode - * @out_len: 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. - * - * Return value: 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 text; -} - - -#define __G_BASE64_C__ -#include "galiasdef.c" diff --git a/glib/gbookmarkfile.c b/glib/gbookmarkfile.c deleted file mode 100644 index 01c7e639e..000000000 --- a/glib/gbookmarkfile.c +++ /dev/null @@ -1,3709 +0,0 @@ -/* gbookmarkfile.c: 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 Library General Public - * License as published by the Free Software Foundation; either - * version 2 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - */ - -#include "config.h" - -#include "gbookmarkfile.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <fcntl.h> -#include <locale.h> -#include <time.h> -#include <stdarg.h> -#include <sys/types.h> -#include <sys/stat.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#include "gconvert.h" -#include "gdataset.h" -#include "gerror.h" -#include "gfileutils.h" -#include "ghash.h" -#include "glibintl.h" -#include "glist.h" -#include "gslist.h" -#include "gmain.h" -#include "gmarkup.h" -#include "gmem.h" -#include "gmessages.h" -#include "gshell.h" -#include "gslice.h" -#include "gstdio.h" -#include "gstring.h" -#include "gstrfuncs.h" -#include "gtimer.h" -#include "gutils.h" - -#include "galias.h" - -/* XBEL 1.0 standard entities */ -#define XBEL_VERSION "1.0" -#define XBEL_DTD_NICK "xbel" -#define XBEL_DTD_SYSTEM "+//IDN python.org//DTD XML Bookmark " \ - "Exchange Language 1.0//EN//XML" - -#define XBEL_DTD_URI "http://www.python.org/topics/xml/dtds/xbel-1.0.dtd" - -#define XBEL_ROOT_ELEMENT "xbel" -#define XBEL_FOLDER_ELEMENT "folder" /* unused */ -#define XBEL_BOOKMARK_ELEMENT "bookmark" -#define XBEL_ALIAS_ELEMENT "alias" /* unused */ -#define XBEL_SEPARATOR_ELEMENT "separator" /* unused */ -#define XBEL_TITLE_ELEMENT "title" -#define XBEL_DESC_ELEMENT "desc" -#define XBEL_INFO_ELEMENT "info" -#define XBEL_METADATA_ELEMENT "metadata" - -#define XBEL_VERSION_ATTRIBUTE "version" -#define XBEL_FOLDED_ATTRIBUTE "folded" /* unused */ -#define XBEL_OWNER_ATTRIBUTE "owner" -#define XBEL_ADDED_ATTRIBUTE "added" -#define XBEL_VISITED_ATTRIBUTE "visited" -#define XBEL_MODIFIED_ATTRIBUTE "modified" -#define XBEL_ID_ATTRIBUTE "id" -#define XBEL_HREF_ATTRIBUTE "href" -#define XBEL_REF_ATTRIBUTE "ref" /* unused */ - -#define XBEL_YES_VALUE "yes" -#define XBEL_NO_VALUE "no" - -/* Desktop bookmark spec entities */ -#define BOOKMARK_METADATA_OWNER "http://freedesktop.org" - -#define BOOKMARK_NAMESPACE_NAME "bookmark" -#define BOOKMARK_NAMESPACE_URI "http://www.freedesktop.org/standards/desktop-bookmarks" - -#define BOOKMARK_GROUPS_ELEMENT "groups" -#define BOOKMARK_GROUP_ELEMENT "group" -#define BOOKMARK_APPLICATIONS_ELEMENT "applications" -#define BOOKMARK_APPLICATION_ELEMENT "application" -#define BOOKMARK_ICON_ELEMENT "icon" -#define BOOKMARK_PRIVATE_ELEMENT "private" - -#define BOOKMARK_NAME_ATTRIBUTE "name" -#define BOOKMARK_EXEC_ATTRIBUTE "exec" -#define BOOKMARK_COUNT_ATTRIBUTE "count" -#define BOOKMARK_TIMESTAMP_ATTRIBUTE "timestamp" /* deprecated by "modified" */ -#define BOOKMARK_MODIFIED_ATTRIBUTE "modified" -#define BOOKMARK_HREF_ATTRIBUTE "href" -#define BOOKMARK_TYPE_ATTRIBUTE "type" - -/* Shared MIME Info entities */ -#define MIME_NAMESPACE_NAME "mime" -#define MIME_NAMESPACE_URI "http://www.freedesktop.org/standards/shared-mime-info" -#define MIME_TYPE_ELEMENT "mime-type" -#define MIME_TYPE_ATTRIBUTE "type" - - -typedef struct _BookmarkAppInfo BookmarkAppInfo; -typedef struct _BookmarkMetadata BookmarkMetadata; -typedef struct _BookmarkItem BookmarkItem; -typedef struct _ParseData ParseData; - -struct _BookmarkAppInfo -{ - gchar *name; - gchar *exec; - - guint count; - - time_t stamp; -}; - -struct _BookmarkMetadata -{ - gchar *mime_type; - - GList *groups; - - GList *applications; - GHashTable *apps_by_name; - - gchar *icon_href; - gchar *icon_mime; - - guint is_private : 1; -}; - -struct _BookmarkItem -{ - gchar *uri; - - gchar *title; - gchar *description; - - time_t added; - time_t modified; - time_t visited; - - BookmarkMetadata *metadata; -}; - -struct _GBookmarkFile -{ - gchar *title; - gchar *description; - - /* we store our items in a list and keep a copy inside - * an hash table for faster lookup performances - */ - GList *items; - GHashTable *items_by_uri; -}; - -/* parser state machine */ -enum -{ - STATE_STARTED = 0, - - STATE_ROOT, - STATE_BOOKMARK, - STATE_TITLE, - STATE_DESC, - STATE_INFO, - STATE_METADATA, - STATE_APPLICATIONS, - STATE_APPLICATION, - STATE_GROUPS, - STATE_GROUP, - STATE_MIME, - STATE_ICON, - - STATE_FINISHED -}; - -static void g_bookmark_file_init (GBookmarkFile *bookmark); -static void g_bookmark_file_clear (GBookmarkFile *bookmark); -static gboolean g_bookmark_file_parse (GBookmarkFile *bookmark, - const gchar *buffer, - gsize length, - GError **error); -static gchar * g_bookmark_file_dump (GBookmarkFile *bookmark, - gsize *length, - GError **error); -static BookmarkItem *g_bookmark_file_lookup_item (GBookmarkFile *bookmark, - const gchar *uri); -static void g_bookmark_file_add_item (GBookmarkFile *bookmark, - BookmarkItem *item, - GError **error); - -static time_t timestamp_from_iso8601 (const gchar *iso_date); -static gchar * timestamp_to_iso8601 (time_t timestamp); - -/******************************** - * BookmarkAppInfo * - * * - * Application metadata storage * - ********************************/ -static BookmarkAppInfo * -bookmark_app_info_new (const gchar *name) -{ - BookmarkAppInfo *retval; - - g_warn_if_fail (name != NULL); - - retval = g_slice_new (BookmarkAppInfo); - - retval->name = g_strdup (name); - retval->exec = NULL; - retval->count = 0; - retval->stamp = 0; - - return retval; -} - -static void -bookmark_app_info_free (BookmarkAppInfo *app_info) -{ - if (!app_info) - return; - - g_free (app_info->name); - g_free (app_info->exec); - - g_slice_free (BookmarkAppInfo, app_info); -} - -static gchar * -bookmark_app_info_dump (BookmarkAppInfo *app_info) -{ - gchar *retval; - gchar *name, *exec, *modified, *count; - - g_warn_if_fail (app_info != NULL); - - if (app_info->count == 0) - return NULL; - - name = g_markup_escape_text (app_info->name, -1); - exec = g_markup_escape_text (app_info->exec, -1); - modified = timestamp_to_iso8601 (app_info->stamp); - count = g_strdup_printf ("%u", app_info->count); - - retval = g_strconcat (" " - "<" BOOKMARK_NAMESPACE_NAME ":" BOOKMARK_APPLICATION_ELEMENT - " " BOOKMARK_NAME_ATTRIBUTE "=\"", name, "\"" - " " BOOKMARK_EXEC_ATTRIBUTE "=\"", exec, "\"" - " " BOOKMARK_MODIFIED_ATTRIBUTE "=\"", modified, "\"" - " " BOOKMARK_COUNT_ATTRIBUTE "=\"", count, "\"/>\n", - NULL); - - g_free (name); - g_free (exec); - g_free (modified); - g_free (count); - - return retval; -} - - -/*********************** - * BookmarkMetadata * - * * - * Metadata storage * - ***********************/ -static BookmarkMetadata * -bookmark_metadata_new (void) -{ - BookmarkMetadata *retval; - - retval = g_slice_new (BookmarkMetadata); - - retval->mime_type = NULL; - - retval->groups = NULL; - - retval->applications = NULL; - retval->apps_by_name = g_hash_table_new_full (g_str_hash, - g_str_equal, - NULL, - NULL); - - retval->is_private = FALSE; - - retval->icon_href = NULL; - retval->icon_mime = NULL; - - return retval; -} - -static void -bookmark_metadata_free (BookmarkMetadata *metadata) -{ - if (!metadata) - return; - - g_free (metadata->mime_type); - - if (metadata->groups) - { - g_list_foreach (metadata->groups, - (GFunc) g_free, - NULL); - g_list_free (metadata->groups); - } - - if (metadata->applications) - { - g_list_foreach (metadata->applications, - (GFunc) bookmark_app_info_free, - NULL); - g_list_free (metadata->applications); - } - - g_hash_table_destroy (metadata->apps_by_name); - - g_free (metadata->icon_href); - g_free (metadata->icon_mime); - - g_slice_free (BookmarkMetadata, metadata); -} - -static gchar * -bookmark_metadata_dump (BookmarkMetadata *metadata) -{ - GString *retval; - gchar *buffer; - - if (!metadata->applications) - return NULL; - - retval = g_string_sized_new (1024); - - /* metadata container */ - g_string_append (retval, - " " - "<" XBEL_METADATA_ELEMENT - " " XBEL_OWNER_ATTRIBUTE "=\"" BOOKMARK_METADATA_OWNER - "\">\n"); - - /* mime type */ - if (metadata->mime_type) { - buffer = g_strconcat (" " - "<" MIME_NAMESPACE_NAME ":" MIME_TYPE_ELEMENT " " - MIME_TYPE_ATTRIBUTE "=\"", metadata->mime_type, "\"/>\n", - NULL); - g_string_append (retval, buffer); - g_free (buffer); - } - - if (metadata->groups) - { - GList *l; - - /* open groups container */ - g_string_append (retval, - " " - "<" BOOKMARK_NAMESPACE_NAME - ":" BOOKMARK_GROUPS_ELEMENT ">\n"); - - for (l = g_list_last (metadata->groups); l != NULL; l = l->prev) - { - gchar *group_name; - - group_name = g_markup_escape_text ((gchar *) l->data, -1); - buffer = g_strconcat (" " - "<" BOOKMARK_NAMESPACE_NAME - ":" BOOKMARK_GROUP_ELEMENT ">", - group_name, - "</" BOOKMARK_NAMESPACE_NAME - ":" BOOKMARK_GROUP_ELEMENT ">\n", NULL); - g_string_append (retval, buffer); - - g_free (buffer); - g_free (group_name); - } - - /* close groups container */ - g_string_append (retval, - " " - "</" BOOKMARK_NAMESPACE_NAME - ":" BOOKMARK_GROUPS_ELEMENT ">\n"); - } - - if (metadata->applications) - { - GList *l; - - /* open applications container */ - g_string_append (retval, - " " - "<" BOOKMARK_NAMESPACE_NAME - ":" BOOKMARK_APPLICATIONS_ELEMENT ">\n"); - - for (l = g_list_last (metadata->applications); l != NULL; l = l->prev) - { - BookmarkAppInfo *app_info = (BookmarkAppInfo *) l->data; - gchar *app_data; - - g_warn_if_fail (app_info != NULL); - - app_data = bookmark_app_info_dump (app_info); - - if (app_data) - { - retval = g_string_append (retval, app_data); - - g_free (app_data); - } - } - - /* close applications container */ - g_string_append (retval, - " " - "</" BOOKMARK_NAMESPACE_NAME - ":" BOOKMARK_APPLICATIONS_ELEMENT ">\n"); - } - - /* icon */ - if (metadata->icon_href) - { - if (!metadata->icon_mime) - metadata->icon_mime = g_strdup ("application/octet-stream"); - - buffer = g_strconcat (" " - "<" BOOKMARK_NAMESPACE_NAME - ":" BOOKMARK_ICON_ELEMENT - " " BOOKMARK_HREF_ATTRIBUTE "=\"", metadata->icon_href, - "\" " BOOKMARK_TYPE_ATTRIBUTE "=\"", metadata->icon_mime, "\"/>\n", NULL); - g_string_append (retval, buffer); - - g_free (buffer); - } - - /* private hint */ - if (metadata->is_private) - g_string_append (retval, - " " - "<" BOOKMARK_NAMESPACE_NAME - ":" BOOKMARK_PRIVATE_ELEMENT "/>\n"); - - /* close metadata container */ - g_string_append (retval, - " " - "</" XBEL_METADATA_ELEMENT ">\n"); - - return g_string_free (retval, FALSE); -} - -/****************************************************** - * BookmarkItem * - * * - * Storage for a single bookmark item inside the list * - ******************************************************/ -static BookmarkItem * -bookmark_item_new (const gchar *uri) -{ - BookmarkItem *item; - - g_warn_if_fail (uri != NULL); - - item = g_slice_new (BookmarkItem); - item->uri = g_strdup (uri); - - item->title = NULL; - item->description = NULL; - - item->added = (time_t) -1; - item->modified = (time_t) -1; - item->visited = (time_t) -1; - - item->metadata = NULL; - - return item; -} - -static void -bookmark_item_free (BookmarkItem *item) -{ - if (!item) - return; - - g_free (item->uri); - g_free (item->title); - g_free (item->description); - - if (item->metadata) - bookmark_metadata_free (item->metadata); - - g_slice_free (BookmarkItem, item); -} - -static gchar * -bookmark_item_dump (BookmarkItem *item) -{ - GString *retval; - gchar *added, *visited, *modified; - gchar *escaped_uri; - gchar *buffer; - - /* at this point, we must have at least a registered application; if we don't - * we don't screw up the bookmark file, and just skip this item - */ - if (!item->metadata || !item->metadata->applications) - { - g_warning ("Item for URI '%s' has no registered applications: skipping.\n", item->uri); - return NULL; - } - - retval = g_string_sized_new (4096); - - added = timestamp_to_iso8601 (item->added); - modified = timestamp_to_iso8601 (item->modified); - visited = timestamp_to_iso8601 (item->visited); - - escaped_uri = g_markup_escape_text (item->uri, -1); - - buffer = g_strconcat (" <" - XBEL_BOOKMARK_ELEMENT - " " - XBEL_HREF_ATTRIBUTE "=\"", escaped_uri, "\" " - XBEL_ADDED_ATTRIBUTE "=\"", added, "\" " - XBEL_MODIFIED_ATTRIBUTE "=\"", modified, "\" " - XBEL_VISITED_ATTRIBUTE "=\"", visited, "\">\n", - NULL); - - g_string_append (retval, buffer); - - g_free (escaped_uri); - g_free (visited); - g_free (modified); - g_free (added); - g_free (buffer); - - if (item->title) - { - gchar *escaped_title; - - escaped_title = g_markup_escape_text (item->title, -1); - buffer = g_strconcat (" " - "<" XBEL_TITLE_ELEMENT ">", - escaped_title, - "</" XBEL_TITLE_ELEMENT ">\n", - NULL); - g_string_append (retval, buffer); - - g_free (escaped_title); - g_free (buffer); - } - - if (item->description) - { - gchar *escaped_desc; - - escaped_desc = g_markup_escape_text (item->description, -1); - buffer = g_strconcat (" " - "<" XBEL_DESC_ELEMENT ">", - escaped_desc, - "</" XBEL_DESC_ELEMENT ">\n", - NULL); - g_string_append (retval, buffer); - - g_free (escaped_desc); - g_free (buffer); - } - - if (item->metadata) - { - gchar *metadata; - - metadata = bookmark_metadata_dump (item->metadata); - if (metadata) - { - buffer = g_strconcat (" " - "<" XBEL_INFO_ELEMENT ">\n", - metadata, - " " - "</" XBEL_INFO_ELEMENT ">\n", - NULL); - retval = g_string_append (retval, buffer); - - g_free (buffer); - g_free (metadata); - } - } - - g_string_append (retval, " </" XBEL_BOOKMARK_ELEMENT ">\n"); - - return g_string_free (retval, FALSE); -} - -static BookmarkAppInfo * -bookmark_item_lookup_app_info (BookmarkItem *item, - const gchar *app_name) -{ - g_warn_if_fail (item != NULL && app_name != NULL); - - if (!item->metadata) - return NULL; - - return g_hash_table_lookup (item->metadata->apps_by_name, app_name); -} - -/************************* - * GBookmarkFile * - *************************/ - -static void -g_bookmark_file_init (GBookmarkFile *bookmark) -{ - bookmark->title = NULL; - bookmark->description = NULL; - - bookmark->items = NULL; - bookmark->items_by_uri = g_hash_table_new_full (g_str_hash, - g_str_equal, - NULL, - NULL); -} - -static void -g_bookmark_file_clear (GBookmarkFile *bookmark) -{ - g_free (bookmark->title); - g_free (bookmark->description); - - if (bookmark->items) - { - g_list_foreach (bookmark->items, - (GFunc) bookmark_item_free, - NULL); - g_list_free (bookmark->items); - - bookmark->items = NULL; - } - - if (bookmark->items_by_uri) - { - g_hash_table_destroy (bookmark->items_by_uri); - - bookmark->items_by_uri = NULL; - } -} - -struct _ParseData -{ - gint state; - - GHashTable *namespaces; - - GBookmarkFile *bookmark_file; - BookmarkItem *current_item; -}; - -static ParseData * -parse_data_new (void) -{ - ParseData *retval; - - retval = g_new (ParseData, 1); - - retval->state = STATE_STARTED; - retval->namespaces = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_free); - retval->bookmark_file = NULL; - retval->current_item = NULL; - - return retval; -} - -static void -parse_data_free (ParseData *parse_data) -{ - g_hash_table_destroy (parse_data->namespaces); - - g_free (parse_data); -} - -#define IS_ATTRIBUTE(s,a) ((0 == strcmp ((s), (a)))) - -static void -parse_bookmark_element (GMarkupParseContext *context, - ParseData *parse_data, - const gchar **attribute_names, - const gchar **attribute_values, - GError **error) -{ - const gchar *uri, *added, *modified, *visited; - const gchar *attr; - gint i; - BookmarkItem *item; - GError *add_error; - - g_warn_if_fail ((parse_data != NULL) && (parse_data->state == STATE_BOOKMARK)); - - i = 0; - uri = added = modified = visited = NULL; - for (attr = attribute_names[i]; attr != NULL; attr = attribute_names[++i]) - { - if (IS_ATTRIBUTE (attr, XBEL_HREF_ATTRIBUTE)) - uri = attribute_values[i]; - else if (IS_ATTRIBUTE (attr, XBEL_ADDED_ATTRIBUTE)) - added = attribute_values[i]; - else if (IS_ATTRIBUTE (attr, XBEL_MODIFIED_ATTRIBUTE)) - modified = attribute_values[i]; - else if (IS_ATTRIBUTE (attr, XBEL_VISITED_ATTRIBUTE)) - visited = attribute_values[i]; - else - { - /* bookmark is defined by the XBEL spec, so we need - * to error out if the element has different or - * missing attributes - */ - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, - _("Unexpected attribute '%s' for element '%s'"), - attr, - XBEL_BOOKMARK_ELEMENT); - return; - } - } - - if (!uri) - { - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("Attribute '%s' of element '%s' not found"), - XBEL_HREF_ATTRIBUTE, - XBEL_BOOKMARK_ELEMENT); - return; - } - - g_warn_if_fail (parse_data->current_item == NULL); - - item = bookmark_item_new (uri); - - if (added) - item->added = timestamp_from_iso8601 (added); - - if (modified) - item->modified = timestamp_from_iso8601 (modified); - - if (visited) - item->visited = timestamp_from_iso8601 (visited); - - add_error = NULL; - g_bookmark_file_add_item (parse_data->bookmark_file, - item, - &add_error); - if (add_error) - { - bookmark_item_free (item); - - g_propagate_error (error, add_error); - - return; - } - - parse_data->current_item = item; -} - -static void -parse_application_element (GMarkupParseContext *context, - ParseData *parse_data, - const gchar **attribute_names, - const gchar **attribute_values, - GError **error) -{ - const gchar *name, *exec, *count, *stamp, *modified; - const gchar *attr; - gint i; - BookmarkItem *item; - BookmarkAppInfo *ai; - - g_warn_if_fail ((parse_data != NULL) && (parse_data->state == STATE_APPLICATION)); - - i = 0; - name = exec = count = stamp = modified = NULL; - for (attr = attribute_names[i]; attr != NULL; attr = attribute_names[++i]) - { - if (IS_ATTRIBUTE (attr, BOOKMARK_NAME_ATTRIBUTE)) - name = attribute_values[i]; - else if (IS_ATTRIBUTE (attr, BOOKMARK_EXEC_ATTRIBUTE)) - exec = attribute_values[i]; - else if (IS_ATTRIBUTE (attr, BOOKMARK_COUNT_ATTRIBUTE)) - count = attribute_values[i]; - else if (IS_ATTRIBUTE (attr, BOOKMARK_TIMESTAMP_ATTRIBUTE)) - stamp = attribute_values[i]; - else if (IS_ATTRIBUTE (attr, BOOKMARK_MODIFIED_ATTRIBUTE)) - modified = attribute_values[i]; - } - - /* the "name" and "exec" attributes are mandatory */ - if (!name) - { - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("Attribute '%s' of element '%s' not found"), - BOOKMARK_NAME_ATTRIBUTE, - BOOKMARK_APPLICATION_ELEMENT); - return; - } - - if (!exec) - { - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("Attribute '%s' of element '%s' not found"), - BOOKMARK_EXEC_ATTRIBUTE, - BOOKMARK_APPLICATION_ELEMENT); - return; - } - - g_warn_if_fail (parse_data->current_item != NULL); - item = parse_data->current_item; - - ai = bookmark_item_lookup_app_info (item, name); - if (!ai) - { - ai = bookmark_app_info_new (name); - - if (!item->metadata) - item->metadata = bookmark_metadata_new (); - - item->metadata->applications = g_list_prepend (item->metadata->applications, ai); - g_hash_table_replace (item->metadata->apps_by_name, ai->name, ai); - } - - ai->exec = g_strdup (exec); - - if (count) - ai->count = atoi (count); - else - ai->count = 1; - - if (modified) - ai->stamp = timestamp_from_iso8601 (modified); - else - { - /* the timestamp attribute has been deprecated but we still parse - * it for backward compatibility - */ - if (stamp) - ai->stamp = (time_t) atol (stamp); - else - ai->stamp = time (NULL); - } -} - -static void -parse_mime_type_element (GMarkupParseContext *context, - ParseData *parse_data, - const gchar **attribute_names, - const gchar **attribute_values, - GError **error) -{ - const gchar *type; - const gchar *attr; - gint i; - BookmarkItem *item; - - g_warn_if_fail ((parse_data != NULL) && (parse_data->state == STATE_MIME)); - - i = 0; - type = NULL; - for (attr = attribute_names[i]; attr != NULL; attr = attribute_names[++i]) - { - if (IS_ATTRIBUTE (attr, MIME_TYPE_ATTRIBUTE)) - type = attribute_values[i]; - } - - if (!type) - type = "application/octet-stream"; - - g_warn_if_fail (parse_data->current_item != NULL); - item = parse_data->current_item; - - if (!item->metadata) - item->metadata = bookmark_metadata_new (); - - item->metadata->mime_type = g_strdup (type); -} - -static void -parse_icon_element (GMarkupParseContext *context, - ParseData *parse_data, - const gchar **attribute_names, - const gchar **attribute_values, - GError **error) -{ - const gchar *href; - const gchar *type; - const gchar *attr; - gint i; - BookmarkItem *item; - - g_warn_if_fail ((parse_data != NULL) && (parse_data->state == STATE_ICON)); - - i = 0; - href = NULL; - type = NULL; - for (attr = attribute_names[i]; attr != NULL; attr = attribute_names[++i]) - { - if (IS_ATTRIBUTE (attr, BOOKMARK_HREF_ATTRIBUTE)) - href = attribute_values[i]; - else if (IS_ATTRIBUTE (attr, BOOKMARK_TYPE_ATTRIBUTE)) - type = attribute_values[i]; - } - - /* the "href" attribute is mandatory */ - if (!href) - { - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("Attribute '%s' of element '%s' not found"), - BOOKMARK_HREF_ATTRIBUTE, - BOOKMARK_ICON_ELEMENT); - return; - } - - if (!type) - type = "application/octet-stream"; - - g_warn_if_fail (parse_data->current_item != NULL); - item = parse_data->current_item; - - if (!item->metadata) - item->metadata = bookmark_metadata_new (); - - item->metadata->icon_href = g_strdup (href); - item->metadata->icon_mime = g_strdup (type); -} - -/* scans through the attributes of an element for the "xmlns" pragma, and - * adds any resulting namespace declaration to a per-parser hashtable, using - * the namespace name as a key for the namespace URI; if no key was found, - * the namespace is considered as default, and stored under the "default" key. - * - * FIXME: this works on the assumption that the generator of the XBEL file - * is either this code or is smart enough to place the namespace declarations - * inside the main root node or inside the metadata node and does not redefine - * a namespace inside an inner node; this does *not* conform to the - * XML-NS standard, although is a close approximation. In order to make this - * conformant to the XML-NS specification we should use a per-element - * namespace table inside GMarkup and ask it to resolve the namespaces for us. - */ -static void -map_namespace_to_name (ParseData *parse_data, - const gchar **attribute_names, - const gchar **attribute_values) -{ - const gchar *attr; - gint i; - - g_warn_if_fail (parse_data != NULL); - - if (!attribute_names || !attribute_names[0]) - return; - - i = 0; - for (attr = attribute_names[i]; attr; attr = attribute_names[++i]) - { - if (g_str_has_prefix (attr, "xmlns")) - { - gchar *namespace_name, *namespace_uri; - gchar *p; - - p = g_utf8_strchr (attr, -1, ':'); - if (p) - p = g_utf8_next_char (p); - else - p = "default"; - - namespace_name = g_strdup (p); - namespace_uri = g_strdup (attribute_values[i]); - - g_hash_table_replace (parse_data->namespaces, - namespace_name, - namespace_uri); - } - } -} - -/* checks whether @element_full is equal to @element. - * - * if @namespace is set, it tries to resolve the namespace to a known URI, - * and if found is prepended to the element name, from which is separated - * using the character specified in the @sep parameter. - */ -static gboolean -is_element_full (ParseData *parse_data, - const gchar *element_full, - const gchar *namespace, - const gchar *element, - const gchar sep) -{ - gchar *ns_uri, *ns_name; - const gchar *p, *element_name; - gboolean retval; - - g_warn_if_fail (parse_data != NULL); - g_warn_if_fail (element_full != NULL); - - if (!element) - return FALSE; - - /* no namespace requested: dumb element compare */ - if (!namespace) - return (0 == strcmp (element_full, element)); - - /* search for namespace separator; if none found, assume we are under the - * default namespace, and set ns_name to our "default" marker; if no default - * namespace has been set, just do a plain comparison between @full_element - * and @element. - */ - p = g_utf8_strchr (element_full, -1, ':'); - if (p) - { - ns_name = g_strndup (element_full, p - element_full); - element_name = g_utf8_next_char (p); - } - else - { - ns_name = g_strdup ("default"); - element_name = element_full; - } - - ns_uri = g_hash_table_lookup (parse_data->namespaces, ns_name); - if (!ns_uri) - { - /* no default namespace found */ - g_free (ns_name); - - return (0 == strcmp (element_full, element)); - } - - retval = (0 == strcmp (ns_uri, namespace) && - 0 == strcmp (element_name, element)); - - g_free (ns_name); - - return retval; -} - -#define IS_ELEMENT(p,s,e) (is_element_full ((p), (s), NULL, (e), '\0')) -#define IS_ELEMENT_NS(p,s,n,e) (is_element_full ((p), (s), (n), (e), '|')) - -static void -start_element_raw_cb (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - gpointer user_data, - GError **error) -{ - ParseData *parse_data = (ParseData *) user_data; - - /* we must check for namespace declarations first - * - * XXX - we could speed up things by checking for namespace declarations - * only on the root node, where they usually are; this would probably break - * on streams not produced by us or by "smart" generators - */ - map_namespace_to_name (parse_data, attribute_names, attribute_values); - - switch (parse_data->state) - { - case STATE_STARTED: - if (IS_ELEMENT (parse_data, element_name, XBEL_ROOT_ELEMENT)) - { - const gchar *attr; - gint i; - - i = 0; - for (attr = attribute_names[i]; attr; attr = attribute_names[++i]) - { - if ((IS_ATTRIBUTE (attr, XBEL_VERSION_ATTRIBUTE)) && - (0 == strcmp (attribute_values[i], XBEL_VERSION))) - parse_data->state = STATE_ROOT; - } - } - else - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("Unexpected tag '%s', tag '%s' expected"), - element_name, XBEL_ROOT_ELEMENT); - break; - case STATE_ROOT: - if (IS_ELEMENT (parse_data, element_name, XBEL_TITLE_ELEMENT)) - parse_data->state = STATE_TITLE; - else if (IS_ELEMENT (parse_data, element_name, XBEL_DESC_ELEMENT)) - parse_data->state = STATE_DESC; - else if (IS_ELEMENT (parse_data, element_name, XBEL_BOOKMARK_ELEMENT)) - { - GError *inner_error = NULL; - - parse_data->state = STATE_BOOKMARK; - - parse_bookmark_element (context, - parse_data, - attribute_names, - attribute_values, - &inner_error); - if (inner_error) - g_propagate_error (error, inner_error); - } - else - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("Unexpected tag '%s' inside '%s'"), - element_name, - XBEL_ROOT_ELEMENT); - break; - case STATE_BOOKMARK: - if (IS_ELEMENT (parse_data, element_name, XBEL_TITLE_ELEMENT)) - parse_data->state = STATE_TITLE; - else if (IS_ELEMENT (parse_data, element_name, XBEL_DESC_ELEMENT)) - parse_data->state = STATE_DESC; - else if (IS_ELEMENT (parse_data, element_name, XBEL_INFO_ELEMENT)) - parse_data->state = STATE_INFO; - else - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("Unexpected tag '%s' inside '%s'"), - element_name, - XBEL_BOOKMARK_ELEMENT); - break; - case STATE_INFO: - if (IS_ELEMENT (parse_data, element_name, XBEL_METADATA_ELEMENT)) - { - const gchar *attr; - gint i; - - i = 0; - for (attr = attribute_names[i]; attr; attr = attribute_names[++i]) - { - if ((IS_ATTRIBUTE (attr, XBEL_OWNER_ATTRIBUTE)) && - (0 == strcmp (attribute_values[i], BOOKMARK_METADATA_OWNER))) - { - parse_data->state = STATE_METADATA; - - if (!parse_data->current_item->metadata) - parse_data->current_item->metadata = bookmark_metadata_new (); - } - } - } - else - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("Unexpected tag '%s', tag '%s' expected"), - element_name, - XBEL_METADATA_ELEMENT); - break; - case STATE_METADATA: - if (IS_ELEMENT_NS (parse_data, element_name, BOOKMARK_NAMESPACE_URI, BOOKMARK_APPLICATIONS_ELEMENT)) - parse_data->state = STATE_APPLICATIONS; - else if (IS_ELEMENT_NS (parse_data, element_name, BOOKMARK_NAMESPACE_URI, BOOKMARK_GROUPS_ELEMENT)) - parse_data->state = STATE_GROUPS; - else if (IS_ELEMENT_NS (parse_data, element_name, BOOKMARK_NAMESPACE_URI, BOOKMARK_PRIVATE_ELEMENT)) - parse_data->current_item->metadata->is_private = TRUE; - else if (IS_ELEMENT_NS (parse_data, element_name, BOOKMARK_NAMESPACE_URI, BOOKMARK_ICON_ELEMENT)) - { - GError *inner_error = NULL; - - parse_data->state = STATE_ICON; - - parse_icon_element (context, - parse_data, - attribute_names, - attribute_values, - &inner_error); - if (inner_error) - g_propagate_error (error, inner_error); - } - else if (IS_ELEMENT_NS (parse_data, element_name, MIME_NAMESPACE_URI, MIME_TYPE_ELEMENT)) - { - GError *inner_error = NULL; - - parse_data->state = STATE_MIME; - - parse_mime_type_element (context, - parse_data, - attribute_names, - attribute_values, - &inner_error); - if (inner_error) - g_propagate_error (error, inner_error); - } - else - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_UNKNOWN_ELEMENT, - _("Unexpected tag '%s' inside '%s'"), - element_name, - XBEL_METADATA_ELEMENT); - break; - case STATE_APPLICATIONS: - if (IS_ELEMENT_NS (parse_data, element_name, BOOKMARK_NAMESPACE_URI, BOOKMARK_APPLICATION_ELEMENT)) - { - GError *inner_error = NULL; - - parse_data->state = STATE_APPLICATION; - - parse_application_element (context, - parse_data, - attribute_names, - attribute_values, - &inner_error); - if (inner_error) - g_propagate_error (error, inner_error); - } - else - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("Unexpected tag '%s', tag '%s' expected"), - element_name, - BOOKMARK_APPLICATION_ELEMENT); - break; - case STATE_GROUPS: - if (IS_ELEMENT_NS (parse_data, element_name, BOOKMARK_NAMESPACE_URI, BOOKMARK_GROUP_ELEMENT)) - parse_data->state = STATE_GROUP; - else - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("Unexpected tag '%s', tag '%s' expected"), - element_name, - BOOKMARK_GROUP_ELEMENT); - break; - case STATE_ICON: - if (IS_ELEMENT_NS (parse_data, element_name, BOOKMARK_NAMESPACE_URI, BOOKMARK_ICON_ELEMENT)) - { - GError *inner_error = NULL; - - parse_icon_element (context, - parse_data, - attribute_names, - attribute_values, - &inner_error); - if (inner_error) - g_propagate_error (error, inner_error); - } - else - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_UNKNOWN_ELEMENT, - _("Unexpected tag '%s' inside '%s'"), - element_name, - XBEL_METADATA_ELEMENT); - break; - default: - g_warn_if_reached (); - break; - } -} - -static void -end_element_raw_cb (GMarkupParseContext *context, - const gchar *element_name, - gpointer user_data, - GError **error) -{ - ParseData *parse_data = (ParseData *) user_data; - - if (IS_ELEMENT (parse_data, element_name, XBEL_ROOT_ELEMENT)) - parse_data->state = STATE_FINISHED; - else if (IS_ELEMENT (parse_data, element_name, XBEL_BOOKMARK_ELEMENT)) - { - parse_data->current_item = NULL; - - parse_data->state = STATE_ROOT; - } - else if ((IS_ELEMENT (parse_data, element_name, XBEL_INFO_ELEMENT)) || - (IS_ELEMENT (parse_data, element_name, XBEL_TITLE_ELEMENT)) || - (IS_ELEMENT (parse_data, element_name, XBEL_DESC_ELEMENT))) - { - if (parse_data->current_item) - parse_data->state = STATE_BOOKMARK; - else - parse_data->state = STATE_ROOT; - } - else if (IS_ELEMENT (parse_data, element_name, XBEL_METADATA_ELEMENT)) - parse_data->state = STATE_INFO; - else if (IS_ELEMENT_NS (parse_data, element_name, - BOOKMARK_NAMESPACE_URI, - BOOKMARK_APPLICATION_ELEMENT)) - parse_data->state = STATE_APPLICATIONS; - else if (IS_ELEMENT_NS (parse_data, element_name, - BOOKMARK_NAMESPACE_URI, - BOOKMARK_GROUP_ELEMENT)) - parse_data->state = STATE_GROUPS; - else if ((IS_ELEMENT_NS (parse_data, element_name, BOOKMARK_NAMESPACE_URI, BOOKMARK_APPLICATIONS_ELEMENT)) || - (IS_ELEMENT_NS (parse_data, element_name, BOOKMARK_NAMESPACE_URI, BOOKMARK_GROUPS_ELEMENT)) || - (IS_ELEMENT_NS (parse_data, element_name, BOOKMARK_NAMESPACE_URI, BOOKMARK_PRIVATE_ELEMENT)) || - (IS_ELEMENT_NS (parse_data, element_name, BOOKMARK_NAMESPACE_URI, BOOKMARK_ICON_ELEMENT)) || - (IS_ELEMENT_NS (parse_data, element_name, MIME_NAMESPACE_URI, MIME_TYPE_ELEMENT))) - parse_data->state = STATE_METADATA; -} - -static void -text_raw_cb (GMarkupParseContext *context, - const gchar *text, - gsize length, - gpointer user_data, - GError **error) -{ - ParseData *parse_data = (ParseData *) user_data; - gchar *payload; - - payload = g_strndup (text, length); - - switch (parse_data->state) - { - case STATE_TITLE: - if (parse_data->current_item) - { - g_free (parse_data->current_item->title); - parse_data->current_item->title = g_strdup (payload); - } - else - { - g_free (parse_data->bookmark_file->title); - parse_data->bookmark_file->title = g_strdup (payload); - } - break; - case STATE_DESC: - if (parse_data->current_item) - { - g_free (parse_data->current_item->description); - parse_data->current_item->description = g_strdup (payload); - } - else - { - g_free (parse_data->bookmark_file->description); - parse_data->bookmark_file->description = g_strdup (payload); - } - break; - case STATE_GROUP: - { - GList *groups; - - g_warn_if_fail (parse_data->current_item != NULL); - - if (!parse_data->current_item->metadata) - parse_data->current_item->metadata = bookmark_metadata_new (); - - groups = parse_data->current_item->metadata->groups; - parse_data->current_item->metadata->groups = g_list_prepend (groups, g_strdup (payload)); - } - break; - case STATE_ROOT: - case STATE_BOOKMARK: - case STATE_INFO: - case STATE_METADATA: - case STATE_APPLICATIONS: - case STATE_APPLICATION: - case STATE_GROUPS: - case STATE_MIME: - case STATE_ICON: - break; - default: - g_warn_if_reached (); - break; - } - - g_free (payload); -} - -static const GMarkupParser markup_parser = -{ - start_element_raw_cb, /* start_element */ - end_element_raw_cb, /* end_element */ - text_raw_cb, /* text */ - NULL, /* passthrough */ - NULL -}; - -static gboolean -g_bookmark_file_parse (GBookmarkFile *bookmark, - const gchar *buffer, - gsize length, - GError **error) -{ - GMarkupParseContext *context; - ParseData *parse_data; - GError *parse_error, *end_error; - gboolean retval; - - g_warn_if_fail (bookmark != NULL); - - if (!buffer) - return FALSE; - - if (length == (gsize) -1) - length = strlen (buffer); - - parse_data = parse_data_new (); - parse_data->bookmark_file = bookmark; - - context = g_markup_parse_context_new (&markup_parser, - 0, - parse_data, - (GDestroyNotify) parse_data_free); - - parse_error = NULL; - retval = g_markup_parse_context_parse (context, - buffer, - length, - &parse_error); - if (!retval) - { - g_propagate_error (error, parse_error); - - return FALSE; - } - - end_error = NULL; - retval = g_markup_parse_context_end_parse (context, &end_error); - if (!retval) - { - g_propagate_error (error, end_error); - - return FALSE; - } - - g_markup_parse_context_free (context); - - return TRUE; -} - -static gchar * -g_bookmark_file_dump (GBookmarkFile *bookmark, - gsize *length, - GError **error) -{ - GString *retval; - gchar *buffer; - GList *l; - - retval = g_string_sized_new (4096); - - g_string_append (retval, - "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" -#if 0 - /* XXX - do we really need the doctype? */ - "<!DOCTYPE " XBEL_DTD_NICK "\n" - " PUBLIC \"" XBEL_DTD_SYSTEM "\"\n" - " \"" XBEL_DTD_URI "\">\n" -#endif - "<" XBEL_ROOT_ELEMENT " " XBEL_VERSION_ATTRIBUTE "=\"" XBEL_VERSION "\"\n" - " xmlns:" BOOKMARK_NAMESPACE_NAME "=\"" BOOKMARK_NAMESPACE_URI "\"\n" - " xmlns:" MIME_NAMESPACE_NAME "=\"" MIME_NAMESPACE_URI "\"\n>"); - - if (bookmark->title) - { - gchar *escaped_title; - - escaped_title = g_markup_escape_text (bookmark->title, -1); - - buffer = g_strconcat (" " - "<" XBEL_TITLE_ELEMENT ">", - escaped_title, - "</" XBEL_TITLE_ELEMENT ">\n", NULL); - - g_string_append (retval, buffer); - - g_free (buffer); - g_free (escaped_title); - } - - if (bookmark->description) - { - gchar *escaped_desc; - - escaped_desc = g_markup_escape_text (bookmark->description, -1); - - buffer = g_strconcat (" " - "<" XBEL_DESC_ELEMENT ">", - escaped_desc, - "</" XBEL_DESC_ELEMENT ">\n", NULL); - g_string_append (retval, buffer); - - g_free (buffer); - g_free (escaped_desc); - } - - if (!bookmark->items) - goto out; - else - retval = g_string_append (retval, "\n"); - - /* the items are stored in reverse order */ - for (l = g_list_last (bookmark->items); - l != NULL; - l = l->prev) - { - BookmarkItem *item = (BookmarkItem *) l->data; - gchar *item_dump; - - item_dump = bookmark_item_dump (item); - if (!item_dump) - continue; - - retval = g_string_append (retval, item_dump); - - g_free (item_dump); - } - -out: - g_string_append (retval, "</" XBEL_ROOT_ELEMENT ">"); - - if (length) - *length = retval->len; - - return g_string_free (retval, FALSE); -} - -/************** - * Misc * - **************/ - -/* converts a Unix timestamp in a ISO 8601 compliant string; you - * should free the returned string. - */ -static gchar * -timestamp_to_iso8601 (time_t timestamp) -{ - GTimeVal stamp; - - if (timestamp == (time_t) -1) - g_get_current_time (&stamp); - else - { - stamp.tv_sec = timestamp; - stamp.tv_usec = 0; - } - - return g_time_val_to_iso8601 (&stamp); -} - -static time_t -timestamp_from_iso8601 (const gchar *iso_date) -{ - GTimeVal stamp; - - if (!g_time_val_from_iso8601 (iso_date, &stamp)) - return (time_t) -1; - - return (time_t) stamp.tv_sec; -} - - - -GQuark -g_bookmark_file_error_quark (void) -{ - return g_quark_from_static_string ("g-bookmark-file-error-quark"); -} - - - -/******************** - * Public API * - ********************/ - -/** - * g_bookmark_file_new: - * - * Creates a new empty #GBookmarkFile object. - * - * Use g_bookmark_file_load_from_file(), g_bookmark_file_load_from_data() - * or g_bookmark_file_load_from_data_dirs() to read an existing bookmark - * file. - * - * Return value: an empty #GBookmarkFile - * - * Since: 2.12 - */ -GBookmarkFile * -g_bookmark_file_new (void) -{ - GBookmarkFile *bookmark; - - bookmark = g_new (GBookmarkFile, 1); - - g_bookmark_file_init (bookmark); - - return bookmark; -} - -/** - * g_bookmark_file_free: - * @bookmark: a #GBookmarkFile - * - * Frees a #GBookmarkFile. - * - * Since: 2.12 - */ -void -g_bookmark_file_free (GBookmarkFile *bookmark) -{ - if (!bookmark) - return; - - g_bookmark_file_clear (bookmark); - - g_free (bookmark); -} - -/** - * g_bookmark_file_load_from_data: - * @bookmark: an empty #GBookmarkFile struct - * @data: desktop bookmarks loaded in memory - * @length: the length of @data in bytes - * @error: return location for a #GError, or %NULL - * - * Loads a bookmark file from memory into an empty #GBookmarkFile - * structure. If the object cannot be created then @error is set to a - * #GBookmarkFileError. - * - * Return value: %TRUE if a desktop bookmark could be loaded. - * - * Since: 2.12 - */ -gboolean -g_bookmark_file_load_from_data (GBookmarkFile *bookmark, - const gchar *data, - gsize length, - GError **error) -{ - GError *parse_error; - gboolean retval; - - g_return_val_if_fail (bookmark != NULL, FALSE); - g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (length != 0, FALSE); - - if (length == (gsize) -1) - length = strlen (data); - - if (bookmark->items) - { - g_bookmark_file_clear (bookmark); - g_bookmark_file_init (bookmark); - } - - parse_error = NULL; - retval = g_bookmark_file_parse (bookmark, data, length, &parse_error); - if (!retval) - { - g_propagate_error (error, parse_error); - - return FALSE; - } - - return TRUE; -} - -/** - * g_bookmark_file_load_from_file: - * @bookmark: an empty #GBookmarkFile struct - * @filename: the path of a filename to load, in the GLib file name encoding - * @error: return location for a #GError, or %NULL - * - * Loads a desktop bookmark file into an empty #GBookmarkFile structure. - * If the file could not be loaded then @error is set to either a #GFileError - * or #GBookmarkFileError. - * - * Return value: %TRUE if a desktop bookmark file could be loaded - * - * Since: 2.12 - */ -gboolean -g_bookmark_file_load_from_file (GBookmarkFile *bookmark, - const gchar *filename, - GError **error) -{ - gchar *buffer; - gsize len; - GError *read_error; - gboolean retval; - - g_return_val_if_fail (bookmark != NULL, FALSE); - g_return_val_if_fail (filename != NULL, FALSE); - - read_error = NULL; - g_file_get_contents (filename, &buffer, &len, &read_error); - if (read_error) - { - g_propagate_error (error, read_error); - - return FALSE; - } - - read_error = NULL; - retval = g_bookmark_file_load_from_data (bookmark, - buffer, - len, - &read_error); - if (read_error) - { - g_propagate_error (error, read_error); - - g_free (buffer); - - return FALSE; - } - - g_free (buffer); - - return retval; -} - - -/* Iterates through all the directories in *dirs trying to - * find file. When it successfully locates file, returns a - * string its absolute path. It also leaves the unchecked - * directories in *dirs. You should free the returned string - * - * Adapted from gkeyfile.c - */ -static gchar * -find_file_in_data_dirs (const gchar *file, - gchar ***dirs, - GError **error) -{ - gchar **data_dirs, *data_dir, *path; - - path = NULL; - - if (dirs == NULL) - return NULL; - - data_dirs = *dirs; - path = NULL; - while (data_dirs && (data_dir = *data_dirs) && !path) - { - gchar *candidate_file, *sub_dir; - - candidate_file = (gchar *) file; - sub_dir = g_strdup (""); - while (candidate_file != NULL && !path) - { - gchar *p; - - path = g_build_filename (data_dir, sub_dir, - candidate_file, NULL); - - candidate_file = strchr (candidate_file, '-'); - - if (candidate_file == NULL) - break; - - candidate_file++; - - g_free (sub_dir); - sub_dir = g_strndup (file, candidate_file - file - 1); - - for (p = sub_dir; *p != '\0'; p++) - { - if (*p == '-') - *p = G_DIR_SEPARATOR; - } - } - g_free (sub_dir); - data_dirs++; - } - - *dirs = data_dirs; - - if (!path) - { - g_set_error_literal (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_FILE_NOT_FOUND, - _("No valid bookmark file found in data dirs")); - - return NULL; - } - - return path; -} - - -/** - * g_bookmark_file_load_from_data_dirs: - * @bookmark: a #GBookmarkFile - * @file: a relative path to a filename to open and parse - * @full_path: return location for a string containing the full path - * of the file, or %NULL - * @error: return location for a #GError, or %NULL - * - * This function looks for a desktop bookmark file named @file in the - * paths returned from g_get_user_data_dir() and g_get_system_data_dirs(), - * loads the file into @bookmark and returns the file's full path in - * @full_path. If the file could not be loaded then an %error is - * set to either a #GFileError or #GBookmarkFileError. - * - * Return value: %TRUE if a key file could be loaded, %FALSE othewise - * - * Since: 2.12 - */ -gboolean -g_bookmark_file_load_from_data_dirs (GBookmarkFile *bookmark, - const gchar *file, - gchar **full_path, - GError **error) -{ - GError *file_error = NULL; - gchar **all_data_dirs, **data_dirs; - const gchar *user_data_dir; - const gchar * const * system_data_dirs; - gsize i, j; - gchar *output_path; - gboolean found_file; - - g_return_val_if_fail (bookmark != NULL, FALSE); - g_return_val_if_fail (!g_path_is_absolute (file), FALSE); - - user_data_dir = g_get_user_data_dir (); - system_data_dirs = g_get_system_data_dirs (); - all_data_dirs = g_new0 (gchar *, g_strv_length ((gchar **)system_data_dirs) + 2); - - i = 0; - all_data_dirs[i++] = g_strdup (user_data_dir); - - j = 0; - while (system_data_dirs[j] != NULL) - all_data_dirs[i++] = g_strdup (system_data_dirs[j++]); - - found_file = FALSE; - data_dirs = all_data_dirs; - output_path = NULL; - while (*data_dirs != NULL && !found_file) - { - g_free (output_path); - - output_path = find_file_in_data_dirs (file, &data_dirs, &file_error); - - if (file_error) - { - g_propagate_error (error, file_error); - break; - } - - found_file = g_bookmark_file_load_from_file (bookmark, - output_path, - &file_error); - if (file_error) - { - g_propagate_error (error, file_error); - break; - } - } - - if (found_file && full_path) - *full_path = output_path; - else - g_free (output_path); - - g_strfreev (all_data_dirs); - - return found_file; -} - - -/** - * g_bookmark_file_to_data: - * @bookmark: a #GBookmarkFile - * @length: return location for the length of the returned string, or %NULL - * @error: return location for a #GError, or %NULL - * - * This function outputs @bookmark as a string. - * - * Return value: a newly allocated string holding - * the contents of the #GBookmarkFile - * - * Since: 2.12 - */ -gchar * -g_bookmark_file_to_data (GBookmarkFile *bookmark, - gsize *length, - GError **error) -{ - GError *write_error = NULL; - gchar *retval; - - g_return_val_if_fail (bookmark != NULL, NULL); - - retval = g_bookmark_file_dump (bookmark, length, &write_error); - if (write_error) - { - g_propagate_error (error, write_error); - - return NULL; - } - - return retval; -} - -/** - * g_bookmark_file_to_file: - * @bookmark: a #GBookmarkFile - * @filename: path of the output file - * @error: return location for a #GError, or %NULL - * - * This function outputs @bookmark into a file. The write process is - * guaranteed to be atomic by using g_file_set_contents() internally. - * - * Return value: %TRUE if the file was successfully written. - * - * Since: 2.12 - */ -gboolean -g_bookmark_file_to_file (GBookmarkFile *bookmark, - const gchar *filename, - GError **error) -{ - gchar *data; - GError *data_error, *write_error; - gsize len; - gboolean retval; - - g_return_val_if_fail (bookmark != NULL, FALSE); - g_return_val_if_fail (filename != NULL, FALSE); - - data_error = NULL; - data = g_bookmark_file_to_data (bookmark, &len, &data_error); - if (data_error) - { - g_propagate_error (error, data_error); - - return FALSE; - } - - write_error = NULL; - g_file_set_contents (filename, data, len, &write_error); - if (write_error) - { - g_propagate_error (error, write_error); - - retval = FALSE; - } - else - retval = TRUE; - - g_free (data); - - return retval; -} - -static BookmarkItem * -g_bookmark_file_lookup_item (GBookmarkFile *bookmark, - const gchar *uri) -{ - g_warn_if_fail (bookmark != NULL && uri != NULL); - - return g_hash_table_lookup (bookmark->items_by_uri, uri); -} - -/* this function adds a new item to the list */ -static void -g_bookmark_file_add_item (GBookmarkFile *bookmark, - BookmarkItem *item, - GError **error) -{ - g_warn_if_fail (bookmark != NULL); - g_warn_if_fail (item != NULL); - - /* this should never happen; and if it does, then we are - * screwing up something big time. - */ - if (G_UNLIKELY (g_bookmark_file_has_item (bookmark, item->uri))) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_INVALID_URI, - _("A bookmark for URI '%s' already exists"), - item->uri); - return; - } - - bookmark->items = g_list_prepend (bookmark->items, item); - - g_hash_table_replace (bookmark->items_by_uri, - item->uri, - item); - - if (item->added == (time_t) -1) - item->added = time (NULL); - - if (item->modified == (time_t) -1) - item->modified = time (NULL); -} - -/** - * g_bookmark_file_remove_item: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @error: return location for a #GError, or %NULL - * - * Removes the bookmark for @uri from the bookmark file @bookmark. - * - * Return value: %TRUE if the bookmark was removed successfully. - * - * Since: 2.12 - */ -gboolean -g_bookmark_file_remove_item (GBookmarkFile *bookmark, - const gchar *uri, - GError **error) -{ - BookmarkItem *item; - - g_return_val_if_fail (bookmark != NULL, FALSE); - g_return_val_if_fail (uri != NULL, FALSE); - - item = g_bookmark_file_lookup_item (bookmark, uri); - - if (!item) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - uri); - return FALSE; - } - - bookmark->items = g_list_remove (bookmark->items, item); - g_hash_table_remove (bookmark->items_by_uri, item->uri); - - bookmark_item_free (item); - - return TRUE; -} - -/** - * g_bookmark_file_has_item: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * - * Looks whether the desktop bookmark has an item with its URI set to @uri. - * - * Return value: %TRUE if @uri is inside @bookmark, %FALSE otherwise - * - * Since: 2.12 - */ -gboolean -g_bookmark_file_has_item (GBookmarkFile *bookmark, - const gchar *uri) -{ - g_return_val_if_fail (bookmark != NULL, FALSE); - g_return_val_if_fail (uri != NULL, FALSE); - - return (NULL != g_hash_table_lookup (bookmark->items_by_uri, uri)); -} - -/** - * g_bookmark_file_get_uris: - * @bookmark: a #GBookmarkFile - * @length: return location for the number of returned URIs, or %NULL - * - * Returns all URIs of the bookmarks in the bookmark file @bookmark. - * The array of returned URIs will be %NULL-terminated, so @length may - * optionally be %NULL. - * - * Return value: a newly allocated %NULL-terminated array of strings. - * Use g_strfreev() to free it. - * - * Since: 2.12 - */ -gchar ** -g_bookmark_file_get_uris (GBookmarkFile *bookmark, - gsize *length) -{ - GList *l; - gchar **uris; - gsize i, n_items; - - g_return_val_if_fail (bookmark != NULL, NULL); - - n_items = g_list_length (bookmark->items); - uris = g_new0 (gchar *, n_items + 1); - - /* the items are stored in reverse order, so we walk the list backward */ - for (l = g_list_last (bookmark->items), i = 0; l != NULL; l = l->prev) - { - BookmarkItem *item = (BookmarkItem *) l->data; - - g_warn_if_fail (item != NULL); - - uris[i++] = g_strdup (item->uri); - } - uris[i] = NULL; - - if (length) - *length = i; - - return uris; -} - -/** - * g_bookmark_file_set_title: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI or %NULL - * @title: a UTF-8 encoded string - * - * Sets @title as the title of the bookmark for @uri inside the - * bookmark file @bookmark. - * - * If @uri is %NULL, the title of @bookmark is set. - * - * If a bookmark for @uri cannot be found then it is created. - * - * Since: 2.12 - */ -void -g_bookmark_file_set_title (GBookmarkFile *bookmark, - const gchar *uri, - const gchar *title) -{ - g_return_if_fail (bookmark != NULL); - - if (!uri) - { - g_free (bookmark->title); - bookmark->title = g_strdup (title); - } - else - { - BookmarkItem *item; - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - item = bookmark_item_new (uri); - g_bookmark_file_add_item (bookmark, item, NULL); - } - - g_free (item->title); - item->title = g_strdup (title); - - item->modified = time (NULL); - } -} - -/** - * g_bookmark_file_get_title: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI or %NULL - * @error: return location for a #GError, or %NULL - * - * Returns the title of the bookmark for @uri. - * - * If @uri is %NULL, the title of @bookmark is returned. - * - * In the event the URI cannot be found, %NULL is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND. - * - * Return value: a newly allocated string or %NULL if the specified - * URI cannot be found. - * - * Since: 2.12 - */ -gchar * -g_bookmark_file_get_title (GBookmarkFile *bookmark, - const gchar *uri, - GError **error) -{ - BookmarkItem *item; - - g_return_val_if_fail (bookmark != NULL, NULL); - - if (!uri) - return g_strdup (bookmark->title); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - uri); - return NULL; - } - - return g_strdup (item->title); -} - -/** - * g_bookmark_file_set_description: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI or %NULL - * @description: a string - * - * Sets @description as the description of the bookmark for @uri. - * - * If @uri is %NULL, the description of @bookmark is set. - * - * If a bookmark for @uri cannot be found then it is created. - * - * Since: 2.12 - */ -void -g_bookmark_file_set_description (GBookmarkFile *bookmark, - const gchar *uri, - const gchar *description) -{ - g_return_if_fail (bookmark != NULL); - - if (!uri) - { - g_free (bookmark->description); - bookmark->description = g_strdup (description); - } - else - { - BookmarkItem *item; - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - item = bookmark_item_new (uri); - g_bookmark_file_add_item (bookmark, item, NULL); - } - - g_free (item->description); - item->description = g_strdup (description); - - item->modified = time (NULL); - } -} - -/** - * g_bookmark_file_get_description: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @error: return location for a #GError, or %NULL - * - * Retrieves the description of the bookmark for @uri. - * - * In the event the URI cannot be found, %NULL is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND. - * - * Return value: a newly allocated string or %NULL if the specified - * URI cannot be found. - * - * Since: 2.12 - */ -gchar * -g_bookmark_file_get_description (GBookmarkFile *bookmark, - const gchar *uri, - GError **error) -{ - BookmarkItem *item; - - g_return_val_if_fail (bookmark != NULL, NULL); - - if (!uri) - return g_strdup (bookmark->description); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - uri); - return NULL; - } - - return g_strdup (item->description); -} - -/** - * g_bookmark_file_set_mime_type: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @mime_type: a MIME type - * - * Sets @mime_type as the MIME type of the bookmark for @uri. - * - * If a bookmark for @uri cannot be found then it is created. - * - * Since: 2.12 - */ -void -g_bookmark_file_set_mime_type (GBookmarkFile *bookmark, - const gchar *uri, - const gchar *mime_type) -{ - BookmarkItem *item; - - g_return_if_fail (bookmark != NULL); - g_return_if_fail (uri != NULL); - g_return_if_fail (mime_type != NULL); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - item = bookmark_item_new (uri); - g_bookmark_file_add_item (bookmark, item, NULL); - } - - if (!item->metadata) - item->metadata = bookmark_metadata_new (); - - g_free (item->metadata->mime_type); - - item->metadata->mime_type = g_strdup (mime_type); - item->modified = time (NULL); -} - -/** - * g_bookmark_file_get_mime_type: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @error: return location for a #GError, or %NULL - * - * Retrieves the MIME type of the resource pointed by @uri. - * - * In the event the URI cannot be found, %NULL is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND. In the - * event that the MIME type cannot be found, %NULL is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_INVALID_VALUE. - * - * Return value: a newly allocated string or %NULL if the specified - * URI cannot be found. - * - * Since: 2.12 - */ -gchar * -g_bookmark_file_get_mime_type (GBookmarkFile *bookmark, - const gchar *uri, - GError **error) -{ - BookmarkItem *item; - - g_return_val_if_fail (bookmark != NULL, NULL); - g_return_val_if_fail (uri != NULL, NULL); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - uri); - return NULL; - } - - if (!item->metadata) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_INVALID_VALUE, - _("No MIME type defined in the bookmark for URI '%s'"), - uri); - return NULL; - } - - return g_strdup (item->metadata->mime_type); -} - -/** - * g_bookmark_file_set_is_private: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @is_private: %TRUE if the bookmark should be marked as private - * - * Sets the private flag of the bookmark for @uri. - * - * If a bookmark for @uri cannot be found then it is created. - * - * Since: 2.12 - */ -void -g_bookmark_file_set_is_private (GBookmarkFile *bookmark, - const gchar *uri, - gboolean is_private) -{ - BookmarkItem *item; - - g_return_if_fail (bookmark != NULL); - g_return_if_fail (uri != NULL); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - item = bookmark_item_new (uri); - g_bookmark_file_add_item (bookmark, item, NULL); - } - - if (!item->metadata) - item->metadata = bookmark_metadata_new (); - - item->metadata->is_private = (is_private == TRUE); - item->modified = time (NULL); -} - -/** - * g_bookmark_file_get_is_private: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @error: return location for a #GError, or %NULL - * - * Gets whether the private flag of the bookmark for @uri is set. - * - * In the event the URI cannot be found, %FALSE is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND. In the - * event that the private flag cannot be found, %FALSE is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_INVALID_VALUE. - * - * Return value: %TRUE if the private flag is set, %FALSE otherwise. - * - * Since: 2.12 - */ -gboolean -g_bookmark_file_get_is_private (GBookmarkFile *bookmark, - const gchar *uri, - GError **error) -{ - BookmarkItem *item; - - g_return_val_if_fail (bookmark != NULL, FALSE); - g_return_val_if_fail (uri != NULL, FALSE); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - uri); - return FALSE; - } - - if (!item->metadata) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_INVALID_VALUE, - _("No private flag has been defined in bookmark for URI '%s'"), - uri); - return FALSE; - } - - return item->metadata->is_private; -} - -/** - * g_bookmark_file_set_added: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @added: a timestamp or -1 to use the current time - * - * Sets the time the bookmark for @uri was added into @bookmark. - * - * If no bookmark for @uri is found then it is created. - * - * Since: 2.12 - */ -void -g_bookmark_file_set_added (GBookmarkFile *bookmark, - const gchar *uri, - time_t added) -{ - BookmarkItem *item; - - g_return_if_fail (bookmark != NULL); - g_return_if_fail (uri != NULL); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - item = bookmark_item_new (uri); - g_bookmark_file_add_item (bookmark, item, NULL); - } - - if (added == (time_t) -1) - time (&added); - - item->added = added; - item->modified = added; -} - -/** - * g_bookmark_file_get_added: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @error: return location for a #GError, or %NULL - * - * Gets the time the bookmark for @uri was added to @bookmark - * - * In the event the URI cannot be found, -1 is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND. - * - * Return value: a timestamp - * - * Since: 2.12 - */ -time_t -g_bookmark_file_get_added (GBookmarkFile *bookmark, - const gchar *uri, - GError **error) -{ - BookmarkItem *item; - - g_return_val_if_fail (bookmark != NULL, (time_t) -1); - g_return_val_if_fail (uri != NULL, (time_t) -1); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - uri); - return (time_t) -1; - } - - return item->added; -} - -/** - * g_bookmark_file_set_modified: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @modified: a timestamp or -1 to use the current time - * - * Sets the last time the bookmark for @uri was last modified. - * - * If no bookmark for @uri is found then it is created. - * - * The "modified" time should only be set when the bookmark's meta-data - * was actually changed. Every function of #GBookmarkFile that - * modifies a bookmark also changes the modification time, except for - * g_bookmark_file_set_visited(). - * - * Since: 2.12 - */ -void -g_bookmark_file_set_modified (GBookmarkFile *bookmark, - const gchar *uri, - time_t modified) -{ - BookmarkItem *item; - - g_return_if_fail (bookmark != NULL); - g_return_if_fail (uri != NULL); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - item = bookmark_item_new (uri); - g_bookmark_file_add_item (bookmark, item, NULL); - } - - if (modified == (time_t) -1) - time (&modified); - - item->modified = modified; -} - -/** - * g_bookmark_file_get_modified: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @error: return location for a #GError, or %NULL - * - * Gets the time when the bookmark for @uri was last modified. - * - * In the event the URI cannot be found, -1 is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND. - * - * Return value: a timestamp - * - * Since: 2.12 - */ -time_t -g_bookmark_file_get_modified (GBookmarkFile *bookmark, - const gchar *uri, - GError **error) -{ - BookmarkItem *item; - - g_return_val_if_fail (bookmark != NULL, (time_t) -1); - g_return_val_if_fail (uri != NULL, (time_t) -1); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - uri); - return (time_t) -1; - } - - return item->modified; -} - -/** - * g_bookmark_file_set_visited: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @visited: a timestamp or -1 to use the current time - * - * Sets the time the bookmark for @uri was last visited. - * - * If no bookmark for @uri is found then it is created. - * - * The "visited" time should only be set if the bookmark was launched, - * either using the command line retrieved by g_bookmark_file_get_app_info() - * or by the default application for the bookmark's MIME type, retrieved - * using g_bookmark_file_get_mime_type(). Changing the "visited" time - * does not affect the "modified" time. - * - * Since: 2.12 - */ -void -g_bookmark_file_set_visited (GBookmarkFile *bookmark, - const gchar *uri, - time_t visited) -{ - BookmarkItem *item; - - g_return_if_fail (bookmark != NULL); - g_return_if_fail (uri != NULL); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - item = bookmark_item_new (uri); - g_bookmark_file_add_item (bookmark, item, NULL); - } - - if (visited == (time_t) -1) - time (&visited); - - item->visited = visited; -} - -/** - * g_bookmark_file_get_visited: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @error: return location for a #GError, or %NULL - * - * Gets the time the bookmark for @uri was last visited. - * - * In the event the URI cannot be found, -1 is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND. - * - * Return value: a timestamp. - * - * Since: 2.12 - */ -time_t -g_bookmark_file_get_visited (GBookmarkFile *bookmark, - const gchar *uri, - GError **error) -{ - BookmarkItem *item; - - g_return_val_if_fail (bookmark != NULL, (time_t) -1); - g_return_val_if_fail (uri != NULL, (time_t) -1); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - uri); - return (time_t) -1; - } - - return item->visited; -} - -/** - * g_bookmark_file_has_group: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @group: the group name to be searched - * @error: return location for a #GError, or %NULL - * - * Checks whether @group appears in the list of groups to which - * the bookmark for @uri belongs to. - * - * In the event the URI cannot be found, %FALSE is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND. - * - * Return value: %TRUE if @group was found. - * - * Since: 2.12 - */ -gboolean -g_bookmark_file_has_group (GBookmarkFile *bookmark, - const gchar *uri, - const gchar *group, - GError **error) -{ - BookmarkItem *item; - GList *l; - - g_return_val_if_fail (bookmark != NULL, FALSE); - g_return_val_if_fail (uri != NULL, FALSE); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - uri); - return FALSE; - } - - if (!item->metadata) - return FALSE; - - for (l = item->metadata->groups; l != NULL; l = l->next) - { - if (strcmp (l->data, group) == 0) - return TRUE; - } - - return FALSE; - -} - -/** - * g_bookmark_file_add_group: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @group: the group name to be added - * - * Adds @group to the list of groups to which the bookmark for @uri - * belongs to. - * - * If no bookmark for @uri is found then it is created. - * - * Since: 2.12 - */ -void -g_bookmark_file_add_group (GBookmarkFile *bookmark, - const gchar *uri, - const gchar *group) -{ - BookmarkItem *item; - - g_return_if_fail (bookmark != NULL); - g_return_if_fail (uri != NULL); - g_return_if_fail (group != NULL && group[0] != '\0'); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - item = bookmark_item_new (uri); - g_bookmark_file_add_item (bookmark, item, NULL); - } - - if (!item->metadata) - item->metadata = bookmark_metadata_new (); - - if (!g_bookmark_file_has_group (bookmark, uri, group, NULL)) - { - item->metadata->groups = g_list_prepend (item->metadata->groups, - g_strdup (group)); - - item->modified = time (NULL); - } -} - -/** - * g_bookmark_file_remove_group: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @group: the group name to be removed - * @error: return location for a #GError, or %NULL - * - * Removes @group from the list of groups to which the bookmark - * for @uri belongs to. - * - * In the event the URI cannot be found, %FALSE is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND. - * In the event no group was defined, %FALSE is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_INVALID_VALUE. - * - * Return value: %TRUE if @group was successfully removed. - * - * Since: 2.12 - */ -gboolean -g_bookmark_file_remove_group (GBookmarkFile *bookmark, - const gchar *uri, - const gchar *group, - GError **error) -{ - BookmarkItem *item; - GList *l; - - g_return_val_if_fail (bookmark != NULL, FALSE); - g_return_val_if_fail (uri != NULL, FALSE); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - uri); - return FALSE; - } - - if (!item->metadata) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_INVALID_VALUE, - _("No groups set in bookmark for URI '%s'"), - uri); - return FALSE; - } - - for (l = item->metadata->groups; l != NULL; l = l->next) - { - if (strcmp (l->data, group) == 0) - { - item->metadata->groups = g_list_remove_link (item->metadata->groups, l); - g_free (l->data); - g_list_free_1 (l); - - item->modified = time (NULL); - - return TRUE; - } - } - - return FALSE; -} - -/** - * g_bookmark_file_set_groups: - * @bookmark: a #GBookmarkFile - * @uri: an item's URI - * @groups: an array of group names, or %NULL to remove all groups - * @length: number of group name values in @groups - * - * Sets a list of group names for the item with URI @uri. Each previously - * set group name list is removed. - * - * If @uri cannot be found then an item for it is created. - * - * Since: 2.12 - */ -void -g_bookmark_file_set_groups (GBookmarkFile *bookmark, - const gchar *uri, - const gchar **groups, - gsize length) -{ - BookmarkItem *item; - gsize i; - - g_return_if_fail (bookmark != NULL); - g_return_if_fail (uri != NULL); - g_return_if_fail (groups != NULL); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - item = bookmark_item_new (uri); - g_bookmark_file_add_item (bookmark, item, NULL); - } - - if (!item->metadata) - item->metadata = bookmark_metadata_new (); - - if (item->metadata->groups != NULL) - { - g_list_foreach (item->metadata->groups, - (GFunc) g_free, - NULL); - g_list_free (item->metadata->groups); - item->metadata->groups = NULL; - } - - if (groups) - { - for (i = 0; groups[i] != NULL && i < length; i++) - item->metadata->groups = g_list_append (item->metadata->groups, - g_strdup (groups[i])); - } - - item->modified = time (NULL); -} - -/** - * g_bookmark_file_get_groups: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @length: return location for the length of the returned string, or %NULL - * @error: return location for a #GError, or %NULL - * - * Retrieves the list of group names of the bookmark for @uri. - * - * In the event the URI cannot be found, %NULL is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND. - * - * The returned array is %NULL terminated, so @length may optionally - * be %NULL. - * - * Return value: a newly allocated %NULL-terminated array of group names. - * Use g_strfreev() to free it. - * - * Since: 2.12 - */ -gchar ** -g_bookmark_file_get_groups (GBookmarkFile *bookmark, - const gchar *uri, - gsize *length, - GError **error) -{ - BookmarkItem *item; - GList *l; - gsize len, i; - gchar **retval; - - g_return_val_if_fail (bookmark != NULL, NULL); - g_return_val_if_fail (uri != NULL, NULL); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - uri); - return NULL; - } - - if (!item->metadata) - { - if (length) - *length = 0; - - return NULL; - } - - len = g_list_length (item->metadata->groups); - retval = g_new0 (gchar *, len + 1); - for (l = g_list_last (item->metadata->groups), i = 0; - l != NULL; - l = l->prev) - { - gchar *group_name = (gchar *) l->data; - - g_warn_if_fail (group_name != NULL); - - retval[i++] = g_strdup (group_name); - } - retval[i] = NULL; - - if (length) - *length = len; - - return retval; -} - -/** - * g_bookmark_file_add_application: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @name: the name of the application registering the bookmark - * or %NULL - * @exec: command line to be used to launch the bookmark or %NULL - * - * Adds the application with @name and @exec to the list of - * applications that have registered a bookmark for @uri into - * @bookmark. - * - * Every bookmark inside a #GBookmarkFile must have at least an - * application registered. Each application must provide a name, a - * command line useful for launching the bookmark, the number of times - * the bookmark has been registered by the application and the last - * time the application registered this bookmark. - * - * If @name is %NULL, the name of the application will be the - * same returned by g_get_application_name(); if @exec is %NULL, the - * command line will be a composition of the program name as - * returned by g_get_prgname() and the "%u" modifier, which will be - * expanded to the bookmark's URI. - * - * This function will automatically take care of updating the - * registrations count and timestamping in case an application - * with the same @name had already registered a bookmark for - * @uri inside @bookmark. - * - * If no bookmark for @uri is found, one is created. - * - * Since: 2.12 - */ -void -g_bookmark_file_add_application (GBookmarkFile *bookmark, - const gchar *uri, - const gchar *name, - const gchar *exec) -{ - BookmarkItem *item; - gchar *app_name, *app_exec; - - g_return_if_fail (bookmark != NULL); - g_return_if_fail (uri != NULL); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - item = bookmark_item_new (uri); - g_bookmark_file_add_item (bookmark, item, NULL); - } - - if (name && name[0] != '\0') - app_name = g_strdup (name); - else - app_name = g_strdup (g_get_application_name ()); - - if (exec && exec[0] != '\0') - app_exec = g_strdup (exec); - else - app_exec = g_strjoin (" ", g_get_prgname(), "%u", NULL); - - g_bookmark_file_set_app_info (bookmark, uri, - app_name, - app_exec, - -1, - (time_t) -1, - NULL); - - g_free (app_exec); - g_free (app_name); -} - -/** - * g_bookmark_file_remove_application: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @name: the name of the application - * @error: return location for a #GError or %NULL - * - * Removes application registered with @name from the list of applications - * that have registered a bookmark for @uri inside @bookmark. - * - * In the event the URI cannot be found, %FALSE is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND. - * In the event that no application with name @app_name has registered - * a bookmark for @uri, %FALSE is returned and error is set to - * #G_BOOKMARK_FILE_ERROR_APP_NOT_REGISTERED. - * - * Return value: %TRUE if the application was successfully removed. - * - * Since: 2.12 - */ -gboolean -g_bookmark_file_remove_application (GBookmarkFile *bookmark, - const gchar *uri, - const gchar *name, - GError **error) -{ - GError *set_error; - gboolean retval; - - g_return_val_if_fail (bookmark != NULL, FALSE); - g_return_val_if_fail (uri != NULL, FALSE); - g_return_val_if_fail (name != NULL, FALSE); - - set_error = NULL; - retval = g_bookmark_file_set_app_info (bookmark, uri, - name, - "", - 0, - (time_t) -1, - &set_error); - if (set_error) - { - g_propagate_error (error, set_error); - - return FALSE; - } - - return retval; -} - -/** - * g_bookmark_file_has_application: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @name: the name of the application - * @error: return location for a #GError or %NULL - * - * Checks whether the bookmark for @uri inside @bookmark has been - * registered by application @name. - * - * In the event the URI cannot be found, %FALSE is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND. - * - * Return value: %TRUE if the application @name was found - * - * Since: 2.12 - */ -gboolean -g_bookmark_file_has_application (GBookmarkFile *bookmark, - const gchar *uri, - const gchar *name, - GError **error) -{ - BookmarkItem *item; - - g_return_val_if_fail (bookmark != NULL, FALSE); - g_return_val_if_fail (uri != NULL, FALSE); - g_return_val_if_fail (name != NULL, FALSE); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - uri); - return FALSE; - } - - return (NULL != bookmark_item_lookup_app_info (item, name)); -} - -/** - * g_bookmark_file_set_app_info: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @name: an application's name - * @exec: an application's command line - * @count: the number of registrations done for this application - * @stamp: the time of the last registration for this application - * @error: return location for a #GError or %NULL - * - * Sets the meta-data of application @name inside the list of - * applications that have registered a bookmark for @uri inside - * @bookmark. - * - * You should rarely use this function; use g_bookmark_file_add_application() - * and g_bookmark_file_remove_application() instead. - * - * @name can be any UTF-8 encoded string used to identify an - * application. - * @exec can have one of these two modifiers: "%f", which will - * be expanded as the local file name retrieved from the bookmark's - * URI; "%u", which will be expanded as the bookmark's URI. - * The expansion is done automatically when retrieving the stored - * command line using the g_bookmark_file_get_app_info() function. - * @count is the number of times the application has registered the - * bookmark; if is < 0, the current registration count will be increased - * by one, if is 0, the application with @name will be removed from - * the list of registered applications. - * @stamp is the Unix time of the last registration; if it is -1, the - * current time will be used. - * - * If you try to remove an application by setting its registration count to - * zero, and no bookmark for @uri is found, %FALSE is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND; similarly, - * in the event that no application @name has registered a bookmark - * for @uri, %FALSE is returned and error is set to - * #G_BOOKMARK_FILE_ERROR_APP_NOT_REGISTERED. Otherwise, if no bookmark - * for @uri is found, one is created. - * - * Return value: %TRUE if the application's meta-data was successfully - * changed. - * - * Since: 2.12 - */ -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) -{ - BookmarkItem *item; - BookmarkAppInfo *ai; - - g_return_val_if_fail (bookmark != NULL, FALSE); - g_return_val_if_fail (uri != NULL, FALSE); - g_return_val_if_fail (name != NULL, FALSE); - g_return_val_if_fail (exec != NULL, FALSE); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - if (count == 0) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - uri); - return FALSE; - } - else - { - item = bookmark_item_new (uri); - g_bookmark_file_add_item (bookmark, item, NULL); - } - } - - ai = bookmark_item_lookup_app_info (item, name); - if (!ai) - { - if (count == 0) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_APP_NOT_REGISTERED, - _("No application with name '%s' registered a bookmark for '%s'"), - name, - uri); - return FALSE; - } - else - { - ai = bookmark_app_info_new (name); - - item->metadata->applications = g_list_prepend (item->metadata->applications, ai); - g_hash_table_replace (item->metadata->apps_by_name, ai->name, ai); - } - } - - if (count == 0) - { - item->metadata->applications = g_list_remove (item->metadata->applications, ai); - g_hash_table_remove (item->metadata->apps_by_name, ai->name); - bookmark_app_info_free (ai); - - item->modified = time (NULL); - - return TRUE; - } - else if (count > 0) - ai->count = count; - else - ai->count += 1; - - if (stamp != (time_t) -1) - ai->stamp = stamp; - else - ai->stamp = time (NULL); - - if (exec && exec[0] != '\0') - { - g_free (ai->exec); - ai->exec = g_shell_quote (exec); - } - - item->modified = time (NULL); - - return TRUE; -} - -/* expands the application's command line */ -static gchar * -expand_exec_line (const gchar *exec_fmt, - const gchar *uri) -{ - GString *exec; - gchar ch; - - exec = g_string_sized_new (512); - while ((ch = *exec_fmt++) != '\0') - { - if (ch != '%') - { - exec = g_string_append_c (exec, ch); - continue; - } - - ch = *exec_fmt++; - switch (ch) - { - case '\0': - goto out; - case 'U': - case 'u': - g_string_append (exec, uri); - break; - case 'F': - case 'f': - { - gchar *file = g_filename_from_uri (uri, NULL, NULL); - if (file) - { - g_string_append (exec, file); - g_free (file); - } - else - { - g_string_free (exec, TRUE); - return NULL; - } - } - break; - case '%': - default: - exec = g_string_append_c (exec, ch); - break; - } - } - - out: - return g_string_free (exec, FALSE); -} - -/** - * g_bookmark_file_get_app_info: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @name: an application's name - * @exec: location for the command line of the application, or %NULL - * @count: return location for the registration count, or %NULL - * @stamp: return location for the last registration time, or %NULL - * @error: return location for a #GError, or %NULL - * - * Gets the registration informations of @app_name for the bookmark for - * @uri. See g_bookmark_file_set_app_info() for more informations about - * the returned data. - * - * The string returned in @app_exec must be freed. - * - * In the event the URI cannot be found, %FALSE is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND. In the - * event that no application with name @app_name has registered a bookmark - * for @uri, %FALSE is returned and error is set to - * #G_BOOKMARK_FILE_ERROR_APP_NOT_REGISTERED. In the event that unquoting - * the command line fails, an error of the #G_SHELL_ERROR domain is - * set and %FALSE is returned. - * - * Return value: %TRUE on success. - * - * Since: 2.12 - */ -gboolean -g_bookmark_file_get_app_info (GBookmarkFile *bookmark, - const gchar *uri, - const gchar *name, - gchar **exec, - guint *count, - time_t *stamp, - GError **error) -{ - BookmarkItem *item; - BookmarkAppInfo *ai; - - g_return_val_if_fail (bookmark != NULL, FALSE); - g_return_val_if_fail (uri != NULL, FALSE); - g_return_val_if_fail (name != NULL, FALSE); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - uri); - return FALSE; - } - - ai = bookmark_item_lookup_app_info (item, name); - if (!ai) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_APP_NOT_REGISTERED, - _("No application with name '%s' registered a bookmark for '%s'"), - name, - uri); - return FALSE; - } - - if (exec) - { - GError *unquote_error = NULL; - gchar *command_line; - - command_line = g_shell_unquote (ai->exec, &unquote_error); - if (unquote_error) - { - g_propagate_error (error, unquote_error); - return FALSE; - } - - *exec = expand_exec_line (command_line, uri); - if (!*exec) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_INVALID_URI, - _("Failed to expand exec line '%s' with URI '%s'"), - ai->exec, uri); - g_free (command_line); - - return FALSE; - } - else - g_free (command_line); - } - - if (count) - *count = ai->count; - - if (stamp) - *stamp = ai->stamp; - - return TRUE; -} - -/** - * g_bookmark_file_get_applications: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @length: return location of the length of the returned list, or %NULL - * @error: return location for a #GError, or %NULL - * - * Retrieves the names of the applications that have registered the - * bookmark for @uri. - * - * In the event the URI cannot be found, %NULL is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND. - * - * Return value: a newly allocated %NULL-terminated array of strings. - * Use g_strfreev() to free it. - * - * Since: 2.12 - */ -gchar ** -g_bookmark_file_get_applications (GBookmarkFile *bookmark, - const gchar *uri, - gsize *length, - GError **error) -{ - BookmarkItem *item; - GList *l; - gchar **apps; - gsize i, n_apps; - - g_return_val_if_fail (bookmark != NULL, NULL); - g_return_val_if_fail (uri != NULL, NULL); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - uri); - return NULL; - } - - if (!item->metadata) - { - if (length) - *length = 0; - - return NULL; - } - - n_apps = g_list_length (item->metadata->applications); - apps = g_new0 (gchar *, n_apps + 1); - - for (l = g_list_last (item->metadata->applications), i = 0; - l != NULL; - l = l->prev) - { - BookmarkAppInfo *ai; - - ai = (BookmarkAppInfo *) l->data; - - g_warn_if_fail (ai != NULL); - g_warn_if_fail (ai->name != NULL); - - apps[i++] = g_strdup (ai->name); - } - apps[i] = NULL; - - if (length) - *length = i; - - return apps; -} - -/** - * g_bookmark_file_get_size: - * @bookmark: a #GBookmarkFile - * - * Gets the number of bookmarks inside @bookmark. - * - * Return value: the number of bookmarks - * - * Since: 2.12 - */ -gint -g_bookmark_file_get_size (GBookmarkFile *bookmark) -{ - g_return_val_if_fail (bookmark != NULL, 0); - - return g_list_length (bookmark->items); -} - -/** - * g_bookmark_file_move_item: - * @bookmark: a #GBookmarkFile - * @old_uri: a valid URI - * @new_uri: a valid URI, or %NULL - * @error: return location for a #GError or %NULL - * - * Changes the URI of a bookmark item from @old_uri to @new_uri. Any - * existing bookmark for @new_uri will be overwritten. If @new_uri is - * %NULL, then the bookmark is removed. - * - * In the event the URI cannot be found, %FALSE is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND. - * - * Return value: %TRUE if the URI was successfully changed - * - * Since: 2.12 - */ -gboolean -g_bookmark_file_move_item (GBookmarkFile *bookmark, - const gchar *old_uri, - const gchar *new_uri, - GError **error) -{ - BookmarkItem *item; - GError *remove_error; - - g_return_val_if_fail (bookmark != NULL, FALSE); - g_return_val_if_fail (old_uri != NULL, FALSE); - - item = g_bookmark_file_lookup_item (bookmark, old_uri); - if (!item) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - old_uri); - return FALSE; - } - - if (new_uri && new_uri[0] != '\0') - { - if (g_bookmark_file_has_item (bookmark, new_uri)) - { - remove_error = NULL; - g_bookmark_file_remove_item (bookmark, new_uri, &remove_error); - if (remove_error) - { - g_propagate_error (error, remove_error); - - return FALSE; - } - } - - g_hash_table_steal (bookmark->items_by_uri, item->uri); - - g_free (item->uri); - item->uri = g_strdup (new_uri); - item->modified = time (NULL); - - g_hash_table_replace (bookmark->items_by_uri, item->uri, item); - - return TRUE; - } - else - { - remove_error = NULL; - g_bookmark_file_remove_item (bookmark, old_uri, &remove_error); - if (remove_error) - { - g_propagate_error (error, remove_error); - - return FALSE; - } - - return TRUE; - } -} - -/** - * g_bookmark_file_set_icon: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @href: the URI of the icon for the bookmark, or %NULL - * @mime_type: the MIME type of the icon for the bookmark - * - * Sets the icon for the bookmark for @uri. If @href is %NULL, unsets - * the currently set icon. @href can either be a full URL for the icon - * file or the icon name following the Icon Naming specification. - * - * If no bookmark for @uri is found one is created. - * - * Since: 2.12 - */ -void -g_bookmark_file_set_icon (GBookmarkFile *bookmark, - const gchar *uri, - const gchar *href, - const gchar *mime_type) -{ - BookmarkItem *item; - - g_return_if_fail (bookmark != NULL); - g_return_if_fail (uri != NULL); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - item = bookmark_item_new (uri); - g_bookmark_file_add_item (bookmark, item, NULL); - } - - if (!item->metadata) - item->metadata = bookmark_metadata_new (); - - g_free (item->metadata->icon_href); - g_free (item->metadata->icon_mime); - - item->metadata->icon_href = g_strdup (href); - - if (mime_type && mime_type[0] != '\0') - item->metadata->icon_mime = g_strdup (mime_type); - else - item->metadata->icon_mime = g_strdup ("application/octet-stream"); - - item->modified = time (NULL); -} - -/** - * g_bookmark_file_get_icon: - * @bookmark: a #GBookmarkFile - * @uri: a valid URI - * @href: return location for the icon's location or %NULL - * @mime_type: return location for the icon's MIME type or %NULL - * @error: return location for a #GError or %NULL - * - * Gets the icon of the bookmark for @uri. - * - * In the event the URI cannot be found, %FALSE is returned and - * @error is set to #G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND. - * - * Return value: %TRUE if the icon for the bookmark for the URI was found. - * You should free the returned strings. - * - * Since: 2.12 - */ -gboolean -g_bookmark_file_get_icon (GBookmarkFile *bookmark, - const gchar *uri, - gchar **href, - gchar **mime_type, - GError **error) -{ - BookmarkItem *item; - - g_return_val_if_fail (bookmark != NULL, FALSE); - g_return_val_if_fail (uri != NULL, FALSE); - - item = g_bookmark_file_lookup_item (bookmark, uri); - if (!item) - { - g_set_error (error, G_BOOKMARK_FILE_ERROR, - G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, - _("No bookmark found for URI '%s'"), - uri); - return FALSE; - } - - if ((!item->metadata) || (!item->metadata->icon_href)) - return FALSE; - - if (href) - *href = g_strdup (item->metadata->icon_href); - - if (mime_type) - *mime_type = g_strdup (item->metadata->icon_mime); - - return TRUE; -} - -#define __G_BOOKMARK_FILE_C__ -#include "galiasdef.c" diff --git a/glib/gcache.c b/glib/gcache.c deleted file mode 100644 index a5b02974c..000000000 --- a/glib/gcache.c +++ /dev/null @@ -1,197 +0,0 @@ -/* 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, 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" - -#include "glib.h" -#include "galias.h" - - -typedef struct _GCacheNode GCacheNode; - -struct _GCacheNode -{ - /* A reference counted node */ - gpointer value; - gint ref_count; -}; - -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); -} - -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; -} - -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); -} - -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; -} - -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); - } -} - -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); -} - -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); -} - -#define __G_CACHE_C__ -#include "galiasdef.c" diff --git a/glib/gchecksum.c b/glib/gchecksum.c deleted file mode 100644 index 1611193d4..000000000 --- a/glib/gchecksum.c +++ /dev/null @@ -1,1439 +0,0 @@ -/* 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 Library General Public - * License as published by the Free Software Foundation; either - * version 2 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "config.h" - -#include <string.h> - -#include "glibconfig.h" -#include "gchecksum.h" -#include "glib.h" -#include "glibintl.h" - -#include "galias.h" - -#define IS_VALID_TYPE(type) ((type) >= G_CHECKSUM_MD5 && (type) <= G_CHECKSUM_SHA256) - -/* The fact that these are lower case characters is part of the ABI */ -static const gchar hex_digits[] = "0123456789abcdef"; - -#define MD5_DATASIZE 64 -#define MD5_DIGEST_LEN 16 - -typedef struct -{ - guint32 buf[4]; - guint32 bits[2]; - - guchar data[MD5_DATASIZE]; - - guchar digest[MD5_DIGEST_LEN]; -} Md5sum; - -#define SHA1_DATASIZE 64 -#define SHA1_DIGEST_LEN 20 - -typedef struct -{ - guint32 buf[5]; - guint32 bits[2]; - - /* we pack 64 unsigned chars into 16 32-bit unsigned integers */ - guint32 data[16]; - - guchar digest[SHA1_DIGEST_LEN]; -} Sha1sum; - -#define SHA256_DATASIZE 64 -#define SHA256_DIGEST_LEN 32 - -typedef struct -{ - guint32 buf[8]; - guint32 bits[2]; - - guint8 data[SHA256_DATASIZE]; - - guchar digest[SHA256_DIGEST_LEN]; -} Sha256sum; - -struct _GChecksum -{ - GChecksumType type; - - gchar *digest_str; - - union { - Md5sum md5; - Sha1sum sha1; - Sha256sum sha256; - } sum; -}; - -/* we need different byte swapping functions because MD5 expects buffers - * to be little-endian, while SHA1 and SHA256 expect them in big-endian - * form. - */ - -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -#define md5_byte_reverse(buffer,length) -#else -/* assume that the passed buffer is integer aligned */ -static inline void -md5_byte_reverse (guchar *buffer, - gulong length) -{ - guint32 bit; - - do - { - bit = (guint32) ((unsigned) buffer[3] << 8 | buffer[2]) << 16 | - ((unsigned) buffer[1] << 8 | buffer[0]); - * (guint32 *) buffer = bit; - buffer += 4; - } - while (--length); -} -#endif /* G_BYTE_ORDER == G_LITTLE_ENDIAN */ - -#if G_BYTE_ORDER == G_BIG_ENDIAN -#define sha_byte_reverse(buffer,length) -#else -static inline void -sha_byte_reverse (guint32 *buffer, - gint length) -{ - length /= sizeof (guint32); - while (length--) - { - *buffer = GUINT32_SWAP_LE_BE (*buffer); - ++buffer; - } -} -#endif /* G_BYTE_ORDER == G_BIG_ENDIAN */ - -static gchar * -digest_to_string (guint8 *digest, - gsize digest_len) -{ - gint len = digest_len * 2; - gint i; - gchar *retval; - - retval = g_new (gchar, len + 1); - - for (i = 0; i < digest_len; i++) - { - guint8 byte = digest[i]; - - retval[2 * i] = hex_digits[byte >> 4]; - retval[2 * i + 1] = hex_digits[byte & 0xf]; - } - - retval[len] = 0; - - return retval; -} - -/* - * MD5 Checksum - */ - -/* This MD5 digest computation is based on the equivalent code - * written by Colin Plumb. It came with this notice: - * - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - */ - -static void -md5_sum_init (Md5sum *md5) -{ - /* arbitrary constants */ - md5->buf[0] = 0x67452301; - md5->buf[1] = 0xefcdab89; - md5->buf[2] = 0x98badcfe; - md5->buf[3] = 0x10325476; - - md5->bits[0] = md5->bits[1] = 0; -} - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. md5_sum_update() - * blocks the data and converts bytes into longwords for this routine. - */ -static void -md5_transform (guint32 buf[4], - guint32 const in[16]) -{ - register guint32 a, b, c, d; - -/* The four core functions - F1 is optimized somewhat */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1 (z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define md5_step(f, w, x, y, z, data, s) \ - ( w += f (x, y, z) + data, w = w << s | w >> (32 - s), w += x ) - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - md5_step (F1, a, b, c, d, in[0] + 0xd76aa478, 7); - md5_step (F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - md5_step (F1, c, d, a, b, in[2] + 0x242070db, 17); - md5_step (F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - md5_step (F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - md5_step (F1, d, a, b, c, in[5] + 0x4787c62a, 12); - md5_step (F1, c, d, a, b, in[6] + 0xa8304613, 17); - md5_step (F1, b, c, d, a, in[7] + 0xfd469501, 22); - md5_step (F1, a, b, c, d, in[8] + 0x698098d8, 7); - md5_step (F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - md5_step (F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - md5_step (F1, b, c, d, a, in[11] + 0x895cd7be, 22); - md5_step (F1, a, b, c, d, in[12] + 0x6b901122, 7); - md5_step (F1, d, a, b, c, in[13] + 0xfd987193, 12); - md5_step (F1, c, d, a, b, in[14] + 0xa679438e, 17); - md5_step (F1, b, c, d, a, in[15] + 0x49b40821, 22); - - md5_step (F2, a, b, c, d, in[1] + 0xf61e2562, 5); - md5_step (F2, d, a, b, c, in[6] + 0xc040b340, 9); - md5_step (F2, c, d, a, b, in[11] + 0x265e5a51, 14); - md5_step (F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - md5_step (F2, a, b, c, d, in[5] + 0xd62f105d, 5); - md5_step (F2, d, a, b, c, in[10] + 0x02441453, 9); - md5_step (F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - md5_step (F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - md5_step (F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - md5_step (F2, d, a, b, c, in[14] + 0xc33707d6, 9); - md5_step (F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - md5_step (F2, b, c, d, a, in[8] + 0x455a14ed, 20); - md5_step (F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - md5_step (F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - md5_step (F2, c, d, a, b, in[7] + 0x676f02d9, 14); - md5_step (F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - md5_step (F3, a, b, c, d, in[5] + 0xfffa3942, 4); - md5_step (F3, d, a, b, c, in[8] + 0x8771f681, 11); - md5_step (F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - md5_step (F3, b, c, d, a, in[14] + 0xfde5380c, 23); - md5_step (F3, a, b, c, d, in[1] + 0xa4beea44, 4); - md5_step (F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - md5_step (F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - md5_step (F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - md5_step (F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - md5_step (F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - md5_step (F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - md5_step (F3, b, c, d, a, in[6] + 0x04881d05, 23); - md5_step (F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - md5_step (F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - md5_step (F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - md5_step (F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - md5_step (F4, a, b, c, d, in[0] + 0xf4292244, 6); - md5_step (F4, d, a, b, c, in[7] + 0x432aff97, 10); - md5_step (F4, c, d, a, b, in[14] + 0xab9423a7, 15); - md5_step (F4, b, c, d, a, in[5] + 0xfc93a039, 21); - md5_step (F4, a, b, c, d, in[12] + 0x655b59c3, 6); - md5_step (F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - md5_step (F4, c, d, a, b, in[10] + 0xffeff47d, 15); - md5_step (F4, b, c, d, a, in[1] + 0x85845dd1, 21); - md5_step (F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - md5_step (F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - md5_step (F4, c, d, a, b, in[6] + 0xa3014314, 15); - md5_step (F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - md5_step (F4, a, b, c, d, in[4] + 0xf7537e82, 6); - md5_step (F4, d, a, b, c, in[11] + 0xbd3af235, 10); - md5_step (F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - md5_step (F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; - -#undef F1 -#undef F2 -#undef F3 -#undef F4 -#undef md5_step -} - -static void -md5_sum_update (Md5sum *md5, - const guchar *data, - gsize length) -{ - guint32 bit; - - bit = md5->bits[0]; - md5->bits[0] = bit + ((guint32) length << 3); - - /* carry from low to high */ - if (md5->bits[0] < bit) - md5->bits[1] += 1; - - md5->bits[1] += length >> 29; - - /* bytes already in Md5sum->data */ - bit = (bit >> 3) & 0x3f; - - /* handle any leading odd-sized chunks */ - if (bit) - { - guchar *p = (guchar *) md5->data + bit; - - bit = MD5_DATASIZE - bit; - if (length < bit) - { - memcpy (p, data, length); - return; - } - - memcpy (p, data, bit); - - md5_byte_reverse (md5->data, 16); - md5_transform (md5->buf, (guint32 *) md5->data); - - data += bit; - length -= bit; - } - - /* process data in 64-byte chunks */ - while (length >= MD5_DATASIZE) - { - memcpy (md5->data, data, MD5_DATASIZE); - - md5_byte_reverse (md5->data, 16); - md5_transform (md5->buf, (guint32 *) md5->data); - - data += MD5_DATASIZE; - length -= MD5_DATASIZE; - } - - /* handle any remaining bytes of data */ - memcpy (md5->data, data, length); -} - -/* closes a checksum */ -static void -md5_sum_close (Md5sum *md5) -{ - guint count; - guchar *p; - - /* Compute number of bytes mod 64 */ - count = (md5->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. - * This is safe since there is always at least one byte free - */ - p = md5->data + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = MD5_DATASIZE - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) - { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset (p, 0, count); - - md5_byte_reverse (md5->data, 16); - md5_transform (md5->buf, (guint32 *) md5->data); - - /* Now fill the next block with 56 bytes */ - memset (md5->data, 0, MD5_DATASIZE - 8); - } - else - { - /* Pad block to 56 bytes */ - memset (p, 0, count - 8); - } - - md5_byte_reverse (md5->data, 14); - - /* Append length in bits and transform */ - ((guint32 *) md5->data)[14] = md5->bits[0]; - ((guint32 *) md5->data)[15] = md5->bits[1]; - - md5_transform (md5->buf, (guint32 *) md5->data); - md5_byte_reverse ((guchar *) md5->buf, 4); - - memcpy (md5->digest, md5->buf, 16); - - /* Reset buffers in case they contain sensitive data */ - memset (md5->buf, 0, sizeof (md5->buf)); - memset (md5->data, 0, sizeof (md5->data)); -} - -static gchar * -md5_sum_to_string (Md5sum *md5) -{ - return digest_to_string (md5->digest, MD5_DIGEST_LEN); -} - -static void -md5_sum_digest (Md5sum *md5, - guint8 *digest) -{ - gint i; - - for (i = 0; i < MD5_DIGEST_LEN; i++) - digest[i] = md5->digest[i]; -} - -/* - * SHA-1 Checksum - */ - -/* The following implementation comes from D-Bus dbus-sha.c. I've changed - * it to use GLib types and to work more like the MD5 implementation above. - * I left the comments to have an history of this code. - * -- Emmanuele Bassi, ebassi@gnome.org - */ - -/* The following comments have the history of where this code - * comes from. I actually copied it from GNet in GNOME CVS. - * - hp@redhat.com - */ - -/* - * sha.h : Implementation of the Secure Hash Algorithm - * - * Part of the Python Cryptography Toolkit, version 1.0.0 - * - * Copyright (C) 1995, A.M. Kuchling - * - * Distribute and use freely; there are no restrictions on further - * dissemination and usage except those imposed by the laws of your - * country of residence. - * - */ - -/* SHA: NIST's Secure Hash Algorithm */ - -/* Based on SHA code originally posted to sci.crypt by Peter Gutmann - in message <30ajo5$oe8@ccu2.auckland.ac.nz>. - Modified to test for endianness on creation of SHA objects by AMK. - Also, the original specification of SHA was found to have a weakness - by NSA/NIST. This code implements the fixed version of SHA. -*/ - -/* Here's the first paragraph of Peter Gutmann's posting: - -The following is my SHA (FIPS 180) code updated to allow use of the "fixed" -SHA, thanks to Jim Gillogly and an anonymous contributor for the information on -what's changed in the new version. The fix is a simple change which involves -adding a single rotate in the initial expansion function. It is unknown -whether this is an optimal solution to the problem which was discovered in the -SHA or whether it's simply a bandaid which fixes the problem with a minimum of -effort (for example the reengineering of a great many Capstone chips). -*/ - -static void -sha1_sum_init (Sha1sum *sha1) -{ - /* initialize constants */ - sha1->buf[0] = 0x67452301L; - sha1->buf[1] = 0xEFCDAB89L; - sha1->buf[2] = 0x98BADCFEL; - sha1->buf[3] = 0x10325476L; - sha1->buf[4] = 0xC3D2E1F0L; - - /* initialize bits */ - sha1->bits[0] = sha1->bits[1] = 0; -} - -/* The SHA f()-functions. */ - -#define f1(x,y,z) (z ^ (x & (y ^ z))) /* Rounds 0-19 */ -#define f2(x,y,z) (x ^ y ^ z) /* Rounds 20-39 */ -#define f3(x,y,z) (( x & y) | (z & (x | y))) /* Rounds 40-59 */ -#define f4(x,y,z) (x ^ y ^ z) /* Rounds 60-79 */ - -/* The SHA Mysterious Constants */ -#define K1 0x5A827999L /* Rounds 0-19 */ -#define K2 0x6ED9EBA1L /* Rounds 20-39 */ -#define K3 0x8F1BBCDCL /* Rounds 40-59 */ -#define K4 0xCA62C1D6L /* Rounds 60-79 */ - -/* 32-bit rotate left - kludged with shifts */ -#define ROTL(n,X) (((X) << n ) | ((X) >> (32 - n))) - -/* The initial expanding function. The hash function is defined over an - 80-word expanded input array W, where the first 16 are copies of the input - data, and the remaining 64 are defined by - - W[ i ] = W[ i - 16 ] ^ W[ i - 14 ] ^ W[ i - 8 ] ^ W[ i - 3 ] - - This implementation generates these values on the fly in a circular - buffer - thanks to Colin Plumb, colin@nyx10.cs.du.edu for this - optimization. - - The updated SHA changes the expanding function by adding a rotate of 1 - bit. Thanks to Jim Gillogly, jim@rand.org, and an anonymous contributor - for this information */ - -#define expand(W,i) (W[ i & 15 ] = ROTL (1, (W[ i & 15] ^ \ - W[(i - 14) & 15] ^ \ - W[(i - 8) & 15] ^ \ - W[(i - 3) & 15]))) - - -/* The prototype SHA sub-round. The fundamental sub-round is: - - a' = e + ROTL( 5, a ) + f( b, c, d ) + k + data; - b' = a; - c' = ROTL( 30, b ); - d' = c; - e' = d; - - but this is implemented by unrolling the loop 5 times and renaming the - variables ( e, a, b, c, d ) = ( a', b', c', d', e' ) each iteration. - This code is then replicated 20 times for each of the 4 functions, using - the next 20 values from the W[] array each time */ - -#define subRound(a, b, c, d, e, f, k, data) \ - (e += ROTL (5, a) + f(b, c, d) + k + data, b = ROTL (30, b)) - -static void -sha1_transform (guint32 buf[5], - guint32 in[16]) -{ - guint32 A, B, C, D, E; - - A = buf[0]; - B = buf[1]; - C = buf[2]; - D = buf[3]; - E = buf[4]; - - /* Heavy mangling, in 4 sub-rounds of 20 interations each. */ - subRound (A, B, C, D, E, f1, K1, in[0]); - subRound (E, A, B, C, D, f1, K1, in[1]); - subRound (D, E, A, B, C, f1, K1, in[2]); - subRound (C, D, E, A, B, f1, K1, in[3]); - subRound (B, C, D, E, A, f1, K1, in[4]); - subRound (A, B, C, D, E, f1, K1, in[5]); - subRound (E, A, B, C, D, f1, K1, in[6]); - subRound (D, E, A, B, C, f1, K1, in[7]); - subRound (C, D, E, A, B, f1, K1, in[8]); - subRound (B, C, D, E, A, f1, K1, in[9]); - subRound (A, B, C, D, E, f1, K1, in[10]); - subRound (E, A, B, C, D, f1, K1, in[11]); - subRound (D, E, A, B, C, f1, K1, in[12]); - subRound (C, D, E, A, B, f1, K1, in[13]); - subRound (B, C, D, E, A, f1, K1, in[14]); - subRound (A, B, C, D, E, f1, K1, in[15]); - subRound (E, A, B, C, D, f1, K1, expand (in, 16)); - subRound (D, E, A, B, C, f1, K1, expand (in, 17)); - subRound (C, D, E, A, B, f1, K1, expand (in, 18)); - subRound (B, C, D, E, A, f1, K1, expand (in, 19)); - - subRound (A, B, C, D, E, f2, K2, expand (in, 20)); - subRound (E, A, B, C, D, f2, K2, expand (in, 21)); - subRound (D, E, A, B, C, f2, K2, expand (in, 22)); - subRound (C, D, E, A, B, f2, K2, expand (in, 23)); - subRound (B, C, D, E, A, f2, K2, expand (in, 24)); - subRound (A, B, C, D, E, f2, K2, expand (in, 25)); - subRound (E, A, B, C, D, f2, K2, expand (in, 26)); - subRound (D, E, A, B, C, f2, K2, expand (in, 27)); - subRound (C, D, E, A, B, f2, K2, expand (in, 28)); - subRound (B, C, D, E, A, f2, K2, expand (in, 29)); - subRound (A, B, C, D, E, f2, K2, expand (in, 30)); - subRound (E, A, B, C, D, f2, K2, expand (in, 31)); - subRound (D, E, A, B, C, f2, K2, expand (in, 32)); - subRound (C, D, E, A, B, f2, K2, expand (in, 33)); - subRound (B, C, D, E, A, f2, K2, expand (in, 34)); - subRound (A, B, C, D, E, f2, K2, expand (in, 35)); - subRound (E, A, B, C, D, f2, K2, expand (in, 36)); - subRound (D, E, A, B, C, f2, K2, expand (in, 37)); - subRound (C, D, E, A, B, f2, K2, expand (in, 38)); - subRound (B, C, D, E, A, f2, K2, expand (in, 39)); - - subRound (A, B, C, D, E, f3, K3, expand (in, 40)); - subRound (E, A, B, C, D, f3, K3, expand (in, 41)); - subRound (D, E, A, B, C, f3, K3, expand (in, 42)); - subRound (C, D, E, A, B, f3, K3, expand (in, 43)); - subRound (B, C, D, E, A, f3, K3, expand (in, 44)); - subRound (A, B, C, D, E, f3, K3, expand (in, 45)); - subRound (E, A, B, C, D, f3, K3, expand (in, 46)); - subRound (D, E, A, B, C, f3, K3, expand (in, 47)); - subRound (C, D, E, A, B, f3, K3, expand (in, 48)); - subRound (B, C, D, E, A, f3, K3, expand (in, 49)); - subRound (A, B, C, D, E, f3, K3, expand (in, 50)); - subRound (E, A, B, C, D, f3, K3, expand (in, 51)); - subRound (D, E, A, B, C, f3, K3, expand (in, 52)); - subRound (C, D, E, A, B, f3, K3, expand (in, 53)); - subRound (B, C, D, E, A, f3, K3, expand (in, 54)); - subRound (A, B, C, D, E, f3, K3, expand (in, 55)); - subRound (E, A, B, C, D, f3, K3, expand (in, 56)); - subRound (D, E, A, B, C, f3, K3, expand (in, 57)); - subRound (C, D, E, A, B, f3, K3, expand (in, 58)); - subRound (B, C, D, E, A, f3, K3, expand (in, 59)); - - subRound (A, B, C, D, E, f4, K4, expand (in, 60)); - subRound (E, A, B, C, D, f4, K4, expand (in, 61)); - subRound (D, E, A, B, C, f4, K4, expand (in, 62)); - subRound (C, D, E, A, B, f4, K4, expand (in, 63)); - subRound (B, C, D, E, A, f4, K4, expand (in, 64)); - subRound (A, B, C, D, E, f4, K4, expand (in, 65)); - subRound (E, A, B, C, D, f4, K4, expand (in, 66)); - subRound (D, E, A, B, C, f4, K4, expand (in, 67)); - subRound (C, D, E, A, B, f4, K4, expand (in, 68)); - subRound (B, C, D, E, A, f4, K4, expand (in, 69)); - subRound (A, B, C, D, E, f4, K4, expand (in, 70)); - subRound (E, A, B, C, D, f4, K4, expand (in, 71)); - subRound (D, E, A, B, C, f4, K4, expand (in, 72)); - subRound (C, D, E, A, B, f4, K4, expand (in, 73)); - subRound (B, C, D, E, A, f4, K4, expand (in, 74)); - subRound (A, B, C, D, E, f4, K4, expand (in, 75)); - subRound (E, A, B, C, D, f4, K4, expand (in, 76)); - subRound (D, E, A, B, C, f4, K4, expand (in, 77)); - subRound (C, D, E, A, B, f4, K4, expand (in, 78)); - subRound (B, C, D, E, A, f4, K4, expand (in, 79)); - - /* Build message digest */ - buf[0] += A; - buf[1] += B; - buf[2] += C; - buf[3] += D; - buf[4] += E; -} - -#undef K1 -#undef K2 -#undef K3 -#undef K4 -#undef f1 -#undef f2 -#undef f3 -#undef f4 -#undef ROTL -#undef expand -#undef subRound - -static void -sha1_sum_update (Sha1sum *sha1, - const guchar *buffer, - gsize count) -{ - guint32 tmp; - guint dataCount; - - /* Update bitcount */ - tmp = sha1->bits[0]; - if ((sha1->bits[0] = tmp + ((guint32) count << 3) ) < tmp) - sha1->bits[1] += 1; /* Carry from low to high */ - sha1->bits[1] += count >> 29; - - /* Get count of bytes already in data */ - dataCount = (guint) (tmp >> 3) & 0x3F; - - /* Handle any leading odd-sized chunks */ - if (dataCount) - { - guchar *p = (guchar *) sha1->data + dataCount; - - dataCount = SHA1_DATASIZE - dataCount; - if (count < dataCount) - { - memcpy (p, buffer, count); - return; - } - - memcpy (p, buffer, dataCount); - - sha_byte_reverse (sha1->data, SHA1_DATASIZE); - sha1_transform (sha1->buf, sha1->data); - - buffer += dataCount; - count -= dataCount; - } - - /* Process data in SHA1_DATASIZE chunks */ - while (count >= SHA1_DATASIZE) - { - memcpy (sha1->data, buffer, SHA1_DATASIZE); - - sha_byte_reverse (sha1->data, SHA1_DATASIZE); - sha1_transform (sha1->buf, sha1->data); - - buffer += SHA1_DATASIZE; - count -= SHA1_DATASIZE; - } - - /* Handle any remaining bytes of data. */ - memcpy (sha1->data, buffer, count); -} - -/* Final wrapup - pad to SHA_DATASIZE-byte boundary with the bit pattern - 1 0* (64-bit count of bits processed, MSB-first) */ -static void -sha1_sum_close (Sha1sum *sha1) -{ - gint count; - guchar *data_p; - - /* Compute number of bytes mod 64 */ - count = (gint) ((sha1->bits[0] >> 3) & 0x3f); - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - data_p = (guchar *) sha1->data + count; - *data_p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = SHA1_DATASIZE - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) - { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset (data_p, 0, count); - - sha_byte_reverse (sha1->data, SHA1_DATASIZE); - sha1_transform (sha1->buf, sha1->data); - - /* Now fill the next block with 56 bytes */ - memset (sha1->data, 0, SHA1_DATASIZE - 8); - } - else - { - /* Pad block to 56 bytes */ - memset (data_p, 0, count - 8); - } - - /* Append length in bits and transform */ - sha1->data[14] = sha1->bits[1]; - sha1->data[15] = sha1->bits[0]; - - sha_byte_reverse (sha1->data, SHA1_DATASIZE - 8); - sha1_transform (sha1->buf, sha1->data); - sha_byte_reverse (sha1->buf, SHA1_DIGEST_LEN); - - memcpy (sha1->digest, sha1->buf, SHA1_DIGEST_LEN); - - /* Reset buffers in case they contain sensitive data */ - memset (sha1->buf, 0, sizeof (sha1->buf)); - memset (sha1->data, 0, sizeof (sha1->data)); -} - -static gchar * -sha1_sum_to_string (Sha1sum *sha1) -{ - return digest_to_string (sha1->digest, SHA1_DIGEST_LEN); -} - -static void -sha1_sum_digest (Sha1sum *sha1, - guint8 *digest) -{ - gint i; - - for (i = 0; i < SHA1_DIGEST_LEN; i++) - digest[i] = sha1->digest[i]; -} - -/* - * SHA-256 Checksum - */ - -/* adapted from the SHA256 implementation in gsk/src/hash/gskhash.c. - * - * Copyright (C) 2006 Dave Benson - * Released under the terms of the GNU Lesser General Public License - */ - -static void -sha256_sum_init (Sha256sum *sha256) -{ - sha256->buf[0] = 0x6a09e667; - sha256->buf[1] = 0xbb67ae85; - sha256->buf[2] = 0x3c6ef372; - sha256->buf[3] = 0xa54ff53a; - sha256->buf[4] = 0x510e527f; - sha256->buf[5] = 0x9b05688c; - sha256->buf[6] = 0x1f83d9ab; - sha256->buf[7] = 0x5be0cd19; - - sha256->bits[0] = sha256->bits[1] = 0; -} - -#define GET_UINT32(n,b,i) G_STMT_START{ \ - (n) = ((guint32) (b)[(i) ] << 24) \ - | ((guint32) (b)[(i) + 1] << 16) \ - | ((guint32) (b)[(i) + 2] << 8) \ - | ((guint32) (b)[(i) + 3] ); } G_STMT_END - -#define PUT_UINT32(n,b,i) G_STMT_START{ \ - (b)[(i) ] = (guint8) ((n) >> 24); \ - (b)[(i) + 1] = (guint8) ((n) >> 16); \ - (b)[(i) + 2] = (guint8) ((n) >> 8); \ - (b)[(i) + 3] = (guint8) ((n) ); } G_STMT_END - -static void -sha256_transform (guint32 buf[8], - guint8 const data[64]) -{ - guint32 temp1, temp2, W[64]; - guint32 A, B, C, D, E, F, G, H; - - GET_UINT32 (W[0], data, 0); - GET_UINT32 (W[1], data, 4); - GET_UINT32 (W[2], data, 8); - GET_UINT32 (W[3], data, 12); - GET_UINT32 (W[4], data, 16); - GET_UINT32 (W[5], data, 20); - GET_UINT32 (W[6], data, 24); - GET_UINT32 (W[7], data, 28); - GET_UINT32 (W[8], data, 32); - GET_UINT32 (W[9], data, 36); - GET_UINT32 (W[10], data, 40); - GET_UINT32 (W[11], data, 44); - GET_UINT32 (W[12], data, 48); - GET_UINT32 (W[13], data, 52); - GET_UINT32 (W[14], data, 56); - GET_UINT32 (W[15], data, 60); - -#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) -#define ROTR(x,n) (SHR (x,n) | (x << (32 - n))) - -#define S0(x) (ROTR (x, 7) ^ ROTR (x,18) ^ SHR (x, 3)) -#define S1(x) (ROTR (x,17) ^ ROTR (x,19) ^ SHR (x,10)) -#define S2(x) (ROTR (x, 2) ^ ROTR (x,13) ^ ROTR (x,22)) -#define S3(x) (ROTR (x, 6) ^ ROTR (x,11) ^ ROTR (x,25)) - -#define F0(x,y,z) ((x & y) | (z & (x | y))) -#define F1(x,y,z) (z ^ (x & (y ^ z))) - -#define R(t) (W[t] = S1(W[t - 2]) + W[t - 7] + \ - S0(W[t - 15]) + W[t - 16]) - -#define P(a,b,c,d,e,f,g,h,x,K) G_STMT_START { \ - temp1 = h + S3(e) + F1(e,f,g) + K + x; \ - temp2 = S2(a) + F0(a,b,c); \ - d += temp1; h = temp1 + temp2; } G_STMT_END - - A = buf[0]; - B = buf[1]; - C = buf[2]; - D = buf[3]; - E = buf[4]; - F = buf[5]; - G = buf[6]; - H = buf[7]; - - P (A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98); - P (H, A, B, C, D, E, F, G, W[ 1], 0x71374491); - P (G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF); - P (F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5); - P (E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B); - P (D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1); - P (C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4); - P (B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5); - P (A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98); - P (H, A, B, C, D, E, F, G, W[ 9], 0x12835B01); - P (G, H, A, B, C, D, E, F, W[10], 0x243185BE); - P (F, G, H, A, B, C, D, E, W[11], 0x550C7DC3); - P (E, F, G, H, A, B, C, D, W[12], 0x72BE5D74); - P (D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE); - P (C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7); - P (B, C, D, E, F, G, H, A, W[15], 0xC19BF174); - P (A, B, C, D, E, F, G, H, R(16), 0xE49B69C1); - P (H, A, B, C, D, E, F, G, R(17), 0xEFBE4786); - P (G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6); - P (F, G, H, A, B, C, D, E, R(19), 0x240CA1CC); - P (E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F); - P (D, E, F, G, H, A, B, C, R(21), 0x4A7484AA); - P (C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC); - P (B, C, D, E, F, G, H, A, R(23), 0x76F988DA); - P (A, B, C, D, E, F, G, H, R(24), 0x983E5152); - P (H, A, B, C, D, E, F, G, R(25), 0xA831C66D); - P (G, H, A, B, C, D, E, F, R(26), 0xB00327C8); - P (F, G, H, A, B, C, D, E, R(27), 0xBF597FC7); - P (E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3); - P (D, E, F, G, H, A, B, C, R(29), 0xD5A79147); - P (C, D, E, F, G, H, A, B, R(30), 0x06CA6351); - P (B, C, D, E, F, G, H, A, R(31), 0x14292967); - P (A, B, C, D, E, F, G, H, R(32), 0x27B70A85); - P (H, A, B, C, D, E, F, G, R(33), 0x2E1B2138); - P (G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC); - P (F, G, H, A, B, C, D, E, R(35), 0x53380D13); - P (E, F, G, H, A, B, C, D, R(36), 0x650A7354); - P (D, E, F, G, H, A, B, C, R(37), 0x766A0ABB); - P (C, D, E, F, G, H, A, B, R(38), 0x81C2C92E); - P (B, C, D, E, F, G, H, A, R(39), 0x92722C85); - P (A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1); - P (H, A, B, C, D, E, F, G, R(41), 0xA81A664B); - P (G, H, A, B, C, D, E, F, R(42), 0xC24B8B70); - P (F, G, H, A, B, C, D, E, R(43), 0xC76C51A3); - P (E, F, G, H, A, B, C, D, R(44), 0xD192E819); - P (D, E, F, G, H, A, B, C, R(45), 0xD6990624); - P (C, D, E, F, G, H, A, B, R(46), 0xF40E3585); - P (B, C, D, E, F, G, H, A, R(47), 0x106AA070); - P (A, B, C, D, E, F, G, H, R(48), 0x19A4C116); - P (H, A, B, C, D, E, F, G, R(49), 0x1E376C08); - P (G, H, A, B, C, D, E, F, R(50), 0x2748774C); - P (F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5); - P (E, F, G, H, A, B, C, D, R(52), 0x391C0CB3); - P (D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A); - P (C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F); - P (B, C, D, E, F, G, H, A, R(55), 0x682E6FF3); - P (A, B, C, D, E, F, G, H, R(56), 0x748F82EE); - P (H, A, B, C, D, E, F, G, R(57), 0x78A5636F); - P (G, H, A, B, C, D, E, F, R(58), 0x84C87814); - P (F, G, H, A, B, C, D, E, R(59), 0x8CC70208); - P (E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA); - P (D, E, F, G, H, A, B, C, R(61), 0xA4506CEB); - P (C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7); - P (B, C, D, E, F, G, H, A, R(63), 0xC67178F2); - -#undef SHR -#undef ROTR -#undef S0 -#undef S1 -#undef S2 -#undef S3 -#undef F0 -#undef F1 -#undef R -#undef P - - buf[0] += A; - buf[1] += B; - buf[2] += C; - buf[3] += D; - buf[4] += E; - buf[5] += F; - buf[6] += G; - buf[7] += H; -} - -static void -sha256_sum_update (Sha256sum *sha256, - const guchar *buffer, - gsize length) -{ - guint32 left, fill; - const guint8 *input = buffer; - - if (length == 0) - return; - - left = sha256->bits[0] & 0x3F; - fill = 64 - left; - - sha256->bits[0] += length; - sha256->bits[0] &= 0xFFFFFFFF; - - if (sha256->bits[0] < length) - sha256->bits[1]++; - - if (left > 0 && length >= fill) - { - memcpy ((sha256->data + left), input, fill); - - sha256_transform (sha256->buf, sha256->data); - length -= fill; - input += fill; - - left = 0; - } - - while (length >= SHA256_DATASIZE) - { - sha256_transform (sha256->buf, input); - - length -= 64; - input += 64; - } - - if (length) - memcpy (sha256->data + left, input, length); -} - -static guint8 sha256_padding[64] = -{ - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static void -sha256_sum_close (Sha256sum *sha256) -{ - guint32 last, padn; - guint32 high, low; - guint8 msglen[8]; - - high = (sha256->bits[0] >> 29) - | (sha256->bits[1] << 3); - low = (sha256->bits[0] << 3); - - PUT_UINT32 (high, msglen, 0); - PUT_UINT32 (low, msglen, 4); - - last = sha256->bits[0] & 0x3F; - padn = (last < 56) ? (56 - last) : (120 - last); - - sha256_sum_update (sha256, sha256_padding, padn); - sha256_sum_update (sha256, msglen, 8); - - PUT_UINT32 (sha256->buf[0], sha256->digest, 0); - PUT_UINT32 (sha256->buf[1], sha256->digest, 4); - PUT_UINT32 (sha256->buf[2], sha256->digest, 8); - PUT_UINT32 (sha256->buf[3], sha256->digest, 12); - PUT_UINT32 (sha256->buf[4], sha256->digest, 16); - PUT_UINT32 (sha256->buf[5], sha256->digest, 20); - PUT_UINT32 (sha256->buf[6], sha256->digest, 24); - PUT_UINT32 (sha256->buf[7], sha256->digest, 28); -} - -#undef PUT_UINT32 -#undef GET_UINT32 - -static gchar * -sha256_sum_to_string (Sha256sum *sha256) -{ - return digest_to_string (sha256->digest, SHA256_DIGEST_LEN); -} - -static void -sha256_sum_digest (Sha256sum *sha256, - guint8 *digest) -{ - gint i; - - for (i = 0; i < SHA256_DIGEST_LEN; i++) - digest[i] = sha256->digest[i]; -} - - -/* - * Public API - */ - -/** - * g_checksum_type_get_length: - * @checksum_type: a #GChecksumType - * - * Gets the length in bytes of digests of type @checksum_type - * - * Return value: the checksum length, or -1 if @checksum_type is - * not supported. - * - * Since: 2.16 - */ -gssize -g_checksum_type_get_length (GChecksumType checksum_type) -{ - gssize len = -1; - - switch (checksum_type) - { - case G_CHECKSUM_MD5: - len = MD5_DIGEST_LEN; - break; - case G_CHECKSUM_SHA1: - len = SHA1_DIGEST_LEN; - break; - case G_CHECKSUM_SHA256: - len = SHA256_DIGEST_LEN; - break; - default: - len = -1; - break; - } - - return len; -} - -/** - * g_checksum_new: - * @checksum_type: the desired type of checksum - * - * Creates a new #GChecksum, using the checksum algorithm @checksum_type. - * If the @checksum_type is not known, %NULL is returned. - * A #GChecksum can be used to compute the checksum, or digest, of an - * arbitrary binary blob, using different hashing algorithms. - * - * A #GChecksum works by feeding a binary blob through g_checksum_update() - * until there is data to be checked; the digest can then be extracted - * using g_checksum_get_string(), which will return the checksum as a - * hexadecimal string; or g_checksum_get_digest(), which will return a - * vector of raw bytes. Once either g_checksum_get_string() or - * g_checksum_get_digest() have been called on a #GChecksum, the checksum - * will be closed and it won't be possible to call g_checksum_update() - * on it anymore. - * - * Return value: the newly created #GChecksum, or %NULL. - * Use g_checksum_free() to free the memory allocated by it. - * - * Since: 2.16 - */ -GChecksum * -g_checksum_new (GChecksumType checksum_type) -{ - GChecksum *checksum; - - if (! IS_VALID_TYPE (checksum_type)) - return NULL; - - checksum = g_slice_new0 (GChecksum); - checksum->type = checksum_type; - - g_checksum_reset (checksum); - - return checksum; -} - -/** - * g_checksum_reset: - * @checksum: the #GChecksum to reset - * - * Resets the state of the @checksum back to its initial state. - * - * Since: 2.18 - **/ -void -g_checksum_reset (GChecksum *checksum) -{ - g_return_if_fail (checksum != NULL); - - g_free (checksum->digest_str); - checksum->digest_str = NULL; - - switch (checksum->type) - { - case G_CHECKSUM_MD5: - md5_sum_init (&(checksum->sum.md5)); - break; - case G_CHECKSUM_SHA1: - sha1_sum_init (&(checksum->sum.sha1)); - break; - case G_CHECKSUM_SHA256: - sha256_sum_init (&(checksum->sum.sha256)); - break; - default: - g_assert_not_reached (); - break; - } -} - -/** - * g_checksum_copy: - * @checksum: the #GChecksum to copy - * - * Copies a #GChecksum. If @checksum has been closed, by calling - * g_checksum_get_string() or g_checksum_get_digest(), the copied - * checksum will be closed as well. - * - * Return value: the copy of the passed #GChecksum. Use g_checksum_free() - * when finished using it. - * - * Since: 2.16 - */ -GChecksum * -g_checksum_copy (const GChecksum *checksum) -{ - GChecksum *copy; - - g_return_val_if_fail (checksum != NULL, NULL); - - copy = g_slice_new (GChecksum); - *copy = *checksum; - - copy->digest_str = g_strdup (checksum->digest_str); - - return copy; -} - -/** - * g_checksum_free: - * @checksum: a #GChecksum - * - * Frees the memory allocated for @checksum. - * - * Since: 2.16 - */ -void -g_checksum_free (GChecksum *checksum) -{ - if (G_LIKELY (checksum)) - { - g_free (checksum->digest_str); - - g_slice_free (GChecksum, checksum); - } -} - -/** - * g_checksum_update: - * @checksum: a #GChecksum - * @data: buffer used to compute the checksum - * @length: size of the buffer, or -1 if it is a null-terminated string. - * - * Feeds @data into an existing #GChecksum. The checksum must still be - * open, that is g_checksum_get_string() or g_checksum_get_digest() must - * not have been called on @checksum. - * - * Since: 2.16 - */ -void -g_checksum_update (GChecksum *checksum, - const guchar *data, - gssize length) -{ - g_return_if_fail (checksum != NULL); - g_return_if_fail (data != NULL); - - if (length < 0) - length = strlen ((const gchar *) data); - - if (checksum->digest_str) - { - g_warning ("The checksum `%s' has been closed and cannot be updated " - "anymore.", - checksum->digest_str); - return; - } - - switch (checksum->type) - { - case G_CHECKSUM_MD5: - md5_sum_update (&(checksum->sum.md5), data, length); - break; - case G_CHECKSUM_SHA1: - sha1_sum_update (&(checksum->sum.sha1), data, length); - break; - case G_CHECKSUM_SHA256: - sha256_sum_update (&(checksum->sum.sha256), data, length); - break; - default: - g_assert_not_reached (); - break; - } -} - -/** - * g_checksum_get_string: - * @checksum: a #GChecksum - * - * Gets the digest as an hexadecimal string. - * - * Once this function has been called the #GChecksum can no longer be - * updated with g_checksum_update(). - * - * The hexadecimal characters will be lower case. - * - * Return value: the hexadecimal representation of the checksum. The - * returned string is owned by the checksum and should not be modified - * or freed. - * - * Since: 2.16 - */ -G_CONST_RETURN gchar * -g_checksum_get_string (GChecksum *checksum) -{ - gchar *str = NULL; - - g_return_val_if_fail (checksum != NULL, NULL); - - if (checksum->digest_str) - return checksum->digest_str; - - switch (checksum->type) - { - case G_CHECKSUM_MD5: - md5_sum_close (&(checksum->sum.md5)); - str = md5_sum_to_string (&(checksum->sum.md5)); - break; - case G_CHECKSUM_SHA1: - sha1_sum_close (&(checksum->sum.sha1)); - str = sha1_sum_to_string (&(checksum->sum.sha1)); - break; - case G_CHECKSUM_SHA256: - sha256_sum_close (&(checksum->sum.sha256)); - str = sha256_sum_to_string (&(checksum->sum.sha256)); - break; - default: - g_assert_not_reached (); - break; - } - - checksum->digest_str = str; - - return checksum->digest_str; -} - -/** - * g_checksum_get_digest: - * @checksum: a #GChecksum - * @buffer: output buffer - * @digest_len: 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 vector and places it - * into @buffer. The size of the digest depends on the type of checksum. - * - * Once this function has been called, the #GChecksum is closed and can - * no longer be updated with g_checksum_update(). - * - * Since: 2.16 - */ -void -g_checksum_get_digest (GChecksum *checksum, - guint8 *buffer, - gsize *digest_len) -{ - gboolean checksum_open = FALSE; - gchar *str = NULL; - gsize len; - - g_return_if_fail (checksum != NULL); - - len = g_checksum_type_get_length (checksum->type); - g_return_if_fail (*digest_len >= len); - - checksum_open = !!(checksum->digest_str == NULL); - - switch (checksum->type) - { - case G_CHECKSUM_MD5: - if (checksum_open) - { - md5_sum_close (&(checksum->sum.md5)); - str = md5_sum_to_string (&(checksum->sum.md5)); - } - md5_sum_digest (&(checksum->sum.md5), buffer); - break; - case G_CHECKSUM_SHA1: - if (checksum_open) - { - sha1_sum_close (&(checksum->sum.sha1)); - str = sha1_sum_to_string (&(checksum->sum.sha1)); - } - sha1_sum_digest (&(checksum->sum.sha1), buffer); - break; - case G_CHECKSUM_SHA256: - if (checksum_open) - { - sha256_sum_close (&(checksum->sum.sha256)); - str = sha256_sum_to_string (&(checksum->sum.sha256)); - } - sha256_sum_digest (&(checksum->sum.sha256), buffer); - break; - default: - g_assert_not_reached (); - break; - } - - if (str) - checksum->digest_str = str; - - *digest_len = len; -} - -/** - * g_compute_checksum_for_data: - * @checksum_type: a #GChecksumType - * @data: binary blob to compute the digest of - * @length: length of @data - * - * Computes the checksum for a binary @data of @length. This is a - * convenience wrapper for g_checksum_new(), g_checksum_get_string() - * and g_checksum_free(). - * - * The hexadecimal string returned will be in lower case. - * - * Return value: the digest of the binary data as a string in hexadecimal. - * The returned string should be freed with g_free() when done using it. - * - * Since: 2.16 - */ -gchar * -g_compute_checksum_for_data (GChecksumType checksum_type, - const guchar *data, - gsize length) -{ - GChecksum *checksum; - gchar *retval; - - g_return_val_if_fail (IS_VALID_TYPE (checksum_type), NULL); - g_return_val_if_fail (data != NULL, NULL); - - checksum = g_checksum_new (checksum_type); - if (!checksum) - return NULL; - - g_checksum_update (checksum, data, length); - retval = g_strdup (g_checksum_get_string (checksum)); - g_checksum_free (checksum); - - return retval; -} - -/** - * g_compute_checksum_for_string: - * @checksum_type: a #GChecksumType - * @str: the string to compute the checksum of - * @length: the length of the string, or -1 if the string is null-terminated. - * - * Computes the checksum of a string. - * - * The hexadecimal string returned will be in lower case. - * - * Return value: the checksum as a hexadecimal string. The returned string - * should be freed with g_free() when done using it. - * - * Since: 2.16 - */ -gchar * -g_compute_checksum_for_string (GChecksumType checksum_type, - const gchar *str, - gssize length) -{ - g_return_val_if_fail (IS_VALID_TYPE (checksum_type), NULL); - g_return_val_if_fail (str != NULL, NULL); - - if (length < 0) - length = strlen (str); - - return g_compute_checksum_for_data (checksum_type, (const guchar *) str, length); -} - -#define __G_CHECKSUM_C__ -#include "galiasdef.c" diff --git a/glib/gcompletion.c b/glib/gcompletion.c deleted file mode 100644 index 5d2607846..000000000 --- a/glib/gcompletion.c +++ /dev/null @@ -1,350 +0,0 @@ -/* 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, 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" - -#include <string.h> - -#include "glib.h" -#include "galias.h" - -static void completion_check_cache (GCompletion* cmp, - gchar** new_prefix); - -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; -} - -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; - } -} - -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; - } -} - -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) -{ - register GList* list; - register gsize len; - register gsize i; - register 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. - * - * Return value: the list of items whose strings begin with @prefix. This should - * not be changed. - * - * Since: 2.4 - **/ -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; -} - -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; -} - -void -g_completion_free (GCompletion* cmp) -{ - g_return_if_fail (cmp != NULL); - - g_completion_clear_items (cmp); - g_free (cmp); -} - -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 ...]\n", argv[0]); - return 1; - } - - file = fopen (argv[1], "r"); - if (!file) - { - g_warning ("Cannot open %s\n", 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 - -#define __G_COMPLETION_C__ -#include "galiasdef.c" diff --git a/glib/gconvert.c b/glib/gconvert.c index 7aefe24f3..c0952da59 100644 --- a/glib/gconvert.c +++ b/glib/gconvert.c @@ -24,9 +24,13 @@ #include "glib.h" + +#ifdef ANDROID_STUB #ifndef G_OS_WIN32 #include <iconv.h> #endif +#endif + #include <errno.h> #include <stdio.h> #include <string.h> @@ -57,6 +61,8 @@ #include "galias.h" +typedef void iconv_t; + GQuark g_convert_error_quark (void) { @@ -68,12 +74,16 @@ try_conversion (const char *to_codeset, const char *from_codeset, iconv_t *cd) { +#ifdef ANDROID_STUB *cd = iconv_open (to_codeset, from_codeset); if (*cd == (iconv_t)-1 && errno == EINVAL) return FALSE; else return TRUE; +#else + return FALSE; +#endif } static gboolean @@ -96,8 +106,10 @@ try_to_aliases (const char **to_aliases, return FALSE; } +#ifdef ANDROID_STUB G_GNUC_INTERNAL extern const char ** _g_charset_get_aliases (const char *canonical_name); +#endif /** * g_iconv_open: @@ -118,6 +130,7 @@ GIConv g_iconv_open (const gchar *to_codeset, const gchar *from_codeset) { +#ifdef ANDROID_STUB iconv_t cd; if (!try_conversion (to_codeset, from_codeset, &cd)) @@ -146,6 +159,9 @@ g_iconv_open (const gchar *to_codeset, out: return (cd == (iconv_t)-1) ? (GIConv)-1 : (GIConv)cd; +#else + return (GIConv) -1; +#endif } /** @@ -172,9 +188,13 @@ g_iconv (GIConv converter, gchar **outbuf, gsize *outbytes_left) { +#ifdef ANDROID_STUB iconv_t cd = (iconv_t)converter; return iconv (cd, inbuf, inbytes_left, outbuf, outbytes_left); +#else + return -1; +#endif } /** @@ -195,9 +215,13 @@ g_iconv (GIConv converter, gint g_iconv_close (GIConv converter) { +#ifdef ANDROID_STUB iconv_t cd = (iconv_t)converter; return iconv_close (cd); +#else + return -1; +#endif } diff --git a/glib/gdate.c b/glib/gdate.c deleted file mode 100644 index cb25f3c56..000000000 --- a/glib/gdate.c +++ /dev/null @@ -1,1905 +0,0 @@ -/* 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, 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" - -#define DEBUG_MSG(x) /* */ -#ifdef G_ENABLE_DEBUG -/* #define DEBUG_MSG(args) g_message args ; */ -#endif - -#include "glib.h" - -#include <time.h> -#include <string.h> -#include <stdlib.h> -#include <locale.h> - -#ifdef G_OS_WIN32 -#include <windows.h> -#endif - -#include "galias.h" - -GDate* -g_date_new (void) -{ - GDate *d = g_new0 (GDate, 1); /* happily, 0 is the invalid flag for everything. */ - - return d; -} - -GDate* -g_date_new_dmy (GDateDay day, - GDateMonth m, - GDateYear y) -{ - GDate *d; - g_return_val_if_fail (g_date_valid_dmy (day, m, y), NULL); - - d = g_new (GDate, 1); - - d->julian = FALSE; - d->dmy = TRUE; - - d->month = m; - d->day = day; - d->year = y; - - g_assert (g_date_valid (d)); - - return d; -} - -GDate* -g_date_new_julian (guint32 j) -{ - GDate *d; - g_return_val_if_fail (g_date_valid_julian (j), NULL); - - d = g_new (GDate, 1); - - d->julian = TRUE; - d->dmy = FALSE; - - d->julian_days = j; - - g_assert (g_date_valid (d)); - - return d; -} - -void -g_date_free (GDate *d) -{ - g_return_if_fail (d != NULL); - - g_free (d); -} - -gboolean -g_date_valid (const GDate *d) -{ - g_return_val_if_fail (d != NULL, FALSE); - - return (d->julian || d->dmy); -} - -static const guint8 days_in_months[2][13] = -{ /* error, jan feb mar apr may jun jul aug sep oct nov dec */ - { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } /* leap year */ -}; - -static const guint16 days_in_year[2][14] = -{ /* 0, jan feb mar apr may jun jul aug sep oct nov dec */ - { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, - { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } -}; - -gboolean -g_date_valid_month (GDateMonth m) -{ - return ( (m > G_DATE_BAD_MONTH) && (m < 13) ); -} - -gboolean -g_date_valid_year (GDateYear y) -{ - return ( y > G_DATE_BAD_YEAR ); -} - -gboolean -g_date_valid_day (GDateDay d) -{ - return ( (d > G_DATE_BAD_DAY) && (d < 32) ); -} - -gboolean -g_date_valid_weekday (GDateWeekday w) -{ - return ( (w > G_DATE_BAD_WEEKDAY) && (w < 8) ); -} - -gboolean -g_date_valid_julian (guint32 j) -{ - return (j > G_DATE_BAD_JULIAN); -} - -gboolean -g_date_valid_dmy (GDateDay d, - GDateMonth m, - GDateYear y) -{ - return ( (m > G_DATE_BAD_MONTH) && - (m < 13) && - (d > G_DATE_BAD_DAY) && - (y > G_DATE_BAD_YEAR) && /* must check before using g_date_is_leap_year */ - (d <= (g_date_is_leap_year (y) ? - days_in_months[1][m] : days_in_months[0][m])) ); -} - - -/* "Julian days" just means an absolute number of days, where Day 1 == - * Jan 1, Year 1 - */ -static void -g_date_update_julian (const GDate *const_d) -{ - GDate *d = (GDate *) const_d; - GDateYear year; - gint idx; - - g_return_if_fail (d != NULL); - g_return_if_fail (d->dmy); - g_return_if_fail (!d->julian); - g_return_if_fail (g_date_valid_dmy (d->day, d->month, d->year)); - - /* What we actually do is: multiply years * 365 days in the year, - * add the number of years divided by 4, subtract the number of - * years divided by 100 and add the number of years divided by 400, - * which accounts for leap year stuff. Code from Steffen Beyer's - * DateCalc. - */ - - year = d->year - 1; /* we know d->year > 0 since it's valid */ - - d->julian_days = year * 365U; - d->julian_days += (year >>= 2); /* divide by 4 and add */ - d->julian_days -= (year /= 25); /* divides original # years by 100 */ - d->julian_days += year >> 2; /* divides by 4, which divides original by 400 */ - - idx = g_date_is_leap_year (d->year) ? 1 : 0; - - d->julian_days += days_in_year[idx][d->month] + d->day; - - g_return_if_fail (g_date_valid_julian (d->julian_days)); - - d->julian = TRUE; -} - -static void -g_date_update_dmy (const GDate *const_d) -{ - GDate *d = (GDate *) const_d; - GDateYear y; - GDateMonth m; - GDateDay day; - - guint32 A, B, C, D, E, M; - - g_return_if_fail (d != NULL); - g_return_if_fail (d->julian); - g_return_if_fail (!d->dmy); - g_return_if_fail (g_date_valid_julian (d->julian_days)); - - /* Formula taken from the Calendar FAQ; the formula was for the - * Julian Period which starts on 1 January 4713 BC, so we add - * 1,721,425 to the number of days before doing the formula. - * - * I'm sure this can be simplified for our 1 January 1 AD period - * start, but I can't figure out how to unpack the formula. - */ - - A = d->julian_days + 1721425 + 32045; - B = ( 4 *(A + 36524) )/ 146097 - 1; - C = A - (146097 * B)/4; - D = ( 4 * (C + 365) ) / 1461 - 1; - E = C - ((1461*D) / 4); - M = (5 * (E - 1) + 2)/153; - - m = M + 3 - (12*(M/10)); - day = E - (153*M + 2)/5; - y = 100 * B + D - 4800 + (M/10); - -#ifdef G_ENABLE_DEBUG - if (!g_date_valid_dmy (day, m, y)) - g_warning ("\nOOPS julian: %u computed dmy: %u %u %u\n", - d->julian_days, day, m, y); -#endif - - d->month = m; - d->day = day; - d->year = y; - - d->dmy = TRUE; -} - -GDateWeekday -g_date_get_weekday (const GDate *d) -{ - g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_WEEKDAY); - - if (!d->julian) - g_date_update_julian (d); - - g_return_val_if_fail (d->julian, G_DATE_BAD_WEEKDAY); - - return ((d->julian_days - 1) % 7) + 1; -} - -GDateMonth -g_date_get_month (const GDate *d) -{ - g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_MONTH); - - if (!d->dmy) - g_date_update_dmy (d); - - g_return_val_if_fail (d->dmy, G_DATE_BAD_MONTH); - - return d->month; -} - -GDateYear -g_date_get_year (const GDate *d) -{ - g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_YEAR); - - if (!d->dmy) - g_date_update_dmy (d); - - g_return_val_if_fail (d->dmy, G_DATE_BAD_YEAR); - - return d->year; -} - -GDateDay -g_date_get_day (const GDate *d) -{ - g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_DAY); - - if (!d->dmy) - g_date_update_dmy (d); - - g_return_val_if_fail (d->dmy, G_DATE_BAD_DAY); - - return d->day; -} - -guint32 -g_date_get_julian (const GDate *d) -{ - g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_JULIAN); - - if (!d->julian) - g_date_update_julian (d); - - g_return_val_if_fail (d->julian, G_DATE_BAD_JULIAN); - - return d->julian_days; -} - -guint -g_date_get_day_of_year (const GDate *d) -{ - gint idx; - - g_return_val_if_fail (g_date_valid (d), 0); - - if (!d->dmy) - g_date_update_dmy (d); - - g_return_val_if_fail (d->dmy, 0); - - idx = g_date_is_leap_year (d->year) ? 1 : 0; - - return (days_in_year[idx][d->month] + d->day); -} - -guint -g_date_get_monday_week_of_year (const GDate *d) -{ - GDateWeekday wd; - guint day; - GDate first; - - g_return_val_if_fail (g_date_valid (d), 0); - - if (!d->dmy) - g_date_update_dmy (d); - - g_return_val_if_fail (d->dmy, 0); - - g_date_clear (&first, 1); - - g_date_set_dmy (&first, 1, 1, d->year); - - wd = g_date_get_weekday (&first) - 1; /* make Monday day 0 */ - day = g_date_get_day_of_year (d) - 1; - - return ((day + wd)/7U + (wd == 0 ? 1 : 0)); -} - -guint -g_date_get_sunday_week_of_year (const GDate *d) -{ - GDateWeekday wd; - guint day; - GDate first; - - g_return_val_if_fail (g_date_valid (d), 0); - - if (!d->dmy) - g_date_update_dmy (d); - - g_return_val_if_fail (d->dmy, 0); - - g_date_clear (&first, 1); - - g_date_set_dmy (&first, 1, 1, d->year); - - wd = g_date_get_weekday (&first); - if (wd == 7) wd = 0; /* make Sunday day 0 */ - day = g_date_get_day_of_year (d) - 1; - - return ((day + wd)/7U + (wd == 0 ? 1 : 0)); -} - -/** - * g_date_get_iso8601_week_of_year: - * @date: a valid #GDate - * - * Returns the week of the year, where weeks are interpreted according - * to ISO 8601. - * - * Returns: ISO 8601 week number of the year. - * - * Since: 2.6 - **/ -guint -g_date_get_iso8601_week_of_year (const GDate *d) -{ - guint j, d4, L, d1, w; - - g_return_val_if_fail (g_date_valid (d), 0); - - if (!d->julian) - g_date_update_julian (d); - - g_return_val_if_fail (d->julian, 0); - - /* Formula taken from the Calendar FAQ; the formula was for the - * Julian Period which starts on 1 January 4713 BC, so we add - * 1,721,425 to the number of days before doing the formula. - */ - j = d->julian_days + 1721425; - d4 = (j + 31741 - (j % 7)) % 146097 % 36524 % 1461; - L = d4 / 1460; - d1 = ((d4 - L) % 365) + L; - w = d1 / 7 + 1; - - return w; -} - -gint -g_date_days_between (const GDate *d1, - const GDate *d2) -{ - g_return_val_if_fail (g_date_valid (d1), 0); - g_return_val_if_fail (g_date_valid (d2), 0); - - return (gint)g_date_get_julian (d2) - (gint)g_date_get_julian (d1); -} - -void -g_date_clear (GDate *d, guint ndates) -{ - g_return_if_fail (d != NULL); - g_return_if_fail (ndates != 0); - - memset (d, 0x0, ndates*sizeof (GDate)); -} - -G_LOCK_DEFINE_STATIC (g_date_global); - -/* These are for the parser, output to the user should use * - * g_date_strftime () - this creates more never-freed memory to annoy - * all those memory debugger users. :-) - */ - -static gchar *long_month_names[13] = -{ - NULL, -}; - -static gchar *short_month_names[13] = -{ - NULL, -}; - -/* This tells us if we need to update the parse info */ -static gchar *current_locale = NULL; - -/* order of these in the current locale */ -static GDateDMY dmy_order[3] = -{ - G_DATE_DAY, G_DATE_MONTH, G_DATE_YEAR -}; - -/* Where to chop two-digit years: i.e., for the 1930 default, numbers - * 29 and below are counted as in the year 2000, numbers 30 and above - * are counted as in the year 1900. - */ - -static const GDateYear twodigit_start_year = 1930; - -/* It is impossible to enter a year between 1 AD and 99 AD with this - * in effect. - */ -static gboolean using_twodigit_years = FALSE; - -/* Adjustment of locale era to AD, non-zero means using locale era - */ -static gint locale_era_adjust = 0; - -struct _GDateParseTokens { - gint num_ints; - gint n[3]; - guint month; -}; - -typedef struct _GDateParseTokens GDateParseTokens; - -#define NUM_LEN 10 - -/* HOLDS: g_date_global_lock */ -static void -g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt) -{ - gchar num[4][NUM_LEN+1]; - gint i; - const guchar *s; - - /* We count 4, but store 3; so we can give an error - * if there are 4. - */ - num[0][0] = num[1][0] = num[2][0] = num[3][0] = '\0'; - - s = (const guchar *) str; - pt->num_ints = 0; - while (*s && pt->num_ints < 4) - { - - i = 0; - while (*s && g_ascii_isdigit (*s) && i < NUM_LEN) - { - num[pt->num_ints][i] = *s; - ++s; - ++i; - } - - if (i > 0) - { - num[pt->num_ints][i] = '\0'; - ++(pt->num_ints); - } - - if (*s == '\0') break; - - ++s; - } - - pt->n[0] = pt->num_ints > 0 ? atoi (num[0]) : 0; - pt->n[1] = pt->num_ints > 1 ? atoi (num[1]) : 0; - pt->n[2] = pt->num_ints > 2 ? atoi (num[2]) : 0; - - pt->month = G_DATE_BAD_MONTH; - - if (pt->num_ints < 3) - { - gchar *casefold; - gchar *normalized; - - casefold = g_utf8_casefold (str, -1); - normalized = g_utf8_normalize (casefold, -1, G_NORMALIZE_ALL); - g_free (casefold); - - i = 1; - while (i < 13) - { - if (long_month_names[i] != NULL) - { - const gchar *found = strstr (normalized, long_month_names[i]); - - if (found != NULL) - { - pt->month = i; - break; - } - } - - if (short_month_names[i] != NULL) - { - const gchar *found = strstr (normalized, short_month_names[i]); - - if (found != NULL) - { - pt->month = i; - break; - } - } - - ++i; - } - - g_free (normalized); - } -} - -/* HOLDS: g_date_global_lock */ -static void -g_date_prepare_to_parse (const gchar *str, - GDateParseTokens *pt) -{ - const gchar *locale = setlocale (LC_TIME, NULL); - gboolean recompute_localeinfo = FALSE; - GDate d; - - g_return_if_fail (locale != NULL); /* should not happen */ - - g_date_clear (&d, 1); /* clear for scratch use */ - - if ( (current_locale == NULL) || (strcmp (locale, current_locale) != 0) ) - recompute_localeinfo = TRUE; /* Uh, there used to be a reason for the temporary */ - - if (recompute_localeinfo) - { - int i = 1; - GDateParseTokens testpt; - gchar buf[128]; - - g_free (current_locale); /* still works if current_locale == NULL */ - - current_locale = g_strdup (locale); - - short_month_names[0] = "Error"; - long_month_names[0] = "Error"; - - while (i < 13) - { - gchar *casefold; - - g_date_set_dmy (&d, 1, i, 1); - - g_return_if_fail (g_date_valid (&d)); - - g_date_strftime (buf, 127, "%b", &d); - - casefold = g_utf8_casefold (buf, -1); - g_free (short_month_names[i]); - short_month_names[i] = g_utf8_normalize (casefold, -1, G_NORMALIZE_ALL); - g_free (casefold); - - g_date_strftime (buf, 127, "%B", &d); - casefold = g_utf8_casefold (buf, -1); - g_free (long_month_names[i]); - long_month_names[i] = g_utf8_normalize (casefold, -1, G_NORMALIZE_ALL); - g_free (casefold); - - ++i; - } - - /* Determine DMY order */ - - /* had to pick a random day - don't change this, some strftimes - * are broken on some days, and this one is good so far. */ - g_date_set_dmy (&d, 4, 7, 1976); - - g_date_strftime (buf, 127, "%x", &d); - - g_date_fill_parse_tokens (buf, &testpt); - - i = 0; - while (i < testpt.num_ints) - { - switch (testpt.n[i]) - { - case 7: - dmy_order[i] = G_DATE_MONTH; - break; - case 4: - dmy_order[i] = G_DATE_DAY; - break; - case 76: - using_twodigit_years = TRUE; /* FALL THRU */ - case 1976: - dmy_order[i] = G_DATE_YEAR; - break; - default: - /* assume locale era */ - locale_era_adjust = 1976 - testpt.n[i]; - dmy_order[i] = G_DATE_YEAR; - break; - } - ++i; - } - -#ifdef G_ENABLE_DEBUG - DEBUG_MSG (("**GDate prepared a new set of locale-specific parse rules.")); - i = 1; - while (i < 13) - { - DEBUG_MSG ((" %s %s", long_month_names[i], short_month_names[i])); - ++i; - } - if (using_twodigit_years) - { - DEBUG_MSG (("**Using twodigit years with cutoff year: %u", twodigit_start_year)); - } - { - gchar *strings[3]; - i = 0; - while (i < 3) - { - switch (dmy_order[i]) - { - case G_DATE_MONTH: - strings[i] = "Month"; - break; - case G_DATE_YEAR: - strings[i] = "Year"; - break; - case G_DATE_DAY: - strings[i] = "Day"; - break; - default: - strings[i] = NULL; - break; - } - ++i; - } - DEBUG_MSG (("**Order: %s, %s, %s", strings[0], strings[1], strings[2])); - DEBUG_MSG (("**Sample date in this locale: `%s'", buf)); - } -#endif - } - - g_date_fill_parse_tokens (str, pt); -} - -void -g_date_set_parse (GDate *d, - const gchar *str) -{ - GDateParseTokens pt; - guint m = G_DATE_BAD_MONTH, day = G_DATE_BAD_DAY, y = G_DATE_BAD_YEAR; - - g_return_if_fail (d != NULL); - - /* set invalid */ - g_date_clear (d, 1); - - G_LOCK (g_date_global); - - g_date_prepare_to_parse (str, &pt); - - DEBUG_MSG (("Found %d ints, `%d' `%d' `%d' and written out month %d", - pt.num_ints, pt.n[0], pt.n[1], pt.n[2], pt.month)); - - - if (pt.num_ints == 4) - { - G_UNLOCK (g_date_global); - return; /* presumably a typo; bail out. */ - } - - if (pt.num_ints > 1) - { - int i = 0; - int j = 0; - - g_assert (pt.num_ints < 4); /* i.e., it is 2 or 3 */ - - while (i < pt.num_ints && j < 3) - { - switch (dmy_order[j]) - { - case G_DATE_MONTH: - { - if (pt.num_ints == 2 && pt.month != G_DATE_BAD_MONTH) - { - m = pt.month; - ++j; /* skip months, but don't skip this number */ - continue; - } - else - m = pt.n[i]; - } - break; - case G_DATE_DAY: - { - if (pt.num_ints == 2 && pt.month == G_DATE_BAD_MONTH) - { - day = 1; - ++j; /* skip days, since we may have month/year */ - continue; - } - day = pt.n[i]; - } - break; - case G_DATE_YEAR: - { - y = pt.n[i]; - - if (locale_era_adjust != 0) - { - y += locale_era_adjust; - } - else if (using_twodigit_years && y < 100) - { - guint two = twodigit_start_year % 100; - guint century = (twodigit_start_year / 100) * 100; - - if (y < two) - century += 100; - - y += century; - } - } - break; - default: - break; - } - - ++i; - ++j; - } - - - if (pt.num_ints == 3 && !g_date_valid_dmy (day, m, y)) - { - /* Try YYYY MM DD */ - y = pt.n[0]; - m = pt.n[1]; - day = pt.n[2]; - - if (using_twodigit_years && y < 100) - y = G_DATE_BAD_YEAR; /* avoids ambiguity */ - } - else if (pt.num_ints == 2) - { - if (m == G_DATE_BAD_MONTH && pt.month != G_DATE_BAD_MONTH) - m = pt.month; - } - } - else if (pt.num_ints == 1) - { - if (pt.month != G_DATE_BAD_MONTH) - { - /* Month name and year? */ - m = pt.month; - day = 1; - y = pt.n[0]; - } - else - { - /* Try yyyymmdd and yymmdd */ - - m = (pt.n[0]/100) % 100; - day = pt.n[0] % 100; - y = pt.n[0]/10000; - - /* FIXME move this into a separate function */ - if (using_twodigit_years && y < 100) - { - guint two = twodigit_start_year % 100; - guint century = (twodigit_start_year / 100) * 100; - - if (y < two) - century += 100; - - y += century; - } - } - } - - /* See if we got anything valid out of all this. */ - /* y < 8000 is to catch 19998 style typos; the library is OK up to 65535 or so */ - if (y < 8000 && g_date_valid_dmy (day, m, y)) - { - d->month = m; - d->day = day; - d->year = y; - d->dmy = TRUE; - } -#ifdef G_ENABLE_DEBUG - else - { - DEBUG_MSG (("Rejected DMY %u %u %u", day, m, y)); - } -#endif - G_UNLOCK (g_date_global); -} - -/** - * g_date_set_time_t: - * @date: a #GDate - * @timet: <type>time_t</type> value to set - * - * Sets the value of a date to the date corresponding to a time - * specified as a time_t. The time to date conversion is done using - * the user's current timezone. - * - * To set the value of a date to the current day, you could write: - * |[ - * g_date_set_time_t (date, time (NULL)); - * ]| - * - * Since: 2.10 - */ -void -g_date_set_time_t (GDate *date, - time_t timet) -{ - struct tm tm; - - g_return_if_fail (date != NULL); - -#ifdef HAVE_LOCALTIME_R - localtime_r (&timet, &tm); -#else - { - struct tm *ptm = localtime (&timet); - - if (ptm == NULL) - { - /* Happens at least in Microsoft's C library if you pass a - * negative time_t. Use 2000-01-01 as default date. - */ -#ifndef G_DISABLE_CHECKS - g_return_if_fail_warning (G_LOG_DOMAIN, "g_date_set_time", "ptm != NULL"); -#endif - - tm.tm_mon = 0; - tm.tm_mday = 1; - tm.tm_year = 100; - } - else - memcpy ((void *) &tm, (void *) ptm, sizeof(struct tm)); - } -#endif - - date->julian = FALSE; - - date->month = tm.tm_mon + 1; - date->day = tm.tm_mday; - date->year = tm.tm_year + 1900; - - g_return_if_fail (g_date_valid_dmy (date->day, date->month, date->year)); - - date->dmy = TRUE; -} - - -/** - * g_date_set_time: - * @date: a #GDate. - * @time_: #GTime value to set. - * - * Sets the value of a date from a #GTime value. - * The time to date conversion is done using the user's current timezone. - * - * @Deprecated:2.10: Use g_date_set_time_t() instead. - */ -void -g_date_set_time (GDate *date, - GTime time_) -{ - g_date_set_time_t (date, (time_t) time_); -} - -/** - * g_date_set_time_val: - * @date: a #GDate - * @timeval: #GTimeVal value to set - * - * Sets the value of a date from a #GTimeVal value. Note that the - * @tv_usec member is ignored, because #GDate can't make use of the - * additional precision. - * - * Since: 2.10 - */ -void -g_date_set_time_val (GDate *date, - GTimeVal *timeval) -{ - g_date_set_time_t (date, (time_t) timeval->tv_sec); -} - -void -g_date_set_month (GDate *d, - GDateMonth m) -{ - g_return_if_fail (d != NULL); - g_return_if_fail (g_date_valid_month (m)); - - if (d->julian && !d->dmy) g_date_update_dmy(d); - d->julian = FALSE; - - d->month = m; - - if (g_date_valid_dmy (d->day, d->month, d->year)) - d->dmy = TRUE; - else - d->dmy = FALSE; -} - -void -g_date_set_day (GDate *d, - GDateDay day) -{ - g_return_if_fail (d != NULL); - g_return_if_fail (g_date_valid_day (day)); - - if (d->julian && !d->dmy) g_date_update_dmy(d); - d->julian = FALSE; - - d->day = day; - - if (g_date_valid_dmy (d->day, d->month, d->year)) - d->dmy = TRUE; - else - d->dmy = FALSE; -} - -void -g_date_set_year (GDate *d, - GDateYear y) -{ - g_return_if_fail (d != NULL); - g_return_if_fail (g_date_valid_year (y)); - - if (d->julian && !d->dmy) g_date_update_dmy(d); - d->julian = FALSE; - - d->year = y; - - if (g_date_valid_dmy (d->day, d->month, d->year)) - d->dmy = TRUE; - else - d->dmy = FALSE; -} - -void -g_date_set_dmy (GDate *d, - GDateDay day, - GDateMonth m, - GDateYear y) -{ - g_return_if_fail (d != NULL); - g_return_if_fail (g_date_valid_dmy (day, m, y)); - - d->julian = FALSE; - - d->month = m; - d->day = day; - d->year = y; - - d->dmy = TRUE; -} - -void -g_date_set_julian (GDate *d, - guint32 j) -{ - g_return_if_fail (d != NULL); - g_return_if_fail (g_date_valid_julian (j)); - - d->julian_days = j; - d->julian = TRUE; - d->dmy = FALSE; -} - - -gboolean -g_date_is_first_of_month (const GDate *d) -{ - g_return_val_if_fail (g_date_valid (d), FALSE); - - if (!d->dmy) - g_date_update_dmy (d); - - g_return_val_if_fail (d->dmy, FALSE); - - if (d->day == 1) return TRUE; - else return FALSE; -} - -gboolean -g_date_is_last_of_month (const GDate *d) -{ - gint idx; - - g_return_val_if_fail (g_date_valid (d), FALSE); - - if (!d->dmy) - g_date_update_dmy (d); - - g_return_val_if_fail (d->dmy, FALSE); - - idx = g_date_is_leap_year (d->year) ? 1 : 0; - - if (d->day == days_in_months[idx][d->month]) return TRUE; - else return FALSE; -} - -void -g_date_add_days (GDate *d, - guint ndays) -{ - g_return_if_fail (g_date_valid (d)); - - if (!d->julian) - g_date_update_julian (d); - - g_return_if_fail (d->julian); - - d->julian_days += ndays; - d->dmy = FALSE; -} - -void -g_date_subtract_days (GDate *d, - guint ndays) -{ - g_return_if_fail (g_date_valid (d)); - - if (!d->julian) - g_date_update_julian (d); - - g_return_if_fail (d->julian); - g_return_if_fail (d->julian_days > ndays); - - d->julian_days -= ndays; - d->dmy = FALSE; -} - -void -g_date_add_months (GDate *d, - guint nmonths) -{ - guint years, months; - gint idx; - - g_return_if_fail (g_date_valid (d)); - - if (!d->dmy) - g_date_update_dmy (d); - - g_return_if_fail (d->dmy); - - nmonths += d->month - 1; - - years = nmonths/12; - months = nmonths%12; - - d->month = months + 1; - d->year += years; - - idx = g_date_is_leap_year (d->year) ? 1 : 0; - - if (d->day > days_in_months[idx][d->month]) - d->day = days_in_months[idx][d->month]; - - d->julian = FALSE; - - g_return_if_fail (g_date_valid (d)); -} - -void -g_date_subtract_months (GDate *d, - guint nmonths) -{ - guint years, months; - gint idx; - - g_return_if_fail (g_date_valid (d)); - - if (!d->dmy) - g_date_update_dmy (d); - - g_return_if_fail (d->dmy); - - years = nmonths/12; - months = nmonths%12; - - g_return_if_fail (d->year > years); - - d->year -= years; - - if (d->month > months) d->month -= months; - else - { - months -= d->month; - d->month = 12 - months; - d->year -= 1; - } - - idx = g_date_is_leap_year (d->year) ? 1 : 0; - - if (d->day > days_in_months[idx][d->month]) - d->day = days_in_months[idx][d->month]; - - d->julian = FALSE; - - g_return_if_fail (g_date_valid (d)); -} - -void -g_date_add_years (GDate *d, - guint nyears) -{ - g_return_if_fail (g_date_valid (d)); - - if (!d->dmy) - g_date_update_dmy (d); - - g_return_if_fail (d->dmy); - - d->year += nyears; - - if (d->month == 2 && d->day == 29) - { - if (!g_date_is_leap_year (d->year)) - d->day = 28; - } - - d->julian = FALSE; -} - -void -g_date_subtract_years (GDate *d, - guint nyears) -{ - g_return_if_fail (g_date_valid (d)); - - if (!d->dmy) - g_date_update_dmy (d); - - g_return_if_fail (d->dmy); - g_return_if_fail (d->year > nyears); - - d->year -= nyears; - - if (d->month == 2 && d->day == 29) - { - if (!g_date_is_leap_year (d->year)) - d->day = 28; - } - - d->julian = FALSE; -} - -gboolean -g_date_is_leap_year (GDateYear year) -{ - g_return_val_if_fail (g_date_valid_year (year), FALSE); - - return ( (((year % 4) == 0) && ((year % 100) != 0)) || - (year % 400) == 0 ); -} - -guint8 -g_date_get_days_in_month (GDateMonth month, - GDateYear year) -{ - gint idx; - - g_return_val_if_fail (g_date_valid_year (year), 0); - g_return_val_if_fail (g_date_valid_month (month), 0); - - idx = g_date_is_leap_year (year) ? 1 : 0; - - return days_in_months[idx][month]; -} - -guint8 -g_date_get_monday_weeks_in_year (GDateYear year) -{ - GDate d; - - g_return_val_if_fail (g_date_valid_year (year), 0); - - g_date_clear (&d, 1); - g_date_set_dmy (&d, 1, 1, year); - if (g_date_get_weekday (&d) == G_DATE_MONDAY) return 53; - g_date_set_dmy (&d, 31, 12, year); - if (g_date_get_weekday (&d) == G_DATE_MONDAY) return 53; - if (g_date_is_leap_year (year)) - { - g_date_set_dmy (&d, 2, 1, year); - if (g_date_get_weekday (&d) == G_DATE_MONDAY) return 53; - g_date_set_dmy (&d, 30, 12, year); - if (g_date_get_weekday (&d) == G_DATE_MONDAY) return 53; - } - return 52; -} - -guint8 -g_date_get_sunday_weeks_in_year (GDateYear year) -{ - GDate d; - - g_return_val_if_fail (g_date_valid_year (year), 0); - - g_date_clear (&d, 1); - g_date_set_dmy (&d, 1, 1, year); - if (g_date_get_weekday (&d) == G_DATE_SUNDAY) return 53; - g_date_set_dmy (&d, 31, 12, year); - if (g_date_get_weekday (&d) == G_DATE_SUNDAY) return 53; - if (g_date_is_leap_year (year)) - { - g_date_set_dmy (&d, 2, 1, year); - if (g_date_get_weekday (&d) == G_DATE_SUNDAY) return 53; - g_date_set_dmy (&d, 30, 12, year); - if (g_date_get_weekday (&d) == G_DATE_SUNDAY) return 53; - } - return 52; -} - -gint -g_date_compare (const GDate *lhs, - const GDate *rhs) -{ - g_return_val_if_fail (lhs != NULL, 0); - g_return_val_if_fail (rhs != NULL, 0); - g_return_val_if_fail (g_date_valid (lhs), 0); - g_return_val_if_fail (g_date_valid (rhs), 0); - - /* Remember the self-comparison case! I think it works right now. */ - - while (TRUE) - { - if (lhs->julian && rhs->julian) - { - if (lhs->julian_days < rhs->julian_days) return -1; - else if (lhs->julian_days > rhs->julian_days) return 1; - else return 0; - } - else if (lhs->dmy && rhs->dmy) - { - if (lhs->year < rhs->year) return -1; - else if (lhs->year > rhs->year) return 1; - else - { - if (lhs->month < rhs->month) return -1; - else if (lhs->month > rhs->month) return 1; - else - { - if (lhs->day < rhs->day) return -1; - else if (lhs->day > rhs->day) return 1; - else return 0; - } - - } - - } - else - { - if (!lhs->julian) g_date_update_julian (lhs); - if (!rhs->julian) g_date_update_julian (rhs); - g_return_val_if_fail (lhs->julian, 0); - g_return_val_if_fail (rhs->julian, 0); - } - - } - return 0; /* warnings */ -} - - -void -g_date_to_struct_tm (const GDate *d, - struct tm *tm) -{ - GDateWeekday day; - - g_return_if_fail (g_date_valid (d)); - g_return_if_fail (tm != NULL); - - if (!d->dmy) - g_date_update_dmy (d); - - g_return_if_fail (d->dmy); - - /* zero all the irrelevant fields to be sure they're valid */ - - /* On Linux and maybe other systems, there are weird non-POSIX - * fields on the end of struct tm that choke strftime if they - * contain garbage. So we need to 0 the entire struct, not just the - * fields we know to exist. - */ - - memset (tm, 0x0, sizeof (struct tm)); - - tm->tm_mday = d->day; - tm->tm_mon = d->month - 1; /* 0-11 goes in tm */ - tm->tm_year = ((int)d->year) - 1900; /* X/Open says tm_year can be negative */ - - day = g_date_get_weekday (d); - if (day == 7) day = 0; /* struct tm wants days since Sunday, so Sunday is 0 */ - - tm->tm_wday = (int)day; - - tm->tm_yday = g_date_get_day_of_year (d) - 1; /* 0 to 365 */ - tm->tm_isdst = -1; /* -1 means "information not available" */ -} - -void -g_date_clamp (GDate *date, - const GDate *min_date, - const GDate *max_date) -{ - g_return_if_fail (g_date_valid (date)); - - if (min_date != NULL) - g_return_if_fail (g_date_valid (min_date)); - - if (max_date != NULL) - g_return_if_fail (g_date_valid (max_date)); - - if (min_date != NULL && max_date != NULL) - g_return_if_fail (g_date_compare (min_date, max_date) <= 0); - - if (min_date && g_date_compare (date, min_date) < 0) - *date = *min_date; - - if (max_date && g_date_compare (max_date, date) < 0) - *date = *max_date; -} - -void -g_date_order (GDate *date1, - GDate *date2) -{ - g_return_if_fail (g_date_valid (date1)); - g_return_if_fail (g_date_valid (date2)); - - if (g_date_compare (date1, date2) > 0) - { - GDate tmp = *date1; - *date1 = *date2; - *date2 = tmp; - } -} - -#ifdef G_OS_WIN32 -static gsize -win32_strftime_helper (const GDate *d, - const gchar *format, - const struct tm *tm, - gchar *s, - gsize slen) -{ - SYSTEMTIME systemtime; - TIME_ZONE_INFORMATION tzinfo; - LCID lcid; - int n, k; - GArray *result; - const gchar *p; - gunichar c; - const wchar_t digits[] = L"0123456789"; - gchar *convbuf; - glong convlen = 0; - gsize retval; - - systemtime.wYear = tm->tm_year + 1900; - systemtime.wMonth = tm->tm_mon + 1; - systemtime.wDayOfWeek = tm->tm_wday; - systemtime.wDay = tm->tm_mday; - systemtime.wHour = tm->tm_hour; - systemtime.wMinute = tm->tm_min; - systemtime.wSecond = tm->tm_sec; - systemtime.wMilliseconds = 0; - - lcid = GetThreadLocale (); - result = g_array_sized_new (FALSE, FALSE, sizeof (wchar_t), MAX (128, strlen (format) * 2)); - - p = format; - while (*p) - { - c = g_utf8_get_char (p); - if (c == '%') - { - p = g_utf8_next_char (p); - if (!*p) - { - s[0] = '\0'; - g_array_free (result, TRUE); - - return 0; - } - - c = g_utf8_get_char (p); - if (c == 'E' || c == 'O') - { - /* Ignore modified conversion specifiers for now. */ - p = g_utf8_next_char (p); - if (!*p) - { - s[0] = '\0'; - g_array_free (result, TRUE); - - return 0; - } - - c = g_utf8_get_char (p); - } - - switch (c) - { - case 'a': - if (systemtime.wDayOfWeek == 0) - k = 6; - else - k = systemtime.wDayOfWeek - 1; - n = GetLocaleInfoW (lcid, LOCALE_SABBREVDAYNAME1+k, NULL, 0); - g_array_set_size (result, result->len + n); - GetLocaleInfoW (lcid, LOCALE_SABBREVDAYNAME1+k, ((wchar_t *) result->data) + result->len - n, n); - g_array_set_size (result, result->len - 1); - break; - case 'A': - if (systemtime.wDayOfWeek == 0) - k = 6; - else - k = systemtime.wDayOfWeek - 1; - n = GetLocaleInfoW (lcid, LOCALE_SDAYNAME1+k, NULL, 0); - g_array_set_size (result, result->len + n); - GetLocaleInfoW (lcid, LOCALE_SDAYNAME1+k, ((wchar_t *) result->data) + result->len - n, n); - g_array_set_size (result, result->len - 1); - break; - case 'b': - case 'h': - n = GetLocaleInfoW (lcid, LOCALE_SABBREVMONTHNAME1+systemtime.wMonth-1, NULL, 0); - g_array_set_size (result, result->len + n); - GetLocaleInfoW (lcid, LOCALE_SABBREVMONTHNAME1+systemtime.wMonth-1, ((wchar_t *) result->data) + result->len - n, n); - g_array_set_size (result, result->len - 1); - break; - case 'B': - n = GetLocaleInfoW (lcid, LOCALE_SMONTHNAME1+systemtime.wMonth-1, NULL, 0); - g_array_set_size (result, result->len + n); - GetLocaleInfoW (lcid, LOCALE_SMONTHNAME1+systemtime.wMonth-1, ((wchar_t *) result->data) + result->len - n, n); - g_array_set_size (result, result->len - 1); - break; - case 'c': - n = GetDateFormatW (lcid, 0, &systemtime, NULL, NULL, 0); - if (n > 0) - { - g_array_set_size (result, result->len + n); - GetDateFormatW (lcid, 0, &systemtime, NULL, ((wchar_t *) result->data) + result->len - n, n); - g_array_set_size (result, result->len - 1); - } - g_array_append_vals (result, L" ", 1); - n = GetTimeFormatW (lcid, 0, &systemtime, NULL, NULL, 0); - if (n > 0) - { - g_array_set_size (result, result->len + n); - GetTimeFormatW (lcid, 0, &systemtime, NULL, ((wchar_t *) result->data) + result->len - n, n); - g_array_set_size (result, result->len - 1); - } - break; - case 'C': - g_array_append_vals (result, digits + systemtime.wYear/1000, 1); - g_array_append_vals (result, digits + (systemtime.wYear/1000)%10, 1); - break; - case 'd': - g_array_append_vals (result, digits + systemtime.wDay/10, 1); - g_array_append_vals (result, digits + systemtime.wDay%10, 1); - break; - case 'D': - g_array_append_vals (result, digits + systemtime.wMonth/10, 1); - g_array_append_vals (result, digits + systemtime.wMonth%10, 1); - g_array_append_vals (result, L"/", 1); - g_array_append_vals (result, digits + systemtime.wDay/10, 1); - g_array_append_vals (result, digits + systemtime.wDay%10, 1); - g_array_append_vals (result, L"/", 1); - g_array_append_vals (result, digits + (systemtime.wYear/10)%10, 1); - g_array_append_vals (result, digits + systemtime.wYear%10, 1); - break; - case 'e': - if (systemtime.wDay >= 10) - g_array_append_vals (result, digits + systemtime.wDay/10, 1); - else - g_array_append_vals (result, L" ", 1); - g_array_append_vals (result, digits + systemtime.wDay%10, 1); - break; - - /* A GDate has no time fields, so for now we can - * hardcode all time conversions into zeros (or 12 for - * %I). The alternative code snippets in the #else - * branches are here ready to be taken into use when - * needed by a g_strftime() or g_date_and_time_format() - * or whatever. - */ - case 'H': -#if 1 - g_array_append_vals (result, L"00", 2); -#else - g_array_append_vals (result, digits + systemtime.wHour/10, 1); - g_array_append_vals (result, digits + systemtime.wHour%10, 1); -#endif - break; - case 'I': -#if 1 - g_array_append_vals (result, L"12", 2); -#else - if (systemtime.wHour == 0) - g_array_append_vals (result, L"12", 2); - else - { - g_array_append_vals (result, digits + (systemtime.wHour%12)/10, 1); - g_array_append_vals (result, digits + (systemtime.wHour%12)%10, 1); - } -#endif - break; - case 'j': - g_array_append_vals (result, digits + (tm->tm_yday+1)/100, 1); - g_array_append_vals (result, digits + ((tm->tm_yday+1)/10)%10, 1); - g_array_append_vals (result, digits + (tm->tm_yday+1)%10, 1); - break; - case 'm': - g_array_append_vals (result, digits + systemtime.wMonth/10, 1); - g_array_append_vals (result, digits + systemtime.wMonth%10, 1); - break; - case 'M': -#if 1 - g_array_append_vals (result, L"00", 2); -#else - g_array_append_vals (result, digits + systemtime.wMinute/10, 1); - g_array_append_vals (result, digits + systemtime.wMinute%10, 1); -#endif - break; - case 'n': - g_array_append_vals (result, L"\n", 1); - break; - case 'p': - n = GetTimeFormatW (lcid, 0, &systemtime, L"tt", NULL, 0); - if (n > 0) - { - g_array_set_size (result, result->len + n); - GetTimeFormatW (lcid, 0, &systemtime, L"tt", ((wchar_t *) result->data) + result->len - n, n); - g_array_set_size (result, result->len - 1); - } - break; - case 'r': - /* This is a rather odd format. Hard to say what to do. - * Let's always use the POSIX %I:%M:%S %p - */ -#if 1 - g_array_append_vals (result, L"12:00:00", 8); -#else - if (systemtime.wHour == 0) - g_array_append_vals (result, L"12", 2); - else - { - g_array_append_vals (result, digits + (systemtime.wHour%12)/10, 1); - g_array_append_vals (result, digits + (systemtime.wHour%12)%10, 1); - } - g_array_append_vals (result, L":", 1); - g_array_append_vals (result, digits + systemtime.wMinute/10, 1); - g_array_append_vals (result, digits + systemtime.wMinute%10, 1); - g_array_append_vals (result, L":", 1); - g_array_append_vals (result, digits + systemtime.wSecond/10, 1); - g_array_append_vals (result, digits + systemtime.wSecond%10, 1); - g_array_append_vals (result, L" ", 1); -#endif - n = GetTimeFormatW (lcid, 0, &systemtime, L"tt", NULL, 0); - if (n > 0) - { - g_array_set_size (result, result->len + n); - GetTimeFormatW (lcid, 0, &systemtime, L"tt", ((wchar_t *) result->data) + result->len - n, n); - g_array_set_size (result, result->len - 1); - } - break; - case 'R': -#if 1 - g_array_append_vals (result, L"00:00", 5); -#else - g_array_append_vals (result, digits + systemtime.wHour/10, 1); - g_array_append_vals (result, digits + systemtime.wHour%10, 1); - g_array_append_vals (result, L":", 1); - g_array_append_vals (result, digits + systemtime.wMinute/10, 1); - g_array_append_vals (result, digits + systemtime.wMinute%10, 1); -#endif - break; - case 'S': -#if 1 - g_array_append_vals (result, L"00", 2); -#else - g_array_append_vals (result, digits + systemtime.wSecond/10, 1); - g_array_append_vals (result, digits + systemtime.wSecond%10, 1); -#endif - break; - case 't': - g_array_append_vals (result, L"\t", 1); - break; - case 'T': -#if 1 - g_array_append_vals (result, L"00:00:00", 8); -#else - g_array_append_vals (result, digits + systemtime.wHour/10, 1); - g_array_append_vals (result, digits + systemtime.wHour%10, 1); - g_array_append_vals (result, L":", 1); - g_array_append_vals (result, digits + systemtime.wMinute/10, 1); - g_array_append_vals (result, digits + systemtime.wMinute%10, 1); - g_array_append_vals (result, L":", 1); - g_array_append_vals (result, digits + systemtime.wSecond/10, 1); - g_array_append_vals (result, digits + systemtime.wSecond%10, 1); -#endif - break; - case 'u': - if (systemtime.wDayOfWeek == 0) - g_array_append_vals (result, L"7", 1); - else - g_array_append_vals (result, digits + systemtime.wDayOfWeek, 1); - break; - case 'U': - n = g_date_get_sunday_week_of_year (d); - g_array_append_vals (result, digits + n/10, 1); - g_array_append_vals (result, digits + n%10, 1); - break; - case 'V': - n = g_date_get_iso8601_week_of_year (d); - g_array_append_vals (result, digits + n/10, 1); - g_array_append_vals (result, digits + n%10, 1); - break; - case 'w': - g_array_append_vals (result, digits + systemtime.wDayOfWeek, 1); - break; - case 'W': - n = g_date_get_monday_week_of_year (d); - g_array_append_vals (result, digits + n/10, 1); - g_array_append_vals (result, digits + n%10, 1); - break; - case 'x': - n = GetDateFormatW (lcid, 0, &systemtime, NULL, NULL, 0); - if (n > 0) - { - g_array_set_size (result, result->len + n); - GetDateFormatW (lcid, 0, &systemtime, NULL, ((wchar_t *) result->data) + result->len - n, n); - g_array_set_size (result, result->len - 1); - } - break; - case 'X': - n = GetTimeFormatW (lcid, 0, &systemtime, NULL, NULL, 0); - if (n > 0) - { - g_array_set_size (result, result->len + n); - GetTimeFormatW (lcid, 0, &systemtime, NULL, ((wchar_t *) result->data) + result->len - n, n); - g_array_set_size (result, result->len - 1); - } - break; - case 'y': - g_array_append_vals (result, digits + (systemtime.wYear/10)%10, 1); - g_array_append_vals (result, digits + systemtime.wYear%10, 1); - break; - case 'Y': - g_array_append_vals (result, digits + systemtime.wYear/1000, 1); - g_array_append_vals (result, digits + (systemtime.wYear/100)%10, 1); - g_array_append_vals (result, digits + (systemtime.wYear/10)%10, 1); - g_array_append_vals (result, digits + systemtime.wYear%10, 1); - break; - case 'Z': - n = GetTimeZoneInformation (&tzinfo); - if (n == TIME_ZONE_ID_UNKNOWN) - ; - else if (n == TIME_ZONE_ID_STANDARD) - g_array_append_vals (result, tzinfo.StandardName, wcslen (tzinfo.StandardName)); - else if (n == TIME_ZONE_ID_DAYLIGHT) - g_array_append_vals (result, tzinfo.DaylightName, wcslen (tzinfo.DaylightName)); - break; - case '%': - g_array_append_vals (result, L"%", 1); - break; - } - } - else if (c <= 0xFFFF) - { - wchar_t wc = c; - g_array_append_vals (result, &wc, 1); - } - else - { - glong nwc; - wchar_t *ws; - - ws = g_ucs4_to_utf16 (&c, 1, NULL, &nwc, NULL); - g_array_append_vals (result, ws, nwc); - g_free (ws); - } - p = g_utf8_next_char (p); - } - - convbuf = g_utf16_to_utf8 ((wchar_t *) result->data, result->len, NULL, &convlen, NULL); - g_array_free (result, TRUE); - - if (!convbuf) - { - s[0] = '\0'; - return 0; - } - - if (slen <= convlen) - { - /* Ensure only whole characters are copied into the buffer. */ - gchar *end = g_utf8_find_prev_char (convbuf, convbuf + slen); - g_assert (end != NULL); - convlen = end - convbuf; - - /* Return 0 because the buffer isn't large enough. */ - retval = 0; - } - else - retval = convlen; - - memcpy (s, convbuf, convlen); - s[convlen] = '\0'; - g_free (convbuf); - - return retval; -} - -#endif - -gsize -g_date_strftime (gchar *s, - gsize slen, - const gchar *format, - const GDate *d) -{ - struct tm tm; -#ifndef G_OS_WIN32 - gsize locale_format_len = 0; - gchar *locale_format; - gsize tmplen; - gchar *tmpbuf; - gsize tmpbufsize; - gsize convlen = 0; - gchar *convbuf; - GError *error = NULL; - gsize retval; -#endif - - g_return_val_if_fail (g_date_valid (d), 0); - g_return_val_if_fail (slen > 0, 0); - g_return_val_if_fail (format != NULL, 0); - g_return_val_if_fail (s != NULL, 0); - - g_date_to_struct_tm (d, &tm); - -#ifdef G_OS_WIN32 - if (!g_utf8_validate (format, -1, NULL)) - { - s[0] = '\0'; - return 0; - } - return win32_strftime_helper (d, format, &tm, s, slen); -#else - - locale_format = g_locale_from_utf8 (format, -1, NULL, &locale_format_len, &error); - - if (error) - { - g_warning (G_STRLOC "Error converting format to locale encoding: %s\n", error->message); - g_error_free (error); - - s[0] = '\0'; - return 0; - } - - tmpbufsize = MAX (128, locale_format_len * 2); - while (TRUE) - { - tmpbuf = g_malloc (tmpbufsize); - - /* Set the first byte to something other than '\0', to be able to - * recognize whether strftime actually failed or just returned "". - */ - tmpbuf[0] = '\1'; - tmplen = strftime (tmpbuf, tmpbufsize, locale_format, &tm); - - if (tmplen == 0 && tmpbuf[0] != '\0') - { - g_free (tmpbuf); - tmpbufsize *= 2; - - if (tmpbufsize > 65536) - { - g_warning (G_STRLOC "Maximum buffer size for g_date_strftime exceeded: giving up\n"); - g_free (locale_format); - - s[0] = '\0'; - return 0; - } - } - else - break; - } - g_free (locale_format); - - convbuf = g_locale_to_utf8 (tmpbuf, tmplen, NULL, &convlen, &error); - g_free (tmpbuf); - - if (error) - { - g_warning (G_STRLOC "Error converting results of strftime to UTF-8: %s\n", error->message); - g_error_free (error); - - s[0] = '\0'; - return 0; - } - - if (slen <= convlen) - { - /* Ensure only whole characters are copied into the buffer. - */ - gchar *end = g_utf8_find_prev_char (convbuf, convbuf + slen); - g_assert (end != NULL); - convlen = end - convbuf; - - /* Return 0 because the buffer isn't large enough. - */ - retval = 0; - } - else - retval = convlen; - - memcpy (s, convbuf, convlen); - s[convlen] = '\0'; - g_free (convbuf); - - return retval; -#endif -} - -#define __G_DATE_C__ -#include "galiasdef.c" - diff --git a/glib/gen-script-table.pl b/glib/gen-script-table.pl deleted file mode 100755 index 27268ab84..000000000 --- a/glib/gen-script-table.pl +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/perl -w -# -# Script to convert http://www.unicode.org/Public/UNIDATA/Scripts.txt -# into a machine-readable table. -# -###################################################################### - -if (@ARGV != 1) { - die "Usage: gen-script-table.pl Scripts.txt > gscripttable.h\n"; -} - -open IN, $ARGV[0] || die "Cannot open $ARGV[0]: $!\n"; - -my @ranges; -my $file; -my $easy_range; -my $i; -my $start; -my $end; -my $script; - - -while (<IN>) { - if (/^\#\s+(Scripts-.*.txt)/) { - $file = $1; - } - - s/#.*//; - next if /^\s*$/; - if (!/^([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s*;\s*([A-Za-z_]+)\s*$/) { - die "Cannot parse line: '$_'\n"; - } - - if (defined $2) { - push @ranges, [ hex $1, hex $2, uc $3 ]; - } else { - push @ranges, [ hex $1, hex $1, uc $3 ]; - } -} - -@ranges = sort { $a->[0] <=> $b->[0] } @ranges; -$date = gmtime; - -print <<"EOT"; -/* gscripttable.h: Generated by gen-script-table.pl - * - * Date: $date - * Source: $file - * - * Do not edit. - */ - -EOT - -$easy_range = 0x2000; - -print <<"EOT"; -#define G_EASY_SCRIPTS_RANGE $easy_range - -static const guchar g_script_easy_table[$easy_range] = { -EOT - -$i = 0; -$end = -1; - -for (my $c = 0; $c < $easy_range; $c++) { - - if ($c % 3 == 0) { - printf "\n "; - } - - if ($c > $end) { - $start = $ranges[$i]->[0]; - $end = $ranges[$i]->[1]; - $script = $ranges[$i]->[2]; - $i++; - } - - if ($c < $start) { - printf " G_UNICODE_SCRIPT_UNKNOWN,"; - } else { - printf " G_UNICODE_SCRIPT_%s,", $script; - } -} - -if ($end >= $easy_range) { - $i--; - $ranges[$i]->[0] = $easy_range; -} - - -print <<"EOT"; - -}; - -static const struct { - gunichar start; - guint16 chars; - guint16 script; -} g_script_table[] = { -EOT - -for (; $i <= $#ranges; $i++) { - $start = $ranges[$i]->[0]; - $end = $ranges[$i]->[1]; - $script = $ranges[$i]->[2]; - - while ($i <= $#ranges - 1 && - $ranges[$i + 1]->[0] == $end + 1 && - $ranges[$i + 1]->[2] eq $script) { - $i++; - $end = $ranges[$i]->[1]; - } - - printf " { %#06x, %5d, G_UNICODE_SCRIPT_%s },\n", $start, $end - $start + 1, $script; -} - -printf "};\n"; - diff --git a/glib/gen-unicode-tables.pl b/glib/gen-unicode-tables.pl deleted file mode 100755 index 5368adfc6..000000000 --- a/glib/gen-unicode-tables.pl +++ /dev/null @@ -1,1303 +0,0 @@ -#! /usr/bin/perl -w - -# Copyright (C) 1998, 1999 Tom Tromey -# Copyright (C) 2001 Red Hat Software - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. - -# This program 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 General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -# 02111-1307, USA. - -# Contributer(s): -# Andrew Taylor <andrew.taylor@montage.ca> - -# gen-unicode-tables.pl - Generate tables for libunicode from Unicode data. -# See http://www.unicode.org/Public/UNIDATA/UnicodeCharacterDatabase.html -# I consider the output of this program to be unrestricted. Use it as -# you will. - -# FIXME: -# * For decomp table it might make sense to use a shift count other -# than 8. We could easily compute the perfect shift count. - -# we use some perl unicode features -require 5.006; - -use vars qw($CODE $NAME $CATEGORY $COMBINING_CLASSES $BIDI_CATEGORY $DECOMPOSITION $DECIMAL_VALUE $DIGIT_VALUE $NUMERIC_VALUE $MIRRORED $OLD_NAME $COMMENT $UPPER $LOWER $TITLE $BREAK_CODE $BREAK_CATEGORY $BREAK_NAME $CASE_CODE $CASE_LOWER $CASE_TITLE $CASE_UPPER $CASE_CONDITION); - - -# Names of fields in Unicode data table. -$CODE = 0; -$NAME = 1; -$CATEGORY = 2; -$COMBINING_CLASSES = 3; -$BIDI_CATEGORY = 4; -$DECOMPOSITION = 5; -$DECIMAL_VALUE = 6; -$DIGIT_VALUE = 7; -$NUMERIC_VALUE = 8; -$MIRRORED = 9; -$OLD_NAME = 10; -$COMMENT = 11; -$UPPER = 12; -$LOWER = 13; -$TITLE = 14; - -# Names of fields in the line break table -$BREAK_CODE = 0; -$BREAK_PROPERTY = 1; - -# Names of fields in the SpecialCasing table -$CASE_CODE = 0; -$CASE_LOWER = 1; -$CASE_TITLE = 2; -$CASE_UPPER = 3; -$CASE_CONDITION = 4; - -# Names of fields in the CaseFolding table -$FOLDING_CODE = 0; -$FOLDING_STATUS = 1; -$FOLDING_MAPPING = 2; - -# Map general category code onto symbolic name. -%mappings = - ( - # Normative. - 'Lu' => "G_UNICODE_UPPERCASE_LETTER", - 'Ll' => "G_UNICODE_LOWERCASE_LETTER", - 'Lt' => "G_UNICODE_TITLECASE_LETTER", - 'Mn' => "G_UNICODE_NON_SPACING_MARK", - 'Mc' => "G_UNICODE_COMBINING_MARK", - 'Me' => "G_UNICODE_ENCLOSING_MARK", - 'Nd' => "G_UNICODE_DECIMAL_NUMBER", - 'Nl' => "G_UNICODE_LETTER_NUMBER", - 'No' => "G_UNICODE_OTHER_NUMBER", - 'Zs' => "G_UNICODE_SPACE_SEPARATOR", - 'Zl' => "G_UNICODE_LINE_SEPARATOR", - 'Zp' => "G_UNICODE_PARAGRAPH_SEPARATOR", - 'Cc' => "G_UNICODE_CONTROL", - 'Cf' => "G_UNICODE_FORMAT", - 'Cs' => "G_UNICODE_SURROGATE", - 'Co' => "G_UNICODE_PRIVATE_USE", - 'Cn' => "G_UNICODE_UNASSIGNED", - - # Informative. - 'Lm' => "G_UNICODE_MODIFIER_LETTER", - 'Lo' => "G_UNICODE_OTHER_LETTER", - 'Pc' => "G_UNICODE_CONNECT_PUNCTUATION", - 'Pd' => "G_UNICODE_DASH_PUNCTUATION", - 'Ps' => "G_UNICODE_OPEN_PUNCTUATION", - 'Pe' => "G_UNICODE_CLOSE_PUNCTUATION", - 'Pi' => "G_UNICODE_INITIAL_PUNCTUATION", - 'Pf' => "G_UNICODE_FINAL_PUNCTUATION", - 'Po' => "G_UNICODE_OTHER_PUNCTUATION", - 'Sm' => "G_UNICODE_MATH_SYMBOL", - 'Sc' => "G_UNICODE_CURRENCY_SYMBOL", - 'Sk' => "G_UNICODE_MODIFIER_SYMBOL", - 'So' => "G_UNICODE_OTHER_SYMBOL" - ); - -%break_mappings = - ( - 'BK' => "G_UNICODE_BREAK_MANDATORY", - 'CR' => "G_UNICODE_BREAK_CARRIAGE_RETURN", - 'LF' => "G_UNICODE_BREAK_LINE_FEED", - 'CM' => "G_UNICODE_BREAK_COMBINING_MARK", - 'SG' => "G_UNICODE_BREAK_SURROGATE", - 'ZW' => "G_UNICODE_BREAK_ZERO_WIDTH_SPACE", - 'IN' => "G_UNICODE_BREAK_INSEPARABLE", - 'GL' => "G_UNICODE_BREAK_NON_BREAKING_GLUE", - 'CB' => "G_UNICODE_BREAK_CONTINGENT", - 'SP' => "G_UNICODE_BREAK_SPACE", - 'BA' => "G_UNICODE_BREAK_AFTER", - 'BB' => "G_UNICODE_BREAK_BEFORE", - 'B2' => "G_UNICODE_BREAK_BEFORE_AND_AFTER", - 'HY' => "G_UNICODE_BREAK_HYPHEN", - 'NS' => "G_UNICODE_BREAK_NON_STARTER", - 'OP' => "G_UNICODE_BREAK_OPEN_PUNCTUATION", - 'CL' => "G_UNICODE_BREAK_CLOSE_PUNCTUATION", - 'QU' => "G_UNICODE_BREAK_QUOTATION", - 'EX' => "G_UNICODE_BREAK_EXCLAMATION", - 'ID' => "G_UNICODE_BREAK_IDEOGRAPHIC", - 'NU' => "G_UNICODE_BREAK_NUMERIC", - 'IS' => "G_UNICODE_BREAK_INFIX_SEPARATOR", - 'SY' => "G_UNICODE_BREAK_SYMBOL", - 'AL' => "G_UNICODE_BREAK_ALPHABETIC", - 'PR' => "G_UNICODE_BREAK_PREFIX", - 'PO' => "G_UNICODE_BREAK_POSTFIX", - 'SA' => "G_UNICODE_BREAK_COMPLEX_CONTEXT", - 'AI' => "G_UNICODE_BREAK_AMBIGUOUS", - 'NL' => "G_UNICODE_BREAK_NEXT_LINE", - 'WJ' => "G_UNICODE_BREAK_WORD_JOINER", - 'XX' => "G_UNICODE_BREAK_UNKNOWN", - 'JL' => "G_UNICODE_BREAK_HANGUL_L_JAMO", - 'JV' => "G_UNICODE_BREAK_HANGUL_V_JAMO", - 'JT' => "G_UNICODE_BREAK_HANGUL_T_JAMO", - 'H2' => "G_UNICODE_BREAK_HANGUL_LV_SYLLABLE", - 'H3' => "G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE" - ); - -# Title case mappings. -%title_to_lower = (); -%title_to_upper = (); - -# Maximum length of special-case strings - -my @special_cases; -my @special_case_offsets; -my $special_case_offset = 0; - -$do_decomp = 0; -$do_props = 1; -if (@ARGV && $ARGV[0] eq '-decomp') -{ - $do_decomp = 1; - $do_props = 0; - shift @ARGV; -} -elsif (@ARGV && $ARGV[0] eq '-both') -{ - $do_decomp = 1; - shift @ARGV; -} - -if (@ARGV != 2) { - $0 =~ s@.*/@@; - die "\nUsage: $0 [-decomp | -both] UNICODE-VERSION DIRECTORY\n\n DIRECTORY should contain the following Unicode data files:\n UnicodeData.txt, LineBreak.txt, SpecialCasing.txt, CaseFolding.txt,\n CompositionExclusions.txt, BidiMirroring.txt\n\n"; -} - -my ($unicodedatatxt, $linebreaktxt, $specialcasingtxt, $casefoldingtxt, $compositionexclusionstxt); - -my $d = $ARGV[1]; -opendir (my $dir, $d) or die "Cannot open Unicode data dir $d: $!\n"; -for my $f (readdir ($dir)) -{ - $unicodedatatxt = "$d/$f" if ($f =~ /UnicodeData.*\.txt/); - $linebreaktxt = "$d/$f" if ($f =~ /LineBreak.*\.txt/); - $specialcasingtxt = "$d/$f" if ($f =~ /SpecialCasing.*\.txt/); - $casefoldingtxt = "$d/$f" if ($f =~ /CaseFolding.*\.txt/); - $compositionexclusionstxt = "$d/$f" if ($f =~ /CompositionExclusions.*\.txt/); -} - -defined $unicodedatatxt or die "Did not find UnicodeData file"; -defined $linebreaktxt or die "Did not find LineBreak file"; -defined $specialcasingtxt or die "Did not find SpecialCasing file"; -defined $casefoldingtxt or die "Did not find CaseFolding file"; -defined $compositionexclusionstxt or die "Did not find CompositionExclusions file"; - -print "Creating decomp table\n" if ($do_decomp); -print "Creating property table\n" if ($do_props); - -print "Composition exlusions from $compositionexclusionstxt\n"; - -open (INPUT, "< $compositionexclusionstxt") || exit 1; - -while (<INPUT>) { - - chop; - - next if /^#/; - next if /^\s*$/; - - s/\s*#.*//; - - s/^\s*//; - s/\s*$//; - - $composition_exclusions{hex($_)} = 1; -} - -close INPUT; - -print "Unicode data from $unicodedatatxt\n"; - -open (INPUT, "< $unicodedatatxt") || exit 1; - -# we save memory by skipping the huge empty area before U+E0000 -my $pages_before_e0000; - -$last_code = -1; -while (<INPUT>) -{ - chop; - @fields = split (';', $_, 30); - if ($#fields != 14) - { - printf STDERR ("Entry for $fields[$CODE] has wrong number of fields (%d)\n", $#fields); - } - - $code = hex ($fields[$CODE]); - - if ($code >= 0xE0000 and $last_code < 0xE0000) - { - $pages_before_e0000 = ($last_code >> 8) + 1; - } - - if ($code > $last_code + 1) - { - # Found a gap. - if ($fields[$NAME] =~ /Last>/) - { - # Fill the gap with the last character read, - # since this was a range specified in the char database - @gfields = @fields; - } - else - { - # The gap represents undefined characters. Only the type - # matters. - @gfields = ('', '', 'Cn', '0', '', '', '', '', '', '', '', - '', '', '', ''); - } - for (++$last_code; $last_code < $code; ++$last_code) - { - $gfields{$CODE} = sprintf ("%04x", $last_code); - &process_one ($last_code, @gfields); - } - } - &process_one ($code, @fields); - $last_code = $code; -} - -close INPUT; - -@gfields = ('', '', 'Cn', '0', '', '', '', '', '', '', '', - '', '', '', ''); -for (++$last_code; $last_code <= 0x10FFFF; ++$last_code) -{ - $gfields{$CODE} = sprintf ("%04x", $last_code); - &process_one ($last_code, @gfields); -} ---$last_code; # Want last to be 0x10FFFF. - -print "Creating line break table\n"; - -print "Line break data from $linebreaktxt\n"; - -open (INPUT, "< $linebreaktxt") || exit 1; - -$last_code = -1; -while (<INPUT>) -{ - my ($start_code, $end_code); - - chop; - - next if /^#/; - - s/\s*#.*//; - - @fields = split (';', $_, 30); - if ($#fields != 1) - { - printf STDERR ("Entry for $fields[$CODE] has wrong number of fields (%d)\n", $#fields); - next; - } - - if ($fields[$CODE] =~ /([A-F0-9]{4,6})\.\.([A-F0-9]{4,6})/) - { - $start_code = hex ($1); - $end_code = hex ($2); - } else { - $start_code = $end_code = hex ($fields[$CODE]); - - } - - if ($start_code > $last_code + 1) - { - # The gap represents undefined characters. If assigned, - # they are AL, if not assigned, XX - for (++$last_code; $last_code < $start_code; ++$last_code) - { - if ($type[$last_code] eq 'Cn') - { - $break_props[$last_code] = 'XX'; - } - else - { - $break_props[$last_code] = 'AL'; - } - } - } - - for ($last_code = $start_code; $last_code <= $end_code; $last_code++) - { - $break_props[$last_code] = $fields[$BREAK_PROPERTY]; - } - - $last_code = $end_code; -} - -close INPUT; - -for (++$last_code; $last_code <= 0x10FFFF; ++$last_code) -{ - if ($type[$last_code] eq 'Cn') - { - $break_props[$last_code] = 'XX'; - } - else - { - $break_props[$last_code] = 'AL'; - } -} ---$last_code; # Want last to be 0x10FFFF. - -print STDERR "Last code is not 0x10FFFF" if ($last_code != 0x10FFFF); - -print "Reading special-casing table for case conversion\n"; - -open (INPUT, "< $specialcasingtxt") || exit 1; - -while (<INPUT>) -{ - my $code; - - chop; - - next if /^#/; - next if /^\s*$/; - - s/\s*#.*//; - - @fields = split ('\s*;\s*', $_, 30); - - $raw_code = $fields[$CASE_CODE]; - $code = hex ($raw_code); - - if ($#fields != 4 && $#fields != 5) - { - printf STDERR ("Entry for $raw_code has wrong number of fields (%d)\n", $#fields); - next; - } - - if (!defined $type[$code]) - { - printf STDERR "Special case for code point: $code, which has no defined type\n"; - next; - } - - if (defined $fields[5]) { - # Ignore conditional special cases - we'll handle them in code - next; - } - - if ($type[$code] eq 'Lu') - { - (hex $fields[$CASE_UPPER] == $code) || die "$raw_code is Lu and UCD_Upper($raw_code) != $raw_code"; - - &add_special_case ($code, $value[$code], $fields[$CASE_LOWER], $fields[$CASE_TITLE]); - - } elsif ($type[$code] eq 'Lt') - { - (hex $fields[$CASE_TITLE] == $code) || die "$raw_code is Lt and UCD_Title($raw_code) != $raw_code"; - - &add_special_case ($code, undef, $fields[$CASE_LOWER], $fields[$CASE_UPPER]); - } elsif ($type[$code] eq 'Ll') - { - (hex $fields[$CASE_LOWER] == $code) || die "$raw_code is Ll and UCD_Lower($raw_code) != $raw_code"; - - &add_special_case ($code, $value[$code], $fields[$CASE_UPPER], $fields[$CASE_TITLE]); - } else { - printf STDERR "Special case for non-alphabetic code point: $raw_code\n"; - next; - } -} - -close INPUT; - -open (INPUT, "< $casefoldingtxt") || exit 1; - -my $casefoldlen = 0; -my @casefold; - -while (<INPUT>) -{ - my $code; - - chop; - - next if /^#/; - next if /^\s*$/; - - s/\s*#.*//; - - @fields = split ('\s*;\s*', $_, 30); - - $raw_code = $fields[$FOLDING_CODE]; - $code = hex ($raw_code); - - if ($#fields != 3) - { - printf STDERR ("Entry for $raw_code has wrong number of fields (%d)\n", $#fields); - next; - } - - # we don't use Simple or Turkic rules here - next if ($fields[$FOLDING_STATUS] =~ /^[ST]$/); - - @values = map { hex ($_) } split /\s+/, $fields[$FOLDING_MAPPING]; - - # Check simple case - - if (@values == 1 && - !(defined $value[$code] && $value[$code] >= 0x1000000) && - defined $type[$code]) { - - my $lower; - if ($type[$code] eq 'Ll') - { - $lower = $code; - } elsif ($type[$code] eq 'Lt') - { - $lower = $title_to_lower{$code}; - } elsif ($type[$code] eq 'Lu') - { - $lower = $value[$code]; - } else { - $lower = $code; - } - - if ($lower == $values[0]) { - next; - } - } - - my $string = pack ("U*", @values); - - if (1 + &length_in_bytes ($string) > $casefoldlen) { - $casefoldlen = 1 + &length_in_bytes ($string); - } - - push @casefold, [ $code, &escape ($string) ]; -} - -close INPUT; - -if ($do_props) { - &print_tables ($last_code) -} -if ($do_decomp) { - &print_decomp ($last_code); - &output_composition_table; -} - -&print_line_break ($last_code); - -exit 0; - - -# perl "length" returns the length in characters -sub length_in_bytes -{ - my ($string) = @_; - - use bytes; - return length $string; -} - -# Process a single character. -sub process_one -{ - my ($code, @fields) = @_; - - $type[$code] = $fields[$CATEGORY]; - if ($type[$code] eq 'Nd') - { - $value[$code] = int ($fields[$DECIMAL_VALUE]); - } - elsif ($type[$code] eq 'Ll') - { - $value[$code] = hex ($fields[$UPPER]); - } - elsif ($type[$code] eq 'Lu') - { - $value[$code] = hex ($fields[$LOWER]); - } - - if ($type[$code] eq 'Lt') - { - $title_to_lower{$code} = hex ($fields[$LOWER]); - $title_to_upper{$code} = hex ($fields[$UPPER]); - } - - $cclass[$code] = $fields[$COMBINING_CLASSES]; - - # Handle decompositions. - if ($fields[$DECOMPOSITION] ne '') - { - if ($fields[$DECOMPOSITION] =~ s/\<.*\>\s*//) { - $decompose_compat[$code] = 1; - } else { - $decompose_compat[$code] = 0; - - if (!exists $composition_exclusions{$code}) { - $compositions{$code} = $fields[$DECOMPOSITION]; - } - } - $decompositions[$code] = $fields[$DECOMPOSITION]; - } -} - -sub print_tables -{ - my ($last) = @_; - my ($outfile) = "gunichartables.h"; - - local ($bytes_out) = 0; - - print "Writing $outfile...\n"; - - open (OUT, "> $outfile"); - - print OUT "/* This file is automatically generated. DO NOT EDIT!\n"; - print OUT " Instead, edit gen-unicode-tables.pl and re-run. */\n\n"; - - print OUT "#ifndef CHARTABLES_H\n"; - print OUT "#define CHARTABLES_H\n\n"; - - print OUT "#define G_UNICODE_DATA_VERSION \"$ARGV[0]\"\n\n"; - - printf OUT "#define G_UNICODE_LAST_CHAR 0x%04x\n\n", $last; - - printf OUT "#define G_UNICODE_MAX_TABLE_INDEX 10000\n\n"; - - my $last_part1 = ($pages_before_e0000 * 256) - 1; - printf OUT "#define G_UNICODE_LAST_CHAR_PART1 0x%04X\n\n", $last_part1; - printf OUT "#define G_UNICODE_LAST_PAGE_PART1 %d\n\n", $pages_before_e0000 - 1; - - $table_index = 0; - printf OUT "static const char type_data[][256] = {\n"; - for ($count = 0; $count <= $last; $count += 256) - { - $row[$count / 256] = &print_row ($count, 1, \&fetch_type); - } - printf OUT "\n};\n\n"; - - printf OUT "/* U+0000 through U+%04X */\n", $last_part1; - print OUT "static const gint16 type_table_part1[$pages_before_e0000] = {\n"; - for ($count = 0; $count <= $last_part1; $count += 256) - { - print OUT ",\n" if $count > 0; - print OUT " ", $row[$count / 256]; - $bytes_out += 2; - } - print OUT "\n};\n\n"; - - printf OUT "/* U+E0000 through U+%04X */\n", $last; - print OUT "static const gint16 type_table_part2[768] = {\n"; - for ($count = 0xE0000; $count <= $last; $count += 256) - { - print OUT ",\n" if $count > 0xE0000; - print OUT " ", $row[$count / 256]; - $bytes_out += 2; - } - print OUT "\n};\n\n"; - - - # - # Now print attribute table. - # - - $table_index = 0; - printf OUT "static const gunichar attr_data[][256] = {\n"; - for ($count = 0; $count <= $last; $count += 256) - { - $row[$count / 256] = &print_row ($count, 4, \&fetch_attr); - } - printf OUT "\n};\n\n"; - - printf OUT "/* U+0000 through U+%04X */\n", $last_part1; - print OUT "static const gint16 attr_table_part1[$pages_before_e0000] = {\n"; - for ($count = 0; $count <= $last_part1; $count += 256) - { - print OUT ",\n" if $count > 0; - print OUT " ", $row[$count / 256]; - $bytes_out += 2; - } - print OUT "\n};\n\n"; - - printf OUT "/* U+E0000 through U+%04X */\n", $last; - print OUT "static const gint16 attr_table_part2[768] = {\n"; - for ($count = 0xE0000; $count <= $last; $count += 256) - { - print OUT ",\n" if $count > 0xE0000; - print OUT " ", $row[$count / 256]; - $bytes_out += 2; - } - print OUT "\n};\n\n"; - - # - # print title case table - # - - print OUT "static const gunichar title_table[][3] = {\n"; - my ($item); - my ($first) = 1; - foreach $item (sort keys %title_to_lower) - { - print OUT ",\n" - unless $first; - $first = 0; - printf OUT " { 0x%04x, 0x%04x, 0x%04x }", $item, $title_to_upper{$item}, $title_to_lower{$item}; - $bytes_out += 12; - } - print OUT "\n};\n\n"; - - # - # And special case conversion table -- conversions that change length - # - &output_special_case_table (\*OUT); - &output_casefold_table (\*OUT); - - print OUT "#endif /* CHARTABLES_H */\n"; - - close (OUT); - - printf STDERR "Generated %d bytes in tables\n", $bytes_out; -} - -# A fetch function for the type table. -sub fetch_type -{ - my ($index) = @_; - return $mappings{$type[$index]}; -} - -# A fetch function for the attribute table. -sub fetch_attr -{ - my ($index) = @_; - if (defined $value[$index]) - { - return sprintf ("0x%04x", $value[$index]); - } - else - { - return "0x0000"; - } -} - -sub print_row -{ - my ($start, $typsize, $fetcher) = @_; - - my ($i); - my (@values); - my ($flag) = 1; - my ($off); - - for ($off = 0; $off < 256; ++$off) - { - $values[$off] = $fetcher->($off + $start); - if ($values[$off] ne $values[0]) - { - $flag = 0; - } - } - if ($flag) - { - return $values[0] . " + G_UNICODE_MAX_TABLE_INDEX"; - } - - printf OUT ",\n" if ($table_index != 0); - printf OUT " { /* page %d, index %d */\n ", $start / 256, $table_index; - my ($column) = 4; - for ($i = $start; $i < $start + 256; ++$i) - { - print OUT ", " - if $i > $start; - my ($text) = $values[$i - $start]; - if (length ($text) + $column + 2 > 78) - { - print OUT "\n "; - $column = 4; - } - print OUT $text; - $column += length ($text) + 2; - } - print OUT "\n }"; - - $bytes_out += 256 * $typsize; - - return sprintf "%d /* page %d */", $table_index++, $start / 256; -} - -sub escape -{ - my ($string) = @_; - - my $escaped = unpack("H*", $string); - $escaped =~ s/(.{2})/\\x$1/g; - - return $escaped; -} - -# Returns the offset of $decomp in the offset string. Updates the -# referenced variables as appropriate. -sub handle_decomp ($$$$) -{ - my ($decomp, $decomp_offsets_ref, $decomp_string_ref, $decomp_string_offset_ref) = @_; - my $offset = "G_UNICODE_NOT_PRESENT_OFFSET"; - - if (defined $decomp) - { - if (defined $decomp_offsets_ref->{$decomp}) - { - $offset = $decomp_offsets_ref->{$decomp}; - } - else - { - $offset = ${$decomp_string_offset_ref}; - $decomp_offsets_ref->{$decomp} = $offset; - ${$decomp_string_ref} .= "\n \"" . &escape ($decomp) . "\\0\" /* offset ${$decomp_string_offset_ref} */"; - ${$decomp_string_offset_ref} += &length_in_bytes ($decomp) + 1; - } - } - - return $offset; -} - -# Generate the character decomposition header. -sub print_decomp -{ - my ($last) = @_; - my ($outfile) = "gunidecomp.h"; - - local ($bytes_out) = 0; - - print "Writing $outfile...\n"; - - open (OUT, "> $outfile") || exit 1; - - print OUT "/* This file is automatically generated. DO NOT EDIT! */\n\n"; - print OUT "#ifndef DECOMP_H\n"; - print OUT "#define DECOMP_H\n\n"; - - printf OUT "#define G_UNICODE_LAST_CHAR 0x%04x\n\n", $last; - - printf OUT "#define G_UNICODE_MAX_TABLE_INDEX (0x110000 / 256)\n\n"; - - my $last_part1 = ($pages_before_e0000 * 256) - 1; - printf OUT "#define G_UNICODE_LAST_CHAR_PART1 0x%04X\n\n", $last_part1; - printf OUT "#define G_UNICODE_LAST_PAGE_PART1 %d\n\n", $pages_before_e0000 - 1; - - $NOT_PRESENT_OFFSET = 65535; - print OUT "#define G_UNICODE_NOT_PRESENT_OFFSET $NOT_PRESENT_OFFSET\n\n"; - - my ($count, @row); - $table_index = 0; - printf OUT "static const guchar cclass_data[][256] = {\n"; - for ($count = 0; $count <= $last; $count += 256) - { - $row[$count / 256] = &print_row ($count, 1, \&fetch_cclass); - } - printf OUT "\n};\n\n"; - - print OUT "static const gint16 combining_class_table_part1[$pages_before_e0000] = {\n"; - for ($count = 0; $count <= $last_part1; $count += 256) - { - print OUT ",\n" if $count > 0; - print OUT " ", $row[$count / 256]; - $bytes_out += 2; - } - print OUT "\n};\n\n"; - - print OUT "static const gint16 combining_class_table_part2[768] = {\n"; - for ($count = 0xE0000; $count <= $last; $count += 256) - { - print OUT ",\n" if $count > 0xE0000; - print OUT " ", $row[$count / 256]; - $bytes_out += 2; - } - print OUT "\n};\n\n"; - - print OUT "typedef struct\n{\n"; - print OUT " gunichar ch;\n"; - print OUT " guint16 canon_offset;\n"; - print OUT " guint16 compat_offset;\n"; - print OUT "} decomposition;\n\n"; - - print OUT "static const decomposition decomp_table[] =\n{\n"; - my ($iter); - my ($first) = 1; - my ($decomp_string) = ""; - my ($decomp_string_offset) = 0; - for ($count = 0; $count <= $last; ++$count) - { - if (defined $decompositions[$count]) - { - print OUT ",\n" - if ! $first; - $first = 0; - - my $canon_decomp; - my $compat_decomp; - - if (!$decompose_compat[$count]) { - $canon_decomp = make_decomp ($count, 0); - } - $compat_decomp = make_decomp ($count, 1); - - if (defined $canon_decomp && $compat_decomp eq $canon_decomp) { - undef $compat_decomp; - } - - my $canon_offset = handle_decomp ($canon_decomp, \%decomp_offsets, \$decomp_string, \$decomp_string_offset); - my $compat_offset = handle_decomp ($compat_decomp, \%decomp_offsets, \$decomp_string, \$decomp_string_offset); - - die if $decomp_string_offset > $NOT_PRESENT_OFFSET; - - printf OUT qq( { 0x%04x, $canon_offset, $compat_offset }), $count; - $bytes_out += 8; - } - } - print OUT "\n};\n\n"; - $bytes_out += $decomp_string_offset + 1; - - printf OUT "static const gchar decomp_expansion_string[] = %s;\n\n", $decomp_string; - - print OUT "#endif /* DECOMP_H */\n"; - - printf STDERR "Generated %d bytes in decomp tables\n", $bytes_out; -} - -sub print_line_break -{ - my ($last) = @_; - my ($outfile) = "gunibreak.h"; - - local ($bytes_out) = 0; - - print "Writing $outfile...\n"; - - open (OUT, "> $outfile"); - - print OUT "/* This file is automatically generated. DO NOT EDIT!\n"; - print OUT " Instead, edit gen-unicode-tables.pl and re-run. */\n\n"; - - print OUT "#ifndef BREAKTABLES_H\n"; - print OUT "#define BREAKTABLES_H\n\n"; - - print OUT "#define G_UNICODE_DATA_VERSION \"$ARGV[0]\"\n\n"; - - printf OUT "#define G_UNICODE_LAST_CHAR 0x%04X\n\n", $last; - - printf OUT "#define G_UNICODE_MAX_TABLE_INDEX 10000\n\n"; - - my $last_part1 = ($pages_before_e0000 * 256) - 1; - printf OUT "/* the last code point that should be looked up in break_property_table_part1 */\n"; - printf OUT "#define G_UNICODE_LAST_CHAR_PART1 0x%04X\n\n", $last_part1; - - $table_index = 0; - printf OUT "static const gint8 break_property_data[][256] = {\n"; - for ($count = 0; $count <= $last; $count += 256) - { - $row[$count / 256] = &print_row ($count, 1, \&fetch_break_type); - } - printf OUT "\n};\n\n"; - - printf OUT "/* U+0000 through U+%04X */\n", $last_part1; - print OUT "static const gint16 break_property_table_part1[$pages_before_e0000] = {\n"; - for ($count = 0; $count <= $last_part1; $count += 256) - { - print OUT ",\n" if $count > 0; - print OUT " ", $row[$count / 256]; - $bytes_out += 2; - } - print OUT "\n};\n\n"; - - printf OUT "/* U+E0000 through U+%04X */\n", $last; - print OUT "static const gint16 break_property_table_part2[768] = {\n"; - for ($count = 0xE0000; $count <= $last; $count += 256) - { - print OUT ",\n" if $count > 0xE0000; - print OUT " ", $row[$count / 256]; - $bytes_out += 2; - } - print OUT "\n};\n\n"; - - - print OUT "#endif /* BREAKTABLES_H */\n"; - - close (OUT); - - printf STDERR "Generated %d bytes in break tables\n", $bytes_out; -} - - -# A fetch function for the break properties table. -sub fetch_break_type -{ - my ($index) = @_; - return $break_mappings{$break_props[$index]}; -} - -# Fetcher for combining class. -sub fetch_cclass -{ - my ($i) = @_; - return $cclass[$i]; -} - -# Expand a character decomposition recursively. -sub expand_decomp -{ - my ($code, $compat) = @_; - - my ($iter, $val); - my (@result) = (); - foreach $iter (split (' ', $decompositions[$code])) - { - $val = hex ($iter); - if (defined $decompositions[$val] && - ($compat || !$decompose_compat[$val])) - { - push (@result, &expand_decomp ($val, $compat)); - } - else - { - push (@result, $val); - } - } - - return @result; -} - -sub make_decomp -{ - my ($code, $compat) = @_; - - my $result = ""; - foreach $iter (&expand_decomp ($code, $compat)) - { - $result .= pack ("U", $iter); # to utf-8 - } - - $result; -} -# Generate special case data string from two fields -sub add_special_case -{ - my ($code, $single, $field1, $field2) = @_; - - @values = (defined $single ? $single : (), - (map { hex ($_) } split /\s+/, $field1), - 0, - (map { hex ($_) } split /\s+/, $field2)); - $result = ""; - - - for $value (@values) { - $result .= pack ("U", $value); # to utf-8 - } - - push @special_case_offsets, $special_case_offset; - - # We encode special cases up in the 0x1000000 space - $value[$code] = 0x1000000 + $special_case_offset; - - $special_case_offset += 1 + &length_in_bytes ($result); - - push @special_cases, &escape ($result); -} - -sub output_special_case_table -{ - my $out = shift; - - print $out <<EOT; - -/* Table of special cases for case conversion; each record contains - * First, the best single character mapping to lowercase if Lu, - * and to uppercase if Ll, followed by the output mapping for the two cases - * other than the case of the codepoint, in the order [Ll],[Lu],[Lt], - * encoded in UTF-8, separated and terminated by a null character. - */ -static const gchar special_case_table[] = { -EOT - - my $i = 0; - for $case (@special_cases) { - print $out qq( "$case\\0" /* offset ${special_case_offsets[$i]} */\n); - $i++; - } - - print $out <<EOT; -}; - -EOT - - print STDERR "Generated " . ($special_case_offset + 1) . " bytes in special case table\n"; -} - -sub enumerate_ordered -{ - my ($array) = @_; - - my $n = 0; - for my $code (sort { $a <=> $b } keys %$array) { - if ($array->{$code} == 1) { - delete $array->{$code}; - next; - } - $array->{$code} = $n++; - } - - return $n; -} - -sub output_composition_table -{ - print STDERR "Generating composition table\n"; - - local ($bytes_out) = 0; - - my %first; - my %second; - - # First we need to go through and remove decompositions - # starting with a non-starter, and single-character - # decompositions. At the same time, record - # the first and second character of each decomposition - - for $code (keys %compositions) - { - @values = map { hex ($_) } split /\s+/, $compositions{$code}; - - # non-starters - if ($cclass[$values[0]]) { - delete $compositions{$code}; - next; - } - - # single-character decompositions - if (@values == 1) { - delete $compositions{$code}; - next; - } - - if (@values != 2) { - die "$code has more than two elements in its decomposition!\n"; - } - - if (exists $first{$values[0]}) { - $first{$values[0]}++; - } else { - $first{$values[0]} = 1; - } - } - - # Assign integer indices, removing singletons - my $n_first = enumerate_ordered (\%first); - - # Now record the second character of each (non-singleton) decomposition - for $code (keys %compositions) { - @values = map { hex ($_) } split /\s+/, $compositions{$code}; - - if (exists $first{$values[0]}) { - if (exists $second{$values[1]}) { - $second{$values[1]}++; - } else { - $second{$values[1]} = 1; - } - } - } - - # Assign integer indices, removing duplicate - my $n_second = enumerate_ordered (\%second); - - # Build reverse table - - my @first_singletons; - my @second_singletons; - my %reverse; - for $code (keys %compositions) { - @values = map { hex ($_) } split /\s+/, $compositions{$code}; - - my $first = $first{$values[0]}; - my $second = $second{$values[1]}; - - if (defined $first && defined $second) { - $reverse{"$first|$second"} = $code; - } elsif (!defined $first) { - push @first_singletons, [ $values[0], $values[1], $code ]; - } else { - push @second_singletons, [ $values[1], $values[0], $code ]; - } - } - - @first_singletons = sort { $a->[0] <=> $b->[0] } @first_singletons; - @second_singletons = sort { $a->[0] <=> $b->[0] } @second_singletons; - - my %vals; - - open OUT, ">gunicomp.h" or die "Cannot open gunicomp.h: $!\n"; - - # Assign values in lookup table for all code points involved - - my $total = 1; - my $last = 0; - printf OUT "#define COMPOSE_FIRST_START %d\n", $total; - for $code (keys %first) { - $vals{$code} = $first{$code} + $total; - $last = $code if $code > $last; - } - $total += $n_first; - $i = 0; - printf OUT "#define COMPOSE_FIRST_SINGLE_START %d\n", $total; - for $record (@first_singletons) { - my $code = $record->[0]; - $vals{$code} = $i++ + $total; - $last = $code if $code > $last; - } - $total += @first_singletons; - printf OUT "#define COMPOSE_SECOND_START %d\n", $total; - for $code (keys %second) { - $vals{$code} = $second{$code} + $total; - $last = $code if $code > $last; - } - $total += $n_second; - $i = 0; - printf OUT "#define COMPOSE_SECOND_SINGLE_START %d\n\n", $total; - for $record (@second_singletons) { - my $code = $record->[0]; - $vals{$code} = $i++ + $total; - $last = $code if $code > $last; - } - - printf OUT "#define COMPOSE_TABLE_LAST %d\n\n", $last / 256; - - # Output lookup table - - my @row; - $table_index = 0; - printf OUT "static const guint16 compose_data[][256] = {\n"; - for (my $count = 0; $count <= $last; $count += 256) - { - $row[$count / 256] = &print_row ($count, 2, sub { exists $vals{$_[0]} ? $vals{$_[0]} : 0; }); - } - printf OUT "\n};\n\n"; - - print OUT "static const gint16 compose_table[COMPOSE_TABLE_LAST + 1] = {\n"; - for (my $count = 0; $count <= $last; $count += 256) - { - print OUT ",\n" if $count > 0; - print OUT " ", $row[$count / 256]; - $bytes_out += 2; - } - print OUT "\n};\n\n"; - - # Output first singletons - - print OUT "static const guint16 compose_first_single[][2] = {\n"; - $i = 0; - for $record (@first_singletons) { - if ($record->[1] > 0xFFFF or $record->[2] > 0xFFFF) { - die "time to switch compose_first_single to gunichar" ; - } - print OUT ",\n" if $i++ > 0; - printf OUT " { %#06x, %#06x }", $record->[1], $record->[2]; - } - print OUT "\n};\n"; - - $bytes_out += @first_singletons * 4; - - # Output second singletons - - print OUT "static const guint16 compose_second_single[][2] = {\n"; - $i = 0; - for $record (@second_singletons) { - if ($record->[1] > 0xFFFF or $record->[2] > 0xFFFF) { - die "time to switch compose_second_single to gunichar"; - } - print OUT ",\n" if $i++ > 0; - printf OUT " { %#06x, %#06x }", $record->[1], $record->[2]; - } - print OUT "\n};\n"; - - $bytes_out += @second_singletons * 4; - - # Output array of composition pairs - - print OUT <<EOT; -static const guint16 compose_array[$n_first][$n_second] = { -EOT - - for (my $i = 0; $i < $n_first; $i++) { - print OUT ",\n" if $i; - print OUT " { "; - for (my $j = 0; $j < $n_second; $j++) { - print OUT ", " if $j; - if (exists $reverse{"$i|$j"}) { - if ($reverse{"$i|$j"} > 0xFFFF) { - die "time to switch compose_array to gunichar" ; - } - printf OUT "0x%04x", $reverse{"$i|$j"}; - } else { - print OUT " 0"; - } - } - print OUT " }"; - } - print OUT "\n"; - - print OUT <<EOT; -}; -EOT - - $bytes_out += $n_first * $n_second * 2; - - printf STDERR "Generated %d bytes in compose tables\n", $bytes_out; -} - -sub output_casefold_table -{ - my $out = shift; - - print $out <<EOT; - -/* Table of casefolding cases that can't be derived by lowercasing - */ -static const struct { - guint16 ch; - gchar data[$casefoldlen]; -} casefold_table[] = { -EOT - - @casefold = sort { $a->[0] <=> $b->[0] } @casefold; - - for $case (@casefold) - { - $code = $case->[0]; - $string = $case->[1]; - - if ($code > 0xFFFF) { - die "time to switch casefold_table to gunichar" ; - } - - print $out sprintf(qq( { 0x%04x, "$string" },\n), $code); - - } - - print $out <<EOT; -}; - -EOT - - my $recordlen = (2+$casefoldlen+1) & ~1; - printf "Generated %d bytes for casefold table\n", $recordlen * @casefold; -} - - - diff --git a/glib/ghook.c b/glib/ghook.c deleted file mode 100644 index d038ee2c2..000000000 --- a/glib/ghook.c +++ /dev/null @@ -1,638 +0,0 @@ -/* GLIB - Library of useful routines for C programming - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * GHook: Callback maintenance functions - * Copyright (C) 1998 Tim Janik - * - * 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, 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" - -#include "glib.h" -#include "galias.h" - - -/* --- functions --- */ -static void -default_finalize_hook (GHookList *hook_list, - GHook *hook) -{ - GDestroyNotify destroy = hook->destroy; - - if (destroy) - { - hook->destroy = NULL; - destroy (hook->data); - } -} - -void -g_hook_list_init (GHookList *hook_list, - guint hook_size) -{ - g_return_if_fail (hook_list != NULL); - g_return_if_fail (hook_size >= sizeof (GHook)); - - hook_list->seq_id = 1; - hook_list->hook_size = hook_size; - hook_list->is_setup = TRUE; - hook_list->hooks = NULL; - hook_list->dummy3 = NULL; - hook_list->finalize_hook = default_finalize_hook; - hook_list->dummy[0] = NULL; - hook_list->dummy[1] = NULL; -} - -void -g_hook_list_clear (GHookList *hook_list) -{ - g_return_if_fail (hook_list != NULL); - - if (hook_list->is_setup) - { - GHook *hook; - - hook_list->is_setup = FALSE; - - hook = hook_list->hooks; - if (!hook) - { - /* destroy hook_list->hook_memchunk */ - } - else - do - { - GHook *tmp; - - g_hook_ref (hook_list, hook); - g_hook_destroy_link (hook_list, hook); - tmp = hook->next; - g_hook_unref (hook_list, hook); - hook = tmp; - } - while (hook); - } -} - -GHook* -g_hook_alloc (GHookList *hook_list) -{ - GHook *hook; - - g_return_val_if_fail (hook_list != NULL, NULL); - g_return_val_if_fail (hook_list->is_setup, NULL); - - hook = g_slice_alloc0 (hook_list->hook_size); - hook->data = NULL; - hook->next = NULL; - hook->prev = NULL; - hook->flags = G_HOOK_FLAG_ACTIVE; - hook->ref_count = 0; - hook->hook_id = 0; - hook->func = NULL; - hook->destroy = NULL; - - return hook; -} - -void -g_hook_free (GHookList *hook_list, - GHook *hook) -{ - g_return_if_fail (hook_list != NULL); - g_return_if_fail (hook_list->is_setup); - g_return_if_fail (hook != NULL); - g_return_if_fail (G_HOOK_IS_UNLINKED (hook)); - g_return_if_fail (!G_HOOK_IN_CALL (hook)); - - if(hook_list->finalize_hook != NULL) - hook_list->finalize_hook (hook_list, hook); - g_slice_free1 (hook_list->hook_size, hook); -} - -void -g_hook_destroy_link (GHookList *hook_list, - GHook *hook) -{ - g_return_if_fail (hook_list != NULL); - g_return_if_fail (hook != NULL); - - hook->flags &= ~G_HOOK_FLAG_ACTIVE; - if (hook->hook_id) - { - hook->hook_id = 0; - g_hook_unref (hook_list, hook); /* counterpart to g_hook_insert_before */ - } -} - -gboolean -g_hook_destroy (GHookList *hook_list, - gulong hook_id) -{ - GHook *hook; - - g_return_val_if_fail (hook_list != NULL, FALSE); - g_return_val_if_fail (hook_id > 0, FALSE); - - hook = g_hook_get (hook_list, hook_id); - if (hook) - { - g_hook_destroy_link (hook_list, hook); - return TRUE; - } - - return FALSE; -} - -void -g_hook_unref (GHookList *hook_list, - GHook *hook) -{ - g_return_if_fail (hook_list != NULL); - g_return_if_fail (hook != NULL); - g_return_if_fail (hook->ref_count > 0); - - hook->ref_count--; - if (!hook->ref_count) - { - g_return_if_fail (hook->hook_id == 0); - g_return_if_fail (!G_HOOK_IN_CALL (hook)); - - if (hook->prev) - hook->prev->next = hook->next; - else - hook_list->hooks = hook->next; - if (hook->next) - { - hook->next->prev = hook->prev; - hook->next = NULL; - } - hook->prev = NULL; - - if (!hook_list->is_setup) - { - hook_list->is_setup = TRUE; - g_hook_free (hook_list, hook); - hook_list->is_setup = FALSE; - - if (!hook_list->hooks) - { - /* destroy hook_list->hook_memchunk */ - } - } - else - g_hook_free (hook_list, hook); - } -} - -GHook * -g_hook_ref (GHookList *hook_list, - GHook *hook) -{ - g_return_val_if_fail (hook_list != NULL, NULL); - g_return_val_if_fail (hook != NULL, NULL); - g_return_val_if_fail (hook->ref_count > 0, NULL); - - hook->ref_count++; - - return hook; -} - -void -g_hook_prepend (GHookList *hook_list, - GHook *hook) -{ - g_return_if_fail (hook_list != NULL); - - g_hook_insert_before (hook_list, hook_list->hooks, hook); -} - -void -g_hook_insert_before (GHookList *hook_list, - GHook *sibling, - GHook *hook) -{ - g_return_if_fail (hook_list != NULL); - g_return_if_fail (hook_list->is_setup); - g_return_if_fail (hook != NULL); - g_return_if_fail (G_HOOK_IS_UNLINKED (hook)); - g_return_if_fail (hook->ref_count == 0); - - hook->hook_id = hook_list->seq_id++; - hook->ref_count = 1; /* counterpart to g_hook_destroy_link */ - - if (sibling) - { - if (sibling->prev) - { - hook->prev = sibling->prev; - hook->prev->next = hook; - hook->next = sibling; - sibling->prev = hook; - } - else - { - hook_list->hooks = hook; - hook->next = sibling; - sibling->prev = hook; - } - } - else - { - if (hook_list->hooks) - { - sibling = hook_list->hooks; - while (sibling->next) - sibling = sibling->next; - hook->prev = sibling; - sibling->next = hook; - } - else - hook_list->hooks = hook; - } -} - -void -g_hook_list_invoke (GHookList *hook_list, - gboolean may_recurse) -{ - GHook *hook; - - g_return_if_fail (hook_list != NULL); - g_return_if_fail (hook_list->is_setup); - - hook = g_hook_first_valid (hook_list, may_recurse); - while (hook) - { - GHookFunc func; - gboolean was_in_call; - - func = (GHookFunc) hook->func; - - was_in_call = G_HOOK_IN_CALL (hook); - hook->flags |= G_HOOK_FLAG_IN_CALL; - func (hook->data); - if (!was_in_call) - hook->flags &= ~G_HOOK_FLAG_IN_CALL; - - hook = g_hook_next_valid (hook_list, hook, may_recurse); - } -} - -void -g_hook_list_invoke_check (GHookList *hook_list, - gboolean may_recurse) -{ - GHook *hook; - - g_return_if_fail (hook_list != NULL); - g_return_if_fail (hook_list->is_setup); - - hook = g_hook_first_valid (hook_list, may_recurse); - while (hook) - { - GHookCheckFunc func; - gboolean was_in_call; - gboolean need_destroy; - - func = (GHookCheckFunc) hook->func; - - was_in_call = G_HOOK_IN_CALL (hook); - hook->flags |= G_HOOK_FLAG_IN_CALL; - need_destroy = !func (hook->data); - if (!was_in_call) - hook->flags &= ~G_HOOK_FLAG_IN_CALL; - if (need_destroy) - g_hook_destroy_link (hook_list, hook); - - hook = g_hook_next_valid (hook_list, hook, may_recurse); - } -} - -void -g_hook_list_marshal_check (GHookList *hook_list, - gboolean may_recurse, - GHookCheckMarshaller marshaller, - gpointer data) -{ - GHook *hook; - - g_return_if_fail (hook_list != NULL); - g_return_if_fail (hook_list->is_setup); - g_return_if_fail (marshaller != NULL); - - hook = g_hook_first_valid (hook_list, may_recurse); - while (hook) - { - gboolean was_in_call; - gboolean need_destroy; - - was_in_call = G_HOOK_IN_CALL (hook); - hook->flags |= G_HOOK_FLAG_IN_CALL; - need_destroy = !marshaller (hook, data); - if (!was_in_call) - hook->flags &= ~G_HOOK_FLAG_IN_CALL; - if (need_destroy) - g_hook_destroy_link (hook_list, hook); - - hook = g_hook_next_valid (hook_list, hook, may_recurse); - } -} - -void -g_hook_list_marshal (GHookList *hook_list, - gboolean may_recurse, - GHookMarshaller marshaller, - gpointer data) -{ - GHook *hook; - - g_return_if_fail (hook_list != NULL); - g_return_if_fail (hook_list->is_setup); - g_return_if_fail (marshaller != NULL); - - hook = g_hook_first_valid (hook_list, may_recurse); - while (hook) - { - gboolean was_in_call; - - was_in_call = G_HOOK_IN_CALL (hook); - hook->flags |= G_HOOK_FLAG_IN_CALL; - marshaller (hook, data); - if (!was_in_call) - hook->flags &= ~G_HOOK_FLAG_IN_CALL; - - hook = g_hook_next_valid (hook_list, hook, may_recurse); - } -} - -GHook* -g_hook_first_valid (GHookList *hook_list, - gboolean may_be_in_call) -{ - g_return_val_if_fail (hook_list != NULL, NULL); - - if (hook_list->is_setup) - { - GHook *hook; - - hook = hook_list->hooks; - if (hook) - { - g_hook_ref (hook_list, hook); - if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook))) - return hook; - else - return g_hook_next_valid (hook_list, hook, may_be_in_call); - } - } - - return NULL; -} - -GHook* -g_hook_next_valid (GHookList *hook_list, - GHook *hook, - gboolean may_be_in_call) -{ - GHook *ohook = hook; - - g_return_val_if_fail (hook_list != NULL, NULL); - - if (!hook) - return NULL; - - hook = hook->next; - while (hook) - { - if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook))) - { - g_hook_ref (hook_list, hook); - g_hook_unref (hook_list, ohook); - - return hook; - } - hook = hook->next; - } - g_hook_unref (hook_list, ohook); - - return NULL; -} - -GHook* -g_hook_get (GHookList *hook_list, - gulong hook_id) -{ - GHook *hook; - - g_return_val_if_fail (hook_list != NULL, NULL); - g_return_val_if_fail (hook_id > 0, NULL); - - hook = hook_list->hooks; - while (hook) - { - if (hook->hook_id == hook_id) - return hook; - hook = hook->next; - } - - return NULL; -} - -GHook* -g_hook_find (GHookList *hook_list, - gboolean need_valids, - GHookFindFunc func, - gpointer data) -{ - GHook *hook; - - g_return_val_if_fail (hook_list != NULL, NULL); - g_return_val_if_fail (func != NULL, NULL); - - hook = hook_list->hooks; - while (hook) - { - GHook *tmp; - - /* test only non-destroyed hooks */ - if (!hook->hook_id) - { - hook = hook->next; - continue; - } - - g_hook_ref (hook_list, hook); - - if (func (hook, data) && hook->hook_id && (!need_valids || G_HOOK_ACTIVE (hook))) - { - g_hook_unref (hook_list, hook); - - return hook; - } - - tmp = hook->next; - g_hook_unref (hook_list, hook); - hook = tmp; - } - - return NULL; -} - -GHook* -g_hook_find_data (GHookList *hook_list, - gboolean need_valids, - gpointer data) -{ - GHook *hook; - - g_return_val_if_fail (hook_list != NULL, NULL); - - hook = hook_list->hooks; - while (hook) - { - /* test only non-destroyed hooks */ - if (hook->data == data && - hook->hook_id && - (!need_valids || G_HOOK_ACTIVE (hook))) - return hook; - - hook = hook->next; - } - - return NULL; -} - -GHook* -g_hook_find_func (GHookList *hook_list, - gboolean need_valids, - gpointer func) -{ - GHook *hook; - - g_return_val_if_fail (hook_list != NULL, NULL); - g_return_val_if_fail (func != NULL, NULL); - - hook = hook_list->hooks; - while (hook) - { - /* test only non-destroyed hooks */ - if (hook->func == func && - hook->hook_id && - (!need_valids || G_HOOK_ACTIVE (hook))) - return hook; - - hook = hook->next; - } - - return NULL; -} - -GHook* -g_hook_find_func_data (GHookList *hook_list, - gboolean need_valids, - gpointer func, - gpointer data) -{ - GHook *hook; - - g_return_val_if_fail (hook_list != NULL, NULL); - g_return_val_if_fail (func != NULL, NULL); - - hook = hook_list->hooks; - while (hook) - { - /* test only non-destroyed hooks */ - if (hook->data == data && - hook->func == func && - hook->hook_id && - (!need_valids || G_HOOK_ACTIVE (hook))) - return hook; - - hook = hook->next; - } - - return NULL; -} - -void -g_hook_insert_sorted (GHookList *hook_list, - GHook *hook, - GHookCompareFunc func) -{ - GHook *sibling; - - g_return_if_fail (hook_list != NULL); - g_return_if_fail (hook_list->is_setup); - g_return_if_fail (hook != NULL); - g_return_if_fail (G_HOOK_IS_UNLINKED (hook)); - g_return_if_fail (hook->func != NULL); - g_return_if_fail (func != NULL); - - /* first non-destroyed hook */ - sibling = hook_list->hooks; - while (sibling && !sibling->hook_id) - sibling = sibling->next; - - while (sibling) - { - GHook *tmp; - - g_hook_ref (hook_list, sibling); - if (func (hook, sibling) <= 0 && sibling->hook_id) - { - g_hook_unref (hook_list, sibling); - break; - } - - /* next non-destroyed hook */ - tmp = sibling->next; - while (tmp && !tmp->hook_id) - tmp = tmp->next; - - g_hook_unref (hook_list, sibling); - sibling = tmp; - } - - g_hook_insert_before (hook_list, sibling, hook); -} - -gint -g_hook_compare_ids (GHook *new_hook, - GHook *sibling) -{ - if (new_hook->hook_id < sibling->hook_id) - return -1; - else if (new_hook->hook_id > sibling->hook_id) - return 1; - - return 0; -} - -#define __G_HOOK_C__ -#include "galiasdef.c" diff --git a/glib/giowin32.c b/glib/giowin32.c deleted file mode 100644 index 7f395473d..000000000 --- a/glib/giowin32.c +++ /dev/null @@ -1,2191 +0,0 @@ -/* GLIB - Library of useful routines for C programming - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * giowin32.c: IO Channels for Win32. - * Copyright 1998 Owen Taylor and Tor Lillqvist - * Copyright 1999-2000 Tor Lillqvist and Craig Setera - * Copyright 2001-2003 Andrew Lanoix - * - * 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, 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/. - */ - -/* - * Bugs that are related to the code in this file: - * - * Bug 137968 - Sometimes a GIOFunc on Win32 is called with zero condition - * http://bugzilla.gnome.org/show_bug.cgi?id=137968 - * - * Bug 324234 - Using g_io_add_watch_full() to wait for connect() to return on a non-blocking socket returns prematurely - * http://bugzilla.gnome.org/show_bug.cgi?id=324234 - * - * Bug 331214 - g_io_channel async socket io stalls - * http://bugzilla.gnome.org/show_bug.cgi?id=331214 - * - * Bug 338943 - Multiple watches on the same socket - * http://bugzilla.gnome.org/show_bug.cgi?id=338943 - * - * Bug 357674 - 2 serious bugs in giowin32.c making glib iochannels useless - * http://bugzilla.gnome.org/show_bug.cgi?id=357674 - * - * Bug 425156 - GIOChannel deadlocks on a win32 socket - * http://bugzilla.gnome.org/show_bug.cgi?id=425156 - * - * Bug 468910 - giofunc condition=0 - * http://bugzilla.gnome.org/show_bug.cgi?id=468910 - * - * Bug 500246 - Bug fixes for giowin32 - * http://bugzilla.gnome.org/show_bug.cgi?id=500246 - * - * Bug 548278 - Async GETs connections are always terminated unexpectedly on windows - * http://bugzilla.gnome.org/show_bug.cgi?id=548278 - * - * Bug 548536 - giowin32 problem when adding and removing watches - * http://bugzilla.gnome.org/show_bug.cgi?id=548536 - * - * When fixing bugs related to the code in this file, either the above - * bugs or others, make sure that the test programs attached to the - * above bugs continue to work. - */ - -#include "config.h" - -#include "glib.h" - -#include <stdlib.h> -#include <winsock2.h> -#include <windows.h> -#include <conio.h> -#include <fcntl.h> -#include <io.h> -#include <process.h> -#include <errno.h> -#include <sys/stat.h> - -#include "gstdio.h" -#include "glibintl.h" - -#include "galias.h" - -typedef struct _GIOWin32Channel GIOWin32Channel; -typedef struct _GIOWin32Watch GIOWin32Watch; - -#define BUFFER_SIZE 4096 - -typedef enum { - G_IO_WIN32_WINDOWS_MESSAGES, /* Windows messages */ - - G_IO_WIN32_FILE_DESC, /* Unix-like file descriptors from - * _open() or _pipe(), except for - * console IO. Separate thread to read - * or write. - */ - - G_IO_WIN32_CONSOLE, /* Console IO (usually stdin, stdout, stderr) */ - - G_IO_WIN32_SOCKET /* Sockets. No separate thread. */ -} GIOWin32ChannelType; - -struct _GIOWin32Channel { - GIOChannel channel; - gint fd; /* Either a Unix-like file handle as provided - * by the Microsoft C runtime, or a SOCKET - * as provided by WinSock. - */ - GIOWin32ChannelType type; - - gboolean debug; - - /* Field used by G_IO_WIN32_WINDOWS_MESSAGES channels */ - HWND hwnd; /* Handle of window, or NULL */ - - /* Fields used by G_IO_WIN32_FILE_DESC channels. */ - CRITICAL_SECTION mutex; - - int direction; /* 0 means we read from it, - * 1 means we write to it. - */ - - gboolean running; /* Is reader or writer thread - * running. FALSE if EOF has been - * reached by the reader thread. - */ - - gboolean needs_close; /* If the channel has been closed while - * the reader thread was still running. - */ - - guint thread_id; /* If non-NULL the channel has or has - * had a reader or writer thread. - */ - HANDLE data_avail_event; - - gushort revents; - - /* Data is kept in a circular buffer. To be able to distinguish between - * empty and full buffers, we cannot fill it completely, but have to - * leave a one character gap. - * - * Data available is between indexes rdp and wrp-1 (modulo BUFFER_SIZE). - * - * Empty: wrp == rdp - * Full: (wrp + 1) % BUFFER_SIZE == rdp - * Partial: otherwise - */ - guchar *buffer; /* (Circular) buffer */ - gint wrp, rdp; /* Buffer indices for writing and reading */ - HANDLE space_avail_event; - - /* Fields used by G_IO_WIN32_SOCKET channels */ - int event_mask; - int last_events; - HANDLE event; - gboolean write_would_have_blocked; - gboolean ever_writable; -}; - -struct _GIOWin32Watch { - GSource source; - GPollFD pollfd; - GIOChannel *channel; - GIOCondition condition; -}; - -static void -g_win32_print_access_mode (int flags) -{ - g_print ("%s%s%s%s%s%s%s%s%s%s", - ((flags & 0x3) == _O_RDWR ? "O_RDWR" : - ((flags & 0x3) == _O_RDONLY ? "O_RDONLY" : - ((flags & 0x3) == _O_WRONLY ? "O_WRONLY" : "0"))), - (flags & _O_APPEND ? "|O_APPEND" : ""), - (flags & _O_RANDOM ? "|O_RANDOM" : ""), - (flags & _O_SEQUENTIAL ? "|O_SEQUENTIAL" : ""), - (flags & _O_TEMPORARY ? "|O_TEMPORARY" : ""), - (flags & _O_CREAT ? "|O_CREAT" : ""), - (flags & _O_TRUNC ? "|O_TRUNC" : ""), - (flags & _O_EXCL ? "|O_EXCL" : ""), - (flags & _O_TEXT ? "|O_TEXT" : ""), - (flags & _O_BINARY ? "|O_BINARY" : "")); -} - -static void -g_win32_print_gioflags (GIOFlags flags) -{ - char *bar = ""; - - if (flags & G_IO_FLAG_APPEND) - bar = "|", g_print ("APPEND"); - if (flags & G_IO_FLAG_NONBLOCK) - g_print ("%sNONBLOCK", bar), bar = "|"; - if (flags & G_IO_FLAG_IS_READABLE) - g_print ("%sREADABLE", bar), bar = "|"; - if (flags & G_IO_FLAG_IS_WRITEABLE) - g_print ("%sWRITEABLE", bar), bar = "|"; - if (flags & G_IO_FLAG_IS_SEEKABLE) - g_print ("%sSEEKABLE", bar), bar = "|"; -} - -static const char * -event_mask_to_string (int mask) -{ - char buf[100]; - int checked_bits = 0; - char *bufp = buf; - - if (mask == 0) - return ""; - -#define BIT(n) checked_bits |= FD_##n; if (mask & FD_##n) bufp += sprintf (bufp, "%s" #n, (bufp>buf ? "|" : "")) - - BIT (READ); - BIT (WRITE); - BIT (OOB); - BIT (ACCEPT); - BIT (CONNECT); - BIT (CLOSE); - BIT (QOS); - BIT (GROUP_QOS); - BIT (ROUTING_INTERFACE_CHANGE); - BIT (ADDRESS_LIST_CHANGE); - -#undef BIT - - if ((mask & ~checked_bits) != 0) - bufp += sprintf (bufp, "|%#x", mask & ~checked_bits); - - return g_quark_to_string (g_quark_from_string (buf)); -} - -static const char * -condition_to_string (GIOCondition condition) -{ - char buf[100]; - int checked_bits = 0; - char *bufp = buf; - - if (condition == 0) - return ""; - -#define BIT(n) checked_bits |= G_IO_##n; if (condition & G_IO_##n) bufp += sprintf (bufp, "%s" #n, (bufp>buf ? "|" : "")) - - BIT (IN); - BIT (OUT); - BIT (PRI); - BIT (ERR); - BIT (HUP); - BIT (NVAL); - -#undef BIT - - if ((condition & ~checked_bits) != 0) - bufp += sprintf (bufp, "|%#x", condition & ~checked_bits); - - return g_quark_to_string (g_quark_from_string (buf)); -} - -static gboolean -g_io_win32_get_debug_flag (void) -{ - return (getenv ("G_IO_WIN32_DEBUG") != NULL); -} - -static void -g_io_channel_win32_init (GIOWin32Channel *channel) -{ - channel->debug = g_io_win32_get_debug_flag (); - - InitializeCriticalSection (&channel->mutex); - channel->running = FALSE; - channel->needs_close = FALSE; - channel->thread_id = 0; - channel->data_avail_event = NULL; - channel->revents = 0; - channel->buffer = NULL; - channel->space_avail_event = NULL; - - channel->event_mask = 0; - channel->last_events = 0; - channel->event = NULL; - channel->write_would_have_blocked = FALSE; - channel->ever_writable = FALSE; -} - -static void -create_events (GIOWin32Channel *channel) -{ - SECURITY_ATTRIBUTES sec_attrs; - - sec_attrs.nLength = sizeof (SECURITY_ATTRIBUTES); - sec_attrs.lpSecurityDescriptor = NULL; - sec_attrs.bInheritHandle = FALSE; - - /* The data available event is manual reset, the space available event - * is automatic reset. - */ - if (!(channel->data_avail_event = CreateEvent (&sec_attrs, TRUE, FALSE, NULL)) - || !(channel->space_avail_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL))) - { - gchar *emsg = g_win32_error_message (GetLastError ()); - - g_error ("Error creating event: %s", emsg); - g_free (emsg); - } -} - -static unsigned __stdcall -read_thread (void *parameter) -{ - GIOWin32Channel *channel = parameter; - guchar *buffer; - gint nbytes; - - g_io_channel_ref ((GIOChannel *)channel); - - if (channel->debug) - g_print ("read_thread %#x: start fd=%d, data_avail=%p space_avail=%p\n", - channel->thread_id, - channel->fd, - channel->data_avail_event, - channel->space_avail_event); - - channel->direction = 0; - channel->buffer = g_malloc (BUFFER_SIZE); - channel->rdp = channel->wrp = 0; - channel->running = TRUE; - - SetEvent (channel->space_avail_event); - - EnterCriticalSection (&channel->mutex); - while (channel->running) - { - if (channel->debug) - g_print ("read_thread %#x: rdp=%d, wrp=%d\n", - channel->thread_id, channel->rdp, channel->wrp); - if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp) - { - /* Buffer is full */ - if (channel->debug) - g_print ("read_thread %#x: resetting space_avail\n", - channel->thread_id); - ResetEvent (channel->space_avail_event); - if (channel->debug) - g_print ("read_thread %#x: waiting for space\n", - channel->thread_id); - LeaveCriticalSection (&channel->mutex); - WaitForSingleObject (channel->space_avail_event, INFINITE); - EnterCriticalSection (&channel->mutex); - if (channel->debug) - g_print ("read_thread %#x: rdp=%d, wrp=%d\n", - channel->thread_id, channel->rdp, channel->wrp); - } - - buffer = channel->buffer + channel->wrp; - - /* Always leave at least one byte unused gap to be able to - * distinguish between the full and empty condition... - */ - nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE, - BUFFER_SIZE - channel->wrp); - - if (channel->debug) - g_print ("read_thread %#x: calling read() for %d bytes\n", - channel->thread_id, nbytes); - - LeaveCriticalSection (&channel->mutex); - - nbytes = read (channel->fd, buffer, nbytes); - - EnterCriticalSection (&channel->mutex); - - channel->revents = G_IO_IN; - if (nbytes == 0) - channel->revents |= G_IO_HUP; - else if (nbytes < 0) - channel->revents |= G_IO_ERR; - - if (channel->debug) - g_print ("read_thread %#x: read() returned %d, rdp=%d, wrp=%d\n", - channel->thread_id, nbytes, channel->rdp, channel->wrp); - - if (nbytes <= 0) - break; - - channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE; - if (channel->debug) - g_print ("read_thread %#x: rdp=%d, wrp=%d, setting data_avail\n", - channel->thread_id, channel->rdp, channel->wrp); - SetEvent (channel->data_avail_event); - } - - channel->running = FALSE; - if (channel->needs_close) - { - if (channel->debug) - g_print ("read_thread %#x: channel fd %d needs closing\n", - channel->thread_id, channel->fd); - close (channel->fd); - channel->fd = -1; - } - - if (channel->debug) - g_print ("read_thread %#x: EOF, rdp=%d, wrp=%d, setting data_avail\n", - channel->thread_id, channel->rdp, channel->wrp); - SetEvent (channel->data_avail_event); - LeaveCriticalSection (&channel->mutex); - - g_io_channel_unref ((GIOChannel *)channel); - - /* No need to call _endthreadex(), the actual thread starter routine - * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls - * _endthreadex() for us. - */ - - return 0; -} - -static unsigned __stdcall -write_thread (void *parameter) -{ - GIOWin32Channel *channel = parameter; - guchar *buffer; - gint nbytes; - - g_io_channel_ref ((GIOChannel *)channel); - - if (channel->debug) - g_print ("write_thread %#x: start fd=%d, data_avail=%p space_avail=%p\n", - channel->thread_id, - channel->fd, - channel->data_avail_event, - channel->space_avail_event); - - channel->direction = 1; - channel->buffer = g_malloc (BUFFER_SIZE); - channel->rdp = channel->wrp = 0; - channel->running = TRUE; - - SetEvent (channel->space_avail_event); - - /* We use the same event objects as for a reader thread, but with - * reversed meaning. So, space_avail is used if data is available - * for writing, and data_avail is used if space is available in the - * write buffer. - */ - - EnterCriticalSection (&channel->mutex); - while (channel->running || channel->rdp != channel->wrp) - { - if (channel->debug) - g_print ("write_thread %#x: rdp=%d, wrp=%d\n", - channel->thread_id, channel->rdp, channel->wrp); - if (channel->wrp == channel->rdp) - { - /* Buffer is empty. */ - if (channel->debug) - g_print ("write_thread %#x: resetting space_avail\n", - channel->thread_id); - ResetEvent (channel->space_avail_event); - if (channel->debug) - g_print ("write_thread %#x: waiting for data\n", - channel->thread_id); - channel->revents = G_IO_OUT; - SetEvent (channel->data_avail_event); - LeaveCriticalSection (&channel->mutex); - WaitForSingleObject (channel->space_avail_event, INFINITE); - - EnterCriticalSection (&channel->mutex); - if (channel->rdp == channel->wrp) - break; - - if (channel->debug) - g_print ("write_thread %#x: rdp=%d, wrp=%d\n", - channel->thread_id, channel->rdp, channel->wrp); - } - - buffer = channel->buffer + channel->rdp; - if (channel->rdp < channel->wrp) - nbytes = channel->wrp - channel->rdp; - else - nbytes = BUFFER_SIZE - channel->rdp; - - if (channel->debug) - g_print ("write_thread %#x: calling write() for %d bytes\n", - channel->thread_id, nbytes); - - LeaveCriticalSection (&channel->mutex); - nbytes = write (channel->fd, buffer, nbytes); - EnterCriticalSection (&channel->mutex); - - if (channel->debug) - g_print ("write_thread %#x: write(%i) returned %d, rdp=%d, wrp=%d\n", - channel->thread_id, channel->fd, nbytes, channel->rdp, channel->wrp); - - channel->revents = 0; - if (nbytes > 0) - channel->revents |= G_IO_OUT; - else if (nbytes <= 0) - channel->revents |= G_IO_ERR; - - channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE; - - if (nbytes <= 0) - break; - - if (channel->debug) - g_print ("write_thread: setting data_avail for thread %#x\n", - channel->thread_id); - SetEvent (channel->data_avail_event); - } - - channel->running = FALSE; - if (channel->needs_close) - { - if (channel->debug) - g_print ("write_thread %#x: channel fd %d needs closing\n", - channel->thread_id, channel->fd); - close (channel->fd); - channel->fd = -1; - } - - LeaveCriticalSection (&channel->mutex); - - g_io_channel_unref ((GIOChannel *)channel); - - return 0; -} - -static void -create_thread (GIOWin32Channel *channel, - GIOCondition condition, - unsigned (__stdcall *thread) (void *parameter)) -{ - HANDLE thread_handle; - - thread_handle = (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0, - &channel->thread_id); - if (thread_handle == 0) - g_warning ("Error creating thread: %s.", - g_strerror (errno)); - else if (!CloseHandle (thread_handle)) - { - gchar *emsg = g_win32_error_message (GetLastError ()); - - g_warning ("Error closing thread handle: %s.", emsg); - g_free (emsg); - } - - WaitForSingleObject (channel->space_avail_event, INFINITE); -} - -static GIOStatus -buffer_read (GIOWin32Channel *channel, - gchar *dest, - gsize count, - gsize *bytes_read, - GError **err) -{ - guint nbytes; - guint left = count; - - EnterCriticalSection (&channel->mutex); - if (channel->debug) - g_print ("reading from thread %#x %" G_GSIZE_FORMAT " bytes, rdp=%d, wrp=%d\n", - channel->thread_id, count, channel->rdp, channel->wrp); - - if (channel->wrp == channel->rdp) - { - LeaveCriticalSection (&channel->mutex); - if (channel->debug) - g_print ("waiting for data from thread %#x\n", channel->thread_id); - WaitForSingleObject (channel->data_avail_event, INFINITE); - if (channel->debug) - g_print ("done waiting for data from thread %#x\n", channel->thread_id); - EnterCriticalSection (&channel->mutex); - if (channel->wrp == channel->rdp && !channel->running) - { - if (channel->debug) - g_print ("wrp==rdp, !running\n"); - LeaveCriticalSection (&channel->mutex); - *bytes_read = 0; - return G_IO_STATUS_EOF; - } - } - - if (channel->rdp < channel->wrp) - nbytes = channel->wrp - channel->rdp; - else - nbytes = BUFFER_SIZE - channel->rdp; - LeaveCriticalSection (&channel->mutex); - nbytes = MIN (left, nbytes); - if (channel->debug) - g_print ("moving %d bytes from thread %#x\n", - nbytes, channel->thread_id); - memcpy (dest, channel->buffer + channel->rdp, nbytes); - dest += nbytes; - left -= nbytes; - EnterCriticalSection (&channel->mutex); - channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE; - if (channel->debug) - g_print ("setting space_avail for thread %#x\n", channel->thread_id); - SetEvent (channel->space_avail_event); - if (channel->debug) - g_print ("for thread %#x: rdp=%d, wrp=%d\n", - channel->thread_id, channel->rdp, channel->wrp); - if (channel->running && channel->wrp == channel->rdp) - { - if (channel->debug) - g_print ("resetting data_avail of thread %#x\n", - channel->thread_id); - ResetEvent (channel->data_avail_event); - }; - LeaveCriticalSection (&channel->mutex); - - /* We have no way to indicate any errors form the actual - * read() or recv() call in the reader thread. Should we have? - */ - *bytes_read = count - left; - return (*bytes_read > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF; -} - - -static GIOStatus -buffer_write (GIOWin32Channel *channel, - const gchar *dest, - gsize count, - gsize *bytes_written, - GError **err) -{ - guint nbytes; - guint left = count; - - EnterCriticalSection (&channel->mutex); - if (channel->debug) - g_print ("buffer_write: writing to thread %#x %" G_GSIZE_FORMAT " bytes, rdp=%d, wrp=%d\n", - channel->thread_id, count, channel->rdp, channel->wrp); - - if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp) - { - /* Buffer is full */ - if (channel->debug) - g_print ("buffer_write: tid %#x: resetting data_avail\n", - channel->thread_id); - ResetEvent (channel->data_avail_event); - if (channel->debug) - g_print ("buffer_write: tid %#x: waiting for space\n", - channel->thread_id); - LeaveCriticalSection (&channel->mutex); - WaitForSingleObject (channel->data_avail_event, INFINITE); - EnterCriticalSection (&channel->mutex); - if (channel->debug) - g_print ("buffer_write: tid %#x: rdp=%d, wrp=%d\n", - channel->thread_id, channel->rdp, channel->wrp); - } - - nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE, - BUFFER_SIZE - channel->wrp); - - LeaveCriticalSection (&channel->mutex); - nbytes = MIN (left, nbytes); - if (channel->debug) - g_print ("buffer_write: tid %#x: writing %d bytes\n", - channel->thread_id, nbytes); - memcpy (channel->buffer + channel->wrp, dest, nbytes); - dest += nbytes; - left -= nbytes; - EnterCriticalSection (&channel->mutex); - - channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE; - if (channel->debug) - g_print ("buffer_write: tid %#x: rdp=%d, wrp=%d, setting space_avail\n", - channel->thread_id, channel->rdp, channel->wrp); - SetEvent (channel->space_avail_event); - - if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp) - { - /* Buffer is full */ - if (channel->debug) - g_print ("buffer_write: tid %#x: resetting data_avail\n", - channel->thread_id); - ResetEvent (channel->data_avail_event); - } - - LeaveCriticalSection (&channel->mutex); - - /* We have no way to indicate any errors form the actual - * write() call in the writer thread. Should we have? - */ - *bytes_written = count - left; - return (*bytes_written > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF; -} - - -static gboolean -g_io_win32_prepare (GSource *source, - gint *timeout) -{ - GIOWin32Watch *watch = (GIOWin32Watch *)source; - GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel); - GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel; - int event_mask; - - *timeout = -1; - - if (channel->debug) - g_print ("g_io_win32_prepare: source=%p channel=%p", source, channel); - - switch (channel->type) - { - case G_IO_WIN32_WINDOWS_MESSAGES: - if (channel->debug) - g_print (" MSG"); - break; - - case G_IO_WIN32_CONSOLE: - if (channel->debug) - g_print (" CON"); - break; - - case G_IO_WIN32_FILE_DESC: - if (channel->debug) - g_print (" FD thread=%#x buffer_condition:{%s}" - "\n watch->pollfd.events:{%s} watch->pollfd.revents:{%s} channel->revents:{%s}", - channel->thread_id, condition_to_string (buffer_condition), - condition_to_string (watch->pollfd.events), - condition_to_string (watch->pollfd.revents), - condition_to_string (channel->revents)); - - EnterCriticalSection (&channel->mutex); - if (channel->running) - { - if (channel->direction == 0 && channel->wrp == channel->rdp) - { - if (channel->debug) - g_print ("\n setting revents=0"); - channel->revents = 0; - } - } - else - { - if (channel->direction == 1 - && (channel->wrp + 1) % BUFFER_SIZE == channel->rdp) - { - if (channel->debug) - g_print ("\n setting revents=0"); - channel->revents = 0; - } - } - LeaveCriticalSection (&channel->mutex); - break; - - case G_IO_WIN32_SOCKET: - if (channel->debug) - g_print (" SOCK"); - event_mask = 0; - if (watch->condition & G_IO_IN) - event_mask |= (FD_READ | FD_ACCEPT); - if (watch->condition & G_IO_OUT) - event_mask |= (FD_WRITE | FD_CONNECT); - event_mask |= FD_CLOSE; - - if (channel->event_mask != event_mask) - { - if (channel->debug) - g_print ("\n WSAEventSelect(%d,%p,{%s})", - channel->fd, (HANDLE) watch->pollfd.fd, - event_mask_to_string (event_mask)); - if (WSAEventSelect (channel->fd, (HANDLE) watch->pollfd.fd, - event_mask) == SOCKET_ERROR) - if (channel->debug) - { - gchar *emsg = g_win32_error_message (WSAGetLastError ()); - - g_print (" failed: %s", emsg); - g_free (emsg); - } - channel->event_mask = event_mask; - - if (channel->debug) - g_print ("\n setting last_events=0"); - channel->last_events = 0; - - if ((event_mask & FD_WRITE) && - channel->ever_writable && - !channel->write_would_have_blocked) - { - if (channel->debug) - g_print (" WSASetEvent(%p)", (WSAEVENT) watch->pollfd.fd); - WSASetEvent ((WSAEVENT) watch->pollfd.fd); - } - } - break; - - default: - g_assert_not_reached (); - abort (); - } - if (channel->debug) - g_print ("\n"); - - return ((watch->condition & buffer_condition) == watch->condition); -} - -static gboolean -g_io_win32_check (GSource *source) -{ - MSG msg; - GIOWin32Watch *watch = (GIOWin32Watch *)source; - GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel; - GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel); - WSANETWORKEVENTS events; - - if (channel->debug) - g_print ("g_io_win32_check: source=%p channel=%p", source, channel); - - switch (channel->type) - { - case G_IO_WIN32_WINDOWS_MESSAGES: - if (channel->debug) - g_print (" MSG\n"); - return (PeekMessage (&msg, channel->hwnd, 0, 0, PM_NOREMOVE)); - - case G_IO_WIN32_FILE_DESC: - if (channel->debug) - g_print (" FD thread=%#x buffer_condition=%s\n" - " watch->pollfd.events={%s} watch->pollfd.revents={%s} channel->revents={%s}\n", - channel->thread_id, condition_to_string (buffer_condition), - condition_to_string (watch->pollfd.events), - condition_to_string (watch->pollfd.revents), - condition_to_string (channel->revents)); - - watch->pollfd.revents = (watch->pollfd.events & channel->revents); - - return ((watch->pollfd.revents | buffer_condition) & watch->condition); - - case G_IO_WIN32_CONSOLE: - if (channel->debug) - g_print (" CON\n"); - if (watch->channel->is_writeable) - return TRUE; - else if (watch->channel->is_readable) - { - INPUT_RECORD buffer; - DWORD n; - if (PeekConsoleInput ((HANDLE) watch->pollfd.fd, &buffer, 1, &n) && - n == 1) - { - /* _kbhit() does quite complex processing to find out - * whether at least one of the key events pending corresponds - * to a "real" character that can be read. - */ - if (_kbhit ()) - return TRUE; - - /* Discard all other kinds of events */ - ReadConsoleInput ((HANDLE) watch->pollfd.fd, &buffer, 1, &n); - } - } - return FALSE; - - case G_IO_WIN32_SOCKET: - if (channel->debug) - g_print (" SOCK"); - if (channel->last_events & FD_WRITE) - { - if (channel->debug) - g_print (" sock=%d event=%p last_events has FD_WRITE", - channel->fd, (HANDLE) watch->pollfd.fd); - } - else - { - WSAEnumNetworkEvents (channel->fd, 0, &events); - - if (channel->debug) - g_print ("\n revents={%s} condition={%s}" - "\n WSAEnumNetworkEvents(%d,0) sets events={%s}", - condition_to_string (watch->pollfd.revents), - condition_to_string (watch->condition), - channel->fd, - event_mask_to_string (events.lNetworkEvents)); - - if (watch->pollfd.revents != 0 && - events.lNetworkEvents == 0 && - !(channel->event_mask & FD_WRITE)) - { - channel->event_mask = 0; - if (channel->debug) - g_print ("\n WSAEventSelect(%d,%p,{})", - channel->fd, (HANDLE) watch->pollfd.fd); - WSAEventSelect (channel->fd, (HANDLE) watch->pollfd.fd, 0); - if (channel->debug) - g_print (" ResetEvent(%p)", - (HANDLE) watch->pollfd.fd); - ResetEvent ((HANDLE) watch->pollfd.fd); - } - else if (events.lNetworkEvents & FD_WRITE) - channel->ever_writable = TRUE; - channel->last_events = events.lNetworkEvents; - } - - watch->pollfd.revents = 0; - if (channel->last_events & (FD_READ | FD_ACCEPT)) - watch->pollfd.revents |= G_IO_IN; - - if (channel->last_events & FD_WRITE) - watch->pollfd.revents |= G_IO_OUT; - else - { - /* We have called WSAEnumNetworkEvents() above but it didn't - * set FD_WRITE. - */ - if (events.lNetworkEvents & FD_CONNECT) - { - if (events.iErrorCode[FD_CONNECT_BIT] == 0) - watch->pollfd.revents |= G_IO_OUT; - else - watch->pollfd.revents |= (G_IO_HUP | G_IO_ERR); - } - if (watch->pollfd.revents == 0 && (channel->last_events & (FD_CLOSE))) - watch->pollfd.revents |= G_IO_HUP; - } - - /* Regardless of WSAEnumNetworkEvents() result, if watching for - * writability, and if we have ever got a FD_WRITE event, and - * unless last write would have blocked, set G_IO_OUT. But never - * set both G_IO_OUT and G_IO_HUP. - */ - if (!(watch->pollfd.revents & G_IO_HUP) && - channel->ever_writable && - !channel->write_would_have_blocked && - (channel->event_mask & FD_WRITE)) - watch->pollfd.revents |= G_IO_OUT; - - if (channel->debug) - g_print ("\n revents={%s} retval={%s}\n", - condition_to_string (watch->pollfd.revents), - condition_to_string ((watch->pollfd.revents | buffer_condition) & watch->condition)); - - return ((watch->pollfd.revents | buffer_condition) & watch->condition); - - default: - g_assert_not_reached (); - abort (); - } -} - -static gboolean -g_io_win32_dispatch (GSource *source, - GSourceFunc callback, - gpointer user_data) -{ - GIOFunc func = (GIOFunc)callback; - GIOWin32Watch *watch = (GIOWin32Watch *)source; - GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel; - GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel); - - if (!func) - { - g_warning ("IO Watch dispatched without callback\n" - "You must call g_source_connect()."); - return FALSE; - } - - if (channel->debug) - g_print ("g_io_win32_dispatch: pollfd.revents=%s condition=%s result=%s\n", - condition_to_string (watch->pollfd.revents), - condition_to_string (watch->condition), - condition_to_string ((watch->pollfd.revents | buffer_condition) & watch->condition)); - - return (*func) (watch->channel, - (watch->pollfd.revents | buffer_condition) & watch->condition, - user_data); -} - -static void -g_io_win32_finalize (GSource *source) -{ - GIOWin32Watch *watch = (GIOWin32Watch *)source; - GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel; - - if (channel->debug) - g_print ("g_io_win32_finalize: source=%p channel=%p", source, channel); - - switch (channel->type) - { - case G_IO_WIN32_WINDOWS_MESSAGES: - if (channel->debug) - g_print (" MSG"); - break; - - case G_IO_WIN32_CONSOLE: - if (channel->debug) - g_print (" CON"); - break; - - case G_IO_WIN32_FILE_DESC: - if (channel->debug) - g_print (" FD thread=%#x", channel->thread_id); - break; - - case G_IO_WIN32_SOCKET: - if (channel->debug) - g_print (" SOCK sock=%d", channel->fd); - break; - - default: - g_assert_not_reached (); - abort (); - } - if (channel->debug) - g_print ("\n"); - g_io_channel_unref (watch->channel); -} - -GSourceFuncs g_io_watch_funcs = { - g_io_win32_prepare, - g_io_win32_check, - g_io_win32_dispatch, - g_io_win32_finalize -}; - -static GIOStatus -g_io_win32_msg_read (GIOChannel *channel, - gchar *buf, - gsize count, - gsize *bytes_read, - GError **err) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - MSG msg; /* In case of alignment problems */ - - if (count < sizeof (MSG)) - { - g_set_error_literal (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL, - "Incorrect message size"); /* Informative enough error message? */ - return G_IO_STATUS_ERROR; - } - - if (win32_channel->debug) - g_print ("g_io_win32_msg_read: channel=%p hwnd=%p\n", - channel, win32_channel->hwnd); - if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE)) - return G_IO_STATUS_AGAIN; - - memmove (buf, &msg, sizeof (MSG)); - *bytes_read = sizeof (MSG); - - return G_IO_STATUS_NORMAL; -} - -static GIOStatus -g_io_win32_msg_write (GIOChannel *channel, - const gchar *buf, - gsize count, - gsize *bytes_written, - GError **err) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - MSG msg; - - if (count != sizeof (MSG)) - { - g_set_error_literal (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL, - "Incorrect message size"); /* Informative enough error message? */ - return G_IO_STATUS_ERROR; - } - - /* In case of alignment problems */ - memmove (&msg, buf, sizeof (MSG)); - if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam)) - { - gchar *emsg = g_win32_error_message (GetLastError ()); - - g_set_error_literal (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg); - g_free (emsg); - - return G_IO_STATUS_ERROR; - } - - *bytes_written = sizeof (MSG); - - return G_IO_STATUS_NORMAL; -} - -static GIOStatus -g_io_win32_msg_close (GIOChannel *channel, - GError **err) -{ - /* Nothing to be done. Or should we set hwnd to some invalid value? */ - - return G_IO_STATUS_NORMAL; -} - -static void -g_io_win32_free (GIOChannel *channel) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - - if (win32_channel->debug) - g_print ("g_io_win32_free channel=%p fd=%d\n", channel, win32_channel->fd); - - DeleteCriticalSection (&win32_channel->mutex); - - if (win32_channel->data_avail_event) - if (!CloseHandle (win32_channel->data_avail_event)) - if (win32_channel->debug) - { - gchar *emsg = g_win32_error_message (GetLastError ()); - - g_print (" CloseHandle(%p) failed: %s\n", - win32_channel->data_avail_event, emsg); - g_free (emsg); - } - - g_free (win32_channel->buffer); - - if (win32_channel->space_avail_event) - if (!CloseHandle (win32_channel->space_avail_event)) - if (win32_channel->debug) - { - gchar *emsg = g_win32_error_message (GetLastError ()); - - g_print (" CloseHandle(%p) failed: %s\n", - win32_channel->space_avail_event, emsg); - g_free (emsg); - } - - if (win32_channel->type == G_IO_WIN32_SOCKET) - if (WSAEventSelect (win32_channel->fd, NULL, 0) == SOCKET_ERROR) - if (win32_channel->debug) - { - gchar *emsg = g_win32_error_message (WSAGetLastError ()); - - g_print (" WSAEventSelect(%d,NULL,{}) failed: %s\n", - win32_channel->fd, emsg); - g_free (emsg); - } - - if (win32_channel->event) - if (!WSACloseEvent (win32_channel->event)) - if (win32_channel->debug) - { - gchar *emsg = g_win32_error_message (WSAGetLastError ()); - - g_print (" WSACloseEvent(%p) failed: %s\n", - win32_channel->event, emsg); - g_free (emsg); - } - - g_free (win32_channel); -} - -static GSource * -g_io_win32_msg_create_watch (GIOChannel *channel, - GIOCondition condition) -{ - GIOWin32Watch *watch; - GSource *source; - - source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch)); - watch = (GIOWin32Watch *)source; - - watch->channel = channel; - g_io_channel_ref (channel); - - watch->condition = condition; - - watch->pollfd.fd = (gintptr) G_WIN32_MSG_HANDLE; - watch->pollfd.events = condition; - - g_source_add_poll (source, &watch->pollfd); - - return source; -} - -static GIOStatus -g_io_win32_fd_and_console_read (GIOChannel *channel, - gchar *buf, - gsize count, - gsize *bytes_read, - GError **err) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - gint result; - - if (win32_channel->debug) - g_print ("g_io_win32_fd_read: fd=%d count=%" G_GSIZE_FORMAT "\n", - win32_channel->fd, count); - - if (win32_channel->thread_id) - { - return buffer_read (win32_channel, buf, count, bytes_read, err); - } - - result = read (win32_channel->fd, buf, count); - - if (win32_channel->debug) - g_print ("g_io_win32_fd_read: read() => %d\n", result); - - if (result < 0) - { - *bytes_read = 0; - - switch (errno) - { -#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 (errno), - g_strerror (errno)); - return G_IO_STATUS_ERROR; - } - } - - *bytes_read = result; - - return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF; -} - -static GIOStatus -g_io_win32_fd_and_console_write (GIOChannel *channel, - const gchar *buf, - gsize count, - gsize *bytes_written, - GError **err) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - gint result; - - if (win32_channel->thread_id) - { - return buffer_write (win32_channel, buf, count, bytes_written, err); - } - - result = write (win32_channel->fd, buf, count); - if (win32_channel->debug) - g_print ("g_io_win32_fd_write: fd=%d count=%" G_GSIZE_FORMAT " => %d\n", - win32_channel->fd, count, result); - - if (result < 0) - { - *bytes_written = 0; - - switch (errno) - { -#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 (errno), - g_strerror (errno)); - return G_IO_STATUS_ERROR; - } - } - - *bytes_written = result; - - return G_IO_STATUS_NORMAL; -} - -static GIOStatus -g_io_win32_fd_seek (GIOChannel *channel, - gint64 offset, - GSeekType type, - GError **err) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)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; /* Keep the compiler quiet */ - g_assert_not_reached (); - abort (); - } - - 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 (win32_channel->fd, tmp_offset, whence); - - if (result < 0) - { - g_set_error_literal (err, G_IO_CHANNEL_ERROR, - g_io_channel_error_from_errno (errno), - g_strerror (errno)); - return G_IO_STATUS_ERROR; - } - - return G_IO_STATUS_NORMAL; -} - -static GIOStatus -g_io_win32_fd_close (GIOChannel *channel, - GError **err) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - - if (win32_channel->debug) - g_print ("g_io_win32_fd_close: thread=%#x: fd=%d\n", - win32_channel->thread_id, - win32_channel->fd); - EnterCriticalSection (&win32_channel->mutex); - if (win32_channel->running) - { - if (win32_channel->debug) - g_print ("thread %#x: running, marking fd %d for later close\n", - win32_channel->thread_id, win32_channel->fd); - win32_channel->running = FALSE; - win32_channel->needs_close = TRUE; - if (win32_channel->direction == 0) - SetEvent (win32_channel->data_avail_event); - else - SetEvent (win32_channel->space_avail_event); - } - else - { - if (win32_channel->debug) - g_print ("closing fd %d\n", win32_channel->fd); - close (win32_channel->fd); - if (win32_channel->debug) - g_print ("closed fd %d, setting to -1\n", - win32_channel->fd); - win32_channel->fd = -1; - } - LeaveCriticalSection (&win32_channel->mutex); - - /* FIXME error detection? */ - - return G_IO_STATUS_NORMAL; -} - -static GSource * -g_io_win32_fd_create_watch (GIOChannel *channel, - GIOCondition condition) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - GSource *source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch)); - GIOWin32Watch *watch = (GIOWin32Watch *)source; - - watch->channel = channel; - g_io_channel_ref (channel); - - watch->condition = condition; - - if (win32_channel->data_avail_event == NULL) - create_events (win32_channel); - - watch->pollfd.fd = (gintptr) win32_channel->data_avail_event; - watch->pollfd.events = condition; - - if (win32_channel->debug) - g_print ("g_io_win32_fd_create_watch: channel=%p fd=%d condition={%s} event=%p\n", - channel, win32_channel->fd, - condition_to_string (condition), (HANDLE) watch->pollfd.fd); - - EnterCriticalSection (&win32_channel->mutex); - if (win32_channel->thread_id == 0) - { - if (condition & G_IO_IN) - create_thread (win32_channel, condition, read_thread); - else if (condition & G_IO_OUT) - create_thread (win32_channel, condition, write_thread); - } - - g_source_add_poll (source, &watch->pollfd); - LeaveCriticalSection (&win32_channel->mutex); - - return source; -} - -static GIOStatus -g_io_win32_console_close (GIOChannel *channel, - GError **err) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - - if (close (win32_channel->fd) < 0) - { - g_set_error_literal (err, G_IO_CHANNEL_ERROR, - g_io_channel_error_from_errno (errno), - g_strerror (errno)); - return G_IO_STATUS_ERROR; - } - - return G_IO_STATUS_NORMAL; -} - -static GSource * -g_io_win32_console_create_watch (GIOChannel *channel, - GIOCondition condition) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - GSource *source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch)); - GIOWin32Watch *watch = (GIOWin32Watch *)source; - - watch->channel = channel; - g_io_channel_ref (channel); - - watch->condition = condition; - - watch->pollfd.fd = _get_osfhandle (win32_channel->fd); - watch->pollfd.events = condition; - - g_source_add_poll (source, &watch->pollfd); - - return source; -} - -static GIOStatus -g_io_win32_sock_read (GIOChannel *channel, - gchar *buf, - gsize count, - gsize *bytes_read, - GError **err) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - gint result; - GIOChannelError error; - int winsock_error; - - if (win32_channel->debug) - g_print ("g_io_win32_sock_read: channel=%p sock=%d count=%" G_GSIZE_FORMAT, - channel, win32_channel->fd, count); - - result = recv (win32_channel->fd, buf, count, 0); - if (result == SOCKET_ERROR) - winsock_error = WSAGetLastError (); - - if (win32_channel->debug) - g_print (" recv=%d", result); - - if (result == SOCKET_ERROR) - { - gchar *emsg = g_win32_error_message (winsock_error); - - if (win32_channel->debug) - g_print (" %s\n", emsg); - - *bytes_read = 0; - - switch (winsock_error) - { - case WSAEINVAL: - error = G_IO_CHANNEL_ERROR_INVAL; - break; - case WSAEWOULDBLOCK: - g_free (emsg); - return G_IO_STATUS_AGAIN; - default: - error = G_IO_CHANNEL_ERROR_FAILED; - break; - } - g_set_error_literal (err, G_IO_CHANNEL_ERROR, error, emsg); - g_free (emsg); - - return G_IO_STATUS_ERROR; - } - else - { - if (win32_channel->debug) - g_print ("\n"); - *bytes_read = result; - if (result == 0) - return G_IO_STATUS_EOF; - else - return G_IO_STATUS_NORMAL; - } -} - -static GIOStatus -g_io_win32_sock_write (GIOChannel *channel, - const gchar *buf, - gsize count, - gsize *bytes_written, - GError **err) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - gint result; - GIOChannelError error; - int winsock_error; - - if (win32_channel->debug) - g_print ("g_io_win32_sock_write: channel=%p sock=%d count=%" G_GSIZE_FORMAT, - channel, win32_channel->fd, count); - - result = send (win32_channel->fd, buf, count, 0); - if (result == SOCKET_ERROR) - winsock_error = WSAGetLastError (); - - if (win32_channel->debug) - g_print (" send=%d", result); - - if (result == SOCKET_ERROR) - { - gchar *emsg = g_win32_error_message (winsock_error); - - if (win32_channel->debug) - g_print (" %s\n", emsg); - - *bytes_written = 0; - - switch (winsock_error) - { - case WSAEINVAL: - error = G_IO_CHANNEL_ERROR_INVAL; - break; - case WSAEWOULDBLOCK: - win32_channel->write_would_have_blocked = TRUE; - win32_channel->last_events = 0; - g_free (emsg); - return G_IO_STATUS_AGAIN; - default: - error = G_IO_CHANNEL_ERROR_FAILED; - break; - } - g_set_error_literal (err, G_IO_CHANNEL_ERROR, error, emsg); - g_free (emsg); - - return G_IO_STATUS_ERROR; - } - else - { - if (win32_channel->debug) - g_print ("\n"); - *bytes_written = result; - win32_channel->write_would_have_blocked = FALSE; - - return G_IO_STATUS_NORMAL; - } -} - -static GIOStatus -g_io_win32_sock_close (GIOChannel *channel, - GError **err) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - - if (win32_channel->fd != -1) - { - if (win32_channel->debug) - g_print ("g_io_win32_sock_close: channel=%p sock=%d\n", - channel, win32_channel->fd); - - closesocket (win32_channel->fd); - win32_channel->fd = -1; - } - - /* FIXME error detection? */ - - return G_IO_STATUS_NORMAL; -} - -static GSource * -g_io_win32_sock_create_watch (GIOChannel *channel, - GIOCondition condition) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - GSource *source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch)); - GIOWin32Watch *watch = (GIOWin32Watch *)source; - - watch->channel = channel; - g_io_channel_ref (channel); - - watch->condition = condition; - - if (win32_channel->event == 0) - win32_channel->event = WSACreateEvent (); - - watch->pollfd.fd = (gintptr) win32_channel->event; - watch->pollfd.events = condition; - - if (win32_channel->debug) - g_print ("g_io_win32_sock_create_watch: channel=%p sock=%d event=%p condition={%s}\n", - channel, win32_channel->fd, (HANDLE) watch->pollfd.fd, - condition_to_string (watch->condition)); - - g_source_add_poll (source, &watch->pollfd); - - return source; -} - -GIOChannel * -g_io_channel_new_file (const gchar *filename, - const gchar *mode, - GError **error) -{ - int fid, flags, pmode; - GIOChannel *channel; - - enum { /* Cheesy hack */ - MODE_R = 1 << 0, - MODE_W = 1 << 1, - MODE_A = 1 << 2, - MODE_PLUS = 1 << 3, - } mode_num; - - 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; - } - /* Fall through */ - default: - g_warning ("Invalid GIOFileMode %s.", mode); - return NULL; - } - - switch (mode_num) - { - case MODE_R: - flags = O_RDONLY; - pmode = _S_IREAD; - break; - case MODE_W: - flags = O_WRONLY | O_TRUNC | O_CREAT; - pmode = _S_IWRITE; - break; - case MODE_A: - flags = O_WRONLY | O_APPEND | O_CREAT; - pmode = _S_IWRITE; - break; - case MODE_R | MODE_PLUS: - flags = O_RDWR; - pmode = _S_IREAD | _S_IWRITE; - break; - case MODE_W | MODE_PLUS: - flags = O_RDWR | O_TRUNC | O_CREAT; - pmode = _S_IREAD | _S_IWRITE; - break; - case MODE_A | MODE_PLUS: - flags = O_RDWR | O_APPEND | O_CREAT; - pmode = _S_IREAD | _S_IWRITE; - break; - default: - g_assert_not_reached (); - abort (); - } - - /* always open 'untranslated' */ - fid = g_open (filename, flags | _O_BINARY, pmode); - - if (g_io_win32_get_debug_flag ()) - { - g_print ("g_io_channel_win32_new_file: open(\"%s\",", filename); - g_win32_print_access_mode (flags|_O_BINARY); - g_print (",%#o)=%d\n", pmode, fid); - } - - if (fid < 0) - { - g_set_error_literal (error, G_FILE_ERROR, - g_file_error_from_errno (errno), - g_strerror (errno)); - return (GIOChannel *)NULL; - } - - channel = g_io_channel_win32_new_fd (fid); - - /* XXX: move this to g_io_channel_win32_new_fd () */ - channel->close_on_unref = TRUE; - channel->is_seekable = TRUE; - - /* g_io_channel_win32_new_fd sets is_readable and is_writeable to - * correspond to actual readability/writeability. Set to FALSE those - * that mode doesn't allow - */ - switch (mode_num) - { - case MODE_R: - channel->is_writeable = FALSE; - break; - case MODE_W: - case MODE_A: - channel->is_readable = FALSE; - break; - case MODE_R | MODE_PLUS: - case MODE_W | MODE_PLUS: - case MODE_A | MODE_PLUS: - break; - default: - g_assert_not_reached (); - abort (); - } - - return channel; -} - -#if !defined (_WIN64) - -#undef g_io_channel_new_file - -/* Binary compatibility version. Not for newly compiled code. */ - -GIOChannel * -g_io_channel_new_file (const gchar *filename, - const gchar *mode, - GError **error) -{ - gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, error); - GIOChannel *retval; - - if (utf8_filename == NULL) - return NULL; - - retval = g_io_channel_new_file_utf8 (utf8_filename, mode, error); - - g_free (utf8_filename); - - return retval; -} - -#endif - -static GIOStatus -g_io_win32_unimpl_set_flags (GIOChannel *channel, - GIOFlags flags, - GError **err) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - - if (win32_channel->debug) - { - g_print ("g_io_win32_unimpl_set_flags: "); - g_win32_print_gioflags (flags); - g_print ("\n"); - } - - g_set_error_literal (err, G_IO_CHANNEL_ERROR, - G_IO_CHANNEL_ERROR_FAILED, - "Not implemented on Win32"); - - return G_IO_STATUS_ERROR; -} - -static GIOFlags -g_io_win32_fd_get_flags_internal (GIOChannel *channel, - struct stat *st) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel; - gchar c; - DWORD count; - - if (st->st_mode & _S_IFIFO) - { - channel->is_readable = - (PeekNamedPipe ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL, NULL) != 0) || GetLastError () == ERROR_BROKEN_PIPE; - channel->is_writeable = - (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0); - channel->is_seekable = FALSE; - } - else - { - channel->is_readable = - (ReadFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0); - channel->is_writeable = - (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0); - channel->is_seekable = TRUE; - } - - /* XXX: G_IO_FLAG_APPEND */ - /* XXX: G_IO_FLAG_NONBLOCK */ - - return 0; -} - -static GIOFlags -g_io_win32_fd_get_flags (GIOChannel *channel) -{ - struct stat st; - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - - g_return_val_if_fail (win32_channel != NULL, 0); - g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0); - - if (0 == fstat (win32_channel->fd, &st)) - return g_io_win32_fd_get_flags_internal (channel, &st); - else - return 0; -} - -static GIOFlags -g_io_win32_console_get_flags_internal (GIOChannel *channel) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel; - HANDLE handle = (HANDLE) _get_osfhandle (win32_channel->fd); - gchar c; - DWORD count; - INPUT_RECORD record; - - channel->is_readable = PeekConsoleInput (handle, &record, 1, &count); - channel->is_writeable = WriteFile (handle, &c, 0, &count, NULL); - channel->is_seekable = FALSE; - - return 0; -} - -static GIOFlags -g_io_win32_console_get_flags (GIOChannel *channel) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - - g_return_val_if_fail (win32_channel != NULL, 0); - g_return_val_if_fail (win32_channel->type == G_IO_WIN32_CONSOLE, 0); - - return g_io_win32_console_get_flags_internal (channel); -} - -static GIOFlags -g_io_win32_msg_get_flags (GIOChannel *channel) -{ - return 0; -} - -static GIOStatus -g_io_win32_sock_set_flags (GIOChannel *channel, - GIOFlags flags, - GError **err) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - u_long arg; - - if (win32_channel->debug) - { - g_print ("g_io_win32_sock_set_flags: "); - g_win32_print_gioflags (flags); - g_print ("\n"); - } - - if (flags & G_IO_FLAG_NONBLOCK) - { - arg = 1; - if (ioctlsocket (win32_channel->fd, FIONBIO, &arg) == SOCKET_ERROR) - { - gchar *emsg = g_win32_error_message (WSAGetLastError ()); - - g_set_error_literal (err, G_IO_CHANNEL_ERROR, - G_IO_CHANNEL_ERROR_FAILED, - emsg); - g_free (emsg); - - return G_IO_STATUS_ERROR; - } - } - else - { - arg = 0; - if (ioctlsocket (win32_channel->fd, FIONBIO, &arg) == SOCKET_ERROR) - { - gchar *emsg = g_win32_error_message (WSAGetLastError ()); - - g_set_error_literal (err, G_IO_CHANNEL_ERROR, - G_IO_CHANNEL_ERROR_FAILED, - emsg); - g_free (emsg); - - return G_IO_STATUS_ERROR; - } - } - - return G_IO_STATUS_NORMAL; -} - -static GIOFlags -g_io_win32_sock_get_flags (GIOChannel *channel) -{ - /* Could we do something here? */ - return 0; -} - -static GIOFuncs win32_channel_msg_funcs = { - g_io_win32_msg_read, - g_io_win32_msg_write, - NULL, - g_io_win32_msg_close, - g_io_win32_msg_create_watch, - g_io_win32_free, - g_io_win32_unimpl_set_flags, - g_io_win32_msg_get_flags, -}; - -static GIOFuncs win32_channel_fd_funcs = { - g_io_win32_fd_and_console_read, - g_io_win32_fd_and_console_write, - g_io_win32_fd_seek, - g_io_win32_fd_close, - g_io_win32_fd_create_watch, - g_io_win32_free, - g_io_win32_unimpl_set_flags, - g_io_win32_fd_get_flags, -}; - -static GIOFuncs win32_channel_console_funcs = { - g_io_win32_fd_and_console_read, - g_io_win32_fd_and_console_write, - NULL, - g_io_win32_console_close, - g_io_win32_console_create_watch, - g_io_win32_free, - g_io_win32_unimpl_set_flags, - g_io_win32_console_get_flags, -}; - -static GIOFuncs win32_channel_sock_funcs = { - g_io_win32_sock_read, - g_io_win32_sock_write, - NULL, - g_io_win32_sock_close, - g_io_win32_sock_create_watch, - g_io_win32_free, - g_io_win32_sock_set_flags, - g_io_win32_sock_get_flags, -}; - -GIOChannel * -#if GLIB_SIZEOF_VOID_P == 8 -g_io_channel_win32_new_messages (gsize hwnd) -#else -g_io_channel_win32_new_messages (guint hwnd) -#endif -{ - GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1); - GIOChannel *channel = (GIOChannel *)win32_channel; - - g_io_channel_init (channel); - g_io_channel_win32_init (win32_channel); - if (win32_channel->debug) - g_print ("g_io_channel_win32_new_messages: channel=%p hwnd=%p\n", - channel, (HWND) hwnd); - channel->funcs = &win32_channel_msg_funcs; - win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES; - win32_channel->hwnd = (HWND) hwnd; - - /* XXX: check this. */ - channel->is_readable = IsWindow (win32_channel->hwnd); - channel->is_writeable = IsWindow (win32_channel->hwnd); - - channel->is_seekable = FALSE; - - return channel; -} - -static GIOChannel * -g_io_channel_win32_new_fd_internal (gint fd, - struct stat *st) -{ - GIOWin32Channel *win32_channel; - GIOChannel *channel; - - win32_channel = g_new (GIOWin32Channel, 1); - channel = (GIOChannel *)win32_channel; - - g_io_channel_init (channel); - g_io_channel_win32_init (win32_channel); - - win32_channel->fd = fd; - - if (win32_channel->debug) - g_print ("g_io_channel_win32_new_fd: channel=%p fd=%u\n", - channel, fd); - - if (st->st_mode & _S_IFCHR) /* console */ - { - channel->funcs = &win32_channel_console_funcs; - win32_channel->type = G_IO_WIN32_CONSOLE; - g_io_win32_console_get_flags_internal (channel); - } - else - { - channel->funcs = &win32_channel_fd_funcs; - win32_channel->type = G_IO_WIN32_FILE_DESC; - g_io_win32_fd_get_flags_internal (channel, st); - } - - return channel; -} - -GIOChannel * -g_io_channel_win32_new_fd (gint fd) -{ - struct stat st; - - if (fstat (fd, &st) == -1) - { - g_warning ("g_io_channel_win32_new_fd: %d isn't an open file descriptor in the C library GLib uses.", fd); - return NULL; - } - - return g_io_channel_win32_new_fd_internal (fd, &st); -} - -gint -g_io_channel_win32_get_fd (GIOChannel *channel) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - - return win32_channel->fd; -} - -GIOChannel * -g_io_channel_win32_new_socket (int socket) -{ - GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1); - GIOChannel *channel = (GIOChannel *)win32_channel; - - g_io_channel_init (channel); - g_io_channel_win32_init (win32_channel); - if (win32_channel->debug) - g_print ("g_io_channel_win32_new_socket: channel=%p sock=%d\n", - channel, socket); - channel->funcs = &win32_channel_sock_funcs; - win32_channel->type = G_IO_WIN32_SOCKET; - win32_channel->fd = socket; - - channel->is_readable = TRUE; - channel->is_writeable = TRUE; - channel->is_seekable = FALSE; - - return channel; -} - -GIOChannel * -g_io_channel_unix_new (gint fd) -{ - gboolean is_fd, is_socket; - struct stat st; - int optval, optlen; - - is_fd = (fstat (fd, &st) == 0); - - optlen = sizeof (optval); - is_socket = (getsockopt (fd, SOL_SOCKET, SO_TYPE, (char *) &optval, &optlen) != SOCKET_ERROR); - - if (is_fd && is_socket) - g_warning ("g_io_channel_unix_new: %d is both a file descriptor and a socket. File descriptor interpretation assumed. To avoid ambiguity, call either g_io_channel_win32_new_fd() or g_io_channel_win32_new_socket() instead.", fd); - - if (is_fd) - return g_io_channel_win32_new_fd_internal (fd, &st); - - if (is_socket) - return g_io_channel_win32_new_socket(fd); - - g_warning ("g_io_channel_unix_new: %d is neither a file descriptor or a socket.", fd); - - return NULL; -} - -gint -g_io_channel_unix_get_fd (GIOChannel *channel) -{ - return g_io_channel_win32_get_fd (channel); -} - -void -g_io_channel_win32_set_debug (GIOChannel *channel, - gboolean flag) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - - win32_channel->debug = flag; -} - -gint -g_io_channel_win32_poll (GPollFD *fds, - gint n_fds, - gint timeout) -{ - g_return_val_if_fail (n_fds >= 0, 0); - - return g_poll (fds, n_fds, timeout); -} - -void -g_io_channel_win32_make_pollfd (GIOChannel *channel, - GIOCondition condition, - GPollFD *fd) -{ - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - - switch (win32_channel->type) - { - case G_IO_WIN32_FILE_DESC: - if (win32_channel->data_avail_event == NULL) - create_events (win32_channel); - - fd->fd = (gintptr) win32_channel->data_avail_event; - - if (win32_channel->thread_id == 0) - { - /* Is it meaningful for a file descriptor to be polled for - * both IN and OUT? For what kind of file descriptor would - * that be? Doesn't seem to make sense, in practise the file - * descriptors handled here are always read or write ends of - * pipes surely, and thus unidirectional. - */ - if (condition & G_IO_IN) - create_thread (win32_channel, condition, read_thread); - else if (condition & G_IO_OUT) - create_thread (win32_channel, condition, write_thread); - } - break; - - case G_IO_WIN32_CONSOLE: - fd->fd = _get_osfhandle (win32_channel->fd); - break; - - case G_IO_WIN32_SOCKET: - fd->fd = (gintptr) WSACreateEvent (); - break; - - case G_IO_WIN32_WINDOWS_MESSAGES: - fd->fd = G_WIN32_MSG_HANDLE; - break; - - default: - g_assert_not_reached (); - abort (); - } - - fd->events = condition; -} - -#ifndef _WIN64 - -/* Binary compatibility */ -GIOChannel * -g_io_channel_win32_new_stream_socket (int socket) -{ - return g_io_channel_win32_new_socket (socket); -} - -#endif - -#define __G_IO_WIN32_C__ -#include "galiasdef.c" diff --git a/glib/glib-mirroring-tab/Makefile b/glib/glib-mirroring-tab/Makefile deleted file mode 100644 index 8ab193c17..000000000 --- a/glib/glib-mirroring-tab/Makefile +++ /dev/null @@ -1,11 +0,0 @@ - -CFLAGS = `pkg-config --cflags glib-2.0` -LIBS = `pkg-config --libs glib-2.0` - - -all: gen-mirroring-tab - -gen-mirroring-tab: gen-mirroring-tab.o packtab.o - -clean: - $(RM) gen-mirroring-tab *.o diff --git a/glib/glib-mirroring-tab/gen-mirroring-tab.c b/glib/glib-mirroring-tab/gen-mirroring-tab.c deleted file mode 100644 index 6b1637657..000000000 --- a/glib/glib-mirroring-tab/gen-mirroring-tab.c +++ /dev/null @@ -1,232 +0,0 @@ -/* 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, in a file named COPYING; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA - * - * 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 %ld: %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; -} diff --git a/glib/glib-mirroring-tab/packtab.c b/glib/glib-mirroring-tab/packtab.c deleted file mode 100644 index 7c0ff5db4..000000000 --- a/glib/glib-mirroring-tab/packtab.c +++ /dev/null @@ -1,424 +0,0 @@ -/* 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, in a file named COPYING; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA - * - * 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 */ diff --git a/glib/glib-mirroring-tab/packtab.h b/glib/glib-mirroring-tab/packtab.h deleted file mode 100644 index 7cab9be31..000000000 --- a/glib/glib-mirroring-tab/packtab.h +++ /dev/null @@ -1,50 +0,0 @@ -/* 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, in a file named COPYING; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA - * - * 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 */ diff --git a/glib/glib.rc.in b/glib/glib.rc.in deleted file mode 100644 index 77596cc41..000000000 --- a/glib/glib.rc.in +++ /dev/null @@ -1,30 +0,0 @@ -#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-1997 Peter Mattis, Spencer Kimball and Josh MacDonald. Modified by the GLib Team and others 1997-2004." - 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 diff --git a/glib/glib.symbols b/glib/glib.symbols deleted file mode 100644 index a8b7b44f0..000000000 --- a/glib/glib.symbols +++ /dev/null @@ -1,1655 +0,0 @@ -/* This file lists all exported symbols. It is used to generate - * the glib.def file used to control exports on Windows and the - * galias.h/galiasdef.c files used to avoid PLT entries for - * internal uses of exported functions (see makegalias.pl). - * - * Every symbol must be included in the right - * #ifdef IN_HEADER(sym) #endif and - * #ifdef IN_FILE(sym) #endif sections. - */ -#ifdef ALL_FILES -#define IN_FILE(x) 1 -#define IN_HEADER(x) 1 -#endif -#if IN_HEADER(__G_ARRAY_H__) -#if IN_FILE(__G_ARRAY_C__) -g_array_append_vals -g_array_free -g_array_insert_vals -g_array_new -g_array_prepend_vals -g_array_remove_index -g_array_remove_index_fast -g_array_remove_range -g_array_set_size -g_array_sized_new -g_array_sort -g_array_sort_with_data -g_byte_array_append -g_byte_array_free -g_byte_array_new -g_byte_array_prepend -g_byte_array_remove_index -g_byte_array_remove_index_fast -g_byte_array_remove_range -g_byte_array_set_size -g_byte_array_sized_new -g_byte_array_sort -g_byte_array_sort_with_data -g_ptr_array_add -g_ptr_array_foreach -g_ptr_array_free -g_ptr_array_new -g_ptr_array_remove -g_ptr_array_remove_fast -g_ptr_array_remove_index -g_ptr_array_remove_index_fast -g_ptr_array_remove_range -g_ptr_array_set_size -g_ptr_array_sized_new -g_ptr_array_sort -g_ptr_array_sort_with_data -#endif -#endif - -#if IN_HEADER(__G_ASYNCQUEUE_H__) -#if IN_FILE(__G_ASYNCQUEUE_C__) -g_async_queue_length -g_async_queue_length_unlocked -g_async_queue_lock -g_async_queue_new -g_async_queue_new_full -g_async_queue_pop -g_async_queue_pop_unlocked -g_async_queue_push -g_async_queue_push_unlocked -g_async_queue_push_sorted -g_async_queue_push_sorted_unlocked -g_async_queue_ref -g_async_queue_sort -g_async_queue_sort_unlocked -g_async_queue_timed_pop -g_async_queue_timed_pop_unlocked -g_async_queue_try_pop -g_async_queue_try_pop_unlocked -g_async_queue_unlock -g_async_queue_unref -#ifndef G_DISABLE_DEPRECATED -g_async_queue_ref_unlocked -g_async_queue_unref_and_unlock -#endif -#endif -#endif - -#if IN_HEADER(__G_ATOMIC_H__) -#if IN_FILE(__G_ATOMIC_C__) -g_atomic_int_add -g_atomic_int_compare_and_exchange -g_atomic_int_exchange_and_add -g_atomic_pointer_compare_and_exchange -#ifdef INCLUDE_INTERNAL_SYMBOLS - /* these are not internal, but we don't want to alias them */ -g_atomic_int_get -g_atomic_pointer_get -g_atomic_int_set -g_atomic_pointer_set -#endif -#endif -#endif - -#if IN_HEADER(__G_BACKTRACE_H__) -#if IN_FILE(__G_BACKTRACE_C__) -g_on_error_query -g_on_error_stack_trace -#endif -#endif - -#if IN_HEADER(__G_BASE64_H__) -#if IN_FILE(__G_BASE64_C__) -g_base64_encode_step -g_base64_encode_close -g_base64_encode G_GNUC_MALLOC -g_base64_decode_step -g_base64_decode G_GNUC_MALLOC -g_base64_decode_inplace -#endif -#endif - -#if IN_HEADER(__G_BOOKMARK_FILE_H__) -#if IN_FILE(__G_BOOKMARK_FILE_C__) -g_bookmark_file_error_quark -g_bookmark_file_new -g_bookmark_file_free -g_bookmark_file_load_from_file -g_bookmark_file_load_from_data -g_bookmark_file_load_from_data_dirs -g_bookmark_file_to_data -g_bookmark_file_to_file -g_bookmark_file_set_title -g_bookmark_file_get_title G_GNUC_MALLOC -g_bookmark_file_set_description -g_bookmark_file_get_description G_GNUC_MALLOC -g_bookmark_file_set_mime_type -g_bookmark_file_get_mime_type G_GNUC_MALLOC -g_bookmark_file_set_groups -g_bookmark_file_add_group -g_bookmark_file_has_group -g_bookmark_file_get_groups G_GNUC_MALLOC -g_bookmark_file_add_application -g_bookmark_file_has_application -g_bookmark_file_get_applications G_GNUC_MALLOC -g_bookmark_file_set_app_info -g_bookmark_file_get_app_info -g_bookmark_file_set_is_private -g_bookmark_file_get_is_private -g_bookmark_file_set_icon -g_bookmark_file_get_icon -g_bookmark_file_set_added -g_bookmark_file_get_added -g_bookmark_file_set_modified -g_bookmark_file_get_modified -g_bookmark_file_set_visited -g_bookmark_file_get_visited -g_bookmark_file_has_item -g_bookmark_file_get_size -g_bookmark_file_get_uris G_GNUC_MALLOC -g_bookmark_file_remove_group -g_bookmark_file_remove_application -g_bookmark_file_remove_item -g_bookmark_file_move_item -#endif -#endif - -#if IN_HEADER(__G_CACHE_H__) -#if IN_FILE(__G_CACHE_C__) -g_cache_destroy -g_cache_insert -g_cache_key_foreach -g_cache_new -g_cache_remove -#ifndef G_DISABLE_DEPRECATED -g_cache_value_foreach -#endif -#endif -#endif - -#if IN_HEADER(__G_CHECKSUM_H__) -#if IN_FILE(__G_CHECKSUM_C__) -g_checksum_type_get_length -g_checksum_new -g_checksum_copy -g_checksum_free -g_checksum_update -g_checksum_reset -g_checksum_get_string -g_checksum_get_digest -g_compute_checksum_for_data -g_compute_checksum_for_string -#endif -#endif - -#if IN_HEADER(__G_COMPLETION_H__) -#if IN_FILE(__G_COMPLETION_C__) -g_completion_add_items -g_completion_clear_items -g_completion_complete -g_completion_complete_utf8 -g_completion_free -g_completion_new -g_completion_remove_items -g_completion_set_compare -#endif -#endif - -#if IN_HEADER(__G_CONVERT_H__) -#if IN_FILE(__G_CONVERT_C__) -g_get_filename_charsets -g_convert G_GNUC_MALLOC -g_convert_error_quark -g_convert_with_fallback G_GNUC_MALLOC -g_convert_with_iconv G_GNUC_MALLOC -g_iconv -g_iconv_close -g_iconv_open -g_locale_from_utf8 G_GNUC_MALLOC -g_locale_to_utf8 G_GNUC_MALLOC -g_filename_display_name G_GNUC_MALLOC -g_filename_display_basename G_GNUC_MALLOC -#ifndef _WIN64 -g_filename_from_uri PRIVATE G_GNUC_MALLOC -g_filename_from_utf8 PRIVATE G_GNUC_MALLOC -g_filename_to_uri PRIVATE G_GNUC_MALLOC -g_filename_to_utf8 PRIVATE G_GNUC_MALLOC -#endif -#ifdef G_OS_WIN32 -g_filename_from_uri_utf8 G_GNUC_MALLOC -g_filename_from_utf8_utf8 -g_filename_to_uri_utf8 G_GNUC_MALLOC -g_filename_to_utf8_utf8 -#endif -g_uri_list_extract_uris G_GNUC_MALLOC -#endif -#endif - -#if IN_HEADER(__G_DATASET_H__) -#if IN_FILE(__G_DATASET_C__) -g_datalist_clear -g_datalist_foreach -g_datalist_get_flags -g_datalist_id_get_data -g_datalist_id_remove_no_notify -g_datalist_id_set_data_full -g_datalist_set_flags -g_datalist_unset_flags -g_datalist_init -g_dataset_destroy -g_dataset_foreach -g_dataset_id_get_data -g_dataset_id_remove_no_notify -g_dataset_id_set_data_full -#endif -#endif - -#if IN_HEADER(__G_QUARK_H__) -#if IN_FILE(__G_DATASET_C__) -g_quark_from_static_string -g_quark_from_string -g_quark_to_string G_GNUC_CONST -g_quark_try_string -g_intern_string -g_intern_static_string -#endif -#endif - -#if IN_HEADER(__G_DATE_H__) -#if IN_FILE(__G_DATE_C__) -g_date_add_days -g_date_add_months -g_date_add_years -g_date_clamp -g_date_clear -g_date_compare -g_date_days_between -g_date_free -g_date_get_day -g_date_get_day_of_year -g_date_get_days_in_month -g_date_get_iso8601_week_of_year -g_date_get_julian -g_date_get_monday_week_of_year -g_date_get_monday_weeks_in_year G_GNUC_CONST -g_date_get_month -g_date_get_sunday_week_of_year -g_date_get_sunday_weeks_in_year G_GNUC_CONST -g_date_get_weekday -g_date_get_year -g_date_is_first_of_month -g_date_is_last_of_month -g_date_is_leap_year G_GNUC_CONST -g_date_new -g_date_new_dmy -g_date_new_julian -g_date_order -g_date_set_day -g_date_set_dmy -g_date_set_julian -g_date_set_month -g_date_set_parse -#ifndef G_DISABLE_DEPRECATED -g_date_set_time -#endif -g_date_set_time_t -g_date_set_time_val -g_date_set_year -g_date_strftime -g_date_subtract_days -g_date_subtract_months -g_date_subtract_years -g_date_to_struct_tm -g_date_valid -g_date_valid_day G_GNUC_CONST -g_date_valid_dmy -g_date_valid_julian G_GNUC_CONST -g_date_valid_month G_GNUC_CONST -g_date_valid_weekday G_GNUC_CONST -g_date_valid_year G_GNUC_CONST -#endif -#endif - -#if IN_HEADER(__G_DIR_H__) -#if IN_FILE(__G_DIR_C__) -g_dir_close -#ifndef _WIN64 -g_dir_open PRIVATE -g_dir_read_name PRIVATE -#endif -#ifdef G_OS_WIN32 -g_dir_open_utf8 -g_dir_read_name_utf8 -#endif -g_dir_rewind -#endif -#endif - -#if IN_HEADER(__G_ERROR_H__) -#if IN_FILE(__G_ERROR_C__) -g_clear_error -g_error_copy -g_error_free -g_error_matches -g_error_new G_GNUC_PRINTF(3,4) -g_error_new_literal -g_propagate_error -g_set_error G_GNUC_PRINTF(4,5) -g_set_error_literal -g_prefix_error G_GNUC_PRINTF(2,3) -g_propagate_prefixed_error G_GNUC_PRINTF(3,4) -#endif -#endif - -#if IN_HEADER(__G_FILEUTILS_H__) -#if IN_FILE(__G_FILEUTILS_C__) -g_build_filename G_GNUC_MALLOC G_GNUC_NULL_TERMINATED -g_build_filenamev G_GNUC_MALLOC -g_build_path G_GNUC_MALLOC G_GNUC_NULL_TERMINATED -g_build_pathv G_GNUC_MALLOC -g_file_error_from_errno -g_file_error_quark -#ifndef _WIN64 -g_file_get_contents PRIVATE -#endif -g_file_set_contents -#ifndef _WIN64 -g_file_open_tmp PRIVATE -g_file_test PRIVATE -#endif -g_file_read_link -g_format_size_for_display -#ifndef _WIN64 -g_mkstemp PRIVATE -#endif -g_mkdir_with_parents -#ifdef G_OS_WIN32 -g_file_get_contents_utf8 -g_file_open_tmp_utf8 -g_file_test_utf8 -g_mkstemp_utf8 -#endif -#endif -#endif - -#if IN_HEADER(__G_HASH_H__) -#if IN_FILE(__G_HASH_C__) -g_hash_table_destroy -g_hash_table_unref -g_hash_table_ref -g_hash_table_find -g_hash_table_foreach -g_hash_table_foreach_remove -g_hash_table_foreach_steal -g_hash_table_get_keys -g_hash_table_get_values -g_hash_table_insert -g_hash_table_lookup -g_hash_table_lookup_extended -g_hash_table_new -g_hash_table_new_full -g_hash_table_remove -g_hash_table_remove_all -g_hash_table_replace -g_hash_table_size -g_hash_table_steal -g_hash_table_steal_all -g_hash_table_iter_init -g_hash_table_iter_next -g_hash_table_iter_get_hash_table -g_hash_table_iter_remove -g_hash_table_iter_steal -#endif -#endif - -#if IN_HEADER(__G_HOOK_H__) -#if IN_FILE(__G_HOOK_C__) -g_hook_alloc -g_hook_compare_ids -g_hook_destroy -g_hook_destroy_link -g_hook_find -g_hook_find_data -g_hook_find_func -g_hook_find_func_data -g_hook_first_valid -g_hook_free -g_hook_get -g_hook_insert_before -g_hook_insert_sorted -g_hook_list_clear -g_hook_list_init -g_hook_list_invoke -g_hook_list_invoke_check -g_hook_list_marshal -g_hook_list_marshal_check -g_hook_next_valid -g_hook_prepend -g_hook_ref -g_hook_unref -#endif -#endif - -#if IN_HEADER(__G_IOCHANNEL_H__) -#if IN_FILE(__G_IOCHANNEL_C__) -g_io_add_watch -g_io_add_watch_full -g_io_create_watch -g_io_channel_error_from_errno -g_io_channel_error_quark -g_io_channel_flush -g_io_channel_get_buffer_condition -g_io_channel_get_buffered -g_io_channel_get_buffer_size -g_io_channel_get_close_on_unref -g_io_channel_get_encoding -g_io_channel_get_flags -g_io_channel_get_line_term -g_io_channel_init -g_io_channel_read_chars -g_io_channel_read_line -g_io_channel_read_line_string -g_io_channel_read_to_end -g_io_channel_read_unichar -g_io_channel_ref -g_io_channel_seek_position -g_io_channel_set_buffered -g_io_channel_set_buffer_size -g_io_channel_set_close_on_unref -g_io_channel_set_encoding -g_io_channel_set_flags -g_io_channel_set_line_term -g_io_channel_shutdown -g_io_channel_unref -#ifndef G_DISABLE_DEPRECATED -g_io_channel_close -g_io_channel_read -g_io_channel_seek -g_io_channel_write -#endif -g_io_channel_write_chars -g_io_channel_write_unichar -#endif -#endif - -#if IN_HEADER(__G_IOCHANNEL_H__) -#if IN_FILE(__G_IO_UNIX_C__) -#ifdef G_OS_UNIX -g_io_channel_unix_get_fd -g_io_channel_unix_new -g_io_channel_new_file PRIVATE -#endif -#endif -#endif - -#if IN_HEADER(__G_IOCHANNEL_H__) -#if IN_FILE(__G_IO_WIN32_C__) -#ifdef G_OS_WIN32 -g_io_channel_unix_get_fd -g_io_channel_unix_new -#ifndef _WIN64 -g_io_channel_new_file PRIVATE -#endif -g_io_channel_new_file_utf8 -g_io_channel_win32_get_fd -g_io_channel_win32_make_pollfd -g_io_channel_win32_new_fd -g_io_channel_win32_new_messages -g_io_channel_win32_new_socket -#ifndef _WIN64 -g_io_channel_win32_new_stream_socket PRIVATE -#endif -g_io_channel_win32_poll -g_io_channel_win32_set_debug -#endif -#endif -#endif - -#if IN_HEADER(__G_KEY_FILE_H__) -#if IN_FILE(__G_KEY_FILE_C__) -g_key_file_error_quark -g_key_file_free -g_key_file_get_boolean -g_key_file_get_boolean_list G_GNUC_MALLOC -g_key_file_get_comment G_GNUC_MALLOC -g_key_file_get_groups G_GNUC_MALLOC -g_key_file_get_double -g_key_file_get_double_list G_GNUC_MALLOC -g_key_file_get_integer -g_key_file_get_integer_list G_GNUC_MALLOC -g_key_file_get_keys G_GNUC_MALLOC -g_key_file_get_locale_string G_GNUC_MALLOC -g_key_file_get_locale_string_list G_GNUC_MALLOC -g_key_file_get_start_group G_GNUC_MALLOC -g_key_file_get_string G_GNUC_MALLOC -g_key_file_get_string_list G_GNUC_MALLOC -g_key_file_get_value G_GNUC_MALLOC -g_key_file_has_group -g_key_file_has_key -g_key_file_load_from_dirs -g_key_file_load_from_data -g_key_file_load_from_data_dirs -g_key_file_load_from_file -g_key_file_new -g_key_file_remove_comment -g_key_file_remove_group -g_key_file_remove_key -g_key_file_set_boolean -g_key_file_set_boolean_list -g_key_file_set_comment -g_key_file_set_double -g_key_file_set_double_list -g_key_file_set_integer -g_key_file_set_integer_list -g_key_file_set_list_separator -g_key_file_set_locale_string -g_key_file_set_locale_string_list -g_key_file_set_string -g_key_file_set_string_list -g_key_file_set_value -g_key_file_to_data G_GNUC_MALLOC -#endif -#endif - -#if IN_HEADER(__G_LIST_H__) -#if IN_FILE(__G_LIST_C__) -g_list_alloc -g_list_append -g_list_concat -g_list_copy -g_list_delete_link -g_list_find -g_list_find_custom -g_list_first -g_list_foreach -g_list_free -g_list_free_1 -g_list_index -g_list_insert -g_list_insert_before -g_list_insert_sorted -g_list_insert_sorted_with_data -g_list_last -g_list_length -g_list_nth -g_list_nth_data -g_list_nth_prev -#ifndef G_DISABLE_DEPRECATED -g_list_pop_allocator -#endif -g_list_position -g_list_prepend -#ifndef G_DISABLE_DEPRECATED -g_list_push_allocator -#endif -g_list_remove -g_list_remove_all -g_list_remove_link -g_list_reverse -g_list_sort -g_list_sort_with_data -#endif -#endif - -#if IN_HEADER(__G_MAIN_H__) -#if IN_FILE(__G_MAIN_C__) -g_child_watch_add -g_child_watch_add_full -g_child_watch_source_new -g_get_current_time -g_main_context_acquire -g_main_context_add_poll -g_main_context_check -g_main_context_default -g_main_context_dispatch -g_main_context_find_source_by_funcs_user_data -g_main_context_find_source_by_id -g_main_context_find_source_by_user_data -g_main_context_get_poll_func -g_main_context_is_owner -g_main_context_iteration -g_main_context_new -g_main_context_pending -g_main_context_prepare -g_main_context_query -g_main_context_ref -g_main_context_release -g_main_context_remove_poll -g_main_context_set_poll_func -g_main_context_unref -g_main_context_wait -g_main_context_wakeup -g_main_depth -g_main_current_source -g_main_loop_get_context -g_main_loop_is_running -g_main_loop_new -g_main_loop_quit -g_main_loop_ref -g_main_loop_run -g_main_loop_unref -g_source_add_poll -g_source_attach -g_source_destroy -g_source_get_can_recurse -g_source_get_context -g_source_get_current_time -g_source_get_id -g_source_get_priority -g_source_new -g_source_ref -g_source_remove -g_source_remove_by_funcs_user_data -g_source_remove_by_user_data -g_source_remove_poll -g_source_set_callback -g_source_set_callback_indirect -g_source_set_can_recurse -g_source_set_funcs -g_source_is_destroyed -g_source_set_priority -g_source_unref -g_idle_add -g_idle_add_full -g_idle_remove_by_data -g_idle_source_new -g_timeout_add -g_timeout_add_seconds -g_timeout_add_full -g_timeout_add_seconds_full -g_timeout_source_new -g_timeout_source_new_seconds -#endif -#endif - -#if IN_HEADER(__G_MAPPED_FILE_H__) -#if IN_FILE(__G_MAPPED_FILE_C__) -g_mapped_file_new G_GNUC_MALLOC -g_mapped_file_get_length -g_mapped_file_get_contents -g_mapped_file_free -#endif -#endif - -#if IN_HEADER(__G_MARKUP_H__) -#if IN_FILE(__G_MARKUP_C__) -g_markup_error_quark -g_markup_escape_text -g_markup_parse_context_end_parse -g_markup_parse_context_free -g_markup_parse_context_get_element -g_markup_parse_context_get_element_stack -g_markup_parse_context_get_position -g_markup_parse_context_get_user_data -g_markup_parse_context_new -g_markup_parse_context_parse -g_markup_parse_context_push -g_markup_parse_context_pop -g_markup_printf_escaped G_GNUC_PRINTF(1,2) -g_markup_vprintf_escaped -g_markup_collect_attributes -#endif -#endif - -#if IN_HEADER(__G_MEM_H__) -#if IN_FILE(__G_MEM_C__) -g_free -g_malloc G_GNUC_MALLOC -g_malloc0 G_GNUC_MALLOC -g_mem_is_system_malloc -g_mem_profile -g_mem_set_vtable -g_realloc -g_try_malloc G_GNUC_MALLOC -g_try_malloc0 G_GNUC_MALLOC -g_try_realloc -#ifndef G_DISABLE_DEPRECATED -g_allocator_free -g_allocator_new -g_mem_chunk_alloc -g_mem_chunk_alloc0 -g_mem_chunk_clean -g_mem_chunk_destroy -g_mem_chunk_free -g_mem_chunk_info -g_mem_chunk_new -g_mem_chunk_print -g_mem_chunk_reset -g_blow_chunks -#endif -#endif -#endif - -#if IN_HEADER(__G_SLICE_H__) -#if IN_FILE(__G_SLICE_C__) -g_slice_alloc G_GNUC_MALLOC -g_slice_alloc0 G_GNUC_MALLOC -g_slice_copy G_GNUC_MALLOC -g_slice_free1 -g_slice_free_chain_with_offset -g_slice_set_config -g_slice_get_config -g_slice_get_config_state -#ifdef G_ENABLE_DEBUG -#ifdef INCLUDE_INTERNAL_SYMBOLS -g_slice_debug_tree_statistics -#endif -#endif -#endif -#endif - -#if IN_HEADER(__G_MESSAGES_H__) -#if IN_FILE(__G_MESSAGES_C__) -g_printf_string_upper_bound -g_log G_GNUC_PRINTF(3,4) -g_log_default_handler -g_log_remove_handler -g_log_set_always_fatal -g_log_set_default_handler -g_log_set_fatal_mask -g_log_set_handler -g_logv -g_return_if_fail_warning -g_warn_message -#ifndef G_DISABLE_DEPRECATED -g_assert_warning G_GNUC_NORETURN -#endif -g_print G_GNUC_PRINTF(1,2) -g_printerr G_GNUC_PRINTF(1,2) -g_set_printerr_handler -g_set_print_handler -#endif -#endif - -#if IN_HEADER(__G_NODE_H__) -#if IN_FILE(__G_NODE_C__) -g_node_child_index -g_node_child_position -g_node_children_foreach -g_node_copy -g_node_copy_deep -g_node_depth -g_node_destroy -g_node_find -g_node_find_child -g_node_first_sibling -g_node_get_root -g_node_insert -g_node_insert_after -g_node_insert_before -g_node_is_ancestor -g_node_last_child -g_node_last_sibling -g_node_max_height -g_node_n_children -g_node_new -g_node_n_nodes -g_node_nth_child -#ifndef G_DISABLE_DEPRECATED -g_node_pop_allocator -#endif -g_node_prepend -#ifndef G_DISABLE_DEPRECATED -g_node_push_allocator -#endif -g_node_reverse_children -g_node_traverse -g_node_unlink -#endif -#endif - -#if IN_HEADER(__G_OPTION_H__) -#if IN_FILE(__G_OPTION_C__) -g_option_context_add_group -g_option_context_add_main_entries -g_option_error_quark -g_option_context_free -g_option_context_get_description -g_option_context_get_help_enabled -g_option_context_get_ignore_unknown_options -g_option_context_get_main_group -g_option_context_get_summary -g_option_context_new -g_option_context_parse -g_option_context_set_description -g_option_context_set_help_enabled -g_option_context_set_ignore_unknown_options -g_option_context_set_main_group -g_option_context_set_summary -g_option_context_set_translate_func -g_option_context_set_translation_domain -g_option_context_get_help -g_option_group_add_entries -g_option_group_free -g_option_group_new -g_option_group_set_error_hook -g_option_group_set_parse_hooks -g_option_group_set_translate_func -g_option_group_set_translation_domain -#endif -#endif - -#if IN_HEADER(__G_PATTERN_H__) -#if IN_FILE(__G_PATTERN_C__) -g_pattern_match -g_pattern_match_simple -g_pattern_match_string -g_pattern_spec_equal -g_pattern_spec_free -g_pattern_spec_new -#endif -#endif - -#if IN_HEADER(__G_POLL_H__) -#if IN_FILE(__G_POLL_C__) -g_poll -#endif -#endif - -#if IN_HEADER(__G_PRIMES_H__) -#if IN_FILE(__G_PRIMES_C__) -g_spaced_primes_closest G_GNUC_CONST -#endif -#endif - -#if IN_HEADER(__G_PRINTF_H__) -#if IN_FILE(__G_PRINTF_C__) -g_fprintf G_GNUC_PRINTF(2,3) -g_printf G_GNUC_PRINTF(1,2) -g_sprintf G_GNUC_PRINTF(2,3) -g_vasprintf -g_vfprintf -g_vprintf -g_vsprintf -#endif -#endif - -#if IN_HEADER(__G_UTILS_H__) -#if IN_FILE(__G_PRINTF_C__) -g_snprintf G_GNUC_PRINTF(3,4) -g_vsnprintf -#endif -#endif - -#if IN_HEADER(__G_QSORT_H__) -#if IN_FILE(__G_QSORT_C__) -g_qsort_with_data -#endif -#endif - -#if IN_HEADER(__G_QUEUE_H__) -#if IN_FILE(__G_QUEUE_C__) -g_queue_clear -g_queue_copy -g_queue_delete_link -g_queue_find -g_queue_find_custom -g_queue_foreach -g_queue_free -g_queue_get_length -g_queue_index -g_queue_init -g_queue_insert_after -g_queue_insert_before -g_queue_insert_sorted -g_queue_is_empty -g_queue_link_index -g_queue_new -g_queue_peek_head -g_queue_peek_head_link -g_queue_peek_nth -g_queue_peek_nth_link -g_queue_peek_tail -g_queue_peek_tail_link -g_queue_pop_head -g_queue_pop_head_link -g_queue_pop_nth -g_queue_pop_nth_link -g_queue_pop_tail -g_queue_pop_tail_link -g_queue_push_head -g_queue_push_head_link -g_queue_push_nth -g_queue_push_nth_link -g_queue_push_tail -g_queue_push_tail_link -g_queue_remove -g_queue_remove_all -g_queue_reverse -g_queue_sort -g_queue_unlink -#endif -#endif - -#if IN_HEADER(__G_RAND_H__) -#if IN_FILE(__G_RAND_C__) -g_rand_copy -g_rand_double -g_rand_double_range -g_rand_free -g_rand_int -g_rand_int_range -g_rand_new -g_rand_new_with_seed -g_rand_new_with_seed_array -g_random_double -g_random_double_range -g_random_int -g_random_int_range -g_random_set_seed -g_rand_set_seed -g_rand_set_seed_array -#endif -#endif - -#if IN_HEADER(__G_REL_H__) -#if IN_FILE(__G_REL_C__) -g_relation_count -g_relation_delete -g_relation_destroy -g_relation_exists -g_relation_index -g_relation_insert -g_relation_new -g_relation_print -g_relation_select -g_tuples_destroy -g_tuples_index -#endif -#endif - -#if IN_HEADER(__G_SCANNER_H__) -#if IN_FILE(__G_SCANNER_C__) -g_scanner_cur_line -g_scanner_cur_position -g_scanner_cur_token -g_scanner_cur_value -g_scanner_destroy -g_scanner_eof -g_scanner_error G_GNUC_PRINTF(2,3) -g_scanner_get_next_token -g_scanner_input_file -g_scanner_input_text -g_scanner_lookup_symbol -g_scanner_new -g_scanner_peek_next_token -g_scanner_scope_add_symbol -g_scanner_scope_foreach_symbol -g_scanner_scope_lookup_symbol -g_scanner_scope_remove_symbol -g_scanner_set_scope -g_scanner_sync_file_offset -g_scanner_unexp_token -g_scanner_warn G_GNUC_PRINTF(2,3) -#endif -#endif - -#if IN_HEADER(__G_SEQUENCE_H__) -#if IN_FILE(__G_SEQUENCE_C__) -g_sequence_new -g_sequence_free -g_sequence_get_length -g_sequence_foreach -g_sequence_foreach_range -g_sequence_sort -g_sequence_sort_iter -g_sequence_get_begin_iter -g_sequence_get_end_iter -g_sequence_get_iter_at_pos -g_sequence_append -g_sequence_prepend -g_sequence_insert_before -g_sequence_move -g_sequence_swap -g_sequence_insert_sorted -g_sequence_insert_sorted_iter -g_sequence_sort_changed -g_sequence_sort_changed_iter -g_sequence_remove -g_sequence_remove_range -g_sequence_move_range -g_sequence_search -g_sequence_search_iter -g_sequence_get -g_sequence_set -g_sequence_iter_is_begin -g_sequence_iter_is_end -g_sequence_iter_next -g_sequence_iter_prev -g_sequence_iter_get_position -g_sequence_iter_move -g_sequence_iter_get_sequence -g_sequence_iter_compare -g_sequence_range_get_midpoint -#endif -#endif - -#if IN_HEADER(__G_SHELL_H__) -#if IN_FILE(__G_SHELL_C__) -g_shell_error_quark -g_shell_parse_argv -g_shell_quote -g_shell_unquote -#endif -#endif - -#if IN_HEADER(__G_SLIST_H__) -#if IN_FILE(__G_SLIST_C__) -g_slist_alloc -g_slist_append -g_slist_concat -g_slist_copy -g_slist_delete_link -g_slist_find -g_slist_find_custom -g_slist_foreach -g_slist_free -g_slist_free_1 -g_slist_index -g_slist_insert -g_slist_insert_before -g_slist_insert_sorted -g_slist_insert_sorted_with_data -g_slist_last -g_slist_length -g_slist_nth -g_slist_nth_data -#ifndef G_DISABLE_DEPRECATED -g_slist_pop_allocator -#endif -g_slist_position -g_slist_prepend -#ifndef G_DISABLE_DEPRECATED -g_slist_push_allocator -#endif -g_slist_remove -g_slist_remove_all -g_slist_remove_link -g_slist_reverse -g_slist_sort -g_slist_sort_with_data -#endif -#endif - -#if IN_HEADER(__G_SPAWN_H__) -#if IN_FILE(__G_SPAWN_C__) -#ifndef _WIN64 -g_spawn_async PRIVATE -g_spawn_async_with_pipes PRIVATE -#endif -g_spawn_close_pid -#ifndef _WIN64 -g_spawn_command_line_async PRIVATE -g_spawn_command_line_sync PRIVATE -#endif -g_spawn_error_quark -#ifndef _WIN64 -g_spawn_sync PRIVATE -#endif -#ifdef G_OS_WIN32 -g_spawn_async_utf8 -g_spawn_async_with_pipes_utf8 -g_spawn_command_line_async_utf8 -g_spawn_command_line_sync_utf8 -g_spawn_sync_utf8 -#endif -#endif -#endif - -#if IN_HEADER(__G_STDIO_H__) -#if IN_FILE(__G_STDIO_C__) -#if !defined(G_OS_UNIX) || defined(G_STDIO_NO_WRAP_ON_UNIX) -/* gstdio wrappers */ -g_chmod -g_open -g_creat -g_rename -g_mkdir -g_stat -g_lstat -g_remove -g_fopen -g_freopen -g_utime -#endif -g_access -g_chdir -g_unlink -g_rmdir -#endif -#endif - -#if IN_HEADER(__G_STRFUNCS_H__) -#if IN_FILE(__G_STRFUNCS_C__) -g_ascii_digit_value G_GNUC_CONST -g_ascii_dtostr -g_ascii_formatd -g_ascii_strdown G_GNUC_MALLOC -g_ascii_strtod -g_ascii_strtoull -g_ascii_strtoll -g_ascii_strup G_GNUC_MALLOC -g_ascii_tolower G_GNUC_CONST -g_ascii_toupper G_GNUC_CONST -g_ascii_xdigit_value G_GNUC_CONST -g_ascii_strcasecmp -g_ascii_strncasecmp -g_memdup G_GNUC_MALLOC -g_stpcpy -g_strcanon -g_strchomp -g_strchug -g_strcompress G_GNUC_MALLOC -g_strconcat G_GNUC_MALLOC G_GNUC_NULL_TERMINATED -g_strdelimit -g_strdup G_GNUC_MALLOC -g_strdup_printf G_GNUC_PRINTF(1,2) G_GNUC_MALLOC -g_strdupv G_GNUC_MALLOC -g_strdup_vprintf G_GNUC_MALLOC -g_strerror G_GNUC_CONST -g_strescape G_GNUC_MALLOC -g_strfreev -g_str_has_prefix -g_str_has_suffix -g_strjoin G_GNUC_MALLOC G_GNUC_NULL_TERMINATED -g_strjoinv G_GNUC_MALLOC -g_strlcat -g_strlcpy -g_strndup G_GNUC_MALLOC -g_strnfill G_GNUC_MALLOC -g_strreverse -g_strrstr -g_strrstr_len -g_strsignal G_GNUC_CONST -g_strsplit G_GNUC_MALLOC -g_strsplit_set G_GNUC_MALLOC -g_strstr_len -g_strtod -#ifndef G_DISABLE_DEPRECATED -g_strcasecmp -g_strncasecmp -g_strup -g_strdown -#endif -g_strv_length -g_strip_context G_GNUC_FORMAT(1) -g_dgettext G_GNUC_FORMAT(2) -g_dngettext G_GNUC_FORMAT(3) -g_dpgettext G_GNUC_FORMAT(2) -g_dpgettext2 G_GNUC_FORMAT(3) -#endif -#endif - -#if IN_HEADER(__G_URI_FUNCS_H__) -#if IN_FILE(__G_URI_FUNCS_C__) -g_uri_unescape_string -g_uri_unescape_segment -g_uri_parse_scheme -g_uri_escape_string -#endif -#endif - -#if IN_HEADER(__G_STRING_H__) -#if IN_FILE(__G_STRING_C__) -g_string_append -g_string_append_len -g_string_append_printf G_GNUC_PRINTF(2,3) -g_string_append_unichar -g_string_append_vprintf -g_string_ascii_down -g_string_ascii_up -g_string_assign -g_string_chunk_free -g_string_chunk_clear -g_string_chunk_insert -g_string_chunk_insert_const -g_string_chunk_insert_len -g_string_chunk_new -g_string_equal -g_string_erase -g_string_free -g_string_hash -g_string_insert -g_string_insert_c -g_string_insert_len -g_string_insert_unichar -g_string_new -g_string_new_len -g_string_overwrite -g_string_overwrite_len -g_string_prepend -g_string_prepend_c -g_string_prepend_len -g_string_prepend_unichar -g_string_printf G_GNUC_PRINTF(2,3) -g_string_set_size -g_string_sized_new -g_string_truncate -g_string_append_uri_escaped -#ifndef G_DISABLE_DEPRECATED -g_string_down -g_string_up -#endif -g_string_vprintf -#ifdef INCLUDE_INTERNAL_SYMBOLS - /* these are not internal, but we don't want to alias them */ -g_string_append_c -#endif -g_str_equal -g_str_hash -#endif -#endif - -#if IN_HEADER(__G_THREAD_H__) -#if IN_FILE(__G_THREAD_C__) -g_once_impl -g_once_init_enter_impl -g_once_init_leave -#ifdef INCLUDE_INTERNAL_SYMBOLS -g_thread_init_glib -g_once_init_enter -#endif -#ifdef INCLUDE_VARIABLES -g_thread_functions_for_glib_use -g_threads_got_initialized -g_thread_use_default_impl -g_thread_gettime -#endif -g_thread_create_full -g_thread_error_quark -g_thread_exit -g_thread_join -g_thread_self -g_thread_set_priority -g_static_mutex_free -g_static_mutex_get_mutex_impl -g_static_mutex_init -g_static_private_free -g_static_private_get -g_static_private_init -g_static_private_set -g_static_rec_mutex_free -g_static_rec_mutex_init -g_static_rec_mutex_lock -g_static_rec_mutex_lock_full -g_static_rec_mutex_trylock -g_static_rec_mutex_unlock -g_static_rec_mutex_unlock_full -g_static_rw_lock_free -g_static_rw_lock_init -g_static_rw_lock_reader_lock -g_static_rw_lock_reader_trylock -g_static_rw_lock_reader_unlock -g_static_rw_lock_writer_lock -g_static_rw_lock_writer_trylock -g_static_rw_lock_writer_unlock -g_thread_foreach -g_thread_get_initialized -#endif -#endif - -#if IN_HEADER(__G_THREADPOOL_H__) -#if IN_FILE(__G_THREADPOOL_C__) -g_thread_pool_free -g_thread_pool_get_max_threads -g_thread_pool_get_max_unused_threads -g_thread_pool_get_max_idle_time -g_thread_pool_get_num_threads -g_thread_pool_get_num_unused_threads -g_thread_pool_new -g_thread_pool_push -g_thread_pool_set_max_threads -g_thread_pool_set_max_unused_threads -g_thread_pool_set_max_idle_time -g_thread_pool_stop_unused_threads -g_thread_pool_unprocessed -g_thread_pool_set_sort_function -#endif -#endif - -#if IN_HEADER(__G_TEST_UTILS_H__) -#if IN_FILE(__G_TEST_UTILS_C__) -g_assertion_message G_GNUC_NORETURN -g_assertion_message_cmpnum G_GNUC_NORETURN -g_assertion_message_cmpstr G_GNUC_NORETURN -g_assertion_message_expr G_GNUC_NORETURN -g_assertion_message_error G_GNUC_NORETURN -g_strcmp0 -g_test_add_data_func -g_test_add_func -g_test_add_vtable -g_test_bug -g_test_bug_base -#ifdef INCLUDE_VARIABLES -g_test_config_vars -#endif -g_test_create_case -g_test_create_suite -g_test_get_root -g_test_init -g_test_log_buffer_free -g_test_log_buffer_new -g_test_log_buffer_pop -g_test_log_buffer_push -g_test_log_msg_free -g_test_log_type_name -g_test_maximized_result -g_test_message -g_test_minimized_result -g_test_queue_destroy -g_test_queue_free -g_test_rand_double -g_test_rand_double_range -g_test_rand_int -g_test_rand_int_range -g_test_run -g_test_run_suite -g_test_suite_add -g_test_suite_add_suite -g_test_timer_elapsed -g_test_timer_last -g_test_timer_start -g_test_trap_assertions -g_test_trap_fork -g_test_trap_has_passed -g_test_trap_reached_timeout -#endif -#endif - -#if IN_HEADER(__G_TIMER_H__) -#if IN_FILE(__G_TIMER_C__) -g_timer_continue -g_timer_destroy -g_timer_elapsed -g_timer_new -g_timer_reset -g_timer_start -g_timer_stop -g_time_val_add -g_time_val_from_iso8601 -g_time_val_to_iso8601 G_GNUC_MALLOC -g_usleep -#endif -#endif - -#if IN_HEADER(__G_TREE_H__) -#if IN_FILE(__G_TREE_C__) -g_tree_destroy -g_tree_foreach -g_tree_height -g_tree_insert -g_tree_lookup -g_tree_lookup_extended -g_tree_new -g_tree_new_full -g_tree_new_with_data -g_tree_nnodes -g_tree_remove -g_tree_replace -g_tree_search -g_tree_steal -#ifndef G_DISABLE_DEPRECATED -g_tree_traverse -#endif -#endif -#endif - -#if IN_HEADER(__G_UNICODE_H__) -#if IN_FILE(__G_UNIBREAK_C__) -g_unichar_break_type G_GNUC_CONST -#endif -#endif - -#if IN_HEADER(__G_UNICODE_H__) -#if IN_FILE(__G_UNICOLLATE_C__) -g_utf8_collate -g_utf8_collate_key G_GNUC_MALLOC -g_utf8_collate_key_for_filename G_GNUC_MALLOC -#endif -#endif - -#if IN_HEADER(__G_UNICODE_H__) -#if IN_FILE(__G_UNIDECOMP_C__) -g_unicode_canonical_decomposition G_GNUC_MALLOC -g_unicode_canonical_ordering -g_unichar_combining_class G_GNUC_CONST -g_utf8_normalize -#endif -#endif - -#if IN_HEADER(__G_UNICODE_H__) -#if IN_FILE(__G_UNIPROP_C__) -g_unichar_isalnum G_GNUC_CONST -g_unichar_isalpha G_GNUC_CONST -g_unichar_iscntrl G_GNUC_CONST -g_unichar_isdefined G_GNUC_CONST -g_unichar_isdigit G_GNUC_CONST -g_unichar_isgraph G_GNUC_CONST -g_unichar_islower G_GNUC_CONST -g_unichar_isprint G_GNUC_CONST -g_unichar_ispunct G_GNUC_CONST -g_unichar_isspace G_GNUC_CONST -g_unichar_istitle G_GNUC_CONST -g_unichar_isupper G_GNUC_CONST -g_unichar_iswide G_GNUC_CONST -g_unichar_iswide_cjk G_GNUC_CONST -g_unichar_isxdigit G_GNUC_CONST -g_unichar_iszerowidth G_GNUC_CONST -g_unichar_tolower G_GNUC_CONST -g_unichar_totitle G_GNUC_CONST -g_unichar_toupper G_GNUC_CONST -g_unichar_ismark G_GNUC_CONST -g_unichar_get_mirror_char -g_unichar_get_script -g_unichar_digit_value G_GNUC_CONST -g_unichar_xdigit_value G_GNUC_CONST -g_unichar_type G_GNUC_CONST -g_utf8_casefold G_GNUC_MALLOC -g_utf8_strup G_GNUC_MALLOC -g_utf8_strdown G_GNUC_MALLOC -#endif -#endif - -#if IN_HEADER(__G_UNICODE_H__) -#if IN_FILE(__G_UTF8_C__) -g_get_charset -g_ucs4_to_utf16 G_GNUC_MALLOC -g_ucs4_to_utf8 G_GNUC_MALLOC -g_utf16_to_ucs4 G_GNUC_MALLOC -g_utf16_to_utf8 G_GNUC_MALLOC -g_utf8_find_next_char -g_utf8_find_prev_char -g_utf8_get_char -g_utf8_get_char_validated -g_utf8_offset_to_pointer -g_utf8_pointer_to_offset -g_utf8_prev_char -g_utf8_strchr -g_utf8_strlen -g_utf8_strncpy -g_utf8_strrchr -g_utf8_strreverse -g_utf8_to_ucs4 G_GNUC_MALLOC -g_utf8_to_ucs4_fast G_GNUC_MALLOC -g_utf8_to_utf16 G_GNUC_MALLOC -g_utf8_validate -g_unichar_to_utf8 -g_unichar_validate -#endif -#endif - -#if IN_HEADER(__GLIBINTL_H__) -#if IN_FILE(__G_UTILS_C__) -glib_gettext G_GNUC_FORMAT(1) -#endif -#endif - -#if IN_HEADER(__G_HASH_H__) -#if IN_FILE(__G_UTILS_C__) -g_int_equal -g_int_hash -g_direct_equal G_GNUC_CONST -g_direct_hash G_GNUC_CONST -#endif -#endif - -#if IN_HEADER(__G_UTILS_H__) -#if IN_FILE(__G_UTILS_C__) -g_atexit -#ifndef G_DISABLE_DEPRECATED -g_basename -#endif -g_get_application_name -#ifndef _WIN64 -g_find_program_in_path PRIVATE -g_get_current_dir PRIVATE -g_getenv PRIVATE -g_unsetenv PRIVATE -g_get_home_dir PRIVATE -#endif -g_get_host_name -#ifndef _WIN64 -g_setenv PRIVATE -#endif -g_listenv -#ifdef G_OS_WIN32 -g_find_program_in_path_utf8 -g_get_current_dir_utf8 -g_getenv_utf8 -g_unsetenv_utf8 -g_setenv_utf8 -g_get_home_dir_utf8 -#endif -g_get_language_names -g_get_prgname -#ifndef _WIN64 -g_get_real_name PRIVATE -#endif -#ifdef G_OS_WIN32 -g_get_real_name_utf8 -#endif -g_get_system_config_dirs -g_get_system_data_dirs -#ifdef G_OS_WIN32 -g_win32_get_system_data_dirs_for_module -#endif -#ifndef _WIN64 -g_get_tmp_dir PRIVATE -#endif -#ifdef G_OS_WIN32 -g_get_tmp_dir_utf8 -#endif -g_get_user_cache_dir -g_get_user_config_dir -g_get_user_data_dir -g_get_user_special_dir -#ifndef _WIN64 -g_get_user_name PRIVATE -#endif -#ifdef G_OS_WIN32 -g_get_user_name_utf8 -#endif -glib_check_version -g_nullify_pointer -g_parse_debug_string -g_path_get_basename G_GNUC_MALLOC -g_path_get_dirname G_GNUC_MALLOC -g_path_is_absolute -g_path_skip_root -g_set_application_name -g_set_prgname -#ifdef INCLUDE_INTERNAL_SYMBOLS -g_bit_nth_lsf -g_bit_nth_msf -g_bit_storage -g_trash_stack_height -g_trash_stack_peek -g_trash_stack_pop -g_trash_stack_push -g_get_codeset -#endif -#endif -#endif - -#if IN_HEADER(__G_REGEX_H__) -#if IN_FILE(__G_REGEX_C__) -g_regex_error_quark -g_regex_new -g_regex_ref -g_regex_unref -g_regex_get_pattern -g_regex_get_max_backref -g_regex_get_capture_count -g_regex_get_string_number -g_regex_escape_string -g_regex_match_simple -g_regex_match -g_regex_match_full -g_regex_match_all -g_regex_match_all_full -g_regex_split_simple -g_regex_split -g_regex_split_full -g_regex_replace -g_regex_replace_literal -g_regex_replace_eval -g_regex_check_replacement -g_match_info_get_regex -g_match_info_get_string -g_match_info_free -g_match_info_next -g_match_info_matches -g_match_info_get_match_count -g_match_info_is_partial_match -g_match_info_expand_references -g_match_info_fetch -g_match_info_fetch_pos -g_match_info_fetch_named -g_match_info_fetch_named_pos -g_match_info_fetch_all -#endif -#endif - -#if IN_HEADER(__G_WIN32_H__) -#if IN_FILE(__G_WIN32_H__) -#ifdef G_OS_WIN32 -g_win32_error_message -g_win32_ftruncate -g_win32_get_package_installation_directory_of_module -#ifndef _WIN64 -g_win32_get_package_installation_directory PRIVATE -#endif -g_win32_get_package_installation_directory_utf8 -#ifndef _WIN64 -g_win32_get_package_installation_subdirectory PRIVATE -#endif -g_win32_get_package_installation_subdirectory_utf8 -g_win32_get_windows_version -g_win32_getlocale -g_win32_locale_filename_from_utf8 -#endif -#endif -#endif - -#ifdef INCLUDE_VARIABLES -g_ascii_table -g_utf8_skip -g_idle_funcs -g_timeout_funcs -g_io_watch_funcs -g_child_watch_funcs -glib_binary_age -glib_interface_age -glib_major_version -glib_mem_profiler_table -glib_micro_version -glib_minor_version -glib_on_error_halt -g_mem_gc_friendly -#endif diff --git a/glib/glibintl.h b/glib/glibintl.h index 47a7910f8..214b26192 100644 --- a/glib/glibintl.h +++ b/glib/glibintl.h @@ -7,7 +7,7 @@ G_CONST_RETURN gchar *glib_gettext (const gchar *str) G_GNUC_FORMAT(1); -#ifdef ENABLE_NLS +#if 0 #include <libintl.h> #define _(String) glib_gettext(String) diff --git a/glib/gmain.c b/glib/gmain.c index 331c0a86b..61fcdded5 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -3665,7 +3665,11 @@ g_child_watch_source_init_single (void) sigaction (SIGCHLD, &action, NULL); } +#ifdef ANDROID_STUB G_GNUC_NORETURN static gpointer +#else +void +#endif child_watch_helper_thread (gpointer data) { while (1) diff --git a/glib/gmappedfile.c b/glib/gmappedfile.c deleted file mode 100644 index 1220f410e..000000000 --- a/glib/gmappedfile.c +++ /dev/null @@ -1,278 +0,0 @@ -/* GLIB - Library of useful routines for C programming - * gmappedfile.c: Simplified wrapper around the mmap() function. - * - * Copyright 2005 Matthias Clasen - * - * 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "config.h" - -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_MMAP -#include <sys/mman.h> -#endif - -#include "glibconfig.h" - -#ifdef G_OS_WIN32 -#include <windows.h> -#include <io.h> -#endif - -#include "gconvert.h" -#include "gerror.h" -#include "gfileutils.h" -#include "gmappedfile.h" -#include "gmem.h" -#include "gmessages.h" -#include "gstdio.h" -#include "gstrfuncs.h" - -#include "glibintl.h" - -#include "galias.h" - -#ifndef _O_BINARY -#define _O_BINARY 0 -#endif - -#ifndef MAP_FAILED -#define MAP_FAILED ((void *) -1) -#endif - -struct _GMappedFile -{ - gsize length; - gchar *contents; -#ifdef G_OS_WIN32 - HANDLE mapping; -#endif -}; - -/** - * g_mapped_file_new: - * @filename: The path of the file to load, in the GLib filename encoding - * @writable: whether the mapping should be writable - * @error: return location for a #GError, or %NULL - * - * Maps a file into memory. On UNIX, this is using the mmap() function. - * - * If @writable is %TRUE, the mapped buffer may be modified, otherwise - * it is an error to modify the mapped buffer. Modifications to the buffer - * are not visible to other processes mapping the same file, and are not - * written back to the file. - * - * Note that modifications of the underlying file might affect the contents - * of the #GMappedFile. Therefore, mapping should only be used if the file - * will not be modified, or if all modifications of the file are done - * atomically (e.g. using g_file_set_contents()). - * - * Return value: a newly allocated #GMappedFile which must be freed - * with g_mapped_file_free(), or %NULL if the mapping failed. - * - * Since: 2.8 - */ -GMappedFile * -g_mapped_file_new (const gchar *filename, - gboolean writable, - GError **error) -{ - GMappedFile *file; - int fd; - struct stat st; - - g_return_val_if_fail (filename != NULL, NULL); - g_return_val_if_fail (!error || *error == NULL, NULL); - - fd = g_open (filename, (writable ? O_RDWR : O_RDONLY) | _O_BINARY, 0); - if (fd == -1) - { - int save_errno = errno; - gchar *display_filename = g_filename_display_name (filename); - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to open file '%s': open() failed: %s"), - display_filename, - g_strerror (save_errno)); - g_free (display_filename); - return NULL; - } - - file = g_new0 (GMappedFile, 1); - - if (fstat (fd, &st) == -1) - { - int save_errno = errno; - gchar *display_filename = g_filename_display_name (filename); - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to get attributes of file '%s': fstat() failed: %s"), - display_filename, - g_strerror (save_errno)); - g_free (display_filename); - goto out; - } - - if (st.st_size == 0) - { - file->length = 0; - file->contents = ""; - close (fd); - return file; - } - - file->contents = MAP_FAILED; - -#ifdef HAVE_MMAP - if (st.st_size > G_MAXSIZE) - { - errno = EINVAL; - } - else - { - file->length = (gsize) st.st_size; - file->contents = (gchar *) mmap (NULL, file->length, - writable ? PROT_READ|PROT_WRITE : PROT_READ, - MAP_PRIVATE, fd, 0); - } -#endif -#ifdef G_OS_WIN32 - file->length = st.st_size; - file->mapping = CreateFileMapping ((HANDLE) _get_osfhandle (fd), NULL, - writable ? PAGE_WRITECOPY : PAGE_READONLY, - 0, 0, - NULL); - if (file->mapping != NULL) - { - file->contents = MapViewOfFile (file->mapping, - writable ? FILE_MAP_COPY : FILE_MAP_READ, - 0, 0, - 0); - if (file->contents == NULL) - { - file->contents = MAP_FAILED; - CloseHandle (file->mapping); - file->mapping = NULL; - } - } -#endif - - - if (file->contents == MAP_FAILED) - { - int save_errno = errno; - gchar *display_filename = g_filename_display_name (filename); - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to map file '%s': mmap() failed: %s"), - display_filename, - g_strerror (save_errno)); - g_free (display_filename); - goto out; - } - - close (fd); - return file; - - out: - close (fd); - g_free (file); - - return NULL; -} - -/** - * g_mapped_file_get_length: - * @file: a #GMappedFile - * - * Returns the length of the contents of a #GMappedFile. - * - * Returns: the length of the contents of @file. - * - * Since: 2.8 - */ -gsize -g_mapped_file_get_length (GMappedFile *file) -{ - g_return_val_if_fail (file != NULL, 0); - - return file->length; -} - -/** - * g_mapped_file_get_contents: - * @file: a #GMappedFile - * - * Returns the contents of a #GMappedFile. - * - * Note that the contents may not be zero-terminated, - * even if the #GMappedFile is backed by a text file. - * - * Returns: the contents of @file. - * - * Since: 2.8 - */ -gchar * -g_mapped_file_get_contents (GMappedFile *file) -{ - g_return_val_if_fail (file != NULL, NULL); - - return file->contents; -} - -/** - * g_mapped_file_free: - * @file: a #GMappedFile - * - * Unmaps the buffer of @file and frees it. - * - * Since: 2.8 - */ -void -g_mapped_file_free (GMappedFile *file) -{ - g_return_if_fail (file != NULL); - - if (file->length) - { -#ifdef HAVE_MMAP - munmap (file->contents, file->length); -#endif -#ifdef G_OS_WIN32 - UnmapViewOfFile (file->contents); - CloseHandle (file->mapping); -#endif - } - - g_free (file); -} - - -#define __G_MAPPED_FILE_C__ -#include "galiasdef.c" diff --git a/glib/gmarkup.c b/glib/gmarkup.c deleted file mode 100644 index b1f4f465f..000000000 --- a/glib/gmarkup.c +++ /dev/null @@ -1,2996 +0,0 @@ -/* gmarkup.c - Simple XML-like parser - * - * Copyright 2000, 2003 Red Hat, Inc. - * Copyright 2007, 2008 Ryan Lortie <desrt@desrt.ca> - * - * GLib 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 of the - * License, or (at your option) any later version. - * - * GLib 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 GLib; see the file COPYING.LIB. If not, - * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "config.h" - -#include <stdarg.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> - -#include "glib.h" -#include "glibintl.h" -#include "galias.h" - -GQuark -g_markup_error_quark (void) -{ - return g_quark_from_static_string ("g-markup-error-quark"); -} - -typedef enum -{ - STATE_START, - STATE_AFTER_OPEN_ANGLE, - STATE_AFTER_CLOSE_ANGLE, - STATE_AFTER_ELISION_SLASH, /* the slash that obviates need for end element */ - STATE_INSIDE_OPEN_TAG_NAME, - STATE_INSIDE_ATTRIBUTE_NAME, - STATE_AFTER_ATTRIBUTE_NAME, - STATE_BETWEEN_ATTRIBUTES, - STATE_AFTER_ATTRIBUTE_EQUALS_SIGN, - STATE_INSIDE_ATTRIBUTE_VALUE_SQ, - STATE_INSIDE_ATTRIBUTE_VALUE_DQ, - STATE_INSIDE_TEXT, - STATE_AFTER_CLOSE_TAG_SLASH, - STATE_INSIDE_CLOSE_TAG_NAME, - STATE_AFTER_CLOSE_TAG_NAME, - STATE_INSIDE_PASSTHROUGH, - STATE_ERROR -} GMarkupParseState; - -typedef struct -{ - const char *prev_element; - const GMarkupParser *prev_parser; - gpointer prev_user_data; -} GMarkupRecursionTracker; - -struct _GMarkupParseContext -{ - const GMarkupParser *parser; - - GMarkupParseFlags flags; - - gint line_number; - gint char_number; - - gpointer user_data; - GDestroyNotify dnotify; - - /* A piece of character data or an element that - * hasn't "ended" yet so we haven't yet called - * the callback for it. - */ - GString *partial_chunk; - - GMarkupParseState state; - GSList *tag_stack; - gchar **attr_names; - gchar **attr_values; - gint cur_attr; - gint alloc_attrs; - - const gchar *current_text; - gssize current_text_len; - const gchar *current_text_end; - - GString *leftover_char_portion; - - /* used to save the start of the last interesting thingy */ - const gchar *start; - - const gchar *iter; - - guint document_empty : 1; - guint parsing : 1; - guint awaiting_pop : 1; - gint balance; - - /* subparser support */ - GSList *subparser_stack; /* (GMarkupRecursionTracker *) */ - const char *subparser_element; - gpointer held_user_data; -}; - -/** - * g_markup_parse_context_new: - * @parser: a #GMarkupParser - * @flags: one or more #GMarkupParseFlags - * @user_data: user data to pass to #GMarkupParser functions - * @user_data_dnotify: user data destroy notifier called when the parse context is freed - * - * Creates a new parse context. A parse context is used to parse - * marked-up documents. You can feed any number of documents into - * a context, as long as no errors occur; once an error occurs, - * the parse context can't continue to parse text (you have to free it - * and create a new parse context). - * - * Return value: a new #GMarkupParseContext - **/ -GMarkupParseContext * -g_markup_parse_context_new (const GMarkupParser *parser, - GMarkupParseFlags flags, - gpointer user_data, - GDestroyNotify user_data_dnotify) -{ - GMarkupParseContext *context; - - g_return_val_if_fail (parser != NULL, NULL); - - context = g_new (GMarkupParseContext, 1); - - context->parser = parser; - context->flags = flags; - context->user_data = user_data; - context->dnotify = user_data_dnotify; - - context->line_number = 1; - context->char_number = 1; - - context->partial_chunk = NULL; - - context->state = STATE_START; - context->tag_stack = NULL; - context->attr_names = NULL; - context->attr_values = NULL; - context->cur_attr = -1; - context->alloc_attrs = 0; - - context->current_text = NULL; - context->current_text_len = -1; - context->current_text_end = NULL; - context->leftover_char_portion = NULL; - - context->start = NULL; - context->iter = NULL; - - context->document_empty = TRUE; - context->parsing = FALSE; - - context->awaiting_pop = FALSE; - context->subparser_stack = NULL; - context->subparser_element = NULL; - - /* this is only looked at if awaiting_pop = TRUE. initialise anyway. */ - context->held_user_data = NULL; - - context->balance = 0; - - return context; -} - -/** - * g_markup_parse_context_free: - * @context: a #GMarkupParseContext - * - * Frees a #GMarkupParseContext. Can't be called from inside - * one of the #GMarkupParser functions. Can't be called while - * a subparser is pushed. - **/ -void -g_markup_parse_context_free (GMarkupParseContext *context) -{ - g_return_if_fail (context != NULL); - g_return_if_fail (!context->parsing); - g_return_if_fail (!context->subparser_stack); - g_return_if_fail (!context->awaiting_pop); - - if (context->dnotify) - (* context->dnotify) (context->user_data); - - g_strfreev (context->attr_names); - g_strfreev (context->attr_values); - - g_slist_foreach (context->tag_stack, (GFunc)g_free, NULL); - g_slist_free (context->tag_stack); - - if (context->partial_chunk) - g_string_free (context->partial_chunk, TRUE); - - if (context->leftover_char_portion) - g_string_free (context->leftover_char_portion, TRUE); - - g_free (context); -} - -static void pop_subparser_stack (GMarkupParseContext *context); - -static void -mark_error (GMarkupParseContext *context, - GError *error) -{ - context->state = STATE_ERROR; - - if (context->parser->error) - (*context->parser->error) (context, error, context->user_data); - - /* report the error all the way up to free all the user-data */ - while (context->subparser_stack) - { - pop_subparser_stack (context); - context->awaiting_pop = FALSE; /* already been freed */ - - if (context->parser->error) - (*context->parser->error) (context, error, context->user_data); - } -} - -static void set_error (GMarkupParseContext *context, - GError **error, - GMarkupError code, - const gchar *format, - ...) G_GNUC_PRINTF (4, 5); - -static void -set_error_literal (GMarkupParseContext *context, - GError **error, - GMarkupError code, - const gchar *message) -{ - GError *tmp_error; - - tmp_error = g_error_new_literal (G_MARKUP_ERROR, code, message); - - g_prefix_error (&tmp_error, - _("Error on line %d char %d: "), - context->line_number, - context->char_number); - - mark_error (context, tmp_error); - - g_propagate_error (error, tmp_error); -} - -static void -set_error (GMarkupParseContext *context, - GError **error, - GMarkupError code, - const gchar *format, - ...) -{ - gchar *s; - gchar *s_valid; - va_list args; - - va_start (args, format); - s = g_strdup_vprintf (format, args); - va_end (args); - - /* Make sure that the GError message is valid UTF-8 even if it is - * complaining about invalid UTF-8 in the markup: */ - s_valid = _g_utf8_make_valid (s); - set_error_literal (context, error, code, s); - - g_free (s); - g_free (s_valid); -} - -static void -propagate_error (GMarkupParseContext *context, - GError **dest, - GError *src) -{ - if (context->flags & G_MARKUP_PREFIX_ERROR_POSITION) - g_prefix_error (&src, - _("Error on line %d char %d: "), - context->line_number, - context->char_number); - - mark_error (context, src); - - g_propagate_error (dest, src); -} - -/* To make these faster, we first use the ascii-only tests, then check - * for the usual non-alnum name-end chars, and only then call the - * expensive unicode stuff. Nobody uses non-ascii in XML tag/attribute - * names, so this is a reasonable hack that virtually always avoids - * the guniprop call. - */ -#define IS_COMMON_NAME_END_CHAR(c) \ - ((c) == '=' || (c) == '/' || (c) == '>' || (c) == ' ') - -static gboolean -is_name_start_char (const gchar *p) -{ - if (g_ascii_isalpha (*p) || - (!IS_COMMON_NAME_END_CHAR (*p) && - (*p == '_' || - *p == ':' || - g_unichar_isalpha (g_utf8_get_char (p))))) - return TRUE; - else - return FALSE; -} - -static gboolean -is_name_char (const gchar *p) -{ - if (g_ascii_isalnum (*p) || - (!IS_COMMON_NAME_END_CHAR (*p) && - (*p == '.' || - *p == '-' || - *p == '_' || - *p == ':' || - g_unichar_isalpha (g_utf8_get_char (p))))) - return TRUE; - else - return FALSE; -} - - -static gchar* -char_str (gunichar c, - gchar *buf) -{ - memset (buf, 0, 8); - g_unichar_to_utf8 (c, buf); - return buf; -} - -static gchar* -utf8_str (const gchar *utf8, - gchar *buf) -{ - char_str (g_utf8_get_char (utf8), buf); - return buf; -} - -static void -set_unescape_error (GMarkupParseContext *context, - GError **error, - const gchar *remaining_text, - const gchar *remaining_text_end, - GMarkupError code, - const gchar *format, - ...) -{ - GError *tmp_error; - gchar *s; - va_list args; - gint remaining_newlines; - const gchar *p; - - remaining_newlines = 0; - p = remaining_text; - while (p != remaining_text_end) - { - if (*p == '\n') - ++remaining_newlines; - ++p; - } - - va_start (args, format); - s = g_strdup_vprintf (format, args); - va_end (args); - - tmp_error = g_error_new (G_MARKUP_ERROR, - code, - _("Error on line %d: %s"), - context->line_number - remaining_newlines, - s); - - g_free (s); - - mark_error (context, tmp_error); - - g_propagate_error (error, tmp_error); -} - -typedef enum -{ - USTATE_INSIDE_TEXT, - USTATE_AFTER_AMPERSAND, - USTATE_INSIDE_ENTITY_NAME, - USTATE_AFTER_CHARREF_HASH -} UnescapeState; - -typedef struct -{ - GMarkupParseContext *context; - GString *str; - UnescapeState state; - const gchar *text; - const gchar *text_end; - const gchar *entity_start; -} UnescapeContext; - -static const gchar* -unescape_text_state_inside_text (UnescapeContext *ucontext, - const gchar *p, - GError **error) -{ - const gchar *start; - gboolean normalize_attribute; - - if (ucontext->context->state == STATE_INSIDE_ATTRIBUTE_VALUE_SQ || - ucontext->context->state == STATE_INSIDE_ATTRIBUTE_VALUE_DQ) - normalize_attribute = TRUE; - else - normalize_attribute = FALSE; - - start = p; - - while (p != ucontext->text_end) - { - if (*p == '&') - { - break; - } - else if (normalize_attribute && (*p == '\t' || *p == '\n')) - { - g_string_append_len (ucontext->str, start, p - start); - g_string_append_c (ucontext->str, ' '); - p = g_utf8_next_char (p); - start = p; - } - else if (*p == '\r') - { - g_string_append_len (ucontext->str, start, p - start); - g_string_append_c (ucontext->str, normalize_attribute ? ' ' : '\n'); - p = g_utf8_next_char (p); - if (p != ucontext->text_end && *p == '\n') - p = g_utf8_next_char (p); - start = p; - } - else - p = g_utf8_next_char (p); - } - - if (p != start) - g_string_append_len (ucontext->str, start, p - start); - - if (p != ucontext->text_end && *p == '&') - { - p = g_utf8_next_char (p); - ucontext->state = USTATE_AFTER_AMPERSAND; - } - - return p; -} - -static const gchar* -unescape_text_state_after_ampersand (UnescapeContext *ucontext, - const gchar *p, - GError **error) -{ - ucontext->entity_start = NULL; - - if (*p == '#') - { - p = g_utf8_next_char (p); - - ucontext->entity_start = p; - ucontext->state = USTATE_AFTER_CHARREF_HASH; - } - else if (!is_name_start_char (p)) - { - if (*p == ';') - { - set_unescape_error (ucontext->context, error, - p, ucontext->text_end, - G_MARKUP_ERROR_PARSE, - _("Empty entity '&;' seen; valid " - "entities are: & " < > '")); - } - else - { - gchar buf[8]; - - set_unescape_error (ucontext->context, error, - p, ucontext->text_end, - G_MARKUP_ERROR_PARSE, - _("Character '%s' is not valid at " - "the start of an entity name; " - "the & character begins an entity; " - "if this ampersand isn't supposed " - "to be an entity, escape it as " - "&"), - utf8_str (p, buf)); - } - } - else - { - ucontext->entity_start = p; - ucontext->state = USTATE_INSIDE_ENTITY_NAME; - } - - return p; -} - -static const gchar* -unescape_text_state_inside_entity_name (UnescapeContext *ucontext, - const gchar *p, - GError **error) -{ - while (p != ucontext->text_end) - { - if (*p == ';') - break; - else if (!is_name_char (p)) - { - gchar ubuf[8]; - - set_unescape_error (ucontext->context, error, - p, ucontext->text_end, - G_MARKUP_ERROR_PARSE, - _("Character '%s' is not valid " - "inside an entity name"), - utf8_str (p, ubuf)); - break; - } - - p = g_utf8_next_char (p); - } - - if (ucontext->context->state != STATE_ERROR) - { - if (p != ucontext->text_end) - { - gint len = p - ucontext->entity_start; - - /* move to after semicolon */ - p = g_utf8_next_char (p); - ucontext->state = USTATE_INSIDE_TEXT; - - if (strncmp (ucontext->entity_start, "lt", len) == 0) - g_string_append_c (ucontext->str, '<'); - else if (strncmp (ucontext->entity_start, "gt", len) == 0) - g_string_append_c (ucontext->str, '>'); - else if (strncmp (ucontext->entity_start, "amp", len) == 0) - g_string_append_c (ucontext->str, '&'); - else if (strncmp (ucontext->entity_start, "quot", len) == 0) - g_string_append_c (ucontext->str, '"'); - else if (strncmp (ucontext->entity_start, "apos", len) == 0) - g_string_append_c (ucontext->str, '\''); - else - { - gchar *name; - - name = g_strndup (ucontext->entity_start, len); - set_unescape_error (ucontext->context, error, - p, ucontext->text_end, - G_MARKUP_ERROR_PARSE, - _("Entity name '%s' is not known"), - name); - g_free (name); - } - } - else - { - set_unescape_error (ucontext->context, error, - /* give line number of the & */ - ucontext->entity_start, ucontext->text_end, - G_MARKUP_ERROR_PARSE, - _("Entity did not end with a semicolon; " - "most likely you used an ampersand " - "character without intending to start " - "an entity - escape ampersand as &")); - } - } -#undef MAX_ENT_LEN - - return p; -} - -static const gchar* -unescape_text_state_after_charref_hash (UnescapeContext *ucontext, - const gchar *p, - GError **error) -{ - gboolean is_hex = FALSE; - const char *start; - - start = ucontext->entity_start; - - if (*p == 'x') - { - is_hex = TRUE; - p = g_utf8_next_char (p); - start = p; - } - - while (p != ucontext->text_end && *p != ';') - p = g_utf8_next_char (p); - - if (p != ucontext->text_end) - { - g_assert (*p == ';'); - - /* digit is between start and p */ - - if (start != p) - { - gulong l; - gchar *end = NULL; - - errno = 0; - if (is_hex) - l = strtoul (start, &end, 16); - else - l = strtoul (start, &end, 10); - - if (end != p || errno != 0) - { - set_unescape_error (ucontext->context, error, - start, ucontext->text_end, - G_MARKUP_ERROR_PARSE, - _("Failed to parse '%-.*s', which " - "should have been a digit " - "inside a character reference " - "(ê for example) - perhaps " - "the digit is too large"), - p - start, start); - } - else - { - /* characters XML 1.1 permits */ - if ((0 < l && l <= 0xD7FF) || - (0xE000 <= l && l <= 0xFFFD) || - (0x10000 <= l && l <= 0x10FFFF)) - { - gchar buf[8]; - g_string_append (ucontext->str, char_str (l, buf)); - } - else - { - set_unescape_error (ucontext->context, error, - start, ucontext->text_end, - G_MARKUP_ERROR_PARSE, - _("Character reference '%-.*s' does not " - "encode a permitted character"), - p - start, start); - } - } - - /* Move to next state */ - p = g_utf8_next_char (p); /* past semicolon */ - ucontext->state = USTATE_INSIDE_TEXT; - } - else - { - set_unescape_error (ucontext->context, error, - start, ucontext->text_end, - G_MARKUP_ERROR_PARSE, - _("Empty character reference; " - "should include a digit such as " - "dž")); - } - } - else - { - set_unescape_error (ucontext->context, error, - start, ucontext->text_end, - G_MARKUP_ERROR_PARSE, - _("Character reference did not end with a " - "semicolon; " - "most likely you used an ampersand " - "character without intending to start " - "an entity - escape ampersand as &")); - } - - return p; -} - -static gboolean -unescape_text (GMarkupParseContext *context, - const gchar *text, - const gchar *text_end, - GString **unescaped, - GError **error) -{ - UnescapeContext ucontext; - const gchar *p; - - ucontext.context = context; - ucontext.text = text; - ucontext.text_end = text_end; - ucontext.entity_start = NULL; - - ucontext.str = g_string_sized_new (text_end - text); - - ucontext.state = USTATE_INSIDE_TEXT; - p = text; - - while (p != text_end && context->state != STATE_ERROR) - { - g_assert (p < text_end); - - switch (ucontext.state) - { - case USTATE_INSIDE_TEXT: - { - p = unescape_text_state_inside_text (&ucontext, - p, - error); - } - break; - - case USTATE_AFTER_AMPERSAND: - { - p = unescape_text_state_after_ampersand (&ucontext, - p, - error); - } - break; - - - case USTATE_INSIDE_ENTITY_NAME: - { - p = unescape_text_state_inside_entity_name (&ucontext, - p, - error); - } - break; - - case USTATE_AFTER_CHARREF_HASH: - { - p = unescape_text_state_after_charref_hash (&ucontext, - p, - error); - } - break; - - default: - g_assert_not_reached (); - break; - } - } - - if (context->state != STATE_ERROR) - { - switch (ucontext.state) - { - case USTATE_INSIDE_TEXT: - break; - case USTATE_AFTER_AMPERSAND: - case USTATE_INSIDE_ENTITY_NAME: - set_unescape_error (context, error, - NULL, NULL, - G_MARKUP_ERROR_PARSE, - _("Unfinished entity reference")); - break; - case USTATE_AFTER_CHARREF_HASH: - set_unescape_error (context, error, - NULL, NULL, - G_MARKUP_ERROR_PARSE, - _("Unfinished character reference")); - break; - } - } - - if (context->state == STATE_ERROR) - { - g_string_free (ucontext.str, TRUE); - *unescaped = NULL; - return FALSE; - } - else - { - *unescaped = ucontext.str; - return TRUE; - } -} - -static inline gboolean -advance_char (GMarkupParseContext *context) -{ - context->iter = g_utf8_next_char (context->iter); - context->char_number += 1; - - if (context->iter == context->current_text_end) - { - return FALSE; - } - else if (*context->iter == '\n') - { - context->line_number += 1; - context->char_number = 1; - } - - return TRUE; -} - -static inline gboolean -xml_isspace (char c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == '\r'; -} - -static void -skip_spaces (GMarkupParseContext *context) -{ - do - { - if (!xml_isspace (*context->iter)) - return; - } - while (advance_char (context)); -} - -static void -advance_to_name_end (GMarkupParseContext *context) -{ - do - { - if (!is_name_char (context->iter)) - return; - } - while (advance_char (context)); -} - -static void -add_to_partial (GMarkupParseContext *context, - const gchar *text_start, - const gchar *text_end) -{ - if (context->partial_chunk == NULL) - context->partial_chunk = g_string_sized_new (text_end - text_start); - - if (text_start != text_end) - g_string_append_len (context->partial_chunk, text_start, - text_end - text_start); - - /* Invariant here that partial_chunk exists */ -} - -static void -truncate_partial (GMarkupParseContext *context) -{ - if (context->partial_chunk != NULL) - { - context->partial_chunk = g_string_truncate (context->partial_chunk, 0); - } -} - -static const gchar* -current_element (GMarkupParseContext *context) -{ - return context->tag_stack->data; -} - -static void -pop_subparser_stack (GMarkupParseContext *context) -{ - GMarkupRecursionTracker *tracker; - - g_assert (context->subparser_stack); - - tracker = context->subparser_stack->data; - - context->awaiting_pop = TRUE; - context->held_user_data = context->user_data; - - context->user_data = tracker->prev_user_data; - context->parser = tracker->prev_parser; - context->subparser_element = tracker->prev_element; - g_slice_free (GMarkupRecursionTracker, tracker); - - context->subparser_stack = g_slist_delete_link (context->subparser_stack, - context->subparser_stack); -} - -static void -possibly_finish_subparser (GMarkupParseContext *context) -{ - if (current_element (context) == context->subparser_element) - pop_subparser_stack (context); -} - -static void -ensure_no_outstanding_subparser (GMarkupParseContext *context) -{ - if (context->awaiting_pop) - g_critical ("During the first end_element call after invoking a " - "subparser you must pop the subparser stack and handle " - "the freeing of the subparser user_data. This can be " - "done by calling the end function of the subparser. " - "Very probably, your program just leaked memory."); - - /* let valgrind watch the pointer disappear... */ - context->held_user_data = NULL; - context->awaiting_pop = FALSE; -} - -static const gchar* -current_attribute (GMarkupParseContext *context) -{ - g_assert (context->cur_attr >= 0); - return context->attr_names[context->cur_attr]; -} - -static void -find_current_text_end (GMarkupParseContext *context) -{ - /* This function must be safe (non-segfaulting) on invalid UTF8. - * It assumes the string starts with a character start - */ - const gchar *end = context->current_text + context->current_text_len; - const gchar *p; - const gchar *next; - - g_assert (context->current_text_len > 0); - - p = g_utf8_find_prev_char (context->current_text, end); - - g_assert (p != NULL); /* since current_text was a char start */ - - /* p is now the start of the last character or character portion. */ - g_assert (p != end); - next = g_utf8_next_char (p); /* this only touches *p, nothing beyond */ - - if (next == end) - { - /* whole character */ - context->current_text_end = end; - } - else - { - /* portion */ - context->leftover_char_portion = g_string_new_len (p, end - p); - context->current_text_len -= (end - p); - context->current_text_end = p; - } -} - - -static void -add_attribute (GMarkupParseContext *context, char *name) -{ - if (context->cur_attr + 2 >= context->alloc_attrs) - { - context->alloc_attrs += 5; /* silly magic number */ - context->attr_names = g_realloc (context->attr_names, sizeof(char*)*context->alloc_attrs); - context->attr_values = g_realloc (context->attr_values, sizeof(char*)*context->alloc_attrs); - } - context->cur_attr++; - context->attr_names[context->cur_attr] = name; - context->attr_values[context->cur_attr] = NULL; - context->attr_names[context->cur_attr+1] = NULL; - context->attr_values[context->cur_attr+1] = NULL; -} - -/** - * g_markup_parse_context_parse: - * @context: a #GMarkupParseContext - * @text: chunk of text to parse - * @text_len: length of @text in bytes - * @error: return location for a #GError - * - * Feed some data to the #GMarkupParseContext. The data need not - * be valid UTF-8; an error will be signaled if it's invalid. - * The data need not be an entire document; you can feed a document - * into the parser incrementally, via multiple calls to this function. - * Typically, as you receive data from a network connection or file, - * you feed each received chunk of data into this function, aborting - * the process if an error occurs. Once an error is reported, no further - * data may be fed to the #GMarkupParseContext; all errors are fatal. - * - * Return value: %FALSE if an error occurred, %TRUE on success - **/ -gboolean -g_markup_parse_context_parse (GMarkupParseContext *context, - const gchar *text, - gssize text_len, - GError **error) -{ - const gchar *first_invalid; - - g_return_val_if_fail (context != NULL, FALSE); - g_return_val_if_fail (text != NULL, FALSE); - g_return_val_if_fail (context->state != STATE_ERROR, FALSE); - g_return_val_if_fail (!context->parsing, FALSE); - - if (text_len < 0) - text_len = strlen (text); - - if (text_len == 0) - return TRUE; - - context->parsing = TRUE; - - if (context->leftover_char_portion) - { - const gchar *first_char; - - if ((*text & 0xc0) != 0x80) - first_char = text; - else - first_char = g_utf8_find_next_char (text, text + text_len); - - if (first_char) - { - /* leftover_char_portion was completed. Parse it. */ - GString *portion = context->leftover_char_portion; - - g_string_append_len (context->leftover_char_portion, - text, first_char - text); - - /* hacks to allow recursion */ - context->parsing = FALSE; - context->leftover_char_portion = NULL; - - if (!g_markup_parse_context_parse (context, - portion->str, portion->len, - error)) - { - g_assert (context->state == STATE_ERROR); - } - - g_string_free (portion, TRUE); - context->parsing = TRUE; - - /* Skip the fraction of char that was in this text */ - text_len -= (first_char - text); - text = first_char; - } - else - { - /* another little chunk of the leftover char; geez - * someone is inefficient. - */ - g_string_append_len (context->leftover_char_portion, - text, text_len); - - if (context->leftover_char_portion->len > 7) - { - /* The leftover char portion is too big to be - * a UTF-8 character - */ - set_error_literal (context, - error, - G_MARKUP_ERROR_BAD_UTF8, - _("Invalid UTF-8 encoded text - overlong sequence")); - } - - goto finished; - } - } - - context->current_text = text; - context->current_text_len = text_len; - context->iter = context->current_text; - context->start = context->iter; - - /* Nothing left after finishing the leftover char, or nothing - * passed in to begin with. - */ - if (context->current_text_len == 0) - goto finished; - - /* find_current_text_end () assumes the string starts at - * a character start, so we need to validate at least - * that much. It doesn't assume any following bytes - * are valid. - */ - if ((*context->current_text & 0xc0) == 0x80) /* not a char start */ - { - set_error_literal (context, - error, - G_MARKUP_ERROR_BAD_UTF8, - _("Invalid UTF-8 encoded text - not a start char")); - goto finished; - } - - /* Initialize context->current_text_end, possibly adjusting - * current_text_len, and add any leftover char portion - */ - find_current_text_end (context); - - /* Validate UTF8 (must be done after we find the end, since - * we could have a trailing incomplete char) - */ - if (!g_utf8_validate (context->current_text, - context->current_text_len, - &first_invalid)) - { - gint newlines = 0; - const gchar *p, *q; - gchar *current_text_dup; - - q = p = context->current_text; - while (p != first_invalid) - { - if (*p == '\n') - { - ++newlines; - q = p + 1; - context->char_number = 1; - } - ++p; - } - - context->line_number += newlines; - context->char_number += g_utf8_strlen (q, first_invalid - q); - - current_text_dup = g_strndup (context->current_text, context->current_text_len); - set_error (context, - error, - G_MARKUP_ERROR_BAD_UTF8, - _("Invalid UTF-8 encoded text - not valid '%s'"), - current_text_dup); - g_free (current_text_dup); - goto finished; - } - - while (context->iter != context->current_text_end) - { - switch (context->state) - { - case STATE_START: - /* Possible next state: AFTER_OPEN_ANGLE */ - - g_assert (context->tag_stack == NULL); - - /* whitespace is ignored outside of any elements */ - skip_spaces (context); - - if (context->iter != context->current_text_end) - { - if (*context->iter == '<') - { - /* Move after the open angle */ - advance_char (context); - - context->state = STATE_AFTER_OPEN_ANGLE; - - /* this could start a passthrough */ - context->start = context->iter; - - /* document is now non-empty */ - context->document_empty = FALSE; - } - else - { - set_error_literal (context, - error, - G_MARKUP_ERROR_PARSE, - _("Document must begin with an element (e.g. <book>)")); - } - } - break; - - case STATE_AFTER_OPEN_ANGLE: - /* Possible next states: INSIDE_OPEN_TAG_NAME, - * AFTER_CLOSE_TAG_SLASH, INSIDE_PASSTHROUGH - */ - if (*context->iter == '?' || - *context->iter == '!') - { - /* include < in the passthrough */ - const gchar *openangle = "<"; - add_to_partial (context, openangle, openangle + 1); - context->start = context->iter; - context->balance = 1; - context->state = STATE_INSIDE_PASSTHROUGH; - } - else if (*context->iter == '/') - { - /* move after it */ - advance_char (context); - - context->state = STATE_AFTER_CLOSE_TAG_SLASH; - } - else if (is_name_start_char (context->iter)) - { - context->state = STATE_INSIDE_OPEN_TAG_NAME; - - /* start of tag name */ - context->start = context->iter; - } - else - { - gchar buf[8]; - - set_error (context, - error, - G_MARKUP_ERROR_PARSE, - _("'%s' is not a valid character following " - "a '<' character; it may not begin an " - "element name"), - utf8_str (context->iter, buf)); - } - break; - - /* The AFTER_CLOSE_ANGLE state is actually sort of - * broken, because it doesn't correspond to a range - * of characters in the input stream as the others do, - * and thus makes things harder to conceptualize - */ - case STATE_AFTER_CLOSE_ANGLE: - /* Possible next states: INSIDE_TEXT, STATE_START */ - if (context->tag_stack == NULL) - { - context->start = NULL; - context->state = STATE_START; - } - else - { - context->start = context->iter; - context->state = STATE_INSIDE_TEXT; - } - break; - - case STATE_AFTER_ELISION_SLASH: - /* Possible next state: AFTER_CLOSE_ANGLE */ - - { - /* We need to pop the tag stack and call the end_element - * function, since this is the close tag - */ - GError *tmp_error = NULL; - - g_assert (context->tag_stack != NULL); - - possibly_finish_subparser (context); - - tmp_error = NULL; - if (context->parser->end_element) - (* context->parser->end_element) (context, - context->tag_stack->data, - context->user_data, - &tmp_error); - - ensure_no_outstanding_subparser (context); - - if (tmp_error) - { - mark_error (context, tmp_error); - g_propagate_error (error, tmp_error); - } - else - { - if (*context->iter == '>') - { - /* move after the close angle */ - advance_char (context); - context->state = STATE_AFTER_CLOSE_ANGLE; - } - else - { - gchar buf[8]; - - set_error (context, - error, - G_MARKUP_ERROR_PARSE, - _("Odd character '%s', expected a '>' character " - "to end the empty-element tag '%s'"), - utf8_str (context->iter, buf), - current_element (context)); - } - } - - g_free (context->tag_stack->data); - context->tag_stack = g_slist_delete_link (context->tag_stack, - context->tag_stack); - } - break; - - case STATE_INSIDE_OPEN_TAG_NAME: - /* Possible next states: BETWEEN_ATTRIBUTES */ - - /* if there's a partial chunk then it's the first part of the - * tag name. If there's a context->start then it's the start - * of the tag name in current_text, the partial chunk goes - * before that start though. - */ - advance_to_name_end (context); - - if (context->iter == context->current_text_end) - { - /* The name hasn't necessarily ended. Merge with - * partial chunk, leave state unchanged. - */ - add_to_partial (context, context->start, context->iter); - } - else - { - /* The name has ended. Combine it with the partial chunk - * if any; push it on the stack; enter next state. - */ - add_to_partial (context, context->start, context->iter); - context->tag_stack = - g_slist_prepend (context->tag_stack, - g_string_free (context->partial_chunk, - FALSE)); - - context->partial_chunk = NULL; - - context->state = STATE_BETWEEN_ATTRIBUTES; - context->start = NULL; - } - break; - - case STATE_INSIDE_ATTRIBUTE_NAME: - /* Possible next states: AFTER_ATTRIBUTE_NAME */ - - advance_to_name_end (context); - add_to_partial (context, context->start, context->iter); - - /* read the full name, if we enter the equals sign state - * then add the attribute to the list (without the value), - * otherwise store a partial chunk to be prepended later. - */ - if (context->iter != context->current_text_end) - context->state = STATE_AFTER_ATTRIBUTE_NAME; - break; - - case STATE_AFTER_ATTRIBUTE_NAME: - /* Possible next states: AFTER_ATTRIBUTE_EQUALS_SIGN */ - - skip_spaces (context); - - if (context->iter != context->current_text_end) - { - /* The name has ended. Combine it with the partial chunk - * if any; push it on the stack; enter next state. - */ - add_attribute (context, g_string_free (context->partial_chunk, FALSE)); - - context->partial_chunk = NULL; - context->start = NULL; - - if (*context->iter == '=') - { - advance_char (context); - context->state = STATE_AFTER_ATTRIBUTE_EQUALS_SIGN; - } - else - { - gchar buf[8]; - - set_error (context, - error, - G_MARKUP_ERROR_PARSE, - _("Odd character '%s', expected a '=' after " - "attribute name '%s' of element '%s'"), - utf8_str (context->iter, buf), - current_attribute (context), - current_element (context)); - - } - } - break; - - case STATE_BETWEEN_ATTRIBUTES: - /* Possible next states: AFTER_CLOSE_ANGLE, - * AFTER_ELISION_SLASH, INSIDE_ATTRIBUTE_NAME - */ - skip_spaces (context); - - if (context->iter != context->current_text_end) - { - if (*context->iter == '/') - { - advance_char (context); - context->state = STATE_AFTER_ELISION_SLASH; - } - else if (*context->iter == '>') - { - - advance_char (context); - context->state = STATE_AFTER_CLOSE_ANGLE; - } - else if (is_name_start_char (context->iter)) - { - context->state = STATE_INSIDE_ATTRIBUTE_NAME; - /* start of attribute name */ - context->start = context->iter; - } - else - { - gchar buf[8]; - - set_error (context, - error, - G_MARKUP_ERROR_PARSE, - _("Odd character '%s', expected a '>' or '/' " - "character to end the start tag of " - "element '%s', or optionally an attribute; " - "perhaps you used an invalid character in " - "an attribute name"), - utf8_str (context->iter, buf), - current_element (context)); - } - - /* If we're done with attributes, invoke - * the start_element callback - */ - if (context->state == STATE_AFTER_ELISION_SLASH || - context->state == STATE_AFTER_CLOSE_ANGLE) - { - const gchar *start_name; - /* Ugly, but the current code expects an empty array instead of NULL */ - const gchar *empty = NULL; - const gchar **attr_names = ∅ - const gchar **attr_values = ∅ - GError *tmp_error; - - /* Call user callback for element start */ - start_name = current_element (context); - - if (context->cur_attr >= 0) - { - attr_names = (const gchar**)context->attr_names; - attr_values = (const gchar**)context->attr_values; - } - - tmp_error = NULL; - if (context->parser->start_element) - (* context->parser->start_element) (context, - start_name, - (const gchar **)attr_names, - (const gchar **)attr_values, - context->user_data, - &tmp_error); - - /* Go ahead and free the attributes. */ - for (; context->cur_attr >= 0; context->cur_attr--) - { - int pos = context->cur_attr; - g_free (context->attr_names[pos]); - g_free (context->attr_values[pos]); - context->attr_names[pos] = context->attr_values[pos] = NULL; - } - g_assert (context->cur_attr == -1); - g_assert (context->attr_names == NULL || - context->attr_names[0] == NULL); - g_assert (context->attr_values == NULL || - context->attr_values[0] == NULL); - - if (tmp_error != NULL) - propagate_error (context, error, tmp_error); - } - } - break; - - case STATE_AFTER_ATTRIBUTE_EQUALS_SIGN: - /* Possible next state: INSIDE_ATTRIBUTE_VALUE_[SQ/DQ] */ - - skip_spaces (context); - - if (context->iter != context->current_text_end) - { - if (*context->iter == '"') - { - advance_char (context); - context->state = STATE_INSIDE_ATTRIBUTE_VALUE_DQ; - context->start = context->iter; - } - else if (*context->iter == '\'') - { - advance_char (context); - context->state = STATE_INSIDE_ATTRIBUTE_VALUE_SQ; - context->start = context->iter; - } - else - { - gchar buf[8]; - - set_error (context, - error, - G_MARKUP_ERROR_PARSE, - _("Odd character '%s', expected an open quote mark " - "after the equals sign when giving value for " - "attribute '%s' of element '%s'"), - utf8_str (context->iter, buf), - current_attribute (context), - current_element (context)); - } - } - break; - - case STATE_INSIDE_ATTRIBUTE_VALUE_SQ: - case STATE_INSIDE_ATTRIBUTE_VALUE_DQ: - /* Possible next states: BETWEEN_ATTRIBUTES */ - { - gchar delim; - - if (context->state == STATE_INSIDE_ATTRIBUTE_VALUE_SQ) - { - delim = '\''; - } - else - { - delim = '"'; - } - - do - { - if (*context->iter == delim) - break; - } - while (advance_char (context)); - } - if (context->iter == context->current_text_end) - { - /* The value hasn't necessarily ended. Merge with - * partial chunk, leave state unchanged. - */ - add_to_partial (context, context->start, context->iter); - } - else - { - /* The value has ended at the quote mark. Combine it - * with the partial chunk if any; set it for the current - * attribute. - */ - GString *unescaped; - - add_to_partial (context, context->start, context->iter); - - g_assert (context->cur_attr >= 0); - - if (unescape_text (context, - context->partial_chunk->str, - context->partial_chunk->str + - context->partial_chunk->len, - &unescaped, - error)) - { - /* success, advance past quote and set state. */ - context->attr_values[context->cur_attr] = g_string_free (unescaped, FALSE); - advance_char (context); - context->state = STATE_BETWEEN_ATTRIBUTES; - context->start = NULL; - } - - truncate_partial (context); - } - break; - - case STATE_INSIDE_TEXT: - /* Possible next states: AFTER_OPEN_ANGLE */ - do - { - if (*context->iter == '<') - break; - } - while (advance_char (context)); - - /* The text hasn't necessarily ended. Merge with - * partial chunk, leave state unchanged. - */ - - add_to_partial (context, context->start, context->iter); - - if (context->iter != context->current_text_end) - { - GString *unescaped = NULL; - - /* The text has ended at the open angle. Call the text - * callback. - */ - - if (unescape_text (context, - context->partial_chunk->str, - context->partial_chunk->str + - context->partial_chunk->len, - &unescaped, - error)) - { - GError *tmp_error = NULL; - - if (context->parser->text) - (*context->parser->text) (context, - unescaped->str, - unescaped->len, - context->user_data, - &tmp_error); - - g_string_free (unescaped, TRUE); - - if (tmp_error == NULL) - { - /* advance past open angle and set state. */ - advance_char (context); - context->state = STATE_AFTER_OPEN_ANGLE; - /* could begin a passthrough */ - context->start = context->iter; - } - else - propagate_error (context, error, tmp_error); - } - - truncate_partial (context); - } - break; - - case STATE_AFTER_CLOSE_TAG_SLASH: - /* Possible next state: INSIDE_CLOSE_TAG_NAME */ - if (is_name_start_char (context->iter)) - { - context->state = STATE_INSIDE_CLOSE_TAG_NAME; - - /* start of tag name */ - context->start = context->iter; - } - else - { - gchar buf[8]; - - set_error (context, - error, - G_MARKUP_ERROR_PARSE, - _("'%s' is not a valid character following " - "the characters '</'; '%s' may not begin an " - "element name"), - utf8_str (context->iter, buf), - utf8_str (context->iter, buf)); - } - break; - - case STATE_INSIDE_CLOSE_TAG_NAME: - /* Possible next state: AFTER_CLOSE_TAG_NAME */ - advance_to_name_end (context); - add_to_partial (context, context->start, context->iter); - - if (context->iter != context->current_text_end) - context->state = STATE_AFTER_CLOSE_TAG_NAME; - break; - - case STATE_AFTER_CLOSE_TAG_NAME: - /* Possible next state: AFTER_CLOSE_TAG_SLASH */ - - skip_spaces (context); - - if (context->iter != context->current_text_end) - { - gchar *close_name; - - /* The name has ended. Combine it with the partial chunk - * if any; check that it matches stack top and pop - * stack; invoke proper callback; enter next state. - */ - close_name = g_string_free (context->partial_chunk, FALSE); - context->partial_chunk = NULL; - - if (*context->iter != '>') - { - gchar buf[8]; - - set_error (context, - error, - G_MARKUP_ERROR_PARSE, - _("'%s' is not a valid character following " - "the close element name '%s'; the allowed " - "character is '>'"), - utf8_str (context->iter, buf), - close_name); - } - else if (context->tag_stack == NULL) - { - set_error (context, - error, - G_MARKUP_ERROR_PARSE, - _("Element '%s' was closed, no element " - "is currently open"), - close_name); - } - else if (strcmp (close_name, current_element (context)) != 0) - { - set_error (context, - error, - G_MARKUP_ERROR_PARSE, - _("Element '%s' was closed, but the currently " - "open element is '%s'"), - close_name, - current_element (context)); - } - else - { - GError *tmp_error; - advance_char (context); - context->state = STATE_AFTER_CLOSE_ANGLE; - context->start = NULL; - - possibly_finish_subparser (context); - - /* call the end_element callback */ - tmp_error = NULL; - if (context->parser->end_element) - (* context->parser->end_element) (context, - close_name, - context->user_data, - &tmp_error); - - ensure_no_outstanding_subparser (context); - - /* Pop the tag stack */ - g_free (context->tag_stack->data); - context->tag_stack = g_slist_delete_link (context->tag_stack, - context->tag_stack); - - if (tmp_error) - propagate_error (context, error, tmp_error); - } - - g_free (close_name); - } - break; - - case STATE_INSIDE_PASSTHROUGH: - /* Possible next state: AFTER_CLOSE_ANGLE */ - do - { - if (*context->iter == '<') - context->balance++; - if (*context->iter == '>') - { - gchar *str; - gsize len; - - context->balance--; - add_to_partial (context, context->start, context->iter); - context->start = context->iter; - - str = context->partial_chunk->str; - len = context->partial_chunk->len; - - if (str[1] == '?' && str[len - 1] == '?') - break; - if (strncmp (str, "<!--", 4) == 0 && - strcmp (str + len - 2, "--") == 0) - break; - if (strncmp (str, "<![CDATA[", 9) == 0 && - strcmp (str + len - 2, "]]") == 0) - break; - if (strncmp (str, "<!DOCTYPE", 9) == 0 && - context->balance == 0) - break; - } - } - while (advance_char (context)); - - if (context->iter == context->current_text_end) - { - /* The passthrough hasn't necessarily ended. Merge with - * partial chunk, leave state unchanged. - */ - add_to_partial (context, context->start, context->iter); - } - else - { - /* The passthrough has ended at the close angle. Combine - * it with the partial chunk if any. Call the passthrough - * callback. Note that the open/close angles are - * included in the text of the passthrough. - */ - GError *tmp_error = NULL; - - advance_char (context); /* advance past close angle */ - add_to_partial (context, context->start, context->iter); - - if (context->flags & G_MARKUP_TREAT_CDATA_AS_TEXT && - strncmp (context->partial_chunk->str, "<![CDATA[", 9) == 0) - { - if (context->parser->text) - (*context->parser->text) (context, - context->partial_chunk->str + 9, - context->partial_chunk->len - 12, - context->user_data, - &tmp_error); - } - else if (context->parser->passthrough) - (*context->parser->passthrough) (context, - context->partial_chunk->str, - context->partial_chunk->len, - context->user_data, - &tmp_error); - - truncate_partial (context); - - if (tmp_error == NULL) - { - context->state = STATE_AFTER_CLOSE_ANGLE; - context->start = context->iter; /* could begin text */ - } - else - propagate_error (context, error, tmp_error); - } - break; - - case STATE_ERROR: - goto finished; - break; - - default: - g_assert_not_reached (); - break; - } - } - - finished: - context->parsing = FALSE; - - return context->state != STATE_ERROR; -} - -/** - * g_markup_parse_context_end_parse: - * @context: a #GMarkupParseContext - * @error: return location for a #GError - * - * Signals to the #GMarkupParseContext that all data has been - * fed into the parse context with g_markup_parse_context_parse(). - * This function reports an error if the document isn't complete, - * for example if elements are still open. - * - * Return value: %TRUE on success, %FALSE if an error was set - **/ -gboolean -g_markup_parse_context_end_parse (GMarkupParseContext *context, - GError **error) -{ - g_return_val_if_fail (context != NULL, FALSE); - g_return_val_if_fail (!context->parsing, FALSE); - g_return_val_if_fail (context->state != STATE_ERROR, FALSE); - - if (context->partial_chunk != NULL) - { - g_string_free (context->partial_chunk, TRUE); - context->partial_chunk = NULL; - } - - if (context->document_empty) - { - set_error_literal (context, error, G_MARKUP_ERROR_EMPTY, - _("Document was empty or contained only whitespace")); - return FALSE; - } - - context->parsing = TRUE; - - switch (context->state) - { - case STATE_START: - /* Nothing to do */ - break; - - case STATE_AFTER_OPEN_ANGLE: - set_error_literal (context, error, G_MARKUP_ERROR_PARSE, - _("Document ended unexpectedly just after an open angle bracket '<'")); - break; - - case STATE_AFTER_CLOSE_ANGLE: - if (context->tag_stack != NULL) - { - /* Error message the same as for INSIDE_TEXT */ - set_error (context, error, G_MARKUP_ERROR_PARSE, - _("Document ended unexpectedly with elements still open - " - "'%s' was the last element opened"), - current_element (context)); - } - break; - - case STATE_AFTER_ELISION_SLASH: - set_error (context, error, G_MARKUP_ERROR_PARSE, - _("Document ended unexpectedly, expected to see a close angle " - "bracket ending the tag <%s/>"), current_element (context)); - break; - - case STATE_INSIDE_OPEN_TAG_NAME: - set_error_literal (context, error, G_MARKUP_ERROR_PARSE, - _("Document ended unexpectedly inside an element name")); - break; - - case STATE_INSIDE_ATTRIBUTE_NAME: - case STATE_AFTER_ATTRIBUTE_NAME: - set_error_literal (context, error, G_MARKUP_ERROR_PARSE, - _("Document ended unexpectedly inside an attribute name")); - break; - - case STATE_BETWEEN_ATTRIBUTES: - set_error_literal (context, error, G_MARKUP_ERROR_PARSE, - _("Document ended unexpectedly inside an element-opening " - "tag.")); - break; - - case STATE_AFTER_ATTRIBUTE_EQUALS_SIGN: - set_error_literal (context, error, G_MARKUP_ERROR_PARSE, - _("Document ended unexpectedly after the equals sign " - "following an attribute name; no attribute value")); - break; - - case STATE_INSIDE_ATTRIBUTE_VALUE_SQ: - case STATE_INSIDE_ATTRIBUTE_VALUE_DQ: - set_error_literal (context, error, G_MARKUP_ERROR_PARSE, - _("Document ended unexpectedly while inside an attribute " - "value")); - break; - - case STATE_INSIDE_TEXT: - g_assert (context->tag_stack != NULL); - set_error (context, error, G_MARKUP_ERROR_PARSE, - _("Document ended unexpectedly with elements still open - " - "'%s' was the last element opened"), - current_element (context)); - break; - - case STATE_AFTER_CLOSE_TAG_SLASH: - case STATE_INSIDE_CLOSE_TAG_NAME: - case STATE_AFTER_CLOSE_TAG_NAME: - set_error (context, error, G_MARKUP_ERROR_PARSE, - _("Document ended unexpectedly inside the close tag for " - "element '%s'"), current_element (context)); - break; - - case STATE_INSIDE_PASSTHROUGH: - set_error_literal (context, error, G_MARKUP_ERROR_PARSE, - _("Document ended unexpectedly inside a comment or " - "processing instruction")); - break; - - case STATE_ERROR: - default: - g_assert_not_reached (); - break; - } - - context->parsing = FALSE; - - return context->state != STATE_ERROR; -} - -/** - * g_markup_parse_context_get_element: - * @context: a #GMarkupParseContext - * @returns: the name of the currently open element, or %NULL - * - * Retrieves the name of the currently open element. - * - * If called from the start_element or end_element handlers this will - * give the element_name as passed to those functions. For the parent - * elements, see g_markup_parse_context_get_element_stack(). - * - * Since: 2.2 - **/ -G_CONST_RETURN gchar * -g_markup_parse_context_get_element (GMarkupParseContext *context) -{ - g_return_val_if_fail (context != NULL, NULL); - - if (context->tag_stack == NULL) - return NULL; - else - return current_element (context); -} - -/** - * g_markup_parse_context_get_element_stack: - * @context: a #GMarkupParseContext - * - * Retrieves the element stack from the internal state of the parser. - * The returned #GSList is a list of strings where the first item is - * the currently open tag (as would be returned by - * g_markup_parse_context_get_element()) and the next item is its - * immediate parent. - * - * This function is intended to be used in the start_element and - * end_element handlers where g_markup_parse_context_get_element() - * would merely return the name of the element that is being - * processed. - * - * Returns: the element stack, which must not be modified - * - * Since: 2.16 - **/ -G_CONST_RETURN GSList * -g_markup_parse_context_get_element_stack (GMarkupParseContext *context) -{ - g_return_val_if_fail (context != NULL, NULL); - - return context->tag_stack; -} - -/** - * g_markup_parse_context_get_position: - * @context: a #GMarkupParseContext - * @line_number: return location for a line number, or %NULL - * @char_number: return location for a char-on-line number, or %NULL - * - * Retrieves the current line number and the number of the character on - * that line. Intended for use in error messages; there are no strict - * semantics for what constitutes the "current" line number other than - * "the best number we could come up with for error messages." - * - **/ -void -g_markup_parse_context_get_position (GMarkupParseContext *context, - gint *line_number, - gint *char_number) -{ - g_return_if_fail (context != NULL); - - if (line_number) - *line_number = context->line_number; - - if (char_number) - *char_number = context->char_number; -} - -/** - * g_markup_parse_context_get_user_data: - * @context: a #GMarkupParseContext - * - * Returns the user_data associated with @context. This will either - * be the user_data that was provided to g_markup_parse_context_new() - * or to the most recent call of g_markup_parse_context_push(). - * - * Returns: the provided user_data. The returned data belongs to - * the markup context and will be freed when g_markup_context_free() - * is called. - * - * Since: 2.18 - **/ -gpointer -g_markup_parse_context_get_user_data (GMarkupParseContext *context) -{ - return context->user_data; -} - -/** - * g_markup_parse_context_push: - * @context: a #GMarkupParseContext - * @parser: a #GMarkupParser - * @user_data: user data to pass to #GMarkupParser functions - * - * Temporarily redirects markup data to a sub-parser. - * - * This function may only be called from the start_element handler of - * a #GMarkupParser. It must be matched with a corresponding call to - * g_markup_parse_context_pop() in the matching end_element handler - * (except in the case that the parser aborts due to an error). - * - * All tags, text and other data between the matching tags is - * redirected to the subparser given by @parser. @user_data is used - * as the user_data for that parser. @user_data is also passed to the - * error callback in the event that an error occurs. This includes - * errors that occur in subparsers of the subparser. - * - * The end tag matching the start tag for which this call was made is - * handled by the previous parser (which is given its own user_data) - * which is why g_markup_parse_context_pop() is provided to allow "one - * last access" to the @user_data provided to this function. In the - * case of error, the @user_data provided here is passed directly to - * the error callback of the subparser and g_markup_parse_context() - * should not be called. In either case, if @user_data was allocated - * then it ought to be freed from both of these locations. - * - * This function is not intended to be directly called by users - * interested in invoking subparsers. Instead, it is intended to be - * used by the subparsers themselves to implement a higher-level - * interface. - * - * As an example, see the following implementation of a simple - * parser that counts the number of tags encountered. - * - * |[ - * typedef struct - * { - * gint tag_count; - * } CounterData; - * - * static void - * counter_start_element (GMarkupParseContext *context, - * const gchar *element_name, - * const gchar **attribute_names, - * const gchar **attribute_values, - * gpointer user_data, - * GError **error) - * { - * CounterData *data = user_data; - * - * data->tag_count++; - * } - * - * static void - * counter_error (GMarkupParseContext *context, - * GError *error, - * gpointer user_data) - * { - * CounterData *data = user_data; - * - * g_slice_free (CounterData, data); - * } - * - * static GMarkupParser counter_subparser = - * { - * counter_start_element, - * NULL, - * NULL, - * NULL, - * counter_error - * }; - * ]| - * - * In order to allow this parser to be easily used as a subparser, the - * following interface is provided: - * - * |[ - * void - * start_counting (GMarkupParseContext *context) - * { - * CounterData *data = g_slice_new (CounterData); - * - * data->tag_count = 0; - * g_markup_parse_context_push (context, &counter_subparser, data); - * } - * - * gint - * end_counting (GMarkupParseContext *context) - * { - * CounterData *data = g_markup_parse_context_pop (context); - * int result; - * - * result = data->tag_count; - * g_slice_free (CounterData, data); - * - * return result; - * } - * ]| - * - * The subparser would then be used as follows: - * - * |[ - * static void start_element (context, element_name, ...) - * { - * if (strcmp (element_name, "count-these") == 0) - * start_counting (context); - * - * /* else, handle other tags... */ - * } - * - * static void end_element (context, element_name, ...) - * { - * if (strcmp (element_name, "count-these") == 0) - * g_print ("Counted %d tags\n", end_counting (context)); - * - * /* else, handle other tags... */ - * } - * ]| - * - * Since: 2.18 - **/ -void -g_markup_parse_context_push (GMarkupParseContext *context, - GMarkupParser *parser, - gpointer user_data) -{ - GMarkupRecursionTracker *tracker; - - tracker = g_slice_new (GMarkupRecursionTracker); - tracker->prev_element = context->subparser_element; - tracker->prev_parser = context->parser; - tracker->prev_user_data = context->user_data; - - context->subparser_element = current_element (context); - context->parser = parser; - context->user_data = user_data; - - context->subparser_stack = g_slist_prepend (context->subparser_stack, - tracker); -} - -/** - * g_markup_parse_context_pop: - * @context: a #GMarkupParseContext - * - * Completes the process of a temporary sub-parser redirection. - * - * This function exists to collect the user_data allocated by a - * matching call to g_markup_parse_context_push(). It must be called - * in the end_element handler corresponding to the start_element - * handler during which g_markup_parse_context_push() was called. You - * must not call this function from the error callback -- the - * @user_data is provided directly to the callback in that case. - * - * This function is not intended to be directly called by users - * interested in invoking subparsers. Instead, it is intended to be - * used by the subparsers themselves to implement a higher-level - * interface. - * - * Returns: the user_data passed to g_markup_parse_context_push(). - * - * Since: 2.18 - **/ -gpointer -g_markup_parse_context_pop (GMarkupParseContext *context) -{ - gpointer user_data; - - if (!context->awaiting_pop) - possibly_finish_subparser (context); - - g_assert (context->awaiting_pop); - - context->awaiting_pop = FALSE; - - /* valgrind friendliness */ - user_data = context->held_user_data; - context->held_user_data = NULL; - - return user_data; -} - -static void -append_escaped_text (GString *str, - const gchar *text, - gssize length) -{ - const gchar *p; - const gchar *end; - gunichar c; - - p = text; - end = text + length; - - while (p != end) - { - const gchar *next; - next = g_utf8_next_char (p); - - switch (*p) - { - case '&': - g_string_append (str, "&"); - break; - - case '<': - g_string_append (str, "<"); - break; - - case '>': - g_string_append (str, ">"); - break; - - case '\'': - g_string_append (str, "'"); - break; - - case '"': - g_string_append (str, """); - break; - - default: - c = g_utf8_get_char (p); - if ((0x1 <= c && c <= 0x8) || - (0xb <= c && c <= 0xc) || - (0xe <= c && c <= 0x1f) || - (0x7f <= c && c <= 0x84) || - (0x86 <= c && c <= 0x9f)) - g_string_append_printf (str, "&#x%x;", c); - else - g_string_append_len (str, p, next - p); - break; - } - - p = next; - } -} - -/** - * g_markup_escape_text: - * @text: some valid UTF-8 text - * @length: length of @text in bytes, or -1 if the text is nul-terminated - * - * Escapes text so that the markup parser will parse it verbatim. - * Less than, greater than, ampersand, etc. are replaced with the - * corresponding entities. This function would typically be used - * when writing out a file to be parsed with the markup parser. - * - * Note that this function doesn't protect whitespace and line endings - * from being processed according to the XML rules for normalization - * of line endings and attribute values. - * - * Note also that if given a string containing them, this function - * will produce character references in the range of &#x1; .. - * &#x1f; for all control sequences except for tabstop, newline - * and carriage return. The character references in this range are - * not valid XML 1.0, but they are valid XML 1.1 and will be accepted - * by the GMarkup parser. - * - * Return value: a newly allocated string with the escaped text - **/ -gchar* -g_markup_escape_text (const gchar *text, - gssize length) -{ - GString *str; - - g_return_val_if_fail (text != NULL, NULL); - - if (length < 0) - length = strlen (text); - - /* prealloc at least as long as original text */ - str = g_string_sized_new (length); - append_escaped_text (str, text, length); - - return g_string_free (str, FALSE); -} - -/** - * find_conversion: - * @format: a printf-style format string - * @after: location to store a pointer to the character after - * the returned conversion. On a %NULL return, returns the - * pointer to the trailing NUL in the string - * - * Find the next conversion in a printf-style format string. - * Partially based on code from printf-parser.c, - * Copyright (C) 1999-2000, 2002-2003 Free Software Foundation, Inc. - * - * Return value: pointer to the next conversion in @format, - * or %NULL, if none. - **/ -static const char * -find_conversion (const char *format, - const char **after) -{ - const char *start = format; - const char *cp; - - while (*start != '\0' && *start != '%') - start++; - - if (*start == '\0') - { - *after = start; - return NULL; - } - - cp = start + 1; - - if (*cp == '\0') - { - *after = cp; - return NULL; - } - - /* Test for positional argument. */ - if (*cp >= '0' && *cp <= '9') - { - const char *np; - - for (np = cp; *np >= '0' && *np <= '9'; np++) - ; - if (*np == '$') - cp = np + 1; - } - - /* Skip the flags. */ - for (;;) - { - if (*cp == '\'' || - *cp == '-' || - *cp == '+' || - *cp == ' ' || - *cp == '#' || - *cp == '0') - cp++; - else - break; - } - - /* Skip the field width. */ - if (*cp == '*') - { - cp++; - - /* Test for positional argument. */ - if (*cp >= '0' && *cp <= '9') - { - const char *np; - - for (np = cp; *np >= '0' && *np <= '9'; np++) - ; - if (*np == '$') - cp = np + 1; - } - } - else - { - for (; *cp >= '0' && *cp <= '9'; cp++) - ; - } - - /* Skip the precision. */ - if (*cp == '.') - { - cp++; - if (*cp == '*') - { - /* Test for positional argument. */ - if (*cp >= '0' && *cp <= '9') - { - const char *np; - - for (np = cp; *np >= '0' && *np <= '9'; np++) - ; - if (*np == '$') - cp = np + 1; - } - } - else - { - for (; *cp >= '0' && *cp <= '9'; cp++) - ; - } - } - - /* Skip argument type/size specifiers. */ - while (*cp == 'h' || - *cp == 'L' || - *cp == 'l' || - *cp == 'j' || - *cp == 'z' || - *cp == 'Z' || - *cp == 't') - cp++; - - /* Skip the conversion character. */ - cp++; - - *after = cp; - return start; -} - -/** - * g_markup_vprintf_escaped: - * @format: printf() style format string - * @args: variable argument list, similar to vprintf() - * - * Formats the data in @args according to @format, escaping - * all string and character arguments in the fashion - * of g_markup_escape_text(). See g_markup_printf_escaped(). - * - * Return value: newly allocated result from formatting - * operation. Free with g_free(). - * - * Since: 2.4 - **/ -char * -g_markup_vprintf_escaped (const char *format, - va_list args) -{ - GString *format1; - GString *format2; - GString *result = NULL; - gchar *output1 = NULL; - gchar *output2 = NULL; - const char *p, *op1, *op2; - va_list args2; - - /* The technique here, is that we make two format strings that - * have the identical conversions in the identical order to the - * original strings, but differ in the text in-between. We - * then use the normal g_strdup_vprintf() to format the arguments - * with the two new format strings. By comparing the results, - * we can figure out what segments of the output come from - * the the original format string, and what from the arguments, - * and thus know what portions of the string to escape. - * - * For instance, for: - * - * g_markup_printf_escaped ("%s ate %d apples", "Susan & Fred", 5); - * - * We form the two format strings "%sX%dX" and %sY%sY". The results - * of formatting with those two strings are - * - * "%sX%dX" => "Susan & FredX5X" - * "%sY%dY" => "Susan & FredY5Y" - * - * To find the span of the first argument, we find the first position - * where the two arguments differ, which tells us that the first - * argument formatted to "Susan & Fred". We then escape that - * to "Susan & Fred" and join up with the intermediate portions - * of the format string and the second argument to get - * "Susan & Fred ate 5 apples". - */ - - /* Create the two modified format strings - */ - format1 = g_string_new (NULL); - format2 = g_string_new (NULL); - p = format; - while (TRUE) - { - const char *after; - const char *conv = find_conversion (p, &after); - if (!conv) - break; - - g_string_append_len (format1, conv, after - conv); - g_string_append_c (format1, 'X'); - g_string_append_len (format2, conv, after - conv); - g_string_append_c (format2, 'Y'); - - p = after; - } - - /* Use them to format the arguments - */ - G_VA_COPY (args2, args); - - output1 = g_strdup_vprintf (format1->str, args); - if (!output1) - { - va_end (args2); - goto cleanup; - } - - output2 = g_strdup_vprintf (format2->str, args2); - va_end (args2); - if (!output2) - goto cleanup; - - result = g_string_new (NULL); - - /* Iterate through the original format string again, - * copying the non-conversion portions and the escaped - * converted arguments to the output string. - */ - op1 = output1; - op2 = output2; - p = format; - while (TRUE) - { - const char *after; - const char *output_start; - const char *conv = find_conversion (p, &after); - char *escaped; - - if (!conv) /* The end, after points to the trailing \0 */ - { - g_string_append_len (result, p, after - p); - break; - } - - g_string_append_len (result, p, conv - p); - output_start = op1; - while (*op1 == *op2) - { - op1++; - op2++; - } - - escaped = g_markup_escape_text (output_start, op1 - output_start); - g_string_append (result, escaped); - g_free (escaped); - - p = after; - op1++; - op2++; - } - - cleanup: - g_string_free (format1, TRUE); - g_string_free (format2, TRUE); - g_free (output1); - g_free (output2); - - if (result) - return g_string_free (result, FALSE); - else - return NULL; -} - -/** - * g_markup_printf_escaped: - * @format: printf() style format string - * @Varargs: the arguments to insert in the format string - * - * Formats arguments according to @format, escaping - * all string and character arguments in the fashion - * of g_markup_escape_text(). This is useful when you - * want to insert literal strings into XML-style markup - * output, without having to worry that the strings - * might themselves contain markup. - * - * |[ - * const char *store = "Fortnum & Mason"; - * const char *item = "Tea"; - * char *output; - * - * output = g_markup_printf_escaped ("<purchase>" - * "<store>%s</store>" - * "<item>%s</item>" - * "</purchase>", - * store, item); - * ]| - * - * Return value: newly allocated result from formatting - * operation. Free with g_free(). - * - * Since: 2.4 - **/ -char * -g_markup_printf_escaped (const char *format, ...) -{ - char *result; - va_list args; - - va_start (args, format); - result = g_markup_vprintf_escaped (format, args); - va_end (args); - - return result; -} - -static gboolean -g_markup_parse_boolean (const char *string, - gboolean *value) -{ - char const * const falses[] = { "false", "f", "no", "n", "0" }; - char const * const trues[] = { "true", "t", "yes", "y", "1" }; - int i; - - for (i = 0; i < G_N_ELEMENTS (falses); i++) - { - if (g_ascii_strcasecmp (string, falses[i]) == 0) - { - if (value != NULL) - *value = FALSE; - - return TRUE; - } - } - - for (i = 0; i < G_N_ELEMENTS (trues); i++) - { - if (g_ascii_strcasecmp (string, trues[i]) == 0) - { - if (value != NULL) - *value = TRUE; - - return TRUE; - } - } - - return FALSE; -} - -/** - * GMarkupCollectType: - * @G_MARKUP_COLLECT_INVALID: used to terminate the list of attributes - * to collect. - * @G_MARKUP_COLLECT_STRING: collect the string pointer directly from - * the attribute_values[] array. Expects a - * parameter of type (const char **). If - * %G_MARKUP_COLLECT_OPTIONAL is specified - * and the attribute isn't present then the - * pointer will be set to %NULL. - * @G_MARKUP_COLLECT_STRDUP: as with %G_MARKUP_COLLECT_STRING, but - * expects a paramter of type (char **) and - * g_strdup()s the returned pointer. The - * pointer must be freed with g_free(). - * @G_MARKUP_COLLECT_BOOLEAN: expects a parameter of type (gboolean *) - * and parses the attribute value as a - * boolean. Sets %FALSE if the attribute - * isn't present. Valid boolean values - * consist of (case insensitive) "false", - * "f", "no", "n", "0" and "true", "t", - * "yes", "y", "1". - * @G_MARKUP_COLLECT_TRISTATE: as with %G_MARKUP_COLLECT_BOOLEAN, but - * in the case of a missing attribute a - * value is set that compares equal to - * neither %FALSE nor %TRUE. - * G_MARKUP_COLLECT_OPTIONAL is implied. - * @G_MARKUP_COLLECT_OPTIONAL: can be bitwise ORed with the other - * fields. If present, allows the - * attribute not to appear. A default - * value is set depending on what value - * type is used. - * - * A mixed enumerated type and flags field. You must specify one type - * (string, strdup, boolean, tristate). Additionally, you may - * optionally bitwise OR the type with the flag - * %G_MARKUP_COLLECT_OPTIONAL. - * - * It is likely that this enum will be extended in the future to - * support other types. - **/ - -/** - * g_markup_collect_attributes: - * @element_name: the current tag name - * @attribute_names: the attribute names - * @attribute_values: the attribute values - * @error: a pointer to a #GError or %NULL - * @first_type: the #GMarkupCollectType of the - * first attribute - * @first_attr: the name of the first attribute - * @...: a pointer to the storage location of the - * first attribute (or %NULL), followed by - * more types names and pointers, ending - * with %G_MARKUP_COLLECT_INVALID. - * - * Collects the attributes of the element from the - * data passed to the #GMarkupParser start_element - * function, dealing with common error conditions - * and supporting boolean values. - * - * This utility function is not required to write - * a parser but can save a lot of typing. - * - * The @element_name, @attribute_names, - * @attribute_values and @error parameters passed - * to the start_element callback should be passed - * unmodified to this function. - * - * Following these arguments is a list of - * "supported" attributes to collect. It is an - * error to specify multiple attributes with the - * same name. If any attribute not in the list - * appears in the @attribute_names array then an - * unknown attribute error will result. - * - * The #GMarkupCollectType field allows specifying - * the type of collection to perform and if a - * given attribute must appear or is optional. - * - * The attribute name is simply the name of the - * attribute to collect. - * - * The pointer should be of the appropriate type - * (see the descriptions under - * #GMarkupCollectType) and may be %NULL in case a - * particular attribute is to be allowed but - * ignored. - * - * This function deals with issuing errors for missing attributes - * (of type %G_MARKUP_ERROR_MISSING_ATTRIBUTE), unknown attributes - * (of type %G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE) and duplicate - * attributes (of type %G_MARKUP_ERROR_INVALID_CONTENT) as well - * as parse errors for boolean-valued attributes (again of type - * %G_MARKUP_ERROR_INVALID_CONTENT). In all of these cases %FALSE - * will be returned and @error will be set as appropriate. - * - * Return value: %TRUE if successful - * - * Since: 2.16 - **/ -gboolean -g_markup_collect_attributes (const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - GError **error, - GMarkupCollectType first_type, - const gchar *first_attr, - ...) -{ - GMarkupCollectType type; - const gchar *attr; - guint64 collected; - int written; - va_list ap; - int i; - - type = first_type; - attr = first_attr; - collected = 0; - written = 0; - - va_start (ap, first_attr); - while (type != G_MARKUP_COLLECT_INVALID) - { - gboolean mandatory; - const gchar *value; - - mandatory = !(type & G_MARKUP_COLLECT_OPTIONAL); - type &= (G_MARKUP_COLLECT_OPTIONAL - 1); - - /* tristate records a value != TRUE and != FALSE - * for the case where the attribute is missing - */ - if (type == G_MARKUP_COLLECT_TRISTATE) - mandatory = FALSE; - - for (i = 0; attribute_names[i]; i++) - if (i >= 40 || !(collected & (G_GUINT64_CONSTANT(1) << i))) - if (!strcmp (attribute_names[i], attr)) - break; - - /* ISO C99 only promises that the user can pass up to 127 arguments. - * Subtracting the first 4 arguments plus the final NULL and dividing - * by 3 arguments per collected attribute, we are left with a maximum - * number of supported attributes of (127 - 5) / 3 = 40. - * - * In reality, nobody is ever going to call us with anywhere close to - * 40 attributes to collect, so it is safe to assume that if i > 40 - * then the user has given some invalid or repeated arguments. These - * problems will be caught and reported at the end of the function. - * - * We know at this point that we have an error, but we don't know - * what error it is, so just continue... - */ - if (i < 40) - collected |= (G_GUINT64_CONSTANT(1) << i); - - value = attribute_values[i]; - - if (value == NULL && mandatory) - { - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_MISSING_ATTRIBUTE, - "element '%s' requires attribute '%s'", - element_name, attr); - - va_end (ap); - goto failure; - } - - switch (type) - { - case G_MARKUP_COLLECT_STRING: - { - const char **str_ptr; - - str_ptr = va_arg (ap, const char **); - - if (str_ptr != NULL) - *str_ptr = value; - } - break; - - case G_MARKUP_COLLECT_STRDUP: - { - char **str_ptr; - - str_ptr = va_arg (ap, char **); - - if (str_ptr != NULL) - *str_ptr = g_strdup (value); - } - break; - - case G_MARKUP_COLLECT_BOOLEAN: - case G_MARKUP_COLLECT_TRISTATE: - if (value == NULL) - { - gboolean *bool_ptr; - - bool_ptr = va_arg (ap, gboolean *); - - if (bool_ptr != NULL) - { - if (type == G_MARKUP_COLLECT_TRISTATE) - /* constructivists rejoice! - * neither false nor true... - */ - *bool_ptr = -1; - - else /* G_MARKUP_COLLECT_BOOLEAN */ - *bool_ptr = FALSE; - } - } - else - { - if (!g_markup_parse_boolean (value, va_arg (ap, gboolean *))) - { - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - "element '%s', attribute '%s', value '%s' " - "cannot be parsed as a boolean value", - element_name, attr, value); - - va_end (ap); - goto failure; - } - } - - break; - - default: - g_assert_not_reached (); - } - - type = va_arg (ap, GMarkupCollectType); - attr = va_arg (ap, const char *); - written++; - } - va_end (ap); - - /* ensure we collected all the arguments */ - for (i = 0; attribute_names[i]; i++) - if ((collected & (G_GUINT64_CONSTANT(1) << i)) == 0) - { - /* attribute not collected: could be caused by two things. - * - * 1) it doesn't exist in our list of attributes - * 2) it existed but was matched by a duplicate attribute earlier - * - * find out. - */ - int j; - - for (j = 0; j < i; j++) - if (strcmp (attribute_names[i], attribute_names[j]) == 0) - /* duplicate! */ - break; - - /* j is now the first occurrence of attribute_names[i] */ - if (i == j) - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, - "attribute '%s' invalid for element '%s'", - attribute_names[i], element_name); - else - g_set_error (error, G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - "attribute '%s' given multiple times for element '%s'", - attribute_names[i], element_name); - - goto failure; - } - - return TRUE; - -failure: - /* replay the above to free allocations */ - type = first_type; - attr = first_attr; - - va_start (ap, first_attr); - while (type != G_MARKUP_COLLECT_INVALID) - { - gpointer ptr; - - ptr = va_arg (ap, gpointer); - - if (ptr == NULL) - continue; - - switch (type & (G_MARKUP_COLLECT_OPTIONAL - 1)) - { - case G_MARKUP_COLLECT_STRDUP: - if (written) - g_free (*(char **) ptr); - - case G_MARKUP_COLLECT_STRING: - *(char **) ptr = NULL; - break; - - case G_MARKUP_COLLECT_BOOLEAN: - *(gboolean *) ptr = FALSE; - break; - - case G_MARKUP_COLLECT_TRISTATE: - *(gboolean *) ptr = -1; - break; - } - - type = va_arg (ap, GMarkupCollectType); - attr = va_arg (ap, const char *); - - if (written) - written--; - } - va_end (ap); - - return FALSE; -} - -#define __G_MARKUP_C__ -#include "galiasdef.c" diff --git a/glib/gnode.c b/glib/gnode.c deleted file mode 100644 index 142eadeed..000000000 --- a/glib/gnode.c +++ /dev/null @@ -1,1165 +0,0 @@ -/* GLIB - Library of useful routines for C programming - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * GNode: N-way tree implementation. - * Copyright (C) 1998 Tim Janik - * - * 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, 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" - -#include "glib.h" -#include "galias.h" - -void g_node_push_allocator (gpointer dummy) { /* present for binary compat only */ } -void g_node_pop_allocator (void) { /* present for binary compat only */ } - -#define g_node_alloc0() g_slice_new0 (GNode) -#define g_node_free(node) g_slice_free (GNode, node) - -/* --- functions --- */ -/** - * g_node_new: - * @data: the data of the new node - * - * Creates a new #GNode containing the given data. - * Used to create the first node in a tree. - * - * Returns: a new #GNode - */ -GNode* -g_node_new (gpointer data) -{ - GNode *node = g_node_alloc0 (); - node->data = data; - return node; -} - -static void -g_nodes_free (GNode *node) -{ - while (node) - { - GNode *next = node->next; - if (node->children) - g_nodes_free (node->children); - g_node_free (node); - node = next; - } -} - -/** - * g_node_destroy: - * @root: the root of the tree/subtree to destroy - * - * Removes @root and its children from the tree, freeing any memory - * allocated. - */ -void -g_node_destroy (GNode *root) -{ - g_return_if_fail (root != NULL); - - if (!G_NODE_IS_ROOT (root)) - g_node_unlink (root); - - g_nodes_free (root); -} - -/** - * g_node_unlink: - * @node: the #GNode to unlink, which becomes the root of a new tree - * - * Unlinks a #GNode from a tree, resulting in two separate trees. - */ -void -g_node_unlink (GNode *node) -{ - g_return_if_fail (node != NULL); - - if (node->prev) - node->prev->next = node->next; - else if (node->parent) - node->parent->children = node->next; - node->parent = NULL; - if (node->next) - { - node->next->prev = node->prev; - node->next = NULL; - } - node->prev = NULL; -} - -/** - * g_node_copy_deep: - * @node: a #GNode - * @copy_func: the function which is called to copy the data inside each node, - * or %NULL to use the original data. - * @data: data to pass to @copy_func - * - * Recursively copies a #GNode and its data. - * - * Return value: a new #GNode containing copies of the data in @node. - * - * Since: 2.4 - **/ -GNode* -g_node_copy_deep (GNode *node, - GCopyFunc copy_func, - gpointer data) -{ - GNode *new_node = NULL; - - if (copy_func == NULL) - return g_node_copy (node); - - if (node) - { - GNode *child, *new_child; - - new_node = g_node_new (copy_func (node->data, data)); - - for (child = g_node_last_child (node); child; child = child->prev) - { - new_child = g_node_copy_deep (child, copy_func, data); - g_node_prepend (new_node, new_child); - } - } - - return new_node; -} - -/** - * g_node_copy: - * @node: a #GNode - * - * Recursively copies a #GNode (but does not deep-copy the data inside the - * nodes, see g_node_copy_deep() if you need that). - * - * Returns: a new #GNode containing the same data pointers - */ -GNode* -g_node_copy (GNode *node) -{ - GNode *new_node = NULL; - - if (node) - { - GNode *child; - - new_node = g_node_new (node->data); - - for (child = g_node_last_child (node); child; child = child->prev) - g_node_prepend (new_node, g_node_copy (child)); - } - - return new_node; -} - -/** - * g_node_insert: - * @parent: the #GNode to place @node under - * @position: the position to place @node at, with respect to its siblings - * If position is -1, @node is inserted as the last child of @parent - * @node: the #GNode to insert - * - * Inserts a #GNode beneath the parent at the given position. - * - * Returns: the inserted #GNode - */ -GNode* -g_node_insert (GNode *parent, - gint position, - GNode *node) -{ - g_return_val_if_fail (parent != NULL, node); - g_return_val_if_fail (node != NULL, node); - g_return_val_if_fail (G_NODE_IS_ROOT (node), node); - - if (position > 0) - return g_node_insert_before (parent, - g_node_nth_child (parent, position), - node); - else if (position == 0) - return g_node_prepend (parent, node); - else /* if (position < 0) */ - return g_node_append (parent, node); -} - -/** - * g_node_insert_before: - * @parent: the #GNode to place @node under - * @sibling: the sibling #GNode to place @node before. - * If sibling is %NULL, the node is inserted as the last child of @parent. - * @node: the #GNode to insert - * - * Inserts a #GNode beneath the parent before the given sibling. - * - * Returns: the inserted #GNode - */ -GNode* -g_node_insert_before (GNode *parent, - GNode *sibling, - GNode *node) -{ - g_return_val_if_fail (parent != NULL, node); - g_return_val_if_fail (node != NULL, node); - g_return_val_if_fail (G_NODE_IS_ROOT (node), node); - if (sibling) - g_return_val_if_fail (sibling->parent == parent, node); - - node->parent = parent; - - if (sibling) - { - if (sibling->prev) - { - node->prev = sibling->prev; - node->prev->next = node; - node->next = sibling; - sibling->prev = node; - } - else - { - node->parent->children = node; - node->next = sibling; - sibling->prev = node; - } - } - else - { - if (parent->children) - { - sibling = parent->children; - while (sibling->next) - sibling = sibling->next; - node->prev = sibling; - sibling->next = node; - } - else - node->parent->children = node; - } - - return node; -} - -/** - * g_node_insert_after: - * @parent: the #GNode to place @node under - * @sibling: the sibling #GNode to place @node after. - * If sibling is %NULL, the node is inserted as the first child of @parent. - * @node: the #GNode to insert - * - * Inserts a #GNode beneath the parent after the given sibling. - * - * Returns: the inserted #GNode - */ -GNode* -g_node_insert_after (GNode *parent, - GNode *sibling, - GNode *node) -{ - g_return_val_if_fail (parent != NULL, node); - g_return_val_if_fail (node != NULL, node); - g_return_val_if_fail (G_NODE_IS_ROOT (node), node); - if (sibling) - g_return_val_if_fail (sibling->parent == parent, node); - - node->parent = parent; - - if (sibling) - { - if (sibling->next) - { - sibling->next->prev = node; - } - node->next = sibling->next; - node->prev = sibling; - sibling->next = node; - } - else - { - if (parent->children) - { - node->next = parent->children; - parent->children->prev = node; - } - parent->children = node; - } - - return node; -} - -/** - * g_node_prepend: - * @parent: the #GNode to place the new #GNode under - * @node: the #GNode to insert - * - * Inserts a #GNode as the first child of the given parent. - * - * Returns: the inserted #GNode - */ -GNode* -g_node_prepend (GNode *parent, - GNode *node) -{ - g_return_val_if_fail (parent != NULL, node); - - return g_node_insert_before (parent, parent->children, node); -} - -/** - * g_node_get_root: - * @node: a #GNode - * - * Gets the root of a tree. - * - * Returns: the root of the tree - */ -GNode* -g_node_get_root (GNode *node) -{ - g_return_val_if_fail (node != NULL, NULL); - - while (node->parent) - node = node->parent; - - return node; -} - -/** - * g_node_is_ancestor: - * @node: a #GNode - * @descendant: a #GNode - * - * Returns %TRUE if @node is an ancestor of @descendant. - * This is true if node is the parent of @descendant, - * or if node is the grandparent of @descendant etc. - * - * Returns: %TRUE if @node is an ancestor of @descendant - */ -gboolean -g_node_is_ancestor (GNode *node, - GNode *descendant) -{ - g_return_val_if_fail (node != NULL, FALSE); - g_return_val_if_fail (descendant != NULL, FALSE); - - while (descendant) - { - if (descendant->parent == node) - return TRUE; - - descendant = descendant->parent; - } - - return FALSE; -} - -/** - * g_node_depth: - * @node: a #GNode - * - * Gets the depth of a #GNode. - * - * If @node is %NULL the depth is 0. The root node has a depth of 1. - * For the children of the root node the depth is 2. And so on. - * - * Returns: the depth of the #GNode - */ -guint -g_node_depth (GNode *node) -{ - guint depth = 0; - - while (node) - { - depth++; - node = node->parent; - } - - return depth; -} - -/** - * g_node_reverse_children: - * @node: a #GNode. - * - * Reverses the order of the children of a #GNode. - * (It doesn't change the order of the grandchildren.) - */ -void -g_node_reverse_children (GNode *node) -{ - GNode *child; - GNode *last; - - g_return_if_fail (node != NULL); - - child = node->children; - last = NULL; - while (child) - { - last = child; - child = last->next; - last->next = last->prev; - last->prev = child; - } - node->children = last; -} - -/** - * g_node_max_height: - * @root: a #GNode - * - * Gets the maximum height of all branches beneath a #GNode. - * This is the maximum distance from the #GNode to all leaf nodes. - * - * If @root is %NULL, 0 is returned. If @root has no children, - * 1 is returned. If @root has children, 2 is returned. And so on. - * - * Returns: the maximum height of the tree beneath @root - */ -guint -g_node_max_height (GNode *root) -{ - GNode *child; - guint max_height = 0; - - if (!root) - return 0; - - child = root->children; - while (child) - { - guint tmp_height; - - tmp_height = g_node_max_height (child); - if (tmp_height > max_height) - max_height = tmp_height; - child = child->next; - } - - return max_height + 1; -} - -static gboolean -g_node_traverse_pre_order (GNode *node, - GTraverseFlags flags, - GNodeTraverseFunc func, - gpointer data) -{ - if (node->children) - { - GNode *child; - - if ((flags & G_TRAVERSE_NON_LEAFS) && - func (node, data)) - return TRUE; - - child = node->children; - while (child) - { - GNode *current; - - current = child; - child = current->next; - if (g_node_traverse_pre_order (current, flags, func, data)) - return TRUE; - } - } - else if ((flags & G_TRAVERSE_LEAFS) && - func (node, data)) - return TRUE; - - return FALSE; -} - -static gboolean -g_node_depth_traverse_pre_order (GNode *node, - GTraverseFlags flags, - guint depth, - GNodeTraverseFunc func, - gpointer data) -{ - if (node->children) - { - GNode *child; - - if ((flags & G_TRAVERSE_NON_LEAFS) && - func (node, data)) - return TRUE; - - depth--; - if (!depth) - return FALSE; - - child = node->children; - while (child) - { - GNode *current; - - current = child; - child = current->next; - if (g_node_depth_traverse_pre_order (current, flags, depth, func, data)) - return TRUE; - } - } - else if ((flags & G_TRAVERSE_LEAFS) && - func (node, data)) - return TRUE; - - return FALSE; -} - -static gboolean -g_node_traverse_post_order (GNode *node, - GTraverseFlags flags, - GNodeTraverseFunc func, - gpointer data) -{ - if (node->children) - { - GNode *child; - - child = node->children; - while (child) - { - GNode *current; - - current = child; - child = current->next; - if (g_node_traverse_post_order (current, flags, func, data)) - return TRUE; - } - - if ((flags & G_TRAVERSE_NON_LEAFS) && - func (node, data)) - return TRUE; - - } - else if ((flags & G_TRAVERSE_LEAFS) && - func (node, data)) - return TRUE; - - return FALSE; -} - -static gboolean -g_node_depth_traverse_post_order (GNode *node, - GTraverseFlags flags, - guint depth, - GNodeTraverseFunc func, - gpointer data) -{ - if (node->children) - { - depth--; - if (depth) - { - GNode *child; - - child = node->children; - while (child) - { - GNode *current; - - current = child; - child = current->next; - if (g_node_depth_traverse_post_order (current, flags, depth, func, data)) - return TRUE; - } - } - - if ((flags & G_TRAVERSE_NON_LEAFS) && - func (node, data)) - return TRUE; - - } - else if ((flags & G_TRAVERSE_LEAFS) && - func (node, data)) - return TRUE; - - return FALSE; -} - -static gboolean -g_node_traverse_in_order (GNode *node, - GTraverseFlags flags, - GNodeTraverseFunc func, - gpointer data) -{ - if (node->children) - { - GNode *child; - GNode *current; - - child = node->children; - current = child; - child = current->next; - - if (g_node_traverse_in_order (current, flags, func, data)) - return TRUE; - - if ((flags & G_TRAVERSE_NON_LEAFS) && - func (node, data)) - return TRUE; - - while (child) - { - current = child; - child = current->next; - if (g_node_traverse_in_order (current, flags, func, data)) - return TRUE; - } - } - else if ((flags & G_TRAVERSE_LEAFS) && - func (node, data)) - return TRUE; - - return FALSE; -} - -static gboolean -g_node_depth_traverse_in_order (GNode *node, - GTraverseFlags flags, - guint depth, - GNodeTraverseFunc func, - gpointer data) -{ - if (node->children) - { - depth--; - if (depth) - { - GNode *child; - GNode *current; - - child = node->children; - current = child; - child = current->next; - - if (g_node_depth_traverse_in_order (current, flags, depth, func, data)) - return TRUE; - - if ((flags & G_TRAVERSE_NON_LEAFS) && - func (node, data)) - return TRUE; - - while (child) - { - current = child; - child = current->next; - if (g_node_depth_traverse_in_order (current, flags, depth, func, data)) - return TRUE; - } - } - else if ((flags & G_TRAVERSE_NON_LEAFS) && - func (node, data)) - return TRUE; - } - else if ((flags & G_TRAVERSE_LEAFS) && - func (node, data)) - return TRUE; - - return FALSE; -} - -static gboolean -g_node_traverse_level (GNode *node, - GTraverseFlags flags, - guint level, - GNodeTraverseFunc func, - gpointer data, - gboolean *more_levels) -{ - if (level == 0) - { - if (node->children) - { - *more_levels = TRUE; - return (flags & G_TRAVERSE_NON_LEAFS) && func (node, data); - } - else - { - return (flags & G_TRAVERSE_LEAFS) && func (node, data); - } - } - else - { - node = node->children; - - while (node) - { - if (g_node_traverse_level (node, flags, level - 1, func, data, more_levels)) - return TRUE; - - node = node->next; - } - } - - return FALSE; -} - -static gboolean -g_node_depth_traverse_level (GNode *node, - GTraverseFlags flags, - guint depth, - GNodeTraverseFunc func, - gpointer data) -{ - guint level; - gboolean more_levels; - - level = 0; - while (level != depth) - { - more_levels = FALSE; - if (g_node_traverse_level (node, flags, level, func, data, &more_levels)) - return TRUE; - if (!more_levels) - break; - level++; - } - return FALSE; -} - -/** - * g_node_traverse: - * @root: the root #GNode of the tree to traverse - * @order: the order in which nodes are visited - %G_IN_ORDER, - * %G_PRE_ORDER, %G_POST_ORDER, or %G_LEVEL_ORDER. - * @flags: which types of children are to be visited, one of - * %G_TRAVERSE_ALL, %G_TRAVERSE_LEAVES and %G_TRAVERSE_NON_LEAVES - * @max_depth: the maximum depth of the traversal. Nodes below this - * depth will not be visited. If max_depth is -1 all nodes in - * the tree are visited. If depth is 1, only the root is visited. - * If depth is 2, the root and its children are visited. And so on. - * @func: the function to call for each visited #GNode - * @data: user data to pass to the function - * - * Traverses a tree starting at the given root #GNode. - * It calls the given function for each node visited. - * The traversal can be halted at any point by returning %TRUE from @func. - */ -void -g_node_traverse (GNode *root, - GTraverseType order, - GTraverseFlags flags, - gint depth, - GNodeTraverseFunc func, - gpointer data) -{ - g_return_if_fail (root != NULL); - g_return_if_fail (func != NULL); - g_return_if_fail (order <= G_LEVEL_ORDER); - g_return_if_fail (flags <= G_TRAVERSE_MASK); - g_return_if_fail (depth == -1 || depth > 0); - - switch (order) - { - case G_PRE_ORDER: - if (depth < 0) - g_node_traverse_pre_order (root, flags, func, data); - else - g_node_depth_traverse_pre_order (root, flags, depth, func, data); - break; - case G_POST_ORDER: - if (depth < 0) - g_node_traverse_post_order (root, flags, func, data); - else - g_node_depth_traverse_post_order (root, flags, depth, func, data); - break; - case G_IN_ORDER: - if (depth < 0) - g_node_traverse_in_order (root, flags, func, data); - else - g_node_depth_traverse_in_order (root, flags, depth, func, data); - break; - case G_LEVEL_ORDER: - g_node_depth_traverse_level (root, flags, depth, func, data); - break; - } -} - -static gboolean -g_node_find_func (GNode *node, - gpointer data) -{ - gpointer *d = data; - - if (*d != node->data) - return FALSE; - - *(++d) = node; - - return TRUE; -} - -/** - * g_node_find: - * @root: the root #GNode of the tree to search - * @order: the order in which nodes are visited - %G_IN_ORDER, - * %G_PRE_ORDER, %G_POST_ORDER, or %G_LEVEL_ORDER - * @flags: which types of children are to be searched, one of - * %G_TRAVERSE_ALL, %G_TRAVERSE_LEAVES and %G_TRAVERSE_NON_LEAVES - * @data: the data to find - * - * Finds a #GNode in a tree. - * - * Returns: the found #GNode, or %NULL if the data is not found - */ -GNode* -g_node_find (GNode *root, - GTraverseType order, - GTraverseFlags flags, - gpointer data) -{ - gpointer d[2]; - - g_return_val_if_fail (root != NULL, NULL); - g_return_val_if_fail (order <= G_LEVEL_ORDER, NULL); - g_return_val_if_fail (flags <= G_TRAVERSE_MASK, NULL); - - d[0] = data; - d[1] = NULL; - - g_node_traverse (root, order, flags, -1, g_node_find_func, d); - - return d[1]; -} - -static void -g_node_count_func (GNode *node, - GTraverseFlags flags, - guint *n) -{ - if (node->children) - { - GNode *child; - - if (flags & G_TRAVERSE_NON_LEAFS) - (*n)++; - - child = node->children; - while (child) - { - g_node_count_func (child, flags, n); - child = child->next; - } - } - else if (flags & G_TRAVERSE_LEAFS) - (*n)++; -} - -/** - * g_node_n_nodes: - * @root: a #GNode - * @flags: which types of children are to be counted, one of - * %G_TRAVERSE_ALL, %G_TRAVERSE_LEAVES and %G_TRAVERSE_NON_LEAVES - * - * Gets the number of nodes in a tree. - * - * Returns: the number of nodes in the tree - */ -guint -g_node_n_nodes (GNode *root, - GTraverseFlags flags) -{ - guint n = 0; - - g_return_val_if_fail (root != NULL, 0); - g_return_val_if_fail (flags <= G_TRAVERSE_MASK, 0); - - g_node_count_func (root, flags, &n); - - return n; -} - -/** - * g_node_last_child: - * @node: a #GNode (must not be %NULL) - * - * Gets the last child of a #GNode. - * - * Returns: the last child of @node, or %NULL if @node has no children - */ -GNode* -g_node_last_child (GNode *node) -{ - g_return_val_if_fail (node != NULL, NULL); - - node = node->children; - if (node) - while (node->next) - node = node->next; - - return node; -} - -/** - * g_node_nth_child: - * @node: a #GNode - * @n: the index of the desired child - * - * Gets a child of a #GNode, using the given index. - * The first child is at index 0. If the index is - * too big, %NULL is returned. - * - * Returns: the child of @node at index @n - */ -GNode* -g_node_nth_child (GNode *node, - guint n) -{ - g_return_val_if_fail (node != NULL, NULL); - - node = node->children; - if (node) - while ((n-- > 0) && node) - node = node->next; - - return node; -} - -/** - * g_node_n_children: - * @node: a #GNode - * - * Gets the number of children of a #GNode. - * - * Returns: the number of children of @node - */ -guint -g_node_n_children (GNode *node) -{ - guint n = 0; - - g_return_val_if_fail (node != NULL, 0); - - node = node->children; - while (node) - { - n++; - node = node->next; - } - - return n; -} - -/** - * g_node_find_child: - * @node: a #GNode - * @flags: which types of children are to be searched, one of - * %G_TRAVERSE_ALL, %G_TRAVERSE_LEAVES and %G_TRAVERSE_NON_LEAVES - * @data: the data to find - * - * Finds the first child of a #GNode with the given data. - * - * Returns: the found child #GNode, or %NULL if the data is not found - */ -GNode* -g_node_find_child (GNode *node, - GTraverseFlags flags, - gpointer data) -{ - g_return_val_if_fail (node != NULL, NULL); - g_return_val_if_fail (flags <= G_TRAVERSE_MASK, NULL); - - node = node->children; - while (node) - { - if (node->data == data) - { - if (G_NODE_IS_LEAF (node)) - { - if (flags & G_TRAVERSE_LEAFS) - return node; - } - else - { - if (flags & G_TRAVERSE_NON_LEAFS) - return node; - } - } - node = node->next; - } - - return NULL; -} - -/** - * g_node_child_position: - * @node: a #GNode - * @child: a child of @node - * - * Gets the position of a #GNode with respect to its siblings. - * @child must be a child of @node. The first child is numbered 0, - * the second 1, and so on. - * - * Returns: the position of @child with respect to its siblings - */ -gint -g_node_child_position (GNode *node, - GNode *child) -{ - guint n = 0; - - g_return_val_if_fail (node != NULL, -1); - g_return_val_if_fail (child != NULL, -1); - g_return_val_if_fail (child->parent == node, -1); - - node = node->children; - while (node) - { - if (node == child) - return n; - n++; - node = node->next; - } - - return -1; -} - -/** - * g_node_child_index: - * @node: a #GNode - * @data: the data to find - * - * Gets the position of the first child of a #GNode - * which contains the given data. - * - * Returns: the index of the child of @node which contains - * @data, or -1 if the data is not found - */ -gint -g_node_child_index (GNode *node, - gpointer data) -{ - guint n = 0; - - g_return_val_if_fail (node != NULL, -1); - - node = node->children; - while (node) - { - if (node->data == data) - return n; - n++; - node = node->next; - } - - return -1; -} - -/** - * g_node_first_sibling: - * @node: a #GNode - * - * Gets the first sibling of a #GNode. - * This could possibly be the node itself. - * - * Returns: the first sibling of @node - */ -GNode* -g_node_first_sibling (GNode *node) -{ - g_return_val_if_fail (node != NULL, NULL); - - if (node->parent) - return node->parent->children; - - while (node->prev) - node = node->prev; - - return node; -} - -/** - * g_node_last_sibling: - * @node: a #GNode - * - * Gets the last sibling of a #GNode. - * This could possibly be the node itself. - * - * Returns: the last sibling of @node - */ -GNode* -g_node_last_sibling (GNode *node) -{ - g_return_val_if_fail (node != NULL, NULL); - - while (node->next) - node = node->next; - - return node; -} - -/** - * g_node_children_foreach: - * @node: a #GNode - * @flags: which types of children are to be visited, one of - * %G_TRAVERSE_ALL, %G_TRAVERSE_LEAVES and %G_TRAVERSE_NON_LEAVES - * @func: the function to call for each visited node - * @data: user data to pass to the function - * - * Calls a function for each of the children of a #GNode. - * Note that it doesn't descend beneath the child nodes. - */ -void -g_node_children_foreach (GNode *node, - GTraverseFlags flags, - GNodeForeachFunc func, - gpointer data) -{ - g_return_if_fail (node != NULL); - g_return_if_fail (flags <= G_TRAVERSE_MASK); - g_return_if_fail (func != NULL); - - node = node->children; - while (node) - { - GNode *current; - - current = node; - node = current->next; - if (G_NODE_IS_LEAF (current)) - { - if (flags & G_TRAVERSE_LEAFS) - func (current, data); - } - else - { - if (flags & G_TRAVERSE_NON_LEAFS) - func (current, data); - } - } -} - -#define __G_NODE_C__ -#include "galiasdef.c" diff --git a/glib/gprimes.c b/glib/gprimes.c deleted file mode 100644 index 7beca710c..000000000 --- a/glib/gprimes.c +++ /dev/null @@ -1,90 +0,0 @@ -/* 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, 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" - -#include "glib.h" -#include "galias.h" - - -static const guint g_primes[] = -{ - 11, - 19, - 37, - 73, - 109, - 163, - 251, - 367, - 557, - 823, - 1237, - 1861, - 2777, - 4177, - 6247, - 9371, - 14057, - 21089, - 31627, - 47431, - 71143, - 106721, - 160073, - 240101, - 360163, - 540217, - 810343, - 1215497, - 1823231, - 2734867, - 4102283, - 6153409, - 9230113, - 13845163, -}; - -static const guint g_nprimes = sizeof (g_primes) / sizeof (g_primes[0]); - -guint -g_spaced_primes_closest (guint num) -{ - gint i; - - for (i = 0; i < g_nprimes; i++) - if (g_primes[i] > num) - return g_primes[i]; - - return g_primes[g_nprimes - 1]; -} - -#define __G_PRIMES_C__ -#include "galiasdef.c" diff --git a/glib/gqueue.c b/glib/gqueue.c deleted file mode 100644 index 1368e2614..000000000 --- a/glib/gqueue.c +++ /dev/null @@ -1,1013 +0,0 @@ -/* GLIB - Library of useful routines for C programming - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * GQueue: Double ended queue implementation, piggy backed on GList. - * Copyright (C) 1998 Tim Janik - * - * 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * MT safe - */ - -#include "config.h" - -#include "glib.h" -#include "galias.h" - -/** - * g_queue_new: - * - * Creates a new #GQueue. - * - * Returns: a new #GQueue. - **/ -GQueue* -g_queue_new (void) -{ - return g_slice_new0 (GQueue); -} - -/** - * g_queue_free: - * @queue: a #GQueue. - * - * Frees the memory allocated for the #GQueue. Only call this function if - * @queue was created with g_queue_new(). If queue elements contain - * dynamically-allocated memory, they should be freed first. - **/ -void -g_queue_free (GQueue *queue) -{ - g_return_if_fail (queue != NULL); - - g_list_free (queue->head); - g_slice_free (GQueue, queue); -} - -/** - * g_queue_init: - * @queue: an uninitialized #GQueue - * - * A statically-allocated #GQueue must be initialized with this function - * before it can be used. Alternatively you can initialize it with - * #G_QUEUE_INIT. It is not necessary to initialize queues created with - * g_queue_new(). - * - * Since: 2.14 - **/ -void -g_queue_init (GQueue *queue) -{ - g_return_if_fail (queue != NULL); - - queue->head = queue->tail = NULL; - queue->length = 0; -} - -/** - * g_queue_clear: - * @queue: a #GQueue - * - * Removes all the elements in @queue. If queue elements contain - * dynamically-allocated memory, they should be freed first. - * - * Since: 2.14 - */ -void -g_queue_clear (GQueue *queue) -{ - g_return_if_fail (queue != NULL); - - g_list_free (queue->head); - g_queue_init (queue); -} - -/** - * g_queue_is_empty: - * @queue: a #GQueue. - * - * Returns %TRUE if the queue is empty. - * - * Returns: %TRUE if the queue is empty. - **/ -gboolean -g_queue_is_empty (GQueue *queue) -{ - g_return_val_if_fail (queue != NULL, TRUE); - - return queue->head == NULL; -} - -/** - * g_queue_get_length: - * @queue: a #GQueue - * - * Returns the number of items in @queue. - * - * Return value: The number of items in @queue. - * - * Since: 2.4 - **/ -guint -g_queue_get_length (GQueue *queue) -{ - g_return_val_if_fail (queue != NULL, 0); - - return queue->length; -} - -/** - * g_queue_reverse: - * @queue: a #GQueue - * - * Reverses the order of the items in @queue. - * - * Since: 2.4 - **/ -void -g_queue_reverse (GQueue *queue) -{ - g_return_if_fail (queue != NULL); - - queue->tail = queue->head; - queue->head = g_list_reverse (queue->head); -} - -/** - * g_queue_copy: - * @queue: a #GQueue - * - * Copies a @queue. Note that is a shallow copy. If the elements in the - * queue consist of pointers to data, the pointers are copied, but the - * actual data is not. - * - * Return value: A copy of @queue - * - * Since: 2.4 - **/ -GQueue * -g_queue_copy (GQueue *queue) -{ - GQueue *result; - GList *list; - - g_return_val_if_fail (queue != NULL, NULL); - - result = g_queue_new (); - - for (list = queue->head; list != NULL; list = list->next) - g_queue_push_tail (result, list->data); - - return result; -} - -/** - * g_queue_foreach: - * @queue: a #GQueue - * @func: the function to call for each element's data - * @user_data: user data to pass to @func - * - * Calls @func for each element in the queue passing @user_data to the - * function. - * - * Since: 2.4 - **/ -void -g_queue_foreach (GQueue *queue, - GFunc func, - gpointer user_data) -{ - GList *list; - - g_return_if_fail (queue != NULL); - g_return_if_fail (func != NULL); - - list = queue->head; - while (list) - { - GList *next = list->next; - func (list->data, user_data); - list = next; - } -} - -/** - * g_queue_find: - * @queue: a #GQueue - * @data: data to find - * - * Finds the first link in @queue which contains @data. - * - * Return value: The first link in @queue which contains @data. - * - * Since: 2.4 - **/ -GList * -g_queue_find (GQueue *queue, - gconstpointer data) -{ - g_return_val_if_fail (queue != NULL, NULL); - - return g_list_find (queue->head, data); -} - -/** - * g_queue_find_custom: - * @queue: a #GQueue - * @data: user data passed to @func - * @func: a #GCompareFunc to call for each element. It should return 0 - * when the desired element is found - * - * Finds an element in a #GQueue, using a supplied function to find the - * desired element. It iterates over the queue, calling the given function - * which should return 0 when the desired element is found. The function - * takes two gconstpointer arguments, the #GQueue element's data as the - * first argument and the given user data as the second argument. - * - * Return value: The found link, or %NULL if it wasn't found - * - * Since: 2.4 - **/ -GList * -g_queue_find_custom (GQueue *queue, - gconstpointer data, - GCompareFunc func) -{ - g_return_val_if_fail (queue != NULL, NULL); - g_return_val_if_fail (func != NULL, NULL); - - return g_list_find_custom (queue->head, data, func); -} - -/** - * g_queue_sort: - * @queue: a #GQueue - * @compare_func: the #GCompareDataFunc used to sort @queue. This function - * is passed two elements of the queue and should return 0 if they are - * equal, a negative value if the first comes before the second, and - * a positive value if the second comes before the first. - * @user_data: user data passed to @compare_func - * - * Sorts @queue using @compare_func. - * - * Since: 2.4 - **/ -void -g_queue_sort (GQueue *queue, - GCompareDataFunc compare_func, - gpointer user_data) -{ - g_return_if_fail (queue != NULL); - g_return_if_fail (compare_func != NULL); - - queue->head = g_list_sort_with_data (queue->head, compare_func, user_data); - queue->tail = g_list_last (queue->head); -} - -/** - * g_queue_push_head: - * @queue: a #GQueue. - * @data: the data for the new element. - * - * Adds a new element at the head of the queue. - **/ -void -g_queue_push_head (GQueue *queue, - gpointer data) -{ - g_return_if_fail (queue != NULL); - - queue->head = g_list_prepend (queue->head, data); - if (!queue->tail) - queue->tail = queue->head; - queue->length++; -} - -/** - * g_queue_push_nth: - * @queue: a #GQueue - * @data: the data for the new element - * @n: the position to insert the new element. If @n is negative or - * larger than the number of elements in the @queue, the element is - * added to the end of the queue. - * - * Inserts a new element into @queue at the given position - * - * Since: 2.4 - **/ -void -g_queue_push_nth (GQueue *queue, - gpointer data, - gint n) -{ - g_return_if_fail (queue != NULL); - - if (n < 0 || n >= queue->length) - { - g_queue_push_tail (queue, data); - return; - } - - g_queue_insert_before (queue, g_queue_peek_nth_link (queue, n), data); -} - -/** - * g_queue_push_head_link: - * @queue: a #GQueue. - * @link_: a single #GList element, <emphasis>not</emphasis> a list with - * more than one element. - * - * Adds a new element at the head of the queue. - **/ -void -g_queue_push_head_link (GQueue *queue, - GList *link) -{ - g_return_if_fail (queue != NULL); - g_return_if_fail (link != NULL); - g_return_if_fail (link->prev == NULL); - g_return_if_fail (link->next == NULL); - - link->next = queue->head; - if (queue->head) - queue->head->prev = link; - else - queue->tail = link; - queue->head = link; - queue->length++; -} - -/** - * g_queue_push_tail: - * @queue: a #GQueue. - * @data: the data for the new element. - * - * Adds a new element at the tail of the queue. - **/ -void -g_queue_push_tail (GQueue *queue, - gpointer data) -{ - g_return_if_fail (queue != NULL); - - queue->tail = g_list_append (queue->tail, data); - if (queue->tail->next) - queue->tail = queue->tail->next; - else - queue->head = queue->tail; - queue->length++; -} - -/** - * g_queue_push_tail_link: - * @queue: a #GQueue. - * @link_: a single #GList element, <emphasis>not</emphasis> a list with - * more than one element. - * - * Adds a new element at the tail of the queue. - **/ -void -g_queue_push_tail_link (GQueue *queue, - GList *link) -{ - g_return_if_fail (queue != NULL); - g_return_if_fail (link != NULL); - g_return_if_fail (link->prev == NULL); - g_return_if_fail (link->next == NULL); - - link->prev = queue->tail; - if (queue->tail) - queue->tail->next = link; - else - queue->head = link; - queue->tail = link; - queue->length++; -} - -/** - * g_queue_push_nth_link: - * @queue: a #GQueue - * @n: the position to insert the link. If this is negative or larger than - * the number of elements in @queue, the link is added to the end of - * @queue. - * @link_: the link to add to @queue - * - * Inserts @link into @queue at the given position. - * - * Since: 2.4 - **/ -void -g_queue_push_nth_link (GQueue *queue, - gint n, - GList *link_) -{ - GList *next; - GList *prev; - - g_return_if_fail (queue != NULL); - g_return_if_fail (link_ != NULL); - - if (n < 0 || n >= queue->length) - { - g_queue_push_tail_link (queue, link_); - return; - } - - g_assert (queue->head); - g_assert (queue->tail); - - next = g_queue_peek_nth_link (queue, n); - prev = next->prev; - - if (prev) - prev->next = link_; - next->prev = link_; - - link_->next = next; - link_->prev = prev; - - if (queue->head->prev) - queue->head = queue->head->prev; - - if (queue->tail->next) - queue->tail = queue->tail->next; - - queue->length++; -} - -/** - * g_queue_pop_head: - * @queue: a #GQueue. - * - * Removes the first element of the queue. - * - * Returns: the data of the first element in the queue, or %NULL if the queue - * is empty. - **/ -gpointer -g_queue_pop_head (GQueue *queue) -{ - g_return_val_if_fail (queue != NULL, NULL); - - if (queue->head) - { - GList *node = queue->head; - gpointer data = node->data; - - queue->head = node->next; - if (queue->head) - queue->head->prev = NULL; - else - queue->tail = NULL; - g_list_free_1 (node); - queue->length--; - - return data; - } - - return NULL; -} - -/** - * g_queue_pop_head_link: - * @queue: a #GQueue. - * - * Removes the first element of the queue. - * - * Returns: the #GList element at the head of the queue, or %NULL if the queue - * is empty. - **/ -GList* -g_queue_pop_head_link (GQueue *queue) -{ - g_return_val_if_fail (queue != NULL, NULL); - - if (queue->head) - { - GList *node = queue->head; - - queue->head = node->next; - if (queue->head) - { - queue->head->prev = NULL; - node->next = NULL; - } - else - queue->tail = NULL; - queue->length--; - - return node; - } - - return NULL; -} - -/** - * g_queue_peek_head_link: - * @queue: a #GQueue - * - * Returns the first link in @queue - * - * Return value: the first link in @queue, or %NULL if @queue is empty - * - * Since: 2.4 - **/ -GList* -g_queue_peek_head_link (GQueue *queue) -{ - g_return_val_if_fail (queue != NULL, NULL); - - return queue->head; -} - -/** - * g_queue_peek_tail_link: - * @queue: a #GQueue - * - * Returns the last link @queue. - * - * Return value: the last link in @queue, or %NULL if @queue is empty - * - * Since: 2.4 - **/ -GList* -g_queue_peek_tail_link (GQueue *queue) -{ - g_return_val_if_fail (queue != NULL, NULL); - - return queue->tail; -} - -/** - * g_queue_pop_tail: - * @queue: a #GQueue. - * - * Removes the last element of the queue. - * - * Returns: the data of the last element in the queue, or %NULL if the queue - * is empty. - **/ -gpointer -g_queue_pop_tail (GQueue *queue) -{ - g_return_val_if_fail (queue != NULL, NULL); - - if (queue->tail) - { - GList *node = queue->tail; - gpointer data = node->data; - - queue->tail = node->prev; - if (queue->tail) - queue->tail->next = NULL; - else - queue->head = NULL; - queue->length--; - g_list_free_1 (node); - - return data; - } - - return NULL; -} - -/** - * g_queue_pop_nth: - * @queue: a #GQueue - * @n: the position of the element. - * - * Removes the @n'th element of @queue. - * - * Return value: the element's data, or %NULL if @n is off the end of @queue. - * - * Since: 2.4 - **/ -gpointer -g_queue_pop_nth (GQueue *queue, - guint n) -{ - GList *nth_link; - gpointer result; - - g_return_val_if_fail (queue != NULL, NULL); - - if (n >= queue->length) - return NULL; - - nth_link = g_queue_peek_nth_link (queue, n); - result = nth_link->data; - - g_queue_delete_link (queue, nth_link); - - return result; -} - -/** - * g_queue_pop_tail_link: - * @queue: a #GQueue. - * - * Removes the last element of the queue. - * - * Returns: the #GList element at the tail of the queue, or %NULL if the queue - * is empty. - **/ -GList* -g_queue_pop_tail_link (GQueue *queue) -{ - g_return_val_if_fail (queue != NULL, NULL); - - if (queue->tail) - { - GList *node = queue->tail; - - queue->tail = node->prev; - if (queue->tail) - { - queue->tail->next = NULL; - node->prev = NULL; - } - else - queue->head = NULL; - queue->length--; - - return node; - } - - return NULL; -} - -/** - * g_queue_pop_nth_link: - * @queue: a #GQueue - * @n: the link's position - * - * Removes and returns the link at the given position. - * - * Return value: The @n'th link, or %NULL if @n is off the end of @queue. - * - * Since: 2.4 - **/ -GList* -g_queue_pop_nth_link (GQueue *queue, - guint n) -{ - GList *link; - - g_return_val_if_fail (queue != NULL, NULL); - - if (n >= queue->length) - return NULL; - - link = g_queue_peek_nth_link (queue, n); - g_queue_unlink (queue, link); - - return link; -} - -/** - * g_queue_peek_nth_link: - * @queue: a #GQueue - * @n: the position of the link - * - * Returns the link at the given position - * - * Return value: The link at the @n'th position, or %NULL if @n is off the - * end of the list - * - * Since: 2.4 - **/ -GList * -g_queue_peek_nth_link (GQueue *queue, - guint n) -{ - GList *link; - gint i; - - g_return_val_if_fail (queue != NULL, NULL); - - if (n >= queue->length) - return NULL; - - if (n > queue->length / 2) - { - n = queue->length - n - 1; - - link = queue->tail; - for (i = 0; i < n; ++i) - link = link->prev; - } - else - { - link = queue->head; - for (i = 0; i < n; ++i) - link = link->next; - } - - return link; -} - -/** - * g_queue_link_index: - * @queue: a #Gqueue - * @link_: A #GList link - * - * Returns the position of @link_ in @queue. - * - * Return value: The position of @link_, or -1 if the link is - * not part of @queue - * - * Since: 2.4 - **/ -gint -g_queue_link_index (GQueue *queue, - GList *link_) -{ - g_return_val_if_fail (queue != NULL, -1); - - return g_list_position (queue->head, link_); -} - -/** - * g_queue_unlink - * @queue: a #GQueue - * @link_: a #GList link that <emphasis>must</emphasis> be part of @queue - * - * Unlinks @link_ so that it will no longer be part of @queue. The link is - * not freed. - * - * @link_ must be part of @queue, - * - * Since: 2.4 - **/ -void -g_queue_unlink (GQueue *queue, - GList *link_) -{ - g_return_if_fail (queue != NULL); - g_return_if_fail (link_ != NULL); - - if (link_ == queue->tail) - queue->tail = queue->tail->prev; - - queue->head = g_list_remove_link (queue->head, link_); - queue->length--; -} - -/** - * g_queue_delete_link: - * @queue: a #GQueue - * @link_: a #GList link that <emphasis>must</emphasis> be part of @queue - * - * Removes @link_ from @queue and frees it. - * - * @link_ must be part of @queue. - * - * Since: 2.4 - **/ -void -g_queue_delete_link (GQueue *queue, - GList *link_) -{ - g_return_if_fail (queue != NULL); - g_return_if_fail (link_ != NULL); - - g_queue_unlink (queue, link_); - g_list_free (link_); -} - -/** - * g_queue_peek_head: - * @queue: a #GQueue. - * - * Returns the first element of the queue. - * - * Returns: the data of the first element in the queue, or %NULL if the queue - * is empty. - **/ -gpointer -g_queue_peek_head (GQueue *queue) -{ - g_return_val_if_fail (queue != NULL, NULL); - - return queue->head ? queue->head->data : NULL; -} - -/** - * g_queue_peek_tail: - * @queue: a #GQueue. - * - * Returns the last element of the queue. - * - * Returns: the data of the last element in the queue, or %NULL if the queue - * is empty. - **/ -gpointer -g_queue_peek_tail (GQueue *queue) -{ - g_return_val_if_fail (queue != NULL, NULL); - - return queue->tail ? queue->tail->data : NULL; -} - -/** - * g_queue_peek_nth: - * @queue: a #GQueue - * @n: the position of the element. - * - * Returns the @n'th element of @queue. - * - * Return value: The data for the @n'th element of @queue, or %NULL if @n is - * off the end of @queue. - * - * Since: 2.4 - **/ -gpointer -g_queue_peek_nth (GQueue *queue, - guint n) -{ - GList *link; - - g_return_val_if_fail (queue != NULL, NULL); - - link = g_queue_peek_nth_link (queue, n); - - if (link) - return link->data; - - return NULL; -} - -/** - * g_queue_index: - * @queue: a #GQueue - * @data: the data to find. - * - * Returns the position of the first element in @queue which contains @data. - * - * Return value: The position of the first element in @queue which contains @data, or -1 if no element in @queue contains @data. - * - * Since: 2.4 - **/ -gint -g_queue_index (GQueue *queue, - gconstpointer data) -{ - g_return_val_if_fail (queue != NULL, -1); - - return g_list_index (queue->head, data); -} - -/** - * g_queue_remove: - * @queue: a #GQueue - * @data: data to remove. - * - * Removes the first element in @queue that contains @data. - * - * Since: 2.4 - **/ -void -g_queue_remove (GQueue *queue, - gconstpointer data) -{ - GList *link; - - g_return_if_fail (queue != NULL); - - link = g_list_find (queue->head, data); - - if (link) - g_queue_delete_link (queue, link); -} - -/** - * g_queue_remove_all: - * @queue: a #GQueue - * @data: data to remove - * - * Remove all elemeents in @queue which contains @data. - * - * Since: 2.4 - **/ -void -g_queue_remove_all (GQueue *queue, - gconstpointer data) -{ - GList *list; - - g_return_if_fail (queue != NULL); - - list = queue->head; - while (list) - { - GList *next = list->next; - - if (list->data == data) - g_queue_delete_link (queue, list); - - list = next; - } -} - -/** - * g_queue_insert_before: - * @queue: a #GQueue - * @sibling: a #GList link that <emphasis>must</emphasis> be part of @queue - * @data: the data to insert - * - * Inserts @data into @queue before @sibling. - * - * @sibling must be part of @queue. - * - * Since: 2.4 - **/ -void -g_queue_insert_before (GQueue *queue, - GList *sibling, - gpointer data) -{ - g_return_if_fail (queue != NULL); - g_return_if_fail (sibling != NULL); - - queue->head = g_list_insert_before (queue->head, sibling, data); - queue->length++; -} - -/** - * g_queue_insert_after: - * @queue: a #GQueue - * @sibling: a #GList link that <emphasis>must</emphasis> be part of @queue - * @data: the data to insert - * - * Inserts @data into @queue after @sibling - * - * @sibling must be part of @queue - * - * Since: 2.4 - **/ -void -g_queue_insert_after (GQueue *queue, - GList *sibling, - gpointer data) -{ - g_return_if_fail (queue != NULL); - g_return_if_fail (sibling != NULL); - - if (sibling == queue->tail) - g_queue_push_tail (queue, data); - else - g_queue_insert_before (queue, sibling->next, data); -} - -/** - * g_queue_insert_sorted: - * @queue: a #GQueue - * @data: the data to insert - * @func: the #GCompareDataFunc used to compare elements in the queue. It is - * called with two elements of the @queue and @user_data. It should - * return 0 if the elements are equal, a negative value if the first - * element comes before the second, and a positive value if the second - * element comes before the first. - * @user_data: user data passed to @func. - * - * Inserts @data into @queue using @func to determine the new position. - * - * Since: 2.4 - **/ -void -g_queue_insert_sorted (GQueue *queue, - gpointer data, - GCompareDataFunc func, - gpointer user_data) -{ - GList *list; - - g_return_if_fail (queue != NULL); - - list = queue->head; - while (list && func (list->data, data, user_data) < 0) - list = list->next; - - if (list) - g_queue_insert_before (queue, list, data); - else - g_queue_push_tail (queue, data); -} - -#define __G_QUEUE_C__ -#include "galiasdef.c" diff --git a/glib/gregex.c b/glib/gregex.c deleted file mode 100644 index 091b418eb..000000000 --- a/glib/gregex.c +++ /dev/null @@ -1,2762 +0,0 @@ -/* GRegex -- regular expression API wrapper around PCRE. - * - * Copyright (C) 1999, 2000 Scott Wimer - * Copyright (C) 2004, Matthias Clasen <mclasen@redhat.com> - * Copyright (C) 2005 - 2007, Marco Barisione <marco@barisione.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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include <string.h> - -#include "glib.h" -#include "glibintl.h" -#include "gregex.h" - -#ifdef USE_SYSTEM_PCRE -#include <pcre.h> -#else -#include "pcre/pcre.h" -#endif - -/* PCRE 7.3 does not contain the definition of PCRE_ERROR_NULLWSLIMIT */ -#ifndef PCRE_ERROR_NULLWSLIMIT -#define PCRE_ERROR_NULLWSLIMIT (-22) -#endif - -#include "galias.h" - -/* Mask of all the possible values for GRegexCompileFlags. */ -#define G_REGEX_COMPILE_MASK (G_REGEX_CASELESS | \ - G_REGEX_MULTILINE | \ - G_REGEX_DOTALL | \ - G_REGEX_EXTENDED | \ - G_REGEX_ANCHORED | \ - G_REGEX_DOLLAR_ENDONLY | \ - G_REGEX_UNGREEDY | \ - G_REGEX_RAW | \ - G_REGEX_NO_AUTO_CAPTURE | \ - G_REGEX_OPTIMIZE | \ - G_REGEX_DUPNAMES | \ - G_REGEX_NEWLINE_CR | \ - G_REGEX_NEWLINE_LF | \ - G_REGEX_NEWLINE_CRLF) - -/* Mask of all the possible values for GRegexMatchFlags. */ -#define G_REGEX_MATCH_MASK (G_REGEX_MATCH_ANCHORED | \ - G_REGEX_MATCH_NOTBOL | \ - G_REGEX_MATCH_NOTEOL | \ - G_REGEX_MATCH_NOTEMPTY | \ - G_REGEX_MATCH_PARTIAL | \ - G_REGEX_MATCH_NEWLINE_CR | \ - G_REGEX_MATCH_NEWLINE_LF | \ - G_REGEX_MATCH_NEWLINE_CRLF | \ - G_REGEX_MATCH_NEWLINE_ANY) - -/* if the string is in UTF-8 use g_utf8_ functions, else use - * use just +/- 1. */ -#define NEXT_CHAR(re, s) (((re)->compile_opts & PCRE_UTF8) ? \ - g_utf8_next_char (s) : \ - ((s) + 1)) -#define PREV_CHAR(re, s) (((re)->compile_opts & PCRE_UTF8) ? \ - g_utf8_prev_char (s) : \ - ((s) - 1)) - -struct _GMatchInfo -{ - GRegex *regex; /* the regex */ - GRegexMatchFlags match_opts; /* options used at match time on the regex */ - gint matches; /* number of matching sub patterns */ - gint pos; /* position in the string where last match left off */ - gint *offsets; /* array of offsets paired 0,1 ; 2,3 ; 3,4 etc */ - gint n_offsets; /* number of offsets */ - gint *workspace; /* workspace for pcre_dfa_exec() */ - gint n_workspace; /* number of workspace elements */ - const gchar *string; /* string passed to the match function */ - gssize string_len; /* length of string */ -}; - -struct _GRegex -{ - volatile gint ref_count; /* the ref count for the immutable part */ - gchar *pattern; /* the pattern */ - pcre *pcre_re; /* compiled form of the pattern */ - GRegexCompileFlags compile_opts; /* options used at compile time on the pattern */ - GRegexMatchFlags match_opts; /* options used at match time on the regex */ - pcre_extra *extra; /* data stored when G_REGEX_OPTIMIZE is used */ -}; - -/* TRUE if ret is an error code, FALSE otherwise. */ -#define IS_PCRE_ERROR(ret) ((ret) < PCRE_ERROR_NOMATCH && (ret) != PCRE_ERROR_PARTIAL) - -typedef struct _InterpolationData InterpolationData; -static gboolean interpolation_list_needs_match (GList *list); -static gboolean interpolate_replacement (const GMatchInfo *match_info, - GString *result, - gpointer data); -static GList *split_replacement (const gchar *replacement, - GError **error); -static void free_interpolation_data (InterpolationData *data); - - -static const gchar * -match_error (gint errcode) -{ - switch (errcode) - { - case PCRE_ERROR_NOMATCH: - /* not an error */ - break; - case PCRE_ERROR_NULL: - /* NULL argument, this should not happen in GRegex */ - g_warning ("A NULL argument was passed to PCRE"); - break; - case PCRE_ERROR_BADOPTION: - return "bad options"; - case PCRE_ERROR_BADMAGIC: - return _("corrupted object"); - case PCRE_ERROR_UNKNOWN_OPCODE: - return N_("internal error or corrupted object"); - case PCRE_ERROR_NOMEMORY: - return _("out of memory"); - case PCRE_ERROR_NOSUBSTRING: - /* not used by pcre_exec() */ - break; - case PCRE_ERROR_MATCHLIMIT: - return _("backtracking limit reached"); - case PCRE_ERROR_CALLOUT: - /* callouts are not implemented */ - break; - case PCRE_ERROR_BADUTF8: - case PCRE_ERROR_BADUTF8_OFFSET: - /* we do not check if strings are valid */ - break; - case PCRE_ERROR_PARTIAL: - /* not an error */ - break; - case PCRE_ERROR_BADPARTIAL: - return _("the pattern contains items not supported for partial matching"); - case PCRE_ERROR_INTERNAL: - return _("internal error"); - case PCRE_ERROR_BADCOUNT: - /* negative ovecsize, this should not happen in GRegex */ - g_warning ("A negative ovecsize was passed to PCRE"); - break; - case PCRE_ERROR_DFA_UITEM: - return _("the pattern contains items not supported for partial matching"); - case PCRE_ERROR_DFA_UCOND: - return _("back references as conditions are not supported for partial matching"); - case PCRE_ERROR_DFA_UMLIMIT: - /* the match_field field is not used in GRegex */ - break; - case PCRE_ERROR_DFA_WSSIZE: - /* handled expanding the workspace */ - break; - case PCRE_ERROR_DFA_RECURSE: - case PCRE_ERROR_RECURSIONLIMIT: - return _("recursion limit reached"); - case PCRE_ERROR_NULLWSLIMIT: - return _("workspace limit for empty substrings reached"); - case PCRE_ERROR_BADNEWLINE: - return _("invalid combination of newline flags"); - default: - break; - } - return _("unknown error"); -} - -static void -translate_compile_error (gint *errcode, const gchar **errmsg) -{ - /* Compile errors are created adding 100 to the error code returned - * by PCRE. - * If errcode is known we put the translatable error message in - * erromsg. If errcode is unknown we put the generic - * G_REGEX_ERROR_COMPILE error code in errcode and keep the - * untranslated error message returned by PCRE. - * Note that there can be more PCRE errors with the same GRegexError - * and that some PCRE errors are useless for us. - */ - *errcode += 100; - - switch (*errcode) - { - case G_REGEX_ERROR_STRAY_BACKSLASH: - *errmsg = _("\\ at end of pattern"); - break; - case G_REGEX_ERROR_MISSING_CONTROL_CHAR: - *errmsg = _("\\c at end of pattern"); - break; - case G_REGEX_ERROR_UNRECOGNIZED_ESCAPE: - *errmsg = _("unrecognized character follows \\"); - break; - case 137: - /* A number of Perl escapes are not handled by PCRE. - * Therefore it explicitly raises ERR37. - */ - *errcode = G_REGEX_ERROR_UNRECOGNIZED_ESCAPE; - *errmsg = _("case-changing escapes (\\l, \\L, \\u, \\U) are not allowed here"); - break; - case G_REGEX_ERROR_QUANTIFIERS_OUT_OF_ORDER: - *errmsg = _("numbers out of order in {} quantifier"); - break; - case G_REGEX_ERROR_QUANTIFIER_TOO_BIG: - *errmsg = _("number too big in {} quantifier"); - break; - case G_REGEX_ERROR_UNTERMINATED_CHARACTER_CLASS: - *errmsg = _("missing terminating ] for character class"); - break; - case G_REGEX_ERROR_INVALID_ESCAPE_IN_CHARACTER_CLASS: - *errmsg = _("invalid escape sequence in character class"); - break; - case G_REGEX_ERROR_RANGE_OUT_OF_ORDER: - *errmsg = _("range out of order in character class"); - break; - case G_REGEX_ERROR_NOTHING_TO_REPEAT: - *errmsg = _("nothing to repeat"); - break; - case G_REGEX_ERROR_UNRECOGNIZED_CHARACTER: - *errmsg = _("unrecognized character after (?"); - break; - case 124: - *errcode = G_REGEX_ERROR_UNRECOGNIZED_CHARACTER; - *errmsg = _("unrecognized character after (?<"); - break; - case 141: - *errcode = G_REGEX_ERROR_UNRECOGNIZED_CHARACTER; - *errmsg = _("unrecognized character after (?P"); - break; - case G_REGEX_ERROR_POSIX_NAMED_CLASS_OUTSIDE_CLASS: - *errmsg = _("POSIX named classes are supported only within a class"); - break; - case G_REGEX_ERROR_UNMATCHED_PARENTHESIS: - *errmsg = _("missing terminating )"); - break; - case 122: - *errcode = G_REGEX_ERROR_UNMATCHED_PARENTHESIS; - *errmsg = _(") without opening ("); - break; - case 129: - *errcode = G_REGEX_ERROR_UNMATCHED_PARENTHESIS; - /* translators: '(?R' and '(?[+-]digits' are both meant as (groups of) - * sequences here, '(?-54' would be an example for the second group. - */ - *errmsg = _("(?R or (?[+-]digits must be followed by )"); - break; - case G_REGEX_ERROR_INEXISTENT_SUBPATTERN_REFERENCE: - *errmsg = _("reference to non-existent subpattern"); - break; - case G_REGEX_ERROR_UNTERMINATED_COMMENT: - *errmsg = _("missing ) after comment"); - break; - case G_REGEX_ERROR_EXPRESSION_TOO_LARGE: - *errmsg = _("regular expression too large"); - break; - case G_REGEX_ERROR_MEMORY_ERROR: - *errmsg = _("failed to get memory"); - break; - case G_REGEX_ERROR_VARIABLE_LENGTH_LOOKBEHIND: - *errmsg = _("lookbehind assertion is not fixed length"); - break; - case G_REGEX_ERROR_MALFORMED_CONDITION: - *errmsg = _("malformed number or name after (?("); - break; - case G_REGEX_ERROR_TOO_MANY_CONDITIONAL_BRANCHES: - *errmsg = _("conditional group contains more than two branches"); - break; - case G_REGEX_ERROR_ASSERTION_EXPECTED: - *errmsg = _("assertion expected after (?("); - break; - case G_REGEX_ERROR_UNKNOWN_POSIX_CLASS_NAME: - *errmsg = _("unknown POSIX class name"); - break; - case G_REGEX_ERROR_POSIX_COLLATING_ELEMENTS_NOT_SUPPORTED: - *errmsg = _("POSIX collating elements are not supported"); - break; - case G_REGEX_ERROR_HEX_CODE_TOO_LARGE: - *errmsg = _("character value in \\x{...} sequence is too large"); - break; - case G_REGEX_ERROR_INVALID_CONDITION: - *errmsg = _("invalid condition (?(0)"); - break; - case G_REGEX_ERROR_SINGLE_BYTE_MATCH_IN_LOOKBEHIND: - *errmsg = _("\\C not allowed in lookbehind assertion"); - break; - case G_REGEX_ERROR_INFINITE_LOOP: - *errmsg = _("recursive call could loop indefinitely"); - break; - case G_REGEX_ERROR_MISSING_SUBPATTERN_NAME_TERMINATOR: - *errmsg = _("missing terminator in subpattern name"); - break; - case G_REGEX_ERROR_DUPLICATE_SUBPATTERN_NAME: - *errmsg = _("two named subpatterns have the same name"); - break; - case G_REGEX_ERROR_MALFORMED_PROPERTY: - *errmsg = _("malformed \\P or \\p sequence"); - break; - case G_REGEX_ERROR_UNKNOWN_PROPERTY: - *errmsg = _("unknown property name after \\P or \\p"); - break; - case G_REGEX_ERROR_SUBPATTERN_NAME_TOO_LONG: - *errmsg = _("subpattern name is too long (maximum 32 characters)"); - break; - case G_REGEX_ERROR_TOO_MANY_SUBPATTERNS: - *errmsg = _("too many named subpatterns (maximum 10,000)"); - break; - case G_REGEX_ERROR_INVALID_OCTAL_VALUE: - *errmsg = _("octal value is greater than \\377"); - break; - case G_REGEX_ERROR_TOO_MANY_BRANCHES_IN_DEFINE: - *errmsg = _("DEFINE group contains more than one branch"); - break; - case G_REGEX_ERROR_DEFINE_REPETION: - *errmsg = _("repeating a DEFINE group is not allowed"); - break; - case G_REGEX_ERROR_INCONSISTENT_NEWLINE_OPTIONS: - *errmsg = _("inconsistent NEWLINE options"); - break; - case G_REGEX_ERROR_MISSING_BACK_REFERENCE: - *errmsg = _("\\g is not followed by a braced name or an optionally " - "braced non-zero number"); - break; - case 11: - *errcode = G_REGEX_ERROR_INTERNAL; - *errmsg = _("unexpected repeat"); - break; - case 23: - *errcode = G_REGEX_ERROR_INTERNAL; - *errmsg = _("code overflow"); - break; - case 52: - *errcode = G_REGEX_ERROR_INTERNAL; - *errmsg = _("overran compiling workspace"); - break; - case 53: - *errcode = G_REGEX_ERROR_INTERNAL; - *errmsg = _("previously-checked referenced subpattern not found"); - break; - case 16: - /* This should not happen as we never pass a NULL erroffset */ - g_warning ("erroffset passed as NULL"); - *errcode = G_REGEX_ERROR_COMPILE; - break; - case 17: - /* This should not happen as we check options before passing them - * to pcre_compile2() */ - g_warning ("unknown option bit(s) set"); - *errcode = G_REGEX_ERROR_COMPILE; - break; - case 32: - case 44: - case 45: - /* These errors should not happen as we are using an UTF8-enabled PCRE - * and we do not check if strings are valid */ - g_warning ("%s", *errmsg); - *errcode = G_REGEX_ERROR_COMPILE; - break; - default: - *errcode = G_REGEX_ERROR_COMPILE; - } -} - -/* GMatchInfo */ - -static GMatchInfo * -match_info_new (const GRegex *regex, - const gchar *string, - gint string_len, - gint start_position, - gint match_options, - gboolean is_dfa) -{ - GMatchInfo *match_info; - - if (string_len < 0) - string_len = strlen (string); - - match_info = g_new0 (GMatchInfo, 1); - match_info->regex = g_regex_ref ((GRegex *)regex); - match_info->string = string; - match_info->string_len = string_len; - match_info->matches = PCRE_ERROR_NOMATCH; - match_info->pos = start_position; - match_info->match_opts = match_options; - - if (is_dfa) - { - /* These values should be enough for most cases, if they are not - * enough g_regex_match_all_full() will expand them. */ - match_info->n_offsets = 24; - match_info->n_workspace = 100; - match_info->workspace = g_new (gint, match_info->n_workspace); - } - else - { - gint capture_count; - pcre_fullinfo (regex->pcre_re, regex->extra, - PCRE_INFO_CAPTURECOUNT, &capture_count); - match_info->n_offsets = (capture_count + 1) * 3; - } - - match_info->offsets = g_new0 (gint, match_info->n_offsets); - /* Set an invalid position for the previous match. */ - match_info->offsets[0] = -1; - match_info->offsets[1] = -1; - - return match_info; -} - -/** - * g_match_info_get_regex: - * @match_info: a #GMatchInfo - * - * Returns #GRegex object used in @match_info. It belongs to Glib - * and must not be freed. Use g_regex_ref() if you need to keep it - * after you free @match_info object. - * - * Returns: #GRegex object used in @match_info - * - * Since: 2.14 - */ -GRegex * -g_match_info_get_regex (const GMatchInfo *match_info) -{ - g_return_val_if_fail (match_info != NULL, NULL); - return match_info->regex; -} - -/** - * g_match_info_get_string: - * @match_info: a #GMatchInfo - * - * Returns the string searched with @match_info. This is the - * string passed to g_regex_match() or g_regex_replace() so - * you may not free it before calling this function. - * - * Returns: the string searched with @match_info - * - * Since: 2.14 - */ -const gchar * -g_match_info_get_string (const GMatchInfo *match_info) -{ - g_return_val_if_fail (match_info != NULL, NULL); - return match_info->string; -} - -/** - * g_match_info_free: - * @match_info: a #GMatchInfo - * - * Frees all the memory associated with the #GMatchInfo structure. - * - * Since: 2.14 - */ -void -g_match_info_free (GMatchInfo *match_info) -{ - if (match_info) - { - g_regex_unref (match_info->regex); - g_free (match_info->offsets); - g_free (match_info->workspace); - g_free (match_info); - } -} - -/** - * g_match_info_next: - * @match_info: a #GMatchInfo structure - * @error: location to store the error occuring, or %NULL to ignore errors - * - * Scans for the next match using the same parameters of the previous - * call to g_regex_match_full() or g_regex_match() that returned - * @match_info. - * - * The match is done on the string passed to the match function, so you - * cannot free it before calling this function. - * - * Returns: %TRUE is the string matched, %FALSE otherwise - * - * Since: 2.14 - */ -gboolean -g_match_info_next (GMatchInfo *match_info, - GError **error) -{ - gint opts; - gint prev_match_start; - gint prev_match_end; - - g_return_val_if_fail (match_info != NULL, FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - g_return_val_if_fail (match_info->pos >= 0, FALSE); - - opts = match_info->regex->match_opts | match_info->match_opts; - - prev_match_start = match_info->offsets[0]; - prev_match_end = match_info->offsets[1]; - - match_info->matches = pcre_exec (match_info->regex->pcre_re, - match_info->regex->extra, - match_info->string, - match_info->string_len, - match_info->pos, - match_info->regex->match_opts | - match_info->match_opts, - match_info->offsets, - match_info->n_offsets); - if (IS_PCRE_ERROR (match_info->matches)) - { - g_set_error (error, G_REGEX_ERROR, G_REGEX_ERROR_MATCH, - _("Error while matching regular expression %s: %s"), - match_info->regex->pattern, match_error (match_info->matches)); - return FALSE; - } - - /* avoid infinite loops if the pattern is an empty string or something - * equivalent */ - if (match_info->pos == match_info->offsets[1]) - { - if (match_info->pos > match_info->string_len) - { - /* we have reached the end of the string */ - match_info->pos = -1; - match_info->matches = PCRE_ERROR_NOMATCH; - return FALSE; - } - - match_info->pos = NEXT_CHAR (match_info->regex, - &match_info->string[match_info->pos]) - - match_info->string; - } - else - { - match_info->pos = match_info->offsets[1]; - } - - /* it's possibile to get two identical matches when we are matching - * empty strings, for instance if the pattern is "(?=[A-Z0-9])" and - * the string is "RegExTest" we have: - * - search at position 0: match from 0 to 0 - * - search at position 1: match from 3 to 3 - * - search at position 3: match from 3 to 3 (duplicate) - * - search at position 4: match from 5 to 5 - * - search at position 5: match from 5 to 5 (duplicate) - * - search at position 6: no match -> stop - * so we have to ignore the duplicates. - * see bug #515944: http://bugzilla.gnome.org/show_bug.cgi?id=515944 */ - if (match_info->matches >= 0 && - prev_match_start == match_info->offsets[0] && - prev_match_end == match_info->offsets[1]) - { - /* ignore this match and search the next one */ - return g_match_info_next (match_info, error); - } - - return match_info->matches >= 0; -} - -/** - * g_match_info_matches: - * @match_info: a #GMatchInfo structure - * - * Returns whether the previous match operation succeeded. - * - * Returns: %TRUE if the previous match operation succeeded, - * %FALSE otherwise - * - * Since: 2.14 - */ -gboolean -g_match_info_matches (const GMatchInfo *match_info) -{ - g_return_val_if_fail (match_info != NULL, FALSE); - - return match_info->matches >= 0; -} - -/** - * g_match_info_get_match_count: - * @match_info: a #GMatchInfo structure - * - * Retrieves the number of matched substrings (including substring 0, - * that is the whole matched text), so 1 is returned if the pattern - * has no substrings in it and 0 is returned if the match failed. - * - * If the last match was obtained using the DFA algorithm, that is - * using g_regex_match_all() or g_regex_match_all_full(), the retrieved - * count is not that of the number of capturing parentheses but that of - * the number of matched substrings. - * - * Returns: Number of matched substrings, or -1 if an error occurred - * - * Since: 2.14 - */ -gint -g_match_info_get_match_count (const GMatchInfo *match_info) -{ - g_return_val_if_fail (match_info, -1); - - if (match_info->matches == PCRE_ERROR_NOMATCH) - /* no match */ - return 0; - else if (match_info->matches < PCRE_ERROR_NOMATCH) - /* error */ - return -1; - else - /* match */ - return match_info->matches; -} - -/** - * g_match_info_is_partial_match: - * @match_info: a #GMatchInfo structure - * - * Usually if the string passed to g_regex_match*() matches as far as - * it goes, but is too short to match the entire pattern, %FALSE is - * returned. There are circumstances where it might be helpful to - * distinguish this case from other cases in which there is no match. - * - * Consider, for example, an application where a human is required to - * type in data for a field with specific formatting requirements. An - * example might be a date in the form ddmmmyy, defined by the pattern - * "^\d?\d(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\d\d$". - * If the application sees the user’s keystrokes one by one, and can - * check that what has been typed so far is potentially valid, it is - * able to raise an error as soon as a mistake is made. - * - * GRegex supports the concept of partial matching by means of the - * #G_REGEX_MATCH_PARTIAL flag. When this is set the return code for - * g_regex_match() or g_regex_match_full() is, as usual, %TRUE - * for a complete match, %FALSE otherwise. But, when these functions - * return %FALSE, you can check if the match was partial calling - * g_match_info_is_partial_match(). - * - * When using partial matching you cannot use g_match_info_fetch*(). - * - * Because of the way certain internal optimizations are implemented - * the partial matching algorithm cannot be used with all patterns. - * So repeated single characters such as "a{2,4}" and repeated single - * meta-sequences such as "\d+" are not permitted if the maximum number - * of occurrences is greater than one. Optional items such as "\d?" - * (where the maximum is one) are permitted. Quantifiers with any values - * are permitted after parentheses, so the invalid examples above can be - * coded thus "(a){2,4}" and "(\d)+". If #G_REGEX_MATCH_PARTIAL is set - * for a pattern that does not conform to the restrictions, matching - * functions return an error. - * - * Returns: %TRUE if the match was partial, %FALSE otherwise - * - * Since: 2.14 - */ -gboolean -g_match_info_is_partial_match (const GMatchInfo *match_info) -{ - g_return_val_if_fail (match_info != NULL, FALSE); - - return match_info->matches == PCRE_ERROR_PARTIAL; -} - -/** - * g_match_info_expand_references: - * @match_info: a #GMatchInfo or %NULL - * @string_to_expand: the string to expand - * @error: location to store the error occuring, or %NULL to ignore errors - * - * Returns a new string containing the text in @string_to_expand with - * references and escape sequences expanded. References refer to the last - * match done with @string against @regex and have the same syntax used by - * g_regex_replace(). - * - * The @string_to_expand must be UTF-8 encoded even if #G_REGEX_RAW was - * passed to g_regex_new(). - * - * The backreferences are extracted from the string passed to the match - * function, so you cannot call this function after freeing the string. - * - * @match_info may be %NULL in which case @string_to_expand must not - * contain references. For instance "foo\n" does not refer to an actual - * pattern and '\n' merely will be replaced with \n character, - * while to expand "\0" (whole match) one needs the result of a match. - * Use g_regex_check_replacement() to find out whether @string_to_expand - * contains references. - * - * Returns: the expanded string, or %NULL if an error occurred - * - * Since: 2.14 - */ -gchar * -g_match_info_expand_references (const GMatchInfo *match_info, - const gchar *string_to_expand, - GError **error) -{ - GString *result; - GList *list; - GError *tmp_error = NULL; - - g_return_val_if_fail (string_to_expand != NULL, NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - list = split_replacement (string_to_expand, &tmp_error); - if (tmp_error != NULL) - { - g_propagate_error (error, tmp_error); - return NULL; - } - - if (!match_info && interpolation_list_needs_match (list)) - { - g_critical ("String '%s' contains references to the match, can't " - "expand references without GMatchInfo object", - string_to_expand); - return NULL; - } - - result = g_string_sized_new (strlen (string_to_expand)); - interpolate_replacement (match_info, result, list); - - g_list_foreach (list, (GFunc)free_interpolation_data, NULL); - g_list_free (list); - - return g_string_free (result, FALSE); -} - -/** - * g_match_info_fetch: - * @match_info: #GMatchInfo structure - * @match_num: number of the sub expression - * - * Retrieves the text matching the @match_num<!-- -->'th capturing - * parentheses. 0 is the full text of the match, 1 is the first paren - * set, 2 the second, and so on. - * - * If @match_num is a valid sub pattern but it didn't match anything - * (e.g. sub pattern 1, matching "b" against "(a)?b") then an empty - * string is returned. - * - * If the match was obtained using the DFA algorithm, that is using - * g_regex_match_all() or g_regex_match_all_full(), the retrieved - * string is not that of a set of parentheses but that of a matched - * substring. Substrings are matched in reverse order of length, so - * 0 is the longest match. - * - * The string is fetched from the string passed to the match function, - * so you cannot call this function after freeing the string. - * - * Returns: The matched substring, or %NULL if an error occurred. - * You have to free the string yourself - * - * Since: 2.14 - */ -gchar * -g_match_info_fetch (const GMatchInfo *match_info, - gint match_num) -{ - /* we cannot use pcre_get_substring() because it allocates the - * string using pcre_malloc(). */ - gchar *match = NULL; - gint start, end; - - g_return_val_if_fail (match_info != NULL, NULL); - g_return_val_if_fail (match_num >= 0, NULL); - - /* match_num does not exist or it didn't matched, i.e. matching "b" - * against "(a)?b" then group 0 is empty. */ - if (!g_match_info_fetch_pos (match_info, match_num, &start, &end)) - match = NULL; - else if (start == -1) - match = g_strdup (""); - else - match = g_strndup (&match_info->string[start], end - start); - - return match; -} - -/** - * g_match_info_fetch_pos: - * @match_info: #GMatchInfo structure - * @match_num: number of the sub expression - * @start_pos: pointer to location where to store the start position - * @end_pos: pointer to location where to store the end position - * - * Retrieves the position in bytes of the @match_num<!-- -->'th capturing - * parentheses. 0 is the full text of the match, 1 is the first - * paren set, 2 the second, and so on. - * - * If @match_num is a valid sub pattern but it didn't match anything - * (e.g. sub pattern 1, matching "b" against "(a)?b") then @start_pos - * and @end_pos are set to -1 and %TRUE is returned. - * - * If the match was obtained using the DFA algorithm, that is using - * g_regex_match_all() or g_regex_match_all_full(), the retrieved - * position is not that of a set of parentheses but that of a matched - * substring. Substrings are matched in reverse order of length, so - * 0 is the longest match. - * - * Returns: %TRUE if the position was fetched, %FALSE otherwise. If - * the position cannot be fetched, @start_pos and @end_pos are left - * unchanged - * - * Since: 2.14 - */ -gboolean -g_match_info_fetch_pos (const GMatchInfo *match_info, - gint match_num, - gint *start_pos, - gint *end_pos) -{ - g_return_val_if_fail (match_info != NULL, FALSE); - g_return_val_if_fail (match_num >= 0, FALSE); - - /* make sure the sub expression number they're requesting is less than - * the total number of sub expressions that were matched. */ - if (match_num >= match_info->matches) - return FALSE; - - if (start_pos != NULL) - *start_pos = match_info->offsets[2 * match_num]; - - if (end_pos != NULL) - *end_pos = match_info->offsets[2 * match_num + 1]; - - return TRUE; -} - -/* - * Returns number of first matched subpattern with name @name. - * There may be more than one in case when DUPNAMES is used, - * and not all subpatterns with that name match; - * pcre_get_stringnumber() does not work in that case. - */ -static gint -get_matched_substring_number (const GMatchInfo *match_info, - const gchar *name) -{ - gint entrysize; - gchar *first, *last; - guchar *entry; - - if (!(match_info->regex->compile_opts & G_REGEX_DUPNAMES)) - return pcre_get_stringnumber (match_info->regex->pcre_re, name); - - /* This code is copied from pcre_get.c: get_first_set() */ - entrysize = pcre_get_stringtable_entries (match_info->regex->pcre_re, - name, - &first, - &last); - - if (entrysize <= 0) - return entrysize; - - for (entry = (guchar*) first; entry <= (guchar*) last; entry += entrysize) - { - gint n = (entry[0] << 8) + entry[1]; - if (match_info->offsets[n*2] >= 0) - return n; - } - - return (first[0] << 8) + first[1]; -} - -/** - * g_match_info_fetch_named: - * @match_info: #GMatchInfo structure - * @name: name of the subexpression - * - * Retrieves the text matching the capturing parentheses named @name. - * - * If @name is a valid sub pattern name but it didn't match anything - * (e.g. sub pattern "X", matching "b" against "(?P<X>a)?b") - * then an empty string is returned. - * - * The string is fetched from the string passed to the match function, - * so you cannot call this function after freeing the string. - * - * Returns: The matched substring, or %NULL if an error occurred. - * You have to free the string yourself - * - * Since: 2.14 - */ -gchar * -g_match_info_fetch_named (const GMatchInfo *match_info, - const gchar *name) -{ - /* we cannot use pcre_get_named_substring() because it allocates the - * string using pcre_malloc(). */ - gint num; - - g_return_val_if_fail (match_info != NULL, NULL); - g_return_val_if_fail (name != NULL, NULL); - - num = get_matched_substring_number (match_info, name); - if (num < 0) - return NULL; - else - return g_match_info_fetch (match_info, num); -} - -/** - * g_match_info_fetch_named_pos: - * @match_info: #GMatchInfo structure - * @name: name of the subexpression - * @start_pos: pointer to location where to store the start position - * @end_pos: pointer to location where to store the end position - * - * Retrieves the position in bytes of the capturing parentheses named @name. - * - * If @name is a valid sub pattern name but it didn't match anything - * (e.g. sub pattern "X", matching "b" against "(?P<X>a)?b") - * then @start_pos and @end_pos are set to -1 and %TRUE is returned. - * - * Returns: %TRUE if the position was fetched, %FALSE otherwise. If - * the position cannot be fetched, @start_pos and @end_pos are left - * unchanged - * - * Since: 2.14 - */ -gboolean -g_match_info_fetch_named_pos (const GMatchInfo *match_info, - const gchar *name, - gint *start_pos, - gint *end_pos) -{ - gint num; - - g_return_val_if_fail (match_info != NULL, FALSE); - g_return_val_if_fail (name != NULL, FALSE); - - num = get_matched_substring_number (match_info, name); - if (num < 0) - return FALSE; - - return g_match_info_fetch_pos (match_info, num, start_pos, end_pos); -} - -/** - * g_match_info_fetch_all: - * @match_info: a #GMatchInfo structure - * - * Bundles up pointers to each of the matching substrings from a match - * and stores them in an array of gchar pointers. The first element in - * the returned array is the match number 0, i.e. the entire matched - * text. - * - * If a sub pattern didn't match anything (e.g. sub pattern 1, matching - * "b" against "(a)?b") then an empty string is inserted. - * - * If the last match was obtained using the DFA algorithm, that is using - * g_regex_match_all() or g_regex_match_all_full(), the retrieved - * strings are not that matched by sets of parentheses but that of the - * matched substring. Substrings are matched in reverse order of length, - * so the first one is the longest match. - * - * The strings are fetched from the string passed to the match function, - * so you cannot call this function after freeing the string. - * - * Returns: a %NULL-terminated array of gchar * pointers. It must be - * freed using g_strfreev(). If the previous match failed %NULL is - * returned - * - * Since: 2.14 - */ -gchar ** -g_match_info_fetch_all (const GMatchInfo *match_info) -{ - /* we cannot use pcre_get_substring_list() because the returned value - * isn't suitable for g_strfreev(). */ - gchar **result; - gint i; - - g_return_val_if_fail (match_info != NULL, NULL); - - if (match_info->matches < 0) - return NULL; - - result = g_new (gchar *, match_info->matches + 1); - for (i = 0; i < match_info->matches; i++) - result[i] = g_match_info_fetch (match_info, i); - result[i] = NULL; - - return result; -} - - -/* GRegex */ - -GQuark -g_regex_error_quark (void) -{ - static GQuark error_quark = 0; - - if (error_quark == 0) - error_quark = g_quark_from_static_string ("g-regex-error-quark"); - - return error_quark; -} - -/** - * g_regex_ref: - * @regex: a #GRegex - * - * Increases reference count of @regex by 1. - * - * Returns: @regex - * - * Since: 2.14 - */ -GRegex * -g_regex_ref (GRegex *regex) -{ - g_return_val_if_fail (regex != NULL, NULL); - g_atomic_int_inc (®ex->ref_count); - return regex; -} - -/** - * g_regex_unref: - * @regex: a #GRegex - * - * Decreases reference count of @regex by 1. When reference count drops - * to zero, it frees all the memory associated with the regex structure. - * - * Since: 2.14 - */ -void -g_regex_unref (GRegex *regex) -{ - g_return_if_fail (regex != NULL); - - if (g_atomic_int_exchange_and_add (®ex->ref_count, -1) - 1 == 0) - { - g_free (regex->pattern); - if (regex->pcre_re != NULL) - pcre_free (regex->pcre_re); - if (regex->extra != NULL) - pcre_free (regex->extra); - g_free (regex); - } -} - -/** - * g_regex_new: - * @pattern: the regular expression - * @compile_options: compile options for the regular expression, or 0 - * @match_options: match options for the regular expression, or 0 - * @error: return location for a #GError - * - * Compiles the regular expression to an internal form, and does - * the initial setup of the #GRegex structure. - * - * Returns: a #GRegex structure. Call g_regex_unref() when you - * are done with it - * - * Since: 2.14 - */ -GRegex * -g_regex_new (const gchar *pattern, - GRegexCompileFlags compile_options, - GRegexMatchFlags match_options, - GError **error) -{ - GRegex *regex; - pcre *re; - const gchar *errmsg; - gint erroffset; - gint errcode; - gboolean optimize = FALSE; - static gboolean initialized = FALSE; - unsigned long int pcre_compile_options; - - g_return_val_if_fail (pattern != NULL, NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - g_return_val_if_fail ((compile_options & ~G_REGEX_COMPILE_MASK) == 0, NULL); - g_return_val_if_fail ((match_options & ~G_REGEX_MATCH_MASK) == 0, NULL); - - if (!initialized) - { - gint support; - const gchar *msg; - - pcre_config (PCRE_CONFIG_UTF8, &support); - if (!support) - { - msg = N_("PCRE library is compiled without UTF8 support"); - g_critical ("%s", msg); - g_set_error_literal (error, G_REGEX_ERROR, G_REGEX_ERROR_COMPILE, gettext (msg)); - return NULL; - } - - pcre_config (PCRE_CONFIG_UNICODE_PROPERTIES, &support); - if (!support) - { - msg = N_("PCRE library is compiled without UTF8 properties support"); - g_critical ("%s", msg); - g_set_error_literal (error, G_REGEX_ERROR, G_REGEX_ERROR_COMPILE, gettext (msg)); - return NULL; - } - - initialized = TRUE; - } - - /* G_REGEX_OPTIMIZE has the same numeric value of PCRE_NO_UTF8_CHECK, - * as we do not need to wrap PCRE_NO_UTF8_CHECK. */ - if (compile_options & G_REGEX_OPTIMIZE) - optimize = TRUE; - - /* In GRegex the string are, by default, UTF-8 encoded. PCRE - * instead uses UTF-8 only if required with PCRE_UTF8. */ - if (compile_options & G_REGEX_RAW) - { - /* disable utf-8 */ - compile_options &= ~G_REGEX_RAW; - } - else - { - /* enable utf-8 */ - compile_options |= PCRE_UTF8 | PCRE_NO_UTF8_CHECK; - match_options |= PCRE_NO_UTF8_CHECK; - } - - /* PCRE_NEWLINE_ANY is the default for the internal PCRE but - * not for the system one. */ - if (!(compile_options & G_REGEX_NEWLINE_CR) && - !(compile_options & G_REGEX_NEWLINE_LF)) - { - compile_options |= PCRE_NEWLINE_ANY; - } - - /* compile the pattern */ - re = pcre_compile2 (pattern, compile_options, &errcode, - &errmsg, &erroffset, NULL); - - /* if the compilation failed, set the error member and return - * immediately */ - if (re == NULL) - { - GError *tmp_error; - - /* Translate the PCRE error code to GRegexError and use a translated - * error message if possible */ - translate_compile_error (&errcode, &errmsg); - - /* PCRE uses byte offsets but we want to show character offsets */ - erroffset = g_utf8_pointer_to_offset (pattern, &pattern[erroffset]); - - tmp_error = g_error_new (G_REGEX_ERROR, errcode, - _("Error while compiling regular " - "expression %s at char %d: %s"), - pattern, erroffset, errmsg); - g_propagate_error (error, tmp_error); - - return NULL; - } - - /* For options set at the beginning of the pattern, pcre puts them into - * compile options, e.g. "(?i)foo" will make the pcre structure store - * PCRE_CASELESS even though it wasn't explicitly given for compilation. */ - pcre_fullinfo (re, NULL, PCRE_INFO_OPTIONS, &pcre_compile_options); - compile_options = pcre_compile_options; - - if (!(compile_options & G_REGEX_DUPNAMES)) - { - gboolean jchanged = FALSE; - pcre_fullinfo (re, NULL, PCRE_INFO_JCHANGED, &jchanged); - if (jchanged) - compile_options |= G_REGEX_DUPNAMES; - } - - regex = g_new0 (GRegex, 1); - regex->ref_count = 1; - regex->pattern = g_strdup (pattern); - regex->pcre_re = re; - regex->compile_opts = compile_options; - regex->match_opts = match_options; - - if (optimize) - { - regex->extra = pcre_study (regex->pcre_re, 0, &errmsg); - if (errmsg != NULL) - { - GError *tmp_error = g_error_new (G_REGEX_ERROR, - G_REGEX_ERROR_OPTIMIZE, - _("Error while optimizing " - "regular expression %s: %s"), - regex->pattern, - errmsg); - g_propagate_error (error, tmp_error); - - g_regex_unref (regex); - return NULL; - } - } - - return regex; -} - -/** - * g_regex_get_pattern: - * @regex: a #GRegex structure - * - * Gets the pattern string associated with @regex, i.e. a copy of - * the string passed to g_regex_new(). - * - * Returns: the pattern of @regex - * - * Since: 2.14 - */ -const gchar * -g_regex_get_pattern (const GRegex *regex) -{ - g_return_val_if_fail (regex != NULL, NULL); - - return regex->pattern; -} - -/** - * g_regex_get_max_backref: - * @regex: a #GRegex - * - * Returns the number of the highest back reference - * in the pattern, or 0 if the pattern does not contain - * back references. - * - * Returns: the number of the highest back reference - * - * Since: 2.14 - */ -gint -g_regex_get_max_backref (const GRegex *regex) -{ - gint value; - - pcre_fullinfo (regex->pcre_re, regex->extra, - PCRE_INFO_BACKREFMAX, &value); - - return value; -} - -/** - * g_regex_get_capture_count: - * @regex: a #GRegex - * - * Returns the number of capturing subpatterns in the pattern. - * - * Returns: the number of capturing subpatterns - * - * Since: 2.14 - */ -gint -g_regex_get_capture_count (const GRegex *regex) -{ - gint value; - - pcre_fullinfo (regex->pcre_re, regex->extra, - PCRE_INFO_CAPTURECOUNT, &value); - - return value; -} - -/** - * g_regex_match_simple: - * @pattern: the regular expression - * @string: the string to scan for matches - * @compile_options: compile options for the regular expression, or 0 - * @match_options: match options, or 0 - * - * Scans for a match in @string for @pattern. - * - * This function is equivalent to g_regex_match() but it does not - * require to compile the pattern with g_regex_new(), avoiding some - * lines of code when you need just to do a match without extracting - * substrings, capture counts, and so on. - * - * If this function is to be called on the same @pattern more than - * once, it's more efficient to compile the pattern once with - * g_regex_new() and then use g_regex_match(). - * - * Returns: %TRUE if the string matched, %FALSE otherwise - * - * Since: 2.14 - */ -gboolean -g_regex_match_simple (const gchar *pattern, - const gchar *string, - GRegexCompileFlags compile_options, - GRegexMatchFlags match_options) -{ - GRegex *regex; - gboolean result; - - regex = g_regex_new (pattern, compile_options, 0, NULL); - if (!regex) - return FALSE; - result = g_regex_match_full (regex, string, -1, 0, match_options, NULL, NULL); - g_regex_unref (regex); - return result; -} - -/** - * g_regex_match: - * @regex: a #GRegex structure from g_regex_new() - * @string: the string to scan for matches - * @match_options: match options - * @match_info: pointer to location where to store the #GMatchInfo, - * or %NULL if you do not need it - * - * Scans for a match in string for the pattern in @regex. - * The @match_options are combined with the match options specified - * when the @regex structure was created, letting you have more - * flexibility in reusing #GRegex structures. - * - * A #GMatchInfo structure, used to get information on the match, - * is stored in @match_info if not %NULL. Note that if @match_info - * is not %NULL then it is created even if the function returns %FALSE, - * i.e. you must free it regardless if regular expression actually matched. - * - * To retrieve all the non-overlapping matches of the pattern in - * string you can use g_match_info_next(). - * - * |[ - * static void - * print_uppercase_words (const gchar *string) - * { - * /* Print all uppercase-only words. */ - * GRegex *regex; - * GMatchInfo *match_info; - * - * regex = g_regex_new ("[A-Z]+", 0, 0, NULL); - * g_regex_match (regex, string, 0, &match_info); - * while (g_match_info_matches (match_info)) - * { - * gchar *word = g_match_info_fetch (match_info, 0); - * g_print ("Found: %s\n", word); - * g_free (word); - * g_match_info_next (match_info, NULL); - * } - * g_match_info_free (match_info); - * g_regex_unref (regex); - * } - * ]| - * - * @string is not copied and is used in #GMatchInfo internally. If - * you use any #GMatchInfo method (except g_match_info_free()) after - * freeing or modifying @string then the behaviour is undefined. - * - * Returns: %TRUE is the string matched, %FALSE otherwise - * - * Since: 2.14 - */ -gboolean -g_regex_match (const GRegex *regex, - const gchar *string, - GRegexMatchFlags match_options, - GMatchInfo **match_info) -{ - return g_regex_match_full (regex, string, -1, 0, match_options, - match_info, NULL); -} - -/** - * g_regex_match_full: - * @regex: a #GRegex structure from g_regex_new() - * @string: the string to scan for matches - * @string_len: the length of @string, or -1 if @string is nul-terminated - * @start_position: starting index of the string to match - * @match_options: match options - * @match_info: pointer to location where to store the #GMatchInfo, - * or %NULL if you do not need it - * @error: location to store the error occuring, or %NULL to ignore errors - * - * Scans for a match in string for the pattern in @regex. - * The @match_options are combined with the match options specified - * when the @regex structure was created, letting you have more - * flexibility in reusing #GRegex structures. - * - * Setting @start_position differs from just passing over a shortened - * string and setting #G_REGEX_MATCH_NOTBOL in the case of a pattern - * that begins with any kind of lookbehind assertion, such as "\b". - * - * A #GMatchInfo structure, used to get information on the match, is - * stored in @match_info if not %NULL. Note that if @match_info is - * not %NULL then it is created even if the function returns %FALSE, - * i.e. you must free it regardless if regular expression actually - * matched. - * - * @string is not copied and is used in #GMatchInfo internally. If - * you use any #GMatchInfo method (except g_match_info_free()) after - * freeing or modifying @string then the behaviour is undefined. - * - * To retrieve all the non-overlapping matches of the pattern in - * string you can use g_match_info_next(). - * - * |[ - * static void - * print_uppercase_words (const gchar *string) - * { - * /* Print all uppercase-only words. */ - * GRegex *regex; - * GMatchInfo *match_info; - * GError *error = NULL; - * - * regex = g_regex_new ("[A-Z]+", 0, 0, NULL); - * g_regex_match_full (regex, string, -1, 0, 0, &match_info, &error); - * while (g_match_info_matches (match_info)) - * { - * gchar *word = g_match_info_fetch (match_info, 0); - * g_print ("Found: %s\n", word); - * g_free (word); - * g_match_info_next (match_info, &error); - * } - * g_match_info_free (match_info); - * g_regex_unref (regex); - * if (error != NULL) - * { - * g_printerr ("Error while matching: %s\n", error->message); - * g_error_free (error); - * } - * } - * ]| - * - * Returns: %TRUE is the string matched, %FALSE otherwise - * - * Since: 2.14 - */ -gboolean -g_regex_match_full (const GRegex *regex, - const gchar *string, - gssize string_len, - gint start_position, - GRegexMatchFlags match_options, - GMatchInfo **match_info, - GError **error) -{ - GMatchInfo *info; - gboolean match_ok; - - g_return_val_if_fail (regex != NULL, FALSE); - g_return_val_if_fail (string != NULL, FALSE); - g_return_val_if_fail (start_position >= 0, FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - g_return_val_if_fail ((match_options & ~G_REGEX_MATCH_MASK) == 0, FALSE); - - info = match_info_new (regex, string, string_len, start_position, - match_options, FALSE); - match_ok = g_match_info_next (info, error); - if (match_info != NULL) - *match_info = info; - else - g_match_info_free (info); - - return match_ok; -} - -/** - * g_regex_match_all: - * @regex: a #GRegex structure from g_regex_new() - * @string: the string to scan for matches - * @match_options: match options - * @match_info: pointer to location where to store the #GMatchInfo, - * or %NULL if you do not need it - * - * Using the standard algorithm for regular expression matching only - * the longest match in the string is retrieved. This function uses - * a different algorithm so it can retrieve all the possible matches. - * For more documentation see g_regex_match_all_full(). - * - * A #GMatchInfo structure, used to get information on the match, is - * stored in @match_info if not %NULL. Note that if @match_info is - * not %NULL then it is created even if the function returns %FALSE, - * i.e. you must free it regardless if regular expression actually - * matched. - * - * @string is not copied and is used in #GMatchInfo internally. If - * you use any #GMatchInfo method (except g_match_info_free()) after - * freeing or modifying @string then the behaviour is undefined. - * - * Returns: %TRUE is the string matched, %FALSE otherwise - * - * Since: 2.14 - */ -gboolean -g_regex_match_all (const GRegex *regex, - const gchar *string, - GRegexMatchFlags match_options, - GMatchInfo **match_info) -{ - return g_regex_match_all_full (regex, string, -1, 0, match_options, - match_info, NULL); -} - -/** - * g_regex_match_all_full: - * @regex: a #GRegex structure from g_regex_new() - * @string: the string to scan for matches - * @string_len: the length of @string, or -1 if @string is nul-terminated - * @start_position: starting index of the string to match - * @match_options: match options - * @match_info: pointer to location where to store the #GMatchInfo, - * or %NULL if you do not need it - * @error: location to store the error occuring, or %NULL to ignore errors - * - * Using the standard algorithm for regular expression matching only - * the longest match in the string is retrieved, it is not possibile - * to obtain all the available matches. For instance matching - * "<a> <b> <c>" against the pattern "<.*>" - * you get "<a> <b> <c>". - * - * This function uses a different algorithm (called DFA, i.e. deterministic - * finite automaton), so it can retrieve all the possible matches, all - * starting at the same point in the string. For instance matching - * "<a> <b> <c>" against the pattern "<.*>" - * you would obtain three matches: "<a> <b> <c>", - * "<a> <b>" and "<a>". - * - * The number of matched strings is retrieved using - * g_match_info_get_match_count(). To obtain the matched strings and - * their position you can use, respectively, g_match_info_fetch() and - * g_match_info_fetch_pos(). Note that the strings are returned in - * reverse order of length; that is, the longest matching string is - * given first. - * - * Note that the DFA algorithm is slower than the standard one and it - * is not able to capture substrings, so backreferences do not work. - * - * Setting @start_position differs from just passing over a shortened - * string and setting #G_REGEX_MATCH_NOTBOL in the case of a pattern - * that begins with any kind of lookbehind assertion, such as "\b". - * - * A #GMatchInfo structure, used to get information on the match, is - * stored in @match_info if not %NULL. Note that if @match_info is - * not %NULL then it is created even if the function returns %FALSE, - * i.e. you must free it regardless if regular expression actually - * matched. - * - * @string is not copied and is used in #GMatchInfo internally. If - * you use any #GMatchInfo method (except g_match_info_free()) after - * freeing or modifying @string then the behaviour is undefined. - * - * Returns: %TRUE is the string matched, %FALSE otherwise - * - * Since: 2.14 - */ -gboolean -g_regex_match_all_full (const GRegex *regex, - const gchar *string, - gssize string_len, - gint start_position, - GRegexMatchFlags match_options, - GMatchInfo **match_info, - GError **error) -{ - GMatchInfo *info; - gboolean done; - - g_return_val_if_fail (regex != NULL, FALSE); - g_return_val_if_fail (string != NULL, FALSE); - g_return_val_if_fail (start_position >= 0, FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - g_return_val_if_fail ((match_options & ~G_REGEX_MATCH_MASK) == 0, FALSE); - - info = match_info_new (regex, string, string_len, start_position, - match_options, TRUE); - - done = FALSE; - while (!done) - { - done = TRUE; - info->matches = pcre_dfa_exec (regex->pcre_re, regex->extra, - info->string, info->string_len, - info->pos, - regex->match_opts | match_options, - info->offsets, info->n_offsets, - info->workspace, info->n_workspace); - if (info->matches == PCRE_ERROR_DFA_WSSIZE) - { - /* info->workspace is too small. */ - info->n_workspace *= 2; - info->workspace = g_realloc (info->workspace, - info->n_workspace * sizeof (gint)); - done = FALSE; - } - else if (info->matches == 0) - { - /* info->offsets is too small. */ - info->n_offsets *= 2; - info->offsets = g_realloc (info->offsets, - info->n_offsets * sizeof (gint)); - done = FALSE; - } - else if (IS_PCRE_ERROR (info->matches)) - { - g_set_error (error, G_REGEX_ERROR, G_REGEX_ERROR_MATCH, - _("Error while matching regular expression %s: %s"), - regex->pattern, match_error (info->matches)); - } - } - - /* set info->pos to -1 so that a call to g_match_info_next() fails. */ - info->pos = -1; - - if (match_info != NULL) - *match_info = info; - else - g_match_info_free (info); - - return info->matches >= 0; -} - -/** - * g_regex_get_string_number: - * @regex: #GRegex structure - * @name: name of the subexpression - * - * Retrieves the number of the subexpression named @name. - * - * Returns: The number of the subexpression or -1 if @name - * does not exists - * - * Since: 2.14 - */ -gint -g_regex_get_string_number (const GRegex *regex, - const gchar *name) -{ - gint num; - - g_return_val_if_fail (regex != NULL, -1); - g_return_val_if_fail (name != NULL, -1); - - num = pcre_get_stringnumber (regex->pcre_re, name); - if (num == PCRE_ERROR_NOSUBSTRING) - num = -1; - - return num; -} - -/** - * g_regex_split_simple: - * @pattern: the regular expression - * @string: the string to scan for matches - * @compile_options: compile options for the regular expression, or 0 - * @match_options: match options, or 0 - * - * Breaks the string on the pattern, and returns an array of - * the tokens. If the pattern contains capturing parentheses, - * then the text for each of the substrings will also be returned. - * If the pattern does not match anywhere in the string, then the - * whole string is returned as the first token. - * - * This function is equivalent to g_regex_split() but it does - * not require to compile the pattern with g_regex_new(), avoiding - * some lines of code when you need just to do a split without - * extracting substrings, capture counts, and so on. - * - * If this function is to be called on the same @pattern more than - * once, it's more efficient to compile the pattern once with - * g_regex_new() and then use g_regex_split(). - * - * As a special case, the result of splitting the empty string "" - * is an empty vector, not a vector containing a single string. - * The reason for this special case is that being able to represent - * a empty vector is typically more useful than consistent handling - * of empty elements. If you do need to represent empty elements, - * you'll need to check for the empty string before calling this - * function. - * - * A pattern that can match empty strings splits @string into - * separate characters wherever it matches the empty string between - * characters. For example splitting "ab c" using as a separator - * "\s*", you will get "a", "b" and "c". - * - * Returns: a %NULL-terminated array of strings. Free it using g_strfreev() - * - * Since: 2.14 - **/ -gchar ** -g_regex_split_simple (const gchar *pattern, - const gchar *string, - GRegexCompileFlags compile_options, - GRegexMatchFlags match_options) -{ - GRegex *regex; - gchar **result; - - regex = g_regex_new (pattern, compile_options, 0, NULL); - if (!regex) - return NULL; - result = g_regex_split_full (regex, string, -1, 0, match_options, 0, NULL); - g_regex_unref (regex); - return result; -} - -/** - * g_regex_split: - * @regex: a #GRegex structure - * @string: the string to split with the pattern - * @match_options: match time option flags - * - * Breaks the string on the pattern, and returns an array of the tokens. - * If the pattern contains capturing parentheses, then the text for each - * of the substrings will also be returned. If the pattern does not match - * anywhere in the string, then the whole string is returned as the first - * token. - * - * As a special case, the result of splitting the empty string "" is an - * empty vector, not a vector containing a single string. The reason for - * this special case is that being able to represent a empty vector is - * typically more useful than consistent handling of empty elements. If - * you do need to represent empty elements, you'll need to check for the - * empty string before calling this function. - * - * A pattern that can match empty strings splits @string into separate - * characters wherever it matches the empty string between characters. - * For example splitting "ab c" using as a separator "\s*", you will get - * "a", "b" and "c". - * - * Returns: a %NULL-terminated gchar ** array. Free it using g_strfreev() - * - * Since: 2.14 - **/ -gchar ** -g_regex_split (const GRegex *regex, - const gchar *string, - GRegexMatchFlags match_options) -{ - return g_regex_split_full (regex, string, -1, 0, - match_options, 0, NULL); -} - -/** - * g_regex_split_full: - * @regex: a #GRegex structure - * @string: the string to split with the pattern - * @string_len: the length of @string, or -1 if @string is nul-terminated - * @start_position: starting index of the string to match - * @match_options: match time option flags - * @max_tokens: the maximum number of tokens to split @string into. - * If this is less than 1, the string is split completely - * @error: return location for a #GError - * - * Breaks the string on the pattern, and returns an array of the tokens. - * If the pattern contains capturing parentheses, then the text for each - * of the substrings will also be returned. If the pattern does not match - * anywhere in the string, then the whole string is returned as the first - * token. - * - * As a special case, the result of splitting the empty string "" is an - * empty vector, not a vector containing a single string. The reason for - * this special case is that being able to represent a empty vector is - * typically more useful than consistent handling of empty elements. If - * you do need to represent empty elements, you'll need to check for the - * empty string before calling this function. - * - * A pattern that can match empty strings splits @string into separate - * characters wherever it matches the empty string between characters. - * For example splitting "ab c" using as a separator "\s*", you will get - * "a", "b" and "c". - * - * Setting @start_position differs from just passing over a shortened - * string and setting #G_REGEX_MATCH_NOTBOL in the case of a pattern - * that begins with any kind of lookbehind assertion, such as "\b". - * - * Returns: a %NULL-terminated gchar ** array. Free it using g_strfreev() - * - * Since: 2.14 - **/ -gchar ** -g_regex_split_full (const GRegex *regex, - const gchar *string, - gssize string_len, - gint start_position, - GRegexMatchFlags match_options, - gint max_tokens, - GError **error) -{ - GError *tmp_error = NULL; - GMatchInfo *match_info; - GList *list, *last; - gint i; - gint token_count; - gboolean match_ok; - /* position of the last separator. */ - gint last_separator_end; - /* was the last match 0 bytes long? */ - gboolean last_match_is_empty; - /* the returned array of char **s */ - gchar **string_list; - - g_return_val_if_fail (regex != NULL, NULL); - g_return_val_if_fail (string != NULL, NULL); - g_return_val_if_fail (start_position >= 0, NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - g_return_val_if_fail ((match_options & ~G_REGEX_MATCH_MASK) == 0, NULL); - - if (max_tokens <= 0) - max_tokens = G_MAXINT; - - if (string_len < 0) - string_len = strlen (string); - - /* zero-length string */ - if (string_len - start_position == 0) - return g_new0 (gchar *, 1); - - if (max_tokens == 1) - { - string_list = g_new0 (gchar *, 2); - string_list[0] = g_strndup (&string[start_position], - string_len - start_position); - return string_list; - } - - list = NULL; - token_count = 0; - last_separator_end = start_position; - last_match_is_empty = FALSE; - - match_ok = g_regex_match_full (regex, string, string_len, start_position, - match_options, &match_info, &tmp_error); - while (tmp_error == NULL) - { - if (match_ok) - { - last_match_is_empty = - (match_info->offsets[0] == match_info->offsets[1]); - - /* we need to skip empty separators at the same position of the end - * of another separator. e.g. the string is "a b" and the separator - * is " *", so from 1 to 2 we have a match and at position 2 we have - * an empty match. */ - if (last_separator_end != match_info->offsets[1]) - { - gchar *token; - gint match_count; - - token = g_strndup (string + last_separator_end, - match_info->offsets[0] - last_separator_end); - list = g_list_prepend (list, token); - token_count++; - - /* if there were substrings, these need to be added to - * the list. */ - match_count = g_match_info_get_match_count (match_info); - if (match_count > 1) - { - for (i = 1; i < match_count; i++) - list = g_list_prepend (list, g_match_info_fetch (match_info, i)); - } - } - } - else - { - /* if there was no match, copy to end of string. */ - if (!last_match_is_empty) - { - gchar *token = g_strndup (string + last_separator_end, - match_info->string_len - last_separator_end); - list = g_list_prepend (list, token); - } - /* no more tokens, end the loop. */ - break; - } - - /* -1 to leave room for the last part. */ - if (token_count >= max_tokens - 1) - { - /* we have reached the maximum number of tokens, so we copy - * the remaining part of the string. */ - if (last_match_is_empty) - { - /* the last match was empty, so we have moved one char - * after the real position to avoid empty matches at the - * same position. */ - match_info->pos = PREV_CHAR (regex, &string[match_info->pos]) - string; - } - /* the if is needed in the case we have terminated the available - * tokens, but we are at the end of the string, so there are no - * characters left to copy. */ - if (string_len > match_info->pos) - { - gchar *token = g_strndup (string + match_info->pos, - string_len - match_info->pos); - list = g_list_prepend (list, token); - } - /* end the loop. */ - break; - } - - last_separator_end = match_info->pos; - if (last_match_is_empty) - /* if the last match was empty, g_match_info_next() has moved - * forward to avoid infinite loops, but we still need to copy that - * character. */ - last_separator_end = PREV_CHAR (regex, &string[last_separator_end]) - string; - - match_ok = g_match_info_next (match_info, &tmp_error); - } - g_match_info_free (match_info); - if (tmp_error != NULL) - { - g_propagate_error (error, tmp_error); - g_list_foreach (list, (GFunc)g_free, NULL); - g_list_free (list); - match_info->pos = -1; - return NULL; - } - - string_list = g_new (gchar *, g_list_length (list) + 1); - i = 0; - for (last = g_list_last (list); last; last = g_list_previous (last)) - string_list[i++] = last->data; - string_list[i] = NULL; - g_list_free (list); - - return string_list; -} - -enum -{ - REPL_TYPE_STRING, - REPL_TYPE_CHARACTER, - REPL_TYPE_SYMBOLIC_REFERENCE, - REPL_TYPE_NUMERIC_REFERENCE, - REPL_TYPE_CHANGE_CASE -}; - -typedef enum -{ - CHANGE_CASE_NONE = 1 << 0, - CHANGE_CASE_UPPER = 1 << 1, - CHANGE_CASE_LOWER = 1 << 2, - CHANGE_CASE_UPPER_SINGLE = 1 << 3, - CHANGE_CASE_LOWER_SINGLE = 1 << 4, - CHANGE_CASE_SINGLE_MASK = CHANGE_CASE_UPPER_SINGLE | CHANGE_CASE_LOWER_SINGLE, - CHANGE_CASE_LOWER_MASK = CHANGE_CASE_LOWER | CHANGE_CASE_LOWER_SINGLE, - CHANGE_CASE_UPPER_MASK = CHANGE_CASE_UPPER | CHANGE_CASE_UPPER_SINGLE -} ChangeCase; - -struct _InterpolationData -{ - gchar *text; - gint type; - gint num; - gchar c; - ChangeCase change_case; -}; - -static void -free_interpolation_data (InterpolationData *data) -{ - g_free (data->text); - g_free (data); -} - -static const gchar * -expand_escape (const gchar *replacement, - const gchar *p, - InterpolationData *data, - GError **error) -{ - const gchar *q, *r; - gint x, d, h, i; - const gchar *error_detail; - gint base = 0; - GError *tmp_error = NULL; - - p++; - switch (*p) - { - case 't': - p++; - data->c = '\t'; - data->type = REPL_TYPE_CHARACTER; - break; - case 'n': - p++; - data->c = '\n'; - data->type = REPL_TYPE_CHARACTER; - break; - case 'v': - p++; - data->c = '\v'; - data->type = REPL_TYPE_CHARACTER; - break; - case 'r': - p++; - data->c = '\r'; - data->type = REPL_TYPE_CHARACTER; - break; - case 'f': - p++; - data->c = '\f'; - data->type = REPL_TYPE_CHARACTER; - break; - case 'a': - p++; - data->c = '\a'; - data->type = REPL_TYPE_CHARACTER; - break; - case 'b': - p++; - data->c = '\b'; - data->type = REPL_TYPE_CHARACTER; - break; - case '\\': - p++; - data->c = '\\'; - data->type = REPL_TYPE_CHARACTER; - break; - case 'x': - p++; - x = 0; - if (*p == '{') - { - p++; - do - { - h = g_ascii_xdigit_value (*p); - if (h < 0) - { - error_detail = _("hexadecimal digit or '}' expected"); - goto error; - } - x = x * 16 + h; - p++; - } - while (*p != '}'); - p++; - } - else - { - for (i = 0; i < 2; i++) - { - h = g_ascii_xdigit_value (*p); - if (h < 0) - { - error_detail = _("hexadecimal digit expected"); - goto error; - } - x = x * 16 + h; - p++; - } - } - data->type = REPL_TYPE_STRING; - data->text = g_new0 (gchar, 8); - g_unichar_to_utf8 (x, data->text); - break; - case 'l': - p++; - data->type = REPL_TYPE_CHANGE_CASE; - data->change_case = CHANGE_CASE_LOWER_SINGLE; - break; - case 'u': - p++; - data->type = REPL_TYPE_CHANGE_CASE; - data->change_case = CHANGE_CASE_UPPER_SINGLE; - break; - case 'L': - p++; - data->type = REPL_TYPE_CHANGE_CASE; - data->change_case = CHANGE_CASE_LOWER; - break; - case 'U': - p++; - data->type = REPL_TYPE_CHANGE_CASE; - data->change_case = CHANGE_CASE_UPPER; - break; - case 'E': - p++; - data->type = REPL_TYPE_CHANGE_CASE; - data->change_case = CHANGE_CASE_NONE; - break; - case 'g': - p++; - if (*p != '<') - { - error_detail = _("missing '<' in symbolic reference"); - goto error; - } - q = p + 1; - do - { - p++; - if (!*p) - { - error_detail = _("unfinished symbolic reference"); - goto error; - } - } - while (*p != '>'); - if (p - q == 0) - { - error_detail = _("zero-length symbolic reference"); - goto error; - } - if (g_ascii_isdigit (*q)) - { - x = 0; - do - { - h = g_ascii_digit_value (*q); - if (h < 0) - { - error_detail = _("digit expected"); - p = q; - goto error; - } - x = x * 10 + h; - q++; - } - while (q != p); - data->num = x; - data->type = REPL_TYPE_NUMERIC_REFERENCE; - } - else - { - r = q; - do - { - if (!g_ascii_isalnum (*r)) - { - error_detail = _("illegal symbolic reference"); - p = r; - goto error; - } - r++; - } - while (r != p); - data->text = g_strndup (q, p - q); - data->type = REPL_TYPE_SYMBOLIC_REFERENCE; - } - p++; - break; - case '0': - /* if \0 is followed by a number is an octal number representing a - * character, else it is a numeric reference. */ - if (g_ascii_digit_value (*g_utf8_next_char (p)) >= 0) - { - base = 8; - p = g_utf8_next_char (p); - } - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - x = 0; - d = 0; - for (i = 0; i < 3; i++) - { - h = g_ascii_digit_value (*p); - if (h < 0) - break; - if (h > 7) - { - if (base == 8) - break; - else - base = 10; - } - if (i == 2 && base == 10) - break; - x = x * 8 + h; - d = d * 10 + h; - p++; - } - if (base == 8 || i == 3) - { - data->type = REPL_TYPE_STRING; - data->text = g_new0 (gchar, 8); - g_unichar_to_utf8 (x, data->text); - } - else - { - data->type = REPL_TYPE_NUMERIC_REFERENCE; - data->num = d; - } - break; - case 0: - error_detail = _("stray final '\\'"); - goto error; - break; - default: - error_detail = _("unknown escape sequence"); - goto error; - } - - return p; - - error: - /* G_GSSIZE_FORMAT doesn't work with gettext, so we use %lu */ - tmp_error = g_error_new (G_REGEX_ERROR, - G_REGEX_ERROR_REPLACE, - _("Error while parsing replacement " - "text \"%s\" at char %lu: %s"), - replacement, - (gulong)(p - replacement), - error_detail); - g_propagate_error (error, tmp_error); - - return NULL; -} - -static GList * -split_replacement (const gchar *replacement, - GError **error) -{ - GList *list = NULL; - InterpolationData *data; - const gchar *p, *start; - - start = p = replacement; - while (*p) - { - if (*p == '\\') - { - data = g_new0 (InterpolationData, 1); - start = p = expand_escape (replacement, p, data, error); - if (p == NULL) - { - g_list_foreach (list, (GFunc)free_interpolation_data, NULL); - g_list_free (list); - free_interpolation_data (data); - - return NULL; - } - list = g_list_prepend (list, data); - } - else - { - p++; - if (*p == '\\' || *p == '\0') - { - if (p - start > 0) - { - data = g_new0 (InterpolationData, 1); - data->text = g_strndup (start, p - start); - data->type = REPL_TYPE_STRING; - list = g_list_prepend (list, data); - } - } - } - } - - return g_list_reverse (list); -} - -/* Change the case of c based on change_case. */ -#define CHANGE_CASE(c, change_case) \ - (((change_case) & CHANGE_CASE_LOWER_MASK) ? \ - g_unichar_tolower (c) : \ - g_unichar_toupper (c)) - -static void -string_append (GString *string, - const gchar *text, - ChangeCase *change_case) -{ - gunichar c; - - if (text[0] == '\0') - return; - - if (*change_case == CHANGE_CASE_NONE) - { - g_string_append (string, text); - } - else if (*change_case & CHANGE_CASE_SINGLE_MASK) - { - c = g_utf8_get_char (text); - g_string_append_unichar (string, CHANGE_CASE (c, *change_case)); - g_string_append (string, g_utf8_next_char (text)); - *change_case = CHANGE_CASE_NONE; - } - else - { - while (*text != '\0') - { - c = g_utf8_get_char (text); - g_string_append_unichar (string, CHANGE_CASE (c, *change_case)); - text = g_utf8_next_char (text); - } - } -} - -static gboolean -interpolate_replacement (const GMatchInfo *match_info, - GString *result, - gpointer data) -{ - GList *list; - InterpolationData *idata; - gchar *match; - ChangeCase change_case = CHANGE_CASE_NONE; - - for (list = data; list; list = list->next) - { - idata = list->data; - switch (idata->type) - { - case REPL_TYPE_STRING: - string_append (result, idata->text, &change_case); - break; - case REPL_TYPE_CHARACTER: - g_string_append_c (result, CHANGE_CASE (idata->c, change_case)); - if (change_case & CHANGE_CASE_SINGLE_MASK) - change_case = CHANGE_CASE_NONE; - break; - case REPL_TYPE_NUMERIC_REFERENCE: - match = g_match_info_fetch (match_info, idata->num); - if (match) - { - string_append (result, match, &change_case); - g_free (match); - } - break; - case REPL_TYPE_SYMBOLIC_REFERENCE: - match = g_match_info_fetch_named (match_info, idata->text); - if (match) - { - string_append (result, match, &change_case); - g_free (match); - } - break; - case REPL_TYPE_CHANGE_CASE: - change_case = idata->change_case; - break; - } - } - - return FALSE; -} - -/* whether actual match_info is needed for replacement, i.e. - * whether there are references - */ -static gboolean -interpolation_list_needs_match (GList *list) -{ - while (list != NULL) - { - InterpolationData *data = list->data; - - if (data->type == REPL_TYPE_SYMBOLIC_REFERENCE || - data->type == REPL_TYPE_NUMERIC_REFERENCE) - { - return TRUE; - } - - list = list->next; - } - - return FALSE; -} - -/** - * g_regex_replace: - * @regex: a #GRegex structure - * @string: the string to perform matches against - * @string_len: the length of @string, or -1 if @string is nul-terminated - * @start_position: starting index of the string to match - * @replacement: text to replace each match with - * @match_options: options for the match - * @error: location to store the error occuring, or %NULL to ignore errors - * - * Replaces all occurrences of the pattern in @regex with the - * replacement text. Backreferences of the form '\number' or - * '\g<number>' in the replacement text are interpolated by the - * number-th captured subexpression of the match, '\g<name>' refers - * to the captured subexpression with the given name. '\0' refers to the - * complete match, but '\0' followed by a number is the octal representation - * of a character. To include a literal '\' in the replacement, write '\\'. - * There are also escapes that changes the case of the following text: - * - * <variablelist> - * <varlistentry><term>\l</term> - * <listitem> - * <para>Convert to lower case the next character</para> - * </listitem> - * </varlistentry> - * <varlistentry><term>\u</term> - * <listitem> - * <para>Convert to upper case the next character</para> - * </listitem> - * </varlistentry> - * <varlistentry><term>\L</term> - * <listitem> - * <para>Convert to lower case till \E</para> - * </listitem> - * </varlistentry> - * <varlistentry><term>\U</term> - * <listitem> - * <para>Convert to upper case till \E</para> - * </listitem> - * </varlistentry> - * <varlistentry><term>\E</term> - * <listitem> - * <para>End case modification</para> - * </listitem> - * </varlistentry> - * </variablelist> - * - * If you do not need to use backreferences use g_regex_replace_literal(). - * - * The @replacement string must be UTF-8 encoded even if #G_REGEX_RAW was - * passed to g_regex_new(). If you want to use not UTF-8 encoded stings - * you can use g_regex_replace_literal(). - * - * Setting @start_position differs from just passing over a shortened - * string and setting #G_REGEX_MATCH_NOTBOL in the case of a pattern that - * begins with any kind of lookbehind assertion, such as "\b". - * - * Returns: a newly allocated string containing the replacements - * - * Since: 2.14 - */ -gchar * -g_regex_replace (const GRegex *regex, - const gchar *string, - gssize string_len, - gint start_position, - const gchar *replacement, - GRegexMatchFlags match_options, - GError **error) -{ - gchar *result; - GList *list; - GError *tmp_error = NULL; - - g_return_val_if_fail (regex != NULL, NULL); - g_return_val_if_fail (string != NULL, NULL); - g_return_val_if_fail (start_position >= 0, NULL); - g_return_val_if_fail (replacement != NULL, NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - g_return_val_if_fail ((match_options & ~G_REGEX_MATCH_MASK) == 0, NULL); - - list = split_replacement (replacement, &tmp_error); - if (tmp_error != NULL) - { - g_propagate_error (error, tmp_error); - return NULL; - } - - result = g_regex_replace_eval (regex, - string, string_len, start_position, - match_options, - interpolate_replacement, - (gpointer)list, - &tmp_error); - if (tmp_error != NULL) - g_propagate_error (error, tmp_error); - - g_list_foreach (list, (GFunc)free_interpolation_data, NULL); - g_list_free (list); - - return result; -} - -static gboolean -literal_replacement (const GMatchInfo *match_info, - GString *result, - gpointer data) -{ - g_string_append (result, data); - return FALSE; -} - -/** - * g_regex_replace_literal: - * @regex: a #GRegex structure - * @string: the string to perform matches against - * @string_len: the length of @string, or -1 if @string is nul-terminated - * @start_position: starting index of the string to match - * @replacement: text to replace each match with - * @match_options: options for the match - * @error: location to store the error occuring, or %NULL to ignore errors - * - * Replaces all occurrences of the pattern in @regex with the - * replacement text. @replacement is replaced literally, to - * include backreferences use g_regex_replace(). - * - * Setting @start_position differs from just passing over a - * shortened string and setting #G_REGEX_MATCH_NOTBOL in the - * case of a pattern that begins with any kind of lookbehind - * assertion, such as "\b". - * - * Returns: a newly allocated string containing the replacements - * - * Since: 2.14 - */ -gchar * -g_regex_replace_literal (const GRegex *regex, - const gchar *string, - gssize string_len, - gint start_position, - const gchar *replacement, - GRegexMatchFlags match_options, - GError **error) -{ - g_return_val_if_fail (replacement != NULL, NULL); - g_return_val_if_fail ((match_options & ~G_REGEX_MATCH_MASK) == 0, NULL); - - return g_regex_replace_eval (regex, - string, string_len, start_position, - match_options, - literal_replacement, - (gpointer)replacement, - error); -} - -/** - * g_regex_replace_eval: - * @regex: a #GRegex structure from g_regex_new() - * @string: string to perform matches against - * @string_len: the length of @string, or -1 if @string is nul-terminated - * @start_position: starting index of the string to match - * @match_options: options for the match - * @eval: a function to call for each match - * @user_data: user data to pass to the function - * @error: location to store the error occuring, or %NULL to ignore errors - * - * Replaces occurrences of the pattern in regex with the output of - * @eval for that occurrence. - * - * Setting @start_position differs from just passing over a shortened - * string and setting #G_REGEX_MATCH_NOTBOL in the case of a pattern - * that begins with any kind of lookbehind assertion, such as "\b". - * - * The following example uses g_regex_replace_eval() to replace multiple - * strings at once: - * |[ - * static gboolean - * eval_cb (const GMatchInfo *info, - * GString *res, - * gpointer data) - * { - * gchar *match; - * gchar *r; - * - * match = g_match_info_fetch (info, 0); - * r = g_hash_table_lookup ((GHashTable *)data, match); - * g_string_append (res, r); - * g_free (match); - * - * return FALSE; - * } - * - * /* ... */ - * - * GRegex *reg; - * GHashTable *h; - * gchar *res; - * - * h = g_hash_table_new (g_str_hash, g_str_equal); - * - * g_hash_table_insert (h, "1", "ONE"); - * g_hash_table_insert (h, "2", "TWO"); - * g_hash_table_insert (h, "3", "THREE"); - * g_hash_table_insert (h, "4", "FOUR"); - * - * reg = g_regex_new ("1|2|3|4", 0, 0, NULL); - * res = g_regex_replace_eval (reg, text, -1, 0, 0, eval_cb, h, NULL); - * g_hash_table_destroy (h); - * - * /* ... */ - * ]| - * - * Returns: a newly allocated string containing the replacements - * - * Since: 2.14 - */ -gchar * -g_regex_replace_eval (const GRegex *regex, - const gchar *string, - gssize string_len, - gint start_position, - GRegexMatchFlags match_options, - GRegexEvalCallback eval, - gpointer user_data, - GError **error) -{ - GMatchInfo *match_info; - GString *result; - gint str_pos = 0; - gboolean done = FALSE; - GError *tmp_error = NULL; - - g_return_val_if_fail (regex != NULL, NULL); - g_return_val_if_fail (string != NULL, NULL); - g_return_val_if_fail (start_position >= 0, NULL); - g_return_val_if_fail (eval != NULL, NULL); - g_return_val_if_fail ((match_options & ~G_REGEX_MATCH_MASK) == 0, NULL); - - if (string_len < 0) - string_len = strlen (string); - - result = g_string_sized_new (string_len); - - /* run down the string making matches. */ - g_regex_match_full (regex, string, string_len, start_position, - match_options, &match_info, &tmp_error); - while (!done && g_match_info_matches (match_info)) - { - g_string_append_len (result, - string + str_pos, - match_info->offsets[0] - str_pos); - done = (*eval) (match_info, result, user_data); - str_pos = match_info->offsets[1]; - g_match_info_next (match_info, &tmp_error); - } - g_match_info_free (match_info); - if (tmp_error != NULL) - { - g_propagate_error (error, tmp_error); - g_string_free (result, TRUE); - return NULL; - } - - g_string_append_len (result, string + str_pos, string_len - str_pos); - return g_string_free (result, FALSE); -} - -/** - * g_regex_check_replacement: - * @replacement: the replacement string - * @has_references: location to store information about - * references in @replacement or %NULL - * @error: location to store error - * - * Checks whether @replacement is a valid replacement string - * (see g_regex_replace()), i.e. that all escape sequences in - * it are valid. - * - * If @has_references is not %NULL then @replacement is checked - * for pattern references. For instance, replacement text 'foo\n' - * does not contain references and may be evaluated without information - * about actual match, but '\0\1' (whole match followed by first - * subpattern) requires valid #GMatchInfo object. - * - * Returns: whether @replacement is a valid replacement string - * - * Since: 2.14 - */ -gboolean -g_regex_check_replacement (const gchar *replacement, - gboolean *has_references, - GError **error) -{ - GList *list; - GError *tmp = NULL; - - list = split_replacement (replacement, &tmp); - - if (tmp) - { - g_propagate_error (error, tmp); - return FALSE; - } - - if (has_references) - *has_references = interpolation_list_needs_match (list); - - g_list_foreach (list, (GFunc) free_interpolation_data, NULL); - g_list_free (list); - - return TRUE; -} - -/** - * g_regex_escape_string: - * @string: the string to escape - * @length: the length of @string, or -1 if @string is nul-terminated - * - * Escapes the special characters used for regular expressions - * in @string, for instance "a.b*c" becomes "a\.b\*c". This - * function is useful to dynamically generate regular expressions. - * - * @string can contain nul characters that are replaced with "\0", - * in this case remember to specify the correct length of @string - * in @length. - * - * Returns: a newly-allocated escaped string - * - * Since: 2.14 - */ -gchar * -g_regex_escape_string (const gchar *string, - gint length) -{ - GString *escaped; - const char *p, *piece_start, *end; - - g_return_val_if_fail (string != NULL, NULL); - - if (length < 0) - length = strlen (string); - - end = string + length; - p = piece_start = string; - escaped = g_string_sized_new (length + 1); - - while (p < end) - { - switch (*p) - { - case '\0': - case '\\': - case '|': - case '(': - case ')': - case '[': - case ']': - case '{': - case '}': - case '^': - case '$': - case '*': - case '+': - case '?': - case '.': - if (p != piece_start) - /* copy the previous piece. */ - g_string_append_len (escaped, piece_start, p - piece_start); - g_string_append_c (escaped, '\\'); - if (*p == '\0') - g_string_append_c (escaped, '0'); - else - g_string_append_c (escaped, *p); - piece_start = ++p; - break; - default: - p = g_utf8_next_char (p); - break; - } - } - - if (piece_start < end) - g_string_append_len (escaped, piece_start, end - piece_start); - - return g_string_free (escaped, FALSE); -} - -#define __G_REGEX_C__ -#include "galiasdef.c" diff --git a/glib/grel.c b/glib/grel.c deleted file mode 100644 index b6ee65110..000000000 --- a/glib/grel.c +++ /dev/null @@ -1,484 +0,0 @@ -/* 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 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" - -#include <stdarg.h> -#include <string.h> - -#include "glib.h" -#include "galias.h" - - -typedef struct _GRealTuples GRealTuples; - -struct _GRelation -{ - gint fields; - gint current_field; - - GHashTable *all_tuples; - GHashTable **hashed_tuple_tables; - - gint count; -}; - -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; -} - -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); -} - -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); - } -} - -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); -} - -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; -} - -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; -} - -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; -} - -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); -} - -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; -} - -void -g_tuples_destroy (GTuples *tuples0) -{ - GRealTuples *tuples = (GRealTuples*) tuples0; - - if (tuples) - { - g_free (tuples->data); - g_free (tuples); - } -} - -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); -} - -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); - } - -} - -#define __G_REL_C__ -#include "galiasdef.c" diff --git a/glib/gscanner.c b/glib/gscanner.c deleted file mode 100644 index 233cc73b9..000000000 --- a/glib/gscanner.c +++ /dev/null @@ -1,1767 +0,0 @@ -/* GLIB - Library of useful routines for C programming - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * GScanner: Flexible lexical scanner for general purpose. - * Copyright (C) 1997, 1998 Tim Janik - * - * 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, 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" - -#include <errno.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <stdio.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#include "glib.h" -#include "gprintfint.h" -#include "galias.h" - -#ifdef G_OS_WIN32 -#include <io.h> /* For _read() */ -#endif - -/* --- defines --- */ -#define to_lower(c) ( \ - (guchar) ( \ - ( (((guchar)(c))>='A' && ((guchar)(c))<='Z') * ('a'-'A') ) | \ - ( (((guchar)(c))>=192 && ((guchar)(c))<=214) * (224-192) ) | \ - ( (((guchar)(c))>=216 && ((guchar)(c))<=222) * (248-216) ) | \ - ((guchar)(c)) \ - ) \ -) -#define READ_BUFFER_SIZE (4000) - - -/* --- typedefs --- */ -typedef struct _GScannerKey GScannerKey; - -struct _GScannerKey -{ - guint scope_id; - gchar *symbol; - gpointer value; -}; - - -/* --- variables --- */ -static const GScannerConfig g_scanner_config_template = -{ - ( - " \t\r\n" - ) /* cset_skip_characters */, - ( - G_CSET_a_2_z - "_" - G_CSET_A_2_Z - ) /* cset_identifier_first */, - ( - G_CSET_a_2_z - "_" - G_CSET_A_2_Z - G_CSET_DIGITS - G_CSET_LATINS - G_CSET_LATINC - ) /* cset_identifier_nth */, - ( "#\n" ) /* cpair_comment_single */, - - FALSE /* case_sensitive */, - - TRUE /* skip_comment_multi */, - TRUE /* skip_comment_single */, - TRUE /* scan_comment_multi */, - TRUE /* scan_identifier */, - FALSE /* scan_identifier_1char */, - FALSE /* scan_identifier_NULL */, - TRUE /* scan_symbols */, - FALSE /* scan_binary */, - TRUE /* scan_octal */, - TRUE /* scan_float */, - TRUE /* scan_hex */, - FALSE /* scan_hex_dollar */, - TRUE /* scan_string_sq */, - TRUE /* scan_string_dq */, - TRUE /* numbers_2_int */, - FALSE /* int_2_float */, - FALSE /* identifier_2_string */, - TRUE /* char_2_token */, - FALSE /* symbol_2_token */, - FALSE /* scope_0_fallback */, - FALSE /* store_int64 */, -}; - - -/* --- prototypes --- */ -static inline -GScannerKey* g_scanner_lookup_internal (GScanner *scanner, - guint scope_id, - const gchar *symbol); -static gboolean g_scanner_key_equal (gconstpointer v1, - gconstpointer v2); -static guint g_scanner_key_hash (gconstpointer v); -static void g_scanner_get_token_ll (GScanner *scanner, - GTokenType *token_p, - GTokenValue *value_p, - guint *line_p, - guint *position_p); -static void g_scanner_get_token_i (GScanner *scanner, - GTokenType *token_p, - GTokenValue *value_p, - guint *line_p, - guint *position_p); - -static guchar g_scanner_peek_next_char (GScanner *scanner); -static guchar g_scanner_get_char (GScanner *scanner, - guint *line_p, - guint *position_p); -static void g_scanner_msg_handler (GScanner *scanner, - gchar *message, - gboolean is_error); - - -/* --- functions --- */ -static inline gint -g_scanner_char_2_num (guchar c, - guchar base) -{ - if (c >= '0' && c <= '9') - c -= '0'; - else if (c >= 'A' && c <= 'Z') - c -= 'A' - 10; - else if (c >= 'a' && c <= 'z') - c -= 'a' - 10; - else - return -1; - - if (c < base) - return c; - - return -1; -} - -GScanner* -g_scanner_new (const GScannerConfig *config_templ) -{ - GScanner *scanner; - - if (!config_templ) - config_templ = &g_scanner_config_template; - - scanner = g_new0 (GScanner, 1); - - scanner->user_data = NULL; - scanner->max_parse_errors = 1; - scanner->parse_errors = 0; - scanner->input_name = NULL; - g_datalist_init (&scanner->qdata); - - scanner->config = g_new0 (GScannerConfig, 1); - - scanner->config->case_sensitive = config_templ->case_sensitive; - scanner->config->cset_skip_characters = config_templ->cset_skip_characters; - if (!scanner->config->cset_skip_characters) - scanner->config->cset_skip_characters = ""; - scanner->config->cset_identifier_first = config_templ->cset_identifier_first; - scanner->config->cset_identifier_nth = config_templ->cset_identifier_nth; - scanner->config->cpair_comment_single = config_templ->cpair_comment_single; - scanner->config->skip_comment_multi = config_templ->skip_comment_multi; - scanner->config->skip_comment_single = config_templ->skip_comment_single; - scanner->config->scan_comment_multi = config_templ->scan_comment_multi; - scanner->config->scan_identifier = config_templ->scan_identifier; - scanner->config->scan_identifier_1char = config_templ->scan_identifier_1char; - scanner->config->scan_identifier_NULL = config_templ->scan_identifier_NULL; - scanner->config->scan_symbols = config_templ->scan_symbols; - scanner->config->scan_binary = config_templ->scan_binary; - scanner->config->scan_octal = config_templ->scan_octal; - scanner->config->scan_float = config_templ->scan_float; - scanner->config->scan_hex = config_templ->scan_hex; - scanner->config->scan_hex_dollar = config_templ->scan_hex_dollar; - scanner->config->scan_string_sq = config_templ->scan_string_sq; - scanner->config->scan_string_dq = config_templ->scan_string_dq; - scanner->config->numbers_2_int = config_templ->numbers_2_int; - scanner->config->int_2_float = config_templ->int_2_float; - scanner->config->identifier_2_string = config_templ->identifier_2_string; - scanner->config->char_2_token = config_templ->char_2_token; - scanner->config->symbol_2_token = config_templ->symbol_2_token; - scanner->config->scope_0_fallback = config_templ->scope_0_fallback; - scanner->config->store_int64 = config_templ->store_int64; - - scanner->token = G_TOKEN_NONE; - scanner->value.v_int64 = 0; - scanner->line = 1; - scanner->position = 0; - - scanner->next_token = G_TOKEN_NONE; - scanner->next_value.v_int64 = 0; - scanner->next_line = 1; - scanner->next_position = 0; - - scanner->symbol_table = g_hash_table_new (g_scanner_key_hash, g_scanner_key_equal); - scanner->input_fd = -1; - scanner->text = NULL; - scanner->text_end = NULL; - scanner->buffer = NULL; - scanner->scope_id = 0; - - scanner->msg_handler = g_scanner_msg_handler; - - return scanner; -} - -static inline void -g_scanner_free_value (GTokenType *token_p, - GTokenValue *value_p) -{ - switch (*token_p) - { - case G_TOKEN_STRING: - case G_TOKEN_IDENTIFIER: - case G_TOKEN_IDENTIFIER_NULL: - case G_TOKEN_COMMENT_SINGLE: - case G_TOKEN_COMMENT_MULTI: - g_free (value_p->v_string); - break; - - default: - break; - } - - *token_p = G_TOKEN_NONE; -} - -static void -g_scanner_destroy_symbol_table_entry (gpointer _key, - gpointer _value, - gpointer _data) -{ - GScannerKey *key = _key; - - g_free (key->symbol); - g_free (key); -} - -void -g_scanner_destroy (GScanner *scanner) -{ - g_return_if_fail (scanner != NULL); - - g_datalist_clear (&scanner->qdata); - g_hash_table_foreach (scanner->symbol_table, - g_scanner_destroy_symbol_table_entry, NULL); - g_hash_table_destroy (scanner->symbol_table); - g_scanner_free_value (&scanner->token, &scanner->value); - g_scanner_free_value (&scanner->next_token, &scanner->next_value); - g_free (scanner->config); - g_free (scanner->buffer); - g_free (scanner); -} - -static void -g_scanner_msg_handler (GScanner *scanner, - gchar *message, - gboolean is_error) -{ - g_return_if_fail (scanner != NULL); - - _g_fprintf (stderr, "%s:%d: ", - scanner->input_name ? scanner->input_name : "<memory>", - scanner->line); - if (is_error) - _g_fprintf (stderr, "error: "); - _g_fprintf (stderr, "%s\n", message); -} - -void -g_scanner_error (GScanner *scanner, - const gchar *format, - ...) -{ - g_return_if_fail (scanner != NULL); - g_return_if_fail (format != NULL); - - scanner->parse_errors++; - - if (scanner->msg_handler) - { - va_list args; - gchar *string; - - va_start (args, format); - string = g_strdup_vprintf (format, args); - va_end (args); - - scanner->msg_handler (scanner, string, TRUE); - - g_free (string); - } -} - -void -g_scanner_warn (GScanner *scanner, - const gchar *format, - ...) -{ - g_return_if_fail (scanner != NULL); - g_return_if_fail (format != NULL); - - if (scanner->msg_handler) - { - va_list args; - gchar *string; - - va_start (args, format); - string = g_strdup_vprintf (format, args); - va_end (args); - - scanner->msg_handler (scanner, string, FALSE); - - g_free (string); - } -} - -static gboolean -g_scanner_key_equal (gconstpointer v1, - gconstpointer v2) -{ - const GScannerKey *key1 = v1; - const GScannerKey *key2 = v2; - - return (key1->scope_id == key2->scope_id) && (strcmp (key1->symbol, key2->symbol) == 0); -} - -static guint -g_scanner_key_hash (gconstpointer v) -{ - const GScannerKey *key = v; - gchar *c; - guint h; - - h = key->scope_id; - for (c = key->symbol; *c; c++) - h = (h << 5) - h + *c; - - return h; -} - -static inline GScannerKey* -g_scanner_lookup_internal (GScanner *scanner, - guint scope_id, - const gchar *symbol) -{ - GScannerKey *key_p; - GScannerKey key; - - key.scope_id = scope_id; - - if (!scanner->config->case_sensitive) - { - gchar *d; - const gchar *c; - - key.symbol = g_new (gchar, strlen (symbol) + 1); - for (d = key.symbol, c = symbol; *c; c++, d++) - *d = to_lower (*c); - *d = 0; - key_p = g_hash_table_lookup (scanner->symbol_table, &key); - g_free (key.symbol); - } - else - { - key.symbol = (gchar*) symbol; - key_p = g_hash_table_lookup (scanner->symbol_table, &key); - } - - return key_p; -} - -void -g_scanner_scope_add_symbol (GScanner *scanner, - guint scope_id, - const gchar *symbol, - gpointer value) -{ - GScannerKey *key; - - g_return_if_fail (scanner != NULL); - g_return_if_fail (symbol != NULL); - - key = g_scanner_lookup_internal (scanner, scope_id, symbol); - - if (!key) - { - key = g_new (GScannerKey, 1); - key->scope_id = scope_id; - key->symbol = g_strdup (symbol); - key->value = value; - if (!scanner->config->case_sensitive) - { - gchar *c; - - c = key->symbol; - while (*c != 0) - { - *c = to_lower (*c); - c++; - } - } - g_hash_table_insert (scanner->symbol_table, key, key); - } - else - key->value = value; -} - -void -g_scanner_scope_remove_symbol (GScanner *scanner, - guint scope_id, - const gchar *symbol) -{ - GScannerKey *key; - - g_return_if_fail (scanner != NULL); - g_return_if_fail (symbol != NULL); - - key = g_scanner_lookup_internal (scanner, scope_id, symbol); - - if (key) - { - g_hash_table_remove (scanner->symbol_table, key); - g_free (key->symbol); - g_free (key); - } -} - -gpointer -g_scanner_lookup_symbol (GScanner *scanner, - const gchar *symbol) -{ - GScannerKey *key; - guint scope_id; - - g_return_val_if_fail (scanner != NULL, NULL); - - if (!symbol) - return NULL; - - scope_id = scanner->scope_id; - key = g_scanner_lookup_internal (scanner, scope_id, symbol); - if (!key && scope_id && scanner->config->scope_0_fallback) - key = g_scanner_lookup_internal (scanner, 0, symbol); - - if (key) - return key->value; - else - return NULL; -} - -gpointer -g_scanner_scope_lookup_symbol (GScanner *scanner, - guint scope_id, - const gchar *symbol) -{ - GScannerKey *key; - - g_return_val_if_fail (scanner != NULL, NULL); - - if (!symbol) - return NULL; - - key = g_scanner_lookup_internal (scanner, scope_id, symbol); - - if (key) - return key->value; - else - return NULL; -} - -guint -g_scanner_set_scope (GScanner *scanner, - guint scope_id) -{ - guint old_scope_id; - - g_return_val_if_fail (scanner != NULL, 0); - - old_scope_id = scanner->scope_id; - scanner->scope_id = scope_id; - - return old_scope_id; -} - -static void -g_scanner_foreach_internal (gpointer _key, - gpointer _value, - gpointer _user_data) -{ - GScannerKey *key; - gpointer *d; - GHFunc func; - gpointer user_data; - guint *scope_id; - - d = _user_data; - func = (GHFunc) d[0]; - user_data = d[1]; - scope_id = d[2]; - key = _value; - - if (key->scope_id == *scope_id) - func (key->symbol, key->value, user_data); -} - -void -g_scanner_scope_foreach_symbol (GScanner *scanner, - guint scope_id, - GHFunc func, - gpointer user_data) -{ - gpointer d[3]; - - g_return_if_fail (scanner != NULL); - - d[0] = (gpointer) func; - d[1] = user_data; - d[2] = &scope_id; - - g_hash_table_foreach (scanner->symbol_table, g_scanner_foreach_internal, d); -} - -GTokenType -g_scanner_peek_next_token (GScanner *scanner) -{ - g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF); - - if (scanner->next_token == G_TOKEN_NONE) - { - scanner->next_line = scanner->line; - scanner->next_position = scanner->position; - g_scanner_get_token_i (scanner, - &scanner->next_token, - &scanner->next_value, - &scanner->next_line, - &scanner->next_position); - } - - return scanner->next_token; -} - -GTokenType -g_scanner_get_next_token (GScanner *scanner) -{ - g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF); - - if (scanner->next_token != G_TOKEN_NONE) - { - g_scanner_free_value (&scanner->token, &scanner->value); - - scanner->token = scanner->next_token; - scanner->value = scanner->next_value; - scanner->line = scanner->next_line; - scanner->position = scanner->next_position; - scanner->next_token = G_TOKEN_NONE; - } - else - g_scanner_get_token_i (scanner, - &scanner->token, - &scanner->value, - &scanner->line, - &scanner->position); - - return scanner->token; -} - -GTokenType -g_scanner_cur_token (GScanner *scanner) -{ - g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF); - - return scanner->token; -} - -GTokenValue -g_scanner_cur_value (GScanner *scanner) -{ - GTokenValue v; - - v.v_int64 = 0; - - g_return_val_if_fail (scanner != NULL, v); - - /* MSC isn't capable of handling return scanner->value; ? */ - - v = scanner->value; - - return v; -} - -guint -g_scanner_cur_line (GScanner *scanner) -{ - g_return_val_if_fail (scanner != NULL, 0); - - return scanner->line; -} - -guint -g_scanner_cur_position (GScanner *scanner) -{ - g_return_val_if_fail (scanner != NULL, 0); - - return scanner->position; -} - -gboolean -g_scanner_eof (GScanner *scanner) -{ - g_return_val_if_fail (scanner != NULL, TRUE); - - return scanner->token == G_TOKEN_EOF || scanner->token == G_TOKEN_ERROR; -} - -void -g_scanner_input_file (GScanner *scanner, - gint input_fd) -{ - g_return_if_fail (scanner != NULL); - g_return_if_fail (input_fd >= 0); - - if (scanner->input_fd >= 0) - g_scanner_sync_file_offset (scanner); - - scanner->token = G_TOKEN_NONE; - scanner->value.v_int64 = 0; - scanner->line = 1; - scanner->position = 0; - scanner->next_token = G_TOKEN_NONE; - - scanner->input_fd = input_fd; - scanner->text = NULL; - scanner->text_end = NULL; - - if (!scanner->buffer) - scanner->buffer = g_new (gchar, READ_BUFFER_SIZE + 1); -} - -void -g_scanner_input_text (GScanner *scanner, - const gchar *text, - guint text_len) -{ - g_return_if_fail (scanner != NULL); - if (text_len) - g_return_if_fail (text != NULL); - else - text = NULL; - - if (scanner->input_fd >= 0) - g_scanner_sync_file_offset (scanner); - - scanner->token = G_TOKEN_NONE; - scanner->value.v_int64 = 0; - scanner->line = 1; - scanner->position = 0; - scanner->next_token = G_TOKEN_NONE; - - scanner->input_fd = -1; - scanner->text = text; - scanner->text_end = text + text_len; - - if (scanner->buffer) - { - g_free (scanner->buffer); - scanner->buffer = NULL; - } -} - -static guchar -g_scanner_peek_next_char (GScanner *scanner) -{ - if (scanner->text < scanner->text_end) - { - return *scanner->text; - } - else if (scanner->input_fd >= 0) - { - gint count; - gchar *buffer; - - buffer = scanner->buffer; - do - { - count = read (scanner->input_fd, buffer, READ_BUFFER_SIZE); - } - while (count == -1 && (errno == EINTR || errno == EAGAIN)); - - if (count < 1) - { - scanner->input_fd = -1; - - return 0; - } - else - { - scanner->text = buffer; - scanner->text_end = buffer + count; - - return *buffer; - } - } - else - return 0; -} - -void -g_scanner_sync_file_offset (GScanner *scanner) -{ - g_return_if_fail (scanner != NULL); - - /* for file input, rewind the filedescriptor to the current - * buffer position and blow the file read ahead buffer. useful - * for third party uses of our file descriptor, which hooks - * onto the current scanning position. - */ - - if (scanner->input_fd >= 0 && scanner->text_end > scanner->text) - { - gint buffered; - - buffered = scanner->text_end - scanner->text; - if (lseek (scanner->input_fd, - buffered, SEEK_CUR) >= 0) - { - /* we succeeded, blow our buffer's contents now */ - scanner->text = NULL; - scanner->text_end = NULL; - } - else - errno = 0; - } -} - -static guchar -g_scanner_get_char (GScanner *scanner, - guint *line_p, - guint *position_p) -{ - guchar fchar; - - if (scanner->text < scanner->text_end) - fchar = *(scanner->text++); - else if (scanner->input_fd >= 0) - { - gint count; - gchar *buffer; - - buffer = scanner->buffer; - do - { - count = read (scanner->input_fd, buffer, READ_BUFFER_SIZE); - } - while (count == -1 && (errno == EINTR || errno == EAGAIN)); - - if (count < 1) - { - scanner->input_fd = -1; - fchar = 0; - } - else - { - scanner->text = buffer + 1; - scanner->text_end = buffer + count; - fchar = *buffer; - if (!fchar) - { - g_scanner_sync_file_offset (scanner); - scanner->text_end = scanner->text; - scanner->input_fd = -1; - } - } - } - else - fchar = 0; - - if (fchar == '\n') - { - (*position_p) = 0; - (*line_p)++; - } - else if (fchar) - { - (*position_p)++; - } - - return fchar; -} - -void -g_scanner_unexp_token (GScanner *scanner, - GTokenType expected_token, - const gchar *identifier_spec, - const gchar *symbol_spec, - const gchar *symbol_name, - const gchar *message, - gint is_error) -{ - gchar *token_string; - guint token_string_len; - gchar *expected_string; - guint expected_string_len; - gchar *message_prefix; - gboolean print_unexp; - void (*msg_handler) (GScanner*, const gchar*, ...); - - g_return_if_fail (scanner != NULL); - - if (is_error) - msg_handler = g_scanner_error; - else - msg_handler = g_scanner_warn; - - if (!identifier_spec) - identifier_spec = "identifier"; - if (!symbol_spec) - symbol_spec = "symbol"; - - token_string_len = 56; - token_string = g_new (gchar, token_string_len + 1); - expected_string_len = 64; - expected_string = g_new (gchar, expected_string_len + 1); - print_unexp = TRUE; - - switch (scanner->token) - { - case G_TOKEN_EOF: - _g_snprintf (token_string, token_string_len, "end of file"); - break; - - default: - if (scanner->token >= 1 && scanner->token <= 255) - { - if ((scanner->token >= ' ' && scanner->token <= '~') || - strchr (scanner->config->cset_identifier_first, scanner->token) || - strchr (scanner->config->cset_identifier_nth, scanner->token)) - _g_snprintf (token_string, token_string_len, "character `%c'", scanner->token); - else - _g_snprintf (token_string, token_string_len, "character `\\%o'", scanner->token); - break; - } - else if (!scanner->config->symbol_2_token) - { - _g_snprintf (token_string, token_string_len, "(unknown) token <%d>", scanner->token); - break; - } - /* fall through */ - case G_TOKEN_SYMBOL: - if (expected_token == G_TOKEN_SYMBOL || - (scanner->config->symbol_2_token && - expected_token > G_TOKEN_LAST)) - print_unexp = FALSE; - if (symbol_name) - _g_snprintf (token_string, - token_string_len, - "%s%s `%s'", - print_unexp ? "" : "invalid ", - symbol_spec, - symbol_name); - else - _g_snprintf (token_string, - token_string_len, - "%s%s", - print_unexp ? "" : "invalid ", - symbol_spec); - break; - - case G_TOKEN_ERROR: - print_unexp = FALSE; - expected_token = G_TOKEN_NONE; - switch (scanner->value.v_error) - { - case G_ERR_UNEXP_EOF: - _g_snprintf (token_string, token_string_len, "scanner: unexpected end of file"); - break; - - case G_ERR_UNEXP_EOF_IN_STRING: - _g_snprintf (token_string, token_string_len, "scanner: unterminated string constant"); - break; - - case G_ERR_UNEXP_EOF_IN_COMMENT: - _g_snprintf (token_string, token_string_len, "scanner: unterminated comment"); - break; - - case G_ERR_NON_DIGIT_IN_CONST: - _g_snprintf (token_string, token_string_len, "scanner: non digit in constant"); - break; - - case G_ERR_FLOAT_RADIX: - _g_snprintf (token_string, token_string_len, "scanner: invalid radix for floating constant"); - break; - - case G_ERR_FLOAT_MALFORMED: - _g_snprintf (token_string, token_string_len, "scanner: malformed floating constant"); - break; - - case G_ERR_DIGIT_RADIX: - _g_snprintf (token_string, token_string_len, "scanner: digit is beyond radix"); - break; - - case G_ERR_UNKNOWN: - default: - _g_snprintf (token_string, token_string_len, "scanner: unknown error"); - break; - } - break; - - case G_TOKEN_CHAR: - _g_snprintf (token_string, token_string_len, "character `%c'", scanner->value.v_char); - break; - - case G_TOKEN_IDENTIFIER: - case G_TOKEN_IDENTIFIER_NULL: - if (expected_token == G_TOKEN_IDENTIFIER || - expected_token == G_TOKEN_IDENTIFIER_NULL) - print_unexp = FALSE; - _g_snprintf (token_string, - token_string_len, - "%s%s `%s'", - print_unexp ? "" : "invalid ", - identifier_spec, - scanner->token == G_TOKEN_IDENTIFIER ? scanner->value.v_string : "null"); - break; - - case G_TOKEN_BINARY: - case G_TOKEN_OCTAL: - case G_TOKEN_INT: - case G_TOKEN_HEX: - if (scanner->config->store_int64) - _g_snprintf (token_string, token_string_len, "number `%" G_GUINT64_FORMAT "'", scanner->value.v_int64); - else - _g_snprintf (token_string, token_string_len, "number `%lu'", scanner->value.v_int); - break; - - case G_TOKEN_FLOAT: - _g_snprintf (token_string, token_string_len, "number `%.3f'", scanner->value.v_float); - break; - - case G_TOKEN_STRING: - if (expected_token == G_TOKEN_STRING) - print_unexp = FALSE; - _g_snprintf (token_string, - token_string_len, - "%s%sstring constant \"%s\"", - print_unexp ? "" : "invalid ", - scanner->value.v_string[0] == 0 ? "empty " : "", - scanner->value.v_string); - token_string[token_string_len - 2] = '"'; - token_string[token_string_len - 1] = 0; - break; - - case G_TOKEN_COMMENT_SINGLE: - case G_TOKEN_COMMENT_MULTI: - _g_snprintf (token_string, token_string_len, "comment"); - break; - - case G_TOKEN_NONE: - /* somehow the user's parsing code is screwed, there isn't much - * we can do about it. - * Note, a common case to trigger this is - * g_scanner_peek_next_token(); g_scanner_unexp_token(); - * without an intermediate g_scanner_get_next_token(). - */ - g_assert_not_reached (); - break; - } - - - switch (expected_token) - { - gboolean need_valid; - gchar *tstring; - case G_TOKEN_EOF: - _g_snprintf (expected_string, expected_string_len, "end of file"); - break; - default: - if (expected_token >= 1 && expected_token <= 255) - { - if ((expected_token >= ' ' && expected_token <= '~') || - strchr (scanner->config->cset_identifier_first, expected_token) || - strchr (scanner->config->cset_identifier_nth, expected_token)) - _g_snprintf (expected_string, expected_string_len, "character `%c'", expected_token); - else - _g_snprintf (expected_string, expected_string_len, "character `\\%o'", expected_token); - break; - } - else if (!scanner->config->symbol_2_token) - { - _g_snprintf (expected_string, expected_string_len, "(unknown) token <%d>", expected_token); - break; - } - /* fall through */ - case G_TOKEN_SYMBOL: - need_valid = (scanner->token == G_TOKEN_SYMBOL || - (scanner->config->symbol_2_token && - scanner->token > G_TOKEN_LAST)); - _g_snprintf (expected_string, - expected_string_len, - "%s%s", - need_valid ? "valid " : "", - symbol_spec); - /* FIXME: should we attempt to lookup the symbol_name for symbol_2_token? */ - break; - case G_TOKEN_CHAR: - _g_snprintf (expected_string, expected_string_len, "%scharacter", - scanner->token == G_TOKEN_CHAR ? "valid " : ""); - break; - case G_TOKEN_BINARY: - tstring = "binary"; - _g_snprintf (expected_string, expected_string_len, "%snumber (%s)", - scanner->token == expected_token ? "valid " : "", tstring); - break; - case G_TOKEN_OCTAL: - tstring = "octal"; - _g_snprintf (expected_string, expected_string_len, "%snumber (%s)", - scanner->token == expected_token ? "valid " : "", tstring); - break; - case G_TOKEN_INT: - tstring = "integer"; - _g_snprintf (expected_string, expected_string_len, "%snumber (%s)", - scanner->token == expected_token ? "valid " : "", tstring); - break; - case G_TOKEN_HEX: - tstring = "hexadecimal"; - _g_snprintf (expected_string, expected_string_len, "%snumber (%s)", - scanner->token == expected_token ? "valid " : "", tstring); - break; - case G_TOKEN_FLOAT: - tstring = "float"; - _g_snprintf (expected_string, expected_string_len, "%snumber (%s)", - scanner->token == expected_token ? "valid " : "", tstring); - break; - case G_TOKEN_STRING: - _g_snprintf (expected_string, - expected_string_len, - "%sstring constant", - scanner->token == G_TOKEN_STRING ? "valid " : ""); - break; - case G_TOKEN_IDENTIFIER: - case G_TOKEN_IDENTIFIER_NULL: - need_valid = (scanner->token == G_TOKEN_IDENTIFIER_NULL || - scanner->token == G_TOKEN_IDENTIFIER); - _g_snprintf (expected_string, - expected_string_len, - "%s%s", - need_valid ? "valid " : "", - identifier_spec); - break; - case G_TOKEN_COMMENT_SINGLE: - tstring = "single-line"; - _g_snprintf (expected_string, expected_string_len, "%scomment (%s)", - scanner->token == expected_token ? "valid " : "", tstring); - break; - case G_TOKEN_COMMENT_MULTI: - tstring = "multi-line"; - _g_snprintf (expected_string, expected_string_len, "%scomment (%s)", - scanner->token == expected_token ? "valid " : "", tstring); - break; - case G_TOKEN_NONE: - case G_TOKEN_ERROR: - /* this is handled upon printout */ - break; - } - - if (message && message[0] != 0) - message_prefix = " - "; - else - { - message_prefix = ""; - message = ""; - } - if (expected_token == G_TOKEN_ERROR) - { - msg_handler (scanner, - "failure around %s%s%s", - token_string, - message_prefix, - message); - } - else if (expected_token == G_TOKEN_NONE) - { - if (print_unexp) - msg_handler (scanner, - "unexpected %s%s%s", - token_string, - message_prefix, - message); - else - msg_handler (scanner, - "%s%s%s", - token_string, - message_prefix, - message); - } - else - { - if (print_unexp) - msg_handler (scanner, - "unexpected %s, expected %s%s%s", - token_string, - expected_string, - message_prefix, - message); - else - msg_handler (scanner, - "%s, expected %s%s%s", - token_string, - expected_string, - message_prefix, - message); - } - - g_free (token_string); - g_free (expected_string); -} - -static void -g_scanner_get_token_i (GScanner *scanner, - GTokenType *token_p, - GTokenValue *value_p, - guint *line_p, - guint *position_p) -{ - do - { - g_scanner_free_value (token_p, value_p); - g_scanner_get_token_ll (scanner, token_p, value_p, line_p, position_p); - } - while (((*token_p > 0 && *token_p < 256) && - strchr (scanner->config->cset_skip_characters, *token_p)) || - (*token_p == G_TOKEN_CHAR && - strchr (scanner->config->cset_skip_characters, value_p->v_char)) || - (*token_p == G_TOKEN_COMMENT_MULTI && - scanner->config->skip_comment_multi) || - (*token_p == G_TOKEN_COMMENT_SINGLE && - scanner->config->skip_comment_single)); - - switch (*token_p) - { - case G_TOKEN_IDENTIFIER: - if (scanner->config->identifier_2_string) - *token_p = G_TOKEN_STRING; - break; - - case G_TOKEN_SYMBOL: - if (scanner->config->symbol_2_token) - *token_p = (GTokenType) value_p->v_symbol; - break; - - case G_TOKEN_BINARY: - case G_TOKEN_OCTAL: - case G_TOKEN_HEX: - if (scanner->config->numbers_2_int) - *token_p = G_TOKEN_INT; - break; - - default: - break; - } - - if (*token_p == G_TOKEN_INT && - scanner->config->int_2_float) - { - *token_p = G_TOKEN_FLOAT; - if (scanner->config->store_int64) - { -#ifdef _MSC_VER - /* work around error C2520, see gvaluetransform.c */ - value_p->v_float = (__int64)value_p->v_int64; -#else - value_p->v_float = value_p->v_int64; -#endif - } - else - value_p->v_float = value_p->v_int; - } - - errno = 0; -} - -static void -g_scanner_get_token_ll (GScanner *scanner, - GTokenType *token_p, - GTokenValue *value_p, - guint *line_p, - guint *position_p) -{ - GScannerConfig *config; - GTokenType token; - gboolean in_comment_multi; - gboolean in_comment_single; - gboolean in_string_sq; - gboolean in_string_dq; - GString *gstring; - GTokenValue value; - guchar ch; - - config = scanner->config; - (*value_p).v_int64 = 0; - - if ((scanner->text >= scanner->text_end && scanner->input_fd < 0) || - scanner->token == G_TOKEN_EOF) - { - *token_p = G_TOKEN_EOF; - return; - } - - in_comment_multi = FALSE; - in_comment_single = FALSE; - in_string_sq = FALSE; - in_string_dq = FALSE; - gstring = NULL; - - do /* while (ch != 0) */ - { - gboolean dotted_float = FALSE; - - ch = g_scanner_get_char (scanner, line_p, position_p); - - value.v_int64 = 0; - token = G_TOKEN_NONE; - - /* this is *evil*, but needed ;( - * we first check for identifier first character, because it - * might interfere with other key chars like slashes or numbers - */ - if (config->scan_identifier && - ch && strchr (config->cset_identifier_first, ch)) - goto identifier_precedence; - - switch (ch) - { - case 0: - token = G_TOKEN_EOF; - (*position_p)++; - /* ch = 0; */ - break; - - case '/': - if (!config->scan_comment_multi || - g_scanner_peek_next_char (scanner) != '*') - goto default_case; - g_scanner_get_char (scanner, line_p, position_p); - token = G_TOKEN_COMMENT_MULTI; - in_comment_multi = TRUE; - gstring = g_string_new (NULL); - while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0) - { - if (ch == '*' && g_scanner_peek_next_char (scanner) == '/') - { - g_scanner_get_char (scanner, line_p, position_p); - in_comment_multi = FALSE; - break; - } - else - gstring = g_string_append_c (gstring, ch); - } - ch = 0; - break; - - case '\'': - if (!config->scan_string_sq) - goto default_case; - token = G_TOKEN_STRING; - in_string_sq = TRUE; - gstring = g_string_new (NULL); - while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0) - { - if (ch == '\'') - { - in_string_sq = FALSE; - break; - } - else - gstring = g_string_append_c (gstring, ch); - } - ch = 0; - break; - - case '"': - if (!config->scan_string_dq) - goto default_case; - token = G_TOKEN_STRING; - in_string_dq = TRUE; - gstring = g_string_new (NULL); - while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0) - { - if (ch == '"') - { - in_string_dq = FALSE; - break; - } - else - { - if (ch == '\\') - { - ch = g_scanner_get_char (scanner, line_p, position_p); - switch (ch) - { - guint i; - guint fchar; - - case 0: - break; - - case '\\': - gstring = g_string_append_c (gstring, '\\'); - break; - - case 'n': - gstring = g_string_append_c (gstring, '\n'); - break; - - case 't': - gstring = g_string_append_c (gstring, '\t'); - break; - - case 'r': - gstring = g_string_append_c (gstring, '\r'); - break; - - case 'b': - gstring = g_string_append_c (gstring, '\b'); - break; - - case 'f': - gstring = g_string_append_c (gstring, '\f'); - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - i = ch - '0'; - fchar = g_scanner_peek_next_char (scanner); - if (fchar >= '0' && fchar <= '7') - { - ch = g_scanner_get_char (scanner, line_p, position_p); - i = i * 8 + ch - '0'; - fchar = g_scanner_peek_next_char (scanner); - if (fchar >= '0' && fchar <= '7') - { - ch = g_scanner_get_char (scanner, line_p, position_p); - i = i * 8 + ch - '0'; - } - } - gstring = g_string_append_c (gstring, i); - break; - - default: - gstring = g_string_append_c (gstring, ch); - break; - } - } - else - gstring = g_string_append_c (gstring, ch); - } - } - ch = 0; - break; - - case '.': - if (!config->scan_float) - goto default_case; - token = G_TOKEN_FLOAT; - dotted_float = TRUE; - ch = g_scanner_get_char (scanner, line_p, position_p); - goto number_parsing; - - case '$': - if (!config->scan_hex_dollar) - goto default_case; - token = G_TOKEN_HEX; - ch = g_scanner_get_char (scanner, line_p, position_p); - goto number_parsing; - - case '0': - if (config->scan_octal) - token = G_TOKEN_OCTAL; - else - token = G_TOKEN_INT; - ch = g_scanner_peek_next_char (scanner); - if (config->scan_hex && (ch == 'x' || ch == 'X')) - { - token = G_TOKEN_HEX; - g_scanner_get_char (scanner, line_p, position_p); - ch = g_scanner_get_char (scanner, line_p, position_p); - if (ch == 0) - { - token = G_TOKEN_ERROR; - value.v_error = G_ERR_UNEXP_EOF; - (*position_p)++; - break; - } - if (g_scanner_char_2_num (ch, 16) < 0) - { - token = G_TOKEN_ERROR; - value.v_error = G_ERR_DIGIT_RADIX; - ch = 0; - break; - } - } - else if (config->scan_binary && (ch == 'b' || ch == 'B')) - { - token = G_TOKEN_BINARY; - g_scanner_get_char (scanner, line_p, position_p); - ch = g_scanner_get_char (scanner, line_p, position_p); - if (ch == 0) - { - token = G_TOKEN_ERROR; - value.v_error = G_ERR_UNEXP_EOF; - (*position_p)++; - break; - } - if (g_scanner_char_2_num (ch, 10) < 0) - { - token = G_TOKEN_ERROR; - value.v_error = G_ERR_NON_DIGIT_IN_CONST; - ch = 0; - break; - } - } - else - ch = '0'; - /* fall through */ - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - number_parsing: - { - gboolean in_number = TRUE; - gchar *endptr; - - if (token == G_TOKEN_NONE) - token = G_TOKEN_INT; - - gstring = g_string_new (dotted_float ? "0." : ""); - gstring = g_string_append_c (gstring, ch); - - do /* while (in_number) */ - { - gboolean is_E; - - is_E = token == G_TOKEN_FLOAT && (ch == 'e' || ch == 'E'); - - ch = g_scanner_peek_next_char (scanner); - - if (g_scanner_char_2_num (ch, 36) >= 0 || - (config->scan_float && ch == '.') || - (is_E && (ch == '+' || ch == '-'))) - { - ch = g_scanner_get_char (scanner, line_p, position_p); - - switch (ch) - { - case '.': - if (token != G_TOKEN_INT && token != G_TOKEN_OCTAL) - { - value.v_error = token == G_TOKEN_FLOAT ? G_ERR_FLOAT_MALFORMED : G_ERR_FLOAT_RADIX; - token = G_TOKEN_ERROR; - in_number = FALSE; - } - else - { - token = G_TOKEN_FLOAT; - gstring = g_string_append_c (gstring, ch); - } - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - gstring = g_string_append_c (gstring, ch); - break; - - case '-': - case '+': - if (token != G_TOKEN_FLOAT) - { - token = G_TOKEN_ERROR; - value.v_error = G_ERR_NON_DIGIT_IN_CONST; - in_number = FALSE; - } - else - gstring = g_string_append_c (gstring, ch); - break; - - case 'e': - case 'E': - if ((token != G_TOKEN_HEX && !config->scan_float) || - (token != G_TOKEN_HEX && - token != G_TOKEN_OCTAL && - token != G_TOKEN_FLOAT && - token != G_TOKEN_INT)) - { - token = G_TOKEN_ERROR; - value.v_error = G_ERR_NON_DIGIT_IN_CONST; - in_number = FALSE; - } - else - { - if (token != G_TOKEN_HEX) - token = G_TOKEN_FLOAT; - gstring = g_string_append_c (gstring, ch); - } - break; - - default: - if (token != G_TOKEN_HEX) - { - token = G_TOKEN_ERROR; - value.v_error = G_ERR_NON_DIGIT_IN_CONST; - in_number = FALSE; - } - else - gstring = g_string_append_c (gstring, ch); - break; - } - } - else - in_number = FALSE; - } - while (in_number); - - endptr = NULL; - if (token == G_TOKEN_FLOAT) - value.v_float = g_strtod (gstring->str, &endptr); - else - { - guint64 ui64 = 0; - switch (token) - { - case G_TOKEN_BINARY: - ui64 = g_ascii_strtoull (gstring->str, &endptr, 2); - break; - case G_TOKEN_OCTAL: - ui64 = g_ascii_strtoull (gstring->str, &endptr, 8); - break; - case G_TOKEN_INT: - ui64 = g_ascii_strtoull (gstring->str, &endptr, 10); - break; - case G_TOKEN_HEX: - ui64 = g_ascii_strtoull (gstring->str, &endptr, 16); - break; - default: ; - } - if (scanner->config->store_int64) - value.v_int64 = ui64; - else - value.v_int = ui64; - } - if (endptr && *endptr) - { - token = G_TOKEN_ERROR; - if (*endptr == 'e' || *endptr == 'E') - value.v_error = G_ERR_NON_DIGIT_IN_CONST; - else - value.v_error = G_ERR_DIGIT_RADIX; - } - g_string_free (gstring, TRUE); - gstring = NULL; - ch = 0; - } /* number_parsing:... */ - break; - - default: - default_case: - { - if (config->cpair_comment_single && - ch == config->cpair_comment_single[0]) - { - token = G_TOKEN_COMMENT_SINGLE; - in_comment_single = TRUE; - gstring = g_string_new (NULL); - ch = g_scanner_get_char (scanner, line_p, position_p); - while (ch != 0) - { - if (ch == config->cpair_comment_single[1]) - { - in_comment_single = FALSE; - ch = 0; - break; - } - - gstring = g_string_append_c (gstring, ch); - ch = g_scanner_get_char (scanner, line_p, position_p); - } - /* ignore a missing newline at EOF for single line comments */ - if (in_comment_single && - config->cpair_comment_single[1] == '\n') - in_comment_single = FALSE; - } - else if (config->scan_identifier && ch && - strchr (config->cset_identifier_first, ch)) - { - identifier_precedence: - - if (config->cset_identifier_nth && ch && - strchr (config->cset_identifier_nth, - g_scanner_peek_next_char (scanner))) - { - token = G_TOKEN_IDENTIFIER; - gstring = g_string_new (NULL); - gstring = g_string_append_c (gstring, ch); - do - { - ch = g_scanner_get_char (scanner, line_p, position_p); - gstring = g_string_append_c (gstring, ch); - ch = g_scanner_peek_next_char (scanner); - } - while (ch && strchr (config->cset_identifier_nth, ch)); - ch = 0; - } - else if (config->scan_identifier_1char) - { - token = G_TOKEN_IDENTIFIER; - value.v_identifier = g_new0 (gchar, 2); - value.v_identifier[0] = ch; - ch = 0; - } - } - if (ch) - { - if (config->char_2_token) - token = ch; - else - { - token = G_TOKEN_CHAR; - value.v_char = ch; - } - ch = 0; - } - } /* default_case:... */ - break; - } - g_assert (ch == 0 && token != G_TOKEN_NONE); /* paranoid */ - } - while (ch != 0); - - if (in_comment_multi || in_comment_single || - in_string_sq || in_string_dq) - { - token = G_TOKEN_ERROR; - if (gstring) - { - g_string_free (gstring, TRUE); - gstring = NULL; - } - (*position_p)++; - if (in_comment_multi || in_comment_single) - value.v_error = G_ERR_UNEXP_EOF_IN_COMMENT; - else /* (in_string_sq || in_string_dq) */ - value.v_error = G_ERR_UNEXP_EOF_IN_STRING; - } - - if (gstring) - { - value.v_string = g_string_free (gstring, FALSE); - gstring = NULL; - } - - if (token == G_TOKEN_IDENTIFIER) - { - if (config->scan_symbols) - { - GScannerKey *key; - guint scope_id; - - scope_id = scanner->scope_id; - key = g_scanner_lookup_internal (scanner, scope_id, value.v_identifier); - if (!key && scope_id && scanner->config->scope_0_fallback) - key = g_scanner_lookup_internal (scanner, 0, value.v_identifier); - - if (key) - { - g_free (value.v_identifier); - token = G_TOKEN_SYMBOL; - value.v_symbol = key->value; - } - } - - if (token == G_TOKEN_IDENTIFIER && - config->scan_identifier_NULL && - strlen (value.v_identifier) == 4) - { - gchar *null_upper = "NULL"; - gchar *null_lower = "null"; - - if (scanner->config->case_sensitive) - { - if (value.v_identifier[0] == null_upper[0] && - value.v_identifier[1] == null_upper[1] && - value.v_identifier[2] == null_upper[2] && - value.v_identifier[3] == null_upper[3]) - token = G_TOKEN_IDENTIFIER_NULL; - } - else - { - if ((value.v_identifier[0] == null_upper[0] || - value.v_identifier[0] == null_lower[0]) && - (value.v_identifier[1] == null_upper[1] || - value.v_identifier[1] == null_lower[1]) && - (value.v_identifier[2] == null_upper[2] || - value.v_identifier[2] == null_lower[2]) && - (value.v_identifier[3] == null_upper[3] || - value.v_identifier[3] == null_lower[3])) - token = G_TOKEN_IDENTIFIER_NULL; - } - } - } - - *token_p = token; - *value_p = value; -} - -#define __G_SCANNER_C__ -#include "galiasdef.c" diff --git a/glib/gsequence.c b/glib/gsequence.c deleted file mode 100644 index fb64658b6..000000000 --- a/glib/gsequence.c +++ /dev/null @@ -1,1750 +0,0 @@ -/* GLIB - Library of useful routines for C programming - * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 - * Soeren Sandmann (sandmann@daimi.au.dk) - * - * 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "config.h" - -#include "glib.h" -#include "galias.h" - -typedef struct _GSequenceNode GSequenceNode; - -struct _GSequence -{ - GSequenceNode * end_node; - GDestroyNotify data_destroy_notify; - gboolean access_prohibited; - - /* The 'real_sequence' is used when temporary sequences are created - * to hold nodes that are being rearranged. The 'real_sequence' of such - * a temporary sequence points to the sequence that is actually being - * manipulated. The only reason we need this is so that when the - * sort/sort_changed/search_iter() functions call out to the application - * g_sequence_iter_get_sequence() will return the correct sequence. - */ - GSequence * real_sequence; -}; - -struct _GSequenceNode -{ - gint n_nodes; - GSequenceNode * parent; - GSequenceNode * left; - GSequenceNode * right; - gpointer data; /* For the end node, this field points - * to the sequence - */ -}; - -/* - * Declaration of GSequenceNode methods - */ -static GSequenceNode *node_new (gpointer data); -static GSequenceNode *node_get_first (GSequenceNode *node); -static GSequenceNode *node_get_last (GSequenceNode *node); -static GSequenceNode *node_get_prev (GSequenceNode *node); -static GSequenceNode *node_get_next (GSequenceNode *node); -static gint node_get_pos (GSequenceNode *node); -static GSequenceNode *node_get_by_pos (GSequenceNode *node, - gint pos); -static GSequenceNode *node_find_closest (GSequenceNode *haystack, - GSequenceNode *needle, - GSequenceNode *end, - GSequenceIterCompareFunc cmp, - gpointer user_data); -static gint node_get_length (GSequenceNode *node); -static void node_free (GSequenceNode *node, - GSequence *seq); -static void node_cut (GSequenceNode *split); -static void node_insert_before (GSequenceNode *node, - GSequenceNode *new); -static void node_unlink (GSequenceNode *node); -static void node_join (GSequenceNode *left, - GSequenceNode *right); -static void node_insert_sorted (GSequenceNode *node, - GSequenceNode *new, - GSequenceNode *end, - GSequenceIterCompareFunc cmp_func, - gpointer cmp_data); - - -/* - * Various helper functions - */ -static void -check_seq_access (GSequence *seq) -{ - if (G_UNLIKELY (seq->access_prohibited)) - { - g_warning ("Accessing a sequence while it is " - "being sorted or searched is not allowed"); - } -} - -static GSequence * -get_sequence (GSequenceNode *node) -{ - return (GSequence *)node_get_last (node)->data; -} - -static void -check_iter_access (GSequenceIter *iter) -{ - check_seq_access (get_sequence (iter)); -} - -static gboolean -is_end (GSequenceIter *iter) -{ - GSequence *seq; - - if (iter->right) - return FALSE; - - if (!iter->parent) - return TRUE; - - if (iter->parent->right != iter) - return FALSE; - - seq = get_sequence (iter); - - return seq->end_node == iter; -} - -typedef struct -{ - GCompareDataFunc cmp_func; - gpointer cmp_data; - GSequenceNode *end_node; -} SortInfo; - -/* This function compares two iters using a normal compare - * function and user_data passed in in a SortInfo struct - */ -static gint -iter_compare (GSequenceIter *node1, - GSequenceIter *node2, - gpointer data) -{ - const SortInfo *info = data; - gint retval; - - if (node1 == info->end_node) - return 1; - - if (node2 == info->end_node) - return -1; - - retval = info->cmp_func (node1->data, node2->data, info->cmp_data); - - return retval; -} - -/* - * Public API - */ - -/** - * g_sequence_new: - * @data_destroy: a #GDestroyNotify function, or %NULL - * - * Creates a new GSequence. The @data_destroy function, if non-%NULL will - * be called on all items when the sequence is destroyed and on items that - * are removed from the sequence. - * - * Return value: a new #GSequence - * - * Since: 2.14 - **/ -GSequence * -g_sequence_new (GDestroyNotify data_destroy) -{ - GSequence *seq = g_new (GSequence, 1); - seq->data_destroy_notify = data_destroy; - - seq->end_node = node_new (seq); - - seq->access_prohibited = FALSE; - - seq->real_sequence = seq; - - return seq; -} - -/** - * g_sequence_free: - * @seq: a #GSequence - * - * Frees the memory allocated for @seq. If @seq has a data destroy - * function associated with it, that function is called on all items in - * @seq. - * - * Since: 2.14 - **/ -void -g_sequence_free (GSequence *seq) -{ - g_return_if_fail (seq != NULL); - - check_seq_access (seq); - - node_free (seq->end_node, seq); - - g_free (seq); -} - -/** - * g_sequence_foreach_range: - * @begin: a #GSequenceIter - * @end: a #GSequenceIter - * @func: a #GFunc - * @user_data: user data passed to @func - * - * Calls @func for each item in the range (@begin, @end) passing - * @user_data to the function. - * - * Since: 2.14 - **/ -void -g_sequence_foreach_range (GSequenceIter *begin, - GSequenceIter *end, - GFunc func, - gpointer user_data) -{ - GSequence *seq; - GSequenceIter *iter; - - g_return_if_fail (func != NULL); - g_return_if_fail (begin != NULL); - g_return_if_fail (end != NULL); - - seq = get_sequence (begin); - - seq->access_prohibited = TRUE; - - iter = begin; - while (iter != end) - { - GSequenceIter *next = node_get_next (iter); - - func (iter->data, user_data); - - iter = next; - } - - seq->access_prohibited = FALSE; -} - -/** - * g_sequence_foreach: - * @seq: a #GSequence - * @func: the function to call for each item in @seq - * @user_data: user data passed to @func - * - * Calls @func for each item in the sequence passing @user_data - * to the function. - * - * Since: 2.14 - **/ -void -g_sequence_foreach (GSequence *seq, - GFunc func, - gpointer user_data) -{ - GSequenceIter *begin, *end; - - check_seq_access (seq); - - begin = g_sequence_get_begin_iter (seq); - end = g_sequence_get_end_iter (seq); - - g_sequence_foreach_range (begin, end, func, user_data); -} - -/** - * g_sequence_range_get_midpoint: - * @begin: a #GSequenceIter - * @end: a #GSequenceIter - * - * Finds an iterator somewhere in the range (@begin, @end). This - * iterator will be close to the middle of the range, but is not - * guaranteed to be <emphasis>exactly</emphasis> in the middle. - * - * The @begin and @end iterators must both point to the same sequence and - * @begin must come before or be equal to @end in the sequence. - * - * Return value: A #GSequenceIter pointing somewhere in the - * (@begin, @end) range. - * - * Since: 2.14 - **/ -GSequenceIter * -g_sequence_range_get_midpoint (GSequenceIter *begin, - GSequenceIter *end) -{ - int begin_pos, end_pos, mid_pos; - - g_return_val_if_fail (begin != NULL, NULL); - g_return_val_if_fail (end != NULL, NULL); - g_return_val_if_fail (get_sequence (begin) == get_sequence (end), NULL); - - begin_pos = node_get_pos (begin); - end_pos = node_get_pos (end); - - g_return_val_if_fail (end_pos >= begin_pos, NULL); - - mid_pos = begin_pos + (end_pos - begin_pos) / 2; - - return node_get_by_pos (begin, mid_pos); -} - -/** - * g_sequence_iter_compare: - * @a: a #GSequenceIter - * @b: a #GSequenceIter - * - * Returns a negative number if @a comes before @b, 0 if they are equal, - * and a positive number if @a comes after @b. - * - * The @a and @b iterators must point into the same sequence. - * - * Return value: A negative number if @a comes before @b, 0 if they are - * equal, and a positive number if @a comes after @b. - * - * Since: 2.14 - **/ -gint -g_sequence_iter_compare (GSequenceIter *a, - GSequenceIter *b) -{ - gint a_pos, b_pos; - - g_return_val_if_fail (a != NULL, 0); - g_return_val_if_fail (b != NULL, 0); - g_return_val_if_fail (get_sequence (a) == get_sequence (b), 0); - - check_iter_access (a); - check_iter_access (b); - - a_pos = node_get_pos (a); - b_pos = node_get_pos (b); - - if (a_pos == b_pos) - return 0; - else if (a_pos > b_pos) - return 1; - else - return -1; -} - -/** - * g_sequence_append: - * @seq: a #GSequencePointer - * @data: the data for the new item - * - * Adds a new item to the end of @seq. - * - * Return value: an iterator pointing to the new item - * - * Since: 2.14 - **/ -GSequenceIter * -g_sequence_append (GSequence *seq, - gpointer data) -{ - GSequenceNode *node; - - g_return_val_if_fail (seq != NULL, NULL); - - check_seq_access (seq); - - node = node_new (data); - node_insert_before (seq->end_node, node); - - return node; -} - -/** - * g_sequence_prepend: - * @seq: a #GSequence - * @data: the data for the new item - * - * Adds a new item to the front of @seq - * - * Return value: an iterator pointing to the new item - * - * Since: 2.14 - **/ -GSequenceIter * -g_sequence_prepend (GSequence *seq, - gpointer data) -{ - GSequenceNode *node, *first; - - g_return_val_if_fail (seq != NULL, NULL); - - check_seq_access (seq); - - node = node_new (data); - first = node_get_first (seq->end_node); - - node_insert_before (first, node); - - return node; -} - -/** - * g_sequence_insert_before: - * @iter: a #GSequenceIter - * @data: the data for the new item - * - * Inserts a new item just before the item pointed to by @iter. - * - * Return value: an iterator pointing to the new item - * - * Since: 2.14 - **/ -GSequenceIter * -g_sequence_insert_before (GSequenceIter *iter, - gpointer data) -{ - GSequenceNode *node; - - g_return_val_if_fail (iter != NULL, NULL); - - check_iter_access (iter); - - node = node_new (data); - - node_insert_before (iter, node); - - return node; -} - -/** - * g_sequence_remove: - * @iter: a #GSequenceIter - * - * Removes the item pointed to by @iter. It is an error to pass the - * end iterator to this function. - * - * If the sequnce has a data destroy function associated with it, this - * function is called on the data for the removed item. - * - * Since: 2.14 - **/ -void -g_sequence_remove (GSequenceIter *iter) -{ - GSequence *seq; - - g_return_if_fail (iter != NULL); - g_return_if_fail (!is_end (iter)); - - check_iter_access (iter); - - seq = get_sequence (iter); - - node_unlink (iter); - node_free (iter, seq); -} - -/** - * g_sequence_remove_range: - * @begin: a #GSequenceIter - * @end: a #GSequenceIter - * - * Removes all items in the (@begin, @end) range. - * - * If the sequence has a data destroy function associated with it, this - * function is called on the data for the removed items. - * - * Since: 2.14 - **/ -void -g_sequence_remove_range (GSequenceIter *begin, - GSequenceIter *end) -{ - g_return_if_fail (get_sequence (begin) == get_sequence (end)); - - check_iter_access (begin); - check_iter_access (end); - - g_sequence_move_range (NULL, begin, end); -} - -/** - * g_sequence_move_range: - * @dest: a #GSequenceIter - * @begin: a #GSequenceIter - * @end: a #GSequenceIter - * - * Inserts the (@begin, @end) range at the destination pointed to by ptr. - * The @begin and @end iters must point into the same sequence. It is - * allowed for @dest to point to a different sequence than the one pointed - * into by @begin and @end. - * - * If @dest is NULL, the range indicated by @begin and @end is - * removed from the sequence. If @dest iter points to a place within - * the (@begin, @end) range, the range does not move. - * - * Since: 2.14 - **/ -void -g_sequence_move_range (GSequenceIter *dest, - GSequenceIter *begin, - GSequenceIter *end) -{ - GSequence *src_seq; - GSequenceNode *first; - - g_return_if_fail (begin != NULL); - g_return_if_fail (end != NULL); - - check_iter_access (begin); - check_iter_access (end); - if (dest) - check_iter_access (dest); - - src_seq = get_sequence (begin); - - g_return_if_fail (src_seq == get_sequence (end)); - - /* Dest points to begin or end? */ - if (dest == begin || dest == end) - return; - - /* begin comes after end? */ - if (g_sequence_iter_compare (begin, end) >= 0) - return; - - /* dest points somewhere in the (begin, end) range? */ - if (dest && get_sequence (dest) == src_seq && - g_sequence_iter_compare (dest, begin) > 0 && - g_sequence_iter_compare (dest, end) < 0) - { - return; - } - - src_seq = get_sequence (begin); - - first = node_get_first (begin); - - node_cut (begin); - - node_cut (end); - - if (first != begin) - node_join (first, end); - - if (dest) - { - first = node_get_first (dest); - - node_cut (dest); - - node_join (begin, dest); - - if (dest != first) - node_join (first, begin); - } - else - { - node_free (begin, src_seq); - } -} - -/** - * g_sequence_sort: - * @seq: a #GSequence - * @cmp_func: the #GCompareDataFunc used to sort @seq. This function is - * passed two items of @seq and should return 0 if they are equal, - * a negative value fi the first comes before the second, and a - * positive value if the second comes before the first. - * @cmp_data: user data passed to @cmp_func - * - * Sorts @seq using @cmp_func. - * - * Since: 2.14 - **/ -void -g_sequence_sort (GSequence *seq, - GCompareDataFunc cmp_func, - gpointer cmp_data) -{ - SortInfo info; - - info.cmp_func = cmp_func; - info.cmp_data = cmp_data; - info.end_node = seq->end_node; - - check_seq_access (seq); - - g_sequence_sort_iter (seq, iter_compare, &info); -} - -/** - * g_sequence_insert_sorted: - * @seq: a #GSequence - * @data: the data to insert - * @cmp_func: the #GCompareDataFunc used to compare items in the sequence. It - * is called with two items of the @seq and @user_data. It should - * return 0 if the items are equal, a negative value if the first - * item comes before the second, and a positive value if the second - * item comes before the first. - * @cmp_data: user data passed to @cmp_func. - * - * Inserts @data into @sequence using @func to determine the new position. - * The sequence must already be sorted according to @cmp_func; otherwise the - * new position of @data is undefined. - * - * Return value: a #GSequenceIter pointing to the new item. - * - * Since: 2.14 - **/ -GSequenceIter * -g_sequence_insert_sorted (GSequence *seq, - gpointer data, - GCompareDataFunc cmp_func, - gpointer cmp_data) -{ - SortInfo info; - - g_return_val_if_fail (seq != NULL, NULL); - g_return_val_if_fail (cmp_func != NULL, NULL); - - info.cmp_func = cmp_func; - info.cmp_data = cmp_data; - info.end_node = seq->end_node; - check_seq_access (seq); - - return g_sequence_insert_sorted_iter (seq, data, iter_compare, &info); -} - -/** - * g_sequence_sort_changed: - * @iter: A #GSequenceIter - * @cmp_func: the #GCompareDataFunc used to compare items in the sequence. It - * is called with two items of the @seq and @user_data. It should - * return 0 if the items are equal, a negative value if the first - * item comes before the second, and a positive value if the second - * item comes before the first. - * @cmp_data: user data passed to @cmp_func. - * - * Moves the data pointed to a new position as indicated by @cmp_func. This - * function should be called for items in a sequence already sorted according - * to @cmp_func whenever some aspect of an item changes so that @cmp_func - * may return different values for that item. - * - * Since: 2.14 - **/ -void -g_sequence_sort_changed (GSequenceIter *iter, - GCompareDataFunc cmp_func, - gpointer cmp_data) -{ - SortInfo info; - - g_return_if_fail (!is_end (iter)); - - info.cmp_func = cmp_func; - info.cmp_data = cmp_data; - info.end_node = get_sequence (iter)->end_node; - check_iter_access (iter); - - g_sequence_sort_changed_iter (iter, iter_compare, &info); -} - -/** - * g_sequence_search: - * @seq: a #GSequence - * @data: data for the new item - * @cmp_func: the #GCompareDataFunc used to compare items in the sequence. It - * is called with two items of the @seq and @user_data. It should - * return 0 if the items are equal, a negative value if the first - * item comes before the second, and a positive value if the second - * item comes before the first. - * @cmp_data: user data passed to @cmp_func. - * - * Returns an iterator pointing to the position where @data would - * be inserted according to @cmp_func and @cmp_data. - * - * Return value: an #GSequenceIter pointing to the position where @data - * would have been inserted according to @cmp_func and @cmp_data. - * - * Since: 2.14 - **/ -GSequenceIter * -g_sequence_search (GSequence *seq, - gpointer data, - GCompareDataFunc cmp_func, - gpointer cmp_data) -{ - SortInfo info; - - g_return_val_if_fail (seq != NULL, NULL); - - info.cmp_func = cmp_func; - info.cmp_data = cmp_data; - info.end_node = seq->end_node; - check_seq_access (seq); - - return g_sequence_search_iter (seq, data, iter_compare, &info); -} - -/** - * g_sequence_sort_iter: - * @seq: a #GSequence - * @cmp_func: the #GSequenceItercompare used to compare iterators in the - * sequence. It is called with two iterators pointing into @seq. It should - * return 0 if the iterators are equal, a negative value if the first - * iterator comes before the second, and a positive value if the second - * iterator comes before the first. - * @cmp_data: user data passed to @cmp_func - * - * Like g_sequence_sort(), but uses a #GSequenceIterCompareFunc instead - * of a GCompareDataFunc as the compare function - * - * Since: 2.14 - **/ -void -g_sequence_sort_iter (GSequence *seq, - GSequenceIterCompareFunc cmp_func, - gpointer cmp_data) -{ - GSequence *tmp; - GSequenceNode *begin, *end; - - g_return_if_fail (seq != NULL); - g_return_if_fail (cmp_func != NULL); - - check_seq_access (seq); - - begin = g_sequence_get_begin_iter (seq); - end = g_sequence_get_end_iter (seq); - - tmp = g_sequence_new (NULL); - tmp->real_sequence = seq; - - g_sequence_move_range (g_sequence_get_begin_iter (tmp), begin, end); - - seq->access_prohibited = TRUE; - tmp->access_prohibited = TRUE; - - while (g_sequence_get_length (tmp) > 0) - { - GSequenceNode *node = g_sequence_get_begin_iter (tmp); - - node_insert_sorted (seq->end_node, node, seq->end_node, - cmp_func, cmp_data); - } - - tmp->access_prohibited = FALSE; - seq->access_prohibited = FALSE; - - g_sequence_free (tmp); -} - -/** - * g_sequence_sort_changed_iter: - * @iter: a #GSequenceIter - * @iter_cmp: the #GSequenceItercompare used to compare iterators in the - * sequence. It is called with two iterators pointing into @seq. It should - * return 0 if the iterators are equal, a negative value if the first - * iterator comes before the second, and a positive value if the second - * iterator comes before the first. - * @cmp_data: user data passed to @cmp_func - * - * Like g_sequence_sort_changed(), but uses - * a #GSequenceIterCompareFunc instead of a #GCompareDataFunc as - * the compare function. - * - * Since: 2.14 - **/ -void -g_sequence_sort_changed_iter (GSequenceIter *iter, - GSequenceIterCompareFunc iter_cmp, - gpointer cmp_data) -{ - GSequence *seq, *tmp_seq; - GSequenceIter *next, *prev; - - g_return_if_fail (iter != NULL); - g_return_if_fail (!is_end (iter)); - g_return_if_fail (iter_cmp != NULL); - check_iter_access (iter); - - /* If one of the neighbours is equal to iter, then - * don't move it. This ensures that sort_changed() is - * a stable operation. - */ - - next = node_get_next (iter); - prev = node_get_prev (iter); - - if (prev != iter && iter_cmp (prev, iter, cmp_data) == 0) - return; - - if (!is_end (next) && iter_cmp (next, iter, cmp_data) == 0) - return; - - seq = get_sequence (iter); - - seq->access_prohibited = TRUE; - - tmp_seq = g_sequence_new (NULL); - tmp_seq->real_sequence = seq; - - node_unlink (iter); - node_insert_before (tmp_seq->end_node, iter); - - node_insert_sorted (seq->end_node, iter, seq->end_node, - iter_cmp, cmp_data); - - g_sequence_free (tmp_seq); - - seq->access_prohibited = FALSE; -} - -/** - * g_sequence_insert_sorted_iter: - * @seq: a #GSequence - * @data: data for the new item - * @iter_cmp: the #GSequenceItercompare used to compare iterators in the - * sequence. It is called with two iterators pointing into @seq. It should - * return 0 if the iterators are equal, a negative value if the first - * iterator comes before the second, and a positive value if the second - * iterator comes before the first. - * @cmp_data: user data passed to @cmp_func - * - * Like g_sequence_insert_sorted(), but uses - * a #GSequenceIterCompareFunc instead of a #GCompareDataFunc as - * the compare function. - * - * Return value: a #GSequenceIter pointing to the new item - * - * Since: 2.14 - **/ -GSequenceIter * -g_sequence_insert_sorted_iter (GSequence *seq, - gpointer data, - GSequenceIterCompareFunc iter_cmp, - gpointer cmp_data) -{ - GSequenceNode *new_node; - GSequence *tmp_seq; - - g_return_val_if_fail (seq != NULL, NULL); - g_return_val_if_fail (iter_cmp != NULL, NULL); - - check_seq_access (seq); - - seq->access_prohibited = TRUE; - - /* Create a new temporary sequence and put the new node into - * that. The reason for this is that the user compare function - * will be called with the new node, and if it dereferences, - * "is_end" will be called on it. But that will crash if the - * node is not actually in a sequence. - * - * node_insert_sorted() makes sure the node is unlinked before - * it is inserted. - * - * The reason we need the "iter" versions at all is that that - * is the only kind of compare functions GtkTreeView can use. - */ - tmp_seq = g_sequence_new (NULL); - tmp_seq->real_sequence = seq; - - new_node = g_sequence_append (tmp_seq, data); - - node_insert_sorted (seq->end_node, new_node, - seq->end_node, iter_cmp, cmp_data); - - g_sequence_free (tmp_seq); - - seq->access_prohibited = FALSE; - - return new_node; -} - -/** - * g_sequence_search_iter: - * @seq: a #GSequence - * @data: data for the new item - * @iter_cmp: the #GSequenceIterCompare function used to compare iterators - * in the sequence. It is called with two iterators pointing into @seq. - * It should return 0 if the iterators are equal, a negative value if the - * first iterator comes before the second, and a positive value if the - * second iterator comes before the first. - * @cmp_data: user data passed to @iter_cmp - * - * Like g_sequence_search(), but uses - * a #GSequenceIterCompareFunc instead of a #GCompareDataFunc as - * the compare function. - * - * Return value: a #GSequenceIter pointing to the position in @seq - * where @data would have been inserted according to @iter_cmp and @cmp_data. - * - * Since: 2.14 - **/ -GSequenceIter * -g_sequence_search_iter (GSequence *seq, - gpointer data, - GSequenceIterCompareFunc iter_cmp, - gpointer cmp_data) -{ - GSequenceNode *node; - GSequenceNode *dummy; - GSequence *tmp_seq; - - g_return_val_if_fail (seq != NULL, NULL); - - check_seq_access (seq); - - seq->access_prohibited = TRUE; - - tmp_seq = g_sequence_new (NULL); - tmp_seq->real_sequence = seq; - - dummy = g_sequence_append (tmp_seq, data); - - node = node_find_closest (seq->end_node, dummy, - seq->end_node, iter_cmp, cmp_data); - - g_sequence_free (tmp_seq); - - seq->access_prohibited = FALSE; - - return node; -} - -/** - * g_sequence_iter_get_sequence: - * @iter: a #GSequenceIter - * - * Returns the #GSequence that @iter points into. - * - * Return value: the #GSequence that @iter points into. - * - * Since: 2.14 - **/ -GSequence * -g_sequence_iter_get_sequence (GSequenceIter *iter) -{ - GSequence *seq; - - g_return_val_if_fail (iter != NULL, NULL); - - seq = get_sequence (iter); - - /* For temporary sequences, this points to the sequence that - * is actually being manipulated - */ - return seq->real_sequence; -} - -/** - * g_sequence_get: - * @iter: a #GSequenceIter - * - * Returns the data that @iter points to. - * - * Return value: the data that @iter points to - * - * Since: 2.14 - **/ -gpointer -g_sequence_get (GSequenceIter *iter) -{ - g_return_val_if_fail (iter != NULL, NULL); - g_return_val_if_fail (!is_end (iter), NULL); - - return iter->data; -} - -/** - * g_sequence_set: - * @iter: a #GSequenceIter - * @data: new data for the item - * - * Changes the data for the item pointed to by @iter to be @data. If - * the sequence has a data destroy function associated with it, that - * function is called on the existing data that @iter pointed to. - * - * Since: 2.14 - **/ -void -g_sequence_set (GSequenceIter *iter, - gpointer data) -{ - GSequence *seq; - - g_return_if_fail (iter != NULL); - g_return_if_fail (!is_end (iter)); - - seq = get_sequence (iter); - - /* If @data is identical to iter->data, it is destroyed - * here. This will work right in case of ref-counted objects. Also - * it is similar to what ghashtables do. - * - * For non-refcounted data it's a little less convenient, but - * code relying on self-setting not destroying would be - * pretty dubious anyway ... - */ - - if (seq->data_destroy_notify) - seq->data_destroy_notify (iter->data); - - iter->data = data; -} - -/** - * g_sequence_get_length: - * @seq: a #GSequence - * - * Returns the length of @seq - * - * Return value: the length of @seq - * - * Since: 2.14 - **/ -gint -g_sequence_get_length (GSequence *seq) -{ - return node_get_length (seq->end_node) - 1; -} - -/** - * g_sequence_get_end_iter: - * @seq: a #GSequence - * - * Returns the end iterator for @seg - * - * Return value: the end iterator for @seq - * - * Since: 2.14 - **/ -GSequenceIter * -g_sequence_get_end_iter (GSequence *seq) -{ - g_return_val_if_fail (seq != NULL, NULL); - - return seq->end_node; -} - -/** - * g_sequence_get_begin_iter: - * @seq: a #GSequence - * - * Returns the begin iterator for @seq. - * - * Return value: the begin iterator for @seq. - * - * Since: 2.14 - **/ -GSequenceIter * -g_sequence_get_begin_iter (GSequence *seq) -{ - g_return_val_if_fail (seq != NULL, NULL); - - return node_get_first (seq->end_node); -} - -static int -clamp_position (GSequence *seq, - int pos) -{ - gint len = g_sequence_get_length (seq); - - if (pos > len || pos < 0) - pos = len; - - return pos; -} - -/* - * if pos > number of items or -1, will return end pointer - */ -/** - * g_sequence_get_iter_at_pos: - * @seq: a #GSequence - * @pos: a position in @seq, or -1 for the end. - * - * Returns the iterator at position @pos. If @pos is negative or larger - * than the number of items in @seq, the end iterator is returned. - * - * Return value: The #GSequenceIter at position @pos - * - * Since: 2.14 - **/ -GSequenceIter * -g_sequence_get_iter_at_pos (GSequence *seq, - gint pos) -{ - g_return_val_if_fail (seq != NULL, NULL); - - pos = clamp_position (seq, pos); - - return node_get_by_pos (seq->end_node, pos); -} - -/** - * g_sequence_move: - * @src: a #GSequenceIter pointing to the item to move - * @dest: a #GSequenceIter pointing to the position to which - * the item is moved. - * - * Moves the item pointed to by @src to the position indicated by @dest. - * After calling this function @dest will point to the position immediately - * after @src. It is allowed for @src and @dest to point into different - * sequences. - * - * Since: 2.14 - **/ -void -g_sequence_move (GSequenceIter *src, - GSequenceIter *dest) -{ - g_return_if_fail (src != NULL); - g_return_if_fail (dest != NULL); - g_return_if_fail (!is_end (src)); - - if (src == dest) - return; - - node_unlink (src); - node_insert_before (dest, src); -} - -/* GSequenceIter */ - -/** - * g_sequence_iter_is_end: - * @iter: a #GSequenceIter - * - * Returns whether @iter is the end iterator - * - * Return value: Whether @iter is the end iterator. - * - * Since: 2.14 - **/ -gboolean -g_sequence_iter_is_end (GSequenceIter *iter) -{ - g_return_val_if_fail (iter != NULL, FALSE); - - return is_end (iter); -} - -/** - * g_sequence_iter_is_begin: - * @iter: a #GSequenceIter - * - * Returns whether @iter is the begin iterator - * - * Return value: whether @iter is the begin iterator - * - * Since: 2.14 - **/ -gboolean -g_sequence_iter_is_begin (GSequenceIter *iter) -{ - g_return_val_if_fail (iter != NULL, FALSE); - - return (node_get_prev (iter) == iter); -} - -/** - * g_sequence_iter_get_position: - * @iter: a #GSequenceIter - * - * Returns the position of @iter - * - * Return value: the position of @iter - * - * Since: 2.14 - **/ -gint -g_sequence_iter_get_position (GSequenceIter *iter) -{ - g_return_val_if_fail (iter != NULL, -1); - - return node_get_pos (iter); -} - -/** - * g_sequence_iter_next: - * @iter: a #GSequenceIter - * - * Returns an iterator pointing to the next position after @iter. If - * @iter is the end iterator, the end iterator is returned. - * - * Return value: a #GSequenceIter pointing to the next position after @iter. - * - * Since: 2.14 - **/ -GSequenceIter * -g_sequence_iter_next (GSequenceIter *iter) -{ - g_return_val_if_fail (iter != NULL, NULL); - - return node_get_next (iter); -} - -/** - * g_sequence_iter_prev: - * @iter: a #GSequenceIter - * - * Returns an iterator pointing to the previous position before @iter. If - * @iter is the begin iterator, the begin iterator is returned. - * - * Return value: a #GSequenceIter pointing to the previous position before - * @iter. - * - * Since: 2.14 - **/ -GSequenceIter * -g_sequence_iter_prev (GSequenceIter *iter) -{ - g_return_val_if_fail (iter != NULL, NULL); - - return node_get_prev (iter); -} - -/** - * g_sequence_iter_move: - * @iter: a #GSequenceIter - * @delta: A positive or negative number indicating how many positions away - * from @iter the returned #GSequenceIter will be. - * - * Returns the #GSequenceIter which is @delta positions away from @iter. - * If @iter is closer than -@delta positions to the beginning of the sequence, - * the begin iterator is returned. If @iter is closer than @delta positions - * to the end of the sequence, the end iterator is returned. - * - * Return value: a #GSequenceIter which is @delta positions away from @iter. - * - * Since: 2.14 - **/ -GSequenceIter * -g_sequence_iter_move (GSequenceIter *iter, - gint delta) -{ - gint new_pos; - - g_return_val_if_fail (iter != NULL, NULL); - - new_pos = node_get_pos (iter) + delta; - - new_pos = clamp_position (get_sequence (iter), new_pos); - - return node_get_by_pos (iter, new_pos); -} - -/** - * g_sequence_swap: - * @a: a #GSequenceIter - * @b: a #GSequenceIter - * - * Swaps the items pointed to by @a and @b. It is allowed for @a and @b - * to point into difference sequences. - * - * Since: 2.14 - **/ -void -g_sequence_swap (GSequenceIter *a, - GSequenceIter *b) -{ - GSequenceNode *leftmost, *rightmost, *rightmost_next; - int a_pos, b_pos; - - g_return_if_fail (!g_sequence_iter_is_end (a)); - g_return_if_fail (!g_sequence_iter_is_end (b)); - - if (a == b) - return; - - a_pos = g_sequence_iter_get_position (a); - b_pos = g_sequence_iter_get_position (b); - - if (a_pos > b_pos) - { - leftmost = b; - rightmost = a; - } - else - { - leftmost = a; - rightmost = b; - } - - rightmost_next = node_get_next (rightmost); - - /* The situation is now like this: - * - * ..., leftmost, ......., rightmost, rightmost_next, ... - * - */ - g_sequence_move (rightmost, leftmost); - g_sequence_move (leftmost, rightmost_next); -} - -/* - * Implementation of a treap - * - * - */ -static guint -get_priority (GSequenceNode *node) -{ - guint key = GPOINTER_TO_UINT (node); - - /* This hash function is based on one found on Thomas Wang's - * web page at - * - * http://www.concentric.net/~Ttwang/tech/inthash.htm - * - */ - key = (key << 15) - key - 1; - key = key ^ (key >> 12); - key = key + (key << 2); - key = key ^ (key >> 4); - key = key + (key << 3) + (key << 11); - key = key ^ (key >> 16); - - /* We rely on 0 being less than all other priorities */ - return key? key : 1; -} - -static GSequenceNode * -find_root (GSequenceNode *node) -{ - while (node->parent) - node = node->parent; - - return node; -} - -static GSequenceNode * -node_new (gpointer data) -{ - GSequenceNode *node = g_slice_new0 (GSequenceNode); - - node->n_nodes = 1; - node->data = data; - node->left = NULL; - node->right = NULL; - node->parent = NULL; - - return node; -} - -static GSequenceNode * -node_get_first (GSequenceNode *node) -{ - node = find_root (node); - - while (node->left) - node = node->left; - - return node; -} - -static GSequenceNode * -node_get_last (GSequenceNode *node) -{ - node = find_root (node); - - while (node->right) - node = node->right; - - return node; -} - -#define NODE_LEFT_CHILD(n) (((n)->parent) && ((n)->parent->left) == (n)) -#define NODE_RIGHT_CHILD(n) (((n)->parent) && ((n)->parent->right) == (n)) - -static GSequenceNode * -node_get_next (GSequenceNode *node) -{ - GSequenceNode *n = node; - - if (n->right) - { - n = n->right; - while (n->left) - n = n->left; - } - else - { - while (NODE_RIGHT_CHILD (n)) - n = n->parent; - - if (n->parent) - n = n->parent; - else - n = node; - } - - return n; -} - -static GSequenceNode * -node_get_prev (GSequenceNode *node) -{ - GSequenceNode *n = node; - - if (n->left) - { - n = n->left; - while (n->right) - n = n->right; - } - else - { - while (NODE_LEFT_CHILD (n)) - n = n->parent; - - if (n->parent) - n = n->parent; - else - n = node; - } - - return n; -} - -#define N_NODES(n) ((n)? (n)->n_nodes : 0) - -static gint -node_get_pos (GSequenceNode *node) -{ - int n_smaller = 0; - - if (node->left) - n_smaller = node->left->n_nodes; - - while (node) - { - if (NODE_RIGHT_CHILD (node)) - n_smaller += N_NODES (node->parent->left) + 1; - - node = node->parent; - } - - return n_smaller; -} - -static GSequenceNode * -node_get_by_pos (GSequenceNode *node, - gint pos) -{ - int i; - - node = find_root (node); - - while ((i = N_NODES (node->left)) != pos) - { - if (i < pos) - { - node = node->right; - pos -= (i + 1); - } - else - { - node = node->left; - } - } - - return node; -} - -static GSequenceNode * -node_find_closest (GSequenceNode *haystack, - GSequenceNode *needle, - GSequenceNode *end, - GSequenceIterCompareFunc iter_cmp, - gpointer cmp_data) -{ - GSequenceNode *best; - gint c; - - haystack = find_root (haystack); - - do - { - best = haystack; - - /* iter_cmp can't be passed the end node, since the function may - * be user-supplied - */ - if (haystack == end) - c = 1; - else - c = iter_cmp (haystack, needle, cmp_data); - - /* In the following we don't break even if c == 0. Instaed we go on - * searching along the 'bigger' nodes, so that we find the last one - * that is equal to the needle. - */ - if (c > 0) - haystack = haystack->left; - else - haystack = haystack->right; - } - while (haystack != NULL); - - /* If the best node is smaller or equal to the data, then move one step - * to the right to make sure the best one is strictly bigger than the data - */ - if (best != end && c <= 0) - best = node_get_next (best); - - return best; -} - -static gint -node_get_length (GSequenceNode *node) -{ - node = find_root (node); - - return node->n_nodes; -} - -static void -real_node_free (GSequenceNode *node, - GSequence *seq) -{ - if (node) - { - real_node_free (node->left, seq); - real_node_free (node->right, seq); - - if (seq && seq->data_destroy_notify && node != seq->end_node) - seq->data_destroy_notify (node->data); - - g_slice_free (GSequenceNode, node); - } -} - -static void -node_free (GSequenceNode *node, - GSequence *seq) -{ - node = find_root (node); - - real_node_free (node, seq); -} - -static void -node_update_fields (GSequenceNode *node) -{ - int n_nodes = 1; - - n_nodes += N_NODES (node->left); - n_nodes += N_NODES (node->right); - - node->n_nodes = n_nodes; -} - -static void -node_rotate (GSequenceNode *node) -{ - GSequenceNode *tmp, *old; - - g_assert (node->parent); - g_assert (node->parent != node); - - if (NODE_LEFT_CHILD (node)) - { - /* rotate right */ - tmp = node->right; - - node->right = node->parent; - node->parent = node->parent->parent; - if (node->parent) - { - if (node->parent->left == node->right) - node->parent->left = node; - else - node->parent->right = node; - } - - g_assert (node->right); - - node->right->parent = node; - node->right->left = tmp; - - if (node->right->left) - node->right->left->parent = node->right; - - old = node->right; - } - else - { - /* rotate left */ - tmp = node->left; - - node->left = node->parent; - node->parent = node->parent->parent; - if (node->parent) - { - if (node->parent->right == node->left) - node->parent->right = node; - else - node->parent->left = node; - } - - g_assert (node->left); - - node->left->parent = node; - node->left->right = tmp; - - if (node->left->right) - node->left->right->parent = node->left; - - old = node->left; - } - - node_update_fields (old); - node_update_fields (node); -} - -static void -node_update_fields_deep (GSequenceNode *node) -{ - if (node) - { - node_update_fields (node); - - node_update_fields_deep (node->parent); - } -} - -static void -rotate_down (GSequenceNode *node, - guint priority) -{ - guint left, right; - - left = node->left ? get_priority (node->left) : 0; - right = node->right ? get_priority (node->right) : 0; - - while (priority < left || priority < right) - { - if (left > right) - node_rotate (node->left); - else - node_rotate (node->right); - - left = node->left ? get_priority (node->left) : 0; - right = node->right ? get_priority (node->right) : 0; - } -} - -static void -node_cut (GSequenceNode *node) -{ - while (node->parent) - node_rotate (node); - - if (node->left) - node->left->parent = NULL; - - node->left = NULL; - node_update_fields (node); - - rotate_down (node, get_priority (node)); -} - -static void -node_join (GSequenceNode *left, - GSequenceNode *right) -{ - GSequenceNode *fake = node_new (NULL); - - fake->left = find_root (left); - fake->right = find_root (right); - fake->left->parent = fake; - fake->right->parent = fake; - - node_update_fields (fake); - - node_unlink (fake); - - node_free (fake, NULL); -} - -static void -node_insert_before (GSequenceNode *node, - GSequenceNode *new) -{ - new->left = node->left; - if (new->left) - new->left->parent = new; - - new->parent = node; - node->left = new; - - node_update_fields_deep (new); - - while (new->parent && get_priority (new) > get_priority (new->parent)) - node_rotate (new); - - rotate_down (new, get_priority (new)); -} - -static void -node_unlink (GSequenceNode *node) -{ - rotate_down (node, 0); - - if (NODE_RIGHT_CHILD (node)) - node->parent->right = NULL; - else if (NODE_LEFT_CHILD (node)) - node->parent->left = NULL; - - if (node->parent) - node_update_fields_deep (node->parent); - - node->parent = NULL; -} - -static void -node_insert_sorted (GSequenceNode *node, - GSequenceNode *new, - GSequenceNode *end, - GSequenceIterCompareFunc iter_cmp, - gpointer cmp_data) -{ - GSequenceNode *closest; - - closest = node_find_closest (node, new, end, iter_cmp, cmp_data); - - node_unlink (new); - - node_insert_before (closest, new); -} - - -#define __G_SEQUENCE_C__ -#include "galiasdef.c" diff --git a/glib/gshell.c b/glib/gshell.c deleted file mode 100644 index 711cdee09..000000000 --- a/glib/gshell.c +++ /dev/null @@ -1,673 +0,0 @@ -/* gshell.c - Shell-related utilities - * - * Copyright 2000 Red Hat, Inc. - * g_execvpe implementation based on GNU libc execvp: - * Copyright 1991, 92, 95, 96, 97, 98, 99 Free Software Foundation, Inc. - * - * GLib 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 of the - * License, or (at your option) any later version. - * - * GLib 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 GLib; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "config.h" - -#include <string.h> - -#include "glib.h" - -#ifdef _ -#warning "FIXME remove gettext hack" -#endif - -#include "glibintl.h" -#include "galias.h" - -GQuark -g_shell_error_quark (void) -{ - return g_quark_from_static_string ("g-shell-error-quark"); -} - -/* Single quotes preserve the literal string exactly. escape - * sequences are not allowed; not even \' - if you want a ' - * in the quoted text, you have to do something like 'foo'\''bar' - * - * Double quotes allow $ ` " \ and newline to be escaped with backslash. - * Otherwise double quotes preserve things literally. - */ - -static gboolean -unquote_string_inplace (gchar* str, gchar** end, GError** err) -{ - gchar* dest; - gchar* s; - gchar quote_char; - - g_return_val_if_fail(end != NULL, FALSE); - g_return_val_if_fail(err == NULL || *err == NULL, FALSE); - g_return_val_if_fail(str != NULL, FALSE); - - dest = s = str; - - quote_char = *s; - - if (!(*s == '"' || *s == '\'')) - { - g_set_error_literal (err, - G_SHELL_ERROR, - G_SHELL_ERROR_BAD_QUOTING, - _("Quoted text doesn't begin with a quotation mark")); - *end = str; - return FALSE; - } - - /* Skip the initial quote mark */ - ++s; - - if (quote_char == '"') - { - while (*s) - { - g_assert(s > dest); /* loop invariant */ - - switch (*s) - { - case '"': - /* End of the string, return now */ - *dest = '\0'; - ++s; - *end = s; - return TRUE; - break; - - case '\\': - /* Possible escaped quote or \ */ - ++s; - switch (*s) - { - case '"': - case '\\': - case '`': - case '$': - case '\n': - *dest = *s; - ++s; - ++dest; - break; - - default: - /* not an escaped char */ - *dest = '\\'; - ++dest; - /* ++s already done. */ - break; - } - break; - - default: - *dest = *s; - ++dest; - ++s; - break; - } - - g_assert(s > dest); /* loop invariant */ - } - } - else - { - while (*s) - { - g_assert(s > dest); /* loop invariant */ - - if (*s == '\'') - { - /* End of the string, return now */ - *dest = '\0'; - ++s; - *end = s; - return TRUE; - } - else - { - *dest = *s; - ++dest; - ++s; - } - - g_assert(s > dest); /* loop invariant */ - } - } - - /* If we reach here this means the close quote was never encountered */ - - *dest = '\0'; - - g_set_error_literal (err, - G_SHELL_ERROR, - G_SHELL_ERROR_BAD_QUOTING, - _("Unmatched quotation mark in command line or other shell-quoted text")); - *end = s; - return FALSE; -} - -/** - * g_shell_quote: - * @unquoted_string: a literal string - * - * Quotes a string so that the shell (/bin/sh) will interpret the - * quoted string to mean @unquoted_string. If you pass a filename to - * the shell, for example, you should first quote it with this - * function. The return value must be freed with g_free(). The - * quoting style used is undefined (single or double quotes may be - * used). - * - * Return value: quoted string - **/ -gchar* -g_shell_quote (const gchar *unquoted_string) -{ - /* We always use single quotes, because the algorithm is cheesier. - * We could use double if we felt like it, that might be more - * human-readable. - */ - - const gchar *p; - GString *dest; - - g_return_val_if_fail (unquoted_string != NULL, NULL); - - dest = g_string_new ("'"); - - p = unquoted_string; - - /* could speed this up a lot by appending chunks of text at a - * time. - */ - while (*p) - { - /* Replace literal ' with a close ', a \', and a open ' */ - if (*p == '\'') - g_string_append (dest, "'\\''"); - else - g_string_append_c (dest, *p); - - ++p; - } - - /* close the quote */ - g_string_append_c (dest, '\''); - - return g_string_free (dest, FALSE); -} - -/** - * g_shell_unquote: - * @quoted_string: shell-quoted string - * @error: error return location or NULL - * - * Unquotes a string as the shell (/bin/sh) would. Only handles - * quotes; if a string contains file globs, arithmetic operators, - * variables, backticks, redirections, or other special-to-the-shell - * features, the result will be different from the result a real shell - * would produce (the variables, backticks, etc. will be passed - * through literally instead of being expanded). This function is - * guaranteed to succeed if applied to the result of - * g_shell_quote(). If it fails, it returns %NULL and sets the - * error. The @quoted_string need not actually contain quoted or - * escaped text; g_shell_unquote() simply goes through the string and - * unquotes/unescapes anything that the shell would. Both single and - * double quotes are handled, as are escapes including escaped - * newlines. The return value must be freed with g_free(). Possible - * errors are in the #G_SHELL_ERROR domain. - * - * Shell quoting rules are a bit strange. Single quotes preserve the - * literal string exactly. escape sequences are not allowed; not even - * \' - if you want a ' in the quoted text, you have to do something - * like 'foo'\''bar'. Double quotes allow $, `, ", \, and newline to - * be escaped with backslash. Otherwise double quotes preserve things - * literally. - * - * Return value: an unquoted string - **/ -gchar* -g_shell_unquote (const gchar *quoted_string, - GError **error) -{ - gchar *unquoted; - gchar *end; - gchar *start; - GString *retval; - - g_return_val_if_fail (quoted_string != NULL, NULL); - - unquoted = g_strdup (quoted_string); - - start = unquoted; - end = unquoted; - retval = g_string_new (NULL); - - /* The loop allows cases such as - * "foo"blah blah'bar'woo foo"baz"la la la\'\''foo' - */ - while (*start) - { - /* Append all non-quoted chars, honoring backslash escape - */ - - while (*start && !(*start == '"' || *start == '\'')) - { - if (*start == '\\') - { - /* all characters can get escaped by backslash, - * except newline, which is removed if it follows - * a backslash outside of quotes - */ - - ++start; - if (*start) - { - if (*start != '\n') - g_string_append_c (retval, *start); - ++start; - } - } - else - { - g_string_append_c (retval, *start); - ++start; - } - } - - if (*start) - { - if (!unquote_string_inplace (start, &end, error)) - { - goto error; - } - else - { - g_string_append (retval, start); - start = end; - } - } - } - - g_free (unquoted); - return g_string_free (retval, FALSE); - - error: - g_assert (error == NULL || *error != NULL); - - g_free (unquoted); - g_string_free (retval, TRUE); - return NULL; -} - -/* g_parse_argv() does a semi-arbitrary weird subset of the way - * the shell parses a command line. We don't do variable expansion, - * don't understand that operators are tokens, don't do tilde expansion, - * don't do command substitution, no arithmetic expansion, IFS gets ignored, - * don't do filename globs, don't remove redirection stuff, etc. - * - * READ THE UNIX98 SPEC on "Shell Command Language" before changing - * the behavior of this code. - * - * Steps to parsing the argv string: - * - * - tokenize the string (but since we ignore operators, - * our tokenization may diverge from what the shell would do) - * note that tokenization ignores the internals of a quoted - * word and it always splits on spaces, not on IFS even - * if we used IFS. We also ignore "end of input indicator" - * (I guess this is control-D?) - * - * Tokenization steps, from UNIX98 with operator stuff removed, - * are: - * - * 1) "If the current character is backslash, single-quote or - * double-quote (\, ' or ") and it is not quoted, it will affect - * quoting for subsequent characters up to the end of the quoted - * text. The rules for quoting are as described in Quoting - * . During token recognition no substitutions will be actually - * performed, and the result token will contain exactly the - * characters that appear in the input (except for newline - * character joining), unmodified, including any embedded or - * enclosing quotes or substitution operators, between the quote - * mark and the end of the quoted text. The token will not be - * delimited by the end of the quoted field." - * - * 2) "If the current character is an unquoted newline character, - * the current token will be delimited." - * - * 3) "If the current character is an unquoted blank character, any - * token containing the previous character is delimited and the - * current character will be discarded." - * - * 4) "If the previous character was part of a word, the current - * character will be appended to that word." - * - * 5) "If the current character is a "#", it and all subsequent - * characters up to, but excluding, the next newline character - * will be discarded as a comment. The newline character that - * ends the line is not considered part of the comment. The - * "#" starts a comment only when it is at the beginning of a - * token. Since the search for the end-of-comment does not - * consider an escaped newline character specially, a comment - * cannot be continued to the next line." - * - * 6) "The current character will be used as the start of a new word." - * - * - * - for each token (word), perform portions of word expansion, namely - * field splitting (using default whitespace IFS) and quote - * removal. Field splitting may increase the number of words. - * Quote removal does not increase the number of words. - * - * "If the complete expansion appropriate for a word results in an - * empty field, that empty field will be deleted from the list of - * fields that form the completely expanded command, unless the - * original word contained single-quote or double-quote characters." - * - UNIX98 spec - * - * - */ - -static inline void -ensure_token (GString **token) -{ - if (*token == NULL) - *token = g_string_new (NULL); -} - -static void -delimit_token (GString **token, - GSList **retval) -{ - if (*token == NULL) - return; - - *retval = g_slist_prepend (*retval, g_string_free (*token, FALSE)); - - *token = NULL; -} - -static GSList* -tokenize_command_line (const gchar *command_line, - GError **error) -{ - gchar current_quote; - const gchar *p; - GString *current_token = NULL; - GSList *retval = NULL; - gboolean quoted;; - - current_quote = '\0'; - quoted = FALSE; - p = command_line; - - while (*p) - { - if (current_quote == '\\') - { - if (*p == '\n') - { - /* we append nothing; backslash-newline become nothing */ - } - else - { - /* we append the backslash and the current char, - * to be interpreted later after tokenization - */ - ensure_token (¤t_token); - g_string_append_c (current_token, '\\'); - g_string_append_c (current_token, *p); - } - - current_quote = '\0'; - } - else if (current_quote == '#') - { - /* Discard up to and including next newline */ - while (*p && *p != '\n') - ++p; - - current_quote = '\0'; - - if (*p == '\0') - break; - } - else if (current_quote) - { - if (*p == current_quote && - /* check that it isn't an escaped double quote */ - !(current_quote == '"' && quoted)) - { - /* close the quote */ - current_quote = '\0'; - } - - /* Everything inside quotes, and the close quote, - * gets appended literally. - */ - - ensure_token (¤t_token); - g_string_append_c (current_token, *p); - } - else - { - switch (*p) - { - case '\n': - delimit_token (¤t_token, &retval); - break; - - case ' ': - case '\t': - /* If the current token contains the previous char, delimit - * the current token. A nonzero length - * token should always contain the previous char. - */ - if (current_token && - current_token->len > 0) - { - delimit_token (¤t_token, &retval); - } - - /* discard all unquoted blanks (don't add them to a token) */ - break; - - - /* single/double quotes are appended to the token, - * escapes are maybe appended next time through the loop, - * comment chars are never appended. - */ - - case '\'': - case '"': - ensure_token (¤t_token); - g_string_append_c (current_token, *p); - - /* FALL THRU */ - - case '#': - case '\\': - current_quote = *p; - break; - - default: - /* Combines rules 4) and 6) - if we have a token, append to it, - * otherwise create a new token. - */ - ensure_token (¤t_token); - g_string_append_c (current_token, *p); - break; - } - } - - /* We need to count consecutive backslashes mod 2, - * to detect escaped doublequotes. - */ - if (*p != '\\') - quoted = FALSE; - else - quoted = !quoted; - - ++p; - } - - delimit_token (¤t_token, &retval); - - if (current_quote) - { - if (current_quote == '\\') - g_set_error (error, - G_SHELL_ERROR, - G_SHELL_ERROR_BAD_QUOTING, - _("Text ended just after a '\\' character." - " (The text was '%s')"), - command_line); - else - g_set_error (error, - G_SHELL_ERROR, - G_SHELL_ERROR_BAD_QUOTING, - _("Text ended before matching quote was found for %c." - " (The text was '%s')"), - current_quote, command_line); - - goto error; - } - - if (retval == NULL) - { - g_set_error_literal (error, - G_SHELL_ERROR, - G_SHELL_ERROR_EMPTY_STRING, - _("Text was empty (or contained only whitespace)")); - - goto error; - } - - /* we appended backward */ - retval = g_slist_reverse (retval); - - return retval; - - error: - g_assert (error == NULL || *error != NULL); - - if (retval) - { - g_slist_foreach (retval, (GFunc)g_free, NULL); - g_slist_free (retval); - } - - return NULL; -} - -/** - * g_shell_parse_argv: - * @command_line: command line to parse - * @argcp: return location for number of args - * @argvp: return location for array of args - * @error: return location for error - * - * Parses a command line into an argument vector, in much the same way - * the shell would, but without many of the expansions the shell would - * perform (variable expansion, globs, operators, filename expansion, - * etc. are not supported). The results are defined to be the same as - * those you would get from a UNIX98 /bin/sh, as long as the input - * contains none of the unsupported shell expansions. If the input - * does contain such expansions, they are passed through - * literally. Possible errors are those from the #G_SHELL_ERROR - * domain. Free the returned vector with g_strfreev(). - * - * Return value: %TRUE on success, %FALSE if error set - **/ -gboolean -g_shell_parse_argv (const gchar *command_line, - gint *argcp, - gchar ***argvp, - GError **error) -{ - /* Code based on poptParseArgvString() from libpopt */ - gint argc = 0; - gchar **argv = NULL; - GSList *tokens = NULL; - gint i; - GSList *tmp_list; - - g_return_val_if_fail (command_line != NULL, FALSE); - - tokens = tokenize_command_line (command_line, error); - if (tokens == NULL) - return FALSE; - - /* Because we can't have introduced any new blank space into the - * tokens (we didn't do any new expansions), we don't need to - * perform field splitting. If we were going to honor IFS or do any - * expansions, we would have to do field splitting on each word - * here. Also, if we were going to do any expansion we would need to - * remove any zero-length words that didn't contain quotes - * originally; but since there's no expansion we know all words have - * nonzero length, unless they contain quotes. - * - * So, we simply remove quotes, and don't do any field splitting or - * empty word removal, since we know there was no way to introduce - * such things. - */ - - argc = g_slist_length (tokens); - argv = g_new0 (gchar*, argc + 1); - i = 0; - tmp_list = tokens; - while (tmp_list) - { - argv[i] = g_shell_unquote (tmp_list->data, error); - - /* Since we already checked that quotes matched up in the - * tokenizer, this shouldn't be possible to reach I guess. - */ - if (argv[i] == NULL) - goto failed; - - tmp_list = g_slist_next (tmp_list); - ++i; - } - - g_slist_foreach (tokens, (GFunc)g_free, NULL); - g_slist_free (tokens); - - if (argcp) - *argcp = argc; - - if (argvp) - *argvp = argv; - else - g_strfreev (argv); - - return TRUE; - - failed: - - g_assert (error == NULL || *error != NULL); - g_strfreev (argv); - g_slist_foreach (tokens, (GFunc) g_free, NULL); - g_slist_free (tokens); - - return FALSE; -} - -#define __G_SHELL_C__ -#include "galiasdef.c" diff --git a/glib/gspawn-win32-helper.c b/glib/gspawn-win32-helper.c deleted file mode 100644 index 40108bb67..000000000 --- a/glib/gspawn-win32-helper.c +++ /dev/null @@ -1,333 +0,0 @@ -/* gspawn-win32-helper.c - Helper program for process launching on Win32. - * - * Copyright 2000 Red Hat, Inc. - * Copyright 2000 Tor Lillqvist - * - * GLib 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 of the - * License, or (at your option) any later version. - * - * GLib 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 GLib; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "config.h" - -#include <fcntl.h> - -#undef G_LOG_DOMAIN -#include "glib.h" -#define GSPAWN_HELPER -#include "gspawn-win32.c" /* For shared definitions */ - - -static void -write_err_and_exit (gint fd, - gintptr msg) -{ - gintptr en = errno; - - write (fd, &msg, sizeof(gintptr)); - write (fd, &en, sizeof(gintptr)); - - _exit (1); -} - -#ifdef __GNUC__ -# ifndef _stdcall -# define _stdcall __attribute__((stdcall)) -# endif -#endif - -/* We build gspawn-win32-helper.exe as a Windows GUI application - * to avoid any temporarily flashing console windows in case - * the gspawn function is invoked by a GUI program. Thus, no main() - * but a WinMain(). We do, however, still use argc and argv tucked - * away in the global __argc and __argv by the C runtime startup code. - */ - -/* Info peeked from mingw runtime's source code. __wgetmainargs() is a - * function to get the program's argv in wide char format. - */ - -typedef struct { - int newmode; -} _startupinfo; - -extern void __wgetmainargs(int *argc, - wchar_t ***wargv, - wchar_t ***wenviron, - int expand_wildcards, - _startupinfo *startupinfo); - -/* Copy of protect_argv that handles wchar_t strings */ - -static gint -protect_wargv (wchar_t **wargv, - wchar_t ***new_wargv) -{ - gint i; - gint argc = 0; - - while (wargv[argc]) - ++argc; - *new_wargv = g_new (wchar_t *, argc+1); - - /* Quote each argv element if necessary, so that it will get - * reconstructed correctly in the C runtime startup code. Note that - * the unquoting algorithm in the C runtime is really weird, and - * rather different than what Unix shells do. See stdargv.c in the C - * runtime sources (in the Platform SDK, in src/crt). - * - * Note that an new_wargv[0] constructed by this function should - * *not* be passed as the filename argument to a _wspawn* or _wexec* - * family function. That argument should be the real file name - * without any quoting. - */ - for (i = 0; i < argc; i++) - { - wchar_t *p = wargv[i]; - wchar_t *q; - gint len = 0; - gboolean need_dblquotes = FALSE; - while (*p) - { - if (*p == ' ' || *p == '\t') - need_dblquotes = TRUE; - else if (*p == '"') - len++; - else if (*p == '\\') - { - wchar_t *pp = p; - while (*pp && *pp == '\\') - pp++; - if (*pp == '"') - len++; - } - len++; - p++; - } - - q = (*new_wargv)[i] = g_new (wchar_t, len + need_dblquotes*2 + 1); - p = wargv[i]; - - if (need_dblquotes) - *q++ = '"'; - - while (*p) - { - if (*p == '"') - *q++ = '\\'; - else if (*p == '\\') - { - wchar_t *pp = p; - while (*pp && *pp == '\\') - pp++; - if (*pp == '"') - *q++ = '\\'; - } - *q++ = *p; - p++; - } - - if (need_dblquotes) - *q++ = '"'; - *q++ = '\0'; - } - (*new_wargv)[argc] = NULL; - - return argc; -} - -#ifndef HELPER_CONSOLE -int _stdcall -WinMain (struct HINSTANCE__ *hInstance, - struct HINSTANCE__ *hPrevInstance, - char *lpszCmdLine, - int nCmdShow) -#else -int -main (int ignored_argc, char **ignored_argv) -#endif -{ - int child_err_report_fd = -1; - int helper_sync_fd = -1; - int i; - int fd; - int mode; - gintptr handle; - int saved_errno; - gintptr no_error = CHILD_NO_ERROR; - gint argv_zero_offset = ARG_PROGRAM; - wchar_t **new_wargv; - int argc; - wchar_t **wargv, **wenvp; - _startupinfo si = { 0 }; - char c; - - g_assert (__argc >= ARG_COUNT); - - /* Fetch the wide-char argument vector */ - __wgetmainargs (&argc, &wargv, &wenvp, 0, &si); - - /* We still have the system codepage args in __argv. We can look - * at the first args in which gspawn-win32.c passes us flags and - * fd numbers in __argv, as we know those are just ASCII anyway. - */ - g_assert (argc == __argc); - - /* argv[ARG_CHILD_ERR_REPORT] is the file descriptor number onto - * which write error messages. - */ - child_err_report_fd = atoi (__argv[ARG_CHILD_ERR_REPORT]); - - /* Hack to implement G_SPAWN_FILE_AND_ARGV_ZERO. If - * argv[ARG_CHILD_ERR_REPORT] is suffixed with a '#' it means we get - * the program to run and its argv[0] separately. - */ - if (__argv[ARG_CHILD_ERR_REPORT][strlen (__argv[ARG_CHILD_ERR_REPORT]) - 1] == '#') - argv_zero_offset++; - - /* argv[ARG_HELPER_SYNC] is the file descriptor number we read a - * byte that tells us it is OK to exit. We have to wait until the - * parent allows us to exit, so that the parent has had time to - * duplicate the process handle we sent it. Duplicating a handle - * from another process works only if that other process exists. - */ - helper_sync_fd = atoi (__argv[ARG_HELPER_SYNC]); - - /* argv[ARG_STDIN..ARG_STDERR] are the file descriptor numbers that - * should be dup2'd to 0, 1 and 2. '-' if the corresponding fd - * should be left alone, and 'z' if it should be connected to the - * bit bucket NUL:. - */ - if (__argv[ARG_STDIN][0] == '-') - ; /* Nothing */ - else if (__argv[ARG_STDIN][0] == 'z') - { - fd = open ("NUL:", O_RDONLY); - if (fd != 0) - { - dup2 (fd, 0); - close (fd); - } - } - else - { - fd = atoi (__argv[ARG_STDIN]); - if (fd != 0) - { - dup2 (fd, 0); - close (fd); - } - } - - if (__argv[ARG_STDOUT][0] == '-') - ; /* Nothing */ - else if (__argv[ARG_STDOUT][0] == 'z') - { - fd = open ("NUL:", O_WRONLY); - if (fd != 1) - { - dup2 (fd, 1); - close (fd); - } - } - else - { - fd = atoi (__argv[ARG_STDOUT]); - if (fd != 1) - { - dup2 (fd, 1); - close (fd); - } - } - - if (__argv[ARG_STDERR][0] == '-') - ; /* Nothing */ - else if (__argv[ARG_STDERR][0] == 'z') - { - fd = open ("NUL:", O_WRONLY); - if (fd != 2) - { - dup2 (fd, 2); - close (fd); - } - } - else - { - fd = atoi (__argv[ARG_STDERR]); - if (fd != 2) - { - dup2 (fd, 2); - close (fd); - } - } - - /* __argv[ARG_WORKING_DIRECTORY] is the directory in which to run the - * process. If "-", don't change directory. - */ - if (__argv[ARG_WORKING_DIRECTORY][0] == '-' && - __argv[ARG_WORKING_DIRECTORY][1] == 0) - ; /* Nothing */ - else if (_wchdir (wargv[ARG_WORKING_DIRECTORY]) < 0) - write_err_and_exit (child_err_report_fd, CHILD_CHDIR_FAILED); - - /* __argv[ARG_CLOSE_DESCRIPTORS] is "y" if file descriptors from 3 - * upwards should be closed - */ - if (__argv[ARG_CLOSE_DESCRIPTORS][0] == 'y') - for (i = 3; i < 1000; i++) /* FIXME real limit? */ - if (i != child_err_report_fd && i != helper_sync_fd) - close (i); - - /* We don't want our child to inherit the error report and - * helper sync fds. - */ - child_err_report_fd = dup_noninherited (child_err_report_fd, _O_WRONLY); - helper_sync_fd = dup_noninherited (helper_sync_fd, _O_RDONLY); - - /* __argv[ARG_WAIT] is "w" to wait for the program to exit */ - if (__argv[ARG_WAIT][0] == 'w') - mode = P_WAIT; - else - mode = P_NOWAIT; - - /* __argv[ARG_USE_PATH] is "y" to use PATH, otherwise not */ - - /* __argv[ARG_PROGRAM] is executable file to run, - * __argv[argv_zero_offset]... is its argv. argv_zero_offset equals - * ARG_PROGRAM unless G_SPAWN_FILE_AND_ARGV_ZERO was used, in which - * case we have a separate executable name and argv[0]. - */ - - /* For the program name passed to spawnv(), don't use the quoted - * version. - */ - protect_wargv (wargv + argv_zero_offset, &new_wargv); - - if (__argv[ARG_USE_PATH][0] == 'y') - handle = _wspawnvp (mode, wargv[ARG_PROGRAM], (const wchar_t **) new_wargv); - else - handle = _wspawnv (mode, wargv[ARG_PROGRAM], (const wchar_t **) new_wargv); - - saved_errno = errno; - - if (handle == -1 && saved_errno != 0) - write_err_and_exit (child_err_report_fd, CHILD_SPAWN_FAILED); - - write (child_err_report_fd, &no_error, sizeof (no_error)); - write (child_err_report_fd, &handle, sizeof (handle)); - - read (helper_sync_fd, &c, 1); - - return 0; -} diff --git a/glib/gspawn-win32.c b/glib/gspawn-win32.c deleted file mode 100644 index ba7970bb1..000000000 --- a/glib/gspawn-win32.c +++ /dev/null @@ -1,1494 +0,0 @@ -/* gspawn-win32.c - Process launching on Win32 - * - * Copyright 2000 Red Hat, Inc. - * Copyright 2003 Tor Lillqvist - * - * GLib 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 of the - * License, or (at your option) any later version. - * - * GLib 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 GLib; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Implementation details on Win32. - * - * - There is no way to set the no-inherit flag for - * a "file descriptor" in the MS C runtime. The flag is there, - * and the dospawn() function uses it, but unfortunately - * this flag can only be set when opening the file. - * - As there is no fork(), we cannot reliably change directory - * before starting the child process. (There might be several threads - * running, and the current directory is common for all threads.) - * - * Thus, we must in many cases use a helper program to handle closing - * of (inherited) file descriptors and changing of directory. The - * helper process is also needed if the standard input, standard - * output, or standard error of the process to be run are supposed to - * be redirected somewhere. - * - * The structure of the source code in this file is a mess, I know. - */ - -/* Define this to get some logging all the time */ -/* #define G_SPAWN_WIN32_DEBUG */ - -#include "config.h" - -#include "glib.h" -#include "gprintfint.h" -#include "glibintl.h" -#include "galias.h" - -#include <string.h> -#include <stdlib.h> -#include <stdio.h> - -#include <windows.h> -#include <errno.h> -#include <fcntl.h> -#include <io.h> -#include <process.h> -#include <direct.h> -#include <wchar.h> - -#ifdef G_SPAWN_WIN32_DEBUG - static int debug = 1; - #define SETUP_DEBUG() /* empty */ -#else - static int debug = -1; - #define SETUP_DEBUG() \ - G_STMT_START \ - { \ - if (debug == -1) \ - { \ - if (getenv ("G_SPAWN_WIN32_DEBUG") != NULL) \ - debug = 1; \ - else \ - debug = 0; \ - } \ - } \ - G_STMT_END -#endif - -enum -{ - CHILD_NO_ERROR, - CHILD_CHDIR_FAILED, - CHILD_SPAWN_FAILED, -}; - -enum { - ARG_CHILD_ERR_REPORT = 1, - ARG_HELPER_SYNC, - ARG_STDIN, - ARG_STDOUT, - ARG_STDERR, - ARG_WORKING_DIRECTORY, - ARG_CLOSE_DESCRIPTORS, - ARG_USE_PATH, - ARG_WAIT, - ARG_PROGRAM, - ARG_COUNT = ARG_PROGRAM -}; - -static int -dup_noninherited (int fd, - int mode) -{ - HANDLE filehandle; - - DuplicateHandle (GetCurrentProcess (), (LPHANDLE) _get_osfhandle (fd), - GetCurrentProcess (), &filehandle, - 0, FALSE, DUPLICATE_SAME_ACCESS); - close (fd); - return _open_osfhandle ((gintptr) filehandle, mode | _O_NOINHERIT); -} - -#ifndef GSPAWN_HELPER - -#ifdef _WIN64 -#define HELPER_PROCESS "gspawn-win64-helper" -#else -#define HELPER_PROCESS "gspawn-win32-helper" -#endif - -static gchar * -protect_argv_string (const gchar *string) -{ - const gchar *p = string; - gchar *retval, *q; - gint len = 0; - gboolean need_dblquotes = FALSE; - while (*p) - { - if (*p == ' ' || *p == '\t') - need_dblquotes = TRUE; - else if (*p == '"') - len++; - else if (*p == '\\') - { - const gchar *pp = p; - while (*pp && *pp == '\\') - pp++; - if (*pp == '"') - len++; - } - len++; - p++; - } - - q = retval = g_malloc (len + need_dblquotes*2 + 1); - p = string; - - if (need_dblquotes) - *q++ = '"'; - - while (*p) - { - if (*p == '"') - *q++ = '\\'; - else if (*p == '\\') - { - const gchar *pp = p; - while (*pp && *pp == '\\') - pp++; - if (*pp == '"') - *q++ = '\\'; - } - *q++ = *p; - p++; - } - - if (need_dblquotes) - *q++ = '"'; - *q++ = '\0'; - - return retval; -} - -static gint -protect_argv (gchar **argv, - gchar ***new_argv) -{ - gint i; - gint argc = 0; - - while (argv[argc]) - ++argc; - *new_argv = g_new (gchar *, argc+1); - - /* Quote each argv element if necessary, so that it will get - * reconstructed correctly in the C runtime startup code. Note that - * the unquoting algorithm in the C runtime is really weird, and - * rather different than what Unix shells do. See stdargv.c in the C - * runtime sources (in the Platform SDK, in src/crt). - * - * Note that an new_argv[0] constructed by this function should - * *not* be passed as the filename argument to a spawn* or exec* - * family function. That argument should be the real file name - * without any quoting. - */ - for (i = 0; i < argc; i++) - (*new_argv)[i] = protect_argv_string (argv[i]); - - (*new_argv)[argc] = NULL; - - return argc; -} - -GQuark -g_spawn_error_quark (void) -{ - return g_quark_from_static_string ("g-exec-error-quark"); -} - -gboolean -g_spawn_async_utf8 (const gchar *working_directory, - gchar **argv, - gchar **envp, - GSpawnFlags flags, - GSpawnChildSetupFunc child_setup, - gpointer user_data, - GPid *child_handle, - GError **error) -{ - g_return_val_if_fail (argv != NULL, FALSE); - - return g_spawn_async_with_pipes_utf8 (working_directory, - argv, envp, - flags, - child_setup, - user_data, - child_handle, - NULL, NULL, NULL, - error); -} - -/* Avoids a danger in threaded situations (calling close() - * on a file descriptor twice, and another thread has - * re-opened it since the first close) - */ -static void -close_and_invalidate (gint *fd) -{ - if (*fd < 0) - return; - - close (*fd); - *fd = -1; -} - -typedef enum -{ - READ_FAILED = 0, /* FALSE */ - READ_OK, - READ_EOF -} ReadResult; - -static ReadResult -read_data (GString *str, - GIOChannel *iochannel, - GError **error) -{ - GIOStatus giostatus; - gsize bytes; - gchar buf[4096]; - - again: - - giostatus = g_io_channel_read_chars (iochannel, buf, sizeof (buf), &bytes, NULL); - - if (bytes == 0) - return READ_EOF; - else if (bytes > 0) - { - g_string_append_len (str, buf, bytes); - return READ_OK; - } - else if (giostatus == G_IO_STATUS_AGAIN) - goto again; - else if (giostatus == G_IO_STATUS_ERROR) - { - g_set_error_literal (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ, - _("Failed to read data from child process")); - - return READ_FAILED; - } - else - return READ_OK; -} - -static gboolean -make_pipe (gint p[2], - GError **error) -{ - if (_pipe (p, 4096, _O_BINARY) < 0) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Failed to create pipe for communicating with child process (%s)"), - g_strerror (errno)); - return FALSE; - } - else - return TRUE; -} - -/* The helper process writes a status report back to us, through a - * pipe, consisting of two ints. - */ -static gboolean -read_helper_report (int fd, - gintptr report[2], - GError **error) -{ - gint bytes = 0; - - while (bytes < sizeof(gintptr)*2) - { - gint chunk; - - if (debug) - g_print ("%s:read_helper_report: read %" G_GSIZE_FORMAT "...\n", - __FILE__, - sizeof(gintptr)*2 - bytes); - - chunk = read (fd, ((gchar*)report) + bytes, - sizeof(gintptr)*2 - bytes); - - if (debug) - g_print ("...got %d bytes\n", chunk); - - if (chunk < 0) - { - /* Some weird shit happened, bail out */ - - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Failed to read from child pipe (%s)"), - g_strerror (errno)); - - return FALSE; - } - else if (chunk == 0) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Failed to read from child pipe (%s)"), - "EOF"); - break; /* EOF */ - } - else - bytes += chunk; - } - - if (bytes < sizeof(gintptr)*2) - return FALSE; - - return TRUE; -} - -static void -set_child_error (gintptr report[2], - const gchar *working_directory, - GError **error) -{ - switch (report[0]) - { - case CHILD_CHDIR_FAILED: - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR, - _("Failed to change to directory '%s' (%s)"), - working_directory, - g_strerror (report[1])); - break; - case CHILD_SPAWN_FAILED: - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Failed to execute child process (%s)"), - g_strerror (report[1])); - break; - default: - g_assert_not_reached (); - } -} - -static gboolean -utf8_charv_to_wcharv (char **utf8_charv, - wchar_t ***wcharv, - int *error_index, - GError **error) -{ - wchar_t **retval = NULL; - - *wcharv = NULL; - if (utf8_charv != NULL) - { - int n = 0, i; - - while (utf8_charv[n]) - n++; - retval = g_new (wchar_t *, n + 1); - - for (i = 0; i < n; i++) - { - retval[i] = g_utf8_to_utf16 (utf8_charv[i], -1, NULL, NULL, error); - if (retval[i] == NULL) - { - if (error_index) - *error_index = i; - while (i) - g_free (retval[--i]); - g_free (retval); - return FALSE; - } - } - - retval[n] = NULL; - } - *wcharv = retval; - return TRUE; -} - -static gboolean -do_spawn_directly (gint *exit_status, - gboolean do_return_handle, - GSpawnFlags flags, - gchar **argv, - char **envp, - char **protected_argv, - GPid *child_handle, - GError **error) -{ - const int mode = (exit_status == NULL) ? P_NOWAIT : P_WAIT; - char **new_argv; - gintptr rc = -1; - int saved_errno; - GError *conv_error = NULL; - gint conv_error_index; - wchar_t *wargv0, **wargv, **wenvp; - - new_argv = (flags & G_SPAWN_FILE_AND_ARGV_ZERO) ? protected_argv + 1 : protected_argv; - - wargv0 = g_utf8_to_utf16 (argv[0], -1, NULL, NULL, &conv_error); - if (wargv0 == NULL) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid program name: %s"), - conv_error->message); - g_error_free (conv_error); - - return FALSE; - } - - if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error)) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in argument vector at %d: %s"), - conv_error_index, conv_error->message); - g_error_free (conv_error); - g_free (wargv0); - - return FALSE; - } - - if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error)) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in environment: %s"), - conv_error->message); - g_error_free (conv_error); - g_free (wargv0); - g_strfreev ((gchar **) wargv); - - return FALSE; - } - - if (flags & G_SPAWN_SEARCH_PATH) - if (wenvp != NULL) - rc = _wspawnvpe (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp); - else - rc = _wspawnvp (mode, wargv0, (const wchar_t **) wargv); - else - if (wenvp != NULL) - rc = _wspawnve (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp); - else - rc = _wspawnv (mode, wargv0, (const wchar_t **) wargv); - - g_free (wargv0); - g_strfreev ((gchar **) wargv); - g_strfreev ((gchar **) wenvp); - - saved_errno = errno; - - if (rc == -1 && saved_errno != 0) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Failed to execute child process (%s)"), - g_strerror (saved_errno)); - return FALSE; - } - - if (exit_status == NULL) - { - if (child_handle && do_return_handle) - *child_handle = (GPid) rc; - else - { - CloseHandle ((HANDLE) rc); - if (child_handle) - *child_handle = 0; - } - } - else - *exit_status = rc; - - return TRUE; -} - -static gboolean -do_spawn_with_pipes (gint *exit_status, - gboolean do_return_handle, - const gchar *working_directory, - gchar **argv, - char **envp, - GSpawnFlags flags, - GSpawnChildSetupFunc child_setup, - GPid *child_handle, - gint *standard_input, - gint *standard_output, - gint *standard_error, - gint *err_report, - GError **error) -{ - char **protected_argv; - char args[ARG_COUNT][10]; - char **new_argv; - int i; - gintptr rc = -1; - int saved_errno; - int argc; - int stdin_pipe[2] = { -1, -1 }; - int stdout_pipe[2] = { -1, -1 }; - int stderr_pipe[2] = { -1, -1 }; - int child_err_report_pipe[2] = { -1, -1 }; - int helper_sync_pipe[2] = { -1, -1 }; - gintptr helper_report[2]; - static gboolean warned_about_child_setup = FALSE; - GError *conv_error = NULL; - gint conv_error_index; - gchar *helper_process; - CONSOLE_CURSOR_INFO cursor_info; - wchar_t *whelper, **wargv, **wenvp; - extern gchar *_glib_get_dll_directory (void); - gchar *glib_dll_directory; - - if (child_setup && !warned_about_child_setup) - { - warned_about_child_setup = TRUE; - g_warning ("passing a child setup function to the g_spawn functions is pointless on Windows and it is ignored"); - } - - argc = protect_argv (argv, &protected_argv); - - if (!standard_input && !standard_output && !standard_error && - (flags & G_SPAWN_CHILD_INHERITS_STDIN) && - !(flags & G_SPAWN_STDOUT_TO_DEV_NULL) && - !(flags & G_SPAWN_STDERR_TO_DEV_NULL) && - (working_directory == NULL || !*working_directory) && - (flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN)) - { - /* We can do without the helper process */ - gboolean retval = - do_spawn_directly (exit_status, do_return_handle, flags, - argv, envp, protected_argv, - child_handle, error); - g_strfreev (protected_argv); - return retval; - } - - if (standard_input && !make_pipe (stdin_pipe, error)) - goto cleanup_and_fail; - - if (standard_output && !make_pipe (stdout_pipe, error)) - goto cleanup_and_fail; - - if (standard_error && !make_pipe (stderr_pipe, error)) - goto cleanup_and_fail; - - if (!make_pipe (child_err_report_pipe, error)) - goto cleanup_and_fail; - - if (!make_pipe (helper_sync_pipe, error)) - goto cleanup_and_fail; - - new_argv = g_new (char *, argc + 1 + ARG_COUNT); - if (GetConsoleCursorInfo (GetStdHandle (STD_OUTPUT_HANDLE), &cursor_info)) - helper_process = HELPER_PROCESS "-console.exe"; - else - helper_process = HELPER_PROCESS ".exe"; - - glib_dll_directory = _glib_get_dll_directory (); - if (glib_dll_directory != NULL) - { - helper_process = g_build_filename (glib_dll_directory, helper_process, NULL); - g_free (glib_dll_directory); - } - else - helper_process = g_strdup (helper_process); - - new_argv[0] = protect_argv_string (helper_process); - - _g_sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_pipe[1]); - new_argv[ARG_CHILD_ERR_REPORT] = args[ARG_CHILD_ERR_REPORT]; - - /* Make the read end of the child error report pipe - * noninherited. Otherwise it will needlessly be inherited by the - * helper process, and the started actual user process. As such that - * shouldn't harm, but it is unnecessary. - */ - child_err_report_pipe[0] = dup_noninherited (child_err_report_pipe[0], _O_RDONLY); - - if (flags & G_SPAWN_FILE_AND_ARGV_ZERO) - { - /* Overload ARG_CHILD_ERR_REPORT to also encode the - * G_SPAWN_FILE_AND_ARGV_ZERO functionality. - */ - strcat (args[ARG_CHILD_ERR_REPORT], "#"); - } - - _g_sprintf (args[ARG_HELPER_SYNC], "%d", helper_sync_pipe[0]); - new_argv[ARG_HELPER_SYNC] = args[ARG_HELPER_SYNC]; - - /* Make the write end of the sync pipe noninherited. Otherwise the - * helper process will inherit it, and thus if this process happens - * to crash before writing the sync byte to the pipe, the helper - * process won't read but won't get any EOF either, as it has the - * write end open itself. - */ - helper_sync_pipe[1] = dup_noninherited (helper_sync_pipe[1], _O_WRONLY); - - if (standard_input) - { - _g_sprintf (args[ARG_STDIN], "%d", stdin_pipe[0]); - new_argv[ARG_STDIN] = args[ARG_STDIN]; - } - else if (flags & G_SPAWN_CHILD_INHERITS_STDIN) - { - /* Let stdin be alone */ - new_argv[ARG_STDIN] = "-"; - } - else - { - /* Keep process from blocking on a read of stdin */ - new_argv[ARG_STDIN] = "z"; - } - - if (standard_output) - { - _g_sprintf (args[ARG_STDOUT], "%d", stdout_pipe[1]); - new_argv[ARG_STDOUT] = args[ARG_STDOUT]; - } - else if (flags & G_SPAWN_STDOUT_TO_DEV_NULL) - { - new_argv[ARG_STDOUT] = "z"; - } - else - { - new_argv[ARG_STDOUT] = "-"; - } - - if (standard_error) - { - _g_sprintf (args[ARG_STDERR], "%d", stderr_pipe[1]); - new_argv[ARG_STDERR] = args[ARG_STDERR]; - } - else if (flags & G_SPAWN_STDERR_TO_DEV_NULL) - { - new_argv[ARG_STDERR] = "z"; - } - else - { - new_argv[ARG_STDERR] = "-"; - } - - if (working_directory && *working_directory) - new_argv[ARG_WORKING_DIRECTORY] = protect_argv_string (working_directory); - else - new_argv[ARG_WORKING_DIRECTORY] = g_strdup ("-"); - - if (!(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN)) - new_argv[ARG_CLOSE_DESCRIPTORS] = "y"; - else - new_argv[ARG_CLOSE_DESCRIPTORS] = "-"; - - if (flags & G_SPAWN_SEARCH_PATH) - new_argv[ARG_USE_PATH] = "y"; - else - new_argv[ARG_USE_PATH] = "-"; - - if (exit_status == NULL) - new_argv[ARG_WAIT] = "-"; - else - new_argv[ARG_WAIT] = "w"; - - for (i = 0; i <= argc; i++) - new_argv[ARG_PROGRAM + i] = protected_argv[i]; - - SETUP_DEBUG(); - - if (debug) - { - g_print ("calling %s with argv:\n", helper_process); - for (i = 0; i < argc + 1 + ARG_COUNT; i++) - g_print ("argv[%d]: %s\n", i, (new_argv[i] ? new_argv[i] : "NULL")); - } - - if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error)) - { - if (conv_error_index == ARG_WORKING_DIRECTORY) - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR, - _("Invalid working directory: %s"), - conv_error->message); - else - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in argument vector at %d: %s"), - conv_error_index - ARG_PROGRAM, conv_error->message); - g_error_free (conv_error); - g_strfreev (protected_argv); - g_free (new_argv[0]); - g_free (new_argv[ARG_WORKING_DIRECTORY]); - g_free (new_argv); - g_free (helper_process); - - goto cleanup_and_fail; - } - - if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error)) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in environment: %s"), - conv_error->message); - g_error_free (conv_error); - g_strfreev (protected_argv); - g_free (new_argv[0]); - g_free (new_argv[ARG_WORKING_DIRECTORY]); - g_free (new_argv); - g_free (helper_process); - g_strfreev ((gchar **) wargv); - - goto cleanup_and_fail; - } - - whelper = g_utf8_to_utf16 (helper_process, -1, NULL, NULL, NULL); - g_free (helper_process); - - if (wenvp != NULL) - rc = _wspawnvpe (P_NOWAIT, whelper, (const wchar_t **) wargv, (const wchar_t **) wenvp); - else - rc = _wspawnvp (P_NOWAIT, whelper, (const wchar_t **) wargv); - - saved_errno = errno; - - g_free (whelper); - g_strfreev ((gchar **) wargv); - g_strfreev ((gchar **) wenvp); - - /* Close the other process's ends of the pipes in this process, - * otherwise the reader will never get EOF. - */ - close_and_invalidate (&child_err_report_pipe[1]); - close_and_invalidate (&helper_sync_pipe[0]); - close_and_invalidate (&stdin_pipe[0]); - close_and_invalidate (&stdout_pipe[1]); - close_and_invalidate (&stderr_pipe[1]); - - g_strfreev (protected_argv); - - g_free (new_argv[0]); - g_free (new_argv[ARG_WORKING_DIRECTORY]); - g_free (new_argv); - - /* Check if gspawn-win32-helper couldn't be run */ - if (rc == -1 && saved_errno != 0) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Failed to execute helper program (%s)"), - g_strerror (saved_errno)); - goto cleanup_and_fail; - } - - if (exit_status != NULL) - { - /* Synchronous case. Pass helper's report pipe back to caller, - * which takes care of reading it after the grandchild has - * finished. - */ - g_assert (err_report != NULL); - *err_report = child_err_report_pipe[0]; - write (helper_sync_pipe[1], " ", 1); - close_and_invalidate (&helper_sync_pipe[1]); - } - else - { - /* Asynchronous case. We read the helper's report right away. */ - if (!read_helper_report (child_err_report_pipe[0], helper_report, error)) - goto cleanup_and_fail; - - close_and_invalidate (&child_err_report_pipe[0]); - - switch (helper_report[0]) - { - case CHILD_NO_ERROR: - if (child_handle && do_return_handle) - { - /* rc is our HANDLE for gspawn-win32-helper. It has - * told us the HANDLE of its child. Duplicate that into - * a HANDLE valid in this process. - */ - if (!DuplicateHandle ((HANDLE) rc, (HANDLE) helper_report[1], - GetCurrentProcess (), (LPHANDLE) child_handle, - 0, TRUE, DUPLICATE_SAME_ACCESS)) - { - char *emsg = g_win32_error_message (GetLastError ()); - g_print("%s\n", emsg); - *child_handle = 0; - } - } - else if (child_handle) - *child_handle = 0; - write (helper_sync_pipe[1], " ", 1); - close_and_invalidate (&helper_sync_pipe[1]); - break; - - default: - write (helper_sync_pipe[1], " ", 1); - close_and_invalidate (&helper_sync_pipe[1]); - set_child_error (helper_report, working_directory, error); - goto cleanup_and_fail; - } - } - - /* Success against all odds! return the information */ - - if (standard_input) - *standard_input = stdin_pipe[1]; - if (standard_output) - *standard_output = stdout_pipe[0]; - if (standard_error) - *standard_error = stderr_pipe[0]; - if (rc != -1) - CloseHandle ((HANDLE) rc); - - return TRUE; - - cleanup_and_fail: - - if (rc != -1) - CloseHandle ((HANDLE) rc); - if (child_err_report_pipe[0] != -1) - close (child_err_report_pipe[0]); - if (child_err_report_pipe[1] != -1) - close (child_err_report_pipe[1]); - if (helper_sync_pipe[0] != -1) - close (helper_sync_pipe[0]); - if (helper_sync_pipe[1] != -1) - close (helper_sync_pipe[1]); - if (stdin_pipe[0] != -1) - close (stdin_pipe[0]); - if (stdin_pipe[1] != -1) - close (stdin_pipe[1]); - if (stdout_pipe[0] != -1) - close (stdout_pipe[0]); - if (stdout_pipe[1] != -1) - close (stdout_pipe[1]); - if (stderr_pipe[0] != -1) - close (stderr_pipe[0]); - if (stderr_pipe[1] != -1) - close (stderr_pipe[1]); - - return FALSE; -} - -gboolean -g_spawn_sync_utf8 (const gchar *working_directory, - gchar **argv, - gchar **envp, - GSpawnFlags flags, - GSpawnChildSetupFunc child_setup, - gpointer user_data, - gchar **standard_output, - gchar **standard_error, - gint *exit_status, - GError **error) -{ - gint outpipe = -1; - gint errpipe = -1; - gint reportpipe = -1; - GIOChannel *outchannel = NULL; - GIOChannel *errchannel = NULL; - GPollFD outfd, errfd; - GPollFD fds[2]; - gint nfds; - gint outindex = -1; - gint errindex = -1; - gint ret; - GString *outstr = NULL; - GString *errstr = NULL; - gboolean failed; - gint status; - - g_return_val_if_fail (argv != NULL, FALSE); - g_return_val_if_fail (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), FALSE); - g_return_val_if_fail (standard_output == NULL || - !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE); - g_return_val_if_fail (standard_error == NULL || - !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE); - - /* Just to ensure segfaults if callers try to use - * these when an error is reported. - */ - if (standard_output) - *standard_output = NULL; - - if (standard_error) - *standard_error = NULL; - - if (!do_spawn_with_pipes (&status, - FALSE, - working_directory, - argv, - envp, - flags, - child_setup, - NULL, - NULL, - standard_output ? &outpipe : NULL, - standard_error ? &errpipe : NULL, - &reportpipe, - error)) - return FALSE; - - /* Read data from child. */ - - failed = FALSE; - - if (outpipe >= 0) - { - outstr = g_string_new (NULL); - outchannel = g_io_channel_win32_new_fd (outpipe); - g_io_channel_set_encoding (outchannel, NULL, NULL); - g_io_channel_set_buffered (outchannel, FALSE); - g_io_channel_win32_make_pollfd (outchannel, - G_IO_IN | G_IO_ERR | G_IO_HUP, - &outfd); - if (debug) - g_print ("outfd=%p\n", (HANDLE) outfd.fd); - } - - if (errpipe >= 0) - { - errstr = g_string_new (NULL); - errchannel = g_io_channel_win32_new_fd (errpipe); - g_io_channel_set_encoding (errchannel, NULL, NULL); - g_io_channel_set_buffered (errchannel, FALSE); - g_io_channel_win32_make_pollfd (errchannel, - G_IO_IN | G_IO_ERR | G_IO_HUP, - &errfd); - if (debug) - g_print ("errfd=%p\n", (HANDLE) errfd.fd); - } - - /* Read data until we get EOF on all pipes. */ - while (!failed && (outpipe >= 0 || errpipe >= 0)) - { - nfds = 0; - if (outpipe >= 0) - { - fds[nfds] = outfd; - outindex = nfds; - nfds++; - } - if (errpipe >= 0) - { - fds[nfds] = errfd; - errindex = nfds; - nfds++; - } - - if (debug) - g_print ("g_spawn_sync: calling g_io_channel_win32_poll, nfds=%d\n", - nfds); - - ret = g_io_channel_win32_poll (fds, nfds, -1); - - if (ret < 0) - { - failed = TRUE; - - g_set_error_literal (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ, - _("Unexpected error in g_io_channel_win32_poll() reading data from a child process")); - - break; - } - - if (outpipe >= 0 && (fds[outindex].revents & G_IO_IN)) - { - switch (read_data (outstr, outchannel, error)) - { - case READ_FAILED: - if (debug) - g_print ("g_spawn_sync: outchannel: READ_FAILED\n"); - failed = TRUE; - break; - case READ_EOF: - if (debug) - g_print ("g_spawn_sync: outchannel: READ_EOF\n"); - g_io_channel_unref (outchannel); - outchannel = NULL; - close_and_invalidate (&outpipe); - break; - default: - if (debug) - g_print ("g_spawn_sync: outchannel: OK\n"); - break; - } - - if (failed) - break; - } - - if (errpipe >= 0 && (fds[errindex].revents & G_IO_IN)) - { - switch (read_data (errstr, errchannel, error)) - { - case READ_FAILED: - if (debug) - g_print ("g_spawn_sync: errchannel: READ_FAILED\n"); - failed = TRUE; - break; - case READ_EOF: - if (debug) - g_print ("g_spawn_sync: errchannel: READ_EOF\n"); - g_io_channel_unref (errchannel); - errchannel = NULL; - close_and_invalidate (&errpipe); - break; - default: - if (debug) - g_print ("g_spawn_sync: errchannel: OK\n"); - break; - } - - if (failed) - break; - } - } - - if (reportpipe == -1) - { - /* No helper process, exit status of actual spawned process - * already available. - */ - if (exit_status) - *exit_status = status; - } - else - { - /* Helper process was involved. Read its report now after the - * grandchild has finished. - */ - gintptr helper_report[2]; - - if (!read_helper_report (reportpipe, helper_report, error)) - failed = TRUE; - else - { - switch (helper_report[0]) - { - case CHILD_NO_ERROR: - if (exit_status) - *exit_status = helper_report[1]; - break; - default: - set_child_error (helper_report, working_directory, error); - failed = TRUE; - break; - } - } - close_and_invalidate (&reportpipe); - } - - - /* These should only be open still if we had an error. */ - - if (outchannel != NULL) - g_io_channel_unref (outchannel); - if (errchannel != NULL) - g_io_channel_unref (errchannel); - if (outpipe >= 0) - close_and_invalidate (&outpipe); - if (errpipe >= 0) - close_and_invalidate (&errpipe); - - if (failed) - { - if (outstr) - g_string_free (outstr, TRUE); - if (errstr) - g_string_free (errstr, TRUE); - - return FALSE; - } - else - { - if (standard_output) - *standard_output = g_string_free (outstr, FALSE); - - if (standard_error) - *standard_error = g_string_free (errstr, FALSE); - - return TRUE; - } -} - -gboolean -g_spawn_async_with_pipes_utf8 (const gchar *working_directory, - gchar **argv, - gchar **envp, - GSpawnFlags flags, - GSpawnChildSetupFunc child_setup, - gpointer user_data, - GPid *child_handle, - gint *standard_input, - gint *standard_output, - gint *standard_error, - GError **error) -{ - g_return_val_if_fail (argv != NULL, FALSE); - g_return_val_if_fail (standard_output == NULL || - !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE); - g_return_val_if_fail (standard_error == NULL || - !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE); - /* can't inherit stdin if we have an input pipe. */ - g_return_val_if_fail (standard_input == NULL || - !(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE); - - return do_spawn_with_pipes (NULL, - (flags & G_SPAWN_DO_NOT_REAP_CHILD), - working_directory, - argv, - envp, - flags, - child_setup, - child_handle, - standard_input, - standard_output, - standard_error, - NULL, - error); -} - -gboolean -g_spawn_command_line_sync_utf8 (const gchar *command_line, - gchar **standard_output, - gchar **standard_error, - gint *exit_status, - GError **error) -{ - gboolean retval; - gchar **argv = 0; - - g_return_val_if_fail (command_line != NULL, FALSE); - - if (!g_shell_parse_argv (command_line, - NULL, &argv, - error)) - return FALSE; - - retval = g_spawn_sync_utf8 (NULL, - argv, - NULL, - G_SPAWN_SEARCH_PATH, - NULL, - NULL, - standard_output, - standard_error, - exit_status, - error); - g_strfreev (argv); - - return retval; -} - -gboolean -g_spawn_command_line_async_utf8 (const gchar *command_line, - GError **error) -{ - gboolean retval; - gchar **argv = 0; - - g_return_val_if_fail (command_line != NULL, FALSE); - - if (!g_shell_parse_argv (command_line, - NULL, &argv, - error)) - return FALSE; - - retval = g_spawn_async_utf8 (NULL, - argv, - NULL, - G_SPAWN_SEARCH_PATH, - NULL, - NULL, - NULL, - error); - g_strfreev (argv); - - return retval; -} - -void -g_spawn_close_pid (GPid pid) -{ - CloseHandle (pid); -} - -#if !defined (_WIN64) - -/* Binary compatibility versions that take system codepage pathnames, - * argument vectors and environments. These get used only by code - * built against 2.8.1 or earlier. Code built against 2.8.2 or later - * will use the _utf8 versions above (see the #defines in gspawn.h). - */ - -#undef g_spawn_async -#undef g_spawn_async_with_pipes -#undef g_spawn_sync -#undef g_spawn_command_line_sync -#undef g_spawn_command_line_async - -static gboolean -setup_utf8_copies (const gchar *working_directory, - gchar **utf8_working_directory, - gchar **argv, - gchar ***utf8_argv, - gchar **envp, - gchar ***utf8_envp, - GError **error) -{ - gint i, argc, envc; - - if (working_directory == NULL) - *utf8_working_directory = NULL; - else - { - GError *conv_error = NULL; - - *utf8_working_directory = g_locale_to_utf8 (working_directory, -1, NULL, NULL, &conv_error); - if (*utf8_working_directory == NULL) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR, - _("Invalid working directory: %s"), - conv_error->message); - g_error_free (conv_error); - return FALSE; - } - } - - argc = 0; - while (argv[argc]) - ++argc; - *utf8_argv = g_new (gchar *, argc + 1); - for (i = 0; i < argc; i++) - { - GError *conv_error = NULL; - - (*utf8_argv)[i] = g_locale_to_utf8 (argv[i], -1, NULL, NULL, &conv_error); - if ((*utf8_argv)[i] == NULL) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in argument vector at %d: %s"), - i, conv_error->message); - g_error_free (conv_error); - - g_strfreev (*utf8_argv); - *utf8_argv = NULL; - - g_free (*utf8_working_directory); - *utf8_working_directory = NULL; - - return FALSE; - } - } - (*utf8_argv)[argc] = NULL; - - if (envp == NULL) - { - *utf8_envp = NULL; - } - else - { - envc = 0; - while (envp[envc]) - ++envc; - *utf8_envp = g_new (gchar *, envc + 1); - for (i = 0; i < envc; i++) - { - GError *conv_error = NULL; - - (*utf8_envp)[i] = g_locale_to_utf8 (envp[i], -1, NULL, NULL, &conv_error); - if ((*utf8_envp)[i] == NULL) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in environment: %s"), - conv_error->message); - g_error_free (conv_error); - - g_strfreev (*utf8_envp); - *utf8_envp = NULL; - - g_strfreev (*utf8_argv); - *utf8_argv = NULL; - - g_free (*utf8_working_directory); - *utf8_working_directory = NULL; - - return FALSE; - } - } - (*utf8_envp)[envc] = NULL; - } - return TRUE; -} - -static void -free_utf8_copies (gchar *utf8_working_directory, - gchar **utf8_argv, - gchar **utf8_envp) -{ - g_free (utf8_working_directory); - g_strfreev (utf8_argv); - g_strfreev (utf8_envp); -} - -gboolean -g_spawn_async_with_pipes (const gchar *working_directory, - gchar **argv, - gchar **envp, - GSpawnFlags flags, - GSpawnChildSetupFunc child_setup, - gpointer user_data, - GPid *child_handle, - gint *standard_input, - gint *standard_output, - gint *standard_error, - GError **error) -{ - gchar *utf8_working_directory; - gchar **utf8_argv; - gchar **utf8_envp; - gboolean retval; - - if (!setup_utf8_copies (working_directory, &utf8_working_directory, - argv, &utf8_argv, - envp, &utf8_envp, - error)) - return FALSE; - - retval = g_spawn_async_with_pipes_utf8 (utf8_working_directory, - utf8_argv, utf8_envp, - flags, child_setup, user_data, - child_handle, - standard_input, standard_output, standard_error, - error); - - free_utf8_copies (utf8_working_directory, utf8_argv, utf8_envp); - - return retval; -} - -gboolean -g_spawn_async (const gchar *working_directory, - gchar **argv, - gchar **envp, - GSpawnFlags flags, - GSpawnChildSetupFunc child_setup, - gpointer user_data, - GPid *child_handle, - GError **error) -{ - return g_spawn_async_with_pipes (working_directory, - argv, envp, - flags, - child_setup, - user_data, - child_handle, - NULL, NULL, NULL, - error); -} - -gboolean -g_spawn_sync (const gchar *working_directory, - gchar **argv, - gchar **envp, - GSpawnFlags flags, - GSpawnChildSetupFunc child_setup, - gpointer user_data, - gchar **standard_output, - gchar **standard_error, - gint *exit_status, - GError **error) -{ - gchar *utf8_working_directory; - gchar **utf8_argv; - gchar **utf8_envp; - gboolean retval; - - if (!setup_utf8_copies (working_directory, &utf8_working_directory, - argv, &utf8_argv, - envp, &utf8_envp, - error)) - return FALSE; - - retval = g_spawn_sync_utf8 (utf8_working_directory, - utf8_argv, utf8_envp, - flags, child_setup, user_data, - standard_output, standard_error, exit_status, - error); - - free_utf8_copies (utf8_working_directory, utf8_argv, utf8_envp); - - return retval; -} - -gboolean -g_spawn_command_line_sync (const gchar *command_line, - gchar **standard_output, - gchar **standard_error, - gint *exit_status, - GError **error) -{ - gboolean retval; - gchar **argv = 0; - - g_return_val_if_fail (command_line != NULL, FALSE); - - if (!g_shell_parse_argv (command_line, - NULL, &argv, - error)) - return FALSE; - - retval = g_spawn_sync (NULL, - argv, - NULL, - G_SPAWN_SEARCH_PATH, - NULL, - NULL, - standard_output, - standard_error, - exit_status, - error); - g_strfreev (argv); - - return retval; -} - -gboolean -g_spawn_command_line_async (const gchar *command_line, - GError **error) -{ - gboolean retval; - gchar **argv = 0; - - g_return_val_if_fail (command_line != NULL, FALSE); - - if (!g_shell_parse_argv (command_line, - NULL, &argv, - error)) - return FALSE; - - retval = g_spawn_async (NULL, - argv, - NULL, - G_SPAWN_SEARCH_PATH, - NULL, - NULL, - NULL, - error); - g_strfreev (argv); - - return retval; -} - -#endif /* !_WIN64 */ - -#endif /* !GSPAWN_HELPER */ - -#define __G_SPAWN_C__ -#include "galiasdef.c" diff --git a/glib/gspawn.c b/glib/gspawn.c deleted file mode 100644 index 406ef2b4b..000000000 --- a/glib/gspawn.c +++ /dev/null @@ -1,1671 +0,0 @@ -/* gspawn.c - Process launching - * - * Copyright 2000 Red Hat, Inc. - * g_execvpe implementation based on GNU libc execvp: - * Copyright 1991, 92, 95, 96, 97, 98, 99 Free Software Foundation, Inc. - * - * GLib 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 of the - * License, or (at your option) any later version. - * - * GLib 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 GLib; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "config.h" - -#include <sys/time.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> -#include <string.h> -#include <stdlib.h> /* for fdwalk */ -#include <dirent.h> - -#ifdef HAVE_SYS_SELECT_H -#include <sys/select.h> -#endif /* HAVE_SYS_SELECT_H */ - -#ifdef HAVE_SYS_RESOURCE_H -#include <sys/resource.h> -#endif /* HAVE_SYS_RESOURCE_H */ - -#include "glib.h" -#include "glibintl.h" -#include "galias.h" - -static gint g_execute (const gchar *file, - gchar **argv, - gchar **envp, - gboolean search_path); - -static gboolean make_pipe (gint p[2], - GError **error); -static gboolean fork_exec_with_pipes (gboolean intermediate_child, - const gchar *working_directory, - gchar **argv, - gchar **envp, - gboolean close_descriptors, - gboolean search_path, - gboolean stdout_to_null, - gboolean stderr_to_null, - gboolean child_inherits_stdin, - gboolean file_and_argv_zero, - GSpawnChildSetupFunc child_setup, - gpointer user_data, - GPid *child_pid, - gint *standard_input, - gint *standard_output, - gint *standard_error, - GError **error); - -GQuark -g_spawn_error_quark (void) -{ - return g_quark_from_static_string ("g-exec-error-quark"); -} - -/** - * g_spawn_async: - * @working_directory: child's current working directory, or %NULL to inherit parent's - * @argv: child's argument vector - * @envp: child's environment, or %NULL to inherit parent's - * @flags: flags from #GSpawnFlags - * @child_setup: function to run in the child just before exec() - * @user_data: user data for @child_setup - * @child_pid: return location for child process reference, or %NULL - * @error: return location for error - * - * See g_spawn_async_with_pipes() for a full description; this function - * simply calls the g_spawn_async_with_pipes() without any pipes. - * - * You should call g_spawn_close_pid() on the returned child process - * reference when you don't need it any more. - * - * <note><para> - * If you are writing a GTK+ application, and the program you - * are spawning is a graphical application, too, then you may - * want to use gdk_spawn_on_screen() instead to ensure that - * the spawned program opens its windows on the right screen. - * </para></note> - * - * <note><para> Note that the returned @child_pid on Windows is a - * handle to the child process and not its identifier. Process handles - * and process identifiers are different concepts on Windows. - * </para></note> - * - * Return value: %TRUE on success, %FALSE if error is set - **/ -gboolean -g_spawn_async (const gchar *working_directory, - gchar **argv, - gchar **envp, - GSpawnFlags flags, - GSpawnChildSetupFunc child_setup, - gpointer user_data, - GPid *child_pid, - GError **error) -{ - g_return_val_if_fail (argv != NULL, FALSE); - - return g_spawn_async_with_pipes (working_directory, - argv, envp, - flags, - child_setup, - user_data, - child_pid, - NULL, NULL, NULL, - error); -} - -/* Avoids a danger in threaded situations (calling close() - * on a file descriptor twice, and another thread has - * re-opened it since the first close) - */ -static gint -close_and_invalidate (gint *fd) -{ - gint ret; - - if (*fd < 0) - return -1; - else - { - ret = close (*fd); - *fd = -1; - } - - return ret; -} - -/* Some versions of OS X define READ_OK in public headers */ -#undef READ_OK - -typedef enum -{ - READ_FAILED = 0, /* FALSE */ - READ_OK, - READ_EOF -} ReadResult; - -static ReadResult -read_data (GString *str, - gint fd, - GError **error) -{ - gssize bytes; - gchar buf[4096]; - - again: - - bytes = read (fd, buf, 4096); - - if (bytes == 0) - return READ_EOF; - else if (bytes > 0) - { - g_string_append_len (str, buf, bytes); - return READ_OK; - } - else if (bytes < 0 && errno == EINTR) - goto again; - else if (bytes < 0) - { - g_set_error (error, - G_SPAWN_ERROR, - G_SPAWN_ERROR_READ, - _("Failed to read data from child process (%s)"), - g_strerror (errno)); - - return READ_FAILED; - } - else - return READ_OK; -} - -/** - * g_spawn_sync: - * @working_directory: child's current working directory, or %NULL to inherit parent's - * @argv: child's argument vector - * @envp: child's environment, or %NULL to inherit parent's - * @flags: flags from #GSpawnFlags - * @child_setup: function to run in the child just before exec() - * @user_data: user data for @child_setup - * @standard_output: return location for child output, or %NULL - * @standard_error: return location for child error messages, or %NULL - * @exit_status: return location for child exit status, as returned by waitpid(), or %NULL - * @error: return location for error, or %NULL - * - * Executes a child synchronously (waits for the child to exit before returning). - * All output from the child is stored in @standard_output and @standard_error, - * if those parameters are non-%NULL. Note that you must set the - * %G_SPAWN_STDOUT_TO_DEV_NULL and %G_SPAWN_STDERR_TO_DEV_NULL flags when - * passing %NULL for @standard_output and @standard_error. - * If @exit_status is non-%NULL, the exit status of the child is stored - * there as it would be returned by waitpid(); standard UNIX macros such - * as WIFEXITED() and WEXITSTATUS() must be used to evaluate the exit status. - * Note that this function call waitpid() even if @exit_status is %NULL, and - * does not accept the %G_SPAWN_DO_NOT_REAP_CHILD flag. - * If an error occurs, no data is returned in @standard_output, - * @standard_error, or @exit_status. - * - * This function calls g_spawn_async_with_pipes() internally; see that - * function for full details on the other parameters and details on - * how these functions work on Windows. - * - * Return value: %TRUE on success, %FALSE if an error was set. - **/ -gboolean -g_spawn_sync (const gchar *working_directory, - gchar **argv, - gchar **envp, - GSpawnFlags flags, - GSpawnChildSetupFunc child_setup, - gpointer user_data, - gchar **standard_output, - gchar **standard_error, - gint *exit_status, - GError **error) -{ - gint outpipe = -1; - gint errpipe = -1; - GPid pid; - fd_set fds; - gint ret; - GString *outstr = NULL; - GString *errstr = NULL; - gboolean failed; - gint status; - - g_return_val_if_fail (argv != NULL, FALSE); - g_return_val_if_fail (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), FALSE); - g_return_val_if_fail (standard_output == NULL || - !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE); - g_return_val_if_fail (standard_error == NULL || - !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE); - - /* Just to ensure segfaults if callers try to use - * these when an error is reported. - */ - if (standard_output) - *standard_output = NULL; - - if (standard_error) - *standard_error = NULL; - - if (!fork_exec_with_pipes (FALSE, - working_directory, - argv, - envp, - !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN), - (flags & G_SPAWN_SEARCH_PATH) != 0, - (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0, - (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0, - (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0, - (flags & G_SPAWN_FILE_AND_ARGV_ZERO) != 0, - child_setup, - user_data, - &pid, - NULL, - standard_output ? &outpipe : NULL, - standard_error ? &errpipe : NULL, - error)) - return FALSE; - - /* Read data from child. */ - - failed = FALSE; - - if (outpipe >= 0) - { - outstr = g_string_new (NULL); - } - - if (errpipe >= 0) - { - errstr = g_string_new (NULL); - } - - /* Read data until we get EOF on both pipes. */ - while (!failed && - (outpipe >= 0 || - errpipe >= 0)) - { - ret = 0; - - FD_ZERO (&fds); - if (outpipe >= 0) - FD_SET (outpipe, &fds); - if (errpipe >= 0) - FD_SET (errpipe, &fds); - - ret = select (MAX (outpipe, errpipe) + 1, - &fds, - NULL, NULL, - NULL /* no timeout */); - - if (ret < 0 && errno != EINTR) - { - failed = TRUE; - - g_set_error (error, - G_SPAWN_ERROR, - G_SPAWN_ERROR_READ, - _("Unexpected error in select() reading data from a child process (%s)"), - g_strerror (errno)); - - break; - } - - if (outpipe >= 0 && FD_ISSET (outpipe, &fds)) - { - switch (read_data (outstr, outpipe, error)) - { - case READ_FAILED: - failed = TRUE; - break; - case READ_EOF: - close_and_invalidate (&outpipe); - outpipe = -1; - break; - default: - break; - } - - if (failed) - break; - } - - if (errpipe >= 0 && FD_ISSET (errpipe, &fds)) - { - switch (read_data (errstr, errpipe, error)) - { - case READ_FAILED: - failed = TRUE; - break; - case READ_EOF: - close_and_invalidate (&errpipe); - errpipe = -1; - break; - default: - break; - } - - if (failed) - break; - } - } - - /* These should only be open still if we had an error. */ - - if (outpipe >= 0) - close_and_invalidate (&outpipe); - if (errpipe >= 0) - close_and_invalidate (&errpipe); - - /* Wait for child to exit, even if we have - * an error pending. - */ - again: - - ret = waitpid (pid, &status, 0); - - if (ret < 0) - { - if (errno == EINTR) - goto again; - else if (errno == ECHILD) - { - if (exit_status) - { - g_warning ("In call to g_spawn_sync(), exit status of a child process was requested but SIGCHLD action was set to SIG_IGN and ECHILD was received by waitpid(), so exit status can't be returned. This is a bug in the program calling g_spawn_sync(); either don't request the exit status, or don't set the SIGCHLD action."); - } - else - { - /* We don't need the exit status. */ - } - } - else - { - if (!failed) /* avoid error pileups */ - { - failed = TRUE; - - g_set_error (error, - G_SPAWN_ERROR, - G_SPAWN_ERROR_READ, - _("Unexpected error in waitpid() (%s)"), - g_strerror (errno)); - } - } - } - - if (failed) - { - if (outstr) - g_string_free (outstr, TRUE); - if (errstr) - g_string_free (errstr, TRUE); - - return FALSE; - } - else - { - if (exit_status) - *exit_status = status; - - if (standard_output) - *standard_output = g_string_free (outstr, FALSE); - - if (standard_error) - *standard_error = g_string_free (errstr, FALSE); - - return TRUE; - } -} - -/** - * g_spawn_async_with_pipes: - * @working_directory: child's current working directory, or %NULL to inherit parent's, in the GLib file name encoding - * @argv: child's argument vector, in the GLib file name encoding - * @envp: child's environment, or %NULL to inherit parent's, in the GLib file name encoding - * @flags: flags from #GSpawnFlags - * @child_setup: function to run in the child just before exec() - * @user_data: user data for @child_setup - * @child_pid: return location for child process ID, or %NULL - * @standard_input: return location for file descriptor to write to child's stdin, or %NULL - * @standard_output: return location for file descriptor to read child's stdout, or %NULL - * @standard_error: return location for file descriptor to read child's stderr, or %NULL - * @error: return location for error - * - * Executes a child program asynchronously (your program will not - * block waiting for the child to exit). The child program is - * specified by the only argument that must be provided, @argv. @argv - * should be a %NULL-terminated array of strings, to be passed as the - * argument vector for the child. The first string in @argv is of - * course the name of the program to execute. By default, the name of - * the program must be a full path; the <envar>PATH</envar> shell variable - * will only be searched if you pass the %G_SPAWN_SEARCH_PATH flag. - * - * On Windows, note that all the string or string vector arguments to - * this function and the other g_spawn*() functions are in UTF-8, the - * GLib file name encoding. Unicode characters that are not part of - * the system codepage passed in these arguments will be correctly - * available in the spawned program only if it uses wide character API - * to retrieve its command line. For C programs built with Microsoft's - * tools it is enough to make the program have a wmain() instead of - * main(). wmain() has a wide character argument vector as parameter. - * - * At least currently, mingw doesn't support wmain(), so if you use - * mingw to develop the spawned program, it will have to call the - * undocumented function __wgetmainargs() to get the wide character - * argument vector and environment. See gspawn-win32-helper.c in the - * GLib sources or init.c in the mingw runtime sources for a prototype - * for that function. Alternatively, you can retrieve the Win32 system - * level wide character command line passed to the spawned program - * using the GetCommandLineW() function. - * - * On Windows the low-level child process creation API - * <function>CreateProcess()</function> doesn't use argument vectors, - * but a command line. The C runtime library's - * <function>spawn*()</function> family of functions (which - * g_spawn_async_with_pipes() eventually calls) paste the argument - * vector elements together into a command line, and the C runtime startup code - * does a corresponding reconstruction of an argument vector from the - * command line, to be passed to main(). Complications arise when you have - * argument vector elements that contain spaces of double quotes. The - * <function>spawn*()</function> functions don't do any quoting or - * escaping, but on the other hand the startup code does do unquoting - * and unescaping in order to enable receiving arguments with embedded - * spaces or double quotes. To work around this asymmetry, - * g_spawn_async_with_pipes() will do quoting and escaping on argument - * vector elements that need it before calling the C runtime - * spawn() function. - * - * The returned @child_pid on Windows is a handle to the child - * process, not its identifier. Process handles and process - * identifiers are different concepts on Windows. - * - * @envp is a %NULL-terminated array of strings, where each string - * has the form <literal>KEY=VALUE</literal>. This will become - * the child's environment. If @envp is %NULL, the child inherits its - * parent's environment. - * - * @flags should be the bitwise OR of any flags you want to affect the - * function's behaviour. The %G_SPAWN_DO_NOT_REAP_CHILD means that - * the child will not automatically be reaped; you must use a - * #GChildWatch source to be notified about the death of the child - * process. Eventually you must call g_spawn_close_pid() on the - * @child_pid, in order to free resources which may be associated - * with the child process. (On Unix, using a #GChildWatch source is - * equivalent to calling waitpid() or handling the %SIGCHLD signal - * manually. On Windows, calling g_spawn_close_pid() is equivalent - * to calling CloseHandle() on the process handle returned in - * @child_pid). - * - * %G_SPAWN_LEAVE_DESCRIPTORS_OPEN means that the parent's open file - * descriptors will be inherited by the child; otherwise all - * descriptors except stdin/stdout/stderr will be closed before - * calling exec() in the child. %G_SPAWN_SEARCH_PATH - * means that <literal>argv[0]</literal> need not be an absolute path, it - * will be looked for in the user's <envar>PATH</envar>. - * %G_SPAWN_STDOUT_TO_DEV_NULL means that the child's standard output will - * be discarded, instead of going to the same location as the parent's - * standard output. If you use this flag, @standard_output must be %NULL. - * %G_SPAWN_STDERR_TO_DEV_NULL means that the child's standard error - * will be discarded, instead of going to the same location as the parent's - * standard error. If you use this flag, @standard_error must be %NULL. - * %G_SPAWN_CHILD_INHERITS_STDIN means that the child will inherit the parent's - * standard input (by default, the child's standard input is attached to - * /dev/null). If you use this flag, @standard_input must be %NULL. - * %G_SPAWN_FILE_AND_ARGV_ZERO means that the first element of @argv is - * the file to execute, while the remaining elements are the - * actual argument vector to pass to the file. Normally - * g_spawn_async_with_pipes() uses @argv[0] as the file to execute, and - * passes all of @argv to the child. - * - * @child_setup and @user_data are a function and user data. On POSIX - * platforms, the function is called in the child after GLib has - * performed all the setup it plans to perform (including creating - * pipes, closing file descriptors, etc.) but before calling - * exec(). That is, @child_setup is called just - * before calling exec() in the child. Obviously - * actions taken in this function will only affect the child, not the - * parent. - * - * On Windows, there is no separate fork() and exec() - * functionality. Child processes are created and run with a single - * API call, CreateProcess(). There is no sensible thing @child_setup - * could be used for on Windows so it is ignored and not called. - * - * If non-%NULL, @child_pid will on Unix be filled with the child's - * process ID. You can use the process ID to send signals to the - * child, or to use g_child_watch_add() (or waitpid()) if you specified the - * %G_SPAWN_DO_NOT_REAP_CHILD flag. On Windows, @child_pid will be - * filled with a handle to the child process only if you specified the - * %G_SPAWN_DO_NOT_REAP_CHILD flag. You can then access the child - * process using the Win32 API, for example wait for its termination - * with the <function>WaitFor*()</function> functions, or examine its - * exit code with GetExitCodeProcess(). You should close the handle - * with CloseHandle() or g_spawn_close_pid() when you no longer need it. - * - * If non-%NULL, the @standard_input, @standard_output, @standard_error - * locations will be filled with file descriptors for writing to the child's - * standard input or reading from its standard output or standard error. - * The caller of g_spawn_async_with_pipes() must close these file descriptors - * when they are no longer in use. If these parameters are %NULL, the corresponding - * pipe won't be created. - * - * If @standard_input is NULL, the child's standard input is attached to - * /dev/null unless %G_SPAWN_CHILD_INHERITS_STDIN is set. - * - * If @standard_error is NULL, the child's standard error goes to the same - * location as the parent's standard error unless %G_SPAWN_STDERR_TO_DEV_NULL - * is set. - * - * If @standard_output is NULL, the child's standard output goes to the same - * location as the parent's standard output unless %G_SPAWN_STDOUT_TO_DEV_NULL - * is set. - * - * @error can be %NULL to ignore errors, or non-%NULL to report errors. - * If an error is set, the function returns %FALSE. Errors - * are reported even if they occur in the child (for example if the - * executable in <literal>argv[0]</literal> is not found). Typically - * the <literal>message</literal> field of returned errors should be displayed - * to users. Possible errors are those from the #G_SPAWN_ERROR domain. - * - * If an error occurs, @child_pid, @standard_input, @standard_output, - * and @standard_error will not be filled with valid values. - * - * If @child_pid is not %NULL and an error does not occur then the returned - * process reference must be closed using g_spawn_close_pid(). - * - * <note><para> - * If you are writing a GTK+ application, and the program you - * are spawning is a graphical application, too, then you may - * want to use gdk_spawn_on_screen_with_pipes() instead to ensure that - * the spawned program opens its windows on the right screen. - * </para></note> - * - * Return value: %TRUE on success, %FALSE if an error was set - **/ -gboolean -g_spawn_async_with_pipes (const gchar *working_directory, - gchar **argv, - gchar **envp, - GSpawnFlags flags, - GSpawnChildSetupFunc child_setup, - gpointer user_data, - GPid *child_pid, - gint *standard_input, - gint *standard_output, - gint *standard_error, - GError **error) -{ - g_return_val_if_fail (argv != NULL, FALSE); - g_return_val_if_fail (standard_output == NULL || - !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE); - g_return_val_if_fail (standard_error == NULL || - !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE); - /* can't inherit stdin if we have an input pipe. */ - g_return_val_if_fail (standard_input == NULL || - !(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE); - - return fork_exec_with_pipes (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), - working_directory, - argv, - envp, - !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN), - (flags & G_SPAWN_SEARCH_PATH) != 0, - (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0, - (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0, - (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0, - (flags & G_SPAWN_FILE_AND_ARGV_ZERO) != 0, - child_setup, - user_data, - child_pid, - standard_input, - standard_output, - standard_error, - error); -} - -/** - * g_spawn_command_line_sync: - * @command_line: a command line - * @standard_output: return location for child output - * @standard_error: return location for child errors - * @exit_status: return location for child exit status, as returned by waitpid() - * @error: return location for errors - * - * A simple version of g_spawn_sync() with little-used parameters - * removed, taking a command line instead of an argument vector. See - * g_spawn_sync() for full details. @command_line will be parsed by - * g_shell_parse_argv(). Unlike g_spawn_sync(), the %G_SPAWN_SEARCH_PATH flag - * is enabled. Note that %G_SPAWN_SEARCH_PATH can have security - * implications, so consider using g_spawn_sync() directly if - * appropriate. Possible errors are those from g_spawn_sync() and those - * from g_shell_parse_argv(). - * - * If @exit_status is non-%NULL, the exit status of the child is stored there as - * it would be returned by waitpid(); standard UNIX macros such as WIFEXITED() - * and WEXITSTATUS() must be used to evaluate the exit status. - * - * On Windows, please note the implications of g_shell_parse_argv() - * parsing @command_line. Parsing is done according to Unix shell rules, not - * Windows command interpreter rules. - * Space is a separator, and backslashes are - * special. Thus you cannot simply pass a @command_line containing - * canonical Windows paths, like "c:\\program files\\app\\app.exe", as - * the backslashes will be eaten, and the space will act as a - * separator. You need to enclose such paths with single quotes, like - * "'c:\\program files\\app\\app.exe' 'e:\\folder\\argument.txt'". - * - * Return value: %TRUE on success, %FALSE if an error was set - **/ -gboolean -g_spawn_command_line_sync (const gchar *command_line, - gchar **standard_output, - gchar **standard_error, - gint *exit_status, - GError **error) -{ - gboolean retval; - gchar **argv = NULL; - - g_return_val_if_fail (command_line != NULL, FALSE); - - if (!g_shell_parse_argv (command_line, - NULL, &argv, - error)) - return FALSE; - - retval = g_spawn_sync (NULL, - argv, - NULL, - G_SPAWN_SEARCH_PATH, - NULL, - NULL, - standard_output, - standard_error, - exit_status, - error); - g_strfreev (argv); - - return retval; -} - -/** - * g_spawn_command_line_async: - * @command_line: a command line - * @error: return location for errors - * - * A simple version of g_spawn_async() that parses a command line with - * g_shell_parse_argv() and passes it to g_spawn_async(). Runs a - * command line in the background. Unlike g_spawn_async(), the - * %G_SPAWN_SEARCH_PATH flag is enabled, other flags are not. Note - * that %G_SPAWN_SEARCH_PATH can have security implications, so - * consider using g_spawn_async() directly if appropriate. Possible - * errors are those from g_shell_parse_argv() and g_spawn_async(). - * - * The same concerns on Windows apply as for g_spawn_command_line_sync(). - * - * Return value: %TRUE on success, %FALSE if error is set. - **/ -gboolean -g_spawn_command_line_async (const gchar *command_line, - GError **error) -{ - gboolean retval; - gchar **argv = NULL; - - g_return_val_if_fail (command_line != NULL, FALSE); - - if (!g_shell_parse_argv (command_line, - NULL, &argv, - error)) - return FALSE; - - retval = g_spawn_async (NULL, - argv, - NULL, - G_SPAWN_SEARCH_PATH, - NULL, - NULL, - NULL, - error); - g_strfreev (argv); - - return retval; -} - -static gint -exec_err_to_g_error (gint en) -{ - switch (en) - { -#ifdef EACCES - case EACCES: - return G_SPAWN_ERROR_ACCES; - break; -#endif - -#ifdef EPERM - case EPERM: - return G_SPAWN_ERROR_PERM; - break; -#endif - -#ifdef E2BIG - case E2BIG: - return G_SPAWN_ERROR_2BIG; - break; -#endif - -#ifdef ENOEXEC - case ENOEXEC: - return G_SPAWN_ERROR_NOEXEC; - break; -#endif - -#ifdef ENAMETOOLONG - case ENAMETOOLONG: - return G_SPAWN_ERROR_NAMETOOLONG; - break; -#endif - -#ifdef ENOENT - case ENOENT: - return G_SPAWN_ERROR_NOENT; - break; -#endif - -#ifdef ENOMEM - case ENOMEM: - return G_SPAWN_ERROR_NOMEM; - break; -#endif - -#ifdef ENOTDIR - case ENOTDIR: - return G_SPAWN_ERROR_NOTDIR; - break; -#endif - -#ifdef ELOOP - case ELOOP: - return G_SPAWN_ERROR_LOOP; - break; -#endif - -#ifdef ETXTBUSY - case ETXTBUSY: - return G_SPAWN_ERROR_TXTBUSY; - break; -#endif - -#ifdef EIO - case EIO: - return G_SPAWN_ERROR_IO; - break; -#endif - -#ifdef ENFILE - case ENFILE: - return G_SPAWN_ERROR_NFILE; - break; -#endif - -#ifdef EMFILE - case EMFILE: - return G_SPAWN_ERROR_MFILE; - break; -#endif - -#ifdef EINVAL - case EINVAL: - return G_SPAWN_ERROR_INVAL; - break; -#endif - -#ifdef EISDIR - case EISDIR: - return G_SPAWN_ERROR_ISDIR; - break; -#endif - -#ifdef ELIBBAD - case ELIBBAD: - return G_SPAWN_ERROR_LIBBAD; - break; -#endif - - default: - return G_SPAWN_ERROR_FAILED; - break; - } -} - -static gssize -write_all (gint fd, gconstpointer vbuf, gsize to_write) -{ - gchar *buf = (gchar *) vbuf; - - while (to_write > 0) - { - gssize count = write (fd, buf, to_write); - if (count < 0) - { - if (errno != EINTR) - return FALSE; - } - else - { - to_write -= count; - buf += count; - } - } - - return TRUE; -} - -G_GNUC_NORETURN -static void -write_err_and_exit (gint fd, gint msg) -{ - gint en = errno; - - write_all (fd, &msg, sizeof(msg)); - write_all (fd, &en, sizeof(en)); - - _exit (1); -} - -static int -set_cloexec (void *data, gint fd) -{ - if (fd >= GPOINTER_TO_INT (data)) - fcntl (fd, F_SETFD, FD_CLOEXEC); - - return 0; -} - -#ifndef HAVE_FDWALK -static int -fdwalk (int (*cb)(void *data, int fd), void *data) -{ - gint open_max; - gint fd; - gint res = 0; - -#ifdef HAVE_SYS_RESOURCE_H - struct rlimit rl; -#endif - -#ifdef __linux__ - DIR *d; - - if ((d = opendir("/proc/self/fd"))) { - struct dirent *de; - - while ((de = readdir(d))) { - glong l; - gchar *e = NULL; - - if (de->d_name[0] == '.') - continue; - - errno = 0; - l = strtol(de->d_name, &e, 10); - if (errno != 0 || !e || *e) - continue; - - fd = (gint) l; - - if ((glong) fd != l) - continue; - - if (fd == dirfd(d)) - continue; - - if ((res = cb (data, fd)) != 0) - break; - } - - closedir(d); - return res; - } - - /* If /proc is not mounted or not accessible we fall back to the old - * rlimit trick */ - -#endif - -#ifdef HAVE_SYS_RESOURCE_H - - if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY) - open_max = rl.rlim_max; - else -#endif - open_max = sysconf (_SC_OPEN_MAX); - - for (fd = 0; fd < open_max; fd++) - if ((res = cb (data, fd)) != 0) - break; - - return res; -} -#endif - -static gint -sane_dup2 (gint fd1, gint fd2) -{ - gint ret; - - retry: - ret = dup2 (fd1, fd2); - if (ret < 0 && errno == EINTR) - goto retry; - - return ret; -} - -enum -{ - CHILD_CHDIR_FAILED, - CHILD_EXEC_FAILED, - CHILD_DUP2_FAILED, - CHILD_FORK_FAILED -}; - -static void -do_exec (gint child_err_report_fd, - gint stdin_fd, - gint stdout_fd, - gint stderr_fd, - const gchar *working_directory, - gchar **argv, - gchar **envp, - gboolean close_descriptors, - gboolean search_path, - gboolean stdout_to_null, - gboolean stderr_to_null, - gboolean child_inherits_stdin, - gboolean file_and_argv_zero, - GSpawnChildSetupFunc child_setup, - gpointer user_data) -{ - if (working_directory && chdir (working_directory) < 0) - write_err_and_exit (child_err_report_fd, - CHILD_CHDIR_FAILED); - - /* Close all file descriptors but stdin stdout and stderr as - * soon as we exec. Note that this includes - * child_err_report_fd, which keeps the parent from blocking - * forever on the other end of that pipe. - */ - if (close_descriptors) - { - fdwalk (set_cloexec, GINT_TO_POINTER(3)); - } - else - { - /* We need to do child_err_report_fd anyway */ - set_cloexec (GINT_TO_POINTER(0), child_err_report_fd); - } - - /* Redirect pipes as required */ - - if (stdin_fd >= 0) - { - /* dup2 can't actually fail here I don't think */ - - if (sane_dup2 (stdin_fd, 0) < 0) - write_err_and_exit (child_err_report_fd, - CHILD_DUP2_FAILED); - - /* ignore this if it doesn't work */ - close_and_invalidate (&stdin_fd); - } - else if (!child_inherits_stdin) - { - /* Keep process from blocking on a read of stdin */ - gint read_null = open ("/dev/null", O_RDONLY); - sane_dup2 (read_null, 0); - close_and_invalidate (&read_null); - } - - if (stdout_fd >= 0) - { - /* dup2 can't actually fail here I don't think */ - - if (sane_dup2 (stdout_fd, 1) < 0) - write_err_and_exit (child_err_report_fd, - CHILD_DUP2_FAILED); - - /* ignore this if it doesn't work */ - close_and_invalidate (&stdout_fd); - } - else if (stdout_to_null) - { - gint write_null = open ("/dev/null", O_WRONLY); - sane_dup2 (write_null, 1); - close_and_invalidate (&write_null); - } - - if (stderr_fd >= 0) - { - /* dup2 can't actually fail here I don't think */ - - if (sane_dup2 (stderr_fd, 2) < 0) - write_err_and_exit (child_err_report_fd, - CHILD_DUP2_FAILED); - - /* ignore this if it doesn't work */ - close_and_invalidate (&stderr_fd); - } - else if (stderr_to_null) - { - gint write_null = open ("/dev/null", O_WRONLY); - sane_dup2 (write_null, 2); - close_and_invalidate (&write_null); - } - - /* Call user function just before we exec */ - if (child_setup) - { - (* child_setup) (user_data); - } - - g_execute (argv[0], - file_and_argv_zero ? argv + 1 : argv, - envp, search_path); - - /* Exec failed */ - write_err_and_exit (child_err_report_fd, - CHILD_EXEC_FAILED); -} - -static gboolean -read_ints (int fd, - gint* buf, - gint n_ints_in_buf, - gint *n_ints_read, - GError **error) -{ - gsize bytes = 0; - - while (TRUE) - { - gssize chunk; - - if (bytes >= sizeof(gint)*2) - break; /* give up, who knows what happened, should not be - * possible. - */ - - again: - chunk = read (fd, - ((gchar*)buf) + bytes, - sizeof(gint) * n_ints_in_buf - bytes); - if (chunk < 0 && errno == EINTR) - goto again; - - if (chunk < 0) - { - /* Some weird shit happened, bail out */ - - g_set_error (error, - G_SPAWN_ERROR, - G_SPAWN_ERROR_FAILED, - _("Failed to read from child pipe (%s)"), - g_strerror (errno)); - - return FALSE; - } - else if (chunk == 0) - break; /* EOF */ - else /* chunk > 0 */ - bytes += chunk; - } - - *n_ints_read = (gint)(bytes / sizeof(gint)); - - return TRUE; -} - -static gboolean -fork_exec_with_pipes (gboolean intermediate_child, - const gchar *working_directory, - gchar **argv, - gchar **envp, - gboolean close_descriptors, - gboolean search_path, - gboolean stdout_to_null, - gboolean stderr_to_null, - gboolean child_inherits_stdin, - gboolean file_and_argv_zero, - GSpawnChildSetupFunc child_setup, - gpointer user_data, - GPid *child_pid, - gint *standard_input, - gint *standard_output, - gint *standard_error, - GError **error) -{ - GPid pid = -1; - gint stdin_pipe[2] = { -1, -1 }; - gint stdout_pipe[2] = { -1, -1 }; - gint stderr_pipe[2] = { -1, -1 }; - gint child_err_report_pipe[2] = { -1, -1 }; - gint child_pid_report_pipe[2] = { -1, -1 }; - gint status; - - if (!make_pipe (child_err_report_pipe, error)) - return FALSE; - - if (intermediate_child && !make_pipe (child_pid_report_pipe, error)) - goto cleanup_and_fail; - - if (standard_input && !make_pipe (stdin_pipe, error)) - goto cleanup_and_fail; - - if (standard_output && !make_pipe (stdout_pipe, error)) - goto cleanup_and_fail; - - if (standard_error && !make_pipe (stderr_pipe, error)) - goto cleanup_and_fail; - - pid = fork (); - - if (pid < 0) - { - g_set_error (error, - G_SPAWN_ERROR, - G_SPAWN_ERROR_FORK, - _("Failed to fork (%s)"), - g_strerror (errno)); - - goto cleanup_and_fail; - } - else if (pid == 0) - { - /* Immediate child. This may or may not be the child that - * actually execs the new process. - */ - - /* Be sure we crash if the parent exits - * and we write to the err_report_pipe - */ - signal (SIGPIPE, SIG_DFL); - - /* Close the parent's end of the pipes; - * not needed in the close_descriptors case, - * though - */ - close_and_invalidate (&child_err_report_pipe[0]); - close_and_invalidate (&child_pid_report_pipe[0]); - close_and_invalidate (&stdin_pipe[1]); - close_and_invalidate (&stdout_pipe[0]); - close_and_invalidate (&stderr_pipe[0]); - - if (intermediate_child) - { - /* We need to fork an intermediate child that launches the - * final child. The purpose of the intermediate child - * is to exit, so we can waitpid() it immediately. - * Then the grandchild will not become a zombie. - */ - GPid grandchild_pid; - - grandchild_pid = fork (); - - if (grandchild_pid < 0) - { - /* report -1 as child PID */ - write_all (child_pid_report_pipe[1], &grandchild_pid, - sizeof(grandchild_pid)); - - write_err_and_exit (child_err_report_pipe[1], - CHILD_FORK_FAILED); - } - else if (grandchild_pid == 0) - { - do_exec (child_err_report_pipe[1], - stdin_pipe[0], - stdout_pipe[1], - stderr_pipe[1], - working_directory, - argv, - envp, - close_descriptors, - search_path, - stdout_to_null, - stderr_to_null, - child_inherits_stdin, - file_and_argv_zero, - child_setup, - user_data); - } - else - { - write_all (child_pid_report_pipe[1], &grandchild_pid, sizeof(grandchild_pid)); - close_and_invalidate (&child_pid_report_pipe[1]); - - _exit (0); - } - } - else - { - /* Just run the child. - */ - - do_exec (child_err_report_pipe[1], - stdin_pipe[0], - stdout_pipe[1], - stderr_pipe[1], - working_directory, - argv, - envp, - close_descriptors, - search_path, - stdout_to_null, - stderr_to_null, - child_inherits_stdin, - file_and_argv_zero, - child_setup, - user_data); - } - } - else - { - /* Parent */ - - gint buf[2]; - gint n_ints = 0; - - /* Close the uncared-about ends of the pipes */ - close_and_invalidate (&child_err_report_pipe[1]); - close_and_invalidate (&child_pid_report_pipe[1]); - close_and_invalidate (&stdin_pipe[0]); - close_and_invalidate (&stdout_pipe[1]); - close_and_invalidate (&stderr_pipe[1]); - - /* If we had an intermediate child, reap it */ - if (intermediate_child) - { - wait_again: - if (waitpid (pid, &status, 0) < 0) - { - if (errno == EINTR) - goto wait_again; - else if (errno == ECHILD) - ; /* do nothing, child already reaped */ - else - g_warning ("waitpid() should not fail in " - "'fork_exec_with_pipes'"); - } - } - - - if (!read_ints (child_err_report_pipe[0], - buf, 2, &n_ints, - error)) - goto cleanup_and_fail; - - if (n_ints >= 2) - { - /* Error from the child. */ - - switch (buf[0]) - { - case CHILD_CHDIR_FAILED: - g_set_error (error, - G_SPAWN_ERROR, - G_SPAWN_ERROR_CHDIR, - _("Failed to change to directory '%s' (%s)"), - working_directory, - g_strerror (buf[1])); - - break; - - case CHILD_EXEC_FAILED: - g_set_error (error, - G_SPAWN_ERROR, - exec_err_to_g_error (buf[1]), - _("Failed to execute child process \"%s\" (%s)"), - argv[0], - g_strerror (buf[1])); - - break; - - case CHILD_DUP2_FAILED: - g_set_error (error, - G_SPAWN_ERROR, - G_SPAWN_ERROR_FAILED, - _("Failed to redirect output or input of child process (%s)"), - g_strerror (buf[1])); - - break; - - case CHILD_FORK_FAILED: - g_set_error (error, - G_SPAWN_ERROR, - G_SPAWN_ERROR_FORK, - _("Failed to fork child process (%s)"), - g_strerror (buf[1])); - break; - - default: - g_set_error (error, - G_SPAWN_ERROR, - G_SPAWN_ERROR_FAILED, - _("Unknown error executing child process \"%s\""), - argv[0]); - break; - } - - goto cleanup_and_fail; - } - - /* Get child pid from intermediate child pipe. */ - if (intermediate_child) - { - n_ints = 0; - - if (!read_ints (child_pid_report_pipe[0], - buf, 1, &n_ints, error)) - goto cleanup_and_fail; - - if (n_ints < 1) - { - g_set_error (error, - G_SPAWN_ERROR, - G_SPAWN_ERROR_FAILED, - _("Failed to read enough data from child pid pipe (%s)"), - g_strerror (errno)); - goto cleanup_and_fail; - } - else - { - /* we have the child pid */ - pid = buf[0]; - } - } - - /* Success against all odds! return the information */ - close_and_invalidate (&child_err_report_pipe[0]); - close_and_invalidate (&child_pid_report_pipe[0]); - - if (child_pid) - *child_pid = pid; - - if (standard_input) - *standard_input = stdin_pipe[1]; - if (standard_output) - *standard_output = stdout_pipe[0]; - if (standard_error) - *standard_error = stderr_pipe[0]; - - return TRUE; - } - - cleanup_and_fail: - - /* There was an error from the Child, reap the child to avoid it being - a zombie. - */ - - if (pid > 0) - { - wait_failed: - if (waitpid (pid, NULL, 0) < 0) - { - if (errno == EINTR) - goto wait_failed; - else if (errno == ECHILD) - ; /* do nothing, child already reaped */ - else - g_warning ("waitpid() should not fail in " - "'fork_exec_with_pipes'"); - } - } - - close_and_invalidate (&child_err_report_pipe[0]); - close_and_invalidate (&child_err_report_pipe[1]); - close_and_invalidate (&child_pid_report_pipe[0]); - close_and_invalidate (&child_pid_report_pipe[1]); - close_and_invalidate (&stdin_pipe[0]); - close_and_invalidate (&stdin_pipe[1]); - close_and_invalidate (&stdout_pipe[0]); - close_and_invalidate (&stdout_pipe[1]); - close_and_invalidate (&stderr_pipe[0]); - close_and_invalidate (&stderr_pipe[1]); - - return FALSE; -} - -static gboolean -make_pipe (gint p[2], - GError **error) -{ - if (pipe (p) < 0) - { - gint errsv = errno; - g_set_error (error, - G_SPAWN_ERROR, - G_SPAWN_ERROR_FAILED, - _("Failed to create pipe for communicating with child process (%s)"), - g_strerror (errsv)); - return FALSE; - } - else - return TRUE; -} - -/* Based on execvp from GNU C Library */ - -static void -script_execute (const gchar *file, - gchar **argv, - gchar **envp, - gboolean search_path) -{ - /* Count the arguments. */ - int argc = 0; - while (argv[argc]) - ++argc; - - /* Construct an argument list for the shell. */ - { - gchar **new_argv; - - new_argv = g_new0 (gchar*, argc + 2); /* /bin/sh and NULL */ - - new_argv[0] = (char *) "/bin/sh"; - new_argv[1] = (char *) file; - while (argc > 0) - { - new_argv[argc + 1] = argv[argc]; - --argc; - } - - /* Execute the shell. */ - if (envp) - execve (new_argv[0], new_argv, envp); - else - execv (new_argv[0], new_argv); - - g_free (new_argv); - } -} - -static gchar* -my_strchrnul (const gchar *str, gchar c) -{ - gchar *p = (gchar*) str; - while (*p && (*p != c)) - ++p; - - return p; -} - -static gint -g_execute (const gchar *file, - gchar **argv, - gchar **envp, - gboolean search_path) -{ - if (*file == '\0') - { - /* We check the simple case first. */ - errno = ENOENT; - return -1; - } - - if (!search_path || strchr (file, '/') != NULL) - { - /* Don't search when it contains a slash. */ - if (envp) - execve (file, argv, envp); - else - execv (file, argv); - - if (errno == ENOEXEC) - script_execute (file, argv, envp, FALSE); - } - else - { - gboolean got_eacces = 0; - const gchar *path, *p; - gchar *name, *freeme; - gsize len; - gsize pathlen; - - path = g_getenv ("PATH"); - if (path == NULL) - { - /* There is no `PATH' in the environment. The default - * search path in libc is the current directory followed by - * the path `confstr' returns for `_CS_PATH'. - */ - - /* In GLib we put . last, for security, and don't use the - * unportable confstr(); UNIX98 does not actually specify - * what to search if PATH is unset. POSIX may, dunno. - */ - - path = "/bin:/usr/bin:."; - } - - len = strlen (file) + 1; - pathlen = strlen (path); - freeme = name = g_malloc (pathlen + len + 1); - - /* Copy the file name at the top, including '\0' */ - memcpy (name + pathlen + 1, file, len); - name = name + pathlen; - /* And add the slash before the filename */ - *name = '/'; - - p = path; - do - { - char *startp; - - path = p; - p = my_strchrnul (path, ':'); - - if (p == path) - /* Two adjacent colons, or a colon at the beginning or the end - * of `PATH' means to search the current directory. - */ - startp = name + 1; - else - startp = memcpy (name - (p - path), path, p - path); - - /* Try to execute this name. If it works, execv will not return. */ - if (envp) - execve (startp, argv, envp); - else - execv (startp, argv); - - if (errno == ENOEXEC) - script_execute (startp, argv, envp, search_path); - - switch (errno) - { - case EACCES: - /* Record the we got a `Permission denied' error. If we end - * up finding no executable we can use, we want to diagnose - * that we did find one but were denied access. - */ - got_eacces = TRUE; - - /* FALL THRU */ - - case ENOENT: -#ifdef ESTALE - case ESTALE: -#endif -#ifdef ENOTDIR - case ENOTDIR: -#endif - /* Those errors indicate the file is missing or not executable - * by us, in which case we want to just try the next path - * directory. - */ - break; - - default: - /* Some other error means we found an executable file, but - * something went wrong executing it; return the error to our - * caller. - */ - g_free (freeme); - return -1; - } - } - while (*p++ != '\0'); - - /* We tried every element and none of them worked. */ - if (got_eacces) - /* At least one failure was due to permissions, so report that - * error. - */ - errno = EACCES; - - g_free (freeme); - } - - /* Return the error from the last attempt (probably ENOENT). */ - return -1; -} - -/** - * g_spawn_close_pid: - * @pid: The process reference to close - * - * On some platforms, notably Windows, the #GPid type represents a resource - * which must be closed to prevent resource leaking. g_spawn_close_pid() - * is provided for this purpose. It should be used on all platforms, even - * though it doesn't do anything under UNIX. - **/ -void -g_spawn_close_pid (GPid pid) -{ -} - -#define __G_SPAWN_C__ -#include "galiasdef.c" diff --git a/glib/gstrfuncs.c b/glib/gstrfuncs.c index 3aed62c9c..b076aa9ee 100644 --- a/glib/gstrfuncs.c +++ b/glib/gstrfuncs.c @@ -428,7 +428,9 @@ g_ascii_strtod (const gchar *nptr, fail_pos = NULL; +#ifdef ANDROID_STUB locale_data = localeconv (); + decimal_point = locale_data->decimal_point; decimal_point_len = strlen (decimal_point); @@ -547,6 +549,7 @@ g_ascii_strtod (const gchar *nptr, g_free (copy); } else +#endif { errno = 0; val = strtod (nptr, &fail_pos); @@ -561,7 +564,6 @@ g_ascii_strtod (const gchar *nptr, return val; } - /** * g_ascii_dtostr: * @buffer: A buffer to place the resulting string in @@ -643,6 +645,7 @@ g_ascii_formatd (gchar *buffer, _g_snprintf (buffer, buf_len, format, d); +#ifdef ANDROID_STUB locale_data = localeconv (); decimal_point = locale_data->decimal_point; decimal_point_len = strlen (decimal_point); @@ -675,6 +678,7 @@ g_ascii_formatd (gchar *buffer, } } } +#endif return buffer; } diff --git a/glib/gtester-report b/glib/gtester-report deleted file mode 100755 index b385094f0..000000000 --- a/glib/gtester-report +++ /dev/null @@ -1,358 +0,0 @@ -#! /usr/bin/env python -# GLib Testing Framework Utility -*- Mode: python; -*- -# Copyright (C) 2007 Imendio AB -# Authors: Tim Janik -# -# 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 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., 59 Temple Place - Suite 330, -# Boston, MA 02111-1307, USA. -import sys, re, xml.dom.minidom -pkginstall_configvars = { - #@PKGINSTALL_CONFIGVARS_IN24LINES@ # configvars are substituted upon script installation -} - -# xml utilities -def find_child (node, child_name): - for child in node.childNodes: - if child.nodeName == child_name: - return child - return None -def list_children (node, child_name): - rlist = [] - for child in node.childNodes: - if child.nodeName == child_name: - rlist += [ child ] - return rlist -def find_node (node, name = None): - if not node or node.nodeName == name or not name: - return node - for child in node.childNodes: - c = find_node (child, name) - if c: - return c - return None -def node_as_text (node, name = None): - if name: - node = find_node (node, name) - txt = '' - if node: - if node.nodeValue: - txt += node.nodeValue - for child in node.childNodes: - txt += node_as_text (child) - return txt -def attribute_as_text (node, aname, node_name = None): - node = find_node (node, node_name) - if not node: - return '' - attr = node.attributes.get (aname, '') - if hasattr (attr, 'value'): - return attr.value - return '' - -# HTML utilities -def html_indent_string (n): - uncollapsible_space = ' ' # HTML won't compress alternating sequences of ' ' and ' ' - string = '' - for i in range (0, (n + 1) / 2): - string += uncollapsible_space - return string - -# TestBinary object, instantiated per test binary in the log file -class TestBinary: - def __init__ (self, name): - self.name = name - self.testcases = [] - self.duration = 0 - self.success_cases = 0 - self.skipped_cases = 0 - self.file = '???' - self.random_seed = '' - -# base class to handle processing/traversion of XML nodes -class TreeProcess: - def __init__ (self): - self.nest_level = 0 - def trampoline (self, node): - name = node.nodeName - if name == '#text': - self.handle_text (node) - else: - try: method = getattr (self, 'handle_' + re.sub ('[^a-zA-Z0-9]', '_', name)) - except: method = None - if method: - return method (node) - else: - return self.process_recursive (name, node) - def process_recursive (self, node_name, node): - self.process_children (node) - def process_children (self, node): - self.nest_level += 1 - for child in node.childNodes: - self.trampoline (child) - self.nest_level += 1 - -# test report reader, this class collects some statistics and merges duplicate test binary runs -class ReportReader (TreeProcess): - def __init__ (self): - TreeProcess.__init__ (self) - self.binary_names = [] - self.binaries = {} - self.last_binary = None - def binary_list (self): - lst = [] - for name in self.binary_names: - lst += [ self.binaries[name] ] - return lst - def handle_testcase (self, node): - self.last_binary.testcases += [ node ] - result = attribute_as_text (node, 'result', 'status') - if result == 'success': - self.last_binary.success_cases += 1 - if bool (int (attribute_as_text (node, 'skipped') + '0')): - self.last_binary.skipped_cases += 1 - def handle_text (self, node): - pass - def handle_testbinary (self, node): - path = node.attributes.get ('path', None).value - if self.binaries.get (path, -1) == -1: - self.binaries[path] = TestBinary (path) - self.binary_names += [ path ] - self.last_binary = self.binaries[path] - dn = find_child (node, 'duration') - dur = node_as_text (dn) - try: dur = float (dur) - except: dur = 0 - if dur: - self.last_binary.duration += dur - bin = find_child (node, 'binary') - if bin: - self.last_binary.file = attribute_as_text (bin, 'file') - rseed = find_child (node, 'random-seed') - if rseed: - self.last_binary.random_seed = node_as_text (rseed) - self.process_children (node) - -# HTML report generation class -class ReportWriter (TreeProcess): - # Javascript/CSS snippet to toggle element visibility - cssjs = r''' - <style type="text/css" media="screen"> - .VisibleSection { } - .HiddenSection { display: none; } - </style> - <script language="javascript" type="text/javascript"><!-- - function toggle_display (parentid, tagtype, idmatch, keymatch) { - ptag = document.getElementById (parentid); - tags = ptag.getElementsByTagName (tagtype); - for (var i = 0; i < tags.length; i++) { - tag = tags[i]; - var key = tag.getAttribute ("keywords"); - if (tag.id.indexOf (idmatch) == 0 && key && key.match (keymatch)) { - if (tag.className.indexOf ("HiddenSection") >= 0) - tag.className = "VisibleSection"; - else - tag.className = "HiddenSection"; - } - } - } - message_array = Array(); - function view_testlog (wname, file, random_seed, tcase, msgtitle, msgid) { - txt = message_array[msgid]; - var w = window.open ("", // URI - wname, - "resizable,scrollbars,status,width=790,height=400"); - var doc = w.document; - doc.write ("<h2>File: " + file + "</h2>\n"); - doc.write ("<h3>Case: " + tcase + "</h3>\n"); - doc.write ("<strong>Random Seed:</strong> <code>" + random_seed + "</code> <br /><br />\n"); - doc.write ("<strong>" + msgtitle + "</strong><br />\n"); - doc.write ("<pre>"); - doc.write (txt); - doc.write ("</pre>\n"); - doc.write ("<a href=\'javascript:window.close()\'>Close Window</a>\n"); - doc.close(); - } - --></script> - ''' - def __init__ (self, binary_list): - TreeProcess.__init__ (self) - self.binaries = binary_list - self.bcounter = 0 - self.tcounter = 0 - self.total_tcounter = 0 - self.total_fcounter = 0 - self.total_duration = 0 - self.indent_depth = 0 - self.lastchar = '' - def oprint (self, message): - sys.stdout.write (message) - if message: - self.lastchar = message[-1] - def handle_text (self, node): - self.oprint (node.nodeValue) - def handle_testcase (self, node, binary): - skipped = bool (int (attribute_as_text (node, 'skipped') + '0')) - if skipped: - return # skipped tests are uninteresting for HTML reports - path = attribute_as_text (node, 'path') - duration = node_as_text (node, 'duration') - result = attribute_as_text (node, 'result', 'status') - rcolor = { - 'success': 'bgcolor="lightgreen"', - 'failed': 'bgcolor="red"', - }.get (result, '') - if result != 'success': - duration = '-' # ignore bogus durations - self.oprint ('<tr id="b%u_t%u_" keywords="%s all" class="HiddenSection">\n' % (self.bcounter, self.tcounter, result)) - self.oprint ('<td>%s %s</td> <td align="right">%s</td> \n' % (html_indent_string (4), path, duration)) - perflist = list_children (node, 'performance') - if result != 'success': - rlist = list_children (node, 'error') - txt = '' - for enode in rlist: - txt += node_as_text (enode) - if txt and txt[-1] != '\n': - txt += '\n' - txt = re.sub (r'"', r'\\"', txt) - txt = re.sub (r'\n', r'\\n', txt) - txt = re.sub (r'&', r'&', txt) - txt = re.sub (r'<', r'<', txt) - self.oprint ('<script language="javascript" type="text/javascript">message_array["b%u_t%u_"] = "%s";</script>\n' % (self.bcounter, self.tcounter, txt)) - self.oprint ('<td align="center"><a href="javascript:view_testlog (\'%s\', \'%s\', \'%s\', \'%s\', \'Output:\', \'b%u_t%u_\')">Details</a></td>\n' % - ('TestResultWindow', binary.file, binary.random_seed, path, self.bcounter, self.tcounter)) - elif perflist: - presults = [] - for perf in perflist: - pmin = bool (int (attribute_as_text (perf, 'minimize'))) - pmax = bool (int (attribute_as_text (perf, 'maximize'))) - pval = float (attribute_as_text (perf, 'value')) - txt = node_as_text (perf) - txt = re.sub (r'&', r'&', txt) - txt = re.sub (r'<', r'>', txt) - txt = '<strong>Performace(' + (pmin and '<em>minimized</em>' or '<em>maximized</em>') + '):</strong> ' + txt.strip() + '<br />\n' - txt = re.sub (r'"', r'\\"', txt) - txt = re.sub (r'\n', r'\\n', txt) - presults += [ (pval, txt) ] - presults.sort() - ptxt = ''.join ([e[1] for e in presults]) - self.oprint ('<script language="javascript" type="text/javascript">message_array["b%u_t%u_"] = "%s";</script>\n' % (self.bcounter, self.tcounter, ptxt)) - self.oprint ('<td align="center"><a href="javascript:view_testlog (\'%s\', \'%s\', \'%s\', \'%s\', \'Test Results:\', \'b%u_t%u_\')">Details</a></td>\n' % - ('TestResultWindow', binary.file, binary.random_seed, path, self.bcounter, self.tcounter)) - else: - self.oprint ('<td align="center">-</td>\n') - self.oprint ('<td align="right" %s>%s</td>\n' % (rcolor, result)) - self.oprint ('</tr>\n') - self.tcounter += 1 - self.total_tcounter += 1 - self.total_fcounter += result != 'success' - def handle_binary (self, binary): - self.tcounter = 1 - self.bcounter += 1 - self.total_duration += binary.duration - self.oprint ('<tr><td><strong>%s</strong></td><td align="right">%f</td> <td align="center">\n' % (binary.name, binary.duration)) - erlink, oklink = ('', '') - real_cases = len (binary.testcases) - binary.skipped_cases - if binary.success_cases < real_cases: - erlink = 'href="javascript:toggle_display (\'ResultTable\', \'tr\', \'b%u_\', \'failed\')"' % self.bcounter - if binary.success_cases: - oklink = 'href="javascript:toggle_display (\'ResultTable\', \'tr\', \'b%u_\', \'success\')"' % self.bcounter - self.oprint ('<a %s>ER</a>\n' % erlink) - self.oprint ('<a %s>OK</a>\n' % oklink) - self.oprint ('</td>\n') - perc = binary.success_cases * 100.0 / real_cases - pcolor = { - 100 : 'bgcolor="lightgreen"', - 0 : 'bgcolor="red"', - }.get (int (perc), 'bgcolor="yellow"') - self.oprint ('<td align="right" %s>%.2f%%</td>\n' % (pcolor, perc)) - self.oprint ('</tr>\n') - for tc in binary.testcases: - self.handle_testcase (tc, binary) - def handle_totals (self): - self.oprint ('<tr>') - self.oprint ('<td><strong>Totals:</strong> %u Binaries, %u Tests, %u Failed, %u Succeeded</td>' % - (self.bcounter, self.total_tcounter, self.total_fcounter, self.total_tcounter - self.total_fcounter)) - self.oprint ('<td align="right">%f</td>\n' % self.total_duration) - self.oprint ('<td align="center">-</td>\n') - perc = (self.total_tcounter - self.total_fcounter) * 100.0 / self.total_tcounter - pcolor = { - 100 : 'bgcolor="lightgreen"', - 0 : 'bgcolor="red"', - }.get (int (perc), 'bgcolor="yellow"') - self.oprint ('<td align="right" %s>%.2f%%</td>\n' % (pcolor, perc)) - self.oprint ('</tr>\n') - def printout (self): - self.oprint ('<html><head>\n') - self.oprint ('<title>GTester Unit Test Report</title>\n') - self.oprint (self.cssjs) - self.oprint ('</head>\n') - self.oprint ('<body>\n') - self.oprint ('<h2>GTester Unit Test Report</h2>\n') - self.oprint ('<table id="ResultTable" width="100%" border="1">\n<tr>\n') - self.oprint ('<th>Program / Testcase </th>\n') - self.oprint ('<th style="width:8em">Duration (sec)</th>\n') - self.oprint ('<th style="width:5em">View</th>\n') - self.oprint ('<th style="width:5em">Result</th>\n') - self.oprint ('</tr>\n') - for tb in self.binaries: - self.handle_binary (tb) - self.handle_totals() - self.oprint ('</table>\n') - self.oprint ('</body>\n') - self.oprint ('</html>\n') - -# main program handling -def parse_files_and_args (): - from sys import argv, stdin - files = [] - arg_iter = sys.argv[1:].__iter__() - rest = len (sys.argv) - 1 - for arg in arg_iter: - rest -= 1 - if arg == '--help' or arg == '-h': - print_help () - sys.exit (0) - elif arg == '--version' or arg == '-v': - print_help (False) - sys.exit (0) - else: - files = files + [ arg ] - return files - -def print_help (with_help = True): - import os - print "gtester-report (GLib utils) version", pkginstall_configvars.get ('glib-version', '0.0-uninstalled') - if not with_help: - return - print "Usage: %s [OPTIONS] <gtester-log.xml>" % os.path.basename (sys.argv[0]) - print "Generate HTML reports from the XML log files generated by gtester." - print "Options:" - print " --help, -h print this help message" - print " --version, -v print version info" - -def main(): - from sys import argv, stdin - files = parse_files_and_args() - if len (files) != 1: - print_help (True) - sys.exit (1) - xd = xml.dom.minidom.parse (files[0]) - rr = ReportReader() - rr.trampoline (xd) - rw = ReportWriter (rr.binary_list()) - rw.printout() - -if __name__ == '__main__': - main() diff --git a/glib/gtester.c b/glib/gtester.c deleted file mode 100644 index ecc9f77fd..000000000 --- a/glib/gtester.c +++ /dev/null @@ -1,711 +0,0 @@ -/* GLib testing framework runner - * Copyright (C) 2007 Sven Herzberg - * Copyright (C) 2007 Tim Janik - * - * 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ -#include <glib.h> -#include <gstdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/wait.h> -#include <errno.h> -#include <signal.h> - -/* the read buffer size in bytes */ -#define READ_BUFFER_SIZE 4096 - -/* --- prototypes --- */ -static int main_selftest (int argc, - char **argv); -static void parse_args (gint *argc_p, - gchar ***argv_p); - -/* --- variables --- */ -static GIOChannel *ioc_report = NULL; -static gboolean gtester_quiet = FALSE; -static gboolean gtester_verbose = FALSE; -static gboolean gtester_list_tests = FALSE; -static gboolean gtester_selftest = FALSE; -static gboolean subtest_running = FALSE; -static gint subtest_exitstatus = 0; -static gboolean subtest_io_pending = FALSE; -static gboolean subtest_quiet = TRUE; -static gboolean subtest_verbose = FALSE; -static gboolean subtest_mode_fatal = TRUE; -static gboolean subtest_mode_perf = FALSE; -static gboolean subtest_mode_quick = TRUE; -static const gchar *subtest_seedstr = NULL; -static gchar *subtest_last_seed = NULL; -static GSList *subtest_paths = NULL; -static GSList *subtest_args = NULL; -static gboolean testcase_open = FALSE; -static guint testcase_count = 0; -static guint testcase_fail_count = 0; -static const gchar *output_filename = NULL; -static guint log_indent = 0; -static gint log_fd = -1; - -/* --- functions --- */ -static const char* -sindent (guint n) -{ - static const char spaces[] = " "; - int l = sizeof (spaces) - 1; - n = MIN (n, l); - return spaces + l - n; -} - -static void G_GNUC_PRINTF (1, 2) -test_log_printfe (const char *format, - ...) -{ - char *result; - int r; - va_list args; - va_start (args, format); - result = g_markup_vprintf_escaped (format, args); - va_end (args); - do - r = write (log_fd, result, strlen (result)); - while (r < 0 && errno == EINTR); - g_free (result); -} - -static void -terminate (void) -{ - kill (getpid(), SIGTERM); - abort(); -} - -static void -testcase_close (long double duration, - gint exit_status, - guint n_forks) -{ - g_return_if_fail (testcase_open > 0); - test_log_printfe ("%s<duration>%.6Lf</duration>\n", sindent (log_indent), duration); - test_log_printfe ("%s<status exit-status=\"%d\" n-forks=\"%d\" result=\"%s\"/>\n", - sindent (log_indent), exit_status, n_forks, - exit_status ? "failed" : "success"); - log_indent -= 2; - test_log_printfe ("%s</testcase>\n", sindent (log_indent)); - testcase_open--; - if (gtester_verbose) - g_print ("%s\n", exit_status ? "FAIL" : "OK"); - if (exit_status && subtest_last_seed) - g_print ("GTester: last random seed: %s\n", subtest_last_seed); - if (exit_status) - testcase_fail_count += 1; - if (subtest_mode_fatal && testcase_fail_count) - terminate(); -} - -static void -test_log_msg (GTestLogMsg *msg) -{ - switch (msg->log_type) - { - guint i; - gchar **strv; - case G_TEST_LOG_NONE: - break; - case G_TEST_LOG_ERROR: - strv = g_strsplit (msg->strings[0], "\n", -1); - for (i = 0; strv[i]; i++) - test_log_printfe ("%s<error>%s</error>\n", sindent (log_indent), strv[i]); - g_strfreev (strv); - break; - case G_TEST_LOG_START_BINARY: - test_log_printfe ("%s<binary file=\"%s\"/>\n", sindent (log_indent), msg->strings[0]); - subtest_last_seed = g_strdup (msg->strings[1]); - test_log_printfe ("%s<random-seed>%s</random-seed>\n", sindent (log_indent), subtest_last_seed); - break; - case G_TEST_LOG_LIST_CASE: - g_print ("%s\n", msg->strings[0]); - break; - case G_TEST_LOG_START_CASE: - testcase_count++; - if (gtester_verbose) - { - gchar *sc = g_strconcat (msg->strings[0], ":", NULL); - gchar *sleft = g_strdup_printf ("%-68s", sc); - g_free (sc); - g_print ("%70s ", sleft); - g_free (sleft); - } - g_return_if_fail (testcase_open == 0); - testcase_open++; - test_log_printfe ("%s<testcase path=\"%s\">\n", sindent (log_indent), msg->strings[0]); - log_indent += 2; - break; - case G_TEST_LOG_SKIP_CASE: - if (FALSE && gtester_verbose) /* enable to debug test case skipping logic */ - { - gchar *sc = g_strconcat (msg->strings[0], ":", NULL); - gchar *sleft = g_strdup_printf ("%-68s", sc); - g_free (sc); - g_print ("%70s SKIPPED\n", sleft); - g_free (sleft); - } - test_log_printfe ("%s<testcase path=\"%s\" skipped=\"1\"/>\n", sindent (log_indent), msg->strings[0]); - break; - case G_TEST_LOG_STOP_CASE: - testcase_close (msg->nums[2], (int) msg->nums[0], (int) msg->nums[1]); - break; - case G_TEST_LOG_MIN_RESULT: - case G_TEST_LOG_MAX_RESULT: - test_log_printfe ("%s<performance minimize=\"%d\" maximize=\"%d\" value=\"%.16Lg\">\n", - sindent (log_indent), msg->log_type == G_TEST_LOG_MIN_RESULT, msg->log_type == G_TEST_LOG_MAX_RESULT, msg->nums[0]); - test_log_printfe ("%s%s\n", sindent (log_indent + 2), msg->strings[0]); - test_log_printfe ("%s</performance>\n", sindent (log_indent)); - break; - case G_TEST_LOG_MESSAGE: - test_log_printfe ("%s<message>\n%s\n%s</message>\n", sindent (log_indent), msg->strings[0], sindent (log_indent)); - break; - } -} - -static gboolean -child_report_cb (GIOChannel *source, - GIOCondition condition, - gpointer data) -{ - GTestLogBuffer *tlb = data; - GIOStatus status = G_IO_STATUS_NORMAL; - gboolean first_read_eof = FALSE, first_read = TRUE; - gsize length = 0; - do - { - guint8 buffer[READ_BUFFER_SIZE]; - GError *error = NULL; - status = g_io_channel_read_chars (source, (gchar*) buffer, sizeof (buffer), &length, &error); - if (first_read && (condition & G_IO_IN)) - { - /* on some unixes (MacOS) we need to detect non-blocking fd EOF - * by an IO_IN select/poll followed by read()==0. - */ - first_read_eof = length == 0; - } - first_read = FALSE; - if (length) - { - GTestLogMsg *msg; - g_test_log_buffer_push (tlb, length, buffer); - do - { - msg = g_test_log_buffer_pop (tlb); - if (msg) - { - test_log_msg (msg); - g_test_log_msg_free (msg); - } - } - while (msg); - } - g_clear_error (&error); - /* ignore the io channel status, which will report intermediate EOFs for non blocking fds */ - (void) status; - } - while (length > 0); - /* g_print ("LASTIOSTATE: first_read_eof=%d condition=%d\n", first_read_eof, condition); */ - if (first_read_eof || (condition & (G_IO_ERR | G_IO_HUP))) - { - /* if there's no data to read and select() reports an error or hangup, - * the fd must have been closed remotely - */ - subtest_io_pending = FALSE; - return FALSE; - } - return TRUE; /* keep polling */ -} - -static void -child_watch_cb (GPid pid, - gint status, - gpointer data) -{ - g_spawn_close_pid (pid); - if (WIFEXITED (status)) /* normal exit */ - subtest_exitstatus = WEXITSTATUS (status); - else /* signal or core dump, etc */ - subtest_exitstatus = 0xffffffff; - subtest_running = FALSE; -} - -static gchar* -queue_gfree (GSList **slistp, - gchar *string) -{ - *slistp = g_slist_prepend (*slistp, string); - return string; -} - -static void -unset_cloexec_fdp (gpointer fdp_data) -{ - int r, *fdp = fdp_data; - do - r = fcntl (*fdp, F_SETFD, 0 /* FD_CLOEXEC */); - while (r < 0 && errno == EINTR); -} - -static gboolean -launch_test_binary (const char *binary, - guint skip_tests) -{ - GTestLogBuffer *tlb; - GSList *slist, *free_list = NULL; - GError *error = NULL; - int argc = 0; - const gchar **argv; - GPid pid = 0; - gint report_pipe[2] = { -1, -1 }; - guint child_report_cb_id = 0; - gboolean loop_pending; - gint i = 0; - - if (pipe (report_pipe) < 0) - { - if (subtest_mode_fatal) - g_error ("Failed to open pipe for test binary: %s: %s", binary, g_strerror (errno)); - else - g_warning ("Failed to open pipe for test binary: %s: %s", binary, g_strerror (errno)); - return FALSE; - } - - /* setup argc */ - for (slist = subtest_args; slist; slist = slist->next) - argc++; - /* argc++; */ - if (subtest_quiet) - argc++; - if (subtest_verbose) - argc++; - if (!subtest_mode_fatal) - argc++; - if (subtest_mode_quick) - argc++; - else - argc++; - if (subtest_mode_perf) - argc++; - if (gtester_list_tests) - argc++; - if (subtest_seedstr) - argc++; - argc++; - if (skip_tests) - argc++; - for (slist = subtest_paths; slist; slist = slist->next) - argc++; - - /* setup argv */ - argv = g_malloc ((argc + 2) * sizeof(gchar *)); - argv[i++] = binary; - for (slist = subtest_args; slist; slist = slist->next) - argv[i++] = (gchar*) slist->data; - /* argv[i++] = "--debug-log"; */ - if (subtest_quiet) - argv[i++] = "--quiet"; - if (subtest_verbose) - argv[i++] = "--verbose"; - if (!subtest_mode_fatal) - argv[i++] = "--keep-going"; - if (subtest_mode_quick) - argv[i++] = "-m=quick"; - else - argv[i++] = "-m=slow"; - if (subtest_mode_perf) - argv[i++] = "-m=perf"; - if (gtester_list_tests) - argv[i++] = "-l"; - if (subtest_seedstr) - argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--seed=%s", subtest_seedstr)); - argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--GTestLogFD=%u", report_pipe[1])); - if (skip_tests) - argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--GTestSkipCount=%u", skip_tests)); - for (slist = subtest_paths; slist; slist = slist->next) - argv[i++] = queue_gfree (&free_list, g_strdup_printf ("-p=%s", (gchar*) slist->data)); - argv[i++] = NULL; - - g_spawn_async_with_pipes (NULL, /* g_get_current_dir() */ - (gchar**) argv, - NULL, /* envp */ - G_SPAWN_DO_NOT_REAP_CHILD, /* G_SPAWN_SEARCH_PATH */ - unset_cloexec_fdp, &report_pipe[1], /* pre-exec callback */ - &pid, - NULL, /* standard_input */ - NULL, /* standard_output */ - NULL, /* standard_error */ - &error); - g_slist_foreach (free_list, (void(*)(void*,void*)) g_free, NULL); - g_slist_free (free_list); - free_list = NULL; - close (report_pipe[1]); - - if (!gtester_quiet) - g_print ("(pid=%lu)\n", (unsigned long) pid); - - if (error) - { - close (report_pipe[0]); - if (subtest_mode_fatal) - g_error ("Failed to execute test binary: %s: %s", argv[0], error->message); - else - g_warning ("Failed to execute test binary: %s: %s", argv[0], error->message); - g_clear_error (&error); - g_free (argv); - return FALSE; - } - g_free (argv); - - subtest_running = TRUE; - subtest_io_pending = TRUE; - tlb = g_test_log_buffer_new(); - if (report_pipe[0] >= 0) - { - ioc_report = g_io_channel_unix_new (report_pipe[0]); - g_io_channel_set_flags (ioc_report, G_IO_FLAG_NONBLOCK, NULL); - g_io_channel_set_encoding (ioc_report, NULL, NULL); - g_io_channel_set_buffered (ioc_report, FALSE); - child_report_cb_id = g_io_add_watch_full (ioc_report, G_PRIORITY_DEFAULT - 1, G_IO_IN | G_IO_ERR | G_IO_HUP, child_report_cb, tlb, NULL); - g_io_channel_unref (ioc_report); - } - g_child_watch_add_full (G_PRIORITY_DEFAULT + 1, pid, child_watch_cb, NULL, NULL); - - loop_pending = g_main_context_pending (NULL); - while (subtest_running || /* FALSE once child exits */ - subtest_io_pending || /* FALSE once ioc_report closes */ - loop_pending) /* TRUE while idler, etc are running */ - { - /* g_print ("LOOPSTATE: subtest_running=%d subtest_io_pending=%d\n", subtest_running, subtest_io_pending); */ - /* check for unexpected hangs that are not signalled on report_pipe */ - if (!subtest_running && /* child exited */ - subtest_io_pending && /* no EOF detected on report_pipe */ - !loop_pending) /* no IO events pending however */ - break; - g_main_context_iteration (NULL, TRUE); - loop_pending = g_main_context_pending (NULL); - } - - g_source_remove (child_report_cb_id); - close (report_pipe[0]); - g_test_log_buffer_free (tlb); - - return TRUE; -} - -static void -launch_test (const char *binary) -{ - gboolean success = TRUE; - GTimer *btimer = g_timer_new(); - gboolean need_restart; - testcase_count = 0; - testcase_fail_count = 0; - if (!gtester_quiet) - g_print ("TEST: %s... ", binary); - - retry: - test_log_printfe ("%s<testbinary path=\"%s\">\n", sindent (log_indent), binary); - log_indent += 2; - g_timer_start (btimer); - subtest_exitstatus = 0; - success &= launch_test_binary (binary, testcase_count); - success &= subtest_exitstatus == 0; - need_restart = testcase_open != 0; - if (testcase_open) - testcase_close (0, -256, 0); - g_timer_stop (btimer); - test_log_printfe ("%s<duration>%.6f</duration>\n", sindent (log_indent), g_timer_elapsed (btimer, NULL)); - log_indent -= 2; - test_log_printfe ("%s</testbinary>\n", sindent (log_indent)); - g_free (subtest_last_seed); - subtest_last_seed = NULL; - if (need_restart) - { - /* restart test binary, skipping processed test cases */ - goto retry; - } - - if (!gtester_quiet) - g_print ("%s: %s\n", testcase_fail_count || !success ? "FAIL" : "PASS", binary); - g_timer_destroy (btimer); - if (subtest_mode_fatal && !success) - terminate(); -} - -static void -usage (gboolean just_version) -{ - if (just_version) - { - g_print ("gtester version %d.%d.%d\n", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); - return; - } - g_print ("Usage: gtester [OPTIONS] testprogram...\n"); - /* 12345678901234567890123456789012345678901234567890123456789012345678901234567890 */ - g_print ("Options:\n"); - g_print (" -h, --help show this help message\n"); - g_print (" -v, --version print version informations\n"); - g_print (" --g-fatal-warnings make warnings fatal (abort)\n"); - g_print (" -k, --keep-going continue running after tests failed\n"); - g_print (" -l list paths of available test cases\n"); - g_print (" -m=perf, -m=slow, -m=quick -m=thorough\n"); - g_print (" run test cases in mode perf, slow/thorough or quick (default)\n"); - g_print (" -p=TESTPATH only start test cases matching TESTPATH\n"); - g_print (" --seed=SEEDSTRING start all tests with random number seed SEEDSTRING\n"); - g_print (" -o=LOGFILE write the test log to LOGFILE\n"); - g_print (" -q, --quiet suppress per test binary output\n"); - g_print (" --verbose report success per testcase\n"); -} - -static void -parse_args (gint *argc_p, - gchar ***argv_p) -{ - guint argc = *argc_p; - gchar **argv = *argv_p; - guint i, e; - /* parse known args */ - for (i = 1; i < argc; i++) - { - if (strcmp (argv[i], "--g-fatal-warnings") == 0) - { - GLogLevelFlags fatal_mask = (GLogLevelFlags) g_log_set_always_fatal ((GLogLevelFlags) G_LOG_FATAL_MASK); - fatal_mask = (GLogLevelFlags) (fatal_mask | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL); - g_log_set_always_fatal (fatal_mask); - argv[i] = NULL; - } - else if (strcmp (argv[i], "--gtester-selftest") == 0) - { - gtester_selftest = TRUE; - argv[i] = NULL; - break; /* stop parsing regular gtester arguments */ - } - else if (strcmp (argv[i], "-h") == 0 || strcmp (argv[i], "--help") == 0) - { - usage (FALSE); - exit (0); - argv[i] = NULL; - } - else if (strcmp (argv[i], "-v") == 0 || strcmp (argv[i], "--version") == 0) - { - usage (TRUE); - exit (0); - argv[i] = NULL; - } - else if (strcmp (argv[i], "--keep-going") == 0 || - strcmp (argv[i], "-k") == 0) - { - subtest_mode_fatal = FALSE; - argv[i] = NULL; - } - else if (strcmp ("-p", argv[i]) == 0 || strncmp ("-p=", argv[i], 3) == 0) - { - gchar *equal = argv[i] + 2; - if (*equal == '=') - subtest_paths = g_slist_prepend (subtest_paths, equal + 1); - else if (i + 1 < argc) - { - argv[i++] = NULL; - subtest_paths = g_slist_prepend (subtest_paths, argv[i]); - } - argv[i] = NULL; - } - else if (strcmp ("--test-arg", argv[i]) == 0 || strncmp ("--test-arg=", argv[i], 11) == 0) - { - gchar *equal = argv[i] + 10; - if (*equal == '=') - subtest_args = g_slist_prepend (subtest_args, equal + 1); - else if (i + 1 < argc) - { - argv[i++] = NULL; - subtest_args = g_slist_prepend (subtest_args, argv[i]); - } - argv[i] = NULL; - } - else if (strcmp ("-o", argv[i]) == 0 || strncmp ("-o=", argv[i], 3) == 0) - { - gchar *equal = argv[i] + 2; - if (*equal == '=') - output_filename = equal + 1; - else if (i + 1 < argc) - { - argv[i++] = NULL; - output_filename = argv[i]; - } - argv[i] = NULL; - } - else if (strcmp ("-m", argv[i]) == 0 || strncmp ("-m=", argv[i], 3) == 0) - { - gchar *equal = argv[i] + 2; - const gchar *mode = ""; - if (*equal == '=') - mode = equal + 1; - else if (i + 1 < argc) - { - argv[i++] = NULL; - mode = argv[i]; - } - if (strcmp (mode, "perf") == 0) - subtest_mode_perf = TRUE; - else if (strcmp (mode, "slow") == 0 || strcmp (mode, "thorough") == 0) - subtest_mode_quick = FALSE; - else if (strcmp (mode, "quick") == 0) - { - subtest_mode_quick = TRUE; - subtest_mode_perf = FALSE; - } - else - g_error ("unknown test mode: -m %s", mode); - argv[i] = NULL; - } - else if (strcmp ("-q", argv[i]) == 0 || strcmp ("--quiet", argv[i]) == 0) - { - gtester_quiet = TRUE; - gtester_verbose = FALSE; - argv[i] = NULL; - } - else if (strcmp ("--verbose", argv[i]) == 0) - { - gtester_quiet = FALSE; - gtester_verbose = TRUE; - argv[i] = NULL; - } - else if (strcmp ("-l", argv[i]) == 0) - { - gtester_list_tests = TRUE; - argv[i] = NULL; - } - else if (strcmp ("--seed", argv[i]) == 0 || strncmp ("--seed=", argv[i], 7) == 0) - { - gchar *equal = argv[i] + 6; - if (*equal == '=') - subtest_seedstr = equal + 1; - else if (i + 1 < argc) - { - argv[i++] = NULL; - subtest_seedstr = argv[i]; - } - argv[i] = NULL; - } - } - /* collapse argv */ - e = 1; - for (i = 1; i < argc; i++) - if (argv[i]) - { - argv[e++] = argv[i]; - if (i >= e) - argv[i] = NULL; - } - *argc_p = e; -} - -int -main (int argc, - char **argv) -{ - guint ui; - - /* some unices need SA_RESTART for SIGCHLD to return -EAGAIN for io. - * we must fiddle with sigaction() *before* glib is used, otherwise - * we could revoke signal hanmdler setups from glib initialization code. - */ - if (TRUE) - { - struct sigaction sa; - struct sigaction osa; - sa.sa_handler = SIG_DFL; - sigfillset (&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sigaction (SIGCHLD, &sa, &osa); - } - - g_set_prgname (argv[0]); - parse_args (&argc, &argv); - if (gtester_selftest) - return main_selftest (argc, argv); - - if (argc <= 1) - { - usage (FALSE); - return 1; - } - - if (output_filename) - { - log_fd = g_open (output_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); - if (log_fd < 0) - g_error ("Failed to open log file '%s': %s", output_filename, g_strerror (errno)); - } - - test_log_printfe ("<?xml version=\"1.0\"?>\n"); - test_log_printfe ("%s<gtester>\n", sindent (log_indent)); - log_indent += 2; - for (ui = 1; ui < argc; ui++) - { - const char *binary = argv[ui]; - launch_test (binary); - /* we only get here on success or if !subtest_mode_fatal */ - } - log_indent -= 2; - test_log_printfe ("%s</gtester>\n", sindent (log_indent)); - - close (log_fd); - - return 0; -} - -static void -fixture_setup (guint *fix, - gconstpointer test_data) -{ - g_assert_cmphex (*fix, ==, 0); - *fix = 0xdeadbeef; -} -static void -fixture_test (guint *fix, - gconstpointer test_data) -{ - g_assert_cmphex (*fix, ==, 0xdeadbeef); - g_test_message ("This is a test message API test message."); - g_test_bug_base ("http://www.example.com/bugtracker/"); - g_test_bug ("123"); - g_test_bug_base ("http://www.example.com/bugtracker?bugnum=%s;cmd=showbug"); - g_test_bug ("456"); -} -static void -fixture_teardown (guint *fix, - gconstpointer test_data) -{ - g_assert_cmphex (*fix, ==, 0xdeadbeef); -} - -static int -main_selftest (int argc, - char **argv) -{ - /* gtester main() for --gtester-selftest invokations */ - g_test_init (&argc, &argv, NULL); - g_test_add ("/gtester/fixture-test", guint, NULL, fixture_setup, fixture_test, fixture_teardown); - return g_test_run(); -} diff --git a/glib/gthreadpool.c b/glib/gthreadpool.c deleted file mode 100644 index 2059a999d..000000000 --- a/glib/gthreadpool.c +++ /dev/null @@ -1,945 +0,0 @@ -/* GLIB - Library of useful routines for C programming - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * GAsyncQueue: thread pool implementation. - * 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * MT safe - */ - -#include "config.h" - -#include "glib.h" -#include "galias.h" - -#define DEBUG_MSG(x) -/* #define DEBUG_MSG(args) g_printerr args ; g_printerr ("\n"); */ - -typedef struct _GRealThreadPool GRealThreadPool; - -struct _GRealThreadPool -{ - GThreadPool pool; - GAsyncQueue* queue; - GCond* cond; - gint max_threads; - gint num_threads; - gboolean running; - gboolean immediate; - gboolean waiting; - GCompareDataFunc sort_func; - gpointer sort_user_data; -}; - -/* The following is just an address to mark the wakeup order for a - * thread, it could be any address (as long, as it isn't a valid - * GThreadPool address) */ -static const gpointer wakeup_thread_marker = (gpointer) &g_thread_pool_new; -static gint wakeup_thread_serial = 0; - -/* Here all unused threads are waiting */ -static GAsyncQueue *unused_thread_queue = NULL; -static gint unused_threads = 0; -static gint max_unused_threads = 0; -static gint kill_unused_threads = 0; -static guint max_idle_time = 0; - -static void g_thread_pool_queue_push_unlocked (GRealThreadPool *pool, - gpointer data); -static void g_thread_pool_free_internal (GRealThreadPool *pool); -static gpointer g_thread_pool_thread_proxy (gpointer data); -static void g_thread_pool_start_thread (GRealThreadPool *pool, - GError **error); -static void g_thread_pool_wakeup_and_stop_all (GRealThreadPool *pool); -static GRealThreadPool* g_thread_pool_wait_for_new_pool (void); -static gpointer g_thread_pool_wait_for_new_task (GRealThreadPool *pool); - -static void -g_thread_pool_queue_push_unlocked (GRealThreadPool *pool, - gpointer data) -{ - if (pool->sort_func) - g_async_queue_push_sorted_unlocked (pool->queue, - data, - pool->sort_func, - pool->sort_user_data); - else - g_async_queue_push_unlocked (pool->queue, data); -} - -static GRealThreadPool* -g_thread_pool_wait_for_new_pool (void) -{ - GRealThreadPool *pool; - gint local_wakeup_thread_serial; - guint local_max_unused_threads; - gint local_max_idle_time; - gint last_wakeup_thread_serial; - gboolean have_relayed_thread_marker = FALSE; - - local_max_unused_threads = g_atomic_int_get (&max_unused_threads); - local_max_idle_time = g_atomic_int_get (&max_idle_time); - last_wakeup_thread_serial = g_atomic_int_get (&wakeup_thread_serial); - - g_atomic_int_inc (&unused_threads); - - do - { - if (g_atomic_int_get (&unused_threads) >= local_max_unused_threads) - { - /* If this is a superfluous thread, stop it. */ - pool = NULL; - } - else if (local_max_idle_time > 0) - { - /* If a maximal idle time is given, wait for the given time. */ - GTimeVal end_time; - - g_get_current_time (&end_time); - g_time_val_add (&end_time, local_max_idle_time * 1000); - - DEBUG_MSG (("thread %p waiting in global pool for %f seconds.", - g_thread_self (), local_max_idle_time / 1000.0)); - - pool = g_async_queue_timed_pop (unused_thread_queue, &end_time); - } - else - { - /* If no maximal idle time is given, wait indefinitely. */ - DEBUG_MSG (("thread %p waiting in global pool.", - g_thread_self ())); - pool = g_async_queue_pop (unused_thread_queue); - } - - if (pool == wakeup_thread_marker) - { - local_wakeup_thread_serial = g_atomic_int_get (&wakeup_thread_serial); - if (last_wakeup_thread_serial == local_wakeup_thread_serial) - { - if (!have_relayed_thread_marker) - { - /* If this wakeup marker has been received for - * the second time, relay it. - */ - DEBUG_MSG (("thread %p relaying wakeup message to " - "waiting thread with lower serial.", - g_thread_self ())); - - g_async_queue_push (unused_thread_queue, wakeup_thread_marker); - have_relayed_thread_marker = TRUE; - - /* If a wakeup marker has been relayed, this thread - * will get out of the way for 100 microseconds to - * avoid receiving this marker again. */ - g_usleep (100); - } - } - else - { - if (g_atomic_int_exchange_and_add (&kill_unused_threads, -1) > 0) - { - pool = NULL; - break; - } - - DEBUG_MSG (("thread %p updating to new limits.", - g_thread_self ())); - - local_max_unused_threads = g_atomic_int_get (&max_unused_threads); - local_max_idle_time = g_atomic_int_get (&max_idle_time); - last_wakeup_thread_serial = local_wakeup_thread_serial; - - have_relayed_thread_marker = FALSE; - } - } - } - while (pool == wakeup_thread_marker); - - g_atomic_int_add (&unused_threads, -1); - - return pool; -} - -static gpointer -g_thread_pool_wait_for_new_task (GRealThreadPool *pool) -{ - gpointer task = NULL; - - if (pool->running || (!pool->immediate && - g_async_queue_length_unlocked (pool->queue) > 0)) - { - /* This thread pool is still active. */ - if (pool->num_threads > pool->max_threads && pool->max_threads != -1) - { - /* This is a superfluous thread, so it goes to the global pool. */ - DEBUG_MSG (("superfluous thread %p in pool %p.", - g_thread_self (), pool)); - } - else if (pool->pool.exclusive) - { - /* Exclusive threads stay attached to the pool. */ - task = g_async_queue_pop_unlocked (pool->queue); - - DEBUG_MSG (("thread %p in exclusive pool %p waits for task " - "(%d running, %d unprocessed).", - g_thread_self (), pool, pool->num_threads, - g_async_queue_length_unlocked (pool->queue))); - } - else - { - /* A thread will wait for new tasks for at most 1/2 - * second before going to the global pool. - */ - GTimeVal end_time; - - g_get_current_time (&end_time); - g_time_val_add (&end_time, G_USEC_PER_SEC / 2); /* 1/2 second */ - - DEBUG_MSG (("thread %p in pool %p waits for up to a 1/2 second for task " - "(%d running, %d unprocessed).", - g_thread_self (), pool, pool->num_threads, - g_async_queue_length_unlocked (pool->queue))); - - task = g_async_queue_timed_pop_unlocked (pool->queue, &end_time); - } - } - else - { - /* This thread pool is inactive, it will no longer process tasks. */ - DEBUG_MSG (("pool %p not active, thread %p will go to global pool " - "(running: %s, immediate: %s, len: %d).", - pool, g_thread_self (), - pool->running ? "true" : "false", - pool->immediate ? "true" : "false", - g_async_queue_length_unlocked (pool->queue))); - } - - return task; -} - - -static gpointer -g_thread_pool_thread_proxy (gpointer data) -{ - GRealThreadPool *pool; - - pool = data; - - DEBUG_MSG (("thread %p started for pool %p.", - g_thread_self (), pool)); - - g_async_queue_lock (pool->queue); - - while (TRUE) - { - gpointer task; - - task = g_thread_pool_wait_for_new_task (pool); - if (task) - { - if (pool->running || !pool->immediate) - { - /* A task was received and the thread pool is active, so - * execute the function. - */ - g_async_queue_unlock (pool->queue); - DEBUG_MSG (("thread %p in pool %p calling func.", - g_thread_self (), pool)); - pool->pool.func (task, pool->pool.user_data); - g_async_queue_lock (pool->queue); - } - } - else - { - /* No task was received, so this thread goes to the global - * pool. - */ - gboolean free_pool = FALSE; - - DEBUG_MSG (("thread %p leaving pool %p for global pool.", - g_thread_self (), pool)); - pool->num_threads--; - - if (!pool->running) - { - if (!pool->waiting) - { - if (pool->num_threads == 0) - { - /* If the pool is not running and no other - * thread is waiting for this thread pool to - * finish and this is the last thread of this - * pool, free the pool. - */ - free_pool = TRUE; - } - else - { - /* If the pool is not running and no other - * thread is waiting for this thread pool to - * finish and this is not the last thread of - * this pool and there are no tasks left in the - * queue, wakeup the remaining threads. - */ - if (g_async_queue_length_unlocked (pool->queue) == - - pool->num_threads) - g_thread_pool_wakeup_and_stop_all (pool); - } - } - else if (pool->immediate || - g_async_queue_length_unlocked (pool->queue) <= 0) - { - /* If the pool is not running and another thread is - * waiting for this thread pool to finish and there - * are either no tasks left or the pool shall stop - * immediatly, inform the waiting thread of a change - * of the thread pool state. - */ - g_cond_broadcast (pool->cond); - } - } - - g_async_queue_unlock (pool->queue); - - if (free_pool) - g_thread_pool_free_internal (pool); - - if ((pool = g_thread_pool_wait_for_new_pool ()) == NULL) - break; - - g_async_queue_lock (pool->queue); - - DEBUG_MSG (("thread %p entering pool %p from global pool.", - g_thread_self (), pool)); - - /* pool->num_threads++ is not done here, but in - * g_thread_pool_start_thread to make the new started thread - * known to the pool, before itself can do it. - */ - } - } - - return NULL; -} - -static void -g_thread_pool_start_thread (GRealThreadPool *pool, - GError **error) -{ - gboolean success = FALSE; - - if (pool->num_threads >= pool->max_threads && pool->max_threads != -1) - /* Enough threads are already running */ - return; - - g_async_queue_lock (unused_thread_queue); - - if (g_async_queue_length_unlocked (unused_thread_queue) < 0) - { - g_async_queue_push_unlocked (unused_thread_queue, pool); - success = TRUE; - } - - g_async_queue_unlock (unused_thread_queue); - - if (!success) - { - GError *local_error = NULL; - /* No thread was found, we have to start a new one */ - g_thread_create (g_thread_pool_thread_proxy, pool, FALSE, &local_error); - - if (local_error) - { - g_propagate_error (error, local_error); - return; - } - } - - /* See comment in g_thread_pool_thread_proxy as to why this is done - * here and not there - */ - pool->num_threads++; -} - -/** - * g_thread_pool_new: - * @func: a function to execute in the threads of the new thread pool - * @user_data: user data that is handed over to @func every time it - * is called - * @max_threads: the maximal number of threads to execute concurrently in - * the new thread pool, -1 means no limit - * @exclusive: should this thread pool be exclusive? - * @error: return location for error - * - * This function creates a new thread pool. - * - * Whenever you call g_thread_pool_push(), either a new thread is - * created or an unused one is reused. At most @max_threads threads - * are running concurrently for this thread pool. @max_threads = -1 - * allows unlimited threads to be created for this thread pool. The - * newly created or reused thread now executes the function @func with - * the two arguments. The first one is the parameter to - * g_thread_pool_push() and the second one is @user_data. - * - * The parameter @exclusive determines, whether the thread pool owns - * all threads exclusive or whether the threads are shared - * globally. If @exclusive is %TRUE, @max_threads threads are started - * immediately and they will run exclusively for this thread pool until - * it is destroyed by g_thread_pool_free(). If @exclusive is %FALSE, - * threads are created, when needed and shared between all - * non-exclusive thread pools. This implies that @max_threads may not - * be -1 for exclusive thread pools. - * - * @error can be %NULL to ignore errors, or non-%NULL to report - * errors. An error can only occur when @exclusive is set to %TRUE and - * not all @max_threads threads could be created. - * - * Return value: the new #GThreadPool - **/ -GThreadPool* -g_thread_pool_new (GFunc func, - gpointer user_data, - gint max_threads, - gboolean exclusive, - GError **error) -{ - GRealThreadPool *retval; - G_LOCK_DEFINE_STATIC (init); - - g_return_val_if_fail (func, NULL); - g_return_val_if_fail (!exclusive || max_threads != -1, NULL); - g_return_val_if_fail (max_threads >= -1, NULL); - g_return_val_if_fail (g_thread_supported (), NULL); - - retval = g_new (GRealThreadPool, 1); - - retval->pool.func = func; - retval->pool.user_data = user_data; - retval->pool.exclusive = exclusive; - retval->queue = g_async_queue_new (); - retval->cond = NULL; - retval->max_threads = max_threads; - retval->num_threads = 0; - retval->running = TRUE; - retval->sort_func = NULL; - retval->sort_user_data = NULL; - - G_LOCK (init); - if (!unused_thread_queue) - unused_thread_queue = g_async_queue_new (); - G_UNLOCK (init); - - if (retval->pool.exclusive) - { - g_async_queue_lock (retval->queue); - - while (retval->num_threads < retval->max_threads) - { - GError *local_error = NULL; - g_thread_pool_start_thread (retval, &local_error); - if (local_error) - { - g_propagate_error (error, local_error); - break; - } - } - - g_async_queue_unlock (retval->queue); - } - - return (GThreadPool*) retval; -} - -/** - * g_thread_pool_push: - * @pool: a #GThreadPool - * @data: a new task for @pool - * @error: return location for error - * - * Inserts @data into the list of tasks to be executed by @pool. When - * the number of currently running threads is lower than the maximal - * allowed number of threads, a new thread is started (or reused) with - * the properties given to g_thread_pool_new (). Otherwise @data stays - * in the queue until a thread in this pool finishes its previous task - * and processes @data. - * - * @error can be %NULL to ignore errors, or non-%NULL to report - * errors. An error can only occur when a new thread couldn't be - * created. In that case @data is simply appended to the queue of work - * to do. - **/ -void -g_thread_pool_push (GThreadPool *pool, - gpointer data, - GError **error) -{ - GRealThreadPool *real; - - real = (GRealThreadPool*) pool; - - g_return_if_fail (real); - g_return_if_fail (real->running); - - g_async_queue_lock (real->queue); - - if (g_async_queue_length_unlocked (real->queue) >= 0) - /* No thread is waiting in the queue */ - g_thread_pool_start_thread (real, error); - - g_thread_pool_queue_push_unlocked (real, data); - g_async_queue_unlock (real->queue); -} - -/** - * g_thread_pool_set_max_threads: - * @pool: a #GThreadPool - * @max_threads: a new maximal number of threads for @pool - * @error: return location for error - * - * Sets the maximal allowed number of threads for @pool. A value of -1 - * means, that the maximal number of threads is unlimited. - * - * Setting @max_threads to 0 means stopping all work for @pool. It is - * effectively frozen until @max_threads is set to a non-zero value - * again. - * - * A thread is never terminated while calling @func, as supplied by - * g_thread_pool_new (). Instead the maximal number of threads only - * has effect for the allocation of new threads in g_thread_pool_push(). - * A new thread is allocated, whenever the number of currently - * running threads in @pool is smaller than the maximal number. - * - * @error can be %NULL to ignore errors, or non-%NULL to report - * errors. An error can only occur when a new thread couldn't be - * created. - **/ -void -g_thread_pool_set_max_threads (GThreadPool *pool, - gint max_threads, - GError **error) -{ - GRealThreadPool *real; - gint to_start; - - real = (GRealThreadPool*) pool; - - g_return_if_fail (real); - g_return_if_fail (real->running); - g_return_if_fail (!real->pool.exclusive || max_threads != -1); - g_return_if_fail (max_threads >= -1); - - g_async_queue_lock (real->queue); - - real->max_threads = max_threads; - - if (pool->exclusive) - to_start = real->max_threads - real->num_threads; - else - to_start = g_async_queue_length_unlocked (real->queue); - - for ( ; to_start > 0; to_start--) - { - GError *local_error = NULL; - - g_thread_pool_start_thread (real, &local_error); - if (local_error) - { - g_propagate_error (error, local_error); - break; - } - } - - g_async_queue_unlock (real->queue); -} - -/** - * g_thread_pool_get_max_threads: - * @pool: a #GThreadPool - * - * Returns the maximal number of threads for @pool. - * - * Return value: the maximal number of threads - **/ -gint -g_thread_pool_get_max_threads (GThreadPool *pool) -{ - GRealThreadPool *real; - gint retval; - - real = (GRealThreadPool*) pool; - - g_return_val_if_fail (real, 0); - g_return_val_if_fail (real->running, 0); - - g_async_queue_lock (real->queue); - retval = real->max_threads; - g_async_queue_unlock (real->queue); - - return retval; -} - -/** - * g_thread_pool_get_num_threads: - * @pool: a #GThreadPool - * - * Returns the number of threads currently running in @pool. - * - * Return value: the number of threads currently running - **/ -guint -g_thread_pool_get_num_threads (GThreadPool *pool) -{ - GRealThreadPool *real; - guint retval; - - real = (GRealThreadPool*) pool; - - g_return_val_if_fail (real, 0); - g_return_val_if_fail (real->running, 0); - - g_async_queue_lock (real->queue); - retval = real->num_threads; - g_async_queue_unlock (real->queue); - - return retval; -} - -/** - * g_thread_pool_unprocessed: - * @pool: a #GThreadPool - * - * Returns the number of tasks still unprocessed in @pool. - * - * Return value: the number of unprocessed tasks - **/ -guint -g_thread_pool_unprocessed (GThreadPool *pool) -{ - GRealThreadPool *real; - gint unprocessed; - - real = (GRealThreadPool*) pool; - - g_return_val_if_fail (real, 0); - g_return_val_if_fail (real->running, 0); - - unprocessed = g_async_queue_length (real->queue); - - return MAX (unprocessed, 0); -} - -/** - * g_thread_pool_free: - * @pool: a #GThreadPool - * @immediate: should @pool shut down immediately? - * @wait_: should the function wait for all tasks to be finished? - * - * Frees all resources allocated for @pool. - * - * If @immediate is %TRUE, no new task is processed for - * @pool. Otherwise @pool is not freed before the last task is - * processed. Note however, that no thread of this pool is - * interrupted, while processing a task. Instead at least all still - * running threads can finish their tasks before the @pool is freed. - * - * If @wait_ is %TRUE, the functions does not return before all tasks - * to be processed (dependent on @immediate, whether all or only the - * currently running) are ready. Otherwise the function returns immediately. - * - * After calling this function @pool must not be used anymore. - **/ -void -g_thread_pool_free (GThreadPool *pool, - gboolean immediate, - gboolean wait_) -{ - GRealThreadPool *real; - - real = (GRealThreadPool*) pool; - - g_return_if_fail (real); - g_return_if_fail (real->running); - - /* If there's no thread allowed here, there is not much sense in - * not stopping this pool immediately, when it's not empty - */ - g_return_if_fail (immediate || - real->max_threads != 0 || - g_async_queue_length (real->queue) == 0); - - g_async_queue_lock (real->queue); - - real->running = FALSE; - real->immediate = immediate; - real->waiting = wait_; - - if (wait_) - { - real->cond = g_cond_new (); - - while (g_async_queue_length_unlocked (real->queue) != -real->num_threads && - !(immediate && real->num_threads == 0)) - g_cond_wait (real->cond, _g_async_queue_get_mutex (real->queue)); - } - - if (immediate || g_async_queue_length_unlocked (real->queue) == -real->num_threads) - { - /* No thread is currently doing something (and nothing is left - * to process in the queue) - */ - if (real->num_threads == 0) - { - /* No threads left, we clean up */ - g_async_queue_unlock (real->queue); - g_thread_pool_free_internal (real); - return; - } - - g_thread_pool_wakeup_and_stop_all (real); - } - - /* The last thread should cleanup the pool */ - real->waiting = FALSE; - g_async_queue_unlock (real->queue); -} - -static void -g_thread_pool_free_internal (GRealThreadPool* pool) -{ - g_return_if_fail (pool); - g_return_if_fail (pool->running == FALSE); - g_return_if_fail (pool->num_threads == 0); - - g_async_queue_unref (pool->queue); - - if (pool->cond) - g_cond_free (pool->cond); - - g_free (pool); -} - -static void -g_thread_pool_wakeup_and_stop_all (GRealThreadPool* pool) -{ - guint i; - - g_return_if_fail (pool); - g_return_if_fail (pool->running == FALSE); - g_return_if_fail (pool->num_threads != 0); - - pool->immediate = TRUE; - - for (i = 0; i < pool->num_threads; i++) - g_thread_pool_queue_push_unlocked (pool, GUINT_TO_POINTER (1)); -} - -/** - * g_thread_pool_set_max_unused_threads: - * @max_threads: maximal number of unused threads - * - * Sets the maximal number of unused threads to @max_threads. If - * @max_threads is -1, no limit is imposed on the number of unused - * threads. - **/ -void -g_thread_pool_set_max_unused_threads (gint max_threads) -{ - g_return_if_fail (max_threads >= -1); - - g_atomic_int_set (&max_unused_threads, max_threads); - - if (max_threads != -1) - { - max_threads -= g_atomic_int_get (&unused_threads); - if (max_threads < 0) - { - g_atomic_int_set (&kill_unused_threads, -max_threads); - g_atomic_int_inc (&wakeup_thread_serial); - - g_async_queue_lock (unused_thread_queue); - - do - { - g_async_queue_push_unlocked (unused_thread_queue, - wakeup_thread_marker); - } - while (++max_threads); - - g_async_queue_unlock (unused_thread_queue); - } - } -} - -/** - * g_thread_pool_get_max_unused_threads: - * - * Returns the maximal allowed number of unused threads. - * - * Return value: the maximal number of unused threads - **/ -gint -g_thread_pool_get_max_unused_threads (void) -{ - return g_atomic_int_get (&max_unused_threads); -} - -/** - * g_thread_pool_get_num_unused_threads: - * - * Returns the number of currently unused threads. - * - * Return value: the number of currently unused threads - **/ -guint -g_thread_pool_get_num_unused_threads (void) -{ - return g_atomic_int_get (&unused_threads); -} - -/** - * g_thread_pool_stop_unused_threads: - * - * Stops all currently unused threads. This does not change the - * maximal number of unused threads. This function can be used to - * regularly stop all unused threads e.g. from g_timeout_add(). - **/ -void -g_thread_pool_stop_unused_threads (void) -{ - guint oldval; - - oldval = g_thread_pool_get_max_unused_threads (); - - g_thread_pool_set_max_unused_threads (0); - g_thread_pool_set_max_unused_threads (oldval); -} - -/** - * g_thread_pool_set_sort_function: - * @pool: a #GThreadPool - * @func: the #GCompareDataFunc used to sort the list of tasks. - * This function is passed two tasks. It should return - * 0 if the order in which they are handled does not matter, - * a negative value if the first task should be processed before - * the second or a positive value if the second task should be - * processed first. - * @user_data: user data passed to @func. - * - * Sets the function used to sort the list of tasks. This allows the - * tasks to be processed by a priority determined by @func, and not - * just in the order in which they were added to the pool. - * - * Note, if the maximum number of threads is more than 1, the order - * that threads are executed can not be guranteed 100%. Threads are - * scheduled by the operating system and are executed at random. It - * cannot be assumed that threads are executed in the order they are - * created. - * - * Since: 2.10 - **/ -void -g_thread_pool_set_sort_function (GThreadPool *pool, - GCompareDataFunc func, - gpointer user_data) -{ - GRealThreadPool *real; - - real = (GRealThreadPool*) pool; - - g_return_if_fail (real); - g_return_if_fail (real->running); - - g_async_queue_lock (real->queue); - - real->sort_func = func; - real->sort_user_data = user_data; - - if (func) - g_async_queue_sort_unlocked (real->queue, - real->sort_func, - real->sort_user_data); - - g_async_queue_unlock (real->queue); -} - -/** - * g_thread_pool_set_max_idle_time: - * @interval: the maximum @interval (1/1000ths of a second) a thread - * can be idle. - * - * This function will set the maximum @interval that a thread waiting - * in the pool for new tasks can be idle for before being - * stopped. This function is similar to calling - * g_thread_pool_stop_unused_threads() on a regular timeout, except, - * this is done on a per thread basis. - * - * By setting @interval to 0, idle threads will not be stopped. - * - * This function makes use of g_async_queue_timed_pop () using - * @interval. - * - * Since: 2.10 - **/ -void -g_thread_pool_set_max_idle_time (guint interval) -{ - guint i; - - g_atomic_int_set (&max_idle_time, interval); - - i = g_atomic_int_get (&unused_threads); - if (i > 0) - { - g_atomic_int_inc (&wakeup_thread_serial); - g_async_queue_lock (unused_thread_queue); - - do - { - g_async_queue_push_unlocked (unused_thread_queue, - wakeup_thread_marker); - } - while (--i); - - g_async_queue_unlock (unused_thread_queue); - } -} - -/** - * g_thread_pool_get_max_idle_time: - * - * This function will return the maximum @interval that a thread will - * wait in the thread pool for new tasks before being stopped. - * - * If this function returns 0, threads waiting in the thread pool for - * new work are not stopped. - * - * Return value: the maximum @interval to wait for new tasks in the - * thread pool before stopping the thread (1/1000ths of a second). - * - * Since: 2.10 - **/ -guint -g_thread_pool_get_max_idle_time (void) -{ - return g_atomic_int_get (&max_idle_time); -} - -#define __G_THREADPOOL_C__ -#include "galiasdef.c" diff --git a/glib/gtree.c b/glib/gtree.c deleted file mode 100644 index 8ae5e9812..000000000 --- a/glib/gtree.c +++ /dev/null @@ -1,1290 +0,0 @@ -/* 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, 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" - -#include "glib.h" -#include "galias.h" - -#undef G_TREE_DEBUG - -#define MAX_GTREE_HEIGHT 40 - -typedef struct _GTreeNode GTreeNode; - -struct _GTree -{ - GTreeNode *root; - GCompareDataFunc key_compare; - GDestroyNotify key_destroy_func; - GDestroyNotify value_destroy_func; - gpointer key_compare_data; - guint nnodes; -}; - -struct _GTreeNode -{ - gpointer key; /* key for this node */ - gpointer value; /* value stored at this node */ - GTreeNode *left; /* left subtree */ - GTreeNode *right; /* right subtree */ - gint8 balance; /* height (left) - height (right) */ - guint8 left_child; - guint8 right_child; -}; - - -static GTreeNode* g_tree_node_new (gpointer key, - gpointer value); -static void g_tree_insert_internal (GTree *tree, - gpointer key, - gpointer value, - gboolean replace); -static gboolean g_tree_remove_internal (GTree *tree, - gconstpointer key, - gboolean steal); -static GTreeNode* g_tree_node_balance (GTreeNode *node); -static GTreeNode *g_tree_find_node (GTree *tree, - gconstpointer key); -static gint g_tree_node_pre_order (GTreeNode *node, - GTraverseFunc traverse_func, - gpointer data); -static gint g_tree_node_in_order (GTreeNode *node, - GTraverseFunc traverse_func, - gpointer data); -static gint g_tree_node_post_order (GTreeNode *node, - GTraverseFunc traverse_func, - gpointer data); -static gpointer g_tree_node_search (GTreeNode *node, - GCompareFunc search_func, - gconstpointer data); -static GTreeNode* g_tree_node_rotate_left (GTreeNode *node); -static GTreeNode* g_tree_node_rotate_right (GTreeNode *node); -#ifdef G_TREE_DEBUG -static void g_tree_node_check (GTreeNode *node); -#endif - - -static GTreeNode* -g_tree_node_new (gpointer key, - gpointer value) -{ - GTreeNode *node = g_slice_new (GTreeNode); - - node->balance = 0; - node->left = NULL; - node->right = NULL; - node->left_child = FALSE; - node->right_child = FALSE; - node->key = key; - node->value = value; - - return node; -} - -/** - * g_tree_new: - * @key_compare_func: the function used to order the nodes in the #GTree. - * It should return values similar to the standard strcmp() function - - * 0 if the two arguments are equal, a negative value if the first argument - * comes before the second, or a positive value if the first argument comes - * after the second. - * - * Creates a new #GTree. - * - * Return value: a new #GTree. - **/ -GTree* -g_tree_new (GCompareFunc key_compare_func) -{ - g_return_val_if_fail (key_compare_func != NULL, NULL); - - return g_tree_new_full ((GCompareDataFunc) key_compare_func, NULL, - NULL, NULL); -} - -/** - * g_tree_new_with_data: - * @key_compare_func: qsort()-style comparison function. - * @key_compare_data: data to pass to comparison function. - * - * Creates a new #GTree with a comparison function that accepts user data. - * See g_tree_new() for more details. - * - * Return value: a new #GTree. - **/ -GTree* -g_tree_new_with_data (GCompareDataFunc key_compare_func, - gpointer key_compare_data) -{ - g_return_val_if_fail (key_compare_func != NULL, NULL); - - return g_tree_new_full (key_compare_func, key_compare_data, - NULL, NULL); -} - -/** - * g_tree_new_full: - * @key_compare_func: qsort()-style comparison function. - * @key_compare_data: data to pass to comparison function. - * @key_destroy_func: a function to free the memory allocated for the key - * used when removing the entry from the #GTree or %NULL if you don't - * want to supply such a function. - * @value_destroy_func: a function to free the memory allocated for the - * value used when removing the entry from the #GTree or %NULL if you - * don't want to supply such a function. - * - * Creates a new #GTree like g_tree_new() and allows to specify functions - * to free the memory allocated for the key and value that get called when - * removing the entry from the #GTree. - * - * Return value: a new #GTree. - **/ -GTree* -g_tree_new_full (GCompareDataFunc key_compare_func, - gpointer key_compare_data, - GDestroyNotify key_destroy_func, - GDestroyNotify value_destroy_func) -{ - GTree *tree; - - g_return_val_if_fail (key_compare_func != NULL, NULL); - - tree = g_new (GTree, 1); - tree->root = NULL; - tree->key_compare = key_compare_func; - tree->key_destroy_func = key_destroy_func; - tree->value_destroy_func = value_destroy_func; - tree->key_compare_data = key_compare_data; - tree->nnodes = 0; - - return tree; -} - -static inline GTreeNode * -g_tree_first_node (GTree *tree) -{ - GTreeNode *tmp; - - if (!tree->root) - return NULL; - - tmp = tree->root; - - while (tmp->left_child) - tmp = tmp->left; - - return tmp; -} - -static inline GTreeNode * -g_tree_node_previous (GTreeNode *node) -{ - GTreeNode *tmp; - - tmp = node->left; - - if (node->left_child) - while (tmp->right_child) - tmp = tmp->right; - - return tmp; -} - -static inline GTreeNode * -g_tree_node_next (GTreeNode *node) -{ - GTreeNode *tmp; - - tmp = node->right; - - if (node->right_child) - while (tmp->left_child) - tmp = tmp->left; - - return tmp; -} - -/** - * g_tree_destroy: - * @tree: a #GTree. - * - * Destroys the #GTree. If keys and/or values are dynamically allocated, you - * should either free them first or create the #GTree using g_tree_new_full(). - * In the latter case the destroy functions you supplied will be called on - * all keys and values before destroying the #GTree. - **/ -void -g_tree_destroy (GTree *tree) -{ - GTreeNode *node; - GTreeNode *next; - - g_return_if_fail (tree != NULL); - - node = g_tree_first_node (tree); - - while (node) - { - next = g_tree_node_next (node); - - if (tree->key_destroy_func) - tree->key_destroy_func (node->key); - if (tree->value_destroy_func) - tree->value_destroy_func (node->value); - g_slice_free (GTreeNode, node); - - node = next; - } - - g_free (tree); -} - -/** - * g_tree_insert: - * @tree: a #GTree. - * @key: the key to insert. - * @value: the value corresponding to the key. - * - * Inserts a key/value pair into a #GTree. If the given key already exists - * in the #GTree its corresponding value is set to the new value. If you - * supplied a value_destroy_func when creating the #GTree, the old value is - * freed using that function. If you supplied a @key_destroy_func when - * creating the #GTree, the passed key is freed using that function. - * - * The tree is automatically 'balanced' as new key/value pairs are added, - * so that the distance from the root to every leaf is as small as possible. - **/ -void -g_tree_insert (GTree *tree, - gpointer key, - gpointer value) -{ - g_return_if_fail (tree != NULL); - - g_tree_insert_internal (tree, key, value, FALSE); - -#ifdef G_TREE_DEBUG - g_tree_node_check (tree->root); -#endif -} - -/** - * g_tree_replace: - * @tree: a #GTree. - * @key: the key to insert. - * @value: the value corresponding to the key. - * - * Inserts a new key and value into a #GTree similar to g_tree_insert(). - * The difference is that if the key already exists in the #GTree, it gets - * replaced by the new key. If you supplied a @value_destroy_func when - * creating the #GTree, the old value is freed using that function. If you - * supplied a @key_destroy_func when creating the #GTree, the old key is - * freed using that function. - * - * The tree is automatically 'balanced' as new key/value pairs are added, - * so that the distance from the root to every leaf is as small as possible. - **/ -void -g_tree_replace (GTree *tree, - gpointer key, - gpointer value) -{ - g_return_if_fail (tree != NULL); - - g_tree_insert_internal (tree, key, value, TRUE); - -#ifdef G_TREE_DEBUG - g_tree_node_check (tree->root); -#endif -} - -/* internal insert routine */ -static void -g_tree_insert_internal (GTree *tree, - gpointer key, - gpointer value, - gboolean replace) -{ - GTreeNode *node; - GTreeNode *path[MAX_GTREE_HEIGHT]; - int idx; - - g_return_if_fail (tree != NULL); - - if (!tree->root) - { - tree->root = g_tree_node_new (key, value); - tree->nnodes++; - return; - } - - idx = 0; - path[idx++] = NULL; - node = tree->root; - - while (1) - { - int cmp = tree->key_compare (key, node->key, tree->key_compare_data); - - if (cmp == 0) - { - if (tree->value_destroy_func) - tree->value_destroy_func (node->value); - - node->value = value; - - if (replace) - { - if (tree->key_destroy_func) - tree->key_destroy_func (node->key); - - node->key = key; - } - else - { - /* free the passed key */ - if (tree->key_destroy_func) - tree->key_destroy_func (key); - } - - return; - } - else if (cmp < 0) - { - if (node->left_child) - { - path[idx++] = node; - node = node->left; - } - else - { - GTreeNode *child = g_tree_node_new (key, value); - - child->left = node->left; - child->right = node; - node->left = child; - node->left_child = TRUE; - node->balance -= 1; - - tree->nnodes++; - - break; - } - } - else - { - if (node->right_child) - { - path[idx++] = node; - node = node->right; - } - else - { - GTreeNode *child = g_tree_node_new (key, value); - - child->right = node->right; - child->left = node; - node->right = child; - node->right_child = TRUE; - node->balance += 1; - - tree->nnodes++; - - break; - } - } - } - - /* restore balance. This is the goodness of a non-recursive - implementation, when we are done with balancing we 'break' - the loop and we are done. */ - while (1) - { - GTreeNode *bparent = path[--idx]; - gboolean left_node = (bparent && node == bparent->left); - g_assert (!bparent || bparent->left == node || bparent->right == node); - - if (node->balance < -1 || node->balance > 1) - { - node = g_tree_node_balance (node); - if (bparent == NULL) - tree->root = node; - else if (left_node) - bparent->left = node; - else - bparent->right = node; - } - - if (node->balance == 0 || bparent == NULL) - break; - - if (left_node) - bparent->balance -= 1; - else - bparent->balance += 1; - - node = bparent; - } -} - -/** - * g_tree_remove: - * @tree: a #GTree. - * @key: the key to remove. - * - * Removes a key/value pair from a #GTree. - * - * If the #GTree was created using g_tree_new_full(), the key and value - * are freed using the supplied destroy functions, otherwise you have to - * make sure that any dynamically allocated values are freed yourself. - * If the key does not exist in the #GTree, the function does nothing. - * - * Returns: %TRUE if the key was found (prior to 2.8, this function returned - * nothing) - **/ -gboolean -g_tree_remove (GTree *tree, - gconstpointer key) -{ - gboolean removed; - - g_return_val_if_fail (tree != NULL, FALSE); - - removed = g_tree_remove_internal (tree, key, FALSE); - -#ifdef G_TREE_DEBUG - g_tree_node_check (tree->root); -#endif - - return removed; -} - -/** - * g_tree_steal: - * @tree: a #GTree. - * @key: the key to remove. - * - * Removes a key and its associated value from a #GTree without calling - * the key and value destroy functions. - * - * If the key does not exist in the #GTree, the function does nothing. - * - * Returns: %TRUE if the key was found (prior to 2.8, this function returned - * nothing) - **/ -gboolean -g_tree_steal (GTree *tree, - gconstpointer key) -{ - gboolean removed; - - g_return_val_if_fail (tree != NULL, FALSE); - - removed = g_tree_remove_internal (tree, key, TRUE); - -#ifdef G_TREE_DEBUG - g_tree_node_check (tree->root); -#endif - - return removed; -} - -/* internal remove routine */ -static gboolean -g_tree_remove_internal (GTree *tree, - gconstpointer key, - gboolean steal) -{ - GTreeNode *node, *parent, *balance; - GTreeNode *path[MAX_GTREE_HEIGHT]; - int idx; - gboolean left_node; - - g_return_val_if_fail (tree != NULL, FALSE); - - if (!tree->root) - return FALSE; - - idx = 0; - path[idx++] = NULL; - node = tree->root; - - while (1) - { - int cmp = tree->key_compare (key, node->key, tree->key_compare_data); - - if (cmp == 0) - break; - else if (cmp < 0) - { - if (!node->left_child) - return FALSE; - - path[idx++] = node; - node = node->left; - } - else - { - if (!node->right_child) - return FALSE; - - path[idx++] = node; - node = node->right; - } - } - - /* the following code is almost equal to g_tree_remove_node, - except that we do not have to call g_tree_node_parent. */ - balance = parent = path[--idx]; - g_assert (!parent || parent->left == node || parent->right == node); - left_node = (parent && node == parent->left); - - if (!node->left_child) - { - if (!node->right_child) - { - if (!parent) - tree->root = NULL; - else if (left_node) - { - parent->left_child = FALSE; - parent->left = node->left; - parent->balance += 1; - } - else - { - parent->right_child = FALSE; - parent->right = node->right; - parent->balance -= 1; - } - } - else /* node has a right child */ - { - GTreeNode *tmp = g_tree_node_next (node); - tmp->left = node->left; - - if (!parent) - tree->root = node->right; - else if (left_node) - { - parent->left = node->right; - parent->balance += 1; - } - else - { - parent->right = node->right; - parent->balance -= 1; - } - } - } - else /* node has a left child */ - { - if (!node->right_child) - { - GTreeNode *tmp = g_tree_node_previous (node); - tmp->right = node->right; - - if (parent == NULL) - tree->root = node->left; - else if (left_node) - { - parent->left = node->left; - parent->balance += 1; - } - else - { - parent->right = node->left; - parent->balance -= 1; - } - } - else /* node has a both children (pant, pant!) */ - { - GTreeNode *prev = node->left; - GTreeNode *next = node->right; - GTreeNode *nextp = node; - int old_idx = idx + 1; - idx++; - - /* path[idx] == parent */ - /* find the immediately next node (and its parent) */ - while (next->left_child) - { - path[++idx] = nextp = next; - next = next->left; - } - - path[old_idx] = next; - balance = path[idx]; - - /* remove 'next' from the tree */ - if (nextp != node) - { - if (next->right_child) - nextp->left = next->right; - else - nextp->left_child = FALSE; - nextp->balance += 1; - - next->right_child = TRUE; - next->right = node->right; - } - else - node->balance -= 1; - - /* set the prev to point to the right place */ - while (prev->right_child) - prev = prev->right; - prev->right = next; - - /* prepare 'next' to replace 'node' */ - next->left_child = TRUE; - next->left = node->left; - next->balance = node->balance; - - if (!parent) - tree->root = next; - else if (left_node) - parent->left = next; - else - parent->right = next; - } - } - - /* restore balance */ - if (balance) - while (1) - { - GTreeNode *bparent = path[--idx]; - g_assert (!bparent || bparent->left == balance || bparent->right == balance); - left_node = (bparent && balance == bparent->left); - - if(balance->balance < -1 || balance->balance > 1) - { - balance = g_tree_node_balance (balance); - if (!bparent) - tree->root = balance; - else if (left_node) - bparent->left = balance; - else - bparent->right = balance; - } - - if (balance->balance != 0 || !bparent) - break; - - if (left_node) - bparent->balance += 1; - else - bparent->balance -= 1; - - balance = bparent; - } - - if (!steal) - { - if (tree->key_destroy_func) - tree->key_destroy_func (node->key); - if (tree->value_destroy_func) - tree->value_destroy_func (node->value); - } - - g_slice_free (GTreeNode, node); - - tree->nnodes--; - - return TRUE; -} - -/** - * g_tree_lookup: - * @tree: a #GTree. - * @key: the key to look up. - * - * Gets the value corresponding to the given key. Since a #GTree is - * automatically balanced as key/value pairs are added, key lookup is very - * fast. - * - * Return value: the value corresponding to the key, or %NULL if the key was - * not found. - **/ -gpointer -g_tree_lookup (GTree *tree, - gconstpointer key) -{ - GTreeNode *node; - - g_return_val_if_fail (tree != NULL, NULL); - - node = g_tree_find_node (tree, key); - - return node ? node->value : NULL; -} - -/** - * g_tree_lookup_extended: - * @tree: a #GTree. - * @lookup_key: the key to look up. - * @orig_key: returns the original key. - * @value: returns the value associated with the key. - * - * Looks up a key in the #GTree, returning the original key and the - * associated value and a #gboolean which is %TRUE if the key was found. This - * is useful if you need to free the memory allocated for the original key, - * for example before calling g_tree_remove(). - * - * Return value: %TRUE if the key was found in the #GTree. - **/ -gboolean -g_tree_lookup_extended (GTree *tree, - gconstpointer lookup_key, - gpointer *orig_key, - gpointer *value) -{ - GTreeNode *node; - - g_return_val_if_fail (tree != NULL, FALSE); - - node = g_tree_find_node (tree, lookup_key); - - if (node) - { - if (orig_key) - *orig_key = node->key; - if (value) - *value = node->value; - return TRUE; - } - else - return FALSE; -} - -/** - * g_tree_foreach: - * @tree: a #GTree. - * @func: the function to call for each node visited. If this function - * returns %TRUE, the traversal is stopped. - * @user_data: user data to pass to the function. - * - * Calls the given function for each of the key/value pairs in the #GTree. - * The function is passed the key and value of each pair, and the given - * @data parameter. The tree is traversed in sorted order. - * - * The tree may not be modified while iterating over it (you can't - * add/remove items). To remove all items matching a predicate, you need - * to add each item to a list in your #GTraverseFunc as you walk over - * the tree, then walk the list and remove each item. - **/ -void -g_tree_foreach (GTree *tree, - GTraverseFunc func, - gpointer user_data) -{ - GTreeNode *node; - - g_return_if_fail (tree != NULL); - - if (!tree->root) - return; - - node = g_tree_first_node (tree); - - while (node) - { - if ((*func) (node->key, node->value, user_data)) - break; - - node = g_tree_node_next (node); - } -} - -/** - * g_tree_traverse: - * @tree: a #GTree. - * @traverse_func: the function to call for each node visited. If this - * function returns %TRUE, the traversal is stopped. - * @traverse_type: the order in which nodes are visited, one of %G_IN_ORDER, - * %G_PRE_ORDER and %G_POST_ORDER. - * @user_data: user data to pass to the function. - * - * Calls the given function for each node in the #GTree. - * - * Deprecated:2.2: The order of a balanced tree is somewhat arbitrary. If you - * just want to visit all nodes in sorted order, use g_tree_foreach() - * instead. If you really need to visit nodes in a different order, consider - * using an <link linkend="glib-N-ary-Trees">N-ary Tree</link>. - **/ -void -g_tree_traverse (GTree *tree, - GTraverseFunc traverse_func, - GTraverseType traverse_type, - gpointer user_data) -{ - g_return_if_fail (tree != NULL); - - if (!tree->root) - return; - - switch (traverse_type) - { - case G_PRE_ORDER: - g_tree_node_pre_order (tree->root, traverse_func, user_data); - break; - - case G_IN_ORDER: - g_tree_node_in_order (tree->root, traverse_func, user_data); - break; - - case G_POST_ORDER: - g_tree_node_post_order (tree->root, traverse_func, user_data); - break; - - case G_LEVEL_ORDER: - g_warning ("g_tree_traverse(): traverse type G_LEVEL_ORDER isn't implemented."); - break; - } -} - -/** - * g_tree_search: - * @tree: a #GTree. - * @search_func: a function used to search the #GTree. - * @user_data: the data passed as the second argument to the @search_func - * function. - * - * Searches a #GTree using @search_func. - * - * The @search_func is called with a pointer to the key of a key/value pair in - * the tree, and the passed in @user_data. If @search_func returns 0 for a - * key/value pair, then g_tree_search_func() will return the value of that - * pair. If @search_func returns -1, searching will proceed among the - * key/value pairs that have a smaller key; if @search_func returns 1, - * searching will proceed among the key/value pairs that have a larger key. - * - * Return value: the value corresponding to the found key, or %NULL if the key - * was not found. - **/ -gpointer -g_tree_search (GTree *tree, - GCompareFunc search_func, - gconstpointer user_data) -{ - g_return_val_if_fail (tree != NULL, NULL); - - if (tree->root) - return g_tree_node_search (tree->root, search_func, user_data); - else - return NULL; -} - -/** - * g_tree_height: - * @tree: a #GTree. - * - * Gets the height of a #GTree. - * - * If the #GTree contains no nodes, the height is 0. - * If the #GTree contains only one root node the height is 1. - * If the root node has children the height is 2, etc. - * - * Return value: the height of the #GTree. - **/ -gint -g_tree_height (GTree *tree) -{ - GTreeNode *node; - gint height; - - g_return_val_if_fail (tree != NULL, 0); - - if (!tree->root) - return 0; - - height = 0; - node = tree->root; - - while (1) - { - height += 1 + MAX(node->balance, 0); - - if (!node->left_child) - return height; - - node = node->left; - } -} - -/** - * g_tree_nnodes: - * @tree: a #GTree. - * - * Gets the number of nodes in a #GTree. - * - * Return value: the number of nodes in the #GTree. - **/ -gint -g_tree_nnodes (GTree *tree) -{ - g_return_val_if_fail (tree != NULL, 0); - - return tree->nnodes; -} - -static GTreeNode* -g_tree_node_balance (GTreeNode *node) -{ - if (node->balance < -1) - { - if (node->left->balance > 0) - node->left = g_tree_node_rotate_left (node->left); - node = g_tree_node_rotate_right (node); - } - else if (node->balance > 1) - { - if (node->right->balance < 0) - node->right = g_tree_node_rotate_right (node->right); - node = g_tree_node_rotate_left (node); - } - - return node; -} - -static GTreeNode * -g_tree_find_node (GTree *tree, - gconstpointer key) -{ - GTreeNode *node; - gint cmp; - - node = tree->root; - if (!node) - return NULL; - - while (1) - { - cmp = tree->key_compare (key, node->key, tree->key_compare_data); - if (cmp == 0) - return node; - else if (cmp < 0) - { - if (!node->left_child) - return NULL; - - node = node->left; - } - else - { - if (!node->right_child) - return NULL; - - node = node->right; - } - } -} - -static gint -g_tree_node_pre_order (GTreeNode *node, - GTraverseFunc traverse_func, - gpointer data) -{ - if ((*traverse_func) (node->key, node->value, data)) - return TRUE; - - if (node->left_child) - { - if (g_tree_node_pre_order (node->left, traverse_func, data)) - return TRUE; - } - - if (node->right_child) - { - if (g_tree_node_pre_order (node->right, traverse_func, data)) - return TRUE; - } - - return FALSE; -} - -static gint -g_tree_node_in_order (GTreeNode *node, - GTraverseFunc traverse_func, - gpointer data) -{ - if (node->left_child) - { - if (g_tree_node_in_order (node->left, traverse_func, data)) - return TRUE; - } - - if ((*traverse_func) (node->key, node->value, data)) - return TRUE; - - if (node->right_child) - { - if (g_tree_node_in_order (node->right, traverse_func, data)) - return TRUE; - } - - return FALSE; -} - -static gint -g_tree_node_post_order (GTreeNode *node, - GTraverseFunc traverse_func, - gpointer data) -{ - if (node->left_child) - { - if (g_tree_node_post_order (node->left, traverse_func, data)) - return TRUE; - } - - if (node->right_child) - { - if (g_tree_node_post_order (node->right, traverse_func, data)) - return TRUE; - } - - if ((*traverse_func) (node->key, node->value, data)) - return TRUE; - - return FALSE; -} - -static gpointer -g_tree_node_search (GTreeNode *node, - GCompareFunc search_func, - gconstpointer data) -{ - gint dir; - - if (!node) - return NULL; - - while (1) - { - dir = (* search_func) (node->key, data); - if (dir == 0) - return node->value; - else if (dir < 0) - { - if (!node->left_child) - return NULL; - - node = node->left; - } - else - { - if (!node->right_child) - return NULL; - - node = node->right; - } - } -} - -static GTreeNode* -g_tree_node_rotate_left (GTreeNode *node) -{ - GTreeNode *right; - gint a_bal; - gint b_bal; - - right = node->right; - - if (right->left_child) - node->right = right->left; - else - { - node->right_child = FALSE; - node->right = right; - right->left_child = TRUE; - } - right->left = node; - - a_bal = node->balance; - b_bal = right->balance; - - if (b_bal <= 0) - { - if (a_bal >= 1) - right->balance = b_bal - 1; - else - right->balance = a_bal + b_bal - 2; - node->balance = a_bal - 1; - } - else - { - if (a_bal <= b_bal) - right->balance = a_bal - 2; - else - right->balance = b_bal - 1; - node->balance = a_bal - b_bal - 1; - } - - return right; -} - -static GTreeNode* -g_tree_node_rotate_right (GTreeNode *node) -{ - GTreeNode *left; - gint a_bal; - gint b_bal; - - left = node->left; - - if (left->right_child) - node->left = left->right; - else - { - node->left_child = FALSE; - node->left = left; - left->right_child = TRUE; - } - left->right = node; - - a_bal = node->balance; - b_bal = left->balance; - - if (b_bal <= 0) - { - if (b_bal > a_bal) - left->balance = b_bal + 1; - else - left->balance = a_bal + 2; - node->balance = a_bal - b_bal + 1; - } - else - { - if (a_bal <= -1) - left->balance = b_bal + 1; - else - left->balance = a_bal + b_bal + 2; - node->balance = a_bal + 1; - } - - return left; -} - -#ifdef G_TREE_DEBUG -static gint -g_tree_node_height (GTreeNode *node) -{ - gint left_height; - gint right_height; - - if (node) - { - left_height = 0; - right_height = 0; - - if (node->left_child) - left_height = g_tree_node_height (node->left); - - if (node->right_child) - right_height = g_tree_node_height (node->right); - - return MAX (left_height, right_height) + 1; - } - - return 0; -} - -static void -g_tree_node_check (GTreeNode *node) -{ - gint left_height; - gint right_height; - gint balance; - GTreeNode *tmp; - - if (node) - { - if (node->left_child) - { - tmp = g_tree_node_previous (node); - g_assert (tmp->right == node); - } - - if (node->right_child) - { - tmp = g_tree_node_next (node); - g_assert (tmp->left == node); - } - - left_height = 0; - right_height = 0; - - if (node->left_child) - left_height = g_tree_node_height (node->left); - if (node->right_child) - right_height = g_tree_node_height (node->right); - - balance = right_height - left_height; - g_assert (balance == node->balance); - - if (node->left_child) - g_tree_node_check (node->left); - if (node->right_child) - g_tree_node_check (node->right); - } -} - -static void -g_tree_node_dump (GTreeNode *node, - gint indent) -{ - g_print ("%*s%c\n", indent, "", *(char *)node->key); - - if (node->left_child) - g_tree_node_dump (node->left, indent + 2); - else if (node->left) - g_print ("%*s<%c\n", indent + 2, "", *(char *)node->left->key); - - if (node->right_child) - g_tree_node_dump (node->right, indent + 2); - else if (node->right) - g_print ("%*s>%c\n", indent + 2, "", *(char *)node->right->key); -} - - -void -g_tree_dump (GTree *tree) -{ - if (tree->root) - g_tree_node_dump (tree->root, 0); -} -#endif - - -#define __G_TREE_C__ -#include "galiasdef.c" - diff --git a/glib/gunibreak.c b/glib/gunibreak.c deleted file mode 100644 index 9c129218c..000000000 --- a/glib/gunibreak.c +++ /dev/null @@ -1,66 +0,0 @@ -/* gunibreak.c - line break properties - * - * Copyright 2000 Red Hat, Inc. - * - * The Gnome 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 of the - * License, or (at your option) any later version. - * - * The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, - * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "config.h" - -#include <stdlib.h> - -#include "glib.h" -#include "gunibreak.h" -#include "galias.h" - -#define TPROP_PART1(Page, Char) \ - ((break_property_table_part1[Page] >= G_UNICODE_MAX_TABLE_INDEX) \ - ? (break_property_table_part1[Page] - G_UNICODE_MAX_TABLE_INDEX) \ - : (break_property_data[break_property_table_part1[Page]][Char])) - -#define TPROP_PART2(Page, Char) \ - ((break_property_table_part2[Page] >= G_UNICODE_MAX_TABLE_INDEX) \ - ? (break_property_table_part2[Page] - G_UNICODE_MAX_TABLE_INDEX) \ - : (break_property_data[break_property_table_part2[Page]][Char])) - -#define PROP(Char) \ - (((Char) <= G_UNICODE_LAST_CHAR_PART1) \ - ? TPROP_PART1 ((Char) >> 8, (Char) & 0xff) \ - : (((Char) >= 0xe0000 && (Char) <= G_UNICODE_LAST_CHAR) \ - ? TPROP_PART2 (((Char) - 0xe0000) >> 8, (Char) & 0xff) \ - : G_UNICODE_BREAK_UNKNOWN)) - -/** - * g_unichar_break_type: - * @c: a Unicode character - * - * Determines the break type of @c. @c should be a Unicode character - * (to derive a character from UTF-8 encoded text, use - * g_utf8_get_char()). The break type is used to find word and line - * breaks ("text boundaries"), Pango implements the Unicode boundary - * resolution algorithms and normally you would use a function such - * as pango_break() instead of caring about break types yourself. - * - * Return value: the break type of @c - **/ -GUnicodeBreakType -g_unichar_break_type (gunichar c) -{ - return PROP (c); -} - -#define __G_UNIBREAK_C__ -#include "galiasdef.c" diff --git a/glib/gunicollate.c b/glib/gunicollate.c deleted file mode 100644 index 2bf579eca..000000000 --- a/glib/gunicollate.c +++ /dev/null @@ -1,679 +0,0 @@ -/* gunicollate.c - Collation - * - * Copyright 2001,2005 Red Hat, Inc. - * - * The Gnome 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 of the - * License, or (at your option) any later version. - * - * The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, - * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "config.h" - -#include <locale.h> -#include <string.h> -#ifdef __STDC_ISO_10646__ -#include <wchar.h> -#endif - -#ifdef HAVE_CARBON -#include <CoreServices/CoreServices.h> -#endif - -#include "glib.h" -#include "gunicodeprivate.h" -#include "galias.h" - -#ifdef _MSC_VER -/* Workaround for bug in MSVCR80.DLL */ -static gsize -msc_strxfrm_wrapper (char *string1, - const char *string2, - gsize count) -{ - if (!string1 || count <= 0) - { - char tmp; - - return strxfrm (&tmp, string2, 1); - } - return strxfrm (string1, string2, count); -} -#define strxfrm msc_strxfrm_wrapper -#endif - -/** - * g_utf8_collate: - * @str1: a UTF-8 encoded string - * @str2: a UTF-8 encoded string - * - * Compares two strings for ordering using the linguistically - * correct rules for the <link linkend="setlocale">current locale</link>. - * When sorting a large number of strings, it will be significantly - * faster to obtain collation keys with g_utf8_collate_key() and - * compare the keys with strcmp() when sorting instead of sorting - * the original strings. - * - * Return value: < 0 if @str1 compares before @str2, - * 0 if they compare equal, > 0 if @str1 compares after @str2. - **/ -gint -g_utf8_collate (const gchar *str1, - const gchar *str2) -{ - gint result; - -#ifdef HAVE_CARBON - - UniChar *str1_utf16; - UniChar *str2_utf16; - glong len1; - glong len2; - SInt32 retval = 0; - - g_return_val_if_fail (str1 != NULL, 0); - g_return_val_if_fail (str2 != NULL, 0); - - str1_utf16 = g_utf8_to_utf16 (str1, -1, NULL, &len1, NULL); - str2_utf16 = g_utf8_to_utf16 (str2, -1, NULL, &len2, NULL); - - UCCompareTextDefault (kUCCollateStandardOptions, - str1_utf16, len1, str2_utf16, len2, - NULL, &retval); - result = retval; - - g_free (str2_utf16); - g_free (str1_utf16); - -#elif defined(__STDC_ISO_10646__) - - gunichar *str1_norm; - gunichar *str2_norm; - - g_return_val_if_fail (str1 != NULL, 0); - g_return_val_if_fail (str2 != NULL, 0); - - str1_norm = _g_utf8_normalize_wc (str1, -1, G_NORMALIZE_ALL_COMPOSE); - str2_norm = _g_utf8_normalize_wc (str2, -1, G_NORMALIZE_ALL_COMPOSE); - - result = wcscoll ((wchar_t *)str1_norm, (wchar_t *)str2_norm); - - g_free (str1_norm); - g_free (str2_norm); - -#else /* !__STDC_ISO_10646__ */ - - const gchar *charset; - gchar *str1_norm; - gchar *str2_norm; - - g_return_val_if_fail (str1 != NULL, 0); - g_return_val_if_fail (str2 != NULL, 0); - - str1_norm = g_utf8_normalize (str1, -1, G_NORMALIZE_ALL_COMPOSE); - str2_norm = g_utf8_normalize (str2, -1, G_NORMALIZE_ALL_COMPOSE); - - if (g_get_charset (&charset)) - { - result = strcoll (str1_norm, str2_norm); - } - else - { - gchar *str1_locale = g_convert (str1_norm, -1, charset, "UTF-8", NULL, NULL, NULL); - gchar *str2_locale = g_convert (str2_norm, -1, charset, "UTF-8", NULL, NULL, NULL); - - if (str1_locale && str2_locale) - result = strcoll (str1_locale, str2_locale); - else if (str1_locale) - result = -1; - else if (str2_locale) - result = 1; - else - result = strcmp (str1_norm, str2_norm); - - g_free (str1_locale); - g_free (str2_locale); - } - - g_free (str1_norm); - g_free (str2_norm); - -#endif /* __STDC_ISO_10646__ */ - - return result; -} - -#if defined(__STDC_ISO_10646__) || defined(HAVE_CARBON) -/* We need UTF-8 encoding of numbers to encode the weights if - * we are using wcsxfrm. However, we aren't encoding Unicode - * characters, so we can't simply use g_unichar_to_utf8. - * - * The following routine is taken (with modification) from GNU - * libc's strxfrm routine: - * - * Copyright (C) 1995-1999,2000,2001 Free Software Foundation, Inc. - * Written by Ulrich Drepper <drepper@cygnus.com>, 1995. - */ -static inline int -utf8_encode (char *buf, wchar_t val) -{ - int retval; - - if (val < 0x80) - { - if (buf) - *buf++ = (char) val; - retval = 1; - } - else - { - int step; - - for (step = 2; step < 6; ++step) - if ((val & (~(guint32)0 << (5 * step + 1))) == 0) - break; - retval = step; - - if (buf) - { - *buf = (unsigned char) (~0xff >> step); - --step; - do - { - buf[step] = 0x80 | (val & 0x3f); - val >>= 6; - } - while (--step > 0); - *buf |= val; - } - } - - return retval; -} -#endif /* __STDC_ISO_10646__ || HAVE_CARBON */ - -#ifdef HAVE_CARBON - -static gchar * -collate_key_to_string (UCCollationValue *key, - gsize key_len) -{ - gchar *result; - gsize result_len; - gsize i; - - /* Pretty smart algorithm here: ignore first eight bytes of the - * collation key. It doesn't produce results equivalent to - * UCCompareCollationKeys's, but the difference seems to be only - * that UCCompareCollationKeys in some cases produces 0 where our - * comparison gets -1 or 1. */ - - if (key_len * sizeof (UCCollationValue) <= 8) - return g_strdup (""); - - result_len = 0; - for (i = 8; i < key_len * sizeof (UCCollationValue); i++) - /* there may be nul bytes, encode byteval+1 */ - result_len += utf8_encode (NULL, *((guchar*)key + i) + 1); - - result = g_malloc (result_len + 1); - result_len = 0; - for (i = 8; i < key_len * sizeof (UCCollationValue); i++) - result_len += utf8_encode (result + result_len, *((guchar*)key + i) + 1); - - result[result_len] = 0; - return result; -} - -static gchar * -carbon_collate_key_with_collator (const gchar *str, - gssize len, - CollatorRef collator) -{ - UniChar *str_utf16 = NULL; - glong len_utf16; - OSStatus ret; - UCCollationValue staticbuf[512]; - UCCollationValue *freeme = NULL; - UCCollationValue *buf; - ItemCount buf_len; - ItemCount key_len; - ItemCount try_len; - gchar *result = NULL; - - str_utf16 = g_utf8_to_utf16 (str, len, NULL, &len_utf16, NULL); - try_len = len_utf16 * 5 + 2; - - if (try_len <= sizeof staticbuf) - { - buf = staticbuf; - buf_len = sizeof staticbuf; - } - else - { - freeme = g_new (UCCollationValue, try_len); - buf = freeme; - buf_len = try_len; - } - - ret = UCGetCollationKey (collator, str_utf16, len_utf16, - buf_len, &key_len, buf); - - if (ret == kCollateBufferTooSmall) - { - freeme = g_renew (UCCollationValue, freeme, try_len * 2); - buf = freeme; - buf_len = try_len * 2; - ret = UCGetCollationKey (collator, str_utf16, len_utf16, - buf_len, &key_len, buf); - } - - if (ret == 0) - result = collate_key_to_string (buf, key_len); - else - result = g_strdup (""); - - g_free (freeme); - g_free (str_utf16); - return result; -} - -static gchar * -carbon_collate_key (const gchar *str, - gssize len) -{ - static CollatorRef collator; - - if (G_UNLIKELY (!collator)) - { - UCCreateCollator (NULL, 0, kUCCollateStandardOptions, &collator); - - if (!collator) - { - static gboolean been_here; - if (!been_here) - g_warning ("%s: UCCreateCollator failed", G_STRLOC); - been_here = TRUE; - return g_strdup (""); - } - } - - return carbon_collate_key_with_collator (str, len, collator); -} - -static gchar * -carbon_collate_key_for_filename (const gchar *str, - gssize len) -{ - static CollatorRef collator; - - if (G_UNLIKELY (!collator)) - { - /* http://developer.apple.com/qa/qa2004/qa1159.html */ - UCCreateCollator (NULL, 0, - kUCCollateComposeInsensitiveMask - | kUCCollateWidthInsensitiveMask - | kUCCollateCaseInsensitiveMask - | kUCCollateDigitsOverrideMask - | kUCCollateDigitsAsNumberMask - | kUCCollatePunctuationSignificantMask, - &collator); - - if (!collator) - { - static gboolean been_here; - if (!been_here) - g_warning ("%s: UCCreateCollator failed", G_STRLOC); - been_here = TRUE; - return g_strdup (""); - } - } - - return carbon_collate_key_with_collator (str, len, collator); -} - -#endif /* HAVE_CARBON */ - -/** - * g_utf8_collate_key: - * @str: a UTF-8 encoded string. - * @len: length of @str, in bytes, or -1 if @str is nul-terminated. - * - * Converts a string into a collation key that can be compared - * with other collation keys produced by the same function using - * strcmp(). - * - * The results of comparing the collation keys of two strings - * with strcmp() will always be the same as comparing the two - * original keys with g_utf8_collate(). - * - * Note that this function depends on the - * <link linkend="setlocale">current locale</link>. - * - * Return value: a newly allocated string. This string should - * be freed with g_free() when you are done with it. - **/ -gchar * -g_utf8_collate_key (const gchar *str, - gssize len) -{ - gchar *result; - -#ifdef HAVE_CARBON - - g_return_val_if_fail (str != NULL, NULL); - result = carbon_collate_key (str, len); - -#elif defined(__STDC_ISO_10646__) - - gsize xfrm_len; - gunichar *str_norm; - wchar_t *result_wc; - gsize i; - gsize result_len = 0; - - g_return_val_if_fail (str != NULL, NULL); - - str_norm = _g_utf8_normalize_wc (str, len, G_NORMALIZE_ALL_COMPOSE); - - xfrm_len = wcsxfrm (NULL, (wchar_t *)str_norm, 0); - result_wc = g_new (wchar_t, xfrm_len + 1); - wcsxfrm (result_wc, (wchar_t *)str_norm, xfrm_len + 1); - - for (i=0; i < xfrm_len; i++) - result_len += utf8_encode (NULL, result_wc[i]); - - result = g_malloc (result_len + 1); - result_len = 0; - for (i=0; i < xfrm_len; i++) - result_len += utf8_encode (result + result_len, result_wc[i]); - - result[result_len] = '\0'; - - g_free (result_wc); - g_free (str_norm); - - return result; -#else /* !__STDC_ISO_10646__ */ - - gsize xfrm_len; - const gchar *charset; - gchar *str_norm; - - g_return_val_if_fail (str != NULL, NULL); - - str_norm = g_utf8_normalize (str, len, G_NORMALIZE_ALL_COMPOSE); - - result = NULL; - - if (g_get_charset (&charset)) - { - xfrm_len = strxfrm (NULL, str_norm, 0); - if (xfrm_len >= 0 && xfrm_len < G_MAXINT - 2) - { - result = g_malloc (xfrm_len + 1); - strxfrm (result, str_norm, xfrm_len + 1); - } - } - else - { - gchar *str_locale = g_convert (str_norm, -1, charset, "UTF-8", NULL, NULL, NULL); - - if (str_locale) - { - xfrm_len = strxfrm (NULL, str_locale, 0); - if (xfrm_len < 0 || xfrm_len >= G_MAXINT - 2) - { - g_free (str_locale); - str_locale = NULL; - } - } - if (str_locale) - { - result = g_malloc (xfrm_len + 2); - result[0] = 'A'; - strxfrm (result + 1, str_locale, xfrm_len + 1); - - g_free (str_locale); - } - } - - if (!result) - { - xfrm_len = strlen (str_norm); - result = g_malloc (xfrm_len + 2); - result[0] = 'B'; - memcpy (result + 1, str_norm, xfrm_len); - result[xfrm_len+1] = '\0'; - } - - g_free (str_norm); -#endif /* __STDC_ISO_10646__ */ - - return result; -} - -/* This is a collation key that is very very likely to sort before any - collation key that libc strxfrm generates. We use this before any - special case (dot or number) to make sure that its sorted before - anything else. - */ -#define COLLATION_SENTINEL "\1\1\1" - -/** - * g_utf8_collate_key_for_filename: - * @str: a UTF-8 encoded string. - * @len: length of @str, in bytes, or -1 if @str is nul-terminated. - * - * Converts a string into a collation key that can be compared - * with other collation keys produced by the same function using strcmp(). - * - * In order to sort filenames correctly, this function treats the dot '.' - * as a special case. Most dictionary orderings seem to consider it - * insignificant, thus producing the ordering "event.c" "eventgenerator.c" - * "event.h" instead of "event.c" "event.h" "eventgenerator.c". Also, we - * would like to treat numbers intelligently so that "file1" "file10" "file5" - * is sorted as "file1" "file5" "file10". - * - * Note that this function depends on the - * <link linkend="setlocale">current locale</link>. - * - * Return value: a newly allocated string. This string should - * be freed with g_free() when you are done with it. - * - * Since: 2.8 - */ -gchar* -g_utf8_collate_key_for_filename (const gchar *str, - gssize len) -{ -#ifndef HAVE_CARBON - GString *result; - GString *append; - const gchar *p; - const gchar *prev; - const gchar *end; - gchar *collate_key; - gint digits; - gint leading_zeros; - - /* - * How it works: - * - * Split the filename into collatable substrings which do - * not contain [.0-9] and special-cased substrings. The collatable - * substrings are run through the normal g_utf8_collate_key() and the - * resulting keys are concatenated with keys generated from the - * special-cased substrings. - * - * Special cases: Dots are handled by replacing them with '\1' which - * implies that short dot-delimited substrings are before long ones, - * e.g. - * - * a\1a (a.a) - * a-\1a (a-.a) - * aa\1a (aa.a) - * - * Numbers are handled by prepending to each number d-1 superdigits - * where d = number of digits in the number and SUPERDIGIT is a - * character with an integer value higher than any digit (for instance - * ':'). This ensures that single-digit numbers are sorted before - * double-digit numbers which in turn are sorted separately from - * triple-digit numbers, etc. To avoid strange side-effects when - * sorting strings that already contain SUPERDIGITs, a '\2' - * is also prepended, like this - * - * file\21 (file1) - * file\25 (file5) - * file\2:10 (file10) - * file\2:26 (file26) - * file\2::100 (file100) - * file:foo (file:foo) - * - * This has the side-effect of sorting numbers before everything else (except - * dots), but this is probably OK. - * - * Leading digits are ignored when doing the above. To discriminate - * numbers which differ only in the number of leading digits, we append - * the number of leading digits as a byte at the very end of the collation - * key. - * - * To try avoid conflict with any collation key sequence generated by libc we - * start each switch to a special cased part with a sentinel that hopefully - * will sort before anything libc will generate. - */ - - if (len < 0) - len = strlen (str); - - result = g_string_sized_new (len * 2); - append = g_string_sized_new (0); - - end = str + len; - - /* No need to use utf8 functions, since we're only looking for ascii chars */ - for (prev = p = str; p < end; p++) - { - switch (*p) - { - case '.': - if (prev != p) - { - collate_key = g_utf8_collate_key (prev, p - prev); - g_string_append (result, collate_key); - g_free (collate_key); - } - - g_string_append (result, COLLATION_SENTINEL "\1"); - - /* skip the dot */ - prev = p + 1; - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (prev != p) - { - collate_key = g_utf8_collate_key (prev, p - prev); - g_string_append (result, collate_key); - g_free (collate_key); - } - - g_string_append (result, COLLATION_SENTINEL "\2"); - - prev = p; - - /* write d-1 colons */ - if (*p == '0') - { - leading_zeros = 1; - digits = 0; - } - else - { - leading_zeros = 0; - digits = 1; - } - - while (++p < end) - { - if (*p == '0' && !digits) - ++leading_zeros; - else if (g_ascii_isdigit(*p)) - ++digits; - else - { - /* count an all-zero sequence as - * one digit plus leading zeros - */ - if (!digits) - { - ++digits; - --leading_zeros; - } - break; - } - } - - while (digits > 1) - { - g_string_append_c (result, ':'); - --digits; - } - - if (leading_zeros > 0) - { - g_string_append_c (append, (char)leading_zeros); - prev += leading_zeros; - } - - /* write the number itself */ - g_string_append_len (result, prev, p - prev); - - prev = p; - --p; /* go one step back to avoid disturbing outer loop */ - break; - - default: - /* other characters just accumulate */ - break; - } - } - - if (prev != p) - { - collate_key = g_utf8_collate_key (prev, p - prev); - g_string_append (result, collate_key); - g_free (collate_key); - } - - g_string_append (result, append->str); - g_string_free (append, TRUE); - - return g_string_free (result, FALSE); -#else /* HAVE_CARBON */ - return carbon_collate_key_for_filename (str, len); -#endif -} - - -#define __G_UNICOLLATE_C__ -#include "galiasdef.c" diff --git a/glib/gurifuncs.c b/glib/gurifuncs.c deleted file mode 100644 index 40f97498d..000000000 --- a/glib/gurifuncs.c +++ /dev/null @@ -1,245 +0,0 @@ -/* GIO - GLib Input, Output and Streaming Library - * - * Copyright (C) 2006-2007 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 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., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - * - * Author: Alexander Larsson <alexl@redhat.com> - */ - -#include "config.h" -#include "gurifuncs.h" -#include "string.h" - -#include "galias.h" - -/** - * SECTION:gurifuncs - * @short_description: URI Functions - * - * Functions for manipulating Universal Resource Identifiers (URIs) as - * defined by <ulink url="http://www.ietf.org/rfc/rfc3986.txt"> - * RFC 3986</ulink>. It is highly recommended that you have read and - * understand RFC 3986 for understanding this API. - */ - -static int -unescape_character (const char *scanner) -{ - int first_digit; - int second_digit; - - first_digit = g_ascii_xdigit_value (*scanner++); - if (first_digit < 0) - return -1; - - second_digit = g_ascii_xdigit_value (*scanner++); - if (second_digit < 0) - return -1; - - return (first_digit << 4) | second_digit; -} - -/** - * g_uri_unescape_segment: - * @escaped_string: a string. - * @escaped_string_end: a string. - * @illegal_characters: an optional string of illegal characters not to be allowed. - * - * Unescapes a segment of an escaped string. - * - * If any of the characters in @illegal_characters or the character zero appears - * as an escaped character in @escaped_string then that is an error and %NULL - * will be returned. This is useful it you want to avoid for instance having a - * slash being expanded in an escaped path element, which might confuse pathname - * handling. - * - * Returns: an unescaped version of @escaped_string or %NULL on error. - * The returned string should be freed when no longer needed. - * - * Since: 2.16 - **/ -char * -g_uri_unescape_segment (const char *escaped_string, - const char *escaped_string_end, - const char *illegal_characters) -{ - const char *in; - char *out, *result; - gint character; - - if (escaped_string == NULL) - return NULL; - - if (escaped_string_end == NULL) - escaped_string_end = escaped_string + strlen (escaped_string); - - result = g_malloc (escaped_string_end - escaped_string + 1); - - out = result; - for (in = escaped_string; in < escaped_string_end; in++) - { - character = *in; - - if (*in == '%') - { - in++; - - if (escaped_string_end - in < 2) - { - /* Invalid escaped char (to short) */ - g_free (result); - return NULL; - } - - character = unescape_character (in); - - /* Check for an illegal character. We consider '\0' illegal here. */ - if (character <= 0 || - (illegal_characters != NULL && - strchr (illegal_characters, (char)character) != NULL)) - { - g_free (result); - return NULL; - } - - in++; /* The other char will be eaten in the loop header */ - } - *out++ = (char)character; - } - - *out = '\0'; - - return result; -} - -/** - * g_uri_unescape_string: - * @escaped_string: an escaped string to be unescaped. - * @illegal_characters: an optional string of illegal characters not to be allowed. - * - * Unescapes a whole escaped string. - * - * If any of the characters in @illegal_characters or the character zero appears - * as an escaped character in @escaped_string then that is an error and %NULL - * will be returned. This is useful it you want to avoid for instance having a - * slash being expanded in an escaped path element, which might confuse pathname - * handling. - * - * Returns: an unescaped version of @escaped_string. The returned string - * should be freed when no longer needed. - * - * Since: 2.16 - **/ -char * -g_uri_unescape_string (const char *escaped_string, - const char *illegal_characters) -{ - return g_uri_unescape_segment (escaped_string, NULL, illegal_characters); -} - -/** - * g_uri_parse_scheme: - * @uri: a valid URI. - * - * Gets the scheme portion of a URI string. RFC 3986 decodes the scheme as: - * <programlisting> - * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] - * </programlisting> - * Common schemes include "file", "http", "svn+ssh", etc. - * - * Returns: The "Scheme" component of the URI, or %NULL on error. - * The returned string should be freed when no longer needed. - * - * Since: 2.16 - **/ -char * -g_uri_parse_scheme (const char *uri) -{ - const char *p; - char c; - - g_return_val_if_fail (uri != NULL, NULL); - - /* From RFC 3986 Decodes: - * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] - */ - - p = uri; - - /* Decode scheme: - scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) - */ - - if (!g_ascii_isalpha (*p)) - return NULL; - - while (1) - { - c = *p++; - - if (c == ':') - break; - - if (!(g_ascii_isalnum(c) || - c == '+' || - c == '-' || - c == '.')) - return NULL; - } - - return g_strndup (uri, p - uri - 1); -} - -/** - * g_uri_escape_string: - * @unescaped: the unescaped input string. - * @reserved_chars_allowed: a string of reserved characters that are - * allowed to be used. - * @allow_utf8: %TRUE if the result can include UTF-8 characters. - * - * Escapes a string for use in a URI. - * - * Normally all characters that are not "unreserved" (i.e. ASCII alphanumerical - * characters plus dash, dot, underscore and tilde) are escaped. - * But if you specify characters in @reserved_chars_allowed they are not - * escaped. This is useful for the "reserved" characters in the URI - * specification, since those are allowed unescaped in some portions of - * a URI. - * - * Returns: an escaped version of @unescaped. The returned string should be - * freed when no longer needed. - * - * Since: 2.16 - **/ -char * -g_uri_escape_string (const char *unescaped, - const char *reserved_chars_allowed, - gboolean allow_utf8) -{ - GString *s; - - g_return_val_if_fail (unescaped != NULL, NULL); - - s = g_string_sized_new (strlen (unescaped) + 10); - - g_string_append_uri_escaped (s, unescaped, reserved_chars_allowed, allow_utf8); - - return g_string_free (s, FALSE); -} - -#define __G_URI_FUNCS_C__ -#include "galiasdef.c" diff --git a/glib/gutf8.c b/glib/gutf8.c index da4a769cc..9f98cc172 100644 --- a/glib/gutf8.c +++ b/glib/gutf8.c @@ -22,9 +22,11 @@ #include "config.h" #include <stdlib.h> +#ifdef ANDROID_STUB #ifdef HAVE_CODESET #include <langinfo.h> #endif +#endif #include <string.h> #include "glib.h" @@ -36,7 +38,9 @@ #undef STRICT #endif +#ifdef ANDROID_STUB #include "libcharset/libcharset.h" +#endif #include "glibintl.h" #include "galias.h" @@ -443,6 +447,7 @@ get_alias_hash (void) /* As an abuse of the alias table, the following routines gets * the charsets that are aliases for the canonical name. */ +#ifdef ANDROID_STUB G_GNUC_INTERNAL const char ** _g_charset_get_aliases (const char *canonical_name) { @@ -450,6 +455,7 @@ _g_charset_get_aliases (const char *canonical_name) return g_hash_table_lookup (alias_hash, canonical_name); } +#endif static gboolean g_utf8_get_charset_internal (const char *raw_data, @@ -471,9 +477,11 @@ g_utf8_get_charset_internal (const char *raw_data, * a lock, but has a memory leak and a missing memory * barrier, so we lock for it */ +#ifdef ANDROID_STUB G_LOCK (aliases); charset = _g_locale_charset_unalias (raw_data); G_UNLOCK (aliases); +#endif if (charset && *charset) { @@ -545,6 +553,7 @@ g_get_charset (G_CONST_RETURN char **charset) g_static_private_set (&cache_private, cache, charset_cache_free); } +#ifdef ANDROID_STUB raw = _g_locale_charset_raw (); if (!(cache->raw && strcmp (cache->raw, raw) == 0)) @@ -557,7 +566,7 @@ g_get_charset (G_CONST_RETURN char **charset) cache->is_utf8 = g_utf8_get_charset_internal (raw, &new_charset); cache->charset = g_strdup (new_charset); } - +#endif if (charset) *charset = cache->charset; diff --git a/glib/gutils.c b/glib/gutils.c index 858603b8d..8228babae 100644 --- a/glib/gutils.c +++ b/glib/gutils.c @@ -116,9 +116,11 @@ #include <CoreServices/CoreServices.h> #endif +#ifdef ANDROID_STUB #ifdef HAVE_CODESET #include <langinfo.h> #endif +#endif const guint glib_major_version = GLIB_MAJOR_VERSION; const guint glib_minor_version = GLIB_MINOR_VERSION; @@ -1679,16 +1681,19 @@ g_get_any_init_do (void) while (!pw); # endif /* HAVE_POSIX_GETPWUID_R || HAVE_NONPOSIX_GETPWUID_R */ +#ifdef ANDROID_STUB if (!pw) { setpwent (); pw = getpwuid (getuid ()); endpwent (); } +#endif if (pw) { g_user_name = g_strdup (pw->pw_name); + #ifdef ANDROID_STUB if (pw->pw_gecos && *pw->pw_gecos != '\0') { gchar **gecos_fields; @@ -1702,7 +1707,7 @@ g_get_any_init_do (void) g_strfreev (gecos_fields); g_strfreev (name_parts); } - + #endif if (!g_home_dir) g_home_dir = g_strdup (pw->pw_dir); } diff --git a/glib/gwin32.c b/glib/gwin32.c deleted file mode 100644 index c2ced69d4..000000000 --- a/glib/gwin32.c +++ /dev/null @@ -1,600 +0,0 @@ -/* GLIB - Library of useful routines for C programming - * Copyright (C) 1995-1998 Peter Mattis, Spencer Kimball and Josh MacDonald - * Copyright (C) 1998-1999 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, 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 for the unix part, FIXME: make the win32 part MT safe as well. - */ - -#include "config.h" - -#include "glibconfig.h" - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <wchar.h> -#include <errno.h> - -#define STRICT /* Strict typing, please */ -#include <windows.h> -#undef STRICT -#ifndef G_WITH_CYGWIN -#include <direct.h> -#endif -#include <errno.h> -#include <ctype.h> -#if defined(_MSC_VER) || defined(__DMC__) -# include <io.h> -#endif /* _MSC_VER || __DMC__ */ - -#include "glib.h" -#include "galias.h" - -#ifdef G_WITH_CYGWIN -#include <sys/cygwin.h> -#endif - -#ifndef G_WITH_CYGWIN - -gint -g_win32_ftruncate (gint fd, - guint size) -{ - return _chsize (fd, size); -} - -#endif - -/** - * g_win32_getlocale: - * - * The setlocale() function in the Microsoft C library uses locale - * names of the form "English_United States.1252" etc. We want the - * UNIXish standard form "en_US", "zh_TW" etc. This function gets the - * current thread locale from Windows - without any encoding info - - * and returns it as a string of the above form for use in forming - * file names etc. The returned string should be deallocated with - * g_free(). - * - * Returns: newly-allocated locale name. - **/ - -#ifndef SUBLANG_SERBIAN_LATIN_BA -#define SUBLANG_SERBIAN_LATIN_BA 0x06 -#endif - -gchar * -g_win32_getlocale (void) -{ - LCID lcid; - LANGID langid; - gchar *ev; - gint primary, sub; - char iso639[10]; - char iso3166[10]; - const gchar *script = NULL; - - /* Let the user override the system settings through environment - * variables, as on POSIX systems. Note that in GTK+ applications - * since GTK+ 2.10.7 setting either LC_ALL or LANG also sets the - * Win32 locale and C library locale through code in gtkmain.c. - */ - if (((ev = getenv ("LC_ALL")) != NULL && ev[0] != '\0') - || ((ev = getenv ("LC_MESSAGES")) != NULL && ev[0] != '\0') - || ((ev = getenv ("LANG")) != NULL && ev[0] != '\0')) - return g_strdup (ev); - - lcid = GetThreadLocale (); - - if (!GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, sizeof (iso639)) || - !GetLocaleInfo (lcid, LOCALE_SISO3166CTRYNAME, iso3166, sizeof (iso3166))) - return g_strdup ("C"); - - /* Strip off the sorting rules, keep only the language part. */ - langid = LANGIDFROMLCID (lcid); - - /* Split into language and territory part. */ - primary = PRIMARYLANGID (langid); - sub = SUBLANGID (langid); - - /* Handle special cases */ - switch (primary) - { - case LANG_AZERI: - switch (sub) - { - case SUBLANG_AZERI_LATIN: - script = "@Latn"; - break; - case SUBLANG_AZERI_CYRILLIC: - script = "@Cyrl"; - break; - } - break; - case LANG_SERBIAN: /* LANG_CROATIAN == LANG_SERBIAN */ - switch (sub) - { - case SUBLANG_SERBIAN_LATIN: - case 0x06: /* Serbian (Latin) - Bosnia and Herzegovina */ - script = "@Latn"; - break; - } - break; - case LANG_UZBEK: - switch (sub) - { - case SUBLANG_UZBEK_LATIN: - script = "@Latn"; - break; - case SUBLANG_UZBEK_CYRILLIC: - script = "@Cyrl"; - break; - } - break; - } - return g_strconcat (iso639, "_", iso3166, script, NULL); -} - -/** - * g_win32_error_message: - * @error: error code. - * - * Translate a Win32 error code (as returned by GetLastError()) into - * the corresponding message. The message is either language neutral, - * or in the thread's language, or the user's language, the system's - * language, or US English (see docs for FormatMessage()). The - * returned string is in UTF-8. It should be deallocated with - * g_free(). - * - * Returns: newly-allocated error message - **/ -gchar * -g_win32_error_message (gint error) -{ - gchar *retval; - wchar_t *msg = NULL; - int nchars; - - FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER - |FORMAT_MESSAGE_IGNORE_INSERTS - |FORMAT_MESSAGE_FROM_SYSTEM, - NULL, error, 0, - (LPWSTR) &msg, 0, NULL); - if (msg != NULL) - { - nchars = wcslen (msg); - - if (nchars > 2 && msg[nchars-1] == '\n' && msg[nchars-2] == '\r') - msg[nchars-2] = '\0'; - - retval = g_utf16_to_utf8 (msg, -1, NULL, NULL, NULL); - - LocalFree (msg); - } - else - retval = g_strdup (""); - - return retval; -} - -/** - * g_win32_get_package_installation_directory_of_module: - * @hmodule: The Win32 handle for a DLL loaded into the current process, or %NULL - * - * This function tries to determine the installation directory of a - * software package based on the location of a DLL of the software - * package. - * - * @hmodule should be the handle of a loaded DLL or %NULL. The - * function looks up the directory that DLL was loaded from. If - * @hmodule is NULL, the directory the main executable of the current - * process is looked up. If that directory's last component is "bin" - * or "lib", its parent directory is returned, otherwise the directory - * itself. - * - * It thus makes sense to pass only the handle to a "public" DLL of a - * software package to this function, as such DLLs typically are known - * to be installed in a "bin" or occasionally "lib" subfolder of the - * installation folder. DLLs that are of the dynamically loaded module - * or plugin variety are often located in more private locations - * deeper down in the tree, from which it is impossible for GLib to - * deduce the root of the package installation. - * - * The typical use case for this function is to have a DllMain() that - * saves the handle for the DLL. Then when code in the DLL needs to - * construct names of files in the installation tree it calls this - * function passing the DLL handle. - * - * Returns: a string containing the guessed installation directory for - * the software package @hmodule is from. The string is in the GLib - * file name encoding, i.e. UTF-8. The return value should be freed - * with g_free() when not needed any longer. If the function fails - * %NULL is returned. - * - * Since: 2.16 - */ -gchar * -g_win32_get_package_installation_directory_of_module (gpointer hmodule) -{ - gchar *retval; - gchar *p; - wchar_t wc_fn[MAX_PATH]; - - if (!GetModuleFileNameW (hmodule, wc_fn, MAX_PATH)) - return NULL; - - retval = g_utf16_to_utf8 (wc_fn, -1, NULL, NULL, NULL); - - if ((p = strrchr (retval, G_DIR_SEPARATOR)) != NULL) - *p = '\0'; - - p = strrchr (retval, G_DIR_SEPARATOR); - if (p && (g_ascii_strcasecmp (p + 1, "bin") == 0 || - g_ascii_strcasecmp (p + 1, "lib") == 0)) - *p = '\0'; - -#ifdef G_WITH_CYGWIN - /* In Cygwin we need to have POSIX paths */ - { - gchar tmp[MAX_PATH]; - - cygwin_conv_to_posix_path (retval, tmp); - g_free (retval); - retval = g_strdup (tmp); - } -#endif - - return retval; -} - -static gchar * -get_package_directory_from_module (const gchar *module_name) -{ - static GHashTable *module_dirs = NULL; - G_LOCK_DEFINE_STATIC (module_dirs); - HMODULE hmodule = NULL; - gchar *fn; - - G_LOCK (module_dirs); - - if (module_dirs == NULL) - module_dirs = g_hash_table_new (g_str_hash, g_str_equal); - - fn = g_hash_table_lookup (module_dirs, module_name ? module_name : ""); - - if (fn) - { - G_UNLOCK (module_dirs); - return g_strdup (fn); - } - - if (module_name) - { - wchar_t *wc_module_name = g_utf8_to_utf16 (module_name, -1, NULL, NULL, NULL); - hmodule = GetModuleHandleW (wc_module_name); - g_free (wc_module_name); - - if (!hmodule) - { - G_UNLOCK (module_dirs); - return NULL; - } - } - - fn = g_win32_get_package_installation_directory_of_module (hmodule); - - if (fn == NULL) - { - G_UNLOCK (module_dirs); - return NULL; - } - - g_hash_table_insert (module_dirs, module_name ? g_strdup (module_name) : "", fn); - - G_UNLOCK (module_dirs); - - return g_strdup (fn); -} - -/** - * g_win32_get_package_installation_directory: - * @package: You should pass %NULL for this. - * @dll_name: The name of a DLL that a package provides in UTF-8, or %NULL. - * - * Try to determine the installation directory for a software package. - * - * This function is deprecated. Use - * g_win32_get_package_installation_directory_of_module() instead. - * - * The use of @package is deprecated. You should always pass %NULL. A - * warning is printed if non-NULL is passed as @package. - * - * The original intended use of @package was for a short identifier of - * the package, typically the same identifier as used for - * <literal>GETTEXT_PACKAGE</literal> in software configured using GNU - * autotools. The function first looks in the Windows Registry for the - * value <literal>#InstallationDirectory</literal> in the key - * <literal>#HKLM\Software\@package</literal>, and if that value - * exists and is a string, returns that. - * - * It is strongly recommended that packagers of GLib-using libraries - * for Windows do not store installation paths in the Registry to be - * used by this function as that interfers with having several - * parallel installations of the library. Enabling multiple - * installations of different versions of some GLib-using library, or - * GLib itself, is desirable for various reasons. - * - * For this reason it is recommeded to always pass %NULL as - * @package to this function, to avoid the temptation to use the - * Registry. In version 2.20 of GLib the @package parameter - * will be ignored and this function won't look in the Registry at all. - * - * If @package is %NULL, or the above value isn't found in the - * Registry, but @dll_name is non-%NULL, it should name a DLL loaded - * into the current process. Typically that would be the name of the - * DLL calling this function, looking for its installation - * directory. The function then asks Windows what directory that DLL - * was loaded from. If that directory's last component is "bin" or - * "lib", the parent directory is returned, otherwise the directory - * itself. If that DLL isn't loaded, the function proceeds as if - * @dll_name was %NULL. - * - * If both @package and @dll_name are %NULL, the directory from where - * the main executable of the process was loaded is used instead in - * the same way as above. - * - * Returns: a string containing the installation directory for - * @package. The string is in the GLib file name encoding, - * i.e. UTF-8. The return value should be freed with g_free() when not - * needed any longer. If the function fails %NULL is returned. - * - * @Deprecated:2.18: Pass the HMODULE of a DLL or EXE to - * g_win32_get_package_installation_directory_of_module() instead. - **/ - - gchar * -g_win32_get_package_installation_directory_utf8 (const gchar *package, - const gchar *dll_name) -{ - gchar *result = NULL; - - if (package != NULL) - g_warning ("Passing a non-NULL package to g_win32_get_package_installation_directory() is deprecated and it is ignored."); - - if (dll_name != NULL) - result = get_package_directory_from_module (dll_name); - - if (result == NULL) - result = get_package_directory_from_module (NULL); - - return result; -} - -#if !defined (_WIN64) - -/* DLL ABI binary compatibility version that uses system codepage file names */ - -gchar * -g_win32_get_package_installation_directory (const gchar *package, - const gchar *dll_name) -{ - gchar *utf8_package = NULL, *utf8_dll_name = NULL; - gchar *utf8_retval, *retval; - - if (package != NULL) - utf8_package = g_locale_to_utf8 (package, -1, NULL, NULL, NULL); - - if (dll_name != NULL) - utf8_dll_name = g_locale_to_utf8 (dll_name, -1, NULL, NULL, NULL); - - utf8_retval = - g_win32_get_package_installation_directory_utf8 (utf8_package, - utf8_dll_name); - - retval = g_locale_from_utf8 (utf8_retval, -1, NULL, NULL, NULL); - - g_free (utf8_package); - g_free (utf8_dll_name); - g_free (utf8_retval); - - return retval; -} - -#endif - -/** - * g_win32_get_package_installation_subdirectory: - * @package: You should pass %NULL for this. - * @dll_name: The name of a DLL that a package provides, in UTF-8, or %NULL. - * @subdir: A subdirectory of the package installation directory, also in UTF-8 - * - * This function is deprecated. Use - * g_win32_get_package_installation_directory_of_module() and - * g_build_filename() instead. - * - * Returns a newly-allocated string containing the path of the - * subdirectory @subdir in the return value from calling - * g_win32_get_package_installation_directory() with the @package and - * @dll_name parameters. See the documentation for - * g_win32_get_package_installation_directory() for more details. In - * particular, note that it is deprecated to pass anything except NULL - * as @package. - * - * Returns: a string containing the complete path to @subdir inside - * the installation directory of @package. The returned string is in - * the GLib file name encoding, i.e. UTF-8. The return value should be - * freed with g_free() when no longer needed. If something goes wrong, - * %NULL is returned. - * - * @Deprecated:2.18: Pass the HMODULE of a DLL or EXE to - * g_win32_get_package_installation_directory_of_module() instead, and - * then construct a subdirectory pathname with g_build_filename(). - **/ - -gchar * -g_win32_get_package_installation_subdirectory_utf8 (const gchar *package, - const gchar *dll_name, - const gchar *subdir) -{ - gchar *prefix; - gchar *dirname; - - prefix = g_win32_get_package_installation_directory_utf8 (package, dll_name); - - dirname = g_build_filename (prefix, subdir, NULL); - g_free (prefix); - - return dirname; -} - -#if !defined (_WIN64) - -/* DLL ABI binary compatibility version that uses system codepage file names */ - -gchar * -g_win32_get_package_installation_subdirectory (const gchar *package, - const gchar *dll_name, - const gchar *subdir) -{ - gchar *prefix; - gchar *dirname; - - prefix = g_win32_get_package_installation_directory (package, dll_name); - - dirname = g_build_filename (prefix, subdir, NULL); - g_free (prefix); - - return dirname; -} - -#endif - -static guint windows_version; - -static void -g_win32_windows_version_init (void) -{ - static gboolean beenhere = FALSE; - - if (!beenhere) - { - beenhere = TRUE; - windows_version = GetVersion (); - - if (windows_version & 0x80000000) - g_error ("This version of GLib requires NT-based Windows."); - } -} - -void -_g_win32_thread_init (void) -{ - g_win32_windows_version_init (); -} - -/** - * g_win32_get_windows_version: - * - * Returns version information for the Windows operating system the - * code is running on. See MSDN documentation for the GetVersion() - * function. To summarize, the most significant bit is one on Win9x, - * and zero on NT-based systems. Since version 2.14, GLib works only - * on NT-based systems, so checking whether your are running on Win9x - * in your own software is moot. The least significant byte is 4 on - * Windows NT 4, and 5 on Windows XP. Software that needs really - * detailled version and feature information should use Win32 API like - * GetVersionEx() and VerifyVersionInfo(). - * - * Returns: The version information. - * - * Since: 2.6 - **/ -guint -g_win32_get_windows_version (void) -{ - g_win32_windows_version_init (); - - return windows_version; -} - -/** - * g_win32_locale_filename_from_utf8: - * @utf8filename: a UTF-8 encoded filename. - * - * Converts a filename from UTF-8 to the system codepage. - * - * On NT-based Windows, on NTFS file systems, file names are in - * Unicode. It is quite possible that Unicode file names contain - * characters not representable in the system codepage. (For instance, - * Greek or Cyrillic characters on Western European or US Windows - * installations, or various less common CJK characters on CJK Windows - * installations.) - * - * In such a case, and if the filename refers to an existing file, and - * the file system stores alternate short (8.3) names for directory - * entries, the short form of the filename is returned. Note that the - * "short" name might in fact be longer than the Unicode name if the - * Unicode name has very short pathname components containing - * non-ASCII characters. If no system codepage name for the file is - * possible, %NULL is returned. - * - * The return value is dynamically allocated and should be freed with - * g_free() when no longer needed. - * - * Return value: The converted filename, or %NULL on conversion - * failure and lack of short names. - * - * Since: 2.8 - */ -gchar * -g_win32_locale_filename_from_utf8 (const gchar *utf8filename) -{ - gchar *retval = g_locale_from_utf8 (utf8filename, -1, NULL, NULL, NULL); - - if (retval == NULL) - { - /* Conversion failed, so convert to wide chars, check if there - * is a 8.3 version, and use that. - */ - wchar_t *wname = g_utf8_to_utf16 (utf8filename, -1, NULL, NULL, NULL); - if (wname != NULL) - { - wchar_t wshortname[MAX_PATH + 1]; - if (GetShortPathNameW (wname, wshortname, G_N_ELEMENTS (wshortname))) - { - gchar *tem = g_utf16_to_utf8 (wshortname, -1, NULL, NULL, NULL); - retval = g_locale_from_utf8 (tem, -1, NULL, NULL, NULL); - g_free (tem); - } - g_free (wname); - } - } - return retval; -} - -#define __G_WIN32_C__ -#include "galiasdef.c" diff --git a/glib/libcharset/.gitignore b/glib/libcharset/.gitignore deleted file mode 100644 index 0cef4408e..000000000 --- a/glib/libcharset/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -charset.alias -ref-add.sed -ref-del.sed diff --git a/glib/libcharset/Makefile.am b/glib/libcharset/Makefile.am deleted file mode 100644 index cfa341218..000000000 --- a/glib/libcharset/Makefile.am +++ /dev/null @@ -1,64 +0,0 @@ -## Process this file with automake to produce Makefile.in -include $(top_srcdir)/Makefile.decl - -INCLUDES = \ - -DLIBDIR=\"$(libdir)\" -I$(top_srcdir) - -noinst_LTLIBRARIES = libcharset.la - -libcharset_la_SOURCES = \ - libcharset.h \ - localcharset.h \ - localcharset.c - -EXTRA_DIST += \ - README \ - config.charset \ - ref-add.sin \ - ref-del.sin \ - glibc21.m4 \ - codeset.m4 \ - update.sh \ - make-patch.sh \ - libcharset-glib.patch - -charset_alias = $(DESTDIR)$(libdir)/charset.alias -charset_tmp = $(DESTDIR)$(libdir)/charset.tmp -install-exec-local: all-local - $(mkinstalldirs) $(DESTDIR)$(libdir) - if test -f $(charset_alias); then \ - sed -f ref-add.sed $(charset_alias) > $(charset_tmp) ; \ - $(INSTALL_DATA) $(charset_tmp) $(charset_alias) ; \ - rm -f $(charset_tmp) ; \ - else \ - if test @GLIBC21@ = no; then \ - sed -f ref-add.sed charset.alias > $(charset_tmp) ; \ - $(INSTALL_DATA) $(charset_tmp) $(charset_alias) ; \ - rm -f $(charset_tmp) ; \ - fi ; \ - fi - -uninstall-local: all-local - if test -f $(charset_alias); then \ - sed -f ref-del.sed $(charset_alias) > $(charset_tmp); \ - if grep '^# Packages using this file: $$' $(charset_tmp) \ - > /dev/null; then \ - rm -f $(charset_alias); \ - else \ - $(INSTALL_DATA) $(charset_tmp) $(charset_alias); \ - fi; \ - rm -f $(charset_tmp); \ - fi - -charset.alias: config.charset - $(SHELL) $(srcdir)/config.charset '@host@' > t-$@ - mv t-$@ $@ - -all-local: ref-add.sed ref-del.sed charset.alias - -SUFFIXES = .sed .sin -.sin.sed: - sed -e '/^#/d' -e 's/@''PACKAGE''@/@PACKAGE@/g' $< > t-$@ - mv t-$@ $@ - -CLEANFILES = charset.alias ref-add.sed ref-del.sed diff --git a/glib/libcharset/README b/glib/libcharset/README deleted file mode 100644 index c8f53bde6..000000000 --- a/glib/libcharset/README +++ /dev/null @@ -1,46 +0,0 @@ -The sources are derived from Bruno Haible's libcharset library included -with libiconv: - - http//www.gnu.org/software/libiconv - -The 'update.sh' script in this directory, when pointed at -the original sources updates the files in this directory -(and elsewhere in the GLib distribution) to the new version - -The 'make-patch.sh' script in this directory regenerates -the patch files included in this directory from a copy -of the pristine sources and the files in this directory. - -The license on the portions from libiconv portions is reproduced -below. - -Owen Taylor -26 September 2001 - -Updated to libiconv-1.12. - -Behdad Esfahbod -20 May 2008 - -==== - -/* Determine a canonical name for the current locale's character encoding. - - Copyright (C) 2000-2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -/* Written by Bruno Haible <haible@clisp.cons.org>. */ diff --git a/glib/libcharset/codeset.m4 b/glib/libcharset/codeset.m4 deleted file mode 100644 index a6e67ec49..000000000 --- a/glib/libcharset/codeset.m4 +++ /dev/null @@ -1,21 +0,0 @@ -# codeset.m4 serial AM1 (gettext-0.10.40) -dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -dnl From Bruno Haible. - -AC_DEFUN([AM_LANGINFO_CODESET], -[ - AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset, - [AC_TRY_LINK([#include <langinfo.h>], - [char* cs = nl_langinfo(CODESET);], - am_cv_langinfo_codeset=yes, - am_cv_langinfo_codeset=no) - ]) - if test $am_cv_langinfo_codeset = yes; then - AC_DEFINE(HAVE_LANGINFO_CODESET, 1, - [Define if you have <langinfo.h> and nl_langinfo(CODESET).]) - fi -]) diff --git a/glib/libcharset/config.charset b/glib/libcharset/config.charset deleted file mode 100755 index e8c258b3f..000000000 --- a/glib/libcharset/config.charset +++ /dev/null @@ -1,640 +0,0 @@ -#! /bin/sh -# Output a system dependent table of character encoding aliases. -# -# Copyright (C) 2000-2004, 2006 Free Software Foundation, Inc. -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Library General Public License as published -# by the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program 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 -# Library General Public License for more details. -# -# You should have received a copy of the GNU Library General Public -# License along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -# USA. -# -# The table consists of lines of the form -# ALIAS CANONICAL -# -# ALIAS is the (system dependent) result of "nl_langinfo (CODESET)". -# ALIAS is compared in a case sensitive way. -# -# CANONICAL is the GNU canonical name for this character encoding. -# It must be an encoding supported by libiconv. Support by GNU libc is -# also desirable. CANONICAL is case insensitive. Usually an upper case -# MIME charset name is preferred. -# The current list of GNU canonical charset names is as follows. -# -# name MIME? used by which systems -# ASCII, ANSI_X3.4-1968 glibc solaris freebsd netbsd darwin -# ISO-8859-1 Y glibc aix hpux irix osf solaris freebsd netbsd darwin -# ISO-8859-2 Y glibc aix hpux irix osf solaris freebsd netbsd darwin -# ISO-8859-3 Y glibc solaris -# ISO-8859-4 Y osf solaris freebsd netbsd darwin -# ISO-8859-5 Y glibc aix hpux irix osf solaris freebsd netbsd darwin -# ISO-8859-6 Y glibc aix hpux solaris -# ISO-8859-7 Y glibc aix hpux irix osf solaris netbsd darwin -# ISO-8859-8 Y glibc aix hpux osf solaris -# ISO-8859-9 Y glibc aix hpux irix osf solaris darwin -# ISO-8859-13 glibc netbsd darwin -# ISO-8859-14 glibc -# ISO-8859-15 glibc aix osf solaris freebsd darwin -# KOI8-R Y glibc solaris freebsd netbsd darwin -# KOI8-U Y glibc freebsd netbsd darwin -# KOI8-T glibc -# CP437 dos -# CP775 dos -# CP850 aix osf dos -# CP852 dos -# CP855 dos -# CP856 aix -# CP857 dos -# CP861 dos -# CP862 dos -# CP864 dos -# CP865 dos -# CP866 freebsd netbsd darwin dos -# CP869 dos -# CP874 woe32 dos -# CP922 aix -# CP932 aix woe32 dos -# CP943 aix -# CP949 osf woe32 dos -# CP950 woe32 dos -# CP1046 aix -# CP1124 aix -# CP1125 dos -# CP1129 aix -# CP1250 woe32 -# CP1251 glibc solaris netbsd darwin woe32 -# CP1252 aix woe32 -# CP1253 woe32 -# CP1254 woe32 -# CP1255 glibc woe32 -# CP1256 woe32 -# CP1257 woe32 -# GB2312 Y glibc aix hpux irix solaris freebsd netbsd darwin -# EUC-JP Y glibc aix hpux irix osf solaris freebsd netbsd darwin -# EUC-KR Y glibc aix hpux irix osf solaris freebsd netbsd darwin -# EUC-TW glibc aix hpux irix osf solaris netbsd -# BIG5 Y glibc aix hpux osf solaris freebsd netbsd darwin -# BIG5-HKSCS glibc solaris -# GBK glibc aix osf solaris woe32 dos -# GB18030 glibc solaris netbsd -# SHIFT_JIS Y hpux osf solaris freebsd netbsd darwin -# JOHAB glibc solaris woe32 -# TIS-620 glibc aix hpux osf solaris -# VISCII Y glibc -# TCVN5712-1 glibc -# GEORGIAN-PS glibc -# HP-ROMAN8 hpux -# HP-ARABIC8 hpux -# HP-GREEK8 hpux -# HP-HEBREW8 hpux -# HP-TURKISH8 hpux -# HP-KANA8 hpux -# DEC-KANJI osf -# DEC-HANYU osf -# UTF-8 Y glibc aix hpux osf solaris netbsd darwin -# -# Note: Names which are not marked as being a MIME name should not be used in -# Internet protocols for information interchange (mail, news, etc.). -# -# Note: ASCII and ANSI_X3.4-1968 are synonymous canonical names. Applications -# must understand both names and treat them as equivalent. -# -# The first argument passed to this file is the canonical host specification, -# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM -# or -# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM - -host="$1" -os=`echo "$host" | sed -e 's/^[^-]*-[^-]*-\(.*\)$/\1/'` -echo "# This file contains a table of character encoding aliases," -echo "# suitable for operating system '${os}'." -echo "# It was automatically generated from config.charset." -# List of references, updated during installation: -echo "# Packages using this file: " -case "$os" in - linux-gnulibc1*) - # Linux libc5 doesn't have nl_langinfo(CODESET); therefore - # localcharset.c falls back to using the full locale name - # from the environment variables. - echo "C ASCII" - echo "POSIX ASCII" - for l in af af_ZA ca ca_ES da da_DK de de_AT de_BE de_CH de_DE de_LU \ - en en_AU en_BW en_CA en_DK en_GB en_IE en_NZ en_US en_ZA \ - en_ZW es es_AR es_BO es_CL es_CO es_DO es_EC es_ES es_GT \ - es_HN es_MX es_PA es_PE es_PY es_SV es_US es_UY es_VE et \ - et_EE eu eu_ES fi fi_FI fo fo_FO fr fr_BE fr_CA fr_CH fr_FR \ - fr_LU ga ga_IE gl gl_ES id id_ID in in_ID is is_IS it it_CH \ - it_IT kl kl_GL nl nl_BE nl_NL no no_NO pt pt_BR pt_PT sv \ - sv_FI sv_SE; do - echo "$l ISO-8859-1" - echo "$l.iso-8859-1 ISO-8859-1" - echo "$l.iso-8859-15 ISO-8859-15" - echo "$l.iso-8859-15@euro ISO-8859-15" - echo "$l@euro ISO-8859-15" - echo "$l.cp-437 CP437" - echo "$l.cp-850 CP850" - echo "$l.cp-1252 CP1252" - echo "$l.cp-1252@euro CP1252" - #echo "$l.atari-st ATARI-ST" # not a commonly used encoding - echo "$l.utf-8 UTF-8" - echo "$l.utf-8@euro UTF-8" - done - for l in cs cs_CZ hr hr_HR hu hu_HU pl pl_PL ro ro_RO sk sk_SK sl \ - sl_SI sr sr_CS sr_YU; do - echo "$l ISO-8859-2" - echo "$l.iso-8859-2 ISO-8859-2" - echo "$l.cp-852 CP852" - echo "$l.cp-1250 CP1250" - echo "$l.utf-8 UTF-8" - done - for l in mk mk_MK ru ru_RU; do - echo "$l ISO-8859-5" - echo "$l.iso-8859-5 ISO-8859-5" - echo "$l.koi8-r KOI8-R" - echo "$l.cp-866 CP866" - echo "$l.cp-1251 CP1251" - echo "$l.utf-8 UTF-8" - done - for l in ar ar_SA; do - echo "$l ISO-8859-6" - echo "$l.iso-8859-6 ISO-8859-6" - echo "$l.cp-864 CP864" - #echo "$l.cp-868 CP868" # not a commonly used encoding - echo "$l.cp-1256 CP1256" - echo "$l.utf-8 UTF-8" - done - for l in el el_GR gr gr_GR; do - echo "$l ISO-8859-7" - echo "$l.iso-8859-7 ISO-8859-7" - echo "$l.cp-869 CP869" - echo "$l.cp-1253 CP1253" - echo "$l.cp-1253@euro CP1253" - echo "$l.utf-8 UTF-8" - echo "$l.utf-8@euro UTF-8" - done - for l in he he_IL iw iw_IL; do - echo "$l ISO-8859-8" - echo "$l.iso-8859-8 ISO-8859-8" - echo "$l.cp-862 CP862" - echo "$l.cp-1255 CP1255" - echo "$l.utf-8 UTF-8" - done - for l in tr tr_TR; do - echo "$l ISO-8859-9" - echo "$l.iso-8859-9 ISO-8859-9" - echo "$l.cp-857 CP857" - echo "$l.cp-1254 CP1254" - echo "$l.utf-8 UTF-8" - done - for l in lt lt_LT lv lv_LV; do - #echo "$l BALTIC" # not a commonly used encoding, wrong encoding name - echo "$l ISO-8859-13" - done - for l in ru_UA uk uk_UA; do - echo "$l KOI8-U" - done - for l in zh zh_CN; do - #echo "$l GB_2312-80" # not a commonly used encoding, wrong encoding name - echo "$l GB2312" - done - for l in ja ja_JP ja_JP.EUC; do - echo "$l EUC-JP" - done - for l in ko ko_KR; do - echo "$l EUC-KR" - done - for l in th th_TH; do - echo "$l TIS-620" - done - for l in fa fa_IR; do - #echo "$l ISIRI-3342" # a broken encoding - echo "$l.utf-8 UTF-8" - done - ;; - linux* | *-gnu*) - # With glibc-2.1 or newer, we don't need any canonicalization, - # because glibc has iconv and both glibc and libiconv support all - # GNU canonical names directly. Therefore, the Makefile does not - # need to install the alias file at all. - # The following applies only to glibc-2.0.x and older libcs. - echo "ISO_646.IRV:1983 ASCII" - ;; - aix*) - echo "ISO8859-1 ISO-8859-1" - echo "ISO8859-2 ISO-8859-2" - echo "ISO8859-5 ISO-8859-5" - echo "ISO8859-6 ISO-8859-6" - echo "ISO8859-7 ISO-8859-7" - echo "ISO8859-8 ISO-8859-8" - echo "ISO8859-9 ISO-8859-9" - echo "ISO8859-15 ISO-8859-15" - echo "IBM-850 CP850" - echo "IBM-856 CP856" - echo "IBM-921 ISO-8859-13" - echo "IBM-922 CP922" - echo "IBM-932 CP932" - echo "IBM-943 CP943" - echo "IBM-1046 CP1046" - echo "IBM-1124 CP1124" - echo "IBM-1129 CP1129" - echo "IBM-1252 CP1252" - echo "IBM-eucCN GB2312" - echo "IBM-eucJP EUC-JP" - echo "IBM-eucKR EUC-KR" - echo "IBM-eucTW EUC-TW" - echo "big5 BIG5" - echo "GBK GBK" - echo "TIS-620 TIS-620" - echo "UTF-8 UTF-8" - ;; - hpux*) - echo "iso88591 ISO-8859-1" - echo "iso88592 ISO-8859-2" - echo "iso88595 ISO-8859-5" - echo "iso88596 ISO-8859-6" - echo "iso88597 ISO-8859-7" - echo "iso88598 ISO-8859-8" - echo "iso88599 ISO-8859-9" - echo "iso885915 ISO-8859-15" - echo "roman8 HP-ROMAN8" - echo "arabic8 HP-ARABIC8" - echo "greek8 HP-GREEK8" - echo "hebrew8 HP-HEBREW8" - echo "turkish8 HP-TURKISH8" - echo "kana8 HP-KANA8" - echo "tis620 TIS-620" - echo "big5 BIG5" - echo "eucJP EUC-JP" - echo "eucKR EUC-KR" - echo "eucTW EUC-TW" - echo "hp15CN GB2312" - #echo "ccdc ?" # what is this? - echo "SJIS SHIFT_JIS" - echo "utf8 UTF-8" - ;; - irix*) - echo "ISO8859-1 ISO-8859-1" - echo "ISO8859-2 ISO-8859-2" - echo "ISO8859-5 ISO-8859-5" - echo "ISO8859-7 ISO-8859-7" - echo "ISO8859-9 ISO-8859-9" - echo "eucCN GB2312" - echo "eucJP EUC-JP" - echo "eucKR EUC-KR" - echo "eucTW EUC-TW" - ;; - osf*) - echo "ISO8859-1 ISO-8859-1" - echo "ISO8859-2 ISO-8859-2" - echo "ISO8859-4 ISO-8859-4" - echo "ISO8859-5 ISO-8859-5" - echo "ISO8859-7 ISO-8859-7" - echo "ISO8859-8 ISO-8859-8" - echo "ISO8859-9 ISO-8859-9" - echo "ISO8859-15 ISO-8859-15" - echo "cp850 CP850" - echo "big5 BIG5" - echo "dechanyu DEC-HANYU" - echo "dechanzi GB2312" - echo "deckanji DEC-KANJI" - echo "deckorean EUC-KR" - echo "eucJP EUC-JP" - echo "eucKR EUC-KR" - echo "eucTW EUC-TW" - echo "GBK GBK" - echo "KSC5601 CP949" - echo "sdeckanji EUC-JP" - echo "SJIS SHIFT_JIS" - echo "TACTIS TIS-620" - echo "UTF-8 UTF-8" - ;; - solaris*) - echo "646 ASCII" - echo "ISO8859-1 ISO-8859-1" - echo "ISO8859-2 ISO-8859-2" - echo "ISO8859-3 ISO-8859-3" - echo "ISO8859-4 ISO-8859-4" - echo "ISO8859-5 ISO-8859-5" - echo "ISO8859-6 ISO-8859-6" - echo "ISO8859-7 ISO-8859-7" - echo "ISO8859-8 ISO-8859-8" - echo "ISO8859-9 ISO-8859-9" - echo "ISO8859-15 ISO-8859-15" - echo "koi8-r KOI8-R" - echo "ansi-1251 CP1251" - echo "BIG5 BIG5" - echo "Big5-HKSCS BIG5-HKSCS" - echo "gb2312 GB2312" - echo "GBK GBK" - echo "GB18030 GB18030" - echo "cns11643 EUC-TW" - echo "5601 EUC-KR" - echo "ko_KR.johap92 JOHAB" - echo "eucJP EUC-JP" - echo "PCK SHIFT_JIS" - echo "TIS620.2533 TIS-620" - #echo "sun_eu_greek ?" # what is this? - echo "UTF-8 UTF-8" - ;; - freebsd* | os2*) - # FreeBSD 4.2 doesn't have nl_langinfo(CODESET); therefore - # localcharset.c falls back to using the full locale name - # from the environment variables. - # Likewise for OS/2. OS/2 has XFree86 just like FreeBSD. Just - # reuse FreeBSD's locale data for OS/2. - echo "C ASCII" - echo "US-ASCII ASCII" - for l in la_LN lt_LN; do - echo "$l.ASCII ASCII" - done - for l in da_DK de_AT de_CH de_DE en_AU en_CA en_GB en_US es_ES \ - fi_FI fr_BE fr_CA fr_CH fr_FR is_IS it_CH it_IT la_LN \ - lt_LN nl_BE nl_NL no_NO pt_PT sv_SE; do - echo "$l.ISO_8859-1 ISO-8859-1" - echo "$l.DIS_8859-15 ISO-8859-15" - done - for l in cs_CZ hr_HR hu_HU la_LN lt_LN pl_PL sl_SI; do - echo "$l.ISO_8859-2 ISO-8859-2" - done - for l in la_LN lt_LT; do - echo "$l.ISO_8859-4 ISO-8859-4" - done - for l in ru_RU ru_SU; do - echo "$l.KOI8-R KOI8-R" - echo "$l.ISO_8859-5 ISO-8859-5" - echo "$l.CP866 CP866" - done - echo "uk_UA.KOI8-U KOI8-U" - echo "zh_TW.BIG5 BIG5" - echo "zh_TW.Big5 BIG5" - echo "zh_CN.EUC GB2312" - echo "ja_JP.EUC EUC-JP" - echo "ja_JP.SJIS SHIFT_JIS" - echo "ja_JP.Shift_JIS SHIFT_JIS" - echo "ko_KR.EUC EUC-KR" - ;; - netbsd*) - echo "646 ASCII" - echo "ISO8859-1 ISO-8859-1" - echo "ISO8859-2 ISO-8859-2" - echo "ISO8859-4 ISO-8859-4" - echo "ISO8859-5 ISO-8859-5" - echo "ISO8859-7 ISO-8859-7" - echo "ISO8859-13 ISO-8859-13" - echo "ISO8859-15 ISO-8859-15" - echo "eucCN GB2312" - echo "eucJP EUC-JP" - echo "eucKR EUC-KR" - echo "eucTW EUC-TW" - echo "BIG5 BIG5" - echo "SJIS SHIFT_JIS" - ;; - darwin[56]*) - # Darwin 6.8 doesn't have nl_langinfo(CODESET); therefore - # localcharset.c falls back to using the full locale name - # from the environment variables. - echo "C ASCII" - for l in en_AU en_CA en_GB en_US la_LN; do - echo "$l.US-ASCII ASCII" - done - for l in da_DK de_AT de_CH de_DE en_AU en_CA en_GB en_US es_ES \ - fi_FI fr_BE fr_CA fr_CH fr_FR is_IS it_CH it_IT nl_BE \ - nl_NL no_NO pt_PT sv_SE; do - echo "$l ISO-8859-1" - echo "$l.ISO8859-1 ISO-8859-1" - echo "$l.ISO8859-15 ISO-8859-15" - done - for l in la_LN; do - echo "$l.ISO8859-1 ISO-8859-1" - echo "$l.ISO8859-15 ISO-8859-15" - done - for l in cs_CZ hr_HR hu_HU la_LN pl_PL sl_SI; do - echo "$l.ISO8859-2 ISO-8859-2" - done - for l in la_LN lt_LT; do - echo "$l.ISO8859-4 ISO-8859-4" - done - for l in ru_RU; do - echo "$l.KOI8-R KOI8-R" - echo "$l.ISO8859-5 ISO-8859-5" - echo "$l.CP866 CP866" - done - for l in bg_BG; do - echo "$l.CP1251 CP1251" - done - echo "uk_UA.KOI8-U KOI8-U" - echo "zh_TW.BIG5 BIG5" - echo "zh_TW.Big5 BIG5" - echo "zh_CN.EUC GB2312" - echo "ja_JP.EUC EUC-JP" - echo "ja_JP.SJIS SHIFT_JIS" - echo "ko_KR.EUC EUC-KR" - ;; - darwin*) - # Darwin 7.5 has nl_langinfo(CODESET), but it is useless: - # - It returns the empty string when LANG is set to a locale of the - # form ll_CC, although ll_CC/LC_CTYPE is a symlink to an UTF-8 - # LC_CTYPE file. - # - The environment variables LANG, LC_CTYPE, LC_ALL are not set by - # the system; nl_langinfo(CODESET) returns "US-ASCII" in this case. - # - The documentation says: - # "... all code that calls BSD system routines should ensure - # that the const *char parameters of these routines are in UTF-8 - # encoding. All BSD system functions expect their string - # parameters to be in UTF-8 encoding and nothing else." - # It also says - # "An additional caveat is that string parameters for files, - # paths, and other file-system entities must be in canonical - # UTF-8. In a canonical UTF-8 Unicode string, all decomposable - # characters are decomposed ..." - # but this is not true: You can pass non-decomposed UTF-8 strings - # to file system functions, and it is the OS which will convert - # them to decomposed UTF-8 before accessing the file system. - # - The Apple Terminal application displays UTF-8 by default. - # - However, other applications are free to use different encodings: - # - xterm uses ISO-8859-1 by default. - # - TextEdit uses MacRoman by default. - # We prefer UTF-8 over decomposed UTF-8-MAC because one should - # minimize the use of decomposed Unicode. Unfortunately, through the - # Darwin file system, decomposed UTF-8 strings are leaked into user - # space nevertheless. - echo "* UTF-8" - ;; - beos*) - # BeOS has a single locale, and it has UTF-8 encoding. - echo "* UTF-8" - ;; - msdosdjgpp*) - # DJGPP 2.03 doesn't have nl_langinfo(CODESET); therefore - # localcharset.c falls back to using the full locale name - # from the environment variables. - echo "#" - echo "# The encodings given here may not all be correct." - echo "# If you find that the encoding given for your language and" - echo "# country is not the one your DOS machine actually uses, just" - echo "# correct it in this file, and send a mail to" - echo "# Juan Manuel Guerrero <juan.guerrero@gmx.de>" - echo "# and Bruno Haible <bruno@clisp.org>." - echo "#" - echo "C ASCII" - # ISO-8859-1 languages - echo "ca CP850" - echo "ca_ES CP850" - echo "da CP865" # not CP850 ?? - echo "da_DK CP865" # not CP850 ?? - echo "de CP850" - echo "de_AT CP850" - echo "de_CH CP850" - echo "de_DE CP850" - echo "en CP850" - echo "en_AU CP850" # not CP437 ?? - echo "en_CA CP850" - echo "en_GB CP850" - echo "en_NZ CP437" - echo "en_US CP437" - echo "en_ZA CP850" # not CP437 ?? - echo "es CP850" - echo "es_AR CP850" - echo "es_BO CP850" - echo "es_CL CP850" - echo "es_CO CP850" - echo "es_CR CP850" - echo "es_CU CP850" - echo "es_DO CP850" - echo "es_EC CP850" - echo "es_ES CP850" - echo "es_GT CP850" - echo "es_HN CP850" - echo "es_MX CP850" - echo "es_NI CP850" - echo "es_PA CP850" - echo "es_PY CP850" - echo "es_PE CP850" - echo "es_SV CP850" - echo "es_UY CP850" - echo "es_VE CP850" - echo "et CP850" - echo "et_EE CP850" - echo "eu CP850" - echo "eu_ES CP850" - echo "fi CP850" - echo "fi_FI CP850" - echo "fr CP850" - echo "fr_BE CP850" - echo "fr_CA CP850" - echo "fr_CH CP850" - echo "fr_FR CP850" - echo "ga CP850" - echo "ga_IE CP850" - echo "gd CP850" - echo "gd_GB CP850" - echo "gl CP850" - echo "gl_ES CP850" - echo "id CP850" # not CP437 ?? - echo "id_ID CP850" # not CP437 ?? - echo "is CP861" # not CP850 ?? - echo "is_IS CP861" # not CP850 ?? - echo "it CP850" - echo "it_CH CP850" - echo "it_IT CP850" - echo "lt CP775" - echo "lt_LT CP775" - echo "lv CP775" - echo "lv_LV CP775" - echo "nb CP865" # not CP850 ?? - echo "nb_NO CP865" # not CP850 ?? - echo "nl CP850" - echo "nl_BE CP850" - echo "nl_NL CP850" - echo "nn CP865" # not CP850 ?? - echo "nn_NO CP865" # not CP850 ?? - echo "no CP865" # not CP850 ?? - echo "no_NO CP865" # not CP850 ?? - echo "pt CP850" - echo "pt_BR CP850" - echo "pt_PT CP850" - echo "sv CP850" - echo "sv_SE CP850" - # ISO-8859-2 languages - echo "cs CP852" - echo "cs_CZ CP852" - echo "hr CP852" - echo "hr_HR CP852" - echo "hu CP852" - echo "hu_HU CP852" - echo "pl CP852" - echo "pl_PL CP852" - echo "ro CP852" - echo "ro_RO CP852" - echo "sk CP852" - echo "sk_SK CP852" - echo "sl CP852" - echo "sl_SI CP852" - echo "sq CP852" - echo "sq_AL CP852" - echo "sr CP852" # CP852 or CP866 or CP855 ?? - echo "sr_CS CP852" # CP852 or CP866 or CP855 ?? - echo "sr_YU CP852" # CP852 or CP866 or CP855 ?? - # ISO-8859-3 languages - echo "mt CP850" - echo "mt_MT CP850" - # ISO-8859-5 languages - echo "be CP866" - echo "be_BE CP866" - echo "bg CP866" # not CP855 ?? - echo "bg_BG CP866" # not CP855 ?? - echo "mk CP866" # not CP855 ?? - echo "mk_MK CP866" # not CP855 ?? - echo "ru CP866" - echo "ru_RU CP866" - echo "uk CP1125" - echo "uk_UA CP1125" - # ISO-8859-6 languages - echo "ar CP864" - echo "ar_AE CP864" - echo "ar_DZ CP864" - echo "ar_EG CP864" - echo "ar_IQ CP864" - echo "ar_IR CP864" - echo "ar_JO CP864" - echo "ar_KW CP864" - echo "ar_MA CP864" - echo "ar_OM CP864" - echo "ar_QA CP864" - echo "ar_SA CP864" - echo "ar_SY CP864" - # ISO-8859-7 languages - echo "el CP869" - echo "el_GR CP869" - # ISO-8859-8 languages - echo "he CP862" - echo "he_IL CP862" - # ISO-8859-9 languages - echo "tr CP857" - echo "tr_TR CP857" - # Japanese - echo "ja CP932" - echo "ja_JP CP932" - # Chinese - echo "zh_CN GBK" - echo "zh_TW CP950" # not CP938 ?? - # Korean - echo "kr CP949" # not CP934 ?? - echo "kr_KR CP949" # not CP934 ?? - # Thai - echo "th CP874" - echo "th_TH CP874" - # Other - echo "eo CP850" - echo "eo_EO CP850" - ;; -esac diff --git a/glib/libcharset/glibc21.m4 b/glib/libcharset/glibc21.m4 deleted file mode 100644 index d95fd9861..000000000 --- a/glib/libcharset/glibc21.m4 +++ /dev/null @@ -1,30 +0,0 @@ -# glibc21.m4 serial 3 -dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -# Test for the GNU C Library, version 2.1 or newer. -# From Bruno Haible. - -AC_DEFUN([gl_GLIBC21], - [ - AC_CACHE_CHECK(whether we are using the GNU C Library 2.1 or newer, - ac_cv_gnu_library_2_1, - [AC_EGREP_CPP([Lucky GNU user], - [ -#include <features.h> -#ifdef __GNU_LIBRARY__ - #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2) - Lucky GNU user - #endif -#endif - ], - ac_cv_gnu_library_2_1=yes, - ac_cv_gnu_library_2_1=no) - ] - ) - AC_SUBST(GLIBC21) - GLIBC21="$ac_cv_gnu_library_2_1" - ] -) diff --git a/glib/libcharset/libcharset-glib.patch b/glib/libcharset/libcharset-glib.patch deleted file mode 100644 index 358d774cf..000000000 --- a/glib/libcharset/libcharset-glib.patch +++ /dev/null @@ -1,77 +0,0 @@ -# Patch against libcharset version 1.4 ---- libiconv-1.12/libcharset//lib/localcharset.c 2006-10-18 07:55:49.000000000 -0400 -+++ localcharset.c 2008-05-20 18:36:24.000000000 -0400 -@@ -103,8 +103,8 @@ - static const char * volatile charset_aliases; - - /* Return a pointer to the contents of the charset.alias file. */ --static const char * --get_charset_aliases (void) -+const char * -+_g_locale_get_charset_aliases (void) - { - const char *cp; - -@@ -280,14 +280,10 @@ - If the canonical name cannot be determined, the result is a non-canonical - name. */ - --#ifdef STATIC --STATIC --#endif - const char * --locale_charset (void) -+_g_locale_charset_raw (void) - { - const char *codeset; -- const char *aliases; - - #if !(defined WIN32_NATIVE || defined OS2) - -@@ -436,12 +432,20 @@ - - #endif - -+ return codeset; -+} -+ -+const char * -+_g_locale_charset_unalias (const char *codeset) -+{ -+ const char *aliases; -+ - if (codeset == NULL) - /* The canonical name cannot be determined. */ - codeset = ""; - - /* Resolve alias. */ -- for (aliases = get_charset_aliases (); -+ for (aliases = _g_locale_get_charset_aliases (); - *aliases != '\0'; - aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1) - if (strcmp (codeset, aliases) == 0 ---- libiconv-1.12/libcharset//include/libcharset.h.in 2005-05-19 13:14:56.000000000 -0400 -+++ libcharset.h 2008-05-20 18:39:44.000000000 -0400 -@@ -19,7 +19,7 @@ - #ifndef _LIBCHARSET_H - #define _LIBCHARSET_H - --#include <localcharset.h> -+#include "localcharset.h" - - - #ifdef __cplusplus ---- libiconv-1.12/libcharset//include/localcharset.h.in 2005-05-19 13:14:57.000000000 -0400 -+++ localcharset.h 2008-05-20 18:36:24.000000000 -0400 -@@ -31,8 +31,9 @@ - The result must not be freed; it is statically allocated. - If the canonical name cannot be determined, the result is a non-canonical - name. */ --extern const char * locale_charset (void); -- -+extern const char * _g_locale_charset_raw (void); -+extern const char * _g_locale_charset_unalias (const char *codeset); -+extern const char * _g_locale_get_charset_aliases (void); - - #ifdef __cplusplus - } diff --git a/glib/libcharset/libcharset.h b/glib/libcharset/libcharset.h deleted file mode 100644 index 686241e74..000000000 --- a/glib/libcharset/libcharset.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (C) 2003 Free Software Foundation, Inc. - This file is part of the GNU CHARSET Library. - - The GNU CHARSET Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU CHARSET 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with the GNU CHARSET Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 51 Franklin Street, - Fifth Floor, Boston, MA 02110-1301, USA. */ - -#ifndef _LIBCHARSET_H -#define _LIBCHARSET_H - -#include "localcharset.h" - - -#ifdef __cplusplus -extern "C" { -#endif - - -/* Support for relocatable packages. */ - -/* Sets the original and the current installation prefix of the package. - Relocation simply replaces a pathname starting with the original prefix - by the corresponding pathname with the current prefix instead. Both - prefixes should be directory names without trailing slash (i.e. use "" - instead of "/"). */ -extern void libcharset_set_relocation_prefix (const char *orig_prefix, - const char *curr_prefix); - - -#ifdef __cplusplus -} -#endif - - -#endif /* _LIBCHARSET_H */ diff --git a/glib/libcharset/localcharset.c b/glib/libcharset/localcharset.c deleted file mode 100644 index 0d001f94c..000000000 --- a/glib/libcharset/localcharset.c +++ /dev/null @@ -1,465 +0,0 @@ -/* Determine a canonical name for the current locale's character encoding. - - Copyright (C) 2000-2006 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - USA. */ - -/* Written by Bruno Haible <bruno@clisp.org>. */ - -#include "config.h" - -/* Specification. */ -#include "localcharset.h" - -#include <stddef.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -#if defined _WIN32 || defined __WIN32__ -# define WIN32_NATIVE -#endif - -#if defined __EMX__ -/* Assume EMX program runs on OS/2, even if compiled under DOS. */ -# define OS2 -#endif - -#if !defined WIN32_NATIVE -# if HAVE_LANGINFO_CODESET -# include <langinfo.h> -# else -# if 0 /* see comment below */ -# include <locale.h> -# endif -# endif -# ifdef __CYGWIN__ -# define WIN32_LEAN_AND_MEAN -# include <windows.h> -# endif -#elif defined WIN32_NATIVE -# define WIN32_LEAN_AND_MEAN -# include <windows.h> -#endif -#if defined OS2 -# define INCL_DOS -# include <os2.h> -#endif - -#if ENABLE_RELOCATABLE -# include "relocatable.h" -#else -# define relocate(pathname) (pathname) -#endif - -/* Get LIBDIR. */ -#ifndef LIBDIR -# include "configmake.h" -#endif - -#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ - /* Win32, Cygwin, OS/2, DOS */ -# define ISSLASH(C) ((C) == '/' || (C) == '\\') -#endif - -#ifndef DIRECTORY_SEPARATOR -# define DIRECTORY_SEPARATOR '/' -#endif - -#ifndef ISSLASH -# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR) -#endif - -#if HAVE_DECL_GETC_UNLOCKED -# undef getc -# define getc getc_unlocked -#endif - -/* The following static variable is declared 'volatile' to avoid a - possible multithread problem in the function get_charset_aliases. If we - are running in a threaded environment, and if two threads initialize - 'charset_aliases' simultaneously, both will produce the same value, - and everything will be ok if the two assignments to 'charset_aliases' - are atomic. But I don't know what will happen if the two assignments mix. */ -#if __STDC__ != 1 -# define volatile /* empty */ -#endif -/* Pointer to the contents of the charset.alias file, if it has already been - read, else NULL. Its format is: - ALIAS_1 '\0' CANONICAL_1 '\0' ... ALIAS_n '\0' CANONICAL_n '\0' '\0' */ -static const char * volatile charset_aliases; - -/* Return a pointer to the contents of the charset.alias file. */ -const char * -_g_locale_get_charset_aliases (void) -{ - const char *cp; - - cp = charset_aliases; - if (cp == NULL) - { -#if !(defined VMS || defined WIN32_NATIVE || defined __CYGWIN__) - FILE *fp; - const char *dir; - const char *base = "charset.alias"; - char *file_name; - - /* Make it possible to override the charset.alias location. This is - necessary for running the testsuite before "make install". */ - dir = getenv ("CHARSETALIASDIR"); - if (dir == NULL || dir[0] == '\0') - dir = relocate (LIBDIR); - - /* Concatenate dir and base into freshly allocated file_name. */ - { - size_t dir_len = strlen (dir); - size_t base_len = strlen (base); - int add_slash = (dir_len > 0 && !ISSLASH (dir[dir_len - 1])); - file_name = (char *) malloc (dir_len + add_slash + base_len + 1); - if (file_name != NULL) - { - memcpy (file_name, dir, dir_len); - if (add_slash) - file_name[dir_len] = DIRECTORY_SEPARATOR; - memcpy (file_name + dir_len + add_slash, base, base_len + 1); - } - } - - if (file_name == NULL || (fp = fopen (file_name, "r")) == NULL) - /* Out of memory or file not found, treat it as empty. */ - cp = ""; - else - { - /* Parse the file's contents. */ - char *res_ptr = NULL; - size_t res_size = 0; - - for (;;) - { - int c; - char buf1[50+1]; - char buf2[50+1]; - size_t l1, l2; - char *old_res_ptr; - - c = getc (fp); - if (c == EOF) - break; - if (c == '\n' || c == ' ' || c == '\t') - continue; - if (c == '#') - { - /* Skip comment, to end of line. */ - do - c = getc (fp); - while (!(c == EOF || c == '\n')); - if (c == EOF) - break; - continue; - } - ungetc (c, fp); - if (fscanf (fp, "%50s %50s", buf1, buf2) < 2) - break; - l1 = strlen (buf1); - l2 = strlen (buf2); - old_res_ptr = res_ptr; - if (res_size == 0) - { - res_size = l1 + 1 + l2 + 1; - res_ptr = (char *) malloc (res_size + 1); - } - else - { - res_size += l1 + 1 + l2 + 1; - res_ptr = (char *) realloc (res_ptr, res_size + 1); - } - if (res_ptr == NULL) - { - /* Out of memory. */ - res_size = 0; - if (old_res_ptr != NULL) - free (old_res_ptr); - break; - } - strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1); - strcpy (res_ptr + res_size - (l2 + 1), buf2); - } - fclose (fp); - if (res_size == 0) - cp = ""; - else - { - *(res_ptr + res_size) = '\0'; - cp = res_ptr; - } - } - - if (file_name != NULL) - free (file_name); - -#else - -# if defined VMS - /* To avoid the troubles of an extra file charset.alias_vms in the - sources of many GNU packages, simply inline the aliases here. */ - /* The list of encodings is taken from the OpenVMS 7.3-1 documentation - "Compaq C Run-Time Library Reference Manual for OpenVMS systems" - section 10.7 "Handling Different Character Sets". */ - cp = "ISO8859-1" "\0" "ISO-8859-1" "\0" - "ISO8859-2" "\0" "ISO-8859-2" "\0" - "ISO8859-5" "\0" "ISO-8859-5" "\0" - "ISO8859-7" "\0" "ISO-8859-7" "\0" - "ISO8859-8" "\0" "ISO-8859-8" "\0" - "ISO8859-9" "\0" "ISO-8859-9" "\0" - /* Japanese */ - "eucJP" "\0" "EUC-JP" "\0" - "SJIS" "\0" "SHIFT_JIS" "\0" - "DECKANJI" "\0" "DEC-KANJI" "\0" - "SDECKANJI" "\0" "EUC-JP" "\0" - /* Chinese */ - "eucTW" "\0" "EUC-TW" "\0" - "DECHANYU" "\0" "DEC-HANYU" "\0" - "DECHANZI" "\0" "GB2312" "\0" - /* Korean */ - "DECKOREAN" "\0" "EUC-KR" "\0"; -# endif - -# if defined WIN32_NATIVE || defined __CYGWIN__ - /* To avoid the troubles of installing a separate file in the same - directory as the DLL and of retrieving the DLL's directory at - runtime, simply inline the aliases here. */ - - cp = "CP936" "\0" "GBK" "\0" - "CP1361" "\0" "JOHAB" "\0" - "CP20127" "\0" "ASCII" "\0" - "CP20866" "\0" "KOI8-R" "\0" - "CP20936" "\0" "GB2312" "\0" - "CP21866" "\0" "KOI8-RU" "\0" - "CP28591" "\0" "ISO-8859-1" "\0" - "CP28592" "\0" "ISO-8859-2" "\0" - "CP28593" "\0" "ISO-8859-3" "\0" - "CP28594" "\0" "ISO-8859-4" "\0" - "CP28595" "\0" "ISO-8859-5" "\0" - "CP28596" "\0" "ISO-8859-6" "\0" - "CP28597" "\0" "ISO-8859-7" "\0" - "CP28598" "\0" "ISO-8859-8" "\0" - "CP28599" "\0" "ISO-8859-9" "\0" - "CP28605" "\0" "ISO-8859-15" "\0" - "CP38598" "\0" "ISO-8859-8" "\0" - "CP51932" "\0" "EUC-JP" "\0" - "CP51936" "\0" "GB2312" "\0" - "CP51949" "\0" "EUC-KR" "\0" - "CP51950" "\0" "EUC-TW" "\0" - "CP54936" "\0" "GB18030" "\0" - "CP65001" "\0" "UTF-8" "\0"; -# endif -#endif - - charset_aliases = cp; - } - - return cp; -} - -/* Determine the current locale's character encoding, and canonicalize it - into one of the canonical names listed in config.charset. - The result must not be freed; it is statically allocated. - If the canonical name cannot be determined, the result is a non-canonical - name. */ - -const char * -_g_locale_charset_raw (void) -{ - const char *codeset; - -#if !(defined WIN32_NATIVE || defined OS2) - -# if HAVE_LANGINFO_CODESET - - /* Most systems support nl_langinfo (CODESET) nowadays. */ - codeset = nl_langinfo (CODESET); - -# ifdef __CYGWIN__ - /* Cygwin 2006 does not have locales. nl_langinfo (CODESET) always - returns "US-ASCII". As long as this is not fixed, return the suffix - of the locale name from the environment variables (if present) or - the codepage as a number. */ - if (codeset != NULL && strcmp (codeset, "US-ASCII") == 0) - { - const char *locale; - static char buf[2 + 10 + 1]; - - locale = getenv ("LC_ALL"); - if (locale == NULL || locale[0] == '\0') - { - locale = getenv ("LC_CTYPE"); - if (locale == NULL || locale[0] == '\0') - locale = 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) - return dot; - if (modifier - dot < sizeof (buf)) - { - memcpy (buf, dot, modifier - dot); - buf [modifier - dot] = '\0'; - return buf; - } - } - } - - /* Woe32 has a function returning the locale's codepage as a number. */ - sprintf (buf, "CP%u", GetACP ()); - codeset = buf; - } -# endif - -# else - - /* On old systems which lack it, use setlocale or getenv. */ - const char *locale = NULL; - - /* But most old systems don't have a complete set of locales. Some - (like SunOS 4 or DJGPP) have only the C locale. Therefore we don't - use setlocale here; it would return "C" when it doesn't support the - locale name the user has set. */ -# if 0 - locale = setlocale (LC_CTYPE, NULL); -# endif - if (locale == NULL || locale[0] == '\0') - { - locale = getenv ("LC_ALL"); - if (locale == NULL || locale[0] == '\0') - { - locale = getenv ("LC_CTYPE"); - if (locale == NULL || locale[0] == '\0') - locale = getenv ("LANG"); - } - } - - /* On some old systems, one used to set locale = "iso8859_1". On others, - you set it to "language_COUNTRY.charset". In any case, we resolve it - through the charset.alias file. */ - codeset = locale; - -# endif - -#elif defined WIN32_NATIVE - - static char buf[2 + 10 + 1]; - - /* Woe32 has a function returning the locale's codepage as a number. */ - sprintf (buf, "CP%u", GetACP ()); - codeset = buf; - -#elif defined OS2 - - const char *locale; - static char buf[2 + 10 + 1]; - ULONG cp[3]; - ULONG cplen; - - /* Allow user to override the codeset, as set in the operating system, - with standard language environment variables. */ - locale = getenv ("LC_ALL"); - if (locale == NULL || locale[0] == '\0') - { - locale = getenv ("LC_CTYPE"); - if (locale == NULL || locale[0] == '\0') - locale = 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) - return dot; - if (modifier - dot < sizeof (buf)) - { - memcpy (buf, dot, modifier - dot); - buf [modifier - dot] = '\0'; - return buf; - } - } - - /* Resolve through the charset.alias file. */ - codeset = locale; - } - else - { - /* OS/2 has a function returning the locale's codepage as a number. */ - if (DosQueryCp (sizeof (cp), cp, &cplen)) - codeset = ""; - else - { - sprintf (buf, "CP%u", cp[0]); - codeset = buf; - } - } - -#endif - - return codeset; -} - -const char * -_g_locale_charset_unalias (const char *codeset) -{ - const char *aliases; - - if (codeset == NULL) - /* The canonical name cannot be determined. */ - codeset = ""; - - /* Resolve alias. */ - for (aliases = _g_locale_get_charset_aliases (); - *aliases != '\0'; - aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1) - if (strcmp (codeset, aliases) == 0 - || (aliases[0] == '*' && aliases[1] == '\0')) - { - codeset = aliases + strlen (aliases) + 1; - break; - } - - /* Don't return an empty string. GNU libc and GNU libiconv interpret - the empty string as denoting "the locale's character encoding", - thus GNU libiconv would call this function a second time. */ - if (codeset[0] == '\0') - codeset = "ASCII"; - - return codeset; -} diff --git a/glib/libcharset/localcharset.h b/glib/libcharset/localcharset.h deleted file mode 100644 index 674aa3ab7..000000000 --- a/glib/libcharset/localcharset.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Determine a canonical name for the current locale's character encoding. - Copyright (C) 2000-2003 Free Software Foundation, Inc. - This file is part of the GNU CHARSET Library. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - USA. */ - -#ifndef _LOCALCHARSET_H -#define _LOCALCHARSET_H - - -#ifdef __cplusplus -extern "C" { -#endif - - -/* Determine the current locale's character encoding, and canonicalize it - into one of the canonical names listed in config.charset. - The result must not be freed; it is statically allocated. - If the canonical name cannot be determined, the result is a non-canonical - name. */ -extern const char * _g_locale_charset_raw (void); -extern const char * _g_locale_charset_unalias (const char *codeset); -extern const char * _g_locale_get_charset_aliases (void); - -#ifdef __cplusplus -} -#endif - - -#endif /* _LOCALCHARSET_H */ diff --git a/glib/libcharset/make-patch.sh b/glib/libcharset/make-patch.sh deleted file mode 100755 index e60014abd..000000000 --- a/glib/libcharset/make-patch.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh - -if test $# = 1 ; then - ORIGINAL=$1 -else - echo "Usage: make-patch.sh /path/to/libcharset" 1>&2 - exit 1 -fi - -if test -f $ORIGINAL/lib/localcharset.c ; then : ; else - echo "Usage: make-patch.sh /path/to/libcharset" 1>&2 - exit 1 -fi - -VERSION=`grep VERSION= $ORIGINAL/configure.ac | sed s/VERSION=//` - -echo "# Patch against libcharset version $VERSION" > libcharset-glib.patch - -for i in localcharset.c ref-add.sin ref-del.sin ; do - diff -u $ORIGINAL/lib/$i $i >> libcharset-glib.patch -done - -for i in glibc21.m4 codeset.m4 ; do - diff -u $ORIGINAL/m4/$i $i >> libcharset-glib.patch -done - -diff -u $ORIGINAL/include/libcharset.h.in libcharset.h >> libcharset-glib.patch -diff -u $ORIGINAL/include/localcharset.h.in localcharset.h >> libcharset-glib.patch diff --git a/glib/libcharset/ref-add.sin b/glib/libcharset/ref-add.sin deleted file mode 100644 index 0e2b97b05..000000000 --- a/glib/libcharset/ref-add.sin +++ /dev/null @@ -1,31 +0,0 @@ -# Add this package to a list of references stored in a text file. -# -# Copyright (C) 2000 Free Software Foundation, Inc. -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Library General Public License as published -# by the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program 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 -# Library General Public License for more details. -# -# You should have received a copy of the GNU Library General Public -# License along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -# USA. -# -# Written by Bruno Haible <bruno@clisp.org>. -# -/^# Packages using this file: / { - s/# Packages using this file:// - ta - :a - s/ @PACKAGE@ / @PACKAGE@ / - tb - s/ $/ @PACKAGE@ / - :b - s/^/# Packages using this file:/ -} diff --git a/glib/libcharset/ref-del.sin b/glib/libcharset/ref-del.sin deleted file mode 100644 index 1fafbfc02..000000000 --- a/glib/libcharset/ref-del.sin +++ /dev/null @@ -1,26 +0,0 @@ -# Remove this package from a list of references stored in a text file. -# -# Copyright (C) 2000 Free Software Foundation, Inc. -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Library General Public License as published -# by the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program 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 -# Library General Public License for more details. -# -# You should have received a copy of the GNU Library General Public -# License along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -# USA. -# -# Written by Bruno Haible <bruno@clisp.org>. -# -/^# Packages using this file: / { - s/# Packages using this file:// - s/ @PACKAGE@ / / - s/^/# Packages using this file:/ -} diff --git a/glib/libcharset/update.sh b/glib/libcharset/update.sh deleted file mode 100755 index 5873fc768..000000000 --- a/glib/libcharset/update.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh - -if test $# = 1 ; then - ORIGINAL=$1 -else - echo "Usage: update.sh /path/to/libcharset" 1>&2 - exit 1 -fi - -if test -f $ORIGINAL/lib/localcharset.c ; then : ; else - echo "Usage: update.sh /path/to/libcharset" 1>&2 - exit 1 -fi - -VERSION=`grep VERSION= $ORIGINAL/configure.ac | sed s/VERSION=//` - -for i in localcharset.c ref-add.sin ref-del.sin config.charset ; do - cp $ORIGINAL/lib/$i . -done - -for i in libcharset.h localcharset.h ; do - cp $ORIGINAL/include/$i.in ./$i -done - -for i in codeset.m4 glibc21.m4 ; do - cp $ORIGINAL/m4/$i . -done - -patch -p0 < libcharset-glib.patch - -echo "dnl From libcharset $VERSION" > ../../aclibcharset.m4 - - diff --git a/glib/makefile.msc.in b/glib/makefile.msc.in deleted file mode 100644 index ebaeff308..000000000 --- a/glib/makefile.msc.in +++ /dev/null @@ -1,141 +0,0 @@ -## Makefile for building the GLib dlls with Microsoft C -## Use: nmake -f makefile.msc - -TOP = ..\.. - -!INCLUDE ..\build\win32\make.msc - -################################################################ - -INCLUDES = -FImsvc_recommended_pragmas.h -I . -I .. -DEFINES = -DHAVE_CONFIG_H -DGLIB_COMPILATION -DG_LOG_DOMAIN=\"GLib\" -DG_ENABLE_DEBUG -DPCRE_STATIC -DEPCFLAGS = -Zm400 $(INTL_CFLAGS) $(DIRENT_CFLAGS) - -all : \ - ..\config.h \ - ..\glibconfig.h \ - galias.h \ - galiasdef.c \ - gnulib\gnulib.lib \ - pcre\pcre.lib \ - libglib-2.0-0.dll \ - glib-@GLIB_MAJOR_VERSION@.@GLIB_MINOR_VERSION@s.lib \ - gspawn-win32-helper.exe \ - - -gnulib\gnulib.lib : - cd gnulib - nmake -f makefile.msc - cd .. - -pcre\pcre.lib : - cd pcre - nmake -f makefile.msc - cd .. - -glib_OBJECTS = \ - garray.obj \ - gasyncqueue.obj \ - gatomic.obj \ - gbacktrace.obj \ - gbase64.obj \ - gbookmarkfile.obj \ - gcache.obj \ - gchecksum.obj \ - gcompletion.obj \ - gconvert.obj \ - gdataset.obj \ - gdate.obj \ - gdir.obj \ - gerror.obj \ - gfileutils.obj \ - ghash.obj \ - ghook.obj \ - giochannel.obj \ - giowin32.obj \ - gkeyfile.obj \ - glist.obj \ - gmain.obj \ - gmappedfile.obj \ - gmarkup.obj \ - gmem.obj \ - gmessages.obj \ - gnode.obj \ - goption.obj \ - gpattern.obj \ - gprimes.obj \ - gprintf.obj \ - gqsort.obj \ - gqueue.obj \ - grand.obj \ - gregex.obj \ - grel.obj \ - gscanner.obj \ - gsequence.obj \ - gshell.obj \ - gslice.obj \ - gslist.obj \ - gspawn-win32.obj \ - gstdio.obj \ - gstrfuncs.obj \ - gstring.obj \ - gtestutils.obj \ - gthread.obj \ - gthreadpool.obj \ - gtimer.obj \ - gtree.obj \ - gunibreak.obj \ - gunicollate.obj \ - gunidecomp.obj \ - guniprop.obj \ - gurifuncs.obj \ - gutf8.obj \ - gutils.obj \ - gwin32.obj \ - localcharset.obj - -..\glibconfig.h: ..\glibconfig.h.win32 - copy ..\glibconfig.h.win32 ..\glibconfig.h - -..\config.h: ..\config.h.win32 - copy ..\config.h.win32 ..\config.h - -galias.h: glib.symbols - perl makegalias.pl < glib.symbols > galias.h - -galiasdef.c: glib.symbols - perl makegalias.pl -def < glib.symbols > galiasdef.c - -localcharset.c : libcharset/localcharset.c - copy libcharset\localcharset.c localcharset.c - -glib.def: glib.symbols - echo EXPORTS > glib.def - cl /EP -DINCLUDE_VARIABLES -DG_OS_WIN32 -DINCLUDE_INTERNAL_SYMBOLS -DALL_FILES \ - -DG_GNUC_MALLOC= -DG_GNUC_CONST= -DG_GNUC_NULL_TERMINATED= -DG_GNUC_NORETURN= \ - -DG_GNUC_PRINTF=;G_GNUC_PRINTF glib.symbols >> glib.def - -glib.res : glib.rc - rc -DBUILDNUMBER=0 -r -fo glib.res glib.rc - -################ glib - -# create a static libary -# static library can well have the real version number in the name -glib-@GLIB_MAJOR_VERSION@.@GLIB_MINOR_VERSION@s.lib : $(glib_OBJECTS) gnulib\gnulib.lib pcre\pcre.lib - lib /out:glib-@GLIB_MAJOR_VERSION@.@GLIB_MINOR_VERSION@s.lib $(glib_OBJECTS) gnulib\gnulib.lib pcre\pcre.lib - -libglib-2.0-0.dll : $(glib_OBJECTS) gnulib\gnulib.lib pcre\pcre.lib glib.def glib.res - $(CC) $(CFLAGS) -LD -Fe$@ $(glib_OBJECTS) glib.res $(INTL_LIBS) \ - gnulib\gnulib.lib pcre\pcre.lib $(DIRENT_LIBS) user32.lib advapi32.lib shell32.lib wsock32.lib ole32.lib ws2_32.lib \ - $(LDFLAGS) /implib:glib-2.0.lib /def:glib.def - -gspawn-win32-helper.exe : gspawn-win32-helper.c libglib-2.0-@LT_CURRENT_MINUS_AGE@.dll - $(CC) $(CFLAGS) -Fe$@ -DG_LOG_DOMAIN=\"gspawn-win32-helper\" gspawn-win32-helper.c glib-2.0.lib $(LDFLAGS) /subsystem:windows user32.lib - -################ other stuff - -clean:: - del ..\config.h - del ..\glibconfig.h - diff --git a/glib/makegalias.pl b/glib/makegalias.pl deleted file mode 100755 index 622026a91..000000000 --- a/glib/makegalias.pl +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/perl -w - -my $do_def = 0; - -if (($#ARGV >= 0) && ($ARGV[0] eq "-def")) { - shift; - $do_def = 1; -} - -print <<EOF; -/* Generated by makegalias.pl */ - -#ifndef DISABLE_VISIBILITY - -#include "glibconfig.h" - -#ifdef G_HAVE_GNUC_VISIBILITY - -EOF - -if ($do_def) { - print <<EOF -#undef IN_FILE -#define IN_FILE defined - -#undef IN_HEADER -#define IN_HEADER(x) 1 - -EOF -} -else { - print <<EOF -#define IN_FILE(x) 1 -#define IN_HEADER defined - -EOF -} - -my $in_comment = 0; -my $in_skipped_section = 0; - -while (<>) { - - # ignore empty lines - next if /^\s*$/; - - # skip comments - if ($_ =~ /^\s*\/\*/) - { - $in_comment = 1; - } - - if ($in_comment) - { - if ($_ =~ /\*\/\s$/) - { - $in_comment = 0; - } - - next; - } - - # handle ifdefs - if ($_ =~ /^\#endif/) - { - if (!$in_skipped_section) - { - print $_; - } - - $in_skipped_section = 0; - - next; - } - - if ($_ =~ /^\#ifdef\s+(INCLUDE_VARIABLES|INCLUDE_INTERNAL_SYMBOLS|ALL_FILES)/) - { - $in_skipped_section = 1; - } - - if ($in_skipped_section) - { - next; - } - - if ($_ =~ /^\#ifn?def\s+(G|DISABLE_MEM_POOLS|_WIN64)/) - { - print $_; - - next; - } - - if ($_ =~ /^\#if.*(G_STDIO_NO_WRAP_ON_UNIX|IN_FILE|IN_HEADER|IN_FILE)/) - { - print $_; - - next; - } - - chop; - my $str = $_; - my @words; - my $attributes = ""; - - @words = split(/ /, $str); - $str = shift(@words); - chomp($str); - my $alias = "IA__".$str; - - # Drop any Win32 specific .def file syntax, but keep attributes - foreach $word (@words) { - $attributes = "$attributes $word" unless $word eq "PRIVATE"; - } - - if (!$do_def) { - print <<EOF -extern __typeof ($str) $alias __attribute((visibility("hidden")))$attributes; -\#define $str $alias - -EOF - } - else { - print <<EOF -\#undef $str -extern __typeof ($str) $str __attribute((alias("$alias"), visibility("default"))); - -EOF - } -} - -print <<EOF - -#endif /* G_HAVE_GNUC_VISIBILITY */ -#endif /* DISABLE_VISIBILITY */ -EOF - diff --git a/glib/pcre/COPYING b/glib/pcre/COPYING deleted file mode 100644 index 58eed01b6..000000000 --- a/glib/pcre/COPYING +++ /dev/null @@ -1,5 +0,0 @@ -PCRE LICENCE - -Please see the file LICENCE in the PCRE distribution for licensing details. - -End diff --git a/glib/pcre/Makefile.am b/glib/pcre/Makefile.am deleted file mode 100644 index b01c44f4d..000000000 --- a/glib/pcre/Makefile.am +++ /dev/null @@ -1,66 +0,0 @@ -include $(top_srcdir)/Makefile.decl - -INCLUDES = \ - -DG_LOG_DOMAIN=\"GLib-GRegex\" \ - -DSUPPORT_UCP \ - -DSUPPORT_UTF8 \ - -DNEWLINE=-1 \ - -DMATCH_LIMIT=10000000 \ - -DMATCH_LIMIT_RECURSION=8192 \ - -DMAX_NAME_SIZE=32 \ - -DMAX_NAME_COUNT=10000 \ - -DMAX_DUPLENGTH=30000 \ - -DLINK_SIZE=2 \ - -DPOSIX_MALLOC_THRESHOLD=10 \ - -DPCRE_STATIC \ - -I$(top_srcdir) \ - -I$(srcdir) \ - -I$(top_srcdir)/glib \ - -I$(top_builddir)/glib \ - @GLIB_DEBUG_FLAGS@ \ - -DG_DISABLE_DEPRECATED \ - -DGLIB_COMPILATION \ - $(DEPRECATED_FLAGS)\ - $(WARN_CFLAGS) \ - $(PCRE_WARN_CFLAGS) \ - $(DEP_CFLAGS) - -noinst_LTLIBRARIES = libpcre.la - -libpcre_headers = - -libpcre_la_SOURCES = \ - pcre_compile.c \ - pcre_chartables.c \ - pcre_config.c \ - pcre_dfa_exec.c \ - pcre_exec.c \ - pcre_fullinfo.c \ - pcre_get.c \ - pcre_globals.c \ - pcre_info.c \ - pcre_maketables.c \ - pcre_newline.c \ - pcre_ord2utf8.c \ - pcre_refcount.c \ - pcre_study.c \ - pcre_tables.c \ - pcre_try_flipped.c \ - pcre_ucp_searchfuncs.c \ - pcre_valid_utf8.c \ - pcre_version.c \ - pcre_xclass.c \ - pcre.h \ - pcre_internal.h \ - ucp.h \ - ucpinternal.h \ - $(libpcre_headers) - -libpcre_la_LIBADD = $(DEP_LIBS) - -libpcre_la_LDFLAGS = -no-undefined - -EXTRA_DIST += \ - COPYING \ - makefile.msc - diff --git a/glib/pcre/makefile.msc b/glib/pcre/makefile.msc deleted file mode 100644 index 1ec1d72c8..000000000 --- a/glib/pcre/makefile.msc +++ /dev/null @@ -1,30 +0,0 @@ -TOP = ..\..\.. -!INCLUDE ..\..\build\win32\make.msc - -INCLUDES = \ - -I ..\.. \ - -I .. - -DEFINES = \ - -DPCRE_STATIC \ - -DHAVE_CONFIG_H \ - -DHAVE_LONG_LONG_FORMAT \ - -DSUPPORT_UCP \ - -DSUPPORT_UTF8 \ - -DNEWLINE=-1 \ - -DMATCH_LIMIT=10000000 \ - -DMATCH_LIMIT_RECURSION=10000000 \ - -DMAX_NAME_SIZE=32 \ - -DMAX_NAME_COUNT=10000 \ - -DMAX_DUPLENGTH=30000 \ - -DLINK_SIZE=2 \ - -DEBCDIC=0 \ - -DPOSIX_MALLOC_THRESHOLD=10 - -OBJECTS = \ - - -all : pcre.lib - -pcre.lib : $(OBJECTS) - lib -out:pcre.lib $(OBJECTS) diff --git a/glib/pcre/pcre.h b/glib/pcre/pcre.h deleted file mode 100644 index 8fc80a70e..000000000 --- a/glib/pcre/pcre.h +++ /dev/null @@ -1,293 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* This is the public header file for the PCRE library, to be #included by -applications that call the PCRE functions. - - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - -#ifndef _PCRE_H -#define _PCRE_H - -/* The current PCRE version information. */ - -#define PCRE_MAJOR 7 -#define PCRE_MINOR 8 -#define PCRE_PRERELEASE -#define PCRE_DATE 2008-09-05 - -/* When an application links to a PCRE DLL in Windows, the symbols that are -imported have to be identified as such. When building PCRE, the appropriate -export setting is defined in pcre_internal.h, which includes this file. So we -don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL. */ - -#if defined(_WIN32) && !defined(PCRE_STATIC) -# ifndef PCRE_EXP_DECL -# define PCRE_EXP_DECL extern __declspec(dllimport) -# endif -# ifdef __cplusplus -# ifndef PCRECPP_EXP_DECL -# define PCRECPP_EXP_DECL extern __declspec(dllimport) -# endif -# ifndef PCRECPP_EXP_DEFN -# define PCRECPP_EXP_DEFN __declspec(dllimport) -# endif -# endif -#endif - -/* By default, we use the standard "extern" declarations. */ - -#ifndef PCRE_EXP_DECL -# ifdef __cplusplus -# define PCRE_EXP_DECL extern "C" -# else -# define PCRE_EXP_DECL extern -# endif -#endif - -#ifdef __cplusplus -# ifndef PCRECPP_EXP_DECL -# define PCRECPP_EXP_DECL extern -# endif -# ifndef PCRECPP_EXP_DEFN -# define PCRECPP_EXP_DEFN -# endif -#endif - -/* Have to include stdlib.h in order to ensure that size_t is defined; -it is needed here for malloc. */ - -#include <stdlib.h> - -/* Allow for C++ users */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Options */ - -#define PCRE_CASELESS 0x00000001 -#define PCRE_MULTILINE 0x00000002 -#define PCRE_DOTALL 0x00000004 -#define PCRE_EXTENDED 0x00000008 -#define PCRE_ANCHORED 0x00000010 -#define PCRE_DOLLAR_ENDONLY 0x00000020 -#define PCRE_EXTRA 0x00000040 -#define PCRE_NOTBOL 0x00000080 -#define PCRE_NOTEOL 0x00000100 -#define PCRE_UNGREEDY 0x00000200 -#define PCRE_NOTEMPTY 0x00000400 -#define PCRE_UTF8 0x00000800 -#define PCRE_NO_AUTO_CAPTURE 0x00001000 -#define PCRE_NO_UTF8_CHECK 0x00002000 -#define PCRE_AUTO_CALLOUT 0x00004000 -#define PCRE_PARTIAL 0x00008000 -#define PCRE_DFA_SHORTEST 0x00010000 -#define PCRE_DFA_RESTART 0x00020000 -#define PCRE_FIRSTLINE 0x00040000 -#define PCRE_DUPNAMES 0x00080000 -#define PCRE_NEWLINE_CR 0x00100000 -#define PCRE_NEWLINE_LF 0x00200000 -#define PCRE_NEWLINE_CRLF 0x00300000 -#define PCRE_NEWLINE_ANY 0x00400000 -#define PCRE_NEWLINE_ANYCRLF 0x00500000 -#define PCRE_BSR_ANYCRLF 0x00800000 -#define PCRE_BSR_UNICODE 0x01000000 -#define PCRE_JAVASCRIPT_COMPAT 0x02000000 - -/* Exec-time and get/set-time error codes */ - -#define PCRE_ERROR_NOMATCH (-1) -#define PCRE_ERROR_NULL (-2) -#define PCRE_ERROR_BADOPTION (-3) -#define PCRE_ERROR_BADMAGIC (-4) -#define PCRE_ERROR_UNKNOWN_OPCODE (-5) -#define PCRE_ERROR_UNKNOWN_NODE (-5) /* For backward compatibility */ -#define PCRE_ERROR_NOMEMORY (-6) -#define PCRE_ERROR_NOSUBSTRING (-7) -#define PCRE_ERROR_MATCHLIMIT (-8) -#define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */ -#define PCRE_ERROR_BADUTF8 (-10) -#define PCRE_ERROR_BADUTF8_OFFSET (-11) -#define PCRE_ERROR_PARTIAL (-12) -#define PCRE_ERROR_BADPARTIAL (-13) -#define PCRE_ERROR_INTERNAL (-14) -#define PCRE_ERROR_BADCOUNT (-15) -#define PCRE_ERROR_DFA_UITEM (-16) -#define PCRE_ERROR_DFA_UCOND (-17) -#define PCRE_ERROR_DFA_UMLIMIT (-18) -#define PCRE_ERROR_DFA_WSSIZE (-19) -#define PCRE_ERROR_DFA_RECURSE (-20) -#define PCRE_ERROR_RECURSIONLIMIT (-21) -#define PCRE_ERROR_NULLWSLIMIT (-22) /* No longer actually used */ -#define PCRE_ERROR_BADNEWLINE (-23) - -/* Request types for pcre_fullinfo() */ - -#define PCRE_INFO_OPTIONS 0 -#define PCRE_INFO_SIZE 1 -#define PCRE_INFO_CAPTURECOUNT 2 -#define PCRE_INFO_BACKREFMAX 3 -#define PCRE_INFO_FIRSTBYTE 4 -#define PCRE_INFO_FIRSTCHAR 4 /* For backwards compatibility */ -#define PCRE_INFO_FIRSTTABLE 5 -#define PCRE_INFO_LASTLITERAL 6 -#define PCRE_INFO_NAMEENTRYSIZE 7 -#define PCRE_INFO_NAMECOUNT 8 -#define PCRE_INFO_NAMETABLE 9 -#define PCRE_INFO_STUDYSIZE 10 -#define PCRE_INFO_DEFAULT_TABLES 11 -#define PCRE_INFO_OKPARTIAL 12 -#define PCRE_INFO_JCHANGED 13 -#define PCRE_INFO_HASCRORLF 14 - -/* Request types for pcre_config(). Do not re-arrange, in order to remain -compatible. */ - -#define PCRE_CONFIG_UTF8 0 -#define PCRE_CONFIG_NEWLINE 1 -#define PCRE_CONFIG_LINK_SIZE 2 -#define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3 -#define PCRE_CONFIG_MATCH_LIMIT 4 -#define PCRE_CONFIG_STACKRECURSE 5 -#define PCRE_CONFIG_UNICODE_PROPERTIES 6 -#define PCRE_CONFIG_MATCH_LIMIT_RECURSION 7 -#define PCRE_CONFIG_BSR 8 - -/* Bit flags for the pcre_extra structure. Do not re-arrange or redefine -these bits, just add new ones on the end, in order to remain compatible. */ - -#define PCRE_EXTRA_STUDY_DATA 0x0001 -#define PCRE_EXTRA_MATCH_LIMIT 0x0002 -#define PCRE_EXTRA_CALLOUT_DATA 0x0004 -#define PCRE_EXTRA_TABLES 0x0008 -#define PCRE_EXTRA_MATCH_LIMIT_RECURSION 0x0010 - -/* Types */ - -struct real_pcre; /* declaration; the definition is private */ -typedef struct real_pcre pcre; - -/* When PCRE is compiled as a C++ library, the subject pointer type can be -replaced with a custom type. For conventional use, the public interface is a -const char *. */ - -#ifndef PCRE_SPTR -#define PCRE_SPTR const char * -#endif - -/* The structure for passing additional data to pcre_exec(). This is defined in -such as way as to be extensible. Always add new fields at the end, in order to -remain compatible. */ - -typedef struct pcre_extra { - unsigned long int flags; /* Bits for which fields are set */ - void *study_data; /* Opaque data from pcre_study() */ - unsigned long int match_limit; /* Maximum number of calls to match() */ - void *callout_data; /* Data passed back in callouts */ - const unsigned char *tables; /* Pointer to character tables */ - unsigned long int match_limit_recursion; /* Max recursive calls to match() */ -} pcre_extra; - -/* The structure for passing out data via the pcre_callout_function. We use a -structure so that new fields can be added on the end in future versions, -without changing the API of the function, thereby allowing old clients to work -without modification. */ - -typedef struct pcre_callout_block { - int version; /* Identifies version of block */ - /* ------------------------ Version 0 ------------------------------- */ - int callout_number; /* Number compiled into pattern */ - int *offset_vector; /* The offset vector */ - PCRE_SPTR subject; /* The subject being matched */ - int subject_length; /* The length of the subject */ - int start_match; /* Offset to start of this match attempt */ - int current_position; /* Where we currently are in the subject */ - int capture_top; /* Max current capture */ - int capture_last; /* Most recently closed capture */ - void *callout_data; /* Data passed in with the call */ - /* ------------------- Added for Version 1 -------------------------- */ - int pattern_position; /* Offset to next item in the pattern */ - int next_item_length; /* Length of next item in the pattern */ - /* ------------------------------------------------------------------ */ -} pcre_callout_block; - -#include "glib.h" -#include "galias.h" - -#define pcre_malloc g_try_malloc -#define pcre_free g_free -#define pcre_stack_malloc g_try_malloc - -PCRE_EXP_DECL int (*pcre_callout)(pcre_callout_block *); - -/* Exported PCRE functions */ - -PCRE_EXP_DECL pcre *pcre_compile(const char *, int, const char **, int *, - const unsigned char *); -PCRE_EXP_DECL pcre *pcre_compile2(const char *, int, int *, const char **, - int *, const unsigned char *); -PCRE_EXP_DECL int pcre_config(int, void *); -PCRE_EXP_DECL int pcre_copy_named_substring(const pcre *, const char *, - int *, int, const char *, char *, int); -PCRE_EXP_DECL int pcre_copy_substring(const char *, int *, int, int, char *, - int); -PCRE_EXP_DECL int pcre_dfa_exec(const pcre *, const pcre_extra *, - const char *, int, int, int, int *, int , int *, int); -PCRE_EXP_DECL int pcre_exec(const pcre *, const pcre_extra *, PCRE_SPTR, - int, int, int, int *, int); -PCRE_EXP_DECL void pcre_free_substring(const char *); -PCRE_EXP_DECL void pcre_free_substring_list(const char **); -PCRE_EXP_DECL int pcre_fullinfo(const pcre *, const pcre_extra *, int, - void *); -PCRE_EXP_DECL int pcre_get_named_substring(const pcre *, const char *, - int *, int, const char *, const char **); -PCRE_EXP_DECL int pcre_get_stringnumber(const pcre *, const char *); -PCRE_EXP_DECL int pcre_get_stringtable_entries(const pcre *, const char *, - char **, char **); -PCRE_EXP_DECL int pcre_get_substring(const char *, int *, int, int, - const char **); -PCRE_EXP_DECL int pcre_get_substring_list(const char *, int *, int, - const char ***); -PCRE_EXP_DECL int pcre_info(const pcre *, int *, int *); -PCRE_EXP_DECL const unsigned char *pcre_maketables(void); -PCRE_EXP_DECL int pcre_refcount(pcre *, int); -PCRE_EXP_DECL pcre_extra *pcre_study(const pcre *, int, const char **); -PCRE_EXP_DECL const char *pcre_version(void); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* End of pcre.h */ diff --git a/glib/pcre/pcre_chartables.c b/glib/pcre/pcre_chartables.c deleted file mode 100644 index ae45db0ca..000000000 --- a/glib/pcre/pcre_chartables.c +++ /dev/null @@ -1,198 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* This file contains character tables that are used when no external tables -are passed to PCRE by the application that calls it. The tables are used only -for characters whose code values are less than 256. - -This is a default version of the tables that assumes ASCII encoding. A program -called dftables (which is distributed with PCRE) can be used to build -alternative versions of this file. This is necessary if you are running in an -EBCDIC environment, or if you want to default to a different encoding, for -example ISO-8859-1. When dftables is run, it creates these tables in the -current locale. If PCRE is configured with --enable-rebuild-chartables, this -happens automatically. - -The following #includes are present because without the gcc 4.x may remove the -array definition from the final binary if PCRE is built into a static library -and dead code stripping is activated. This leads to link errors. Pulling in the -header ensures that the array gets flagged as "someone outside this compilation -unit might reference this" and so it will always be supplied to the linker. */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre_internal.h" - -const unsigned char _pcre_default_tables[] = { - -/* This table is a lower casing table. */ - - 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, 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, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - 64, 97, 98, 99,100,101,102,103, - 104,105,106,107,108,109,110,111, - 112,113,114,115,116,117,118,119, - 120,121,122, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103, - 104,105,106,107,108,109,110,111, - 112,113,114,115,116,117,118,119, - 120,121,122,123,124,125,126,127, - 128,129,130,131,132,133,134,135, - 136,137,138,139,140,141,142,143, - 144,145,146,147,148,149,150,151, - 152,153,154,155,156,157,158,159, - 160,161,162,163,164,165,166,167, - 168,169,170,171,172,173,174,175, - 176,177,178,179,180,181,182,183, - 184,185,186,187,188,189,190,191, - 192,193,194,195,196,197,198,199, - 200,201,202,203,204,205,206,207, - 208,209,210,211,212,213,214,215, - 216,217,218,219,220,221,222,223, - 224,225,226,227,228,229,230,231, - 232,233,234,235,236,237,238,239, - 240,241,242,243,244,245,246,247, - 248,249,250,251,252,253,254,255, - -/* This table is a case flipping table. */ - - 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, 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, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - 64, 97, 98, 99,100,101,102,103, - 104,105,106,107,108,109,110,111, - 112,113,114,115,116,117,118,119, - 120,121,122, 91, 92, 93, 94, 95, - 96, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90,123,124,125,126,127, - 128,129,130,131,132,133,134,135, - 136,137,138,139,140,141,142,143, - 144,145,146,147,148,149,150,151, - 152,153,154,155,156,157,158,159, - 160,161,162,163,164,165,166,167, - 168,169,170,171,172,173,174,175, - 176,177,178,179,180,181,182,183, - 184,185,186,187,188,189,190,191, - 192,193,194,195,196,197,198,199, - 200,201,202,203,204,205,206,207, - 208,209,210,211,212,213,214,215, - 216,217,218,219,220,221,222,223, - 224,225,226,227,228,229,230,231, - 232,233,234,235,236,237,238,239, - 240,241,242,243,244,245,246,247, - 248,249,250,251,252,253,254,255, - -/* This table contains bit maps for various character classes. Each map is 32 -bytes long and the bits run from the least significant end of each byte. The -classes that have their own maps are: space, xdigit, digit, upper, lower, word, -graph, print, punct, and cntrl. Other classes are built from combinations. */ - - 0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, - 0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, - 0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc, - 0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - -/* This table identifies various classes of character by individual bits: - 0x01 white space character - 0x02 letter - 0x04 decimal digit - 0x08 hexadecimal digit - 0x10 alphanumeric or '_' - 0x80 regular expression metacharacter or binary zero -*/ - - 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ - 0x00,0x01,0x01,0x00,0x01,0x01,0x00,0x00, /* 8- 15 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ - 0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /* - ' */ - 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /* ( - / */ - 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */ - 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /* 8 - ? */ - 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* @ - G */ - 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* H - O */ - 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* P - W */ - 0x12,0x12,0x12,0x80,0x80,0x00,0x80,0x10, /* X - _ */ - 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* ` - g */ - 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* h - o */ - 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* p - w */ - 0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /* x -127 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */ - -/* End of pcre_chartables.c */ diff --git a/glib/pcre/pcre_compile.c b/glib/pcre/pcre_compile.c deleted file mode 100644 index ae68fb566..000000000 --- a/glib/pcre/pcre_compile.c +++ /dev/null @@ -1,6258 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains the external function pcre_compile(), along with -supporting internal functions that are not used by other modules. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define NLBLOCK cd /* Block containing newline information */ -#define PSSTART start_pattern /* Field containing processed string start */ -#define PSEND end_pattern /* Field containing processed string end */ - -#include "pcre_internal.h" - - -/* When DEBUG is defined, we need the pcre_printint() function, which is also -used by pcretest. DEBUG is not defined when building a production library. */ - -#ifdef DEBUG -#include "pcre_printint.src" -#endif - - -/* Macro for setting individual bits in class bitmaps. */ - -#define SETBIT(a,b) a[b/8] |= (1 << (b%8)) - -/* Maximum length value to check against when making sure that the integer that -holds the compiled pattern length does not overflow. We make it a bit less than -INT_MAX to allow for adding in group terminating bytes, so that we don't have -to check them every time. */ - -#define OFLOW_MAX (INT_MAX - 20) - - -/************************************************* -* Code parameters and static tables * -*************************************************/ - -/* This value specifies the size of stack workspace that is used during the -first pre-compile phase that determines how much memory is required. The regex -is partly compiled into this space, but the compiled parts are discarded as -soon as they can be, so that hopefully there will never be an overrun. The code -does, however, check for an overrun. The largest amount I've seen used is 218, -so this number is very generous. - -The same workspace is used during the second, actual compile phase for -remembering forward references to groups so that they can be filled in at the -end. Each entry in this list occupies LINK_SIZE bytes, so even when LINK_SIZE -is 4 there is plenty of room. */ - -#define COMPILE_WORK_SIZE (4096) - - -/* Table for handling escaped characters in the range '0'-'z'. Positive returns -are simple data values; negative values are for special things like \d and so -on. Zero means further processing is needed (for things like \x), or the escape -is invalid. */ - -#ifndef EBCDIC /* This is the "normal" table for ASCII systems */ -static const short int escapes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */ - 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */ - '@', -ESC_A, -ESC_B, -ESC_C, -ESC_D, -ESC_E, 0, -ESC_G, /* @ - G */ --ESC_H, 0, 0, -ESC_K, 0, 0, 0, 0, /* H - O */ --ESC_P, -ESC_Q, -ESC_R, -ESC_S, 0, 0, -ESC_V, -ESC_W, /* P - W */ --ESC_X, 0, -ESC_Z, '[', '\\', ']', '^', '_', /* X - _ */ - '`', 7, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, /* ` - g */ --ESC_h, 0, 0, -ESC_k, 0, 0, ESC_n, 0, /* h - o */ --ESC_p, 0, ESC_r, -ESC_s, ESC_tee, 0, -ESC_v, -ESC_w, /* p - w */ - 0, 0, -ESC_z /* x - z */ -}; - -#else /* This is the "abnormal" table for EBCDIC systems */ -static const short int escapes[] = { -/* 48 */ 0, 0, 0, '.', '<', '(', '+', '|', -/* 50 */ '&', 0, 0, 0, 0, 0, 0, 0, -/* 58 */ 0, 0, '!', '$', '*', ')', ';', '~', -/* 60 */ '-', '/', 0, 0, 0, 0, 0, 0, -/* 68 */ 0, 0, '|', ',', '%', '_', '>', '?', -/* 70 */ 0, 0, 0, 0, 0, 0, 0, 0, -/* 78 */ 0, '`', ':', '#', '@', '\'', '=', '"', -/* 80 */ 0, 7, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, -/* 88 */-ESC_h, 0, 0, '{', 0, 0, 0, 0, -/* 90 */ 0, 0, -ESC_k, 'l', 0, ESC_n, 0, -ESC_p, -/* 98 */ 0, ESC_r, 0, '}', 0, 0, 0, 0, -/* A0 */ 0, '~', -ESC_s, ESC_tee, 0,-ESC_v, -ESC_w, 0, -/* A8 */ 0,-ESC_z, 0, 0, 0, '[', 0, 0, -/* B0 */ 0, 0, 0, 0, 0, 0, 0, 0, -/* B8 */ 0, 0, 0, 0, 0, ']', '=', '-', -/* C0 */ '{',-ESC_A, -ESC_B, -ESC_C, -ESC_D,-ESC_E, 0, -ESC_G, -/* C8 */-ESC_H, 0, 0, 0, 0, 0, 0, 0, -/* D0 */ '}', 0, -ESC_K, 0, 0, 0, 0, -ESC_P, -/* D8 */-ESC_Q,-ESC_R, 0, 0, 0, 0, 0, 0, -/* E0 */ '\\', 0, -ESC_S, 0, 0,-ESC_V, -ESC_W, -ESC_X, -/* E8 */ 0,-ESC_Z, 0, 0, 0, 0, 0, 0, -/* F0 */ 0, 0, 0, 0, 0, 0, 0, 0, -/* F8 */ 0, 0, 0, 0, 0, 0, 0, 0 -}; -#endif - - -/* Table of special "verbs" like (*PRUNE). This is a short table, so it is -searched linearly. Put all the names into a single string, in order to reduce -the number of relocations when a shared library is dynamically linked. */ - -typedef struct verbitem { - int len; - int op; -} verbitem; - -static const char verbnames[] = - "ACCEPT\0" - "COMMIT\0" - "F\0" - "FAIL\0" - "PRUNE\0" - "SKIP\0" - "THEN"; - -static const verbitem verbs[] = { - { 6, OP_ACCEPT }, - { 6, OP_COMMIT }, - { 1, OP_FAIL }, - { 4, OP_FAIL }, - { 5, OP_PRUNE }, - { 4, OP_SKIP }, - { 4, OP_THEN } -}; - -static const int verbcount = sizeof(verbs)/sizeof(verbitem); - - -/* Tables of names of POSIX character classes and their lengths. The names are -now all in a single string, to reduce the number of relocations when a shared -library is dynamically loaded. The list of lengths is terminated by a zero -length entry. The first three must be alpha, lower, upper, as this is assumed -for handling case independence. */ - -static const char posix_names[] = - "alpha\0" "lower\0" "upper\0" "alnum\0" "ascii\0" "blank\0" - "cntrl\0" "digit\0" "graph\0" "print\0" "punct\0" "space\0" - "word\0" "xdigit"; - -static const uschar posix_name_lengths[] = { - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 }; - -/* Table of class bit maps for each POSIX class. Each class is formed from a -base map, with an optional addition or removal of another map. Then, for some -classes, there is some additional tweaking: for [:blank:] the vertical space -characters are removed, and for [:alpha:] and [:alnum:] the underscore -character is removed. The triples in the table consist of the base map offset, -second map offset or -1 if no second map, and a non-negative value for map -addition or a negative value for map subtraction (if there are two maps). The -absolute value of the third field has these meanings: 0 => no tweaking, 1 => -remove vertical space characters, 2 => remove underscore. */ - -static const int posix_class_maps[] = { - cbit_word, cbit_digit, -2, /* alpha */ - cbit_lower, -1, 0, /* lower */ - cbit_upper, -1, 0, /* upper */ - cbit_word, -1, 2, /* alnum - word without underscore */ - cbit_print, cbit_cntrl, 0, /* ascii */ - cbit_space, -1, 1, /* blank - a GNU extension */ - cbit_cntrl, -1, 0, /* cntrl */ - cbit_digit, -1, 0, /* digit */ - cbit_graph, -1, 0, /* graph */ - cbit_print, -1, 0, /* print */ - cbit_punct, -1, 0, /* punct */ - cbit_space, -1, 0, /* space */ - cbit_word, -1, 0, /* word - a Perl extension */ - cbit_xdigit,-1, 0 /* xdigit */ -}; - - -#define STRING(a) # a -#define XSTRING(s) STRING(s) - -/* The texts of compile-time error messages. These are "char *" because they -are passed to the outside world. Do not ever re-use any error number, because -they are documented. Always add a new error instead. Messages marked DEAD below -are no longer used. This used to be a table of strings, but in order to reduce -the number of relocations needed when a shared library is loaded dynamically, -it is now one long string. We cannot use a table of offsets, because the -lengths of inserts such as XSTRING(MAX_NAME_SIZE) are not known. Instead, we -simply count through to the one we want - this isn't a performance issue -because these strings are used only when there is a compilation error. */ - -static const char error_texts[] = - "no error\0" - "\\ at end of pattern\0" - "\\c at end of pattern\0" - "unrecognized character follows \\\0" - "numbers out of order in {} quantifier\0" - /* 5 */ - "number too big in {} quantifier\0" - "missing terminating ] for character class\0" - "invalid escape sequence in character class\0" - "range out of order in character class\0" - "nothing to repeat\0" - /* 10 */ - "operand of unlimited repeat could match the empty string\0" /** DEAD **/ - "internal error: unexpected repeat\0" - "unrecognized character after (? or (?-\0" - "POSIX named classes are supported only within a class\0" - "missing )\0" - /* 15 */ - "reference to non-existent subpattern\0" - "erroffset passed as NULL\0" - "unknown option bit(s) set\0" - "missing ) after comment\0" - "parentheses nested too deeply\0" /** DEAD **/ - /* 20 */ - "regular expression is too large\0" - "failed to get memory\0" - "unmatched parentheses\0" - "internal error: code overflow\0" - "unrecognized character after (?<\0" - /* 25 */ - "lookbehind assertion is not fixed length\0" - "malformed number or name after (?(\0" - "conditional group contains more than two branches\0" - "assertion expected after (?(\0" - "(?R or (?[+-]digits must be followed by )\0" - /* 30 */ - "unknown POSIX class name\0" - "POSIX collating elements are not supported\0" - "this version of PCRE is not compiled with PCRE_UTF8 support\0" - "spare error\0" /** DEAD **/ - "character value in \\x{...} sequence is too large\0" - /* 35 */ - "invalid condition (?(0)\0" - "\\C not allowed in lookbehind assertion\0" - "PCRE does not support \\L, \\l, \\N, \\U, or \\u\0" - "number after (?C is > 255\0" - "closing ) for (?C expected\0" - /* 40 */ - "recursive call could loop indefinitely\0" - "unrecognized character after (?P\0" - "syntax error in subpattern name (missing terminator)\0" - "two named subpatterns have the same name\0" - "invalid UTF-8 string\0" - /* 45 */ - "support for \\P, \\p, and \\X has not been compiled\0" - "malformed \\P or \\p sequence\0" - "unknown property name after \\P or \\p\0" - "subpattern name is too long (maximum " XSTRING(MAX_NAME_SIZE) " characters)\0" - "too many named subpatterns (maximum " XSTRING(MAX_NAME_COUNT) ")\0" - /* 50 */ - "repeated subpattern is too long\0" /** DEAD **/ - "octal value is greater than \\377 (not in UTF-8 mode)\0" - "internal error: overran compiling workspace\0" - "internal error: previously-checked referenced subpattern not found\0" - "DEFINE group contains more than one branch\0" - /* 55 */ - "repeating a DEFINE group is not allowed\0" - "inconsistent NEWLINE options\0" - "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number\0" - "a numbered reference must not be zero\0" - "(*VERB) with an argument is not supported\0" - /* 60 */ - "(*VERB) not recognized\0" - "number is too big\0" - "subpattern name expected\0" - "digit expected after (?+\0" - "] is an invalid data character in JavaScript compatibility mode"; - - -/* Definition to allow mutual recursion */ - -static BOOL - compile_regex(int, int, uschar **, const uschar **, int *, BOOL, BOOL, int, - int *, int *, branch_chain *, compile_data *, int *); - - - -/************************************************* -* Find an error text * -*************************************************/ - -/* The error texts are now all in one long string, to save on relocations. As -some of the text is of unknown length, we can't use a table of offsets. -Instead, just count through the strings. This is not a performance issue -because it happens only when there has been a compilation error. - -Argument: the error number -Returns: pointer to the error string -*/ - -static const char * -find_error_text(int n) -{ -const char *s = error_texts; -for (; n > 0; n--) while (*s++ != 0) {}; -return s; -} - - -/************************************************* -* Handle escapes * -*************************************************/ - -/* This function is called when a \ has been encountered. It either returns a -positive value for a simple escape such as \n, or a negative value which -encodes one of the more complicated things such as \d. A backreference to group -n is returned as -(ESC_REF + n); ESC_REF is the highest ESC_xxx macro. When -UTF-8 is enabled, a positive value greater than 255 may be returned. On entry, -ptr is pointing at the \. On exit, it is on the final character of the escape -sequence. - -Arguments: - ptrptr points to the pattern position pointer - errorcodeptr points to the errorcode variable - bracount number of previous extracting brackets - options the options bits - isclass TRUE if inside a character class - -Returns: zero or positive => a data character - negative => a special escape sequence - on error, errorcodeptr is set -*/ - -static int -check_escape(const uschar **ptrptr, int *errorcodeptr, int bracount, - int options, BOOL isclass) -{ -BOOL utf8 = (options & PCRE_UTF8) != 0; -const uschar *ptr = *ptrptr + 1; -int c, i; - -GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */ -ptr--; /* Set pointer back to the last byte */ - -/* If backslash is at the end of the pattern, it's an error. */ - -if (c == 0) *errorcodeptr = ERR1; - -/* Non-alphanumerics are literals. For digits or letters, do an initial lookup -in a table. A non-zero result is something that can be returned immediately. -Otherwise further processing may be required. */ - -#ifndef EBCDIC /* ASCII coding */ -else if (c < '0' || c > 'z') {} /* Not alphanumeric */ -else if ((i = escapes[c - '0']) != 0) c = i; - -#else /* EBCDIC coding */ -else if (c < 'a' || (ebcdic_chartab[c] & 0x0E) == 0) {} /* Not alphanumeric */ -else if ((i = escapes[c - 0x48]) != 0) c = i; -#endif - -/* Escapes that need further processing, or are illegal. */ - -else - { - const uschar *oldptr; - BOOL braced, negated; - - switch (c) - { - /* A number of Perl escapes are not handled by PCRE. We give an explicit - error. */ - - case 'l': - case 'L': - case 'N': - case 'u': - case 'U': - *errorcodeptr = ERR37; - break; - - /* \g must be followed by one of a number of specific things: - - (1) A number, either plain or braced. If positive, it is an absolute - backreference. If negative, it is a relative backreference. This is a Perl - 5.10 feature. - - (2) Perl 5.10 also supports \g{name} as a reference to a named group. This - is part of Perl's movement towards a unified syntax for back references. As - this is synonymous with \k{name}, we fudge it up by pretending it really - was \k. - - (3) For Oniguruma compatibility we also support \g followed by a name or a - number either in angle brackets or in single quotes. However, these are - (possibly recursive) subroutine calls, _not_ backreferences. Just return - the -ESC_g code (cf \k). */ - - case 'g': - if (ptr[1] == '<' || ptr[1] == '\'') - { - c = -ESC_g; - break; - } - - /* Handle the Perl-compatible cases */ - - if (ptr[1] == '{') - { - const uschar *p; - for (p = ptr+2; *p != 0 && *p != '}'; p++) - if (*p != '-' && g_ascii_isdigit (*p) == 0) break; - if (*p != 0 && *p != '}') - { - c = -ESC_k; - break; - } - braced = TRUE; - ptr++; - } - else braced = FALSE; - - if (ptr[1] == '-') - { - negated = TRUE; - ptr++; - } - else negated = FALSE; - - c = 0; - while (g_ascii_isdigit (ptr[1]) != 0) - c = c * 10 + *(++ptr) - '0'; - - if (c < 0) /* Integer overflow */ - { - *errorcodeptr = ERR61; - break; - } - - if (braced && *(++ptr) != '}') - { - *errorcodeptr = ERR57; - break; - } - - if (c == 0) - { - *errorcodeptr = ERR58; - break; - } - - if (negated) - { - if (c > bracount) - { - *errorcodeptr = ERR15; - break; - } - c = bracount - (c - 1); - } - - c = -(ESC_REF + c); - break; - - /* The handling of escape sequences consisting of a string of digits - starting with one that is not zero is not straightforward. By experiment, - the way Perl works seems to be as follows: - - Outside a character class, the digits are read as a decimal number. If the - number is less than 10, or if there are that many previous extracting - left brackets, then it is a back reference. Otherwise, up to three octal - digits are read to form an escaped byte. Thus \123 is likely to be octal - 123 (cf \0123, which is octal 012 followed by the literal 3). If the octal - value is greater than 377, the least significant 8 bits are taken. Inside a - character class, \ followed by a digit is always an octal number. */ - - case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - - if (!isclass) - { - oldptr = ptr; - c -= '0'; - while (g_ascii_isdigit (ptr[1])) - c = c * 10 + *(++ptr) - '0'; - if (c < 0) /* Integer overflow */ - { - *errorcodeptr = ERR61; - break; - } - if (c < 10 || c <= bracount) - { - c = -(ESC_REF + c); - break; - } - ptr = oldptr; /* Put the pointer back and fall through */ - } - - /* Handle an octal number following \. If the first digit is 8 or 9, Perl - generates a binary zero byte and treats the digit as a following literal. - Thus we have to pull back the pointer by one. */ - - if ((c = *ptr) >= '8') - { - ptr--; - c = 0; - break; - } - - /* \0 always starts an octal number, but we may drop through to here with a - larger first octal digit. The original code used just to take the least - significant 8 bits of octal numbers (I think this is what early Perls used - to do). Nowadays we allow for larger numbers in UTF-8 mode, but no more - than 3 octal digits. */ - - case '0': - c -= '0'; - while(i++ < 2 && ptr[1] >= '0' && ptr[1] <= '7') - c = c * 8 + *(++ptr) - '0'; - if (!utf8 && c > 255) *errorcodeptr = ERR51; - break; - - /* \x is complicated. \x{ddd} is a character number which can be greater - than 0xff in utf8 mode, but only if the ddd are hex digits. If not, { is - treated as a data character. */ - - case 'x': - if (ptr[1] == '{') - { - const uschar *pt = ptr + 2; - int count = 0; - - c = 0; - while (g_ascii_isxdigit (*pt) != 0) - { - register int cc = *pt++; - if (c == 0 && cc == '0') continue; /* Leading zeroes */ - count++; - -#ifndef EBCDIC /* ASCII coding */ - if (cc >= 'a') cc -= 32; /* Convert to upper case */ - c = (c << 4) + cc - ((cc < 'A')? '0' : ('A' - 10)); -#else /* EBCDIC coding */ - if (cc >= 'a' && cc <= 'z') cc += 64; /* Convert to upper case */ - c = (c << 4) + cc - ((cc >= '0')? '0' : ('A' - 10)); -#endif - } - - if (*pt == '}') - { - if (c < 0 || count > (utf8? 8 : 2)) *errorcodeptr = ERR34; - ptr = pt; - break; - } - - /* If the sequence of hex digits does not end with '}', then we don't - recognize this construct; fall through to the normal \x handling. */ - } - - /* Read just a single-byte hex-defined char */ - - c = 0; - while (i++ < 2 && g_ascii_isxdigit (ptr[1]) != 0) - { - int cc; /* Some compilers don't like ++ */ - cc = *(++ptr); /* in initializers */ -#ifndef EBCDIC /* ASCII coding */ - if (cc >= 'a') cc -= 32; /* Convert to upper case */ - c = c * 16 + cc - ((cc < 'A')? '0' : ('A' - 10)); -#else /* EBCDIC coding */ - if (cc <= 'z') cc += 64; /* Convert to upper case */ - c = c * 16 + cc - ((cc >= '0')? '0' : ('A' - 10)); -#endif - } - break; - - /* For \c, a following letter is upper-cased; then the 0x40 bit is flipped. - This coding is ASCII-specific, but then the whole concept of \cx is - ASCII-specific. (However, an EBCDIC equivalent has now been added.) */ - - case 'c': - c = *(++ptr); - if (c == 0) - { - *errorcodeptr = ERR2; - break; - } - -#ifndef EBCDIC /* ASCII coding */ - if (c >= 'a' && c <= 'z') c -= 32; - c ^= 0x40; -#else /* EBCDIC coding */ - if (c >= 'a' && c <= 'z') c += 64; - c ^= 0xC0; -#endif - break; - - /* PCRE_EXTRA enables extensions to Perl in the matter of escapes. Any - other alphanumeric following \ is an error if PCRE_EXTRA was set; - otherwise, for Perl compatibility, it is a literal. This code looks a bit - odd, but there used to be some cases other than the default, and there may - be again in future, so I haven't "optimized" it. */ - - default: - if ((options & PCRE_EXTRA) != 0) switch(c) - { - default: - *errorcodeptr = ERR3; - break; - } - break; - } - } - -*ptrptr = ptr; -return c; -} - - - -#ifdef SUPPORT_UCP -/************************************************* -* Handle \P and \p * -*************************************************/ - -/* This function is called after \P or \p has been encountered, provided that -PCRE is compiled with support for Unicode properties. On entry, ptrptr is -pointing at the P or p. On exit, it is pointing at the final character of the -escape sequence. - -Argument: - ptrptr points to the pattern position pointer - negptr points to a boolean that is set TRUE for negation else FALSE - dptr points to an int that is set to the detailed property value - errorcodeptr points to the error code variable - -Returns: type value from ucp_type_table, or -1 for an invalid type -*/ - -static int -get_ucp(const uschar **ptrptr, BOOL *negptr, int *dptr, int *errorcodeptr) -{ -int c, i, bot, top; -const uschar *ptr = *ptrptr; -char name[32]; - -c = *(++ptr); -if (c == 0) goto ERROR_RETURN; - -*negptr = FALSE; - -/* \P or \p can be followed by a name in {}, optionally preceded by ^ for -negation. */ - -if (c == '{') - { - if (ptr[1] == '^') - { - *negptr = TRUE; - ptr++; - } - for (i = 0; i < (int)sizeof(name) - 1; i++) - { - c = *(++ptr); - if (c == 0) goto ERROR_RETURN; - if (c == '}') break; - name[i] = c; - } - if (c !='}') goto ERROR_RETURN; - name[i] = 0; - } - -/* Otherwise there is just one following character */ - -else - { - name[0] = c; - name[1] = 0; - } - -*ptrptr = ptr; - -/* Search for a recognized property name using binary chop */ - -bot = 0; -top = _pcre_utt_size; - -while (bot < top) - { - i = (bot + top) >> 1; - c = strcmp(name, _pcre_utt_names + _pcre_utt[i].name_offset); - if (c == 0) - { - *dptr = _pcre_utt[i].value; - return _pcre_utt[i].type; - } - if (c > 0) bot = i + 1; else top = i; - } - -*errorcodeptr = ERR47; -*ptrptr = ptr; -return -1; - -ERROR_RETURN: -*errorcodeptr = ERR46; -*ptrptr = ptr; -return -1; -} -#endif - - - - -/************************************************* -* Check for counted repeat * -*************************************************/ - -/* This function is called when a '{' is encountered in a place where it might -start a quantifier. It looks ahead to see if it really is a quantifier or not. -It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd} -where the ddds are digits. - -Arguments: - p pointer to the first char after '{' - -Returns: TRUE or FALSE -*/ - -static BOOL -is_counted_repeat(const uschar *p) -{ -if (g_ascii_isdigit (*p++) == 0) return FALSE; -while (g_ascii_isdigit (*p) != 0) p++; -if (*p == '}') return TRUE; - -if (*p++ != ',') return FALSE; -if (*p == '}') return TRUE; - -if (g_ascii_isdigit (*p++) == 0) return FALSE; -while (g_ascii_isdigit (*p) != 0) p++; - -return (*p == '}'); -} - - - -/************************************************* -* Read repeat counts * -*************************************************/ - -/* Read an item of the form {n,m} and return the values. This is called only -after is_counted_repeat() has confirmed that a repeat-count quantifier exists, -so the syntax is guaranteed to be correct, but we need to check the values. - -Arguments: - p pointer to first char after '{' - minp pointer to int for min - maxp pointer to int for max - returned as -1 if no max - errorcodeptr points to error code variable - -Returns: pointer to '}' on success; - current ptr on error, with errorcodeptr set non-zero -*/ - -static const uschar * -read_repeat_counts(const uschar *p, int *minp, int *maxp, int *errorcodeptr) -{ -int min = 0; -int max = -1; - -/* Read the minimum value and do a paranoid check: a negative value indicates -an integer overflow. */ - -while (g_ascii_isdigit (*p) != 0) min = min * 10 + *p++ - '0'; -if (min < 0 || min > 65535) - { - *errorcodeptr = ERR5; - return p; - } - -/* Read the maximum value if there is one, and again do a paranoid on its size. -Also, max must not be less than min. */ - -if (*p == '}') max = min; else - { - if (*(++p) != '}') - { - max = 0; - while(g_ascii_isdigit (*p) != 0) max = max * 10 + *p++ - '0'; - if (max < 0 || max > 65535) - { - *errorcodeptr = ERR5; - return p; - } - if (max < min) - { - *errorcodeptr = ERR4; - return p; - } - } - } - -/* Fill in the required variables, and pass back the pointer to the terminating -'}'. */ - -*minp = min; -*maxp = max; -return p; -} - - - -/************************************************* -* Find forward referenced subpattern * -*************************************************/ - -/* This function scans along a pattern's text looking for capturing -subpatterns, and counting them. If it finds a named pattern that matches the -name it is given, it returns its number. Alternatively, if the name is NULL, it -returns when it reaches a given numbered subpattern. This is used for forward -references to subpatterns. We know that if (?P< is encountered, the name will -be terminated by '>' because that is checked in the first pass. - -Arguments: - ptr current position in the pattern - cd compile background data - name name to seek, or NULL if seeking a numbered subpattern - lorn name length, or subpattern number if name is NULL - xmode TRUE if we are in /x mode - -Returns: the number of the named subpattern, or -1 if not found -*/ - -static int -find_parens(const uschar *ptr, compile_data *cd, const uschar *name, int lorn, - BOOL xmode) -{ -const uschar *thisname; -int count = cd->bracount; - -for (; *ptr != 0; ptr++) - { - int term; - - /* Skip over backslashed characters and also entire \Q...\E */ - - if (*ptr == '\\') - { - if (*(++ptr) == 0) return -1; - if (*ptr == 'Q') for (;;) - { - while (*(++ptr) != 0 && *ptr != '\\') {}; - if (*ptr == 0) return -1; - if (*(++ptr) == 'E') break; - } - continue; - } - - /* Skip over character classes; this logic must be similar to the way they - are handled for real. If the first character is '^', skip it. Also, if the - first few characters (either before or after ^) are \Q\E or \E we skip them - too. This makes for compatibility with Perl. */ - - if (*ptr == '[') - { - BOOL negate_class = FALSE; - for (;;) - { - int c = *(++ptr); - if (c == '\\') - { - if (ptr[1] == 'E') ptr++; - else if (strncmp((const char *)ptr+1, "Q\\E", 3) == 0) ptr += 3; - else break; - } - else if (!negate_class && c == '^') - negate_class = TRUE; - else break; - } - - /* If the next character is ']', it is a data character that must be - skipped, except in JavaScript compatibility mode. */ - - if (ptr[1] == ']' && (cd->external_options & PCRE_JAVASCRIPT_COMPAT) == 0) - ptr++; - - while (*(++ptr) != ']') - { - if (*ptr == 0) return -1; - if (*ptr == '\\') - { - if (*(++ptr) == 0) return -1; - if (*ptr == 'Q') for (;;) - { - while (*(++ptr) != 0 && *ptr != '\\') {}; - if (*ptr == 0) return -1; - if (*(++ptr) == 'E') break; - } - continue; - } - } - continue; - } - - /* Skip comments in /x mode */ - - if (xmode && *ptr == '#') - { - while (*(++ptr) != 0 && *ptr != '\n') {}; - if (*ptr == 0) return -1; - continue; - } - - /* An opening parens must now be a real metacharacter */ - - if (*ptr != '(') continue; - if (ptr[1] != '?' && ptr[1] != '*') - { - count++; - if (name == NULL && count == lorn) return count; - continue; - } - - ptr += 2; - if (*ptr == 'P') ptr++; /* Allow optional P */ - - /* We have to disambiguate (?<! and (?<= from (?<name> */ - - if ((*ptr != '<' || ptr[1] == '!' || ptr[1] == '=') && - *ptr != '\'') - continue; - - count++; - - if (name == NULL && count == lorn) return count; - term = *ptr++; - if (term == '<') term = '>'; - thisname = ptr; - while (*ptr != term) ptr++; - if (name != NULL && lorn == ptr - thisname && - strncmp((const char *)name, (const char *)thisname, lorn) == 0) - return count; - } - -return -1; -} - - - -/************************************************* -* Find first significant op code * -*************************************************/ - -/* This is called by several functions that scan a compiled expression looking -for a fixed first character, or an anchoring op code etc. It skips over things -that do not influence this. For some calls, a change of option is important. -For some calls, it makes sense to skip negative forward and all backward -assertions, and also the \b assertion; for others it does not. - -Arguments: - code pointer to the start of the group - options pointer to external options - optbit the option bit whose changing is significant, or - zero if none are - skipassert TRUE if certain assertions are to be skipped - -Returns: pointer to the first significant opcode -*/ - -static const uschar* -first_significant_code(const uschar *code, int *options, int optbit, - BOOL skipassert) -{ -for (;;) - { - switch ((int)*code) - { - case OP_OPT: - if (optbit > 0 && ((int)code[1] & optbit) != (*options & optbit)) - *options = (int)code[1]; - code += 2; - break; - - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - if (!skipassert) return code; - do code += GET(code, 1); while (*code == OP_ALT); - code += _pcre_OP_lengths[*code]; - break; - - case OP_WORD_BOUNDARY: - case OP_NOT_WORD_BOUNDARY: - if (!skipassert) return code; - /* Fall through */ - - case OP_CALLOUT: - case OP_CREF: - case OP_RREF: - case OP_DEF: - code += _pcre_OP_lengths[*code]; - break; - - default: - return code; - } - } -/* Control never reaches here */ -} - - - - -/************************************************* -* Find the fixed length of a pattern * -*************************************************/ - -/* Scan a pattern and compute the fixed length of subject that will match it, -if the length is fixed. This is needed for dealing with backward assertions. -In UTF8 mode, the result is in characters rather than bytes. - -Arguments: - code points to the start of the pattern (the bracket) - options the compiling options - -Returns: the fixed length, or -1 if there is no fixed length, - or -2 if \C was encountered -*/ - -static int -find_fixedlength(uschar *code, int options) -{ -int length = -1; - -register int branchlength = 0; -register uschar *cc = code + 1 + LINK_SIZE; - -/* Scan along the opcodes for this branch. If we get to the end of the -branch, check the length against that of the other branches. */ - -for (;;) - { - int d; - register int op = *cc; - switch (op) - { - case OP_CBRA: - case OP_BRA: - case OP_ONCE: - case OP_COND: - d = find_fixedlength(cc + ((op == OP_CBRA)? 2:0), options); - if (d < 0) return d; - branchlength += d; - do cc += GET(cc, 1); while (*cc == OP_ALT); - cc += 1 + LINK_SIZE; - break; - - /* Reached end of a branch; if it's a ket it is the end of a nested - call. If it's ALT it is an alternation in a nested call. If it is - END it's the end of the outer call. All can be handled by the same code. */ - - case OP_ALT: - case OP_KET: - case OP_KETRMAX: - case OP_KETRMIN: - case OP_END: - if (length < 0) length = branchlength; - else if (length != branchlength) return -1; - if (*cc != OP_ALT) return length; - cc += 1 + LINK_SIZE; - branchlength = 0; - break; - - /* Skip over assertive subpatterns */ - - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - do cc += GET(cc, 1); while (*cc == OP_ALT); - /* Fall through */ - - /* Skip over things that don't match chars */ - - case OP_REVERSE: - case OP_CREF: - case OP_RREF: - case OP_DEF: - case OP_OPT: - case OP_CALLOUT: - case OP_SOD: - case OP_SOM: - case OP_EOD: - case OP_EODN: - case OP_CIRC: - case OP_DOLL: - case OP_NOT_WORD_BOUNDARY: - case OP_WORD_BOUNDARY: - cc += _pcre_OP_lengths[*cc]; - break; - - /* Handle literal characters */ - - case OP_CHAR: - case OP_CHARNC: - case OP_NOT: - branchlength++; - cc += 2; -#ifdef SUPPORT_UTF8 - if ((options & PCRE_UTF8) != 0) - { - while ((*cc & 0xc0) == 0x80) cc++; - } -#endif - break; - - /* Handle exact repetitions. The count is already in characters, but we - need to skip over a multibyte character in UTF8 mode. */ - - case OP_EXACT: - branchlength += GET2(cc,1); - cc += 4; -#ifdef SUPPORT_UTF8 - if ((options & PCRE_UTF8) != 0) - { - while((*cc & 0x80) == 0x80) cc++; - } -#endif - break; - - case OP_TYPEEXACT: - branchlength += GET2(cc,1); - if (cc[3] == OP_PROP || cc[3] == OP_NOTPROP) cc += 2; - cc += 4; - break; - - /* Handle single-char matchers */ - - case OP_PROP: - case OP_NOTPROP: - cc += 2; - /* Fall through */ - - case OP_NOT_DIGIT: - case OP_DIGIT: - case OP_NOT_WHITESPACE: - case OP_WHITESPACE: - case OP_NOT_WORDCHAR: - case OP_WORDCHAR: - case OP_ANY: - case OP_ALLANY: - branchlength++; - cc++; - break; - - /* The single-byte matcher isn't allowed */ - - case OP_ANYBYTE: - return -2; - - /* Check a class for variable quantification */ - -#ifdef SUPPORT_UTF8 - case OP_XCLASS: - cc += GET(cc, 1) - 33; - /* Fall through */ -#endif - - case OP_CLASS: - case OP_NCLASS: - cc += 33; - - switch (*cc) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRQUERY: - case OP_CRMINQUERY: - return -1; - - case OP_CRRANGE: - case OP_CRMINRANGE: - if (GET2(cc,1) != GET2(cc,3)) return -1; - branchlength += GET2(cc,1); - cc += 5; - break; - - default: - branchlength++; - } - break; - - /* Anything else is variable length */ - - default: - return -1; - } - } -/* Control never gets here */ -} - - - - -/************************************************* -* Scan compiled regex for numbered bracket * -*************************************************/ - -/* This little function scans through a compiled pattern until it finds a -capturing bracket with the given number. - -Arguments: - code points to start of expression - utf8 TRUE in UTF-8 mode - number the required bracket number - -Returns: pointer to the opcode for the bracket, or NULL if not found -*/ - -static const uschar * -find_bracket(const uschar *code, BOOL utf8, int number) -{ -for (;;) - { - register int c = *code; - if (c == OP_END) return NULL; - - /* XCLASS is used for classes that cannot be represented just by a bit - map. This includes negated single high-valued characters. The length in - the table is zero; the actual length is stored in the compiled code. */ - - if (c == OP_XCLASS) code += GET(code, 1); - - /* Handle capturing bracket */ - - else if (c == OP_CBRA) - { - int n = GET2(code, 1+LINK_SIZE); - if (n == number) return (uschar *)code; - code += _pcre_OP_lengths[c]; - } - - /* Otherwise, we can get the item's length from the table, except that for - repeated character types, we have to test for \p and \P, which have an extra - two bytes of parameters. */ - - else - { - switch(c) - { - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSPLUS: - case OP_TYPEPOSQUERY: - if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; - break; - - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEEXACT: - case OP_TYPEPOSUPTO: - if (code[3] == OP_PROP || code[3] == OP_NOTPROP) code += 2; - break; - } - - /* Add in the fixed length from the table */ - - code += _pcre_OP_lengths[c]; - - /* In UTF-8 mode, opcodes that are followed by a character may be followed by - a multi-byte character. The length in the table is a minimum, so we have to - arrange to skip the extra bytes. */ - -#ifdef SUPPORT_UTF8 - if (utf8) switch(c) - { - case OP_CHAR: - case OP_CHARNC: - case OP_EXACT: - case OP_UPTO: - case OP_MINUPTO: - case OP_POSUPTO: - case OP_STAR: - case OP_MINSTAR: - case OP_POSSTAR: - case OP_PLUS: - case OP_MINPLUS: - case OP_POSPLUS: - case OP_QUERY: - case OP_MINQUERY: - case OP_POSQUERY: - if (code[-1] >= 0xc0) code += _pcre_utf8_table4[code[-1] & 0x3f]; - break; - } -#else - (void)(utf8); /* Keep compiler happy by referencing function argument */ -#endif - } - } -} - - - -/************************************************* -* Scan compiled regex for recursion reference * -*************************************************/ - -/* This little function scans through a compiled pattern until it finds an -instance of OP_RECURSE. - -Arguments: - code points to start of expression - utf8 TRUE in UTF-8 mode - -Returns: pointer to the opcode for OP_RECURSE, or NULL if not found -*/ - -static const uschar * -find_recurse(const uschar *code, BOOL utf8) -{ -for (;;) - { - register int c = *code; - if (c == OP_END) return NULL; - if (c == OP_RECURSE) return code; - - /* XCLASS is used for classes that cannot be represented just by a bit - map. This includes negated single high-valued characters. The length in - the table is zero; the actual length is stored in the compiled code. */ - - if (c == OP_XCLASS) code += GET(code, 1); - - /* Otherwise, we can get the item's length from the table, except that for - repeated character types, we have to test for \p and \P, which have an extra - two bytes of parameters. */ - - else - { - switch(c) - { - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSPLUS: - case OP_TYPEPOSQUERY: - if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; - break; - - case OP_TYPEPOSUPTO: - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEEXACT: - if (code[3] == OP_PROP || code[3] == OP_NOTPROP) code += 2; - break; - } - - /* Add in the fixed length from the table */ - - code += _pcre_OP_lengths[c]; - - /* In UTF-8 mode, opcodes that are followed by a character may be followed - by a multi-byte character. The length in the table is a minimum, so we have - to arrange to skip the extra bytes. */ - -#ifdef SUPPORT_UTF8 - if (utf8) switch(c) - { - case OP_CHAR: - case OP_CHARNC: - case OP_EXACT: - case OP_UPTO: - case OP_MINUPTO: - case OP_POSUPTO: - case OP_STAR: - case OP_MINSTAR: - case OP_POSSTAR: - case OP_PLUS: - case OP_MINPLUS: - case OP_POSPLUS: - case OP_QUERY: - case OP_MINQUERY: - case OP_POSQUERY: - if (code[-1] >= 0xc0) code += _pcre_utf8_table4[code[-1] & 0x3f]; - break; - } -#else - (void)(utf8); /* Keep compiler happy by referencing function argument */ -#endif - } - } -} - - - -/************************************************* -* Scan compiled branch for non-emptiness * -*************************************************/ - -/* This function scans through a branch of a compiled pattern to see whether it -can match the empty string or not. It is called from could_be_empty() -below and from compile_branch() when checking for an unlimited repeat of a -group that can match nothing. Note that first_significant_code() skips over -backward and negative forward assertions when its final argument is TRUE. If we -hit an unclosed bracket, we return "empty" - this means we've struck an inner -bracket whose current branch will already have been scanned. - -Arguments: - code points to start of search - endcode points to where to stop - utf8 TRUE if in UTF8 mode - -Returns: TRUE if what is matched could be empty -*/ - -static BOOL -could_be_empty_branch(const uschar *code, const uschar *endcode, BOOL utf8) -{ -register int c; -for (code = first_significant_code(code + _pcre_OP_lengths[*code], NULL, 0, TRUE); - code < endcode; - code = first_significant_code(code + _pcre_OP_lengths[c], NULL, 0, TRUE)) - { - const uschar *ccode; - - c = *code; - - /* Skip over forward assertions; the other assertions are skipped by - first_significant_code() with a TRUE final argument. */ - - if (c == OP_ASSERT) - { - do code += GET(code, 1); while (*code == OP_ALT); - c = *code; - continue; - } - - /* Groups with zero repeats can of course be empty; skip them. */ - - if (c == OP_BRAZERO || c == OP_BRAMINZERO || c == OP_SKIPZERO) - { - code += _pcre_OP_lengths[c]; - do code += GET(code, 1); while (*code == OP_ALT); - c = *code; - continue; - } - - /* For other groups, scan the branches. */ - - if (c == OP_BRA || c == OP_CBRA || c == OP_ONCE || c == OP_COND) - { - BOOL empty_branch; - if (GET(code, 1) == 0) return TRUE; /* Hit unclosed bracket */ - - /* Scan a closed bracket */ - - empty_branch = FALSE; - do - { - if (!empty_branch && could_be_empty_branch(code, endcode, utf8)) - empty_branch = TRUE; - code += GET(code, 1); - } - while (*code == OP_ALT); - if (!empty_branch) return FALSE; /* All branches are non-empty */ - c = *code; - continue; - } - - /* Handle the other opcodes */ - - switch (c) - { - /* Check for quantifiers after a class. XCLASS is used for classes that - cannot be represented just by a bit map. This includes negated single - high-valued characters. The length in _pcre_OP_lengths[] is zero; the - actual length is stored in the compiled code, so we must update "code" - here. */ - -#ifdef SUPPORT_UTF8 - case OP_XCLASS: - ccode = code += GET(code, 1); - goto CHECK_CLASS_REPEAT; -#endif - - case OP_CLASS: - case OP_NCLASS: - ccode = code + 33; - -#ifdef SUPPORT_UTF8 - CHECK_CLASS_REPEAT: -#endif - - switch (*ccode) - { - case OP_CRSTAR: /* These could be empty; continue */ - case OP_CRMINSTAR: - case OP_CRQUERY: - case OP_CRMINQUERY: - break; - - default: /* Non-repeat => class must match */ - case OP_CRPLUS: /* These repeats aren't empty */ - case OP_CRMINPLUS: - return FALSE; - - case OP_CRRANGE: - case OP_CRMINRANGE: - if (GET2(ccode, 1) > 0) return FALSE; /* Minimum > 0 */ - break; - } - break; - - /* Opcodes that must match a character */ - - case OP_PROP: - case OP_NOTPROP: - case OP_EXTUNI: - case OP_NOT_DIGIT: - case OP_DIGIT: - case OP_NOT_WHITESPACE: - case OP_WHITESPACE: - case OP_NOT_WORDCHAR: - case OP_WORDCHAR: - case OP_ANY: - case OP_ALLANY: - case OP_ANYBYTE: - case OP_CHAR: - case OP_CHARNC: - case OP_NOT: - case OP_PLUS: - case OP_MINPLUS: - case OP_POSPLUS: - case OP_EXACT: - case OP_NOTPLUS: - case OP_NOTMINPLUS: - case OP_NOTPOSPLUS: - case OP_NOTEXACT: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEPOSPLUS: - case OP_TYPEEXACT: - return FALSE; - - /* These are going to continue, as they may be empty, but we have to - fudge the length for the \p and \P cases. */ - - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPOSSTAR: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSQUERY: - if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; - break; - - /* Same for these */ - - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEPOSUPTO: - if (code[3] == OP_PROP || code[3] == OP_NOTPROP) code += 2; - break; - - /* End of branch */ - - case OP_KET: - case OP_KETRMAX: - case OP_KETRMIN: - case OP_ALT: - return TRUE; - - /* In UTF-8 mode, STAR, MINSTAR, POSSTAR, QUERY, MINQUERY, POSQUERY, UPTO, - MINUPTO, and POSUPTO may be followed by a multibyte character */ - -#ifdef SUPPORT_UTF8 - case OP_STAR: - case OP_MINSTAR: - case OP_POSSTAR: - case OP_QUERY: - case OP_MINQUERY: - case OP_POSQUERY: - case OP_UPTO: - case OP_MINUPTO: - case OP_POSUPTO: - if (utf8) while ((code[2] & 0xc0) == 0x80) code++; - break; -#endif - } - } - -return TRUE; -} - - - -/************************************************* -* Scan compiled regex for non-emptiness * -*************************************************/ - -/* This function is called to check for left recursive calls. We want to check -the current branch of the current pattern to see if it could match the empty -string. If it could, we must look outwards for branches at other levels, -stopping when we pass beyond the bracket which is the subject of the recursion. - -Arguments: - code points to start of the recursion - endcode points to where to stop (current RECURSE item) - bcptr points to the chain of current (unclosed) branch starts - utf8 TRUE if in UTF-8 mode - -Returns: TRUE if what is matched could be empty -*/ - -static BOOL -could_be_empty(const uschar *code, const uschar *endcode, branch_chain *bcptr, - BOOL utf8) -{ -while (bcptr != NULL && bcptr->current >= code) - { - if (!could_be_empty_branch(bcptr->current, endcode, utf8)) return FALSE; - bcptr = bcptr->outer; - } -return TRUE; -} - - - -/************************************************* -* Check for POSIX class syntax * -*************************************************/ - -/* This function is called when the sequence "[:" or "[." or "[=" is -encountered in a character class. It checks whether this is followed by a -sequence of characters terminated by a matching ":]" or ".]" or "=]". If we -reach an unescaped ']' without the special preceding character, return FALSE. - -Originally, this function only recognized a sequence of letters between the -terminators, but it seems that Perl recognizes any sequence of characters, -though of course unknown POSIX names are subsequently rejected. Perl gives an -"Unknown POSIX class" error for [:f\oo:] for example, where previously PCRE -didn't consider this to be a POSIX class. Likewise for [:1234:]. - -The problem in trying to be exactly like Perl is in the handling of escapes. We -have to be sure that [abc[:x\]pqr] is *not* treated as containing a POSIX -class, but [abc[:x\]pqr:]] is (so that an error can be generated). The code -below handles the special case of \], but does not try to do any other escape -processing. This makes it different from Perl for cases such as [:l\ower:] -where Perl recognizes it as the POSIX class "lower" but PCRE does not recognize -"l\ower". This is a lesser evil that not diagnosing bad classes when Perl does, -I think. - -Arguments: - ptr pointer to the initial [ - endptr where to return the end pointer - -Returns: TRUE or FALSE -*/ - -static BOOL -check_posix_syntax(const uschar *ptr, const uschar **endptr) -{ -int terminator; /* Don't combine these lines; the Solaris cc */ -terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */ -for (++ptr; *ptr != 0; ptr++) - { - if (*ptr == '\\' && ptr[1] == ']') ptr++; else - { - if (*ptr == ']') return FALSE; - if (*ptr == terminator && ptr[1] == ']') - { - *endptr = ptr; - return TRUE; - } - } - } -return FALSE; -} - - - - -/************************************************* -* Check POSIX class name * -*************************************************/ - -/* This function is called to check the name given in a POSIX-style class entry -such as [:alnum:]. - -Arguments: - ptr points to the first letter - len the length of the name - -Returns: a value representing the name, or -1 if unknown -*/ - -static int -check_posix_name(const uschar *ptr, int len) -{ -const char *pn = posix_names; -register int yield = 0; -while (posix_name_lengths[yield] != 0) - { - if (len == posix_name_lengths[yield] && - strncmp((const char *)ptr, pn, len) == 0) return yield; - pn += posix_name_lengths[yield] + 1; - yield++; - } -return -1; -} - - -/************************************************* -* Adjust OP_RECURSE items in repeated group * -*************************************************/ - -/* OP_RECURSE items contain an offset from the start of the regex to the group -that is referenced. This means that groups can be replicated for fixed -repetition simply by copying (because the recursion is allowed to refer to -earlier groups that are outside the current group). However, when a group is -optional (i.e. the minimum quantifier is zero), OP_BRAZERO or OP_SKIPZERO is -inserted before it, after it has been compiled. This means that any OP_RECURSE -items within it that refer to the group itself or any contained groups have to -have their offsets adjusted. That one of the jobs of this function. Before it -is called, the partially compiled regex must be temporarily terminated with -OP_END. - -This function has been extended with the possibility of forward references for -recursions and subroutine calls. It must also check the list of such references -for the group we are dealing with. If it finds that one of the recursions in -the current group is on this list, it adjusts the offset in the list, not the -value in the reference (which is a group number). - -Arguments: - group points to the start of the group - adjust the amount by which the group is to be moved - utf8 TRUE in UTF-8 mode - cd contains pointers to tables etc. - save_hwm the hwm forward reference pointer at the start of the group - -Returns: nothing -*/ - -static void -adjust_recurse(uschar *group, int adjust, BOOL utf8, compile_data *cd, - uschar *save_hwm) -{ -uschar *ptr = group; - -while ((ptr = (uschar *)find_recurse(ptr, utf8)) != NULL) - { - int offset; - uschar *hc; - - /* See if this recursion is on the forward reference list. If so, adjust the - reference. */ - - for (hc = save_hwm; hc < cd->hwm; hc += LINK_SIZE) - { - offset = GET(hc, 0); - if (cd->start_code + offset == ptr + 1) - { - PUT(hc, 0, offset + adjust); - break; - } - } - - /* Otherwise, adjust the recursion offset if it's after the start of this - group. */ - - if (hc >= cd->hwm) - { - offset = GET(ptr, 1); - if (cd->start_code + offset >= group) PUT(ptr, 1, offset + adjust); - } - - ptr += 1 + LINK_SIZE; - } -} - - - -/************************************************* -* Insert an automatic callout point * -*************************************************/ - -/* This function is called when the PCRE_AUTO_CALLOUT option is set, to insert -callout points before each pattern item. - -Arguments: - code current code pointer - ptr current pattern pointer - cd pointers to tables etc - -Returns: new code pointer -*/ - -static uschar * -auto_callout(uschar *code, const uschar *ptr, compile_data *cd) -{ -*code++ = OP_CALLOUT; -*code++ = 255; -PUT(code, 0, ptr - cd->start_pattern); /* Pattern offset */ -PUT(code, LINK_SIZE, 0); /* Default length */ -return code + 2*LINK_SIZE; -} - - - -/************************************************* -* Complete a callout item * -*************************************************/ - -/* A callout item contains the length of the next item in the pattern, which -we can't fill in till after we have reached the relevant point. This is used -for both automatic and manual callouts. - -Arguments: - previous_callout points to previous callout item - ptr current pattern pointer - cd pointers to tables etc - -Returns: nothing -*/ - -static void -complete_callout(uschar *previous_callout, const uschar *ptr, compile_data *cd) -{ -int length = ptr - cd->start_pattern - GET(previous_callout, 2); -PUT(previous_callout, 2 + LINK_SIZE, length); -} - - - -#ifdef SUPPORT_UCP -/************************************************* -* Get othercase range * -*************************************************/ - -/* This function is passed the start and end of a class range, in UTF-8 mode -with UCP support. It searches up the characters, looking for internal ranges of -characters in the "other" case. Each call returns the next one, updating the -start address. - -Arguments: - cptr points to starting character value; updated - d end value - ocptr where to put start of othercase range - odptr where to put end of othercase range - -Yield: TRUE when range returned; FALSE when no more -*/ - -static BOOL -get_othercase_range(unsigned int *cptr, unsigned int d, unsigned int *ocptr, - unsigned int *odptr) -{ -unsigned int c, othercase, next; - -for (c = *cptr; c <= d; c++) - { if ((othercase = UCD_OTHERCASE(c)) != c) break; } - -if (c > d) return FALSE; - -*ocptr = othercase; -next = othercase + 1; - -for (++c; c <= d; c++) - { - if (UCD_OTHERCASE(c) != next) break; - next++; - } - -*odptr = next - 1; -*cptr = c; - -return TRUE; -} -#endif /* SUPPORT_UCP */ - - - -/************************************************* -* Check if auto-possessifying is possible * -*************************************************/ - -/* This function is called for unlimited repeats of certain items, to see -whether the next thing could possibly match the repeated item. If not, it makes -sense to automatically possessify the repeated item. - -Arguments: - op_code the repeated op code - this data for this item, depends on the opcode - utf8 TRUE in UTF-8 mode - utf8_char used for utf8 character bytes, NULL if not relevant - ptr next character in pattern - options options bits - cd contains pointers to tables etc. - -Returns: TRUE if possessifying is wanted -*/ - -static BOOL -check_auto_possessive(int op_code, int item, BOOL utf8, uschar *utf8_char, - const uschar *ptr, int options, compile_data *cd) -{ -int next; - -/* Skip whitespace and comments in extended mode */ - -if ((options & PCRE_EXTENDED) != 0) - { - for (;;) - { - while ((cd->ctypes[*ptr] & ctype_space) != 0) ptr++; - if (*ptr == '#') - { - while (*(++ptr) != 0) - if (IS_NEWLINE(ptr)) { ptr += cd->nllen; break; } - } - else break; - } - } - -/* If the next item is one that we can handle, get its value. A non-negative -value is a character, a negative value is an escape value. */ - -if (*ptr == '\\') - { - int temperrorcode = 0; - next = check_escape(&ptr, &temperrorcode, cd->bracount, options, FALSE); - if (temperrorcode != 0) return FALSE; - ptr++; /* Point after the escape sequence */ - } - -else if ((cd->ctypes[*ptr] & ctype_meta) == 0) - { -#ifdef SUPPORT_UTF8 - if (utf8) { GETCHARINC(next, ptr); } else -#endif - next = *ptr++; - } - -else return FALSE; - -/* Skip whitespace and comments in extended mode */ - -if ((options & PCRE_EXTENDED) != 0) - { - for (;;) - { - while ((cd->ctypes[*ptr] & ctype_space) != 0) ptr++; - if (*ptr == '#') - { - while (*(++ptr) != 0) - if (IS_NEWLINE(ptr)) { ptr += cd->nllen; break; } - } - else break; - } - } - -/* If the next thing is itself optional, we have to give up. */ - -if (*ptr == '*' || *ptr == '?' || strncmp((char *)ptr, "{0,", 3) == 0) - return FALSE; - -/* Now compare the next item with the previous opcode. If the previous is a -positive single character match, "item" either contains the character or, if -"item" is greater than 127 in utf8 mode, the character's bytes are in -utf8_char. */ - - -/* Handle cases when the next item is a character. */ - -if (next >= 0) switch(op_code) - { - case OP_CHAR: -#ifdef SUPPORT_UTF8 - if (utf8 && item > 127) { GETCHAR(item, utf8_char); } -#else - (void)(utf8_char); /* Keep compiler happy by referencing function argument */ -#endif - return item != next; - - /* For CHARNC (caseless character) we must check the other case. If we have - Unicode property support, we can use it to test the other case of - high-valued characters. */ - - case OP_CHARNC: -#ifdef SUPPORT_UTF8 - if (utf8 && item > 127) { GETCHAR(item, utf8_char); } -#endif - if (item == next) return FALSE; -#ifdef SUPPORT_UTF8 - if (utf8) - { - unsigned int othercase; - if (next < 128) othercase = cd->fcc[next]; else -#ifdef SUPPORT_UCP - othercase = UCD_OTHERCASE((unsigned int)next); -#else - othercase = NOTACHAR; -#endif - return (unsigned int)item != othercase; - } - else -#endif /* SUPPORT_UTF8 */ - return (item != cd->fcc[next]); /* Non-UTF-8 mode */ - - /* For OP_NOT, "item" must be a single-byte character. */ - - case OP_NOT: - if (item == next) return TRUE; - if ((options & PCRE_CASELESS) == 0) return FALSE; -#ifdef SUPPORT_UTF8 - if (utf8) - { - unsigned int othercase; - if (next < 128) othercase = cd->fcc[next]; else -#ifdef SUPPORT_UCP - othercase = UCD_OTHERCASE(next); -#else - othercase = NOTACHAR; -#endif - return (unsigned int)item == othercase; - } - else -#endif /* SUPPORT_UTF8 */ - return (item == cd->fcc[next]); /* Non-UTF-8 mode */ - - case OP_DIGIT: - return next > 127 || (cd->ctypes[next] & ctype_digit) == 0; - - case OP_NOT_DIGIT: - return next <= 127 && (cd->ctypes[next] & ctype_digit) != 0; - - case OP_WHITESPACE: - return next > 127 || (cd->ctypes[next] & ctype_space) == 0; - - case OP_NOT_WHITESPACE: - return next <= 127 && (cd->ctypes[next] & ctype_space) != 0; - - case OP_WORDCHAR: - return next > 127 || (cd->ctypes[next] & ctype_word) == 0; - - case OP_NOT_WORDCHAR: - return next <= 127 && (cd->ctypes[next] & ctype_word) != 0; - - case OP_HSPACE: - case OP_NOT_HSPACE: - switch(next) - { - case 0x09: - case 0x20: - case 0xa0: - case 0x1680: - case 0x180e: - case 0x2000: - case 0x2001: - case 0x2002: - case 0x2003: - case 0x2004: - case 0x2005: - case 0x2006: - case 0x2007: - case 0x2008: - case 0x2009: - case 0x200A: - case 0x202f: - case 0x205f: - case 0x3000: - return op_code != OP_HSPACE; - default: - return op_code == OP_HSPACE; - } - - case OP_VSPACE: - case OP_NOT_VSPACE: - switch(next) - { - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x85: - case 0x2028: - case 0x2029: - return op_code != OP_VSPACE; - default: - return op_code == OP_VSPACE; - } - - default: - return FALSE; - } - - -/* Handle the case when the next item is \d, \s, etc. */ - -switch(op_code) - { - case OP_CHAR: - case OP_CHARNC: -#ifdef SUPPORT_UTF8 - if (utf8 && item > 127) { GETCHAR(item, utf8_char); } -#endif - switch(-next) - { - case ESC_d: - return item > 127 || (cd->ctypes[item] & ctype_digit) == 0; - - case ESC_D: - return item <= 127 && (cd->ctypes[item] & ctype_digit) != 0; - - case ESC_s: - return item > 127 || (cd->ctypes[item] & ctype_space) == 0; - - case ESC_S: - return item <= 127 && (cd->ctypes[item] & ctype_space) != 0; - - case ESC_w: - return item > 127 || (cd->ctypes[item] & ctype_word) == 0; - - case ESC_W: - return item <= 127 && (cd->ctypes[item] & ctype_word) != 0; - - case ESC_h: - case ESC_H: - switch(item) - { - case 0x09: - case 0x20: - case 0xa0: - case 0x1680: - case 0x180e: - case 0x2000: - case 0x2001: - case 0x2002: - case 0x2003: - case 0x2004: - case 0x2005: - case 0x2006: - case 0x2007: - case 0x2008: - case 0x2009: - case 0x200A: - case 0x202f: - case 0x205f: - case 0x3000: - return -next != ESC_h; - default: - return -next == ESC_h; - } - - case ESC_v: - case ESC_V: - switch(item) - { - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x85: - case 0x2028: - case 0x2029: - return -next != ESC_v; - default: - return -next == ESC_v; - } - - default: - return FALSE; - } - - case OP_DIGIT: - return next == -ESC_D || next == -ESC_s || next == -ESC_W || - next == -ESC_h || next == -ESC_v; - - case OP_NOT_DIGIT: - return next == -ESC_d; - - case OP_WHITESPACE: - return next == -ESC_S || next == -ESC_d || next == -ESC_w; - - case OP_NOT_WHITESPACE: - return next == -ESC_s || next == -ESC_h || next == -ESC_v; - - case OP_HSPACE: - return next == -ESC_S || next == -ESC_H || next == -ESC_d || next == -ESC_w; - - case OP_NOT_HSPACE: - return next == -ESC_h; - - /* Can't have \S in here because VT matches \S (Perl anomaly) */ - case OP_VSPACE: - return next == -ESC_V || next == -ESC_d || next == -ESC_w; - - case OP_NOT_VSPACE: - return next == -ESC_v; - - case OP_WORDCHAR: - return next == -ESC_W || next == -ESC_s || next == -ESC_h || next == -ESC_v; - - case OP_NOT_WORDCHAR: - return next == -ESC_w || next == -ESC_d; - - default: - return FALSE; - } - -/* Control does not reach here */ -} - - - -/************************************************* -* Compile one branch * -*************************************************/ - -/* Scan the pattern, compiling it into the a vector. If the options are -changed during the branch, the pointer is used to change the external options -bits. This function is used during the pre-compile phase when we are trying -to find out the amount of memory needed, as well as during the real compile -phase. The value of lengthptr distinguishes the two phases. - -Arguments: - optionsptr pointer to the option bits - codeptr points to the pointer to the current code point - ptrptr points to the current pattern pointer - errorcodeptr points to error code variable - firstbyteptr set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE) - reqbyteptr set to the last literal character required, else < 0 - bcptr points to current branch chain - cd contains pointers to tables etc. - lengthptr NULL during the real compile phase - points to length accumulator during pre-compile phase - -Returns: TRUE on success - FALSE, with *errorcodeptr set non-zero on error -*/ - -static BOOL -compile_branch(int *optionsptr, uschar **codeptr, const uschar **ptrptr, - int *errorcodeptr, int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr, - compile_data *cd, int *lengthptr) -{ -int repeat_type, op_type; -int repeat_min = 0, repeat_max = 0; /* To please picky compilers */ -int bravalue = 0; -int greedy_default, greedy_non_default; -int firstbyte, reqbyte; -int zeroreqbyte, zerofirstbyte; -int req_caseopt, reqvary, tempreqvary; -int options = *optionsptr; -int after_manual_callout = 0; -int length_prevgroup = 0; -register int c; -register uschar *code = *codeptr; -uschar *last_code = code; -uschar *orig_code = code; -uschar *tempcode; -BOOL inescq = FALSE; -BOOL groupsetfirstbyte = FALSE; -const uschar *ptr = *ptrptr; -const uschar *tempptr; -uschar *previous = NULL; -uschar *previous_callout = NULL; -uschar *save_hwm = NULL; -uschar classbits[32]; - -#ifdef SUPPORT_UTF8 -BOOL class_utf8; -BOOL utf8 = (options & PCRE_UTF8) != 0; -uschar *class_utf8data; -uschar *class_utf8data_base; -uschar utf8_char[6]; -#else -BOOL utf8 = FALSE; -uschar *utf8_char = NULL; -#endif - -#ifdef DEBUG -if (lengthptr != NULL) DPRINTF((">> start branch\n")); -#endif - -/* Set up the default and non-default settings for greediness */ - -greedy_default = ((options & PCRE_UNGREEDY) != 0); -greedy_non_default = greedy_default ^ 1; - -/* Initialize no first byte, no required byte. REQ_UNSET means "no char -matching encountered yet". It gets changed to REQ_NONE if we hit something that -matches a non-fixed char first char; reqbyte just remains unset if we never -find one. - -When we hit a repeat whose minimum is zero, we may have to adjust these values -to take the zero repeat into account. This is implemented by setting them to -zerofirstbyte and zeroreqbyte when such a repeat is encountered. The individual -item types that can be repeated set these backoff variables appropriately. */ - -firstbyte = reqbyte = zerofirstbyte = zeroreqbyte = REQ_UNSET; - -/* The variable req_caseopt contains either the REQ_CASELESS value or zero, -according to the current setting of the caseless flag. REQ_CASELESS is a bit -value > 255. It is added into the firstbyte or reqbyte variables to record the -case status of the value. This is used only for ASCII characters. */ - -req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS : 0; - -/* Switch on next character until the end of the branch */ - -for (;; ptr++) - { - BOOL negate_class; - BOOL should_flip_negation; - BOOL possessive_quantifier; - BOOL is_quantifier; - BOOL is_recurse; - BOOL reset_bracount; - int class_charcount; - int class_lastchar; - int newoptions; - int recno; - int refsign; - int skipbytes; - int subreqbyte; - int subfirstbyte; - int terminator; - int mclength; - uschar mcbuffer[8]; - - /* Get next byte in the pattern */ - - c = *ptr; - - /* If we are in the pre-compile phase, accumulate the length used for the - previous cycle of this loop. */ - - if (lengthptr != NULL) - { -#ifdef DEBUG - if (code > cd->hwm) cd->hwm = code; /* High water info */ -#endif - if (code > cd->start_workspace + COMPILE_WORK_SIZE) /* Check for overrun */ - { - *errorcodeptr = ERR52; - goto FAILED; - } - - /* There is at least one situation where code goes backwards: this is the - case of a zero quantifier after a class (e.g. [ab]{0}). At compile time, - the class is simply eliminated. However, it is created first, so we have to - allow memory for it. Therefore, don't ever reduce the length at this point. - */ - - if (code < last_code) code = last_code; - - /* Paranoid check for integer overflow */ - - if (OFLOW_MAX - *lengthptr < code - last_code) - { - *errorcodeptr = ERR20; - goto FAILED; - } - - *lengthptr += code - last_code; - DPRINTF(("length=%d added %d c=%c\n", *lengthptr, code - last_code, c)); - - /* If "previous" is set and it is not at the start of the work space, move - it back to there, in order to avoid filling up the work space. Otherwise, - if "previous" is NULL, reset the current code pointer to the start. */ - - if (previous != NULL) - { - if (previous > orig_code) - { - memmove(orig_code, previous, code - previous); - code -= previous - orig_code; - previous = orig_code; - } - } - else code = orig_code; - - /* Remember where this code item starts so we can pick up the length - next time round. */ - - last_code = code; - } - - /* In the real compile phase, just check the workspace used by the forward - reference list. */ - - else if (cd->hwm > cd->start_workspace + COMPILE_WORK_SIZE) - { - *errorcodeptr = ERR52; - goto FAILED; - } - - /* If in \Q...\E, check for the end; if not, we have a literal */ - - if (inescq && c != 0) - { - if (c == '\\' && ptr[1] == 'E') - { - inescq = FALSE; - ptr++; - continue; - } - else - { - if (previous_callout != NULL) - { - if (lengthptr == NULL) /* Don't attempt in pre-compile phase */ - complete_callout(previous_callout, ptr, cd); - previous_callout = NULL; - } - if ((options & PCRE_AUTO_CALLOUT) != 0) - { - previous_callout = code; - code = auto_callout(code, ptr, cd); - } - goto NORMAL_CHAR; - } - } - - /* Fill in length of a previous callout, except when the next thing is - a quantifier. */ - - is_quantifier = c == '*' || c == '+' || c == '?' || - (c == '{' && is_counted_repeat(ptr+1)); - - if (!is_quantifier && previous_callout != NULL && - after_manual_callout-- <= 0) - { - if (lengthptr == NULL) /* Don't attempt in pre-compile phase */ - complete_callout(previous_callout, ptr, cd); - previous_callout = NULL; - } - - /* In extended mode, skip white space and comments */ - - if ((options & PCRE_EXTENDED) != 0) - { - if ((cd->ctypes[c] & ctype_space) != 0) continue; - if (c == '#') - { - while (*(++ptr) != 0) - { - if (IS_NEWLINE(ptr)) { ptr += cd->nllen - 1; break; } - } - if (*ptr != 0) continue; - - /* Else fall through to handle end of string */ - c = 0; - } - } - - /* No auto callout for quantifiers. */ - - if ((options & PCRE_AUTO_CALLOUT) != 0 && !is_quantifier) - { - previous_callout = code; - code = auto_callout(code, ptr, cd); - } - - switch(c) - { - /* ===================================================================*/ - case 0: /* The branch terminates at string end */ - case '|': /* or | or ) */ - case ')': - *firstbyteptr = firstbyte; - *reqbyteptr = reqbyte; - *codeptr = code; - *ptrptr = ptr; - if (lengthptr != NULL) - { - if (OFLOW_MAX - *lengthptr < code - last_code) - { - *errorcodeptr = ERR20; - goto FAILED; - } - *lengthptr += code - last_code; /* To include callout length */ - DPRINTF((">> end branch\n")); - } - return TRUE; - - - /* ===================================================================*/ - /* Handle single-character metacharacters. In multiline mode, ^ disables - the setting of any following char as a first character. */ - - case '^': - if ((options & PCRE_MULTILINE) != 0) - { - if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; - } - previous = NULL; - *code++ = OP_CIRC; - break; - - case '$': - previous = NULL; - *code++ = OP_DOLL; - break; - - /* There can never be a first char if '.' is first, whatever happens about - repeats. The value of reqbyte doesn't change either. */ - - case '.': - if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; - zerofirstbyte = firstbyte; - zeroreqbyte = reqbyte; - previous = code; - *code++ = ((options & PCRE_DOTALL) != 0)? OP_ALLANY: OP_ANY; - break; - - - /* ===================================================================*/ - /* Character classes. If the included characters are all < 256, we build a - 32-byte bitmap of the permitted characters, except in the special case - where there is only one such character. For negated classes, we build the - map as usual, then invert it at the end. However, we use a different opcode - so that data characters > 255 can be handled correctly. - - If the class contains characters outside the 0-255 range, a different - opcode is compiled. It may optionally have a bit map for characters < 256, - but those above are are explicitly listed afterwards. A flag byte tells - whether the bitmap is present, and whether this is a negated class or not. - - In JavaScript compatibility mode, an isolated ']' causes an error. In - default (Perl) mode, it is treated as a data character. */ - - case ']': - if ((cd->external_options & PCRE_JAVASCRIPT_COMPAT) != 0) - { - *errorcodeptr = ERR64; - goto FAILED; - } - goto NORMAL_CHAR; - - case '[': - previous = code; - - /* PCRE supports POSIX class stuff inside a class. Perl gives an error if - they are encountered at the top level, so we'll do that too. */ - - if ((ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') && - check_posix_syntax(ptr, &tempptr)) - { - *errorcodeptr = (ptr[1] == ':')? ERR13 : ERR31; - goto FAILED; - } - - /* If the first character is '^', set the negation flag and skip it. Also, - if the first few characters (either before or after ^) are \Q\E or \E we - skip them too. This makes for compatibility with Perl. */ - - negate_class = FALSE; - for (;;) - { - c = *(++ptr); - if (c == '\\') - { - if (ptr[1] == 'E') ptr++; - else if (strncmp((const char *)ptr+1, "Q\\E", 3) == 0) ptr += 3; - else break; - } - else if (!negate_class && c == '^') - negate_class = TRUE; - else break; - } - - /* Empty classes are allowed in JavaScript compatibility mode. Otherwise, - an initial ']' is taken as a data character -- the code below handles - that. In JS mode, [] must always fail, so generate OP_FAIL, whereas - [^] must match any character, so generate OP_ALLANY. */ - - if (c ==']' && (cd->external_options & PCRE_JAVASCRIPT_COMPAT) != 0) - { - *code++ = negate_class? OP_ALLANY : OP_FAIL; - if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; - zerofirstbyte = firstbyte; - break; - } - - /* If a class contains a negative special such as \S, we need to flip the - negation flag at the end, so that support for characters > 255 works - correctly (they are all included in the class). */ - - should_flip_negation = FALSE; - - /* Keep a count of chars with values < 256 so that we can optimize the case - of just a single character (as long as it's < 256). However, For higher - valued UTF-8 characters, we don't yet do any optimization. */ - - class_charcount = 0; - class_lastchar = -1; - - /* Initialize the 32-char bit map to all zeros. We build the map in a - temporary bit of memory, in case the class contains only 1 character (less - than 256), because in that case the compiled code doesn't use the bit map. - */ - - memset(classbits, 0, 32 * sizeof(uschar)); - -#ifdef SUPPORT_UTF8 - class_utf8 = FALSE; /* No chars >= 256 */ - class_utf8data = code + LINK_SIZE + 2; /* For UTF-8 items */ - class_utf8data_base = class_utf8data; /* For resetting in pass 1 */ -#endif - - /* Process characters until ] is reached. By writing this as a "do" it - means that an initial ] is taken as a data character. At the start of the - loop, c contains the first byte of the character. */ - - if (c != 0) do - { - const uschar *oldptr; - -#ifdef SUPPORT_UTF8 - if (utf8 && c > 127) - { /* Braces are required because the */ - GETCHARLEN(c, ptr, ptr); /* macro generates multiple statements */ - } - - /* In the pre-compile phase, accumulate the length of any UTF-8 extra - data and reset the pointer. This is so that very large classes that - contain a zillion UTF-8 characters no longer overwrite the work space - (which is on the stack). */ - - if (lengthptr != NULL) - { - *lengthptr += class_utf8data - class_utf8data_base; - class_utf8data = class_utf8data_base; - } - -#endif - - /* Inside \Q...\E everything is literal except \E */ - - if (inescq) - { - if (c == '\\' && ptr[1] == 'E') /* If we are at \E */ - { - inescq = FALSE; /* Reset literal state */ - ptr++; /* Skip the 'E' */ - continue; /* Carry on with next */ - } - goto CHECK_RANGE; /* Could be range if \E follows */ - } - - /* Handle POSIX class names. Perl allows a negation extension of the - form [:^name:]. A square bracket that doesn't match the syntax is - treated as a literal. We also recognize the POSIX constructions - [.ch.] and [=ch=] ("collating elements") and fault them, as Perl - 5.6 and 5.8 do. */ - - if (c == '[' && - (ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') && - check_posix_syntax(ptr, &tempptr)) - { - BOOL local_negate = FALSE; - int posix_class, taboffset, tabopt; - register const uschar *cbits = cd->cbits; - uschar pbits[32]; - - if (ptr[1] != ':') - { - *errorcodeptr = ERR31; - goto FAILED; - } - - ptr += 2; - if (*ptr == '^') - { - local_negate = TRUE; - should_flip_negation = TRUE; /* Note negative special */ - ptr++; - } - - posix_class = check_posix_name(ptr, tempptr - ptr); - if (posix_class < 0) - { - *errorcodeptr = ERR30; - goto FAILED; - } - - /* If matching is caseless, upper and lower are converted to - alpha. This relies on the fact that the class table starts with - alpha, lower, upper as the first 3 entries. */ - - if ((options & PCRE_CASELESS) != 0 && posix_class <= 2) - posix_class = 0; - - /* We build the bit map for the POSIX class in a chunk of local store - because we may be adding and subtracting from it, and we don't want to - subtract bits that may be in the main map already. At the end we or the - result into the bit map that is being built. */ - - posix_class *= 3; - - /* Copy in the first table (always present) */ - - memcpy(pbits, cbits + posix_class_maps[posix_class], - 32 * sizeof(uschar)); - - /* If there is a second table, add or remove it as required. */ - - taboffset = posix_class_maps[posix_class + 1]; - tabopt = posix_class_maps[posix_class + 2]; - - if (taboffset >= 0) - { - if (tabopt >= 0) - for (c = 0; c < 32; c++) pbits[c] |= cbits[c + taboffset]; - else - for (c = 0; c < 32; c++) pbits[c] &= ~cbits[c + taboffset]; - } - - /* Not see if we need to remove any special characters. An option - value of 1 removes vertical space and 2 removes underscore. */ - - if (tabopt < 0) tabopt = -tabopt; - if (tabopt == 1) pbits[1] &= ~0x3c; - else if (tabopt == 2) pbits[11] &= 0x7f; - - /* Add the POSIX table or its complement into the main table that is - being built and we are done. */ - - if (local_negate) - for (c = 0; c < 32; c++) classbits[c] |= ~pbits[c]; - else - for (c = 0; c < 32; c++) classbits[c] |= pbits[c]; - - ptr = tempptr + 1; - class_charcount = 10; /* Set > 1; assumes more than 1 per class */ - continue; /* End of POSIX syntax handling */ - } - - /* Backslash may introduce a single character, or it may introduce one - of the specials, which just set a flag. The sequence \b is a special - case. Inside a class (and only there) it is treated as backspace. - Elsewhere it marks a word boundary. Other escapes have preset maps ready - to 'or' into the one we are building. We assume they have more than one - character in them, so set class_charcount bigger than one. */ - - if (c == '\\') - { - c = check_escape(&ptr, errorcodeptr, cd->bracount, options, TRUE); - if (*errorcodeptr != 0) goto FAILED; - - if (-c == ESC_b) c = '\b'; /* \b is backspace in a class */ - else if (-c == ESC_X) c = 'X'; /* \X is literal X in a class */ - else if (-c == ESC_R) c = 'R'; /* \R is literal R in a class */ - else if (-c == ESC_Q) /* Handle start of quoted string */ - { - if (ptr[1] == '\\' && ptr[2] == 'E') - { - ptr += 2; /* avoid empty string */ - } - else inescq = TRUE; - continue; - } - else if (-c == ESC_E) continue; /* Ignore orphan \E */ - - if (c < 0) - { - register const uschar *cbits = cd->cbits; - class_charcount += 2; /* Greater than 1 is what matters */ - - /* Save time by not doing this in the pre-compile phase. */ - - if (lengthptr == NULL) switch (-c) - { - case ESC_d: - for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_digit]; - continue; - - case ESC_D: - should_flip_negation = TRUE; - for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_digit]; - continue; - - case ESC_w: - for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_word]; - continue; - - case ESC_W: - should_flip_negation = TRUE; - for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_word]; - continue; - - case ESC_s: - for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_space]; - classbits[1] &= ~0x08; /* Perl 5.004 onwards omits VT from \s */ - continue; - - case ESC_S: - should_flip_negation = TRUE; - for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_space]; - classbits[1] |= 0x08; /* Perl 5.004 onwards omits VT from \s */ - continue; - - default: /* Not recognized; fall through */ - break; /* Need "default" setting to stop compiler warning. */ - } - - /* In the pre-compile phase, just do the recognition. */ - - else if (c == -ESC_d || c == -ESC_D || c == -ESC_w || - c == -ESC_W || c == -ESC_s || c == -ESC_S) continue; - - /* We need to deal with \H, \h, \V, and \v in both phases because - they use extra memory. */ - - if (-c == ESC_h) - { - SETBIT(classbits, 0x09); /* VT */ - SETBIT(classbits, 0x20); /* SPACE */ - SETBIT(classbits, 0xa0); /* NSBP */ -#ifdef SUPPORT_UTF8 - if (utf8) - { - class_utf8 = TRUE; - *class_utf8data++ = XCL_SINGLE; - class_utf8data += _pcre_ord2utf8(0x1680, class_utf8data); - *class_utf8data++ = XCL_SINGLE; - class_utf8data += _pcre_ord2utf8(0x180e, class_utf8data); - *class_utf8data++ = XCL_RANGE; - class_utf8data += _pcre_ord2utf8(0x2000, class_utf8data); - class_utf8data += _pcre_ord2utf8(0x200A, class_utf8data); - *class_utf8data++ = XCL_SINGLE; - class_utf8data += _pcre_ord2utf8(0x202f, class_utf8data); - *class_utf8data++ = XCL_SINGLE; - class_utf8data += _pcre_ord2utf8(0x205f, class_utf8data); - *class_utf8data++ = XCL_SINGLE; - class_utf8data += _pcre_ord2utf8(0x3000, class_utf8data); - } -#endif - continue; - } - - if (-c == ESC_H) - { - for (c = 0; c < 32; c++) - { - int x = 0xff; - switch (c) - { - case 0x09/8: x ^= 1 << (0x09%8); break; - case 0x20/8: x ^= 1 << (0x20%8); break; - case 0xa0/8: x ^= 1 << (0xa0%8); break; - default: break; - } - classbits[c] |= x; - } - -#ifdef SUPPORT_UTF8 - if (utf8) - { - class_utf8 = TRUE; - *class_utf8data++ = XCL_RANGE; - class_utf8data += _pcre_ord2utf8(0x0100, class_utf8data); - class_utf8data += _pcre_ord2utf8(0x167f, class_utf8data); - *class_utf8data++ = XCL_RANGE; - class_utf8data += _pcre_ord2utf8(0x1681, class_utf8data); - class_utf8data += _pcre_ord2utf8(0x180d, class_utf8data); - *class_utf8data++ = XCL_RANGE; - class_utf8data += _pcre_ord2utf8(0x180f, class_utf8data); - class_utf8data += _pcre_ord2utf8(0x1fff, class_utf8data); - *class_utf8data++ = XCL_RANGE; - class_utf8data += _pcre_ord2utf8(0x200B, class_utf8data); - class_utf8data += _pcre_ord2utf8(0x202e, class_utf8data); - *class_utf8data++ = XCL_RANGE; - class_utf8data += _pcre_ord2utf8(0x2030, class_utf8data); - class_utf8data += _pcre_ord2utf8(0x205e, class_utf8data); - *class_utf8data++ = XCL_RANGE; - class_utf8data += _pcre_ord2utf8(0x2060, class_utf8data); - class_utf8data += _pcre_ord2utf8(0x2fff, class_utf8data); - *class_utf8data++ = XCL_RANGE; - class_utf8data += _pcre_ord2utf8(0x3001, class_utf8data); - class_utf8data += _pcre_ord2utf8(0x7fffffff, class_utf8data); - } -#endif - continue; - } - - if (-c == ESC_v) - { - SETBIT(classbits, 0x0a); /* LF */ - SETBIT(classbits, 0x0b); /* VT */ - SETBIT(classbits, 0x0c); /* FF */ - SETBIT(classbits, 0x0d); /* CR */ - SETBIT(classbits, 0x85); /* NEL */ -#ifdef SUPPORT_UTF8 - if (utf8) - { - class_utf8 = TRUE; - *class_utf8data++ = XCL_RANGE; - class_utf8data += _pcre_ord2utf8(0x2028, class_utf8data); - class_utf8data += _pcre_ord2utf8(0x2029, class_utf8data); - } -#endif - continue; - } - - if (-c == ESC_V) - { - for (c = 0; c < 32; c++) - { - int x = 0xff; - switch (c) - { - case 0x0a/8: x ^= 1 << (0x0a%8); - x ^= 1 << (0x0b%8); - x ^= 1 << (0x0c%8); - x ^= 1 << (0x0d%8); - break; - case 0x85/8: x ^= 1 << (0x85%8); break; - default: break; - } - classbits[c] |= x; - } - -#ifdef SUPPORT_UTF8 - if (utf8) - { - class_utf8 = TRUE; - *class_utf8data++ = XCL_RANGE; - class_utf8data += _pcre_ord2utf8(0x0100, class_utf8data); - class_utf8data += _pcre_ord2utf8(0x2027, class_utf8data); - *class_utf8data++ = XCL_RANGE; - class_utf8data += _pcre_ord2utf8(0x2029, class_utf8data); - class_utf8data += _pcre_ord2utf8(0x7fffffff, class_utf8data); - } -#endif - continue; - } - - /* We need to deal with \P and \p in both phases. */ - -#ifdef SUPPORT_UCP - if (-c == ESC_p || -c == ESC_P) - { - BOOL negated; - int pdata; - int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr); - if (ptype < 0) goto FAILED; - class_utf8 = TRUE; - *class_utf8data++ = ((-c == ESC_p) != negated)? - XCL_PROP : XCL_NOTPROP; - *class_utf8data++ = ptype; - *class_utf8data++ = pdata; - class_charcount -= 2; /* Not a < 256 character */ - continue; - } -#endif - /* Unrecognized escapes are faulted if PCRE is running in its - strict mode. By default, for compatibility with Perl, they are - treated as literals. */ - - if ((options & PCRE_EXTRA) != 0) - { - *errorcodeptr = ERR7; - goto FAILED; - } - - class_charcount -= 2; /* Undo the default count from above */ - c = *ptr; /* Get the final character and fall through */ - } - - /* Fall through if we have a single character (c >= 0). This may be - greater than 256 in UTF-8 mode. */ - - } /* End of backslash handling */ - - /* A single character may be followed by '-' to form a range. However, - Perl does not permit ']' to be the end of the range. A '-' character - at the end is treated as a literal. Perl ignores orphaned \E sequences - entirely. The code for handling \Q and \E is messy. */ - - CHECK_RANGE: - while (ptr[1] == '\\' && ptr[2] == 'E') - { - inescq = FALSE; - ptr += 2; - } - - oldptr = ptr; - - /* Remember \r or \n */ - - if (c == '\r' || c == '\n') cd->external_flags |= PCRE_HASCRORLF; - - /* Check for range */ - - if (!inescq && ptr[1] == '-') - { - int d; - ptr += 2; - while (*ptr == '\\' && ptr[1] == 'E') ptr += 2; - - /* If we hit \Q (not followed by \E) at this point, go into escaped - mode. */ - - while (*ptr == '\\' && ptr[1] == 'Q') - { - ptr += 2; - if (*ptr == '\\' && ptr[1] == 'E') { ptr += 2; continue; } - inescq = TRUE; - break; - } - - if (*ptr == 0 || (!inescq && *ptr == ']')) - { - ptr = oldptr; - goto LONE_SINGLE_CHARACTER; - } - -#ifdef SUPPORT_UTF8 - if (utf8) - { /* Braces are required because the */ - GETCHARLEN(d, ptr, ptr); /* macro generates multiple statements */ - } - else -#endif - d = *ptr; /* Not UTF-8 mode */ - - /* The second part of a range can be a single-character escape, but - not any of the other escapes. Perl 5.6 treats a hyphen as a literal - in such circumstances. */ - - if (!inescq && d == '\\') - { - d = check_escape(&ptr, errorcodeptr, cd->bracount, options, TRUE); - if (*errorcodeptr != 0) goto FAILED; - - /* \b is backspace; \X is literal X; \R is literal R; any other - special means the '-' was literal */ - - if (d < 0) - { - if (d == -ESC_b) d = '\b'; - else if (d == -ESC_X) d = 'X'; - else if (d == -ESC_R) d = 'R'; else - { - ptr = oldptr; - goto LONE_SINGLE_CHARACTER; /* A few lines below */ - } - } - } - - /* Check that the two values are in the correct order. Optimize - one-character ranges */ - - if (d < c) - { - *errorcodeptr = ERR8; - goto FAILED; - } - - if (d == c) goto LONE_SINGLE_CHARACTER; /* A few lines below */ - - /* Remember \r or \n */ - - if (d == '\r' || d == '\n') cd->external_flags |= PCRE_HASCRORLF; - - /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless - matching, we have to use an XCLASS with extra data items. Caseless - matching for characters > 127 is available only if UCP support is - available. */ - -#ifdef SUPPORT_UTF8 - if (utf8 && (d > 255 || ((options & PCRE_CASELESS) != 0 && d > 127))) - { - class_utf8 = TRUE; - - /* With UCP support, we can find the other case equivalents of - the relevant characters. There may be several ranges. Optimize how - they fit with the basic range. */ - -#ifdef SUPPORT_UCP - if ((options & PCRE_CASELESS) != 0) - { - unsigned int occ, ocd; - unsigned int cc = c; - unsigned int origd = d; - while (get_othercase_range(&cc, origd, &occ, &ocd)) - { - if (occ >= (unsigned int)c && - ocd <= (unsigned int)d) - continue; /* Skip embedded ranges */ - - if (occ < (unsigned int)c && - ocd >= (unsigned int)c - 1) /* Extend the basic range */ - { /* if there is overlap, */ - c = occ; /* noting that if occ < c */ - continue; /* we can't have ocd > d */ - } /* because a subrange is */ - if (ocd > (unsigned int)d && - occ <= (unsigned int)d + 1) /* always shorter than */ - { /* the basic range. */ - d = ocd; - continue; - } - - if (occ == ocd) - { - *class_utf8data++ = XCL_SINGLE; - } - else - { - *class_utf8data++ = XCL_RANGE; - class_utf8data += _pcre_ord2utf8(occ, class_utf8data); - } - class_utf8data += _pcre_ord2utf8(ocd, class_utf8data); - } - } -#endif /* SUPPORT_UCP */ - - /* Now record the original range, possibly modified for UCP caseless - overlapping ranges. */ - - *class_utf8data++ = XCL_RANGE; - class_utf8data += _pcre_ord2utf8(c, class_utf8data); - class_utf8data += _pcre_ord2utf8(d, class_utf8data); - - /* With UCP support, we are done. Without UCP support, there is no - caseless matching for UTF-8 characters > 127; we can use the bit map - for the smaller ones. */ - -#ifdef SUPPORT_UCP - continue; /* With next character in the class */ -#else - if ((options & PCRE_CASELESS) == 0 || c > 127) continue; - - /* Adjust upper limit and fall through to set up the map */ - - d = 127; - -#endif /* SUPPORT_UCP */ - } -#endif /* SUPPORT_UTF8 */ - - /* We use the bit map for all cases when not in UTF-8 mode; else - ranges that lie entirely within 0-127 when there is UCP support; else - for partial ranges without UCP support. */ - - class_charcount += d - c + 1; - class_lastchar = d; - - /* We can save a bit of time by skipping this in the pre-compile. */ - - if (lengthptr == NULL) for (; c <= d; c++) - { - classbits[c/8] |= (1 << (c&7)); - if ((options & PCRE_CASELESS) != 0) - { - int uc = cd->fcc[c]; /* flip case */ - classbits[uc/8] |= (1 << (uc&7)); - } - } - - continue; /* Go get the next char in the class */ - } - - /* Handle a lone single character - we can get here for a normal - non-escape char, or after \ that introduces a single character or for an - apparent range that isn't. */ - - LONE_SINGLE_CHARACTER: - - /* Handle a character that cannot go in the bit map */ - -#ifdef SUPPORT_UTF8 - if (utf8 && (c > 255 || ((options & PCRE_CASELESS) != 0 && c > 127))) - { - class_utf8 = TRUE; - *class_utf8data++ = XCL_SINGLE; - class_utf8data += _pcre_ord2utf8(c, class_utf8data); - -#ifdef SUPPORT_UCP - if ((options & PCRE_CASELESS) != 0) - { - unsigned int othercase; - if ((othercase = UCD_OTHERCASE(c)) != c) - { - *class_utf8data++ = XCL_SINGLE; - class_utf8data += _pcre_ord2utf8(othercase, class_utf8data); - } - } -#endif /* SUPPORT_UCP */ - - } - else -#endif /* SUPPORT_UTF8 */ - - /* Handle a single-byte character */ - { - classbits[c/8] |= (1 << (c&7)); - if ((options & PCRE_CASELESS) != 0) - { - c = cd->fcc[c]; /* flip case */ - classbits[c/8] |= (1 << (c&7)); - } - class_charcount++; - class_lastchar = c; - } - } - - /* Loop until ']' reached. This "while" is the end of the "do" above. */ - - while ((c = *(++ptr)) != 0 && (c != ']' || inescq)); - - if (c == 0) /* Missing terminating ']' */ - { - *errorcodeptr = ERR6; - goto FAILED; - } - - -/* This code has been disabled because it would mean that \s counts as -an explicit \r or \n reference, and that's not really what is wanted. Now -we set the flag only if there is a literal "\r" or "\n" in the class. */ - -#if 0 - /* Remember whether \r or \n are in this class */ - - if (negate_class) - { - if ((classbits[1] & 0x24) != 0x24) cd->external_flags |= PCRE_HASCRORLF; - } - else - { - if ((classbits[1] & 0x24) != 0) cd->external_flags |= PCRE_HASCRORLF; - } -#endif - - - /* If class_charcount is 1, we saw precisely one character whose value is - less than 256. As long as there were no characters >= 128 and there was no - use of \p or \P, in other words, no use of any XCLASS features, we can - optimize. - - In UTF-8 mode, we can optimize the negative case only if there were no - characters >= 128 because OP_NOT and the related opcodes like OP_NOTSTAR - operate on single-bytes only. This is an historical hangover. Maybe one day - we can tidy these opcodes to handle multi-byte characters. - - The optimization throws away the bit map. We turn the item into a - 1-character OP_CHAR[NC] if it's positive, or OP_NOT if it's negative. Note - that OP_NOT does not support multibyte characters. In the positive case, it - can cause firstbyte to be set. Otherwise, there can be no first char if - this item is first, whatever repeat count may follow. In the case of - reqbyte, save the previous value for reinstating. */ - -#ifdef SUPPORT_UTF8 - if (class_charcount == 1 && !class_utf8 && - (!utf8 || !negate_class || class_lastchar < 128)) -#else - if (class_charcount == 1) -#endif - { - zeroreqbyte = reqbyte; - - /* The OP_NOT opcode works on one-byte characters only. */ - - if (negate_class) - { - if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; - zerofirstbyte = firstbyte; - *code++ = OP_NOT; - *code++ = class_lastchar; - break; - } - - /* For a single, positive character, get the value into mcbuffer, and - then we can handle this with the normal one-character code. */ - -#ifdef SUPPORT_UTF8 - if (utf8 && class_lastchar > 127) - mclength = _pcre_ord2utf8(class_lastchar, mcbuffer); - else -#endif - { - mcbuffer[0] = class_lastchar; - mclength = 1; - } - goto ONE_CHAR; - } /* End of 1-char optimization */ - - /* The general case - not the one-char optimization. If this is the first - thing in the branch, there can be no first char setting, whatever the - repeat count. Any reqbyte setting must remain unchanged after any kind of - repeat. */ - - if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; - zerofirstbyte = firstbyte; - zeroreqbyte = reqbyte; - - /* If there are characters with values > 255, we have to compile an - extended class, with its own opcode, unless there was a negated special - such as \S in the class, because in that case all characters > 255 are in - the class, so any that were explicitly given as well can be ignored. If - (when there are explicit characters > 255 that must be listed) there are no - characters < 256, we can omit the bitmap in the actual compiled code. */ - -#ifdef SUPPORT_UTF8 - if (class_utf8 && !should_flip_negation) - { - *class_utf8data++ = XCL_END; /* Marks the end of extra data */ - *code++ = OP_XCLASS; - code += LINK_SIZE; - *code = negate_class? XCL_NOT : 0; - - /* If the map is required, move up the extra data to make room for it; - otherwise just move the code pointer to the end of the extra data. */ - - if (class_charcount > 0) - { - *code++ |= XCL_MAP; - memmove(code + 32, code, class_utf8data - code); - memcpy(code, classbits, 32); - code = class_utf8data + 32; - } - else code = class_utf8data; - - /* Now fill in the complete length of the item */ - - PUT(previous, 1, code - previous); - break; /* End of class handling */ - } -#endif - - /* If there are no characters > 255, set the opcode to OP_CLASS or - OP_NCLASS, depending on whether the whole class was negated and whether - there were negative specials such as \S in the class. Then copy the 32-byte - map into the code vector, negating it if necessary. */ - - *code++ = (negate_class == should_flip_negation) ? OP_CLASS : OP_NCLASS; - if (negate_class) - { - if (lengthptr == NULL) /* Save time in the pre-compile phase */ - for (c = 0; c < 32; c++) code[c] = ~classbits[c]; - } - else - { - memcpy(code, classbits, 32); - } - code += 32; - break; - - - /* ===================================================================*/ - /* Various kinds of repeat; '{' is not necessarily a quantifier, but this - has been tested above. */ - - case '{': - if (!is_quantifier) goto NORMAL_CHAR; - ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorcodeptr); - if (*errorcodeptr != 0) goto FAILED; - goto REPEAT; - - case '*': - repeat_min = 0; - repeat_max = -1; - goto REPEAT; - - case '+': - repeat_min = 1; - repeat_max = -1; - goto REPEAT; - - case '?': - repeat_min = 0; - repeat_max = 1; - - REPEAT: - if (previous == NULL) - { - *errorcodeptr = ERR9; - goto FAILED; - } - - if (repeat_min == 0) - { - firstbyte = zerofirstbyte; /* Adjust for zero repeat */ - reqbyte = zeroreqbyte; /* Ditto */ - } - - /* Remember whether this is a variable length repeat */ - - reqvary = (repeat_min == repeat_max)? 0 : REQ_VARY; - - op_type = 0; /* Default single-char op codes */ - possessive_quantifier = FALSE; /* Default not possessive quantifier */ - - /* Save start of previous item, in case we have to move it up to make space - for an inserted OP_ONCE for the additional '+' extension. */ - - tempcode = previous; - - /* If the next character is '+', we have a possessive quantifier. This - implies greediness, whatever the setting of the PCRE_UNGREEDY option. - If the next character is '?' this is a minimizing repeat, by default, - but if PCRE_UNGREEDY is set, it works the other way round. We change the - repeat type to the non-default. */ - - if (ptr[1] == '+') - { - repeat_type = 0; /* Force greedy */ - possessive_quantifier = TRUE; - ptr++; - } - else if (ptr[1] == '?') - { - repeat_type = greedy_non_default; - ptr++; - } - else repeat_type = greedy_default; - - /* If previous was a character match, abolish the item and generate a - repeat item instead. If a char item has a minumum of more than one, ensure - that it is set in reqbyte - it might not be if a sequence such as x{3} is - the first thing in a branch because the x will have gone into firstbyte - instead. */ - - if (*previous == OP_CHAR || *previous == OP_CHARNC) - { - /* Deal with UTF-8 characters that take up more than one byte. It's - easier to write this out separately than try to macrify it. Use c to - hold the length of the character in bytes, plus 0x80 to flag that it's a - length rather than a small character. */ - -#ifdef SUPPORT_UTF8 - if (utf8 && (code[-1] & 0x80) != 0) - { - uschar *lastchar = code - 1; - while((*lastchar & 0xc0) == 0x80) lastchar--; - c = code - lastchar; /* Length of UTF-8 character */ - memcpy(utf8_char, lastchar, c); /* Save the char */ - c |= 0x80; /* Flag c as a length */ - } - else -#endif - - /* Handle the case of a single byte - either with no UTF8 support, or - with UTF-8 disabled, or for a UTF-8 character < 128. */ - - { - c = code[-1]; - if (repeat_min > 1) reqbyte = c | req_caseopt | cd->req_varyopt; - } - - /* If the repetition is unlimited, it pays to see if the next thing on - the line is something that cannot possibly match this character. If so, - automatically possessifying this item gains some performance in the case - where the match fails. */ - - if (!possessive_quantifier && - repeat_max < 0 && - check_auto_possessive(*previous, c, utf8, utf8_char, ptr + 1, - options, cd)) - { - repeat_type = 0; /* Force greedy */ - possessive_quantifier = TRUE; - } - - goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ - } - - /* If previous was a single negated character ([^a] or similar), we use - one of the special opcodes, replacing it. The code is shared with single- - character repeats by setting opt_type to add a suitable offset into - repeat_type. We can also test for auto-possessification. OP_NOT is - currently used only for single-byte chars. */ - - else if (*previous == OP_NOT) - { - op_type = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */ - c = previous[1]; - if (!possessive_quantifier && - repeat_max < 0 && - check_auto_possessive(OP_NOT, c, utf8, NULL, ptr + 1, options, cd)) - { - repeat_type = 0; /* Force greedy */ - possessive_quantifier = TRUE; - } - goto OUTPUT_SINGLE_REPEAT; - } - - /* If previous was a character type match (\d or similar), abolish it and - create a suitable repeat item. The code is shared with single-character - repeats by setting op_type to add a suitable offset into repeat_type. Note - the the Unicode property types will be present only when SUPPORT_UCP is - defined, but we don't wrap the little bits of code here because it just - makes it horribly messy. */ - - else if (*previous < OP_EODN) - { - uschar *oldcode; - int prop_type, prop_value; - op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ - c = *previous; - - if (!possessive_quantifier && - repeat_max < 0 && - check_auto_possessive(c, 0, utf8, NULL, ptr + 1, options, cd)) - { - repeat_type = 0; /* Force greedy */ - possessive_quantifier = TRUE; - } - - OUTPUT_SINGLE_REPEAT: - if (*previous == OP_PROP || *previous == OP_NOTPROP) - { - prop_type = previous[1]; - prop_value = previous[2]; - } - else prop_type = prop_value = -1; - - oldcode = code; - code = previous; /* Usually overwrite previous item */ - - /* If the maximum is zero then the minimum must also be zero; Perl allows - this case, so we do too - by simply omitting the item altogether. */ - - if (repeat_max == 0) goto END_REPEAT; - - /* All real repeats make it impossible to handle partial matching (maybe - one day we will be able to remove this restriction). */ - - if (repeat_max != 1) cd->external_flags |= PCRE_NOPARTIAL; - - /* Combine the op_type with the repeat_type */ - - repeat_type += op_type; - - /* A minimum of zero is handled either as the special case * or ?, or as - an UPTO, with the maximum given. */ - - if (repeat_min == 0) - { - if (repeat_max == -1) *code++ = OP_STAR + repeat_type; - else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type; - else - { - *code++ = OP_UPTO + repeat_type; - PUT2INC(code, 0, repeat_max); - } - } - - /* A repeat minimum of 1 is optimized into some special cases. If the - maximum is unlimited, we use OP_PLUS. Otherwise, the original item is - left in place and, if the maximum is greater than 1, we use OP_UPTO with - one less than the maximum. */ - - else if (repeat_min == 1) - { - if (repeat_max == -1) - *code++ = OP_PLUS + repeat_type; - else - { - code = oldcode; /* leave previous item in place */ - if (repeat_max == 1) goto END_REPEAT; - *code++ = OP_UPTO + repeat_type; - PUT2INC(code, 0, repeat_max - 1); - } - } - - /* The case {n,n} is just an EXACT, while the general case {n,m} is - handled as an EXACT followed by an UPTO. */ - - else - { - *code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */ - PUT2INC(code, 0, repeat_min); - - /* If the maximum is unlimited, insert an OP_STAR. Before doing so, - we have to insert the character for the previous code. For a repeated - Unicode property match, there are two extra bytes that define the - required property. In UTF-8 mode, long characters have their length in - c, with the 0x80 bit as a flag. */ - - if (repeat_max < 0) - { -#ifdef SUPPORT_UTF8 - if (utf8 && c >= 128) - { - memcpy(code, utf8_char, c & 7); - code += c & 7; - } - else -#endif - { - *code++ = c; - if (prop_type >= 0) - { - *code++ = prop_type; - *code++ = prop_value; - } - } - *code++ = OP_STAR + repeat_type; - } - - /* Else insert an UPTO if the max is greater than the min, again - preceded by the character, for the previously inserted code. If the - UPTO is just for 1 instance, we can use QUERY instead. */ - - else if (repeat_max != repeat_min) - { -#ifdef SUPPORT_UTF8 - if (utf8 && c >= 128) - { - memcpy(code, utf8_char, c & 7); - code += c & 7; - } - else -#endif - *code++ = c; - if (prop_type >= 0) - { - *code++ = prop_type; - *code++ = prop_value; - } - repeat_max -= repeat_min; - - if (repeat_max == 1) - { - *code++ = OP_QUERY + repeat_type; - } - else - { - *code++ = OP_UPTO + repeat_type; - PUT2INC(code, 0, repeat_max); - } - } - } - - /* The character or character type itself comes last in all cases. */ - -#ifdef SUPPORT_UTF8 - if (utf8 && c >= 128) - { - memcpy(code, utf8_char, c & 7); - code += c & 7; - } - else -#endif - *code++ = c; - - /* For a repeated Unicode property match, there are two extra bytes that - define the required property. */ - -#ifdef SUPPORT_UCP - if (prop_type >= 0) - { - *code++ = prop_type; - *code++ = prop_value; - } -#endif - } - - /* If previous was a character class or a back reference, we put the repeat - stuff after it, but just skip the item if the repeat was {0,0}. */ - - else if (*previous == OP_CLASS || - *previous == OP_NCLASS || -#ifdef SUPPORT_UTF8 - *previous == OP_XCLASS || -#endif - *previous == OP_REF) - { - if (repeat_max == 0) - { - code = previous; - goto END_REPEAT; - } - - /* All real repeats make it impossible to handle partial matching (maybe - one day we will be able to remove this restriction). */ - - if (repeat_max != 1) cd->external_flags |= PCRE_NOPARTIAL; - - if (repeat_min == 0 && repeat_max == -1) - *code++ = OP_CRSTAR + repeat_type; - else if (repeat_min == 1 && repeat_max == -1) - *code++ = OP_CRPLUS + repeat_type; - else if (repeat_min == 0 && repeat_max == 1) - *code++ = OP_CRQUERY + repeat_type; - else - { - *code++ = OP_CRRANGE + repeat_type; - PUT2INC(code, 0, repeat_min); - if (repeat_max == -1) repeat_max = 0; /* 2-byte encoding for max */ - PUT2INC(code, 0, repeat_max); - } - } - - /* If previous was a bracket group, we may have to replicate it in certain - cases. */ - - else if (*previous == OP_BRA || *previous == OP_CBRA || - *previous == OP_ONCE || *previous == OP_COND) - { - register int i; - int ketoffset = 0; - int len = code - previous; - uschar *bralink = NULL; - - /* Repeating a DEFINE group is pointless */ - - if (*previous == OP_COND && previous[LINK_SIZE+1] == OP_DEF) - { - *errorcodeptr = ERR55; - goto FAILED; - } - - /* If the maximum repeat count is unlimited, find the end of the bracket - by scanning through from the start, and compute the offset back to it - from the current code pointer. There may be an OP_OPT setting following - the final KET, so we can't find the end just by going back from the code - pointer. */ - - if (repeat_max == -1) - { - register uschar *ket = previous; - do ket += GET(ket, 1); while (*ket != OP_KET); - ketoffset = code - ket; - } - - /* The case of a zero minimum is special because of the need to stick - OP_BRAZERO in front of it, and because the group appears once in the - data, whereas in other cases it appears the minimum number of times. For - this reason, it is simplest to treat this case separately, as otherwise - the code gets far too messy. There are several special subcases when the - minimum is zero. */ - - if (repeat_min == 0) - { - /* If the maximum is also zero, we used to just omit the group from the - output altogether, like this: - - ** if (repeat_max == 0) - ** { - ** code = previous; - ** goto END_REPEAT; - ** } - - However, that fails when a group is referenced as a subroutine from - elsewhere in the pattern, so now we stick in OP_SKIPZERO in front of it - so that it is skipped on execution. As we don't have a list of which - groups are referenced, we cannot do this selectively. - - If the maximum is 1 or unlimited, we just have to stick in the BRAZERO - and do no more at this point. However, we do need to adjust any - OP_RECURSE calls inside the group that refer to the group itself or any - internal or forward referenced group, because the offset is from the - start of the whole regex. Temporarily terminate the pattern while doing - this. */ - - if (repeat_max <= 1) /* Covers 0, 1, and unlimited */ - { - *code = OP_END; - adjust_recurse(previous, 1, utf8, cd, save_hwm); - memmove(previous+1, previous, len); - code++; - if (repeat_max == 0) - { - *previous++ = OP_SKIPZERO; - goto END_REPEAT; - } - *previous++ = OP_BRAZERO + repeat_type; - } - - /* If the maximum is greater than 1 and limited, we have to replicate - in a nested fashion, sticking OP_BRAZERO before each set of brackets. - The first one has to be handled carefully because it's the original - copy, which has to be moved up. The remainder can be handled by code - that is common with the non-zero minimum case below. We have to - adjust the value or repeat_max, since one less copy is required. Once - again, we may have to adjust any OP_RECURSE calls inside the group. */ - - else - { - int offset; - *code = OP_END; - adjust_recurse(previous, 2 + LINK_SIZE, utf8, cd, save_hwm); - memmove(previous + 2 + LINK_SIZE, previous, len); - code += 2 + LINK_SIZE; - *previous++ = OP_BRAZERO + repeat_type; - *previous++ = OP_BRA; - - /* We chain together the bracket offset fields that have to be - filled in later when the ends of the brackets are reached. */ - - offset = (bralink == NULL)? 0 : previous - bralink; - bralink = previous; - PUTINC(previous, 0, offset); - } - - repeat_max--; - } - - /* If the minimum is greater than zero, replicate the group as many - times as necessary, and adjust the maximum to the number of subsequent - copies that we need. If we set a first char from the group, and didn't - set a required char, copy the latter from the former. If there are any - forward reference subroutine calls in the group, there will be entries on - the workspace list; replicate these with an appropriate increment. */ - - else - { - if (repeat_min > 1) - { - /* In the pre-compile phase, we don't actually do the replication. We - just adjust the length as if we had. Do some paranoid checks for - potential integer overflow. */ - - if (lengthptr != NULL) - { - int delta = (repeat_min - 1)*length_prevgroup; - if ((double)(repeat_min - 1)*(double)length_prevgroup > - (double)INT_MAX || - OFLOW_MAX - *lengthptr < delta) - { - *errorcodeptr = ERR20; - goto FAILED; - } - *lengthptr += delta; - } - - /* This is compiling for real */ - - else - { - if (groupsetfirstbyte && reqbyte < 0) reqbyte = firstbyte; - for (i = 1; i < repeat_min; i++) - { - uschar *hc; - uschar *this_hwm = cd->hwm; - memcpy(code, previous, len); - for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE) - { - PUT(cd->hwm, 0, GET(hc, 0) + len); - cd->hwm += LINK_SIZE; - } - save_hwm = this_hwm; - code += len; - } - } - } - - if (repeat_max > 0) repeat_max -= repeat_min; - } - - /* This code is common to both the zero and non-zero minimum cases. If - the maximum is limited, it replicates the group in a nested fashion, - remembering the bracket starts on a stack. In the case of a zero minimum, - the first one was set up above. In all cases the repeat_max now specifies - the number of additional copies needed. Again, we must remember to - replicate entries on the forward reference list. */ - - if (repeat_max >= 0) - { - /* In the pre-compile phase, we don't actually do the replication. We - just adjust the length as if we had. For each repetition we must add 1 - to the length for BRAZERO and for all but the last repetition we must - add 2 + 2*LINKSIZE to allow for the nesting that occurs. Do some - paranoid checks to avoid integer overflow. */ - - if (lengthptr != NULL && repeat_max > 0) - { - int delta = repeat_max * (length_prevgroup + 1 + 2 + 2*LINK_SIZE) - - 2 - 2*LINK_SIZE; /* Last one doesn't nest */ - if ((double)repeat_max * - (double)(length_prevgroup + 1 + 2 + 2*LINK_SIZE) - > (double)INT_MAX || - OFLOW_MAX - *lengthptr < delta) - { - *errorcodeptr = ERR20; - goto FAILED; - } - *lengthptr += delta; - } - - /* This is compiling for real */ - - else for (i = repeat_max - 1; i >= 0; i--) - { - uschar *hc; - uschar *this_hwm = cd->hwm; - - *code++ = OP_BRAZERO + repeat_type; - - /* All but the final copy start a new nesting, maintaining the - chain of brackets outstanding. */ - - if (i != 0) - { - int offset; - *code++ = OP_BRA; - offset = (bralink == NULL)? 0 : code - bralink; - bralink = code; - PUTINC(code, 0, offset); - } - - memcpy(code, previous, len); - for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE) - { - PUT(cd->hwm, 0, GET(hc, 0) + len + ((i != 0)? 2+LINK_SIZE : 1)); - cd->hwm += LINK_SIZE; - } - save_hwm = this_hwm; - code += len; - } - - /* Now chain through the pending brackets, and fill in their length - fields (which are holding the chain links pro tem). */ - - while (bralink != NULL) - { - int oldlinkoffset; - int offset = code - bralink + 1; - uschar *bra = code - offset; - oldlinkoffset = GET(bra, 1); - bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset; - *code++ = OP_KET; - PUTINC(code, 0, offset); - PUT(bra, 1, offset); - } - } - - /* If the maximum is unlimited, set a repeater in the final copy. We - can't just offset backwards from the current code point, because we - don't know if there's been an options resetting after the ket. The - correct offset was computed above. - - Then, when we are doing the actual compile phase, check to see whether - this group is a non-atomic one that could match an empty string. If so, - convert the initial operator to the S form (e.g. OP_BRA -> OP_SBRA) so - that runtime checking can be done. [This check is also applied to - atomic groups at runtime, but in a different way.] */ - - else - { - uschar *ketcode = code - ketoffset; - uschar *bracode = ketcode - GET(ketcode, 1); - *ketcode = OP_KETRMAX + repeat_type; - if (lengthptr == NULL && *bracode != OP_ONCE) - { - uschar *scode = bracode; - do - { - if (could_be_empty_branch(scode, ketcode, utf8)) - { - *bracode += OP_SBRA - OP_BRA; - break; - } - scode += GET(scode, 1); - } - while (*scode == OP_ALT); - } - } - } - - /* If previous is OP_FAIL, it was generated by an empty class [] in - JavaScript mode. The other ways in which OP_FAIL can be generated, that is - by (*FAIL) or (?!) set previous to NULL, which gives a "nothing to repeat" - error above. We can just ignore the repeat in JS case. */ - - else if (*previous == OP_FAIL) goto END_REPEAT; - - /* Else there's some kind of shambles */ - - else - { - *errorcodeptr = ERR11; - goto FAILED; - } - - /* If the character following a repeat is '+', or if certain optimization - tests above succeeded, possessive_quantifier is TRUE. For some of the - simpler opcodes, there is an special alternative opcode for this. For - anything else, we wrap the entire repeated item inside OP_ONCE brackets. - The '+' notation is just syntactic sugar, taken from Sun's Java package, - but the special opcodes can optimize it a bit. The repeated item starts at - tempcode, not at previous, which might be the first part of a string whose - (former) last char we repeated. - - Possessifying an 'exact' quantifier has no effect, so we can ignore it. But - an 'upto' may follow. We skip over an 'exact' item, and then test the - length of what remains before proceeding. */ - - if (possessive_quantifier) - { - int len; - if (*tempcode == OP_EXACT || *tempcode == OP_TYPEEXACT || - *tempcode == OP_NOTEXACT) - tempcode += _pcre_OP_lengths[*tempcode] + - ((*tempcode == OP_TYPEEXACT && - (tempcode[3] == OP_PROP || tempcode[3] == OP_NOTPROP))? 2:0); - len = code - tempcode; - if (len > 0) switch (*tempcode) - { - case OP_STAR: *tempcode = OP_POSSTAR; break; - case OP_PLUS: *tempcode = OP_POSPLUS; break; - case OP_QUERY: *tempcode = OP_POSQUERY; break; - case OP_UPTO: *tempcode = OP_POSUPTO; break; - - case OP_TYPESTAR: *tempcode = OP_TYPEPOSSTAR; break; - case OP_TYPEPLUS: *tempcode = OP_TYPEPOSPLUS; break; - case OP_TYPEQUERY: *tempcode = OP_TYPEPOSQUERY; break; - case OP_TYPEUPTO: *tempcode = OP_TYPEPOSUPTO; break; - - case OP_NOTSTAR: *tempcode = OP_NOTPOSSTAR; break; - case OP_NOTPLUS: *tempcode = OP_NOTPOSPLUS; break; - case OP_NOTQUERY: *tempcode = OP_NOTPOSQUERY; break; - case OP_NOTUPTO: *tempcode = OP_NOTPOSUPTO; break; - - default: - memmove(tempcode + 1+LINK_SIZE, tempcode, len); - code += 1 + LINK_SIZE; - len += 1 + LINK_SIZE; - tempcode[0] = OP_ONCE; - *code++ = OP_KET; - PUTINC(code, 0, len); - PUT(tempcode, 1, len); - break; - } - } - - /* In all case we no longer have a previous item. We also set the - "follows varying string" flag for subsequently encountered reqbytes if - it isn't already set and we have just passed a varying length item. */ - - END_REPEAT: - previous = NULL; - cd->req_varyopt |= reqvary; - break; - - - /* ===================================================================*/ - /* Start of nested parenthesized sub-expression, or comment or lookahead or - lookbehind or option setting or condition or all the other extended - parenthesis forms. */ - - case '(': - newoptions = options; - skipbytes = 0; - bravalue = OP_CBRA; - save_hwm = cd->hwm; - reset_bracount = FALSE; - - /* First deal with various "verbs" that can be introduced by '*'. */ - - if (*(++ptr) == '*' && (cd->ctypes[ptr[1]] & ctype_letter) != 0) - { - int i, namelen; - const char *vn = verbnames; - const uschar *name = ++ptr; - previous = NULL; - while ((cd->ctypes[*++ptr] & ctype_letter) != 0) {}; - if (*ptr == ':') - { - *errorcodeptr = ERR59; /* Not supported */ - goto FAILED; - } - if (*ptr != ')') - { - *errorcodeptr = ERR60; - goto FAILED; - } - namelen = ptr - name; - for (i = 0; i < verbcount; i++) - { - if (namelen == verbs[i].len && - strncmp((char *)name, vn, namelen) == 0) - { - *code = verbs[i].op; - if (*code++ == OP_ACCEPT) cd->had_accept = TRUE; - break; - } - vn += verbs[i].len + 1; - } - if (i < verbcount) continue; - *errorcodeptr = ERR60; - goto FAILED; - } - - /* Deal with the extended parentheses; all are introduced by '?', and the - appearance of any of them means that this is not a capturing group. */ - - else if (*ptr == '?') - { - int i, set, unset, namelen; - int *optset; - const uschar *name; - uschar *slot; - - switch (*(++ptr)) - { - case '#': /* Comment; skip to ket */ - ptr++; - while (*ptr != 0 && *ptr != ')') ptr++; - if (*ptr == 0) - { - *errorcodeptr = ERR18; - goto FAILED; - } - continue; - - - /* ------------------------------------------------------------ */ - case '|': /* Reset capture count for each branch */ - reset_bracount = TRUE; - /* Fall through */ - - /* ------------------------------------------------------------ */ - case ':': /* Non-capturing bracket */ - bravalue = OP_BRA; - ptr++; - break; - - - /* ------------------------------------------------------------ */ - case '(': - bravalue = OP_COND; /* Conditional group */ - - /* A condition can be an assertion, a number (referring to a numbered - group), a name (referring to a named group), or 'R', referring to - recursion. R<digits> and R&name are also permitted for recursion tests. - - There are several syntaxes for testing a named group: (?(name)) is used - by Python; Perl 5.10 onwards uses (?(<name>) or (?('name')). - - There are two unfortunate ambiguities, caused by history. (a) 'R' can - be the recursive thing or the name 'R' (and similarly for 'R' followed - by digits), and (b) a number could be a name that consists of digits. - In both cases, we look for a name first; if not found, we try the other - cases. */ - - /* For conditions that are assertions, check the syntax, and then exit - the switch. This will take control down to where bracketed groups, - including assertions, are processed. */ - - if (ptr[1] == '?' && (ptr[2] == '=' || ptr[2] == '!' || ptr[2] == '<')) - break; - - /* Most other conditions use OP_CREF (a couple change to OP_RREF - below), and all need to skip 3 bytes at the start of the group. */ - - code[1+LINK_SIZE] = OP_CREF; - skipbytes = 3; - refsign = -1; - - /* Check for a test for recursion in a named group. */ - - if (ptr[1] == 'R' && ptr[2] == '&') - { - terminator = -1; - ptr += 2; - code[1+LINK_SIZE] = OP_RREF; /* Change the type of test */ - } - - /* Check for a test for a named group's having been set, using the Perl - syntax (?(<name>) or (?('name') */ - - else if (ptr[1] == '<') - { - terminator = '>'; - ptr++; - } - else if (ptr[1] == '\'') - { - terminator = '\''; - ptr++; - } - else - { - terminator = 0; - if (ptr[1] == '-' || ptr[1] == '+') refsign = *(++ptr); - } - - /* We now expect to read a name; any thing else is an error */ - - if ((cd->ctypes[ptr[1]] & ctype_word) == 0) - { - ptr += 1; /* To get the right offset */ - *errorcodeptr = ERR28; - goto FAILED; - } - - /* Read the name, but also get it as a number if it's all digits */ - - recno = 0; - name = ++ptr; - while ((cd->ctypes[*ptr] & ctype_word) != 0) - { - if (recno >= 0) - recno = (g_ascii_isdigit (*ptr) != 0)? - recno * 10 + *ptr - '0' : -1; - ptr++; - } - namelen = ptr - name; - - if ((terminator > 0 && *ptr++ != terminator) || *ptr++ != ')') - { - ptr--; /* Error offset */ - *errorcodeptr = ERR26; - goto FAILED; - } - - /* Do no further checking in the pre-compile phase. */ - - if (lengthptr != NULL) break; - - /* In the real compile we do the work of looking for the actual - reference. If the string started with "+" or "-" we require the rest to - be digits, in which case recno will be set. */ - - if (refsign > 0) - { - if (recno <= 0) - { - *errorcodeptr = ERR58; - goto FAILED; - } - recno = (refsign == '-')? - cd->bracount - recno + 1 : recno +cd->bracount; - if (recno <= 0 || recno > cd->final_bracount) - { - *errorcodeptr = ERR15; - goto FAILED; - } - PUT2(code, 2+LINK_SIZE, recno); - break; - } - - /* Otherwise (did not start with "+" or "-"), start by looking for the - name. */ - - slot = cd->name_table; - for (i = 0; i < cd->names_found; i++) - { - if (strncmp((char *)name, (char *)slot+2, namelen) == 0) break; - slot += cd->name_entry_size; - } - - /* Found a previous named subpattern */ - - if (i < cd->names_found) - { - recno = GET2(slot, 0); - PUT2(code, 2+LINK_SIZE, recno); - } - - /* Search the pattern for a forward reference */ - - else if ((i = find_parens(ptr, cd, name, namelen, - (options & PCRE_EXTENDED) != 0)) > 0) - { - PUT2(code, 2+LINK_SIZE, i); - } - - /* If terminator == 0 it means that the name followed directly after - the opening parenthesis [e.g. (?(abc)...] and in this case there are - some further alternatives to try. For the cases where terminator != 0 - [things like (?(<name>... or (?('name')... or (?(R&name)... ] we have - now checked all the possibilities, so give an error. */ - - else if (terminator != 0) - { - *errorcodeptr = ERR15; - goto FAILED; - } - - /* Check for (?(R) for recursion. Allow digits after R to specify a - specific group number. */ - - else if (*name == 'R') - { - recno = 0; - for (i = 1; i < namelen; i++) - { - if (g_ascii_isdigit (name[i]) == 0) - { - *errorcodeptr = ERR15; - goto FAILED; - } - recno = recno * 10 + name[i] - '0'; - } - if (recno == 0) recno = RREF_ANY; - code[1+LINK_SIZE] = OP_RREF; /* Change test type */ - PUT2(code, 2+LINK_SIZE, recno); - } - - /* Similarly, check for the (?(DEFINE) "condition", which is always - false. */ - - else if (namelen == 6 && strncmp((char *)name, "DEFINE", 6) == 0) - { - code[1+LINK_SIZE] = OP_DEF; - skipbytes = 1; - } - - /* Check for the "name" actually being a subpattern number. We are - in the second pass here, so final_bracount is set. */ - - else if (recno > 0 && recno <= cd->final_bracount) - { - PUT2(code, 2+LINK_SIZE, recno); - } - - /* Either an unidentified subpattern, or a reference to (?(0) */ - - else - { - *errorcodeptr = (recno == 0)? ERR35: ERR15; - goto FAILED; - } - break; - - - /* ------------------------------------------------------------ */ - case '=': /* Positive lookahead */ - bravalue = OP_ASSERT; - ptr++; - break; - - - /* ------------------------------------------------------------ */ - case '!': /* Negative lookahead */ - ptr++; - if (*ptr == ')') /* Optimize (?!) */ - { - *code++ = OP_FAIL; - previous = NULL; - continue; - } - bravalue = OP_ASSERT_NOT; - break; - - - /* ------------------------------------------------------------ */ - case '<': /* Lookbehind or named define */ - switch (ptr[1]) - { - case '=': /* Positive lookbehind */ - bravalue = OP_ASSERTBACK; - ptr += 2; - break; - - case '!': /* Negative lookbehind */ - bravalue = OP_ASSERTBACK_NOT; - ptr += 2; - break; - - default: /* Could be name define, else bad */ - if ((cd->ctypes[ptr[1]] & ctype_word) != 0) goto DEFINE_NAME; - ptr++; /* Correct offset for error */ - *errorcodeptr = ERR24; - goto FAILED; - } - break; - - - /* ------------------------------------------------------------ */ - case '>': /* One-time brackets */ - bravalue = OP_ONCE; - ptr++; - break; - - - /* ------------------------------------------------------------ */ - case 'C': /* Callout - may be followed by digits; */ - previous_callout = code; /* Save for later completion */ - after_manual_callout = 1; /* Skip one item before completing */ - *code++ = OP_CALLOUT; - { - int n = 0; - while (g_ascii_isdigit (*(++ptr)) != 0) - n = n * 10 + *ptr - '0'; - if (*ptr != ')') - { - *errorcodeptr = ERR39; - goto FAILED; - } - if (n > 255) - { - *errorcodeptr = ERR38; - goto FAILED; - } - *code++ = n; - PUT(code, 0, ptr - cd->start_pattern + 1); /* Pattern offset */ - PUT(code, LINK_SIZE, 0); /* Default length */ - code += 2 * LINK_SIZE; - } - previous = NULL; - continue; - - - /* ------------------------------------------------------------ */ - case 'P': /* Python-style named subpattern handling */ - if (*(++ptr) == '=' || *ptr == '>') /* Reference or recursion */ - { - is_recurse = *ptr == '>'; - terminator = ')'; - goto NAMED_REF_OR_RECURSE; - } - else if (*ptr != '<') /* Test for Python-style definition */ - { - *errorcodeptr = ERR41; - goto FAILED; - } - /* Fall through to handle (?P< as (?< is handled */ - - - /* ------------------------------------------------------------ */ - DEFINE_NAME: /* Come here from (?< handling */ - case '\'': - { - terminator = (*ptr == '<')? '>' : '\''; - name = ++ptr; - - while ((cd->ctypes[*ptr] & ctype_word) != 0) ptr++; - namelen = ptr - name; - - /* In the pre-compile phase, just do a syntax check. */ - - if (lengthptr != NULL) - { - if (*ptr != terminator) - { - *errorcodeptr = ERR42; - goto FAILED; - } - if (cd->names_found >= MAX_NAME_COUNT) - { - *errorcodeptr = ERR49; - goto FAILED; - } - if (namelen + 3 > cd->name_entry_size) - { - cd->name_entry_size = namelen + 3; - if (namelen > MAX_NAME_SIZE) - { - *errorcodeptr = ERR48; - goto FAILED; - } - } - } - - /* In the real compile, create the entry in the table */ - - else - { - slot = cd->name_table; - for (i = 0; i < cd->names_found; i++) - { - int crc = memcmp(name, slot+2, namelen); - if (crc == 0) - { - if (slot[2+namelen] == 0) - { - if ((options & PCRE_DUPNAMES) == 0) - { - *errorcodeptr = ERR43; - goto FAILED; - } - } - else crc = -1; /* Current name is substring */ - } - if (crc < 0) - { - memmove(slot + cd->name_entry_size, slot, - (cd->names_found - i) * cd->name_entry_size); - break; - } - slot += cd->name_entry_size; - } - - PUT2(slot, 0, cd->bracount + 1); - memcpy(slot + 2, name, namelen); - slot[2+namelen] = 0; - } - } - - /* In both cases, count the number of names we've encountered. */ - - ptr++; /* Move past > or ' */ - cd->names_found++; - goto NUMBERED_GROUP; - - - /* ------------------------------------------------------------ */ - case '&': /* Perl recursion/subroutine syntax */ - terminator = ')'; - is_recurse = TRUE; - /* Fall through */ - - /* We come here from the Python syntax above that handles both - references (?P=name) and recursion (?P>name), as well as falling - through from the Perl recursion syntax (?&name). We also come here from - the Perl \k<name> or \k'name' back reference syntax and the \k{name} - .NET syntax, and the Oniguruma \g<...> and \g'...' subroutine syntax. */ - - NAMED_REF_OR_RECURSE: - name = ++ptr; - while ((cd->ctypes[*ptr] & ctype_word) != 0) ptr++; - namelen = ptr - name; - - /* In the pre-compile phase, do a syntax check and set a dummy - reference number. */ - - if (lengthptr != NULL) - { - if (namelen == 0) - { - *errorcodeptr = ERR62; - goto FAILED; - } - if (*ptr != terminator) - { - *errorcodeptr = ERR42; - goto FAILED; - } - if (namelen > MAX_NAME_SIZE) - { - *errorcodeptr = ERR48; - goto FAILED; - } - recno = 0; - } - - /* In the real compile, seek the name in the table. We check the name - first, and then check that we have reached the end of the name in the - table. That way, if the name that is longer than any in the table, - the comparison will fail without reading beyond the table entry. */ - - else - { - slot = cd->name_table; - for (i = 0; i < cd->names_found; i++) - { - if (strncmp((char *)name, (char *)slot+2, namelen) == 0 && - slot[2+namelen] == 0) - break; - slot += cd->name_entry_size; - } - - if (i < cd->names_found) /* Back reference */ - { - recno = GET2(slot, 0); - } - else if ((recno = /* Forward back reference */ - find_parens(ptr, cd, name, namelen, - (options & PCRE_EXTENDED) != 0)) <= 0) - { - *errorcodeptr = ERR15; - goto FAILED; - } - } - - /* In both phases, we can now go to the code than handles numerical - recursion or backreferences. */ - - if (is_recurse) goto HANDLE_RECURSION; - else goto HANDLE_REFERENCE; - - - /* ------------------------------------------------------------ */ - case 'R': /* Recursion */ - ptr++; /* Same as (?0) */ - /* Fall through */ - - - /* ------------------------------------------------------------ */ - case '-': case '+': - case '0': case '1': case '2': case '3': case '4': /* Recursion or */ - case '5': case '6': case '7': case '8': case '9': /* subroutine */ - { - const uschar *called; - terminator = ')'; - - /* Come here from the \g<...> and \g'...' code (Oniguruma - compatibility). However, the syntax has been checked to ensure that - the ... are a (signed) number, so that neither ERR63 nor ERR29 will - be called on this path, nor with the jump to OTHER_CHAR_AFTER_QUERY - ever be taken. */ - - HANDLE_NUMERICAL_RECURSION: - - if ((refsign = *ptr) == '+') - { - ptr++; - if (g_ascii_isdigit (*ptr) == 0) - { - *errorcodeptr = ERR63; - goto FAILED; - } - } - else if (refsign == '-') - { - if (g_ascii_isdigit (ptr[1]) == 0) - goto OTHER_CHAR_AFTER_QUERY; - ptr++; - } - - recno = 0; - while(g_ascii_isdigit (*ptr) != 0) - recno = recno * 10 + *ptr++ - '0'; - - if (*ptr != terminator) - { - *errorcodeptr = ERR29; - goto FAILED; - } - - if (refsign == '-') - { - if (recno == 0) - { - *errorcodeptr = ERR58; - goto FAILED; - } - recno = cd->bracount - recno + 1; - if (recno <= 0) - { - *errorcodeptr = ERR15; - goto FAILED; - } - } - else if (refsign == '+') - { - if (recno == 0) - { - *errorcodeptr = ERR58; - goto FAILED; - } - recno += cd->bracount; - } - - /* Come here from code above that handles a named recursion */ - - HANDLE_RECURSION: - - previous = code; - called = cd->start_code; - - /* When we are actually compiling, find the bracket that is being - referenced. Temporarily end the regex in case it doesn't exist before - this point. If we end up with a forward reference, first check that - the bracket does occur later so we can give the error (and position) - now. Then remember this forward reference in the workspace so it can - be filled in at the end. */ - - if (lengthptr == NULL) - { - *code = OP_END; - if (recno != 0) called = find_bracket(cd->start_code, utf8, recno); - - /* Forward reference */ - - if (called == NULL) - { - if (find_parens(ptr, cd, NULL, recno, - (options & PCRE_EXTENDED) != 0) < 0) - { - *errorcodeptr = ERR15; - goto FAILED; - } - called = cd->start_code + recno; - PUTINC(cd->hwm, 0, code + 2 + LINK_SIZE - cd->start_code); - } - - /* If not a forward reference, and the subpattern is still open, - this is a recursive call. We check to see if this is a left - recursion that could loop for ever, and diagnose that case. */ - - else if (GET(called, 1) == 0 && - could_be_empty(called, code, bcptr, utf8)) - { - *errorcodeptr = ERR40; - goto FAILED; - } - } - - /* Insert the recursion/subroutine item, automatically wrapped inside - "once" brackets. Set up a "previous group" length so that a - subsequent quantifier will work. */ - - *code = OP_ONCE; - PUT(code, 1, 2 + 2*LINK_SIZE); - code += 1 + LINK_SIZE; - - *code = OP_RECURSE; - PUT(code, 1, called - cd->start_code); - code += 1 + LINK_SIZE; - - *code = OP_KET; - PUT(code, 1, 2 + 2*LINK_SIZE); - code += 1 + LINK_SIZE; - - length_prevgroup = 3 + 3*LINK_SIZE; - } - - /* Can't determine a first byte now */ - - if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; - continue; - - - /* ------------------------------------------------------------ */ - default: /* Other characters: check option setting */ - OTHER_CHAR_AFTER_QUERY: - set = unset = 0; - optset = &set; - - while (*ptr != ')' && *ptr != ':') - { - switch (*ptr++) - { - case '-': optset = &unset; break; - - case 'J': /* Record that it changed in the external options */ - *optset |= PCRE_DUPNAMES; - cd->external_flags |= PCRE_JCHANGED; - break; - - case 'i': *optset |= PCRE_CASELESS; break; - case 'm': *optset |= PCRE_MULTILINE; break; - case 's': *optset |= PCRE_DOTALL; break; - case 'x': *optset |= PCRE_EXTENDED; break; - case 'U': *optset |= PCRE_UNGREEDY; break; - case 'X': *optset |= PCRE_EXTRA; break; - - default: *errorcodeptr = ERR12; - ptr--; /* Correct the offset */ - goto FAILED; - } - } - - /* Set up the changed option bits, but don't change anything yet. */ - - newoptions = (options | set) & (~unset); - - /* If the options ended with ')' this is not the start of a nested - group with option changes, so the options change at this level. If this - item is right at the start of the pattern, the options can be - abstracted and made external in the pre-compile phase, and ignored in - the compile phase. This can be helpful when matching -- for instance in - caseless checking of required bytes. - - If the code pointer is not (cd->start_code + 1 + LINK_SIZE), we are - definitely *not* at the start of the pattern because something has been - compiled. In the pre-compile phase, however, the code pointer can have - that value after the start, because it gets reset as code is discarded - during the pre-compile. However, this can happen only at top level - if - we are within parentheses, the starting BRA will still be present. At - any parenthesis level, the length value can be used to test if anything - has been compiled at that level. Thus, a test for both these conditions - is necessary to ensure we correctly detect the start of the pattern in - both phases. - - If we are not at the pattern start, compile code to change the ims - options if this setting actually changes any of them, and reset the - greedy defaults and the case value for firstbyte and reqbyte. */ - - if (*ptr == ')') - { - if (code == cd->start_code + 1 + LINK_SIZE && - (lengthptr == NULL || *lengthptr == 2 + 2*LINK_SIZE)) - { - cd->external_options = newoptions; - } - else - { - if ((options & PCRE_IMS) != (newoptions & PCRE_IMS)) - { - *code++ = OP_OPT; - *code++ = newoptions & PCRE_IMS; - } - greedy_default = ((newoptions & PCRE_UNGREEDY) != 0); - greedy_non_default = greedy_default ^ 1; - req_caseopt = ((newoptions & PCRE_CASELESS) != 0)? REQ_CASELESS : 0; - } - - /* Change options at this level, and pass them back for use - in subsequent branches. When not at the start of the pattern, this - information is also necessary so that a resetting item can be - compiled at the end of a group (if we are in a group). */ - - *optionsptr = options = newoptions; - previous = NULL; /* This item can't be repeated */ - continue; /* It is complete */ - } - - /* If the options ended with ':' we are heading into a nested group - with possible change of options. Such groups are non-capturing and are - not assertions of any kind. All we need to do is skip over the ':'; - the newoptions value is handled below. */ - - bravalue = OP_BRA; - ptr++; - } /* End of switch for character following (? */ - } /* End of (? handling */ - - /* Opening parenthesis not followed by '?'. If PCRE_NO_AUTO_CAPTURE is set, - all unadorned brackets become non-capturing and behave like (?:...) - brackets. */ - - else if ((options & PCRE_NO_AUTO_CAPTURE) != 0) - { - bravalue = OP_BRA; - } - - /* Else we have a capturing group. */ - - else - { - NUMBERED_GROUP: - cd->bracount += 1; - PUT2(code, 1+LINK_SIZE, cd->bracount); - skipbytes = 2; - } - - /* Process nested bracketed regex. Assertions may not be repeated, but - other kinds can be. All their opcodes are >= OP_ONCE. We copy code into a - non-register variable in order to be able to pass its address because some - compilers complain otherwise. Pass in a new setting for the ims options if - they have changed. */ - - previous = (bravalue >= OP_ONCE)? code : NULL; - *code = bravalue; - tempcode = code; - tempreqvary = cd->req_varyopt; /* Save value before bracket */ - length_prevgroup = 0; /* Initialize for pre-compile phase */ - - if (!compile_regex( - newoptions, /* The complete new option state */ - options & PCRE_IMS, /* The previous ims option state */ - &tempcode, /* Where to put code (updated) */ - &ptr, /* Input pointer (updated) */ - errorcodeptr, /* Where to put an error message */ - (bravalue == OP_ASSERTBACK || - bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */ - reset_bracount, /* True if (?| group */ - skipbytes, /* Skip over bracket number */ - &subfirstbyte, /* For possible first char */ - &subreqbyte, /* For possible last char */ - bcptr, /* Current branch chain */ - cd, /* Tables block */ - (lengthptr == NULL)? NULL : /* Actual compile phase */ - &length_prevgroup /* Pre-compile phase */ - )) - goto FAILED; - - /* At the end of compiling, code is still pointing to the start of the - group, while tempcode has been updated to point past the end of the group - and any option resetting that may follow it. The pattern pointer (ptr) - is on the bracket. */ - - /* If this is a conditional bracket, check that there are no more than - two branches in the group, or just one if it's a DEFINE group. We do this - in the real compile phase, not in the pre-pass, where the whole group may - not be available. */ - - if (bravalue == OP_COND && lengthptr == NULL) - { - uschar *tc = code; - int condcount = 0; - - do { - condcount++; - tc += GET(tc,1); - } - while (*tc != OP_KET); - - /* A DEFINE group is never obeyed inline (the "condition" is always - false). It must have only one branch. */ - - if (code[LINK_SIZE+1] == OP_DEF) - { - if (condcount > 1) - { - *errorcodeptr = ERR54; - goto FAILED; - } - bravalue = OP_DEF; /* Just a flag to suppress char handling below */ - } - - /* A "normal" conditional group. If there is just one branch, we must not - make use of its firstbyte or reqbyte, because this is equivalent to an - empty second branch. */ - - else - { - if (condcount > 2) - { - *errorcodeptr = ERR27; - goto FAILED; - } - if (condcount == 1) subfirstbyte = subreqbyte = REQ_NONE; - } - } - - /* Error if hit end of pattern */ - - if (*ptr != ')') - { - *errorcodeptr = ERR14; - goto FAILED; - } - - /* In the pre-compile phase, update the length by the length of the group, - less the brackets at either end. Then reduce the compiled code to just a - set of non-capturing brackets so that it doesn't use much memory if it is - duplicated by a quantifier.*/ - - if (lengthptr != NULL) - { - if (OFLOW_MAX - *lengthptr < length_prevgroup - 2 - 2*LINK_SIZE) - { - *errorcodeptr = ERR20; - goto FAILED; - } - *lengthptr += length_prevgroup - 2 - 2*LINK_SIZE; - *code++ = OP_BRA; - PUTINC(code, 0, 1 + LINK_SIZE); - *code++ = OP_KET; - PUTINC(code, 0, 1 + LINK_SIZE); - break; /* No need to waste time with special character handling */ - } - - /* Otherwise update the main code pointer to the end of the group. */ - - code = tempcode; - - /* For a DEFINE group, required and first character settings are not - relevant. */ - - if (bravalue == OP_DEF) break; - - /* Handle updating of the required and first characters for other types of - group. Update for normal brackets of all kinds, and conditions with two - branches (see code above). If the bracket is followed by a quantifier with - zero repeat, we have to back off. Hence the definition of zeroreqbyte and - zerofirstbyte outside the main loop so that they can be accessed for the - back off. */ - - zeroreqbyte = reqbyte; - zerofirstbyte = firstbyte; - groupsetfirstbyte = FALSE; - - if (bravalue >= OP_ONCE) - { - /* If we have not yet set a firstbyte in this branch, take it from the - subpattern, remembering that it was set here so that a repeat of more - than one can replicate it as reqbyte if necessary. If the subpattern has - no firstbyte, set "none" for the whole branch. In both cases, a zero - repeat forces firstbyte to "none". */ - - if (firstbyte == REQ_UNSET) - { - if (subfirstbyte >= 0) - { - firstbyte = subfirstbyte; - groupsetfirstbyte = TRUE; - } - else firstbyte = REQ_NONE; - zerofirstbyte = REQ_NONE; - } - - /* If firstbyte was previously set, convert the subpattern's firstbyte - into reqbyte if there wasn't one, using the vary flag that was in - existence beforehand. */ - - else if (subfirstbyte >= 0 && subreqbyte < 0) - subreqbyte = subfirstbyte | tempreqvary; - - /* If the subpattern set a required byte (or set a first byte that isn't - really the first byte - see above), set it. */ - - if (subreqbyte >= 0) reqbyte = subreqbyte; - } - - /* For a forward assertion, we take the reqbyte, if set. This can be - helpful if the pattern that follows the assertion doesn't set a different - char. For example, it's useful for /(?=abcde).+/. We can't set firstbyte - for an assertion, however because it leads to incorrect effect for patterns - such as /(?=a)a.+/ when the "real" "a" would then become a reqbyte instead - of a firstbyte. This is overcome by a scan at the end if there's no - firstbyte, looking for an asserted first char. */ - - else if (bravalue == OP_ASSERT && subreqbyte >= 0) reqbyte = subreqbyte; - break; /* End of processing '(' */ - - - /* ===================================================================*/ - /* Handle metasequences introduced by \. For ones like \d, the ESC_ values - are arranged to be the negation of the corresponding OP_values. For the - back references, the values are ESC_REF plus the reference number. Only - back references and those types that consume a character may be repeated. - We can test for values between ESC_b and ESC_Z for the latter; this may - have to change if any new ones are ever created. */ - - case '\\': - tempptr = ptr; - c = check_escape(&ptr, errorcodeptr, cd->bracount, options, FALSE); - if (*errorcodeptr != 0) goto FAILED; - - if (c < 0) - { - if (-c == ESC_Q) /* Handle start of quoted string */ - { - if (ptr[1] == '\\' && ptr[2] == 'E') ptr += 2; /* avoid empty string */ - else inescq = TRUE; - continue; - } - - if (-c == ESC_E) continue; /* Perl ignores an orphan \E */ - - /* For metasequences that actually match a character, we disable the - setting of a first character if it hasn't already been set. */ - - if (firstbyte == REQ_UNSET && -c > ESC_b && -c < ESC_Z) - firstbyte = REQ_NONE; - - /* Set values to reset to if this is followed by a zero repeat. */ - - zerofirstbyte = firstbyte; - zeroreqbyte = reqbyte; - - /* \g<name> or \g'name' is a subroutine call by name and \g<n> or \g'n' - is a subroutine call by number (Oniguruma syntax). In fact, the value - -ESC_g is returned only for these cases. So we don't need to check for < - or ' if the value is -ESC_g. For the Perl syntax \g{n} the value is - -ESC_REF+n, and for the Perl syntax \g{name} the result is -ESC_k (as - that is a synonym for a named back reference). */ - - if (-c == ESC_g) - { - const uschar *p; - save_hwm = cd->hwm; /* Normally this is set when '(' is read */ - terminator = (*(++ptr) == '<')? '>' : '\''; - - /* These two statements stop the compiler for warning about possibly - unset variables caused by the jump to HANDLE_NUMERICAL_RECURSION. In - fact, because we actually check for a number below, the paths that - would actually be in error are never taken. */ - - skipbytes = 0; - reset_bracount = FALSE; - - /* Test for a name */ - - if (ptr[1] != '+' && ptr[1] != '-') - { - BOOL isnumber = TRUE; - for (p = ptr + 1; *p != 0 && *p != terminator; p++) - { - if ((cd->ctypes[*p] & ctype_digit) == 0) isnumber = FALSE; - if ((cd->ctypes[*p] & ctype_word) == 0) break; - } - if (*p != terminator) - { - *errorcodeptr = ERR57; - break; - } - if (isnumber) - { - ptr++; - goto HANDLE_NUMERICAL_RECURSION; - } - is_recurse = TRUE; - goto NAMED_REF_OR_RECURSE; - } - - /* Test a signed number in angle brackets or quotes. */ - - p = ptr + 2; - while (g_ascii_isdigit (*p) != 0) p++; - if (*p != terminator) - { - *errorcodeptr = ERR57; - break; - } - ptr++; - goto HANDLE_NUMERICAL_RECURSION; - } - - /* \k<name> or \k'name' is a back reference by name (Perl syntax). - We also support \k{name} (.NET syntax) */ - - if (-c == ESC_k && (ptr[1] == '<' || ptr[1] == '\'' || ptr[1] == '{')) - { - is_recurse = FALSE; - terminator = (*(++ptr) == '<')? '>' : (*ptr == '\'')? '\'' : '}'; - goto NAMED_REF_OR_RECURSE; - } - - /* Back references are handled specially; must disable firstbyte if - not set to cope with cases like (?=(\w+))\1: which would otherwise set - ':' later. */ - - if (-c >= ESC_REF) - { - recno = -c - ESC_REF; - - HANDLE_REFERENCE: /* Come here from named backref handling */ - if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; - previous = code; - *code++ = OP_REF; - PUT2INC(code, 0, recno); - cd->backref_map |= (recno < 32)? (1 << recno) : 1; - if (recno > cd->top_backref) cd->top_backref = recno; - } - - /* So are Unicode property matches, if supported. */ - -#ifdef SUPPORT_UCP - else if (-c == ESC_P || -c == ESC_p) - { - BOOL negated; - int pdata; - int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr); - if (ptype < 0) goto FAILED; - previous = code; - *code++ = ((-c == ESC_p) != negated)? OP_PROP : OP_NOTPROP; - *code++ = ptype; - *code++ = pdata; - } -#else - - /* If Unicode properties are not supported, \X, \P, and \p are not - allowed. */ - - else if (-c == ESC_X || -c == ESC_P || -c == ESC_p) - { - *errorcodeptr = ERR45; - goto FAILED; - } -#endif - - /* For the rest (including \X when Unicode properties are supported), we - can obtain the OP value by negating the escape value. */ - - else - { - previous = (-c > ESC_b && -c < ESC_Z)? code : NULL; - *code++ = -c; - } - continue; - } - - /* We have a data character whose value is in c. In UTF-8 mode it may have - a value > 127. We set its representation in the length/buffer, and then - handle it as a data character. */ - -#ifdef SUPPORT_UTF8 - if (utf8 && c > 127) - mclength = _pcre_ord2utf8(c, mcbuffer); - else -#endif - - { - mcbuffer[0] = c; - mclength = 1; - } - goto ONE_CHAR; - - - /* ===================================================================*/ - /* Handle a literal character. It is guaranteed not to be whitespace or # - when the extended flag is set. If we are in UTF-8 mode, it may be a - multi-byte literal character. */ - - default: - NORMAL_CHAR: - mclength = 1; - mcbuffer[0] = c; - -#ifdef SUPPORT_UTF8 - if (utf8 && c >= 0xc0) - { - while ((ptr[1] & 0xc0) == 0x80) - mcbuffer[mclength++] = *(++ptr); - } -#endif - - /* At this point we have the character's bytes in mcbuffer, and the length - in mclength. When not in UTF-8 mode, the length is always 1. */ - - ONE_CHAR: - previous = code; - *code++ = ((options & PCRE_CASELESS) != 0)? OP_CHARNC : OP_CHAR; - for (c = 0; c < mclength; c++) *code++ = mcbuffer[c]; - - /* Remember if \r or \n were seen */ - - if (mcbuffer[0] == '\r' || mcbuffer[0] == '\n') - cd->external_flags |= PCRE_HASCRORLF; - - /* Set the first and required bytes appropriately. If no previous first - byte, set it from this character, but revert to none on a zero repeat. - Otherwise, leave the firstbyte value alone, and don't change it on a zero - repeat. */ - - if (firstbyte == REQ_UNSET) - { - zerofirstbyte = REQ_NONE; - zeroreqbyte = reqbyte; - - /* If the character is more than one byte long, we can set firstbyte - only if it is not to be matched caselessly. */ - - if (mclength == 1 || req_caseopt == 0) - { - firstbyte = mcbuffer[0] | req_caseopt; - if (mclength != 1) reqbyte = code[-1] | cd->req_varyopt; - } - else firstbyte = reqbyte = REQ_NONE; - } - - /* firstbyte was previously set; we can set reqbyte only the length is - 1 or the matching is caseful. */ - - else - { - zerofirstbyte = firstbyte; - zeroreqbyte = reqbyte; - if (mclength == 1 || req_caseopt == 0) - reqbyte = code[-1] | req_caseopt | cd->req_varyopt; - } - - break; /* End of literal character handling */ - } - } /* end of big loop */ - - -/* Control never reaches here by falling through, only by a goto for all the -error states. Pass back the position in the pattern so that it can be displayed -to the user for diagnosing the error. */ - -FAILED: -*ptrptr = ptr; -return FALSE; -} - - - - -/************************************************* -* Compile sequence of alternatives * -*************************************************/ - -/* On entry, ptr is pointing past the bracket character, but on return it -points to the closing bracket, or vertical bar, or end of string. The code -variable is pointing at the byte into which the BRA operator has been stored. -If the ims options are changed at the start (for a (?ims: group) or during any -branch, we need to insert an OP_OPT item at the start of every following branch -to ensure they get set correctly at run time, and also pass the new options -into every subsequent branch compile. - -This function is used during the pre-compile phase when we are trying to find -out the amount of memory needed, as well as during the real compile phase. The -value of lengthptr distinguishes the two phases. - -Arguments: - options option bits, including any changes for this subpattern - oldims previous settings of ims option bits - codeptr -> the address of the current code pointer - ptrptr -> the address of the current pattern pointer - errorcodeptr -> pointer to error code variable - lookbehind TRUE if this is a lookbehind assertion - reset_bracount TRUE to reset the count for each branch - skipbytes skip this many bytes at start (for brackets and OP_COND) - firstbyteptr place to put the first required character, or a negative number - reqbyteptr place to put the last required character, or a negative number - bcptr pointer to the chain of currently open branches - cd points to the data block with tables pointers etc. - lengthptr NULL during the real compile phase - points to length accumulator during pre-compile phase - -Returns: TRUE on success -*/ - -static BOOL -compile_regex(int options, int oldims, uschar **codeptr, const uschar **ptrptr, - int *errorcodeptr, BOOL lookbehind, BOOL reset_bracount, int skipbytes, - int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr, compile_data *cd, - int *lengthptr) -{ -const uschar *ptr = *ptrptr; -uschar *code = *codeptr; -uschar *last_branch = code; -uschar *start_bracket = code; -uschar *reverse_count = NULL; -int firstbyte, reqbyte; -int branchfirstbyte, branchreqbyte; -int length; -int orig_bracount; -int max_bracount; -branch_chain bc; - -bc.outer = bcptr; -bc.current = code; - -firstbyte = reqbyte = REQ_UNSET; - -/* Accumulate the length for use in the pre-compile phase. Start with the -length of the BRA and KET and any extra bytes that are required at the -beginning. We accumulate in a local variable to save frequent testing of -lenthptr for NULL. We cannot do this by looking at the value of code at the -start and end of each alternative, because compiled items are discarded during -the pre-compile phase so that the work space is not exceeded. */ - -length = 2 + 2*LINK_SIZE + skipbytes; - -/* WARNING: If the above line is changed for any reason, you must also change -the code that abstracts option settings at the start of the pattern and makes -them global. It tests the value of length for (2 + 2*LINK_SIZE) in the -pre-compile phase to find out whether anything has yet been compiled or not. */ - -/* Offset is set zero to mark that this bracket is still open */ - -PUT(code, 1, 0); -code += 1 + LINK_SIZE + skipbytes; - -/* Loop for each alternative branch */ - -orig_bracount = max_bracount = cd->bracount; -for (;;) - { - /* For a (?| group, reset the capturing bracket count so that each branch - uses the same numbers. */ - - if (reset_bracount) cd->bracount = orig_bracount; - - /* Handle a change of ims options at the start of the branch */ - - if ((options & PCRE_IMS) != oldims) - { - *code++ = OP_OPT; - *code++ = options & PCRE_IMS; - length += 2; - } - - /* Set up dummy OP_REVERSE if lookbehind assertion */ - - if (lookbehind) - { - *code++ = OP_REVERSE; - reverse_count = code; - PUTINC(code, 0, 0); - length += 1 + LINK_SIZE; - } - - /* Now compile the branch; in the pre-compile phase its length gets added - into the length. */ - - if (!compile_branch(&options, &code, &ptr, errorcodeptr, &branchfirstbyte, - &branchreqbyte, &bc, cd, (lengthptr == NULL)? NULL : &length)) - { - *ptrptr = ptr; - return FALSE; - } - - /* Keep the highest bracket count in case (?| was used and some branch - has fewer than the rest. */ - - if (cd->bracount > max_bracount) max_bracount = cd->bracount; - - /* In the real compile phase, there is some post-processing to be done. */ - - if (lengthptr == NULL) - { - /* If this is the first branch, the firstbyte and reqbyte values for the - branch become the values for the regex. */ - - if (*last_branch != OP_ALT) - { - firstbyte = branchfirstbyte; - reqbyte = branchreqbyte; - } - - /* If this is not the first branch, the first char and reqbyte have to - match the values from all the previous branches, except that if the - previous value for reqbyte didn't have REQ_VARY set, it can still match, - and we set REQ_VARY for the regex. */ - - else - { - /* If we previously had a firstbyte, but it doesn't match the new branch, - we have to abandon the firstbyte for the regex, but if there was - previously no reqbyte, it takes on the value of the old firstbyte. */ - - if (firstbyte >= 0 && firstbyte != branchfirstbyte) - { - if (reqbyte < 0) reqbyte = firstbyte; - firstbyte = REQ_NONE; - } - - /* If we (now or from before) have no firstbyte, a firstbyte from the - branch becomes a reqbyte if there isn't a branch reqbyte. */ - - if (firstbyte < 0 && branchfirstbyte >= 0 && branchreqbyte < 0) - branchreqbyte = branchfirstbyte; - - /* Now ensure that the reqbytes match */ - - if ((reqbyte & ~REQ_VARY) != (branchreqbyte & ~REQ_VARY)) - reqbyte = REQ_NONE; - else reqbyte |= branchreqbyte; /* To "or" REQ_VARY */ - } - - /* If lookbehind, check that this branch matches a fixed-length string, and - put the length into the OP_REVERSE item. Temporarily mark the end of the - branch with OP_END. */ - - if (lookbehind) - { - int fixed_length; - *code = OP_END; - fixed_length = find_fixedlength(last_branch, options); - DPRINTF(("fixed length = %d\n", fixed_length)); - if (fixed_length < 0) - { - *errorcodeptr = (fixed_length == -2)? ERR36 : ERR25; - *ptrptr = ptr; - return FALSE; - } - PUT(reverse_count, 0, fixed_length); - } - } - - /* Reached end of expression, either ')' or end of pattern. In the real - compile phase, go back through the alternative branches and reverse the chain - of offsets, with the field in the BRA item now becoming an offset to the - first alternative. If there are no alternatives, it points to the end of the - group. The length in the terminating ket is always the length of the whole - bracketed item. If any of the ims options were changed inside the group, - compile a resetting op-code following, except at the very end of the pattern. - Return leaving the pointer at the terminating char. */ - - if (*ptr != '|') - { - if (lengthptr == NULL) - { - int branch_length = code - last_branch; - do - { - int prev_length = GET(last_branch, 1); - PUT(last_branch, 1, branch_length); - branch_length = prev_length; - last_branch -= branch_length; - } - while (branch_length > 0); - } - - /* Fill in the ket */ - - *code = OP_KET; - PUT(code, 1, code - start_bracket); - code += 1 + LINK_SIZE; - - /* Resetting option if needed */ - - if ((options & PCRE_IMS) != oldims && *ptr == ')') - { - *code++ = OP_OPT; - *code++ = oldims; - length += 2; - } - - /* Retain the highest bracket number, in case resetting was used. */ - - cd->bracount = max_bracount; - - /* Set values to pass back */ - - *codeptr = code; - *ptrptr = ptr; - *firstbyteptr = firstbyte; - *reqbyteptr = reqbyte; - if (lengthptr != NULL) - { - if (OFLOW_MAX - *lengthptr < length) - { - *errorcodeptr = ERR20; - return FALSE; - } - *lengthptr += length; - } - return TRUE; - } - - /* Another branch follows. In the pre-compile phase, we can move the code - pointer back to where it was for the start of the first branch. (That is, - pretend that each branch is the only one.) - - In the real compile phase, insert an ALT node. Its length field points back - to the previous branch while the bracket remains open. At the end the chain - is reversed. It's done like this so that the start of the bracket has a - zero offset until it is closed, making it possible to detect recursion. */ - - if (lengthptr != NULL) - { - code = *codeptr + 1 + LINK_SIZE + skipbytes; - length += 1 + LINK_SIZE; - } - else - { - *code = OP_ALT; - PUT(code, 1, code - last_branch); - bc.current = last_branch = code; - code += 1 + LINK_SIZE; - } - - ptr++; - } -/* Control never reaches here */ -} - - - - -/************************************************* -* Check for anchored expression * -*************************************************/ - -/* Try to find out if this is an anchored regular expression. Consider each -alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket -all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then -it's anchored. However, if this is a multiline pattern, then only OP_SOD -counts, since OP_CIRC can match in the middle. - -We can also consider a regex to be anchored if OP_SOM starts all its branches. -This is the code for \G, which means "match at start of match position, taking -into account the match offset". - -A branch is also implicitly anchored if it starts with .* and DOTALL is set, -because that will try the rest of the pattern at all possible matching points, -so there is no point trying again.... er .... - -.... except when the .* appears inside capturing parentheses, and there is a -subsequent back reference to those parentheses. We haven't enough information -to catch that case precisely. - -At first, the best we could do was to detect when .* was in capturing brackets -and the highest back reference was greater than or equal to that level. -However, by keeping a bitmap of the first 31 back references, we can catch some -of the more common cases more precisely. - -Arguments: - code points to start of expression (the bracket) - options points to the options setting - bracket_map a bitmap of which brackets we are inside while testing; this - handles up to substring 31; after that we just have to take - the less precise approach - backref_map the back reference bitmap - -Returns: TRUE or FALSE -*/ - -static BOOL -is_anchored(register const uschar *code, int *options, unsigned int bracket_map, - unsigned int backref_map) -{ -do { - const uschar *scode = first_significant_code(code + _pcre_OP_lengths[*code], - options, PCRE_MULTILINE, FALSE); - register int op = *scode; - - /* Non-capturing brackets */ - - if (op == OP_BRA) - { - if (!is_anchored(scode, options, bracket_map, backref_map)) return FALSE; - } - - /* Capturing brackets */ - - else if (op == OP_CBRA) - { - int n = GET2(scode, 1+LINK_SIZE); - int new_map = bracket_map | ((n < 32)? (1 << n) : 1); - if (!is_anchored(scode, options, new_map, backref_map)) return FALSE; - } - - /* Other brackets */ - - else if (op == OP_ASSERT || op == OP_ONCE || op == OP_COND) - { - if (!is_anchored(scode, options, bracket_map, backref_map)) return FALSE; - } - - /* .* is not anchored unless DOTALL is set (which generates OP_ALLANY) and - it isn't in brackets that are or may be referenced. */ - - else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR || - op == OP_TYPEPOSSTAR)) - { - if (scode[1] != OP_ALLANY || (bracket_map & backref_map) != 0) - return FALSE; - } - - /* Check for explicit anchoring */ - - else if (op != OP_SOD && op != OP_SOM && - ((*options & PCRE_MULTILINE) != 0 || op != OP_CIRC)) - return FALSE; - code += GET(code, 1); - } -while (*code == OP_ALT); /* Loop for each alternative */ -return TRUE; -} - - - -/************************************************* -* Check for starting with ^ or .* * -*************************************************/ - -/* This is called to find out if every branch starts with ^ or .* so that -"first char" processing can be done to speed things up in multiline -matching and for non-DOTALL patterns that start with .* (which must start at -the beginning or after \n). As in the case of is_anchored() (see above), we -have to take account of back references to capturing brackets that contain .* -because in that case we can't make the assumption. - -Arguments: - code points to start of expression (the bracket) - bracket_map a bitmap of which brackets we are inside while testing; this - handles up to substring 31; after that we just have to take - the less precise approach - backref_map the back reference bitmap - -Returns: TRUE or FALSE -*/ - -static BOOL -is_startline(const uschar *code, unsigned int bracket_map, - unsigned int backref_map) -{ -do { - const uschar *scode = first_significant_code(code + _pcre_OP_lengths[*code], - NULL, 0, FALSE); - register int op = *scode; - - /* Non-capturing brackets */ - - if (op == OP_BRA) - { - if (!is_startline(scode, bracket_map, backref_map)) return FALSE; - } - - /* Capturing brackets */ - - else if (op == OP_CBRA) - { - int n = GET2(scode, 1+LINK_SIZE); - int new_map = bracket_map | ((n < 32)? (1 << n) : 1); - if (!is_startline(scode, new_map, backref_map)) return FALSE; - } - - /* Other brackets */ - - else if (op == OP_ASSERT || op == OP_ONCE || op == OP_COND) - { if (!is_startline(scode, bracket_map, backref_map)) return FALSE; } - - /* .* means "start at start or after \n" if it isn't in brackets that - may be referenced. */ - - else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR) - { - if (scode[1] != OP_ANY || (bracket_map & backref_map) != 0) return FALSE; - } - - /* Check for explicit circumflex */ - - else if (op != OP_CIRC) return FALSE; - - /* Move on to the next alternative */ - - code += GET(code, 1); - } -while (*code == OP_ALT); /* Loop for each alternative */ -return TRUE; -} - - - -/************************************************* -* Check for asserted fixed first char * -*************************************************/ - -/* During compilation, the "first char" settings from forward assertions are -discarded, because they can cause conflicts with actual literals that follow. -However, if we end up without a first char setting for an unanchored pattern, -it is worth scanning the regex to see if there is an initial asserted first -char. If all branches start with the same asserted char, or with a bracket all -of whose alternatives start with the same asserted char (recurse ad lib), then -we return that char, otherwise -1. - -Arguments: - code points to start of expression (the bracket) - options pointer to the options (used to check casing changes) - inassert TRUE if in an assertion - -Returns: -1 or the fixed first char -*/ - -static int -find_firstassertedchar(const uschar *code, int *options, BOOL inassert) -{ -register int c = -1; -do { - int d; - const uschar *scode = - first_significant_code(code + 1+LINK_SIZE, options, PCRE_CASELESS, TRUE); - register int op = *scode; - - switch(op) - { - default: - return -1; - - case OP_BRA: - case OP_CBRA: - case OP_ASSERT: - case OP_ONCE: - case OP_COND: - if ((d = find_firstassertedchar(scode, options, op == OP_ASSERT)) < 0) - return -1; - if (c < 0) c = d; else if (c != d) return -1; - break; - - case OP_EXACT: /* Fall through */ - scode += 2; - - case OP_CHAR: - case OP_CHARNC: - case OP_PLUS: - case OP_MINPLUS: - case OP_POSPLUS: - if (!inassert) return -1; - if (c < 0) - { - c = scode[1]; - if ((*options & PCRE_CASELESS) != 0) c |= REQ_CASELESS; - } - else if (c != scode[1]) return -1; - break; - } - - code += GET(code, 1); - } -while (*code == OP_ALT); -return c; -} - - - -/************************************************* -* Compile a Regular Expression * -*************************************************/ - -/* This function takes a string and returns a pointer to a block of store -holding a compiled version of the expression. The original API for this -function had no error code return variable; it is retained for backwards -compatibility. The new function is given a new name. - -Arguments: - pattern the regular expression - options various option bits - errorcodeptr pointer to error code variable (pcre_compile2() only) - can be NULL if you don't want a code value - errorptr pointer to pointer to error text - erroroffset ptr offset in pattern where error was detected - tables pointer to character tables or NULL - -Returns: pointer to compiled data block, or NULL on error, - with errorptr and erroroffset set -*/ - -PCRE_EXP_DEFN pcre * PCRE_CALL_CONVENTION -pcre_compile(const char *pattern, int options, const char **errorptr, - int *erroroffset, const unsigned char *tables) -{ -return pcre_compile2(pattern, options, NULL, errorptr, erroroffset, tables); -} - - -PCRE_EXP_DEFN pcre * PCRE_CALL_CONVENTION -pcre_compile2(const char *pattern, int options, int *errorcodeptr, - const char **errorptr, int *erroroffset, const unsigned char *tables) -{ -real_pcre *re; -int length = 1; /* For final END opcode */ -int firstbyte, reqbyte, newline; -int errorcode = 0; -int skipatstart = 0; -#ifdef SUPPORT_UTF8 -BOOL utf8; -#endif -size_t size; -uschar *code; -const uschar *codestart; -const uschar *ptr; -compile_data compile_block; -compile_data *cd = &compile_block; - -/* This space is used for "compiling" into during the first phase, when we are -computing the amount of memory that is needed. Compiled items are thrown away -as soon as possible, so that a fairly large buffer should be sufficient for -this purpose. The same space is used in the second phase for remembering where -to fill in forward references to subpatterns. */ - -uschar cworkspace[COMPILE_WORK_SIZE]; - -/* Set this early so that early errors get offset 0. */ - -ptr = (const uschar *)pattern; - -/* We can't pass back an error message if errorptr is NULL; I guess the best we -can do is just return NULL, but we can set a code value if there is a code -pointer. */ - -if (errorptr == NULL) - { - if (errorcodeptr != NULL) *errorcodeptr = 99; - return NULL; - } - -*errorptr = NULL; -if (errorcodeptr != NULL) *errorcodeptr = ERR0; - -/* However, we can give a message for this error */ - -if (erroroffset == NULL) - { - errorcode = ERR16; - goto PCRE_EARLY_ERROR_RETURN2; - } - -*erroroffset = 0; - -/* Can't support UTF8 unless PCRE has been compiled to include the code. */ - -#ifdef SUPPORT_UTF8 -utf8 = (options & PCRE_UTF8) != 0; -if (utf8 && (options & PCRE_NO_UTF8_CHECK) == 0 && - (*erroroffset = _pcre_valid_utf8((uschar *)pattern, -1)) >= 0) - { - errorcode = ERR44; - goto PCRE_EARLY_ERROR_RETURN2; - } -#else -if ((options & PCRE_UTF8) != 0) - { - errorcode = ERR32; - goto PCRE_EARLY_ERROR_RETURN; - } -#endif - -if ((options & ~PUBLIC_OPTIONS) != 0) - { - errorcode = ERR17; - goto PCRE_EARLY_ERROR_RETURN; - } - -/* Set up pointers to the individual character tables */ - -if (tables == NULL) tables = _pcre_default_tables; -cd->lcc = tables + lcc_offset; -cd->fcc = tables + fcc_offset; -cd->cbits = tables + cbits_offset; -cd->ctypes = tables + ctypes_offset; - -/* Check for global one-time settings at the start of the pattern, and remember -the offset for later. */ - -while (ptr[skipatstart] == '(' && ptr[skipatstart+1] == '*') - { - int newnl = 0; - int newbsr = 0; - - if (strncmp((char *)(ptr+skipatstart+2), "CR)", 3) == 0) - { skipatstart += 5; newnl = PCRE_NEWLINE_CR; } - else if (strncmp((char *)(ptr+skipatstart+2), "LF)", 3) == 0) - { skipatstart += 5; newnl = PCRE_NEWLINE_LF; } - else if (strncmp((char *)(ptr+skipatstart+2), "CRLF)", 5) == 0) - { skipatstart += 7; newnl = PCRE_NEWLINE_CR + PCRE_NEWLINE_LF; } - else if (strncmp((char *)(ptr+skipatstart+2), "ANY)", 4) == 0) - { skipatstart += 6; newnl = PCRE_NEWLINE_ANY; } - else if (strncmp((char *)(ptr+skipatstart+2), "ANYCRLF)", 8) == 0) - { skipatstart += 10; newnl = PCRE_NEWLINE_ANYCRLF; } - - else if (strncmp((char *)(ptr+skipatstart+2), "BSR_ANYCRLF)", 12) == 0) - { skipatstart += 14; newbsr = PCRE_BSR_ANYCRLF; } - else if (strncmp((char *)(ptr+skipatstart+2), "BSR_UNICODE)", 12) == 0) - { skipatstart += 14; newbsr = PCRE_BSR_UNICODE; } - - if (newnl != 0) - options = (options & ~PCRE_NEWLINE_BITS) | newnl; - else if (newbsr != 0) - options = (options & ~(PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) | newbsr; - else break; - } - -/* Check validity of \R options. */ - -switch (options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) - { - case 0: - case PCRE_BSR_ANYCRLF: - case PCRE_BSR_UNICODE: - break; - default: errorcode = ERR56; goto PCRE_EARLY_ERROR_RETURN; - } - -/* Handle different types of newline. The three bits give seven cases. The -current code allows for fixed one- or two-byte sequences, plus "any" and -"anycrlf". */ - -switch (options & PCRE_NEWLINE_BITS) - { - case 0: newline = NEWLINE; break; /* Build-time default */ - case PCRE_NEWLINE_CR: newline = '\r'; break; - case PCRE_NEWLINE_LF: newline = '\n'; break; - case PCRE_NEWLINE_CR+ - PCRE_NEWLINE_LF: newline = ('\r' << 8) | '\n'; break; - case PCRE_NEWLINE_ANY: newline = -1; break; - case PCRE_NEWLINE_ANYCRLF: newline = -2; break; - default: errorcode = ERR56; goto PCRE_EARLY_ERROR_RETURN; - } - -if (newline == -2) - { - cd->nltype = NLTYPE_ANYCRLF; - } -else if (newline < 0) - { - cd->nltype = NLTYPE_ANY; - } -else - { - cd->nltype = NLTYPE_FIXED; - if (newline > 255) - { - cd->nllen = 2; - cd->nl[0] = (newline >> 8) & 255; - cd->nl[1] = newline & 255; - } - else - { - cd->nllen = 1; - cd->nl[0] = newline; - } - } - -/* Maximum back reference and backref bitmap. The bitmap records up to 31 back -references to help in deciding whether (.*) can be treated as anchored or not. -*/ - -cd->top_backref = 0; -cd->backref_map = 0; - -/* Reflect pattern for debugging output */ - -DPRINTF(("------------------------------------------------------------------\n")); -DPRINTF(("%s\n", pattern)); - -/* Pretend to compile the pattern while actually just accumulating the length -of memory required. This behaviour is triggered by passing a non-NULL final -argument to compile_regex(). We pass a block of workspace (cworkspace) for it -to compile parts of the pattern into; the compiled code is discarded when it is -no longer needed, so hopefully this workspace will never overflow, though there -is a test for its doing so. */ - -cd->bracount = cd->final_bracount = 0; -cd->names_found = 0; -cd->name_entry_size = 0; -cd->name_table = NULL; -cd->start_workspace = cworkspace; -cd->start_code = cworkspace; -cd->hwm = cworkspace; -cd->start_pattern = (const uschar *)pattern; -cd->end_pattern = (const uschar *)(pattern + strlen(pattern)); -cd->req_varyopt = 0; -cd->external_options = options; -cd->external_flags = 0; - -/* Now do the pre-compile. On error, errorcode will be set non-zero, so we -don't need to look at the result of the function here. The initial options have -been put into the cd block so that they can be changed if an option setting is -found within the regex right at the beginning. Bringing initial option settings -outside can help speed up starting point checks. */ - -ptr += skipatstart; -code = cworkspace; -*code = OP_BRA; -(void)compile_regex(cd->external_options, cd->external_options & PCRE_IMS, - &code, &ptr, &errorcode, FALSE, FALSE, 0, &firstbyte, &reqbyte, NULL, cd, - &length); -if (errorcode != 0) goto PCRE_EARLY_ERROR_RETURN; - -DPRINTF(("end pre-compile: length=%d workspace=%d\n", length, - cd->hwm - cworkspace)); - -if (length > MAX_PATTERN_SIZE) - { - errorcode = ERR20; - goto PCRE_EARLY_ERROR_RETURN; - } - -/* Compute the size of data block needed and get it, either from malloc or -externally provided function. Integer overflow should no longer be possible -because nowadays we limit the maximum value of cd->names_found and -cd->name_entry_size. */ - -size = length + sizeof(real_pcre) + cd->names_found * (cd->name_entry_size + 3); -re = (real_pcre *)(pcre_malloc)(size); - -if (re == NULL) - { - errorcode = ERR21; - goto PCRE_EARLY_ERROR_RETURN; - } - -/* Put in the magic number, and save the sizes, initial options, internal -flags, and character table pointer. NULL is used for the default character -tables. The nullpad field is at the end; it's there to help in the case when a -regex compiled on a system with 4-byte pointers is run on another with 8-byte -pointers. */ - -re->magic_number = MAGIC_NUMBER; -re->size = size; -re->options = cd->external_options; -re->flags = cd->external_flags; -re->dummy1 = 0; -re->first_byte = 0; -re->req_byte = 0; -re->name_table_offset = sizeof(real_pcre); -re->name_entry_size = cd->name_entry_size; -re->name_count = cd->names_found; -re->ref_count = 0; -re->tables = (tables == _pcre_default_tables)? NULL : tables; -re->nullpad = NULL; - -/* The starting points of the name/number translation table and of the code are -passed around in the compile data block. The start/end pattern and initial -options are already set from the pre-compile phase, as is the name_entry_size -field. Reset the bracket count and the names_found field. Also reset the hwm -field; this time it's used for remembering forward references to subpatterns. -*/ - -cd->final_bracount = cd->bracount; /* Save for checking forward references */ -cd->bracount = 0; -cd->names_found = 0; -cd->name_table = (uschar *)re + re->name_table_offset; -codestart = cd->name_table + re->name_entry_size * re->name_count; -cd->start_code = codestart; -cd->hwm = cworkspace; -cd->req_varyopt = 0; -cd->had_accept = FALSE; - -/* Set up a starting, non-extracting bracket, then compile the expression. On -error, errorcode will be set non-zero, so we don't need to look at the result -of the function here. */ - -ptr = (const uschar *)pattern + skipatstart; -code = (uschar *)codestart; -*code = OP_BRA; -(void)compile_regex(re->options, re->options & PCRE_IMS, &code, &ptr, - &errorcode, FALSE, FALSE, 0, &firstbyte, &reqbyte, NULL, cd, NULL); -re->top_bracket = cd->bracount; -re->top_backref = cd->top_backref; -re->flags = cd->external_flags; - -if (cd->had_accept) reqbyte = -1; /* Must disable after (*ACCEPT) */ - -/* If not reached end of pattern on success, there's an excess bracket. */ - -if (errorcode == 0 && *ptr != 0) errorcode = ERR22; - -/* Fill in the terminating state and check for disastrous overflow, but -if debugging, leave the test till after things are printed out. */ - -*code++ = OP_END; - -#ifndef DEBUG -if (code - codestart > length) errorcode = ERR23; -#endif - -/* Fill in any forward references that are required. */ - -while (errorcode == 0 && cd->hwm > cworkspace) - { - int offset, recno; - const uschar *groupptr; - cd->hwm -= LINK_SIZE; - offset = GET(cd->hwm, 0); - recno = GET(codestart, offset); - groupptr = find_bracket(codestart, (re->options & PCRE_UTF8) != 0, recno); - if (groupptr == NULL) errorcode = ERR53; - else PUT(((uschar *)codestart), offset, groupptr - codestart); - } - -/* Give an error if there's back reference to a non-existent capturing -subpattern. */ - -if (errorcode == 0 && re->top_backref > re->top_bracket) errorcode = ERR15; - -/* Failed to compile, or error while post-processing */ - -if (errorcode != 0) - { - (pcre_free)(re); - PCRE_EARLY_ERROR_RETURN: - *erroroffset = ptr - (const uschar *)pattern; - PCRE_EARLY_ERROR_RETURN2: - *errorptr = find_error_text(errorcode); - if (errorcodeptr != NULL) *errorcodeptr = errorcode; - return NULL; - } - -/* If the anchored option was not passed, set the flag if we can determine that -the pattern is anchored by virtue of ^ characters or \A or anything else (such -as starting with .* when DOTALL is set). - -Otherwise, if we know what the first byte has to be, save it, because that -speeds up unanchored matches no end. If not, see if we can set the -PCRE_STARTLINE flag. This is helpful for multiline matches when all branches -start with ^. and also when all branches start with .* for non-DOTALL matches. -*/ - -if ((re->options & PCRE_ANCHORED) == 0) - { - int temp_options = re->options; /* May get changed during these scans */ - if (is_anchored(codestart, &temp_options, 0, cd->backref_map)) - re->options |= PCRE_ANCHORED; - else - { - if (firstbyte < 0) - firstbyte = find_firstassertedchar(codestart, &temp_options, FALSE); - if (firstbyte >= 0) /* Remove caseless flag for non-caseable chars */ - { - int ch = firstbyte & 255; - re->first_byte = ((firstbyte & REQ_CASELESS) != 0 && - cd->fcc[ch] == ch)? ch : firstbyte; - re->flags |= PCRE_FIRSTSET; - } - else if (is_startline(codestart, 0, cd->backref_map)) - re->flags |= PCRE_STARTLINE; - } - } - -/* For an anchored pattern, we use the "required byte" only if it follows a -variable length item in the regex. Remove the caseless flag for non-caseable -bytes. */ - -if (reqbyte >= 0 && - ((re->options & PCRE_ANCHORED) == 0 || (reqbyte & REQ_VARY) != 0)) - { - int ch = reqbyte & 255; - re->req_byte = ((reqbyte & REQ_CASELESS) != 0 && - cd->fcc[ch] == ch)? (reqbyte & ~REQ_CASELESS) : reqbyte; - re->flags |= PCRE_REQCHSET; - } - -/* Print out the compiled data if debugging is enabled. This is never the -case when building a production library. */ - -#ifdef DEBUG - -printf("Length = %d top_bracket = %d top_backref = %d\n", - length, re->top_bracket, re->top_backref); - -printf("Options=%08x\n", re->options); - -if ((re->flags & PCRE_FIRSTSET) != 0) - { - int ch = re->first_byte & 255; - const char *caseless = ((re->first_byte & REQ_CASELESS) == 0)? - "" : " (caseless)"; - if (isprint(ch)) printf("First char = %c%s\n", ch, caseless); - else printf("First char = \\x%02x%s\n", ch, caseless); - } - -if ((re->flags & PCRE_REQCHSET) != 0) - { - int ch = re->req_byte & 255; - const char *caseless = ((re->req_byte & REQ_CASELESS) == 0)? - "" : " (caseless)"; - if (isprint(ch)) printf("Req char = %c%s\n", ch, caseless); - else printf("Req char = \\x%02x%s\n", ch, caseless); - } - -pcre_printint(re, stdout, TRUE); - -/* This check is done here in the debugging case so that the code that -was compiled can be seen. */ - -if (code - codestart > length) - { - (pcre_free)(re); - *errorptr = find_error_text(ERR23); - *erroroffset = ptr - (uschar *)pattern; - if (errorcodeptr != NULL) *errorcodeptr = ERR23; - return NULL; - } -#endif /* DEBUG */ - -return (pcre *)re; -} - -/* End of pcre_compile.c */ diff --git a/glib/pcre/pcre_config.c b/glib/pcre/pcre_config.c deleted file mode 100644 index 114f0fb7a..000000000 --- a/glib/pcre/pcre_config.c +++ /dev/null @@ -1,128 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains the external function pcre_config(). */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre_internal.h" - - -/************************************************* -* Return info about what features are configured * -*************************************************/ - -/* This function has an extensible interface so that additional items can be -added compatibly. - -Arguments: - what what information is required - where where to put the information - -Returns: 0 if data returned, negative on error -*/ - -PCRE_EXP_DEFN int PCRE_CALL_CONVENTION -pcre_config(int what, void *where) -{ -switch (what) - { - case PCRE_CONFIG_UTF8: -#ifdef SUPPORT_UTF8 - *((int *)where) = 1; -#else - *((int *)where) = 0; -#endif - break; - - case PCRE_CONFIG_UNICODE_PROPERTIES: -#ifdef SUPPORT_UCP - *((int *)where) = 1; -#else - *((int *)where) = 0; -#endif - break; - - case PCRE_CONFIG_NEWLINE: - *((int *)where) = NEWLINE; - break; - - case PCRE_CONFIG_BSR: -#ifdef BSR_ANYCRLF - *((int *)where) = 1; -#else - *((int *)where) = 0; -#endif - break; - - case PCRE_CONFIG_LINK_SIZE: - *((int *)where) = LINK_SIZE; - break; - - case PCRE_CONFIG_POSIX_MALLOC_THRESHOLD: - *((int *)where) = POSIX_MALLOC_THRESHOLD; - break; - - case PCRE_CONFIG_MATCH_LIMIT: - *((unsigned int *)where) = MATCH_LIMIT; - break; - - case PCRE_CONFIG_MATCH_LIMIT_RECURSION: - *((unsigned int *)where) = MATCH_LIMIT_RECURSION; - break; - - case PCRE_CONFIG_STACKRECURSE: -#ifdef NO_RECURSE - *((int *)where) = 0; -#else - *((int *)where) = 1; -#endif - break; - - default: return PCRE_ERROR_BADOPTION; - } - -return 0; -} - -/* End of pcre_config.c */ diff --git a/glib/pcre/pcre_dfa_exec.c b/glib/pcre/pcre_dfa_exec.c deleted file mode 100644 index 9a73a5209..000000000 --- a/glib/pcre/pcre_dfa_exec.c +++ /dev/null @@ -1,2920 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains the external function pcre_dfa_exec(), which is an -alternative matching function that uses a sort of DFA algorithm (not a true -FSM). This is NOT Perl- compatible, but it has advantages in certain -applications. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define NLBLOCK md /* Block containing newline information */ -#define PSSTART start_subject /* Field containing processed string start */ -#define PSEND end_subject /* Field containing processed string end */ - -#include "pcre_internal.h" - - -/* For use to indent debugging output */ - -#define SP " " - - - -/************************************************* -* Code parameters and static tables * -*************************************************/ - -/* These are offsets that are used to turn the OP_TYPESTAR and friends opcodes -into others, under special conditions. A gap of 20 between the blocks should be -enough. The resulting opcodes don't have to be less than 256 because they are -never stored, so we push them well clear of the normal opcodes. */ - -#define OP_PROP_EXTRA 300 -#define OP_EXTUNI_EXTRA 320 -#define OP_ANYNL_EXTRA 340 -#define OP_HSPACE_EXTRA 360 -#define OP_VSPACE_EXTRA 380 - - -/* This table identifies those opcodes that are followed immediately by a -character that is to be tested in some way. This makes is possible to -centralize the loading of these characters. In the case of Type * etc, the -"character" is the opcode for \D, \d, \S, \s, \W, or \w, which will always be a -small value. ***NOTE*** If the start of this table is modified, the two tables -that follow must also be modified. */ - -static const uschar coptable[] = { - 0, /* End */ - 0, 0, 0, 0, 0, /* \A, \G, \K, \B, \b */ - 0, 0, 0, 0, 0, 0, /* \D, \d, \S, \s, \W, \w */ - 0, 0, 0, /* Any, AllAny, Anybyte */ - 0, 0, 0, /* NOTPROP, PROP, EXTUNI */ - 0, 0, 0, 0, 0, /* \R, \H, \h, \V, \v */ - 0, 0, 0, 0, 0, /* \Z, \z, Opt, ^, $ */ - 1, /* Char */ - 1, /* Charnc */ - 1, /* not */ - /* Positive single-char repeats */ - 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ - 3, 3, 3, /* upto, minupto, exact */ - 1, 1, 1, 3, /* *+, ++, ?+, upto+ */ - /* Negative single-char repeats - only for chars < 256 */ - 1, 1, 1, 1, 1, 1, /* NOT *, *?, +, +?, ?, ?? */ - 3, 3, 3, /* NOT upto, minupto, exact */ - 1, 1, 1, 3, /* NOT *+, ++, ?+, updo+ */ - /* Positive type repeats */ - 1, 1, 1, 1, 1, 1, /* Type *, *?, +, +?, ?, ?? */ - 3, 3, 3, /* Type upto, minupto, exact */ - 1, 1, 1, 3, /* Type *+, ++, ?+, upto+ */ - /* Character class & ref repeats */ - 0, 0, 0, 0, 0, 0, /* *, *?, +, +?, ?, ?? */ - 0, 0, /* CRRANGE, CRMINRANGE */ - 0, /* CLASS */ - 0, /* NCLASS */ - 0, /* XCLASS - variable length */ - 0, /* REF */ - 0, /* RECURSE */ - 0, /* CALLOUT */ - 0, /* Alt */ - 0, /* Ket */ - 0, /* KetRmax */ - 0, /* KetRmin */ - 0, /* Assert */ - 0, /* Assert not */ - 0, /* Assert behind */ - 0, /* Assert behind not */ - 0, /* Reverse */ - 0, 0, 0, 0, /* ONCE, BRA, CBRA, COND */ - 0, 0, 0, /* SBRA, SCBRA, SCOND */ - 0, /* CREF */ - 0, /* RREF */ - 0, /* DEF */ - 0, 0, /* BRAZERO, BRAMINZERO */ - 0, 0, 0, 0, /* PRUNE, SKIP, THEN, COMMIT */ - 0, 0, 0 /* FAIL, ACCEPT, SKIPZERO */ -}; - -/* These 2 tables allow for compact code for testing for \D, \d, \S, \s, \W, -and \w */ - -static const uschar toptable1[] = { - 0, 0, 0, 0, 0, 0, - ctype_digit, ctype_digit, - ctype_space, ctype_space, - ctype_word, ctype_word, - 0, 0 /* OP_ANY, OP_ALLANY */ -}; - -static const uschar toptable2[] = { - 0, 0, 0, 0, 0, 0, - ctype_digit, 0, - ctype_space, 0, - ctype_word, 0, - 1, 1 /* OP_ANY, OP_ALLANY */ -}; - - -/* Structure for holding data about a particular state, which is in effect the -current data for an active path through the match tree. It must consist -entirely of ints because the working vector we are passed, and which we put -these structures in, is a vector of ints. */ - -typedef struct stateblock { - int offset; /* Offset to opcode */ - int count; /* Count for repeats */ - int ims; /* ims flag bits */ - int data; /* Some use extra data */ -} stateblock; - -#define INTS_PER_STATEBLOCK (sizeof(stateblock)/sizeof(int)) - - -#ifdef DEBUG -/************************************************* -* Print character string * -*************************************************/ - -/* Character string printing function for debugging. - -Arguments: - p points to string - length number of bytes - f where to print - -Returns: nothing -*/ - -static void -pchars(unsigned char *p, int length, FILE *f) -{ -int c; -while (length-- > 0) - { - if (isprint(c = *(p++))) - fprintf(f, "%c", c); - else - fprintf(f, "\\x%02x", c); - } -} -#endif - - - -/************************************************* -* Execute a Regular Expression - DFA engine * -*************************************************/ - -/* This internal function applies a compiled pattern to a subject string, -starting at a given point, using a DFA engine. This function is called from the -external one, possibly multiple times if the pattern is not anchored. The -function calls itself recursively for some kinds of subpattern. - -Arguments: - md the match_data block with fixed information - this_start_code the opening bracket of this subexpression's code - current_subject where we currently are in the subject string - start_offset start offset in the subject string - offsets vector to contain the matching string offsets - offsetcount size of same - workspace vector of workspace - wscount size of same - ims the current ims flags - rlevel function call recursion level - recursing regex recursive call level - -Returns: > 0 => number of match offset pairs placed in offsets - = 0 => offsets overflowed; longest matches are present - -1 => failed to match - < -1 => some kind of unexpected problem - -The following macros are used for adding states to the two state vectors (one -for the current character, one for the following character). */ - -#define ADD_ACTIVE(x,y) \ - if (active_count++ < wscount) \ - { \ - next_active_state->offset = (x); \ - next_active_state->count = (y); \ - next_active_state->ims = ims; \ - next_active_state++; \ - DPRINTF(("%.*sADD_ACTIVE(%d,%d)\n", rlevel*2-2, SP, (x), (y))); \ - } \ - else return PCRE_ERROR_DFA_WSSIZE - -#define ADD_ACTIVE_DATA(x,y,z) \ - if (active_count++ < wscount) \ - { \ - next_active_state->offset = (x); \ - next_active_state->count = (y); \ - next_active_state->ims = ims; \ - next_active_state->data = (z); \ - next_active_state++; \ - DPRINTF(("%.*sADD_ACTIVE_DATA(%d,%d,%d)\n", rlevel*2-2, SP, (x), (y), (z))); \ - } \ - else return PCRE_ERROR_DFA_WSSIZE - -#define ADD_NEW(x,y) \ - if (new_count++ < wscount) \ - { \ - next_new_state->offset = (x); \ - next_new_state->count = (y); \ - next_new_state->ims = ims; \ - next_new_state++; \ - DPRINTF(("%.*sADD_NEW(%d,%d)\n", rlevel*2-2, SP, (x), (y))); \ - } \ - else return PCRE_ERROR_DFA_WSSIZE - -#define ADD_NEW_DATA(x,y,z) \ - if (new_count++ < wscount) \ - { \ - next_new_state->offset = (x); \ - next_new_state->count = (y); \ - next_new_state->ims = ims; \ - next_new_state->data = (z); \ - next_new_state++; \ - DPRINTF(("%.*sADD_NEW_DATA(%d,%d,%d)\n", rlevel*2-2, SP, (x), (y), (z))); \ - } \ - else return PCRE_ERROR_DFA_WSSIZE - -/* And now, here is the code */ - -static int -internal_dfa_exec( - dfa_match_data *md, - const uschar *this_start_code, - const uschar *current_subject, - int start_offset, - int *offsets, - int offsetcount, - int *workspace, - int wscount, - int ims, - int rlevel, - int recursing) -{ -stateblock *active_states, *new_states, *temp_states; -stateblock *next_active_state, *next_new_state; - -const uschar *ctypes, *lcc, *fcc; -const uschar *ptr; -const uschar *end_code, *first_op; - -int active_count, new_count, match_count; - -/* Some fields in the md block are frequently referenced, so we load them into -independent variables in the hope that this will perform better. */ - -const uschar *start_subject = md->start_subject; -const uschar *end_subject = md->end_subject; -const uschar *start_code = md->start_code; - -#ifdef SUPPORT_UTF8 -BOOL utf8 = (md->poptions & PCRE_UTF8) != 0; -#else -BOOL utf8 = FALSE; -#endif - -rlevel++; -offsetcount &= (-2); - -wscount -= 2; -wscount = (wscount - (wscount % (INTS_PER_STATEBLOCK * 2))) / - (2 * INTS_PER_STATEBLOCK); - -DPRINTF(("\n%.*s---------------------\n" - "%.*sCall to internal_dfa_exec f=%d r=%d\n", - rlevel*2-2, SP, rlevel*2-2, SP, rlevel, recursing)); - -ctypes = md->tables + ctypes_offset; -lcc = md->tables + lcc_offset; -fcc = md->tables + fcc_offset; - -match_count = PCRE_ERROR_NOMATCH; /* A negative number */ - -active_states = (stateblock *)(workspace + 2); -next_new_state = new_states = active_states + wscount; -new_count = 0; - -first_op = this_start_code + 1 + LINK_SIZE + - ((*this_start_code == OP_CBRA || *this_start_code == OP_SCBRA)? 2:0); - -/* The first thing in any (sub) pattern is a bracket of some sort. Push all -the alternative states onto the list, and find out where the end is. This -makes is possible to use this function recursively, when we want to stop at a -matching internal ket rather than at the end. - -If the first opcode in the first alternative is OP_REVERSE, we are dealing with -a backward assertion. In that case, we have to find out the maximum amount to -move back, and set up each alternative appropriately. */ - -if (*first_op == OP_REVERSE) - { - int max_back = 0; - int gone_back; - - end_code = this_start_code; - do - { - int back = GET(end_code, 2+LINK_SIZE); - if (back > max_back) max_back = back; - end_code += GET(end_code, 1); - } - while (*end_code == OP_ALT); - - /* If we can't go back the amount required for the longest lookbehind - pattern, go back as far as we can; some alternatives may still be viable. */ - -#ifdef SUPPORT_UTF8 - /* In character mode we have to step back character by character */ - - if (utf8) - { - for (gone_back = 0; gone_back < max_back; gone_back++) - { - if (current_subject <= start_subject) break; - current_subject--; - while (current_subject > start_subject && - (*current_subject & 0xc0) == 0x80) - current_subject--; - } - } - else -#endif - - /* In byte-mode we can do this quickly. */ - - { - gone_back = (current_subject - max_back < start_subject)? - current_subject - start_subject : max_back; - current_subject -= gone_back; - } - - /* Now we can process the individual branches. */ - - end_code = this_start_code; - do - { - int back = GET(end_code, 2+LINK_SIZE); - if (back <= gone_back) - { - int bstate = end_code - start_code + 2 + 2*LINK_SIZE; - ADD_NEW_DATA(-bstate, 0, gone_back - back); - } - end_code += GET(end_code, 1); - } - while (*end_code == OP_ALT); - } - -/* This is the code for a "normal" subpattern (not a backward assertion). The -start of a whole pattern is always one of these. If we are at the top level, -we may be asked to restart matching from the same point that we reached for a -previous partial match. We still have to scan through the top-level branches to -find the end state. */ - -else - { - end_code = this_start_code; - - /* Restarting */ - - if (rlevel == 1 && (md->moptions & PCRE_DFA_RESTART) != 0) - { - do { end_code += GET(end_code, 1); } while (*end_code == OP_ALT); - new_count = workspace[1]; - if (!workspace[0]) - memcpy(new_states, active_states, new_count * sizeof(stateblock)); - } - - /* Not restarting */ - - else - { - int length = 1 + LINK_SIZE + - ((*this_start_code == OP_CBRA || *this_start_code == OP_SCBRA)? 2:0); - do - { - ADD_NEW(end_code - start_code + length, 0); - end_code += GET(end_code, 1); - length = 1 + LINK_SIZE; - } - while (*end_code == OP_ALT); - } - } - -workspace[0] = 0; /* Bit indicating which vector is current */ - -DPRINTF(("%.*sEnd state = %d\n", rlevel*2-2, SP, end_code - start_code)); - -/* Loop for scanning the subject */ - -ptr = current_subject; -for (;;) - { - int i, j; - int clen, dlen; - unsigned int c, d; - - /* Make the new state list into the active state list and empty the - new state list. */ - - temp_states = active_states; - active_states = new_states; - new_states = temp_states; - active_count = new_count; - new_count = 0; - - workspace[0] ^= 1; /* Remember for the restarting feature */ - workspace[1] = active_count; - -#ifdef DEBUG - printf("%.*sNext character: rest of subject = \"", rlevel*2-2, SP); - pchars((uschar *)ptr, strlen((char *)ptr), stdout); - printf("\"\n"); - - printf("%.*sActive states: ", rlevel*2-2, SP); - for (i = 0; i < active_count; i++) - printf("%d/%d ", active_states[i].offset, active_states[i].count); - printf("\n"); -#endif - - /* Set the pointers for adding new states */ - - next_active_state = active_states + active_count; - next_new_state = new_states; - - /* Load the current character from the subject outside the loop, as many - different states may want to look at it, and we assume that at least one - will. */ - - if (ptr < end_subject) - { - clen = 1; /* Number of bytes in the character */ -#ifdef SUPPORT_UTF8 - if (utf8) { GETCHARLEN(c, ptr, clen); } else -#endif /* SUPPORT_UTF8 */ - c = *ptr; - } - else - { - clen = 0; /* This indicates the end of the subject */ - c = NOTACHAR; /* This value should never actually be used */ - } - - /* Scan up the active states and act on each one. The result of an action - may be to add more states to the currently active list (e.g. on hitting a - parenthesis) or it may be to put states on the new list, for considering - when we move the character pointer on. */ - - for (i = 0; i < active_count; i++) - { - stateblock *current_state = active_states + i; - const uschar *code; - int state_offset = current_state->offset; - int count, codevalue; - -#ifdef DEBUG - printf ("%.*sProcessing state %d c=", rlevel*2-2, SP, state_offset); - if (clen == 0) printf("EOL\n"); - else if (c > 32 && c < 127) printf("'%c'\n", c); - else printf("0x%02x\n", c); -#endif - - /* This variable is referred to implicity in the ADD_xxx macros. */ - - ims = current_state->ims; - - /* A negative offset is a special case meaning "hold off going to this - (negated) state until the number of characters in the data field have - been skipped". */ - - if (state_offset < 0) - { - if (current_state->data > 0) - { - DPRINTF(("%.*sSkipping this character\n", rlevel*2-2, SP)); - ADD_NEW_DATA(state_offset, current_state->count, - current_state->data - 1); - continue; - } - else - { - current_state->offset = state_offset = -state_offset; - } - } - - /* Check for a duplicate state with the same count, and skip if found. */ - - for (j = 0; j < i; j++) - { - if (active_states[j].offset == state_offset && - active_states[j].count == current_state->count) - { - DPRINTF(("%.*sDuplicate state: skipped\n", rlevel*2-2, SP)); - goto NEXT_ACTIVE_STATE; - } - } - - /* The state offset is the offset to the opcode */ - - code = start_code + state_offset; - codevalue = *code; - - /* If this opcode is followed by an inline character, load it. It is - tempting to test for the presence of a subject character here, but that - is wrong, because sometimes zero repetitions of the subject are - permitted. - - We also use this mechanism for opcodes such as OP_TYPEPLUS that take an - argument that is not a data character - but is always one byte long. We - have to take special action to deal with \P, \p, \H, \h, \V, \v and \X in - this case. To keep the other cases fast, convert these ones to new opcodes. - */ - - if (coptable[codevalue] > 0) - { - dlen = 1; -#ifdef SUPPORT_UTF8 - if (utf8) { GETCHARLEN(d, (code + coptable[codevalue]), dlen); } else -#endif /* SUPPORT_UTF8 */ - d = code[coptable[codevalue]]; - if (codevalue >= OP_TYPESTAR) - { - switch(d) - { - case OP_ANYBYTE: return PCRE_ERROR_DFA_UITEM; - case OP_NOTPROP: - case OP_PROP: codevalue += OP_PROP_EXTRA; break; - case OP_ANYNL: codevalue += OP_ANYNL_EXTRA; break; - case OP_EXTUNI: codevalue += OP_EXTUNI_EXTRA; break; - case OP_NOT_HSPACE: - case OP_HSPACE: codevalue += OP_HSPACE_EXTRA; break; - case OP_NOT_VSPACE: - case OP_VSPACE: codevalue += OP_VSPACE_EXTRA; break; - default: break; - } - } - } - else - { - dlen = 0; /* Not strictly necessary, but compilers moan */ - d = NOTACHAR; /* if these variables are not set. */ - } - - - /* Now process the individual opcodes */ - - switch (codevalue) - { - -/* ========================================================================== */ - /* Reached a closing bracket. If not at the end of the pattern, carry - on with the next opcode. Otherwise, unless we have an empty string and - PCRE_NOTEMPTY is set, save the match data, shifting up all previous - matches so we always have the longest first. */ - - case OP_KET: - case OP_KETRMIN: - case OP_KETRMAX: - if (code != end_code) - { - ADD_ACTIVE(state_offset + 1 + LINK_SIZE, 0); - if (codevalue != OP_KET) - { - ADD_ACTIVE(state_offset - GET(code, 1), 0); - } - } - else if (ptr > current_subject || (md->moptions & PCRE_NOTEMPTY) == 0) - { - if (match_count < 0) match_count = (offsetcount >= 2)? 1 : 0; - else if (match_count > 0 && ++match_count * 2 >= offsetcount) - match_count = 0; - count = ((match_count == 0)? offsetcount : match_count * 2) - 2; - if (count > 0) memmove(offsets + 2, offsets, count * sizeof(int)); - if (offsetcount >= 2) - { - offsets[0] = current_subject - start_subject; - offsets[1] = ptr - start_subject; - DPRINTF(("%.*sSet matched string = \"%.*s\"\n", rlevel*2-2, SP, - offsets[1] - offsets[0], current_subject)); - } - if ((md->moptions & PCRE_DFA_SHORTEST) != 0) - { - DPRINTF(("%.*sEnd of internal_dfa_exec %d: returning %d\n" - "%.*s---------------------\n\n", rlevel*2-2, SP, rlevel, - match_count, rlevel*2-2, SP)); - return match_count; - } - } - break; - -/* ========================================================================== */ - /* These opcodes add to the current list of states without looking - at the current character. */ - - /*-----------------------------------------------------------------*/ - case OP_ALT: - do { code += GET(code, 1); } while (*code == OP_ALT); - ADD_ACTIVE(code - start_code, 0); - break; - - /*-----------------------------------------------------------------*/ - case OP_BRA: - case OP_SBRA: - do - { - ADD_ACTIVE(code - start_code + 1 + LINK_SIZE, 0); - code += GET(code, 1); - } - while (*code == OP_ALT); - break; - - /*-----------------------------------------------------------------*/ - case OP_CBRA: - case OP_SCBRA: - ADD_ACTIVE(code - start_code + 3 + LINK_SIZE, 0); - code += GET(code, 1); - while (*code == OP_ALT) - { - ADD_ACTIVE(code - start_code + 1 + LINK_SIZE, 0); - code += GET(code, 1); - } - break; - - /*-----------------------------------------------------------------*/ - case OP_BRAZERO: - case OP_BRAMINZERO: - ADD_ACTIVE(state_offset + 1, 0); - code += 1 + GET(code, 2); - while (*code == OP_ALT) code += GET(code, 1); - ADD_ACTIVE(code - start_code + 1 + LINK_SIZE, 0); - break; - - /*-----------------------------------------------------------------*/ - case OP_SKIPZERO: - code += 1 + GET(code, 2); - while (*code == OP_ALT) code += GET(code, 1); - ADD_ACTIVE(code - start_code + 1 + LINK_SIZE, 0); - break; - - /*-----------------------------------------------------------------*/ - case OP_CIRC: - if ((ptr == start_subject && (md->moptions & PCRE_NOTBOL) == 0) || - ((ims & PCRE_MULTILINE) != 0 && - ptr != end_subject && - WAS_NEWLINE(ptr))) - { ADD_ACTIVE(state_offset + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - case OP_EOD: - if (ptr >= end_subject) { ADD_ACTIVE(state_offset + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - case OP_OPT: - ims = code[1]; - ADD_ACTIVE(state_offset + 2, 0); - break; - - /*-----------------------------------------------------------------*/ - case OP_SOD: - if (ptr == start_subject) { ADD_ACTIVE(state_offset + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - case OP_SOM: - if (ptr == start_subject + start_offset) { ADD_ACTIVE(state_offset + 1, 0); } - break; - - -/* ========================================================================== */ - /* These opcodes inspect the next subject character, and sometimes - the previous one as well, but do not have an argument. The variable - clen contains the length of the current character and is zero if we are - at the end of the subject. */ - - /*-----------------------------------------------------------------*/ - case OP_ANY: - if (clen > 0 && !IS_NEWLINE(ptr)) - { ADD_NEW(state_offset + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - case OP_ALLANY: - if (clen > 0) - { ADD_NEW(state_offset + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - case OP_EODN: - if (clen == 0 || (IS_NEWLINE(ptr) && ptr == end_subject - md->nllen)) - { ADD_ACTIVE(state_offset + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - case OP_DOLL: - if ((md->moptions & PCRE_NOTEOL) == 0) - { - if (clen == 0 || - (IS_NEWLINE(ptr) && - ((ims & PCRE_MULTILINE) != 0 || ptr == end_subject - md->nllen) - )) - { ADD_ACTIVE(state_offset + 1, 0); } - } - else if ((ims & PCRE_MULTILINE) != 0 && IS_NEWLINE(ptr)) - { ADD_ACTIVE(state_offset + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - - case OP_DIGIT: - case OP_WHITESPACE: - case OP_WORDCHAR: - if (clen > 0 && c < 256 && - ((ctypes[c] & toptable1[codevalue]) ^ toptable2[codevalue]) != 0) - { ADD_NEW(state_offset + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - case OP_NOT_DIGIT: - case OP_NOT_WHITESPACE: - case OP_NOT_WORDCHAR: - if (clen > 0 && (c >= 256 || - ((ctypes[c] & toptable1[codevalue]) ^ toptable2[codevalue]) != 0)) - { ADD_NEW(state_offset + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - case OP_WORD_BOUNDARY: - case OP_NOT_WORD_BOUNDARY: - { - int left_word, right_word; - - if (ptr > start_subject) - { - const uschar *temp = ptr - 1; -#ifdef SUPPORT_UTF8 - if (utf8) BACKCHAR(temp); -#endif - GETCHARTEST(d, temp); - left_word = d < 256 && (ctypes[d] & ctype_word) != 0; - } - else left_word = 0; - - if (clen > 0) right_word = c < 256 && (ctypes[c] & ctype_word) != 0; - else right_word = 0; - - if ((left_word == right_word) == (codevalue == OP_NOT_WORD_BOUNDARY)) - { ADD_ACTIVE(state_offset + 1, 0); } - } - break; - - - /*-----------------------------------------------------------------*/ - /* Check the next character by Unicode property. We will get here only - if the support is in the binary; otherwise a compile-time error occurs. - */ - -#ifdef SUPPORT_UCP - case OP_PROP: - case OP_NOTPROP: - if (clen > 0) - { - BOOL OK; - int chartype = UCD_CHARTYPE(c); - switch(code[1]) - { - case PT_ANY: - OK = TRUE; - break; - - case PT_LAMP: - OK = chartype == ucp_Lu || chartype == ucp_Ll || chartype == ucp_Lt; - break; - - case PT_GC: - OK = _pcre_ucp_gentype[chartype] == code[2]; - break; - - case PT_PC: - OK = chartype == code[2]; - break; - - case PT_SC: - OK = UCD_SCRIPT(c) == code[2]; - break; - - /* Should never occur, but keep compilers from grumbling. */ - - default: - OK = codevalue != OP_PROP; - break; - } - - if (OK == (codevalue == OP_PROP)) { ADD_NEW(state_offset + 3, 0); } - } - break; -#endif - - - -/* ========================================================================== */ - /* These opcodes likewise inspect the subject character, but have an - argument that is not a data character. It is one of these opcodes: - OP_ANY, OP_ALLANY, OP_DIGIT, OP_NOT_DIGIT, OP_WHITESPACE, OP_NOT_SPACE, - OP_WORDCHAR, OP_NOT_WORDCHAR. The value is loaded into d. */ - - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEPOSPLUS: - count = current_state->count; /* Already matched */ - if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } - if (clen > 0) - { - if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) || - (c < 256 && - (d != OP_ANY || !IS_NEWLINE(ptr)) && - ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0)) - { - if (count > 0 && codevalue == OP_TYPEPOSPLUS) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - count++; - ADD_NEW(state_offset, count); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSQUERY: - ADD_ACTIVE(state_offset + 2, 0); - if (clen > 0) - { - if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) || - (c < 256 && - (d != OP_ANY || !IS_NEWLINE(ptr)) && - ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0)) - { - if (codevalue == OP_TYPEPOSQUERY) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW(state_offset + 2, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPOSSTAR: - ADD_ACTIVE(state_offset + 2, 0); - if (clen > 0) - { - if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) || - (c < 256 && - (d != OP_ANY || !IS_NEWLINE(ptr)) && - ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0)) - { - if (codevalue == OP_TYPEPOSSTAR) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW(state_offset, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_TYPEEXACT: - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) || - (c < 256 && - (d != OP_ANY || !IS_NEWLINE(ptr)) && - ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0)) - { - if (++count >= GET2(code, 1)) - { ADD_NEW(state_offset + 4, 0); } - else - { ADD_NEW(state_offset, count); } - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEPOSUPTO: - ADD_ACTIVE(state_offset + 4, 0); - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) || - (c < 256 && - (d != OP_ANY || !IS_NEWLINE(ptr)) && - ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0)) - { - if (codevalue == OP_TYPEPOSUPTO) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - if (++count >= GET2(code, 1)) - { ADD_NEW(state_offset + 4, 0); } - else - { ADD_NEW(state_offset, count); } - } - } - break; - -/* ========================================================================== */ - /* These are virtual opcodes that are used when something like - OP_TYPEPLUS has OP_PROP, OP_NOTPROP, OP_ANYNL, or OP_EXTUNI as its - argument. It keeps the code above fast for the other cases. The argument - is in the d variable. */ - -#ifdef SUPPORT_UCP - case OP_PROP_EXTRA + OP_TYPEPLUS: - case OP_PROP_EXTRA + OP_TYPEMINPLUS: - case OP_PROP_EXTRA + OP_TYPEPOSPLUS: - count = current_state->count; /* Already matched */ - if (count > 0) { ADD_ACTIVE(state_offset + 4, 0); } - if (clen > 0) - { - BOOL OK; - int chartype = UCD_CHARTYPE(c); - switch(code[2]) - { - case PT_ANY: - OK = TRUE; - break; - - case PT_LAMP: - OK = chartype == ucp_Lu || chartype == ucp_Ll || chartype == ucp_Lt; - break; - - case PT_GC: - OK = _pcre_ucp_gentype[chartype] == code[3]; - break; - - case PT_PC: - OK = chartype == code[3]; - break; - - case PT_SC: - OK = UCD_SCRIPT(c) == code[3]; - break; - - /* Should never occur, but keep compilers from grumbling. */ - - default: - OK = codevalue != OP_PROP; - break; - } - - if (OK == (d == OP_PROP)) - { - if (count > 0 && codevalue == OP_PROP_EXTRA + OP_TYPEPOSPLUS) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - count++; - ADD_NEW(state_offset, count); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_EXTUNI_EXTRA + OP_TYPEPLUS: - case OP_EXTUNI_EXTRA + OP_TYPEMINPLUS: - case OP_EXTUNI_EXTRA + OP_TYPEPOSPLUS: - count = current_state->count; /* Already matched */ - if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } - if (clen > 0 && UCD_CATEGORY(c) != ucp_M) - { - const uschar *nptr = ptr + clen; - int ncount = 0; - if (count > 0 && codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSPLUS) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - while (nptr < end_subject) - { - int nd; - int ndlen = 1; - GETCHARLEN(nd, nptr, ndlen); - if (UCD_CATEGORY(nd) != ucp_M) break; - ncount++; - nptr += ndlen; - } - count++; - ADD_NEW_DATA(-state_offset, count, ncount); - } - break; -#endif - - /*-----------------------------------------------------------------*/ - case OP_ANYNL_EXTRA + OP_TYPEPLUS: - case OP_ANYNL_EXTRA + OP_TYPEMINPLUS: - case OP_ANYNL_EXTRA + OP_TYPEPOSPLUS: - count = current_state->count; /* Already matched */ - if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } - if (clen > 0) - { - int ncount = 0; - switch (c) - { - case 0x000b: - case 0x000c: - case 0x0085: - case 0x2028: - case 0x2029: - if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break; - goto ANYNL01; - - case 0x000d: - if (ptr + 1 < end_subject && ptr[1] == 0x0a) ncount = 1; - /* Fall through */ - - ANYNL01: - case 0x000a: - if (count > 0 && codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSPLUS) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - count++; - ADD_NEW_DATA(-state_offset, count, ncount); - break; - - default: - break; - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_VSPACE_EXTRA + OP_TYPEPLUS: - case OP_VSPACE_EXTRA + OP_TYPEMINPLUS: - case OP_VSPACE_EXTRA + OP_TYPEPOSPLUS: - count = current_state->count; /* Already matched */ - if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } - if (clen > 0) - { - BOOL OK; - switch (c) - { - case 0x000a: - case 0x000b: - case 0x000c: - case 0x000d: - case 0x0085: - case 0x2028: - case 0x2029: - OK = TRUE; - break; - - default: - OK = FALSE; - break; - } - - if (OK == (d == OP_VSPACE)) - { - if (count > 0 && codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSPLUS) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - count++; - ADD_NEW_DATA(-state_offset, count, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_HSPACE_EXTRA + OP_TYPEPLUS: - case OP_HSPACE_EXTRA + OP_TYPEMINPLUS: - case OP_HSPACE_EXTRA + OP_TYPEPOSPLUS: - count = current_state->count; /* Already matched */ - if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } - if (clen > 0) - { - BOOL OK; - switch (c) - { - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - OK = TRUE; - break; - - default: - OK = FALSE; - break; - } - - if (OK == (d == OP_HSPACE)) - { - if (count > 0 && codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSPLUS) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - count++; - ADD_NEW_DATA(-state_offset, count, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ -#ifdef SUPPORT_UCP - case OP_PROP_EXTRA + OP_TYPEQUERY: - case OP_PROP_EXTRA + OP_TYPEMINQUERY: - case OP_PROP_EXTRA + OP_TYPEPOSQUERY: - count = 4; - goto QS1; - - case OP_PROP_EXTRA + OP_TYPESTAR: - case OP_PROP_EXTRA + OP_TYPEMINSTAR: - case OP_PROP_EXTRA + OP_TYPEPOSSTAR: - count = 0; - - QS1: - - ADD_ACTIVE(state_offset + 4, 0); - if (clen > 0) - { - BOOL OK; - int chartype = UCD_CHARTYPE(c); - switch(code[2]) - { - case PT_ANY: - OK = TRUE; - break; - - case PT_LAMP: - OK = chartype == ucp_Lu || chartype == ucp_Ll || chartype == ucp_Lt; - break; - - case PT_GC: - OK = _pcre_ucp_gentype[chartype] == code[3]; - break; - - case PT_PC: - OK = chartype == code[3]; - break; - - case PT_SC: - OK = UCD_SCRIPT(c) == code[3]; - break; - - /* Should never occur, but keep compilers from grumbling. */ - - default: - OK = codevalue != OP_PROP; - break; - } - - if (OK == (d == OP_PROP)) - { - if (codevalue == OP_PROP_EXTRA + OP_TYPEPOSSTAR || - codevalue == OP_PROP_EXTRA + OP_TYPEPOSQUERY) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW(state_offset + count, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_EXTUNI_EXTRA + OP_TYPEQUERY: - case OP_EXTUNI_EXTRA + OP_TYPEMINQUERY: - case OP_EXTUNI_EXTRA + OP_TYPEPOSQUERY: - count = 2; - goto QS2; - - case OP_EXTUNI_EXTRA + OP_TYPESTAR: - case OP_EXTUNI_EXTRA + OP_TYPEMINSTAR: - case OP_EXTUNI_EXTRA + OP_TYPEPOSSTAR: - count = 0; - - QS2: - - ADD_ACTIVE(state_offset + 2, 0); - if (clen > 0 && UCD_CATEGORY(c) != ucp_M) - { - const uschar *nptr = ptr + clen; - int ncount = 0; - if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSSTAR || - codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSQUERY) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - while (nptr < end_subject) - { - int nd; - int ndlen = 1; - GETCHARLEN(nd, nptr, ndlen); - if (UCD_CATEGORY(nd) != ucp_M) break; - ncount++; - nptr += ndlen; - } - ADD_NEW_DATA(-(state_offset + count), 0, ncount); - } - break; -#endif - - /*-----------------------------------------------------------------*/ - case OP_ANYNL_EXTRA + OP_TYPEQUERY: - case OP_ANYNL_EXTRA + OP_TYPEMINQUERY: - case OP_ANYNL_EXTRA + OP_TYPEPOSQUERY: - count = 2; - goto QS3; - - case OP_ANYNL_EXTRA + OP_TYPESTAR: - case OP_ANYNL_EXTRA + OP_TYPEMINSTAR: - case OP_ANYNL_EXTRA + OP_TYPEPOSSTAR: - count = 0; - - QS3: - ADD_ACTIVE(state_offset + 2, 0); - if (clen > 0) - { - int ncount = 0; - switch (c) - { - case 0x000b: - case 0x000c: - case 0x0085: - case 0x2028: - case 0x2029: - if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break; - goto ANYNL02; - - case 0x000d: - if (ptr + 1 < end_subject && ptr[1] == 0x0a) ncount = 1; - /* Fall through */ - - ANYNL02: - case 0x000a: - if (codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSSTAR || - codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSQUERY) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW_DATA(-(state_offset + count), 0, ncount); - break; - - default: - break; - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_VSPACE_EXTRA + OP_TYPEQUERY: - case OP_VSPACE_EXTRA + OP_TYPEMINQUERY: - case OP_VSPACE_EXTRA + OP_TYPEPOSQUERY: - count = 2; - goto QS4; - - case OP_VSPACE_EXTRA + OP_TYPESTAR: - case OP_VSPACE_EXTRA + OP_TYPEMINSTAR: - case OP_VSPACE_EXTRA + OP_TYPEPOSSTAR: - count = 0; - - QS4: - ADD_ACTIVE(state_offset + 2, 0); - if (clen > 0) - { - BOOL OK; - switch (c) - { - case 0x000a: - case 0x000b: - case 0x000c: - case 0x000d: - case 0x0085: - case 0x2028: - case 0x2029: - OK = TRUE; - break; - - default: - OK = FALSE; - break; - } - if (OK == (d == OP_VSPACE)) - { - if (codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSSTAR || - codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSQUERY) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW_DATA(-(state_offset + count), 0, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_HSPACE_EXTRA + OP_TYPEQUERY: - case OP_HSPACE_EXTRA + OP_TYPEMINQUERY: - case OP_HSPACE_EXTRA + OP_TYPEPOSQUERY: - count = 2; - goto QS5; - - case OP_HSPACE_EXTRA + OP_TYPESTAR: - case OP_HSPACE_EXTRA + OP_TYPEMINSTAR: - case OP_HSPACE_EXTRA + OP_TYPEPOSSTAR: - count = 0; - - QS5: - ADD_ACTIVE(state_offset + 2, 0); - if (clen > 0) - { - BOOL OK; - switch (c) - { - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - OK = TRUE; - break; - - default: - OK = FALSE; - break; - } - - if (OK == (d == OP_HSPACE)) - { - if (codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSSTAR || - codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSQUERY) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW_DATA(-(state_offset + count), 0, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ -#ifdef SUPPORT_UCP - case OP_PROP_EXTRA + OP_TYPEEXACT: - case OP_PROP_EXTRA + OP_TYPEUPTO: - case OP_PROP_EXTRA + OP_TYPEMINUPTO: - case OP_PROP_EXTRA + OP_TYPEPOSUPTO: - if (codevalue != OP_PROP_EXTRA + OP_TYPEEXACT) - { ADD_ACTIVE(state_offset + 6, 0); } - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - BOOL OK; - int chartype = UCD_CHARTYPE(c); - switch(code[4]) - { - case PT_ANY: - OK = TRUE; - break; - - case PT_LAMP: - OK = chartype == ucp_Lu || chartype == ucp_Ll || chartype == ucp_Lt; - break; - - case PT_GC: - OK = _pcre_ucp_gentype[chartype] == code[5]; - break; - - case PT_PC: - OK = chartype == code[5]; - break; - - case PT_SC: - OK = UCD_SCRIPT(c) == code[5]; - break; - - /* Should never occur, but keep compilers from grumbling. */ - - default: - OK = codevalue != OP_PROP; - break; - } - - if (OK == (d == OP_PROP)) - { - if (codevalue == OP_PROP_EXTRA + OP_TYPEPOSUPTO) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - if (++count >= GET2(code, 1)) - { ADD_NEW(state_offset + 6, 0); } - else - { ADD_NEW(state_offset, count); } - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_EXTUNI_EXTRA + OP_TYPEEXACT: - case OP_EXTUNI_EXTRA + OP_TYPEUPTO: - case OP_EXTUNI_EXTRA + OP_TYPEMINUPTO: - case OP_EXTUNI_EXTRA + OP_TYPEPOSUPTO: - if (codevalue != OP_EXTUNI_EXTRA + OP_TYPEEXACT) - { ADD_ACTIVE(state_offset + 4, 0); } - count = current_state->count; /* Number already matched */ - if (clen > 0 && UCD_CATEGORY(c) != ucp_M) - { - const uschar *nptr = ptr + clen; - int ncount = 0; - if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSUPTO) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - while (nptr < end_subject) - { - int nd; - int ndlen = 1; - GETCHARLEN(nd, nptr, ndlen); - if (UCD_CATEGORY(nd) != ucp_M) break; - ncount++; - nptr += ndlen; - } - if (++count >= GET2(code, 1)) - { ADD_NEW_DATA(-(state_offset + 4), 0, ncount); } - else - { ADD_NEW_DATA(-state_offset, count, ncount); } - } - break; -#endif - - /*-----------------------------------------------------------------*/ - case OP_ANYNL_EXTRA + OP_TYPEEXACT: - case OP_ANYNL_EXTRA + OP_TYPEUPTO: - case OP_ANYNL_EXTRA + OP_TYPEMINUPTO: - case OP_ANYNL_EXTRA + OP_TYPEPOSUPTO: - if (codevalue != OP_ANYNL_EXTRA + OP_TYPEEXACT) - { ADD_ACTIVE(state_offset + 4, 0); } - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - int ncount = 0; - switch (c) - { - case 0x000b: - case 0x000c: - case 0x0085: - case 0x2028: - case 0x2029: - if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break; - goto ANYNL03; - - case 0x000d: - if (ptr + 1 < end_subject && ptr[1] == 0x0a) ncount = 1; - /* Fall through */ - - ANYNL03: - case 0x000a: - if (codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSUPTO) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - if (++count >= GET2(code, 1)) - { ADD_NEW_DATA(-(state_offset + 4), 0, ncount); } - else - { ADD_NEW_DATA(-state_offset, count, ncount); } - break; - - default: - break; - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_VSPACE_EXTRA + OP_TYPEEXACT: - case OP_VSPACE_EXTRA + OP_TYPEUPTO: - case OP_VSPACE_EXTRA + OP_TYPEMINUPTO: - case OP_VSPACE_EXTRA + OP_TYPEPOSUPTO: - if (codevalue != OP_VSPACE_EXTRA + OP_TYPEEXACT) - { ADD_ACTIVE(state_offset + 4, 0); } - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - BOOL OK; - switch (c) - { - case 0x000a: - case 0x000b: - case 0x000c: - case 0x000d: - case 0x0085: - case 0x2028: - case 0x2029: - OK = TRUE; - break; - - default: - OK = FALSE; - } - - if (OK == (d == OP_VSPACE)) - { - if (codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSUPTO) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - if (++count >= GET2(code, 1)) - { ADD_NEW_DATA(-(state_offset + 4), 0, 0); } - else - { ADD_NEW_DATA(-state_offset, count, 0); } - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_HSPACE_EXTRA + OP_TYPEEXACT: - case OP_HSPACE_EXTRA + OP_TYPEUPTO: - case OP_HSPACE_EXTRA + OP_TYPEMINUPTO: - case OP_HSPACE_EXTRA + OP_TYPEPOSUPTO: - if (codevalue != OP_HSPACE_EXTRA + OP_TYPEEXACT) - { ADD_ACTIVE(state_offset + 4, 0); } - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - BOOL OK; - switch (c) - { - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - OK = TRUE; - break; - - default: - OK = FALSE; - break; - } - - if (OK == (d == OP_HSPACE)) - { - if (codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSUPTO) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - if (++count >= GET2(code, 1)) - { ADD_NEW_DATA(-(state_offset + 4), 0, 0); } - else - { ADD_NEW_DATA(-state_offset, count, 0); } - } - } - break; - -/* ========================================================================== */ - /* These opcodes are followed by a character that is usually compared - to the current subject character; it is loaded into d. We still get - here even if there is no subject character, because in some cases zero - repetitions are permitted. */ - - /*-----------------------------------------------------------------*/ - case OP_CHAR: - if (clen > 0 && c == d) { ADD_NEW(state_offset + dlen + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - case OP_CHARNC: - if (clen == 0) break; - -#ifdef SUPPORT_UTF8 - if (utf8) - { - if (c == d) { ADD_NEW(state_offset + dlen + 1, 0); } else - { - unsigned int othercase; - if (c < 128) othercase = fcc[c]; else - - /* If we have Unicode property support, we can use it to test the - other case of the character. */ - -#ifdef SUPPORT_UCP - othercase = UCD_OTHERCASE(c); -#else - othercase = NOTACHAR; -#endif - - if (d == othercase) { ADD_NEW(state_offset + dlen + 1, 0); } - } - } - else -#endif /* SUPPORT_UTF8 */ - - /* Non-UTF-8 mode */ - { - if (lcc[c] == lcc[d]) { ADD_NEW(state_offset + 2, 0); } - } - break; - - -#ifdef SUPPORT_UCP - /*-----------------------------------------------------------------*/ - /* This is a tricky one because it can match more than one character. - Find out how many characters to skip, and then set up a negative state - to wait for them to pass before continuing. */ - - case OP_EXTUNI: - if (clen > 0 && UCD_CATEGORY(c) != ucp_M) - { - const uschar *nptr = ptr + clen; - int ncount = 0; - while (nptr < end_subject) - { - int nclen = 1; - GETCHARLEN(c, nptr, nclen); - if (UCD_CATEGORY(c) != ucp_M) break; - ncount++; - nptr += nclen; - } - ADD_NEW_DATA(-(state_offset + 1), 0, ncount); - } - break; -#endif - - /*-----------------------------------------------------------------*/ - /* This is a tricky like EXTUNI because it too can match more than one - character (when CR is followed by LF). In this case, set up a negative - state to wait for one character to pass before continuing. */ - - case OP_ANYNL: - if (clen > 0) switch(c) - { - case 0x000b: - case 0x000c: - case 0x0085: - case 0x2028: - case 0x2029: - if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break; - - case 0x000a: - ADD_NEW(state_offset + 1, 0); - break; - - case 0x000d: - if (ptr + 1 < end_subject && ptr[1] == 0x0a) - { - ADD_NEW_DATA(-(state_offset + 1), 0, 1); - } - else - { - ADD_NEW(state_offset + 1, 0); - } - break; - } - break; - - /*-----------------------------------------------------------------*/ - case OP_NOT_VSPACE: - if (clen > 0) switch(c) - { - case 0x000a: - case 0x000b: - case 0x000c: - case 0x000d: - case 0x0085: - case 0x2028: - case 0x2029: - break; - - default: - ADD_NEW(state_offset + 1, 0); - break; - } - break; - - /*-----------------------------------------------------------------*/ - case OP_VSPACE: - if (clen > 0) switch(c) - { - case 0x000a: - case 0x000b: - case 0x000c: - case 0x000d: - case 0x0085: - case 0x2028: - case 0x2029: - ADD_NEW(state_offset + 1, 0); - break; - - default: break; - } - break; - - /*-----------------------------------------------------------------*/ - case OP_NOT_HSPACE: - if (clen > 0) switch(c) - { - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - break; - - default: - ADD_NEW(state_offset + 1, 0); - break; - } - break; - - /*-----------------------------------------------------------------*/ - case OP_HSPACE: - if (clen > 0) switch(c) - { - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - ADD_NEW(state_offset + 1, 0); - break; - } - break; - - /*-----------------------------------------------------------------*/ - /* Match a negated single character. This is only used for one-byte - characters, that is, we know that d < 256. The character we are - checking (c) can be multibyte. */ - - case OP_NOT: - if (clen > 0) - { - unsigned int otherd = ((ims & PCRE_CASELESS) != 0)? fcc[d] : d; - if (c != d && c != otherd) { ADD_NEW(state_offset + dlen + 1, 0); } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_PLUS: - case OP_MINPLUS: - case OP_POSPLUS: - case OP_NOTPLUS: - case OP_NOTMINPLUS: - case OP_NOTPOSPLUS: - count = current_state->count; /* Already matched */ - if (count > 0) { ADD_ACTIVE(state_offset + dlen + 1, 0); } - if (clen > 0) - { - unsigned int otherd = NOTACHAR; - if ((ims & PCRE_CASELESS) != 0) - { -#ifdef SUPPORT_UTF8 - if (utf8 && d >= 128) - { -#ifdef SUPPORT_UCP - otherd = UCD_OTHERCASE(d); -#endif /* SUPPORT_UCP */ - } - else -#endif /* SUPPORT_UTF8 */ - otherd = fcc[d]; - } - if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR)) - { - if (count > 0 && - (codevalue == OP_POSPLUS || codevalue == OP_NOTPOSPLUS)) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - count++; - ADD_NEW(state_offset, count); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_QUERY: - case OP_MINQUERY: - case OP_POSQUERY: - case OP_NOTQUERY: - case OP_NOTMINQUERY: - case OP_NOTPOSQUERY: - ADD_ACTIVE(state_offset + dlen + 1, 0); - if (clen > 0) - { - unsigned int otherd = NOTACHAR; - if ((ims & PCRE_CASELESS) != 0) - { -#ifdef SUPPORT_UTF8 - if (utf8 && d >= 128) - { -#ifdef SUPPORT_UCP - otherd = UCD_OTHERCASE(d); -#endif /* SUPPORT_UCP */ - } - else -#endif /* SUPPORT_UTF8 */ - otherd = fcc[d]; - } - if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR)) - { - if (codevalue == OP_POSQUERY || codevalue == OP_NOTPOSQUERY) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW(state_offset + dlen + 1, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_STAR: - case OP_MINSTAR: - case OP_POSSTAR: - case OP_NOTSTAR: - case OP_NOTMINSTAR: - case OP_NOTPOSSTAR: - ADD_ACTIVE(state_offset + dlen + 1, 0); - if (clen > 0) - { - unsigned int otherd = NOTACHAR; - if ((ims & PCRE_CASELESS) != 0) - { -#ifdef SUPPORT_UTF8 - if (utf8 && d >= 128) - { -#ifdef SUPPORT_UCP - otherd = UCD_OTHERCASE(d); -#endif /* SUPPORT_UCP */ - } - else -#endif /* SUPPORT_UTF8 */ - otherd = fcc[d]; - } - if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR)) - { - if (codevalue == OP_POSSTAR || codevalue == OP_NOTPOSSTAR) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW(state_offset, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_EXACT: - case OP_NOTEXACT: - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - unsigned int otherd = NOTACHAR; - if ((ims & PCRE_CASELESS) != 0) - { -#ifdef SUPPORT_UTF8 - if (utf8 && d >= 128) - { -#ifdef SUPPORT_UCP - otherd = UCD_OTHERCASE(d); -#endif /* SUPPORT_UCP */ - } - else -#endif /* SUPPORT_UTF8 */ - otherd = fcc[d]; - } - if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR)) - { - if (++count >= GET2(code, 1)) - { ADD_NEW(state_offset + dlen + 3, 0); } - else - { ADD_NEW(state_offset, count); } - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_UPTO: - case OP_MINUPTO: - case OP_POSUPTO: - case OP_NOTUPTO: - case OP_NOTMINUPTO: - case OP_NOTPOSUPTO: - ADD_ACTIVE(state_offset + dlen + 3, 0); - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - unsigned int otherd = NOTACHAR; - if ((ims & PCRE_CASELESS) != 0) - { -#ifdef SUPPORT_UTF8 - if (utf8 && d >= 128) - { -#ifdef SUPPORT_UCP - otherd = UCD_OTHERCASE(d); -#endif /* SUPPORT_UCP */ - } - else -#endif /* SUPPORT_UTF8 */ - otherd = fcc[d]; - } - if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR)) - { - if (codevalue == OP_POSUPTO || codevalue == OP_NOTPOSUPTO) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - if (++count >= GET2(code, 1)) - { ADD_NEW(state_offset + dlen + 3, 0); } - else - { ADD_NEW(state_offset, count); } - } - } - break; - - -/* ========================================================================== */ - /* These are the class-handling opcodes */ - - case OP_CLASS: - case OP_NCLASS: - case OP_XCLASS: - { - BOOL isinclass = FALSE; - int next_state_offset; - const uschar *ecode; - - /* For a simple class, there is always just a 32-byte table, and we - can set isinclass from it. */ - - if (codevalue != OP_XCLASS) - { - ecode = code + 33; - if (clen > 0) - { - isinclass = (c > 255)? (codevalue == OP_NCLASS) : - ((code[1 + c/8] & (1 << (c&7))) != 0); - } - } - - /* An extended class may have a table or a list of single characters, - ranges, or both, and it may be positive or negative. There's a - function that sorts all this out. */ - - else - { - ecode = code + GET(code, 1); - if (clen > 0) isinclass = _pcre_xclass(c, code + 1 + LINK_SIZE); - } - - /* At this point, isinclass is set for all kinds of class, and ecode - points to the byte after the end of the class. If there is a - quantifier, this is where it will be. */ - - next_state_offset = ecode - start_code; - - switch (*ecode) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - ADD_ACTIVE(next_state_offset + 1, 0); - if (isinclass) { ADD_NEW(state_offset, 0); } - break; - - case OP_CRPLUS: - case OP_CRMINPLUS: - count = current_state->count; /* Already matched */ - if (count > 0) { ADD_ACTIVE(next_state_offset + 1, 0); } - if (isinclass) { count++; ADD_NEW(state_offset, count); } - break; - - case OP_CRQUERY: - case OP_CRMINQUERY: - ADD_ACTIVE(next_state_offset + 1, 0); - if (isinclass) { ADD_NEW(next_state_offset + 1, 0); } - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - count = current_state->count; /* Already matched */ - if (count >= GET2(ecode, 1)) - { ADD_ACTIVE(next_state_offset + 5, 0); } - if (isinclass) - { - int max = GET2(ecode, 3); - if (++count >= max && max != 0) /* Max 0 => no limit */ - { ADD_NEW(next_state_offset + 5, 0); } - else - { ADD_NEW(state_offset, count); } - } - break; - - default: - if (isinclass) { ADD_NEW(next_state_offset, 0); } - break; - } - } - break; - -/* ========================================================================== */ - /* These are the opcodes for fancy brackets of various kinds. We have - to use recursion in order to handle them. The "always failing" assersion - (?!) is optimised when compiling to OP_FAIL, so we have to support that, - though the other "backtracking verbs" are not supported. */ - - case OP_FAIL: - break; - - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - { - int rc; - int local_offsets[2]; - int local_workspace[1000]; - const uschar *endasscode = code + GET(code, 1); - - while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1); - - rc = internal_dfa_exec( - md, /* static match data */ - code, /* this subexpression's code */ - ptr, /* where we currently are */ - ptr - start_subject, /* start offset */ - local_offsets, /* offset vector */ - sizeof(local_offsets)/sizeof(int), /* size of same */ - local_workspace, /* workspace vector */ - sizeof(local_workspace)/sizeof(int), /* size of same */ - ims, /* the current ims flags */ - rlevel, /* function recursion level */ - recursing); /* pass on regex recursion */ - - if ((rc >= 0) == (codevalue == OP_ASSERT || codevalue == OP_ASSERTBACK)) - { ADD_ACTIVE(endasscode + LINK_SIZE + 1 - start_code, 0); } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_COND: - case OP_SCOND: - { - int local_offsets[1000]; - int local_workspace[1000]; - int condcode = code[LINK_SIZE+1]; - - /* Back reference conditions are not supported */ - - if (condcode == OP_CREF) return PCRE_ERROR_DFA_UCOND; - - /* The DEFINE condition is always false */ - - if (condcode == OP_DEF) - { - ADD_ACTIVE(state_offset + GET(code, 1) + LINK_SIZE + 1, 0); - } - - /* The only supported version of OP_RREF is for the value RREF_ANY, - which means "test if in any recursion". We can't test for specifically - recursed groups. */ - - else if (condcode == OP_RREF) - { - int value = GET2(code, LINK_SIZE+2); - if (value != RREF_ANY) return PCRE_ERROR_DFA_UCOND; - if (recursing > 0) { ADD_ACTIVE(state_offset + LINK_SIZE + 4, 0); } - else { ADD_ACTIVE(state_offset + GET(code, 1) + LINK_SIZE + 1, 0); } - } - - /* Otherwise, the condition is an assertion */ - - else - { - int rc; - const uschar *asscode = code + LINK_SIZE + 1; - const uschar *endasscode = asscode + GET(asscode, 1); - - while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1); - - rc = internal_dfa_exec( - md, /* fixed match data */ - asscode, /* this subexpression's code */ - ptr, /* where we currently are */ - ptr - start_subject, /* start offset */ - local_offsets, /* offset vector */ - sizeof(local_offsets)/sizeof(int), /* size of same */ - local_workspace, /* workspace vector */ - sizeof(local_workspace)/sizeof(int), /* size of same */ - ims, /* the current ims flags */ - rlevel, /* function recursion level */ - recursing); /* pass on regex recursion */ - - if ((rc >= 0) == - (condcode == OP_ASSERT || condcode == OP_ASSERTBACK)) - { ADD_ACTIVE(endasscode + LINK_SIZE + 1 - start_code, 0); } - else - { ADD_ACTIVE(state_offset + GET(code, 1) + LINK_SIZE + 1, 0); } - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_RECURSE: - { - int local_offsets[1000]; - int local_workspace[1000]; - int rc; - - DPRINTF(("%.*sStarting regex recursion %d\n", rlevel*2-2, SP, - recursing + 1)); - - rc = internal_dfa_exec( - md, /* fixed match data */ - start_code + GET(code, 1), /* this subexpression's code */ - ptr, /* where we currently are */ - ptr - start_subject, /* start offset */ - local_offsets, /* offset vector */ - sizeof(local_offsets)/sizeof(int), /* size of same */ - local_workspace, /* workspace vector */ - sizeof(local_workspace)/sizeof(int), /* size of same */ - ims, /* the current ims flags */ - rlevel, /* function recursion level */ - recursing + 1); /* regex recurse level */ - - DPRINTF(("%.*sReturn from regex recursion %d: rc=%d\n", rlevel*2-2, SP, - recursing + 1, rc)); - - /* Ran out of internal offsets */ - - if (rc == 0) return PCRE_ERROR_DFA_RECURSE; - - /* For each successful matched substring, set up the next state with a - count of characters to skip before trying it. Note that the count is in - characters, not bytes. */ - - if (rc > 0) - { - for (rc = rc*2 - 2; rc >= 0; rc -= 2) - { - const uschar *p = start_subject + local_offsets[rc]; - const uschar *pp = start_subject + local_offsets[rc+1]; - int charcount = local_offsets[rc+1] - local_offsets[rc]; - while (p < pp) if ((*p++ & 0xc0) == 0x80) charcount--; - if (charcount > 0) - { - ADD_NEW_DATA(-(state_offset + LINK_SIZE + 1), 0, (charcount - 1)); - } - else - { - ADD_ACTIVE(state_offset + LINK_SIZE + 1, 0); - } - } - } - else if (rc != PCRE_ERROR_NOMATCH) return rc; - } - break; - - /*-----------------------------------------------------------------*/ - case OP_ONCE: - { - int local_offsets[2]; - int local_workspace[1000]; - - int rc = internal_dfa_exec( - md, /* fixed match data */ - code, /* this subexpression's code */ - ptr, /* where we currently are */ - ptr - start_subject, /* start offset */ - local_offsets, /* offset vector */ - sizeof(local_offsets)/sizeof(int), /* size of same */ - local_workspace, /* workspace vector */ - sizeof(local_workspace)/sizeof(int), /* size of same */ - ims, /* the current ims flags */ - rlevel, /* function recursion level */ - recursing); /* pass on regex recursion */ - - if (rc >= 0) - { - const uschar *end_subpattern = code; - int charcount = local_offsets[1] - local_offsets[0]; - int next_state_offset, repeat_state_offset; - - do { end_subpattern += GET(end_subpattern, 1); } - while (*end_subpattern == OP_ALT); - next_state_offset = end_subpattern - start_code + LINK_SIZE + 1; - - /* If the end of this subpattern is KETRMAX or KETRMIN, we must - arrange for the repeat state also to be added to the relevant list. - Calculate the offset, or set -1 for no repeat. */ - - repeat_state_offset = (*end_subpattern == OP_KETRMAX || - *end_subpattern == OP_KETRMIN)? - end_subpattern - start_code - GET(end_subpattern, 1) : -1; - - /* If we have matched an empty string, add the next state at the - current character pointer. This is important so that the duplicate - checking kicks in, which is what breaks infinite loops that match an - empty string. */ - - if (charcount == 0) - { - ADD_ACTIVE(next_state_offset, 0); - } - - /* Optimization: if there are no more active states, and there - are no new states yet set up, then skip over the subject string - right here, to save looping. Otherwise, set up the new state to swing - into action when the end of the substring is reached. */ - - else if (i + 1 >= active_count && new_count == 0) - { - ptr += charcount; - clen = 0; - ADD_NEW(next_state_offset, 0); - - /* If we are adding a repeat state at the new character position, - we must fudge things so that it is the only current state. - Otherwise, it might be a duplicate of one we processed before, and - that would cause it to be skipped. */ - - if (repeat_state_offset >= 0) - { - next_active_state = active_states; - active_count = 0; - i = -1; - ADD_ACTIVE(repeat_state_offset, 0); - } - } - else - { - const uschar *p = start_subject + local_offsets[0]; - const uschar *pp = start_subject + local_offsets[1]; - while (p < pp) if ((*p++ & 0xc0) == 0x80) charcount--; - ADD_NEW_DATA(-next_state_offset, 0, (charcount - 1)); - if (repeat_state_offset >= 0) - { ADD_NEW_DATA(-repeat_state_offset, 0, (charcount - 1)); } - } - - } - else if (rc != PCRE_ERROR_NOMATCH) return rc; - } - break; - - -/* ========================================================================== */ - /* Handle callouts */ - - case OP_CALLOUT: - if (pcre_callout != NULL) - { - int rrc; - pcre_callout_block cb; - cb.version = 1; /* Version 1 of the callout block */ - cb.callout_number = code[1]; - cb.offset_vector = offsets; - cb.subject = (PCRE_SPTR)start_subject; - cb.subject_length = end_subject - start_subject; - cb.start_match = current_subject - start_subject; - cb.current_position = ptr - start_subject; - cb.pattern_position = GET(code, 2); - cb.next_item_length = GET(code, 2 + LINK_SIZE); - cb.capture_top = 1; - cb.capture_last = -1; - cb.callout_data = md->callout_data; - if ((rrc = (*pcre_callout)(&cb)) < 0) return rrc; /* Abandon */ - if (rrc == 0) { ADD_ACTIVE(state_offset + 2 + 2*LINK_SIZE, 0); } - } - break; - - -/* ========================================================================== */ - default: /* Unsupported opcode */ - return PCRE_ERROR_DFA_UITEM; - } - - NEXT_ACTIVE_STATE: continue; - - } /* End of loop scanning active states */ - - /* We have finished the processing at the current subject character. If no - new states have been set for the next character, we have found all the - matches that we are going to find. If we are at the top level and partial - matching has been requested, check for appropriate conditions. */ - - if (new_count <= 0) - { - if (match_count < 0 && /* No matches found */ - rlevel == 1 && /* Top level match function */ - (md->moptions & PCRE_PARTIAL) != 0 && /* Want partial matching */ - ptr >= end_subject && /* Reached end of subject */ - ptr > current_subject) /* Matched non-empty string */ - { - if (offsetcount >= 2) - { - offsets[0] = current_subject - start_subject; - offsets[1] = end_subject - start_subject; - } - match_count = PCRE_ERROR_PARTIAL; - } - - DPRINTF(("%.*sEnd of internal_dfa_exec %d: returning %d\n" - "%.*s---------------------\n\n", rlevel*2-2, SP, rlevel, match_count, - rlevel*2-2, SP)); - break; /* In effect, "return", but see the comment below */ - } - - /* One or more states are active for the next character. */ - - ptr += clen; /* Advance to next subject character */ - } /* Loop to move along the subject string */ - -/* Control gets here from "break" a few lines above. We do it this way because -if we use "return" above, we have compiler trouble. Some compilers warn if -there's nothing here because they think the function doesn't return a value. On -the other hand, if we put a dummy statement here, some more clever compilers -complain that it can't be reached. Sigh. */ - -return match_count; -} - - - - -/************************************************* -* Execute a Regular Expression - DFA engine * -*************************************************/ - -/* This external function applies a compiled re to a subject string using a DFA -engine. This function calls the internal function multiple times if the pattern -is not anchored. - -Arguments: - argument_re points to the compiled expression - extra_data points to extra data or is NULL - subject points to the subject string - length length of subject string (may contain binary zeros) - start_offset where to start in the subject string - options option bits - offsets vector of match offsets - offsetcount size of same - workspace workspace vector - wscount size of same - -Returns: > 0 => number of match offset pairs placed in offsets - = 0 => offsets overflowed; longest matches are present - -1 => failed to match - < -1 => some kind of unexpected problem -*/ - -PCRE_EXP_DEFN int PCRE_CALL_CONVENTION -pcre_dfa_exec(const pcre *argument_re, const pcre_extra *extra_data, - const char *subject, int length, int start_offset, int options, int *offsets, - int offsetcount, int *workspace, int wscount) -{ -real_pcre *re = (real_pcre *)argument_re; -dfa_match_data match_block; -dfa_match_data *md = &match_block; -BOOL utf8, anchored, startline, firstline; -const uschar *current_subject, *end_subject, *lcc; - -pcre_study_data internal_study; -const pcre_study_data *study = NULL; -real_pcre internal_re; - -const uschar *req_byte_ptr; -const uschar *start_bits = NULL; -BOOL first_byte_caseless = FALSE; -BOOL req_byte_caseless = FALSE; -int first_byte = -1; -int req_byte = -1; -int req_byte2 = -1; -int newline; - -/* Plausibility checks */ - -if ((options & ~PUBLIC_DFA_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION; -if (re == NULL || subject == NULL || workspace == NULL || - (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL; -if (offsetcount < 0) return PCRE_ERROR_BADCOUNT; -if (wscount < 20) return PCRE_ERROR_DFA_WSSIZE; - -/* We need to find the pointer to any study data before we test for byte -flipping, so we scan the extra_data block first. This may set two fields in the -match block, so we must initialize them beforehand. However, the other fields -in the match block must not be set until after the byte flipping. */ - -md->tables = re->tables; -md->callout_data = NULL; - -if (extra_data != NULL) - { - unsigned int flags = extra_data->flags; - if ((flags & PCRE_EXTRA_STUDY_DATA) != 0) - study = (const pcre_study_data *)extra_data->study_data; - if ((flags & PCRE_EXTRA_MATCH_LIMIT) != 0) return PCRE_ERROR_DFA_UMLIMIT; - if ((flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION) != 0) - return PCRE_ERROR_DFA_UMLIMIT; - if ((flags & PCRE_EXTRA_CALLOUT_DATA) != 0) - md->callout_data = extra_data->callout_data; - if ((flags & PCRE_EXTRA_TABLES) != 0) - md->tables = extra_data->tables; - } - -/* Check that the first field in the block is the magic number. If it is not, -test for a regex that was compiled on a host of opposite endianness. If this is -the case, flipped values are put in internal_re and internal_study if there was -study data too. */ - -if (re->magic_number != MAGIC_NUMBER) - { - re = _pcre_try_flipped(re, &internal_re, study, &internal_study); - if (re == NULL) return PCRE_ERROR_BADMAGIC; - if (study != NULL) study = &internal_study; - } - -/* Set some local values */ - -current_subject = (const unsigned char *)subject + start_offset; -end_subject = (const unsigned char *)subject + length; -req_byte_ptr = current_subject - 1; - -#ifdef SUPPORT_UTF8 -utf8 = (re->options & PCRE_UTF8) != 0; -#else -utf8 = FALSE; -#endif - -anchored = (options & (PCRE_ANCHORED|PCRE_DFA_RESTART)) != 0 || - (re->options & PCRE_ANCHORED) != 0; - -/* The remaining fixed data for passing around. */ - -md->start_code = (const uschar *)argument_re + - re->name_table_offset + re->name_count * re->name_entry_size; -md->start_subject = (const unsigned char *)subject; -md->end_subject = end_subject; -md->moptions = options; -md->poptions = re->options; - -/* If the BSR option is not set at match time, copy what was set -at compile time. */ - -if ((md->moptions & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) == 0) - { - if ((re->options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) != 0) - md->moptions |= re->options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE); -#ifdef BSR_ANYCRLF - else md->moptions |= PCRE_BSR_ANYCRLF; -#endif - } - -/* Handle different types of newline. The three bits give eight cases. If -nothing is set at run time, whatever was used at compile time applies. */ - -switch ((((options & PCRE_NEWLINE_BITS) == 0)? re->options : (pcre_uint32)options) & - PCRE_NEWLINE_BITS) - { - case 0: newline = NEWLINE; break; /* Compile-time default */ - case PCRE_NEWLINE_CR: newline = '\r'; break; - case PCRE_NEWLINE_LF: newline = '\n'; break; - case PCRE_NEWLINE_CR+ - PCRE_NEWLINE_LF: newline = ('\r' << 8) | '\n'; break; - case PCRE_NEWLINE_ANY: newline = -1; break; - case PCRE_NEWLINE_ANYCRLF: newline = -2; break; - default: return PCRE_ERROR_BADNEWLINE; - } - -if (newline == -2) - { - md->nltype = NLTYPE_ANYCRLF; - } -else if (newline < 0) - { - md->nltype = NLTYPE_ANY; - } -else - { - md->nltype = NLTYPE_FIXED; - if (newline > 255) - { - md->nllen = 2; - md->nl[0] = (newline >> 8) & 255; - md->nl[1] = newline & 255; - } - else - { - md->nllen = 1; - md->nl[0] = newline; - } - } - -/* Check a UTF-8 string if required. Unfortunately there's no way of passing -back the character offset. */ - -#ifdef SUPPORT_UTF8 -if (utf8 && (options & PCRE_NO_UTF8_CHECK) == 0) - { - if (_pcre_valid_utf8((uschar *)subject, length) >= 0) - return PCRE_ERROR_BADUTF8; - if (start_offset > 0 && start_offset < length) - { - int tb = ((uschar *)subject)[start_offset]; - if (tb > 127) - { - tb &= 0xc0; - if (tb != 0 && tb != 0xc0) return PCRE_ERROR_BADUTF8_OFFSET; - } - } - } -#endif - -/* If the exec call supplied NULL for tables, use the inbuilt ones. This -is a feature that makes it possible to save compiled regex and re-use them -in other programs later. */ - -if (md->tables == NULL) md->tables = _pcre_default_tables; - -/* The lower casing table and the "must be at the start of a line" flag are -used in a loop when finding where to start. */ - -lcc = md->tables + lcc_offset; -startline = (re->flags & PCRE_STARTLINE) != 0; -firstline = (re->options & PCRE_FIRSTLINE) != 0; - -/* Set up the first character to match, if available. The first_byte value is -never set for an anchored regular expression, but the anchoring may be forced -at run time, so we have to test for anchoring. The first char may be unset for -an unanchored pattern, of course. If there's no first char and the pattern was -studied, there may be a bitmap of possible first characters. */ - -if (!anchored) - { - if ((re->flags & PCRE_FIRSTSET) != 0) - { - first_byte = re->first_byte & 255; - if ((first_byte_caseless = ((re->first_byte & REQ_CASELESS) != 0)) == TRUE) - first_byte = lcc[first_byte]; - } - else - { - if (startline && study != NULL && - (study->options & PCRE_STUDY_MAPPED) != 0) - start_bits = study->start_bits; - } - } - -/* For anchored or unanchored matches, there may be a "last known required -character" set. */ - -if ((re->flags & PCRE_REQCHSET) != 0) - { - req_byte = re->req_byte & 255; - req_byte_caseless = (re->req_byte & REQ_CASELESS) != 0; - req_byte2 = (md->tables + fcc_offset)[req_byte]; /* case flipped */ - } - -/* Call the main matching function, looping for a non-anchored regex after a -failed match. Unless restarting, optimize by moving to the first match -character if possible, when not anchored. Then unless wanting a partial match, -check for a required later character. */ - -for (;;) - { - int rc; - - if ((options & PCRE_DFA_RESTART) == 0) - { - const uschar *save_end_subject = end_subject; - - /* Advance to a unique first char if possible. If firstline is TRUE, the - start of the match is constrained to the first line of a multiline string. - Implement this by temporarily adjusting end_subject so that we stop - scanning at a newline. If the match fails at the newline, later code breaks - this loop. */ - - if (firstline) - { - USPTR t = current_subject; -#ifdef SUPPORT_UTF8 - if (utf8) - { - while (t < md->end_subject && !IS_NEWLINE(t)) - { - t++; - while (t < end_subject && (*t & 0xc0) == 0x80) t++; - } - } - else -#endif - while (t < md->end_subject && !IS_NEWLINE(t)) t++; - end_subject = t; - } - - if (first_byte >= 0) - { - if (first_byte_caseless) - while (current_subject < end_subject && - lcc[*current_subject] != first_byte) - current_subject++; - else - while (current_subject < end_subject && *current_subject != first_byte) - current_subject++; - } - - /* Or to just after a linebreak for a multiline match if possible */ - - else if (startline) - { - if (current_subject > md->start_subject + start_offset) - { -#ifdef SUPPORT_UTF8 - if (utf8) - { - while (current_subject < end_subject && !WAS_NEWLINE(current_subject)) - { - current_subject++; - while(current_subject < end_subject && - (*current_subject & 0xc0) == 0x80) - current_subject++; - } - } - else -#endif - while (current_subject < end_subject && !WAS_NEWLINE(current_subject)) - current_subject++; - - /* If we have just passed a CR and the newline option is ANY or - ANYCRLF, and we are now at a LF, advance the match position by one more - character. */ - - if (current_subject[-1] == '\r' && - (md->nltype == NLTYPE_ANY || md->nltype == NLTYPE_ANYCRLF) && - current_subject < end_subject && - *current_subject == '\n') - current_subject++; - } - } - - /* Or to a non-unique first char after study */ - - else if (start_bits != NULL) - { - while (current_subject < end_subject) - { - register unsigned int c = *current_subject; - if ((start_bits[c/8] & (1 << (c&7))) == 0) current_subject++; - else break; - } - } - - /* Restore fudged end_subject */ - - end_subject = save_end_subject; - } - - /* If req_byte is set, we know that that character must appear in the subject - for the match to succeed. If the first character is set, req_byte must be - later in the subject; otherwise the test starts at the match point. This - optimization can save a huge amount of work in patterns with nested unlimited - repeats that aren't going to match. Writing separate code for cased/caseless - versions makes it go faster, as does using an autoincrement and backing off - on a match. - - HOWEVER: when the subject string is very, very long, searching to its end can - take a long time, and give bad performance on quite ordinary patterns. This - showed up when somebody was matching /^C/ on a 32-megabyte string... so we - don't do this when the string is sufficiently long. - - ALSO: this processing is disabled when partial matching is requested. - */ - - if (req_byte >= 0 && - end_subject - current_subject < REQ_BYTE_MAX && - (options & PCRE_PARTIAL) == 0) - { - register const uschar *p = current_subject + ((first_byte >= 0)? 1 : 0); - - /* We don't need to repeat the search if we haven't yet reached the - place we found it at last time. */ - - if (p > req_byte_ptr) - { - if (req_byte_caseless) - { - while (p < end_subject) - { - register int pp = *p++; - if (pp == req_byte || pp == req_byte2) { p--; break; } - } - } - else - { - while (p < end_subject) - { - if (*p++ == req_byte) { p--; break; } - } - } - - /* If we can't find the required character, break the matching loop, - which will cause a return or PCRE_ERROR_NOMATCH. */ - - if (p >= end_subject) break; - - /* If we have found the required character, save the point where we - found it, so that we don't search again next time round the loop if - the start hasn't passed this character yet. */ - - req_byte_ptr = p; - } - } - - /* OK, now we can do the business */ - - rc = internal_dfa_exec( - md, /* fixed match data */ - md->start_code, /* this subexpression's code */ - current_subject, /* where we currently are */ - start_offset, /* start offset in subject */ - offsets, /* offset vector */ - offsetcount, /* size of same */ - workspace, /* workspace vector */ - wscount, /* size of same */ - re->options & (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL), /* ims flags */ - 0, /* function recurse level */ - 0); /* regex recurse level */ - - /* Anything other than "no match" means we are done, always; otherwise, carry - on only if not anchored. */ - - if (rc != PCRE_ERROR_NOMATCH || anchored) return rc; - - /* Advance to the next subject character unless we are at the end of a line - and firstline is set. */ - - if (firstline && IS_NEWLINE(current_subject)) break; - current_subject++; - if (utf8) - { - while (current_subject < end_subject && (*current_subject & 0xc0) == 0x80) - current_subject++; - } - if (current_subject > end_subject) break; - - /* If we have just passed a CR and we are now at a LF, and the pattern does - not contain any explicit matches for \r or \n, and the newline option is CRLF - or ANY or ANYCRLF, advance the match position by one more character. */ - - if (current_subject[-1] == '\r' && - current_subject < end_subject && - *current_subject == '\n' && - (re->flags & PCRE_HASCRORLF) == 0 && - (md->nltype == NLTYPE_ANY || - md->nltype == NLTYPE_ANYCRLF || - md->nllen == 2)) - current_subject++; - - } /* "Bumpalong" loop */ - -return PCRE_ERROR_NOMATCH; -} - -/* End of pcre_dfa_exec.c */ diff --git a/glib/pcre/pcre_exec.c b/glib/pcre/pcre_exec.c deleted file mode 100644 index 06ce8f70e..000000000 --- a/glib/pcre/pcre_exec.c +++ /dev/null @@ -1,4998 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains pcre_exec(), the externally visible function that does -pattern matching using an NFA algorithm, trying to mimic Perl as closely as -possible. There are also some static supporting functions. */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define NLBLOCK md /* Block containing newline information */ -#define PSSTART start_subject /* Field containing processed string start */ -#define PSEND end_subject /* Field containing processed string end */ - -#include "pcre_internal.h" - -/* Undefine some potentially clashing cpp symbols */ - -#undef min -#undef max - -/* Flag bits for the match() function */ - -#define match_condassert 0x01 /* Called to check a condition assertion */ -#define match_cbegroup 0x02 /* Could-be-empty unlimited repeat group */ - -/* Non-error returns from the match() function. Error returns are externally -defined PCRE_ERROR_xxx codes, which are all negative. */ - -#define MATCH_MATCH 1 -#define MATCH_NOMATCH 0 - -/* Special internal returns from the match() function. Make them sufficiently -negative to avoid the external error codes. */ - -#define MATCH_COMMIT (-999) -#define MATCH_PRUNE (-998) -#define MATCH_SKIP (-997) -#define MATCH_THEN (-996) - -/* Maximum number of ints of offset to save on the stack for recursive calls. -If the offset vector is bigger, malloc is used. This should be a multiple of 3, -because the offset vector is always a multiple of 3 long. */ - -#define REC_STACK_SAVE_MAX 30 - -/* Min and max values for the common repeats; for the maxima, 0 => infinity */ - -static const char rep_min[] = { 0, 0, 1, 1, 0, 0 }; -static const char rep_max[] = { 0, 0, 0, 0, 1, 1 }; - - - -#ifdef DEBUG -/************************************************* -* Debugging function to print chars * -*************************************************/ - -/* Print a sequence of chars in printable format, stopping at the end of the -subject if the requested. - -Arguments: - p points to characters - length number to print - is_subject TRUE if printing from within md->start_subject - md pointer to matching data block, if is_subject is TRUE - -Returns: nothing -*/ - -static void -pchars(const uschar *p, int length, BOOL is_subject, match_data *md) -{ -unsigned int c; -if (is_subject && length > md->end_subject - p) length = md->end_subject - p; -while (length-- > 0) - if (isprint(c = *(p++))) printf("%c", c); else printf("\\x%02x", c); -} -#endif - - - -/************************************************* -* Match a back-reference * -*************************************************/ - -/* If a back reference hasn't been set, the length that is passed is greater -than the number of characters left in the string, so the match fails. - -Arguments: - offset index into the offset vector - eptr points into the subject - length length to be matched - md points to match data block - ims the ims flags - -Returns: TRUE if matched -*/ - -static BOOL -match_ref(int offset, register USPTR eptr, int length, match_data *md, - unsigned long int ims) -{ -USPTR p = md->start_subject + md->offset_vector[offset]; - -#ifdef DEBUG -if (eptr >= md->end_subject) - printf("matching subject <null>"); -else - { - printf("matching subject "); - pchars(eptr, length, TRUE, md); - } -printf(" against backref "); -pchars(p, length, FALSE, md); -printf("\n"); -#endif - -/* Always fail if not enough characters left */ - -if (length > md->end_subject - eptr) return FALSE; - -/* Separate the caseless case for speed. In UTF-8 mode we can only do this -properly if Unicode properties are supported. Otherwise, we can check only -ASCII characters. */ - -if ((ims & PCRE_CASELESS) != 0) - { -#ifdef SUPPORT_UTF8 -#ifdef SUPPORT_UCP - if (md->utf8) - { - USPTR endptr = eptr + length; - while (eptr < endptr) - { - int c, d; - GETCHARINC(c, eptr); - GETCHARINC(d, p); - if (c != d && c != UCD_OTHERCASE(d)) return FALSE; - } - } - else -#endif -#endif - - /* The same code works when not in UTF-8 mode and in UTF-8 mode when there - is no UCP support. */ - - while (length-- > 0) - { if (md->lcc[*p++] != md->lcc[*eptr++]) return FALSE; } - } - -/* In the caseful case, we can just compare the bytes, whether or not we -are in UTF-8 mode. */ - -else - { while (length-- > 0) if (*p++ != *eptr++) return FALSE; } - -return TRUE; -} - - - -/*************************************************************************** -**************************************************************************** - RECURSION IN THE match() FUNCTION - -The match() function is highly recursive, though not every recursive call -increases the recursive depth. Nevertheless, some regular expressions can cause -it to recurse to a great depth. I was writing for Unix, so I just let it call -itself recursively. This uses the stack for saving everything that has to be -saved for a recursive call. On Unix, the stack can be large, and this works -fine. - -It turns out that on some non-Unix-like systems there are problems with -programs that use a lot of stack. (This despite the fact that every last chip -has oodles of memory these days, and techniques for extending the stack have -been known for decades.) So.... - -There is a fudge, triggered by defining NO_RECURSE, which avoids recursive -calls by keeping local variables that need to be preserved in blocks of memory -obtained from malloc() instead instead of on the stack. Macros are used to -achieve this so that the actual code doesn't look very different to what it -always used to. - -The original heap-recursive code used longjmp(). However, it seems that this -can be very slow on some operating systems. Following a suggestion from Stan -Switzer, the use of longjmp() has been abolished, at the cost of having to -provide a unique number for each call to RMATCH. There is no way of generating -a sequence of numbers at compile time in C. I have given them names, to make -them stand out more clearly. - -Crude tests on x86 Linux show a small speedup of around 5-8%. However, on -FreeBSD, avoiding longjmp() more than halves the time taken to run the standard -tests. Furthermore, not using longjmp() means that local dynamic variables -don't have indeterminate values; this has meant that the frame size can be -reduced because the result can be "passed back" by straight setting of the -variable instead of being passed in the frame. -**************************************************************************** -***************************************************************************/ - -/* Numbers for RMATCH calls. When this list is changed, the code at HEAP_RETURN -below must be updated in sync. */ - -enum { RM1=1, RM2, RM3, RM4, RM5, RM6, RM7, RM8, RM9, RM10, - RM11, RM12, RM13, RM14, RM15, RM16, RM17, RM18, RM19, RM20, - RM21, RM22, RM23, RM24, RM25, RM26, RM27, RM28, RM29, RM30, - RM31, RM32, RM33, RM34, RM35, RM36, RM37, RM38, RM39, RM40, - RM41, RM42, RM43, RM44, RM45, RM46, RM47, RM48, RM49, RM50, - RM51, RM52, RM53, RM54 }; - -/* These versions of the macros use the stack, as normal. There are debugging -versions and production versions. Note that the "rw" argument of RMATCH isn't -actuall used in this definition. */ - -#ifndef NO_RECURSE -#define REGISTER register - -#ifdef DEBUG -#define RMATCH(ra,rb,rc,rd,re,rf,rg,rw) \ - { \ - printf("match() called in line %d\n", __LINE__); \ - rrc = match(ra,rb,mstart,rc,rd,re,rf,rg,rdepth+1); \ - printf("to line %d\n", __LINE__); \ - } -#define RRETURN(ra) \ - { \ - printf("match() returned %d from line %d ", ra, __LINE__); \ - return ra; \ - } -#else -#define RMATCH(ra,rb,rc,rd,re,rf,rg,rw) \ - rrc = match(ra,rb,mstart,rc,rd,re,rf,rg,rdepth+1) -#define RRETURN(ra) return ra -#endif - -#else - - -/* These versions of the macros manage a private stack on the heap. Note that -the "rd" argument of RMATCH isn't actually used in this definition. It's the md -argument of match(), which never changes. */ - -#define REGISTER - -#define RMATCH(ra,rb,rc,rd,re,rf,rg,rw)\ - {\ - heapframe *newframe = (pcre_stack_malloc)(sizeof(heapframe));\ - frame->Xwhere = rw; \ - newframe->Xeptr = ra;\ - newframe->Xecode = rb;\ - newframe->Xmstart = mstart;\ - newframe->Xoffset_top = rc;\ - newframe->Xims = re;\ - newframe->Xeptrb = rf;\ - newframe->Xflags = rg;\ - newframe->Xrdepth = frame->Xrdepth + 1;\ - newframe->Xprevframe = frame;\ - frame = newframe;\ - DPRINTF(("restarting from line %d\n", __LINE__));\ - goto HEAP_RECURSE;\ - L_##rw:\ - DPRINTF(("jumped back to line %d\n", __LINE__));\ - } - -#define RRETURN(ra)\ - {\ - heapframe *newframe = frame;\ - frame = newframe->Xprevframe;\ - (pcre_stack_free)(newframe);\ - if (frame != NULL)\ - {\ - rrc = ra;\ - goto HEAP_RETURN;\ - }\ - return ra;\ - } - - -/* Structure for remembering the local variables in a private frame */ - -typedef struct heapframe { - struct heapframe *Xprevframe; - - /* Function arguments that may change */ - - const uschar *Xeptr; - const uschar *Xecode; - const uschar *Xmstart; - int Xoffset_top; - long int Xims; - eptrblock *Xeptrb; - int Xflags; - unsigned int Xrdepth; - - /* Function local variables */ - - const uschar *Xcallpat; - const uschar *Xcharptr; - const uschar *Xdata; - const uschar *Xnext; - const uschar *Xpp; - const uschar *Xprev; - const uschar *Xsaved_eptr; - - recursion_info Xnew_recursive; - - BOOL Xcur_is_word; - BOOL Xcondition; - BOOL Xprev_is_word; - - unsigned long int Xoriginal_ims; - -#ifdef SUPPORT_UCP - int Xprop_type; - int Xprop_value; - int Xprop_fail_result; - int Xprop_category; - int Xprop_chartype; - int Xprop_script; - int Xoclength; - uschar Xocchars[8]; -#endif - - int Xctype; - unsigned int Xfc; - int Xfi; - int Xlength; - int Xmax; - int Xmin; - int Xnumber; - int Xoffset; - int Xop; - int Xsave_capture_last; - int Xsave_offset1, Xsave_offset2, Xsave_offset3; - int Xstacksave[REC_STACK_SAVE_MAX]; - - eptrblock Xnewptrb; - - /* Where to jump back to */ - - int Xwhere; - -} heapframe; - -#endif - - -/*************************************************************************** -***************************************************************************/ - - - -/************************************************* -* Match from current position * -*************************************************/ - -/* This function is called recursively in many circumstances. Whenever it -returns a negative (error) response, the outer incarnation must also return the -same response. - -Performance note: It might be tempting to extract commonly used fields from the -md structure (e.g. utf8, end_subject) into individual variables to improve -performance. Tests using gcc on a SPARC disproved this; in the first case, it -made performance worse. - -Arguments: - eptr pointer to current character in subject - ecode pointer to current position in compiled code - mstart pointer to the current match start position (can be modified - by encountering \K) - offset_top current top pointer - md pointer to "static" info for the match - ims current /i, /m, and /s options - eptrb pointer to chain of blocks containing eptr at start of - brackets - for testing for empty matches - flags can contain - match_condassert - this is an assertion condition - match_cbegroup - this is the start of an unlimited repeat - group that can match an empty string - rdepth the recursion depth - -Returns: MATCH_MATCH if matched ) these values are >= 0 - MATCH_NOMATCH if failed to match ) - a negative PCRE_ERROR_xxx value if aborted by an error condition - (e.g. stopped by repeated call or recursion limit) -*/ - -static int -match(REGISTER USPTR eptr, REGISTER const uschar *ecode, const uschar *mstart, - int offset_top, match_data *md, unsigned long int ims, eptrblock *eptrb, - int flags, unsigned int rdepth) -{ -/* These variables do not need to be preserved over recursion in this function, -so they can be ordinary variables in all cases. Mark some of them with -"register" because they are used a lot in loops. */ - -register int rrc; /* Returns from recursive calls */ -register int i; /* Used for loops not involving calls to RMATCH() */ -register unsigned int c; /* Character values not kept over RMATCH() calls */ -register BOOL utf8; /* Local copy of UTF-8 flag for speed */ - -BOOL minimize, possessive; /* Quantifier options */ - -/* When recursion is not being used, all "local" variables that have to be -preserved over calls to RMATCH() are part of a "frame" which is obtained from -heap storage. Set up the top-level frame here; others are obtained from the -heap whenever RMATCH() does a "recursion". See the macro definitions above. */ - -#ifdef NO_RECURSE -heapframe *frame = (pcre_stack_malloc)(sizeof(heapframe)); -frame->Xprevframe = NULL; /* Marks the top level */ - -/* Copy in the original argument variables */ - -frame->Xeptr = eptr; -frame->Xecode = ecode; -frame->Xmstart = mstart; -frame->Xoffset_top = offset_top; -frame->Xims = ims; -frame->Xeptrb = eptrb; -frame->Xflags = flags; -frame->Xrdepth = rdepth; - -/* This is where control jumps back to to effect "recursion" */ - -HEAP_RECURSE: - -/* Macros make the argument variables come from the current frame */ - -#define eptr frame->Xeptr -#define ecode frame->Xecode -#define mstart frame->Xmstart -#define offset_top frame->Xoffset_top -#define ims frame->Xims -#define eptrb frame->Xeptrb -#define flags frame->Xflags -#define rdepth frame->Xrdepth - -/* Ditto for the local variables */ - -#ifdef SUPPORT_UTF8 -#define charptr frame->Xcharptr -#endif -#define callpat frame->Xcallpat -#define data frame->Xdata -#define next frame->Xnext -#define pp frame->Xpp -#define prev frame->Xprev -#define saved_eptr frame->Xsaved_eptr - -#define new_recursive frame->Xnew_recursive - -#define cur_is_word frame->Xcur_is_word -#define condition frame->Xcondition -#define prev_is_word frame->Xprev_is_word - -#define original_ims frame->Xoriginal_ims - -#ifdef SUPPORT_UCP -#define prop_type frame->Xprop_type -#define prop_value frame->Xprop_value -#define prop_fail_result frame->Xprop_fail_result -#define prop_category frame->Xprop_category -#define prop_chartype frame->Xprop_chartype -#define prop_script frame->Xprop_script -#define oclength frame->Xoclength -#define occhars frame->Xocchars -#endif - -#define ctype frame->Xctype -#define fc frame->Xfc -#define fi frame->Xfi -#define length frame->Xlength -#define max frame->Xmax -#define min frame->Xmin -#define number frame->Xnumber -#define offset frame->Xoffset -#define op frame->Xop -#define save_capture_last frame->Xsave_capture_last -#define save_offset1 frame->Xsave_offset1 -#define save_offset2 frame->Xsave_offset2 -#define save_offset3 frame->Xsave_offset3 -#define stacksave frame->Xstacksave - -#define newptrb frame->Xnewptrb - -/* When recursion is being used, local variables are allocated on the stack and -get preserved during recursion in the normal way. In this environment, fi and -i, and fc and c, can be the same variables. */ - -#else /* NO_RECURSE not defined */ -#define fi i -#define fc c - - -#ifdef SUPPORT_UTF8 /* Many of these variables are used only */ -const uschar *charptr; /* in small blocks of the code. My normal */ -#endif /* style of coding would have declared */ -const uschar *callpat; /* them within each of those blocks. */ -const uschar *data; /* However, in order to accommodate the */ -const uschar *next; /* version of this code that uses an */ -USPTR pp; /* external "stack" implemented on the */ -const uschar *prev; /* heap, it is easier to declare them all */ -USPTR saved_eptr; /* here, so the declarations can be cut */ - /* out in a block. The only declarations */ -recursion_info new_recursive; /* within blocks below are for variables */ - /* that do not have to be preserved over */ -BOOL cur_is_word; /* a recursive call to RMATCH(). */ -BOOL condition; -BOOL prev_is_word; - -unsigned long int original_ims; - -#ifdef SUPPORT_UCP -int prop_type; -int prop_value; -int prop_fail_result; -int prop_category; -int prop_chartype; -int prop_script; -int oclength; -uschar occhars[8]; -#endif - -int ctype; -int length; -int max; -int min; -int number; -int offset; -int op; -int save_capture_last; -int save_offset1, save_offset2, save_offset3; -int stacksave[REC_STACK_SAVE_MAX]; - -eptrblock newptrb; -#endif /* NO_RECURSE */ - -/* These statements are here to stop the compiler complaining about unitialized -variables. */ - -#ifdef SUPPORT_UCP -prop_value = 0; -prop_fail_result = 0; -#endif - - -/* This label is used for tail recursion, which is used in a few cases even -when NO_RECURSE is not defined, in order to reduce the amount of stack that is -used. Thanks to Ian Taylor for noticing this possibility and sending the -original patch. */ - -TAIL_RECURSE: - -/* OK, now we can get on with the real code of the function. Recursive calls -are specified by the macro RMATCH and RRETURN is used to return. When -NO_RECURSE is *not* defined, these just turn into a recursive call to match() -and a "return", respectively (possibly with some debugging if DEBUG is -defined). However, RMATCH isn't like a function call because it's quite a -complicated macro. It has to be used in one particular way. This shouldn't, -however, impact performance when true recursion is being used. */ - -#ifdef SUPPORT_UTF8 -utf8 = md->utf8; /* Local copy of the flag */ -#else -utf8 = FALSE; -#endif - -/* First check that we haven't called match() too many times, or that we -haven't exceeded the recursive call limit. */ - -if (md->match_call_count++ >= md->match_limit) RRETURN(PCRE_ERROR_MATCHLIMIT); -if (rdepth >= md->match_limit_recursion) RRETURN(PCRE_ERROR_RECURSIONLIMIT); - -original_ims = ims; /* Save for resetting on ')' */ - -/* At the start of a group with an unlimited repeat that may match an empty -string, the match_cbegroup flag is set. When this is the case, add the current -subject pointer to the chain of such remembered pointers, to be checked when we -hit the closing ket, in order to break infinite loops that match no characters. -When match() is called in other circumstances, don't add to the chain. The -match_cbegroup flag must NOT be used with tail recursion, because the memory -block that is used is on the stack, so a new one may be required for each -match(). */ - -if ((flags & match_cbegroup) != 0) - { - newptrb.epb_saved_eptr = eptr; - newptrb.epb_prev = eptrb; - eptrb = &newptrb; - } - -/* Now start processing the opcodes. */ - -for (;;) - { - minimize = possessive = FALSE; - op = *ecode; - - /* For partial matching, remember if we ever hit the end of the subject after - matching at least one subject character. */ - - if (md->partial && - eptr >= md->end_subject && - eptr > mstart) - md->hitend = TRUE; - - switch(op) - { - case OP_FAIL: - RRETURN(MATCH_NOMATCH); - - case OP_PRUNE: - RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, - ims, eptrb, flags, RM51); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - RRETURN(MATCH_PRUNE); - - case OP_COMMIT: - RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, - ims, eptrb, flags, RM52); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - RRETURN(MATCH_COMMIT); - - case OP_SKIP: - RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, - ims, eptrb, flags, RM53); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - md->start_match_ptr = eptr; /* Pass back current position */ - RRETURN(MATCH_SKIP); - - case OP_THEN: - RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, - ims, eptrb, flags, RM54); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - RRETURN(MATCH_THEN); - - /* Handle a capturing bracket. If there is space in the offset vector, save - the current subject position in the working slot at the top of the vector. - We mustn't change the current values of the data slot, because they may be - set from a previous iteration of this group, and be referred to by a - reference inside the group. - - If the bracket fails to match, we need to restore this value and also the - values of the final offsets, in case they were set by a previous iteration - of the same bracket. - - If there isn't enough space in the offset vector, treat this as if it were - a non-capturing bracket. Don't worry about setting the flag for the error - case here; that is handled in the code for KET. */ - - case OP_CBRA: - case OP_SCBRA: - number = GET2(ecode, 1+LINK_SIZE); - offset = number << 1; - -#ifdef DEBUG - printf("start bracket %d\n", number); - printf("subject="); - pchars(eptr, 16, TRUE, md); - printf("\n"); -#endif - - if (offset < md->offset_max) - { - save_offset1 = md->offset_vector[offset]; - save_offset2 = md->offset_vector[offset+1]; - save_offset3 = md->offset_vector[md->offset_end - number]; - save_capture_last = md->capture_last; - - DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3)); - md->offset_vector[md->offset_end - number] = eptr - md->start_subject; - - flags = (op == OP_SCBRA)? match_cbegroup : 0; - do - { - RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, - ims, eptrb, flags, RM1); - if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); - md->capture_last = save_capture_last; - ecode += GET(ecode, 1); - } - while (*ecode == OP_ALT); - - DPRINTF(("bracket %d failed\n", number)); - - md->offset_vector[offset] = save_offset1; - md->offset_vector[offset+1] = save_offset2; - md->offset_vector[md->offset_end - number] = save_offset3; - - RRETURN(MATCH_NOMATCH); - } - - /* FALL THROUGH ... Insufficient room for saving captured contents. Treat - as a non-capturing bracket. */ - - /* VVVVVVVVVVVVVVVVVVVVVVVVV */ - /* VVVVVVVVVVVVVVVVVVVVVVVVV */ - - DPRINTF(("insufficient capture room: treat as non-capturing\n")); - - /* VVVVVVVVVVVVVVVVVVVVVVVVV */ - /* VVVVVVVVVVVVVVVVVVVVVVVVV */ - - /* Non-capturing bracket. Loop for all the alternatives. When we get to the - final alternative within the brackets, we would return the result of a - recursive call to match() whatever happened. We can reduce stack usage by - turning this into a tail recursion, except in the case when match_cbegroup - is set.*/ - - case OP_BRA: - case OP_SBRA: - DPRINTF(("start non-capturing bracket\n")); - flags = (op >= OP_SBRA)? match_cbegroup : 0; - for (;;) - { - if (ecode[GET(ecode, 1)] != OP_ALT) /* Final alternative */ - { - if (flags == 0) /* Not a possibly empty group */ - { - ecode += _pcre_OP_lengths[*ecode]; - DPRINTF(("bracket 0 tail recursion\n")); - goto TAIL_RECURSE; - } - - /* Possibly empty group; can't use tail recursion. */ - - RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, ims, - eptrb, flags, RM48); - RRETURN(rrc); - } - - /* For non-final alternatives, continue the loop for a NOMATCH result; - otherwise return. */ - - RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, ims, - eptrb, flags, RM2); - if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); - ecode += GET(ecode, 1); - } - /* Control never reaches here. */ - - /* Conditional group: compilation checked that there are no more than - two branches. If the condition is false, skipping the first branch takes us - past the end if there is only one branch, but that's OK because that is - exactly what going to the ket would do. As there is only one branch to be - obeyed, we can use tail recursion to avoid using another stack frame. */ - - case OP_COND: - case OP_SCOND: - if (ecode[LINK_SIZE+1] == OP_RREF) /* Recursion test */ - { - offset = GET2(ecode, LINK_SIZE + 2); /* Recursion group number*/ - condition = md->recursive != NULL && - (offset == RREF_ANY || offset == md->recursive->group_num); - ecode += condition? 3 : GET(ecode, 1); - } - - else if (ecode[LINK_SIZE+1] == OP_CREF) /* Group used test */ - { - offset = GET2(ecode, LINK_SIZE+2) << 1; /* Doubled ref number */ - condition = offset < offset_top && md->offset_vector[offset] >= 0; - ecode += condition? 3 : GET(ecode, 1); - } - - else if (ecode[LINK_SIZE+1] == OP_DEF) /* DEFINE - always false */ - { - condition = FALSE; - ecode += GET(ecode, 1); - } - - /* The condition is an assertion. Call match() to evaluate it - setting - the final argument match_condassert causes it to stop at the end of an - assertion. */ - - else - { - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, - match_condassert, RM3); - if (rrc == MATCH_MATCH) - { - condition = TRUE; - ecode += 1 + LINK_SIZE + GET(ecode, LINK_SIZE + 2); - while (*ecode == OP_ALT) ecode += GET(ecode, 1); - } - else if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) - { - RRETURN(rrc); /* Need braces because of following else */ - } - else - { - condition = FALSE; - ecode += GET(ecode, 1); - } - } - - /* We are now at the branch that is to be obeyed. As there is only one, - we can use tail recursion to avoid using another stack frame, except when - match_cbegroup is required for an unlimited repeat of a possibly empty - group. If the second alternative doesn't exist, we can just plough on. */ - - if (condition || *ecode == OP_ALT) - { - ecode += 1 + LINK_SIZE; - if (op == OP_SCOND) /* Possibly empty group */ - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, match_cbegroup, RM49); - RRETURN(rrc); - } - else /* Group must match something */ - { - flags = 0; - goto TAIL_RECURSE; - } - } - else /* Condition false & no 2nd alternative */ - { - ecode += 1 + LINK_SIZE; - } - break; - - - /* End of the pattern, either real or forced. If we are in a top-level - recursion, we should restore the offsets appropriately and continue from - after the call. */ - - case OP_ACCEPT: - case OP_END: - if (md->recursive != NULL && md->recursive->group_num == 0) - { - recursion_info *rec = md->recursive; - DPRINTF(("End of pattern in a (?0) recursion\n")); - md->recursive = rec->prevrec; - memmove(md->offset_vector, rec->offset_save, - rec->saved_max * sizeof(int)); - mstart = rec->save_start; - ims = original_ims; - ecode = rec->after_call; - break; - } - - /* Otherwise, if PCRE_NOTEMPTY is set, fail if we have matched an empty - string - backtracking will then try other alternatives, if any. */ - - if (md->notempty && eptr == mstart) RRETURN(MATCH_NOMATCH); - md->end_match_ptr = eptr; /* Record where we ended */ - md->end_offset_top = offset_top; /* and how many extracts were taken */ - md->start_match_ptr = mstart; /* and the start (\K can modify) */ - RRETURN(MATCH_MATCH); - - /* Change option settings */ - - case OP_OPT: - ims = ecode[1]; - ecode += 2; - DPRINTF(("ims set to %02lx\n", ims)); - break; - - /* Assertion brackets. Check the alternative branches in turn - the - matching won't pass the KET for an assertion. If any one branch matches, - the assertion is true. Lookbehind assertions have an OP_REVERSE item at the - start of each branch to move the current point backwards, so the code at - this level is identical to the lookahead case. */ - - case OP_ASSERT: - case OP_ASSERTBACK: - do - { - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, 0, - RM4); - if (rrc == MATCH_MATCH) break; - if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); - ecode += GET(ecode, 1); - } - while (*ecode == OP_ALT); - if (*ecode == OP_KET) RRETURN(MATCH_NOMATCH); - - /* If checking an assertion for a condition, return MATCH_MATCH. */ - - if ((flags & match_condassert) != 0) RRETURN(MATCH_MATCH); - - /* Continue from after the assertion, updating the offsets high water - mark, since extracts may have been taken during the assertion. */ - - do ecode += GET(ecode,1); while (*ecode == OP_ALT); - ecode += 1 + LINK_SIZE; - offset_top = md->end_offset_top; - continue; - - /* Negative assertion: all branches must fail to match */ - - case OP_ASSERT_NOT: - case OP_ASSERTBACK_NOT: - do - { - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, 0, - RM5); - if (rrc == MATCH_MATCH) RRETURN(MATCH_NOMATCH); - if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); - ecode += GET(ecode,1); - } - while (*ecode == OP_ALT); - - if ((flags & match_condassert) != 0) RRETURN(MATCH_MATCH); - - ecode += 1 + LINK_SIZE; - continue; - - /* Move the subject pointer back. This occurs only at the start of - each branch of a lookbehind assertion. If we are too close to the start to - move back, this match function fails. When working with UTF-8 we move - back a number of characters, not bytes. */ - - case OP_REVERSE: -#ifdef SUPPORT_UTF8 - if (utf8) - { - i = GET(ecode, 1); - while (i-- > 0) - { - eptr--; - if (eptr < md->start_subject) RRETURN(MATCH_NOMATCH); - BACKCHAR(eptr); - } - } - else -#endif - - /* No UTF-8 support, or not in UTF-8 mode: count is byte count */ - - { - eptr -= GET(ecode, 1); - if (eptr < md->start_subject) RRETURN(MATCH_NOMATCH); - } - - /* Skip to next op code */ - - ecode += 1 + LINK_SIZE; - break; - - /* The callout item calls an external function, if one is provided, passing - details of the match so far. This is mainly for debugging, though the - function is able to force a failure. */ - - case OP_CALLOUT: - if (pcre_callout != NULL) - { - pcre_callout_block cb; - cb.version = 1; /* Version 1 of the callout block */ - cb.callout_number = ecode[1]; - cb.offset_vector = md->offset_vector; - cb.subject = (PCRE_SPTR)md->start_subject; - cb.subject_length = md->end_subject - md->start_subject; - cb.start_match = mstart - md->start_subject; - cb.current_position = eptr - md->start_subject; - cb.pattern_position = GET(ecode, 2); - cb.next_item_length = GET(ecode, 2 + LINK_SIZE); - cb.capture_top = offset_top/2; - cb.capture_last = md->capture_last; - cb.callout_data = md->callout_data; - if ((rrc = (*pcre_callout)(&cb)) > 0) RRETURN(MATCH_NOMATCH); - if (rrc < 0) RRETURN(rrc); - } - ecode += 2 + 2*LINK_SIZE; - break; - - /* Recursion either matches the current regex, or some subexpression. The - offset data is the offset to the starting bracket from the start of the - whole pattern. (This is so that it works from duplicated subpatterns.) - - If there are any capturing brackets started but not finished, we have to - save their starting points and reinstate them after the recursion. However, - we don't know how many such there are (offset_top records the completed - total) so we just have to save all the potential data. There may be up to - 65535 such values, which is too large to put on the stack, but using malloc - for small numbers seems expensive. As a compromise, the stack is used when - there are no more than REC_STACK_SAVE_MAX values to store; otherwise malloc - is used. A problem is what to do if the malloc fails ... there is no way of - returning to the top level with an error. Save the top REC_STACK_SAVE_MAX - values on the stack, and accept that the rest may be wrong. - - There are also other values that have to be saved. We use a chained - sequence of blocks that actually live on the stack. Thanks to Robin Houston - for the original version of this logic. */ - - case OP_RECURSE: - { - callpat = md->start_code + GET(ecode, 1); - new_recursive.group_num = (callpat == md->start_code)? 0 : - GET2(callpat, 1 + LINK_SIZE); - - /* Add to "recursing stack" */ - - new_recursive.prevrec = md->recursive; - md->recursive = &new_recursive; - - /* Find where to continue from afterwards */ - - ecode += 1 + LINK_SIZE; - new_recursive.after_call = ecode; - - /* Now save the offset data. */ - - new_recursive.saved_max = md->offset_end; - if (new_recursive.saved_max <= REC_STACK_SAVE_MAX) - new_recursive.offset_save = stacksave; - else - { - new_recursive.offset_save = - (int *)(pcre_malloc)(new_recursive.saved_max * sizeof(int)); - if (new_recursive.offset_save == NULL) RRETURN(PCRE_ERROR_NOMEMORY); - } - - memcpy(new_recursive.offset_save, md->offset_vector, - new_recursive.saved_max * sizeof(int)); - new_recursive.save_start = mstart; - mstart = eptr; - - /* OK, now we can do the recursion. For each top-level alternative we - restore the offset and recursion data. */ - - DPRINTF(("Recursing into group %d\n", new_recursive.group_num)); - flags = (*callpat >= OP_SBRA)? match_cbegroup : 0; - do - { - RMATCH(eptr, callpat + _pcre_OP_lengths[*callpat], offset_top, - md, ims, eptrb, flags, RM6); - if (rrc == MATCH_MATCH) - { - DPRINTF(("Recursion matched\n")); - md->recursive = new_recursive.prevrec; - if (new_recursive.offset_save != stacksave) - (pcre_free)(new_recursive.offset_save); - RRETURN(MATCH_MATCH); - } - else if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) - { - DPRINTF(("Recursion gave error %d\n", rrc)); - RRETURN(rrc); - } - - md->recursive = &new_recursive; - memcpy(md->offset_vector, new_recursive.offset_save, - new_recursive.saved_max * sizeof(int)); - callpat += GET(callpat, 1); - } - while (*callpat == OP_ALT); - - DPRINTF(("Recursion didn't match\n")); - md->recursive = new_recursive.prevrec; - if (new_recursive.offset_save != stacksave) - (pcre_free)(new_recursive.offset_save); - RRETURN(MATCH_NOMATCH); - } - /* Control never reaches here */ - - /* "Once" brackets are like assertion brackets except that after a match, - the point in the subject string is not moved back. Thus there can never be - a move back into the brackets. Friedl calls these "atomic" subpatterns. - Check the alternative branches in turn - the matching won't pass the KET - for this kind of subpattern. If any one branch matches, we carry on as at - the end of a normal bracket, leaving the subject pointer. */ - - case OP_ONCE: - prev = ecode; - saved_eptr = eptr; - - do - { - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, 0, RM7); - if (rrc == MATCH_MATCH) break; - if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); - ecode += GET(ecode,1); - } - while (*ecode == OP_ALT); - - /* If hit the end of the group (which could be repeated), fail */ - - if (*ecode != OP_ONCE && *ecode != OP_ALT) RRETURN(MATCH_NOMATCH); - - /* Continue as from after the assertion, updating the offsets high water - mark, since extracts may have been taken. */ - - do ecode += GET(ecode, 1); while (*ecode == OP_ALT); - - offset_top = md->end_offset_top; - eptr = md->end_match_ptr; - - /* For a non-repeating ket, just continue at this level. This also - happens for a repeating ket if no characters were matched in the group. - This is the forcible breaking of infinite loops as implemented in Perl - 5.005. If there is an options reset, it will get obeyed in the normal - course of events. */ - - if (*ecode == OP_KET || eptr == saved_eptr) - { - ecode += 1+LINK_SIZE; - break; - } - - /* The repeating kets try the rest of the pattern or restart from the - preceding bracket, in the appropriate order. The second "call" of match() - uses tail recursion, to avoid using another stack frame. We need to reset - any options that changed within the bracket before re-running it, so - check the next opcode. */ - - if (ecode[1+LINK_SIZE] == OP_OPT) - { - ims = (ims & ~PCRE_IMS) | ecode[4]; - DPRINTF(("ims set to %02lx at group repeat\n", ims)); - } - - if (*ecode == OP_KETRMIN) - { - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, 0, RM8); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - ecode = prev; - flags = 0; - goto TAIL_RECURSE; - } - else /* OP_KETRMAX */ - { - RMATCH(eptr, prev, offset_top, md, ims, eptrb, match_cbegroup, RM9); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - ecode += 1 + LINK_SIZE; - flags = 0; - goto TAIL_RECURSE; - } - /* Control never gets here */ - - /* An alternation is the end of a branch; scan along to find the end of the - bracketed group and go to there. */ - - case OP_ALT: - do ecode += GET(ecode,1); while (*ecode == OP_ALT); - break; - - /* BRAZERO, BRAMINZERO and SKIPZERO occur just before a bracket group, - indicating that it may occur zero times. It may repeat infinitely, or not - at all - i.e. it could be ()* or ()? or even (){0} in the pattern. Brackets - with fixed upper repeat limits are compiled as a number of copies, with the - optional ones preceded by BRAZERO or BRAMINZERO. */ - - case OP_BRAZERO: - { - next = ecode+1; - RMATCH(eptr, next, offset_top, md, ims, eptrb, 0, RM10); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - do next += GET(next,1); while (*next == OP_ALT); - ecode = next + 1 + LINK_SIZE; - } - break; - - case OP_BRAMINZERO: - { - next = ecode+1; - do next += GET(next, 1); while (*next == OP_ALT); - RMATCH(eptr, next + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0, RM11); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - ecode++; - } - break; - - case OP_SKIPZERO: - { - next = ecode+1; - do next += GET(next,1); while (*next == OP_ALT); - ecode = next + 1 + LINK_SIZE; - } - break; - - /* End of a group, repeated or non-repeating. */ - - case OP_KET: - case OP_KETRMIN: - case OP_KETRMAX: - prev = ecode - GET(ecode, 1); - - /* If this was a group that remembered the subject start, in order to break - infinite repeats of empty string matches, retrieve the subject start from - the chain. Otherwise, set it NULL. */ - - if (*prev >= OP_SBRA) - { - saved_eptr = eptrb->epb_saved_eptr; /* Value at start of group */ - eptrb = eptrb->epb_prev; /* Backup to previous group */ - } - else saved_eptr = NULL; - - /* If we are at the end of an assertion group, stop matching and return - MATCH_MATCH, but record the current high water mark for use by positive - assertions. Do this also for the "once" (atomic) groups. */ - - if (*prev == OP_ASSERT || *prev == OP_ASSERT_NOT || - *prev == OP_ASSERTBACK || *prev == OP_ASSERTBACK_NOT || - *prev == OP_ONCE) - { - md->end_match_ptr = eptr; /* For ONCE */ - md->end_offset_top = offset_top; - RRETURN(MATCH_MATCH); - } - - /* For capturing groups we have to check the group number back at the start - and if necessary complete handling an extraction by setting the offsets and - bumping the high water mark. Note that whole-pattern recursion is coded as - a recurse into group 0, so it won't be picked up here. Instead, we catch it - when the OP_END is reached. Other recursion is handled here. */ - - if (*prev == OP_CBRA || *prev == OP_SCBRA) - { - number = GET2(prev, 1+LINK_SIZE); - offset = number << 1; - -#ifdef DEBUG - printf("end bracket %d", number); - printf("\n"); -#endif - - md->capture_last = number; - if (offset >= md->offset_max) md->offset_overflow = TRUE; else - { - md->offset_vector[offset] = - md->offset_vector[md->offset_end - number]; - md->offset_vector[offset+1] = eptr - md->start_subject; - if (offset_top <= offset) offset_top = offset + 2; - } - - /* Handle a recursively called group. Restore the offsets - appropriately and continue from after the call. */ - - if (md->recursive != NULL && md->recursive->group_num == number) - { - recursion_info *rec = md->recursive; - DPRINTF(("Recursion (%d) succeeded - continuing\n", number)); - md->recursive = rec->prevrec; - mstart = rec->save_start; - memcpy(md->offset_vector, rec->offset_save, - rec->saved_max * sizeof(int)); - ecode = rec->after_call; - ims = original_ims; - break; - } - } - - /* For both capturing and non-capturing groups, reset the value of the ims - flags, in case they got changed during the group. */ - - ims = original_ims; - DPRINTF(("ims reset to %02lx\n", ims)); - - /* For a non-repeating ket, just continue at this level. This also - happens for a repeating ket if no characters were matched in the group. - This is the forcible breaking of infinite loops as implemented in Perl - 5.005. If there is an options reset, it will get obeyed in the normal - course of events. */ - - if (*ecode == OP_KET || eptr == saved_eptr) - { - ecode += 1 + LINK_SIZE; - break; - } - - /* The repeating kets try the rest of the pattern or restart from the - preceding bracket, in the appropriate order. In the second case, we can use - tail recursion to avoid using another stack frame, unless we have an - unlimited repeat of a group that can match an empty string. */ - - flags = (*prev >= OP_SBRA)? match_cbegroup : 0; - - if (*ecode == OP_KETRMIN) - { - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, 0, RM12); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (flags != 0) /* Could match an empty string */ - { - RMATCH(eptr, prev, offset_top, md, ims, eptrb, flags, RM50); - RRETURN(rrc); - } - ecode = prev; - goto TAIL_RECURSE; - } - else /* OP_KETRMAX */ - { - RMATCH(eptr, prev, offset_top, md, ims, eptrb, flags, RM13); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - ecode += 1 + LINK_SIZE; - flags = 0; - goto TAIL_RECURSE; - } - /* Control never gets here */ - - /* Start of subject unless notbol, or after internal newline if multiline */ - - case OP_CIRC: - if (md->notbol && eptr == md->start_subject) RRETURN(MATCH_NOMATCH); - if ((ims & PCRE_MULTILINE) != 0) - { - if (eptr != md->start_subject && - (eptr == md->end_subject || !WAS_NEWLINE(eptr))) - RRETURN(MATCH_NOMATCH); - ecode++; - break; - } - /* ... else fall through */ - - /* Start of subject assertion */ - - case OP_SOD: - if (eptr != md->start_subject) RRETURN(MATCH_NOMATCH); - ecode++; - break; - - /* Start of match assertion */ - - case OP_SOM: - if (eptr != md->start_subject + md->start_offset) RRETURN(MATCH_NOMATCH); - ecode++; - break; - - /* Reset the start of match point */ - - case OP_SET_SOM: - mstart = eptr; - ecode++; - break; - - /* Assert before internal newline if multiline, or before a terminating - newline unless endonly is set, else end of subject unless noteol is set. */ - - case OP_DOLL: - if ((ims & PCRE_MULTILINE) != 0) - { - if (eptr < md->end_subject) - { if (!IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); } - else - { if (md->noteol) RRETURN(MATCH_NOMATCH); } - ecode++; - break; - } - else - { - if (md->noteol) RRETURN(MATCH_NOMATCH); - if (!md->endonly) - { - if (eptr != md->end_subject && - (!IS_NEWLINE(eptr) || eptr != md->end_subject - md->nllen)) - RRETURN(MATCH_NOMATCH); - ecode++; - break; - } - } - /* ... else fall through for endonly */ - - /* End of subject assertion (\z) */ - - case OP_EOD: - if (eptr < md->end_subject) RRETURN(MATCH_NOMATCH); - ecode++; - break; - - /* End of subject or ending \n assertion (\Z) */ - - case OP_EODN: - if (eptr != md->end_subject && - (!IS_NEWLINE(eptr) || eptr != md->end_subject - md->nllen)) - RRETURN(MATCH_NOMATCH); - ecode++; - break; - - /* Word boundary assertions */ - - case OP_NOT_WORD_BOUNDARY: - case OP_WORD_BOUNDARY: - { - - /* Find out if the previous and current characters are "word" characters. - It takes a bit more work in UTF-8 mode. Characters > 255 are assumed to - be "non-word" characters. */ - -#ifdef SUPPORT_UTF8 - if (utf8) - { - if (eptr == md->start_subject) prev_is_word = FALSE; else - { - const uschar *lastptr = eptr - 1; - while((*lastptr & 0xc0) == 0x80) lastptr--; - GETCHAR(c, lastptr); - prev_is_word = c < 256 && (md->ctypes[c] & ctype_word) != 0; - } - if (eptr >= md->end_subject) cur_is_word = FALSE; else - { - GETCHAR(c, eptr); - cur_is_word = c < 256 && (md->ctypes[c] & ctype_word) != 0; - } - } - else -#endif - - /* More streamlined when not in UTF-8 mode */ - - { - prev_is_word = (eptr != md->start_subject) && - ((md->ctypes[eptr[-1]] & ctype_word) != 0); - cur_is_word = (eptr < md->end_subject) && - ((md->ctypes[*eptr] & ctype_word) != 0); - } - - /* Now see if the situation is what we want */ - - if ((*ecode++ == OP_WORD_BOUNDARY)? - cur_is_word == prev_is_word : cur_is_word != prev_is_word) - RRETURN(MATCH_NOMATCH); - } - break; - - /* Match a single character type; inline for speed */ - - case OP_ANY: - if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); - /* Fall through */ - - case OP_ALLANY: - if (eptr++ >= md->end_subject) RRETURN(MATCH_NOMATCH); - if (utf8) while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; - ecode++; - break; - - /* Match a single byte, even in UTF-8 mode. This opcode really does match - any byte, even newline, independent of the setting of PCRE_DOTALL. */ - - case OP_ANYBYTE: - if (eptr++ >= md->end_subject) RRETURN(MATCH_NOMATCH); - ecode++; - break; - - case OP_NOT_DIGIT: - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - if ( -#ifdef SUPPORT_UTF8 - c < 256 && -#endif - (md->ctypes[c] & ctype_digit) != 0 - ) - RRETURN(MATCH_NOMATCH); - ecode++; - break; - - case OP_DIGIT: - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - if ( -#ifdef SUPPORT_UTF8 - c >= 256 || -#endif - (md->ctypes[c] & ctype_digit) == 0 - ) - RRETURN(MATCH_NOMATCH); - ecode++; - break; - - case OP_NOT_WHITESPACE: - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - if ( -#ifdef SUPPORT_UTF8 - c < 256 && -#endif - (md->ctypes[c] & ctype_space) != 0 - ) - RRETURN(MATCH_NOMATCH); - ecode++; - break; - - case OP_WHITESPACE: - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - if ( -#ifdef SUPPORT_UTF8 - c >= 256 || -#endif - (md->ctypes[c] & ctype_space) == 0 - ) - RRETURN(MATCH_NOMATCH); - ecode++; - break; - - case OP_NOT_WORDCHAR: - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - if ( -#ifdef SUPPORT_UTF8 - c < 256 && -#endif - (md->ctypes[c] & ctype_word) != 0 - ) - RRETURN(MATCH_NOMATCH); - ecode++; - break; - - case OP_WORDCHAR: - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - if ( -#ifdef SUPPORT_UTF8 - c >= 256 || -#endif - (md->ctypes[c] & ctype_word) == 0 - ) - RRETURN(MATCH_NOMATCH); - ecode++; - break; - - case OP_ANYNL: - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - switch(c) - { - default: RRETURN(MATCH_NOMATCH); - case 0x000d: - if (eptr < md->end_subject && *eptr == 0x0a) eptr++; - break; - - case 0x000a: - break; - - case 0x000b: - case 0x000c: - case 0x0085: - case 0x2028: - case 0x2029: - if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); - break; - } - ecode++; - break; - - case OP_NOT_HSPACE: - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - switch(c) - { - default: break; - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - RRETURN(MATCH_NOMATCH); - } - ecode++; - break; - - case OP_HSPACE: - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - switch(c) - { - default: RRETURN(MATCH_NOMATCH); - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - break; - } - ecode++; - break; - - case OP_NOT_VSPACE: - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - switch(c) - { - default: break; - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ - RRETURN(MATCH_NOMATCH); - } - ecode++; - break; - - case OP_VSPACE: - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - switch(c) - { - default: RRETURN(MATCH_NOMATCH); - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ - break; - } - ecode++; - break; - -#ifdef SUPPORT_UCP - /* Check the next character by Unicode property. We will get here only - if the support is in the binary; otherwise a compile-time error occurs. */ - - case OP_PROP: - case OP_NOTPROP: - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - { - int chartype = UCD_CHARTYPE(c); - switch(ecode[1]) - { - case PT_ANY: - if (op == OP_NOTPROP) RRETURN(MATCH_NOMATCH); - break; - - case PT_LAMP: - if ((chartype == ucp_Lu || - chartype == ucp_Ll || - chartype == ucp_Lt) == (op == OP_NOTPROP)) - RRETURN(MATCH_NOMATCH); - break; - - case PT_GC: - if ((ecode[2] != _pcre_ucp_gentype[chartype]) == (op == OP_PROP)) - RRETURN(MATCH_NOMATCH); - break; - - case PT_PC: - if ((ecode[2] != chartype) == (op == OP_PROP)) - RRETURN(MATCH_NOMATCH); - break; - - case PT_SC: - if ((ecode[2] != UCD_SCRIPT(c)) == (op == OP_PROP)) - RRETURN(MATCH_NOMATCH); - break; - - default: - RRETURN(PCRE_ERROR_INTERNAL); - } - - ecode += 3; - } - break; - - /* Match an extended Unicode sequence. We will get here only if the support - is in the binary; otherwise a compile-time error occurs. */ - - case OP_EXTUNI: - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - { - int category = UCD_CATEGORY(c); - if (category == ucp_M) RRETURN(MATCH_NOMATCH); - while (eptr < md->end_subject) - { - int len = 1; - if (!utf8) c = *eptr; else - { - GETCHARLEN(c, eptr, len); - } - category = UCD_CATEGORY(c); - if (category != ucp_M) break; - eptr += len; - } - } - ecode++; - break; -#endif - - - /* Match a back reference, possibly repeatedly. Look past the end of the - item to see if there is repeat information following. The code is similar - to that for character classes, but repeated for efficiency. Then obey - similar code to character type repeats - written out again for speed. - However, if the referenced string is the empty string, always treat - it as matched, any number of times (otherwise there could be infinite - loops). */ - - case OP_REF: - { - offset = GET2(ecode, 1) << 1; /* Doubled ref number */ - ecode += 3; - - /* If the reference is unset, there are two possibilities: - - (a) In the default, Perl-compatible state, set the length to be longer - than the amount of subject left; this ensures that every attempt at a - match fails. We can't just fail here, because of the possibility of - quantifiers with zero minima. - - (b) If the JavaScript compatibility flag is set, set the length to zero - so that the back reference matches an empty string. - - Otherwise, set the length to the length of what was matched by the - referenced subpattern. */ - - if (offset >= offset_top || md->offset_vector[offset] < 0) - length = (md->jscript_compat)? 0 : md->end_subject - eptr + 1; - else - length = md->offset_vector[offset+1] - md->offset_vector[offset]; - - /* Set up for repetition, or handle the non-repeated case */ - - switch (*ecode) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - c = *ecode++ - OP_CRSTAR; - minimize = (c & 1) != 0; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - minimize = (*ecode == OP_CRMINRANGE); - min = GET2(ecode, 1); - max = GET2(ecode, 3); - if (max == 0) max = INT_MAX; - ecode += 5; - break; - - default: /* No repeat follows */ - if (!match_ref(offset, eptr, length, md, ims)) RRETURN(MATCH_NOMATCH); - eptr += length; - continue; /* With the main loop */ - } - - /* If the length of the reference is zero, just continue with the - main loop. */ - - if (length == 0) continue; - - /* First, ensure the minimum number of matches are present. We get back - the length of the reference string explicitly rather than passing the - address of eptr, so that eptr can be a register variable. */ - - for (i = 1; i <= min; i++) - { - if (!match_ref(offset, eptr, length, md, ims)) RRETURN(MATCH_NOMATCH); - eptr += length; - } - - /* If min = max, continue at the same level without recursion. - They are not both allowed to be zero. */ - - if (min == max) continue; - - /* If minimizing, keep trying and advancing the pointer */ - - if (minimize) - { - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM14); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || !match_ref(offset, eptr, length, md, ims)) - RRETURN(MATCH_NOMATCH); - eptr += length; - } - /* Control never gets here */ - } - - /* If maximizing, find the longest string and work backwards */ - - else - { - pp = eptr; - for (i = min; i < max; i++) - { - if (!match_ref(offset, eptr, length, md, ims)) break; - eptr += length; - } - while (eptr >= pp) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM15); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - eptr -= length; - } - RRETURN(MATCH_NOMATCH); - } - } - /* Control never gets here */ - - - - /* Match a bit-mapped character class, possibly repeatedly. This op code is - used when all the characters in the class have values in the range 0-255, - and either the matching is caseful, or the characters are in the range - 0-127 when UTF-8 processing is enabled. The only difference between - OP_CLASS and OP_NCLASS occurs when a data character outside the range is - encountered. - - First, look past the end of the item to see if there is repeat information - following. Then obey similar code to character type repeats - written out - again for speed. */ - - case OP_NCLASS: - case OP_CLASS: - { - data = ecode + 1; /* Save for matching */ - ecode += 33; /* Advance past the item */ - - switch (*ecode) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - c = *ecode++ - OP_CRSTAR; - minimize = (c & 1) != 0; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - minimize = (*ecode == OP_CRMINRANGE); - min = GET2(ecode, 1); - max = GET2(ecode, 3); - if (max == 0) max = INT_MAX; - ecode += 5; - break; - - default: /* No repeat follows */ - min = max = 1; - break; - } - - /* First, ensure the minimum number of matches are present. */ - -#ifdef SUPPORT_UTF8 - /* UTF-8 mode */ - if (utf8) - { - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(c, eptr); - if (c > 255) - { - if (op == OP_CLASS) RRETURN(MATCH_NOMATCH); - } - else - { - if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); - } - } - } - else -#endif - /* Not UTF-8 mode */ - { - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - c = *eptr++; - if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); - } - } - - /* If max == min we can continue with the main loop without the - need to recurse. */ - - if (min == max) continue; - - /* If minimizing, keep testing the rest of the expression and advancing - the pointer while it matches the class. */ - - if (minimize) - { -#ifdef SUPPORT_UTF8 - /* UTF-8 mode */ - if (utf8) - { - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM16); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(c, eptr); - if (c > 255) - { - if (op == OP_CLASS) RRETURN(MATCH_NOMATCH); - } - else - { - if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); - } - } - } - else -#endif - /* Not UTF-8 mode */ - { - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM17); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - c = *eptr++; - if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); - } - } - /* Control never gets here */ - } - - /* If maximizing, find the longest possible run, then work backwards. */ - - else - { - pp = eptr; - -#ifdef SUPPORT_UTF8 - /* UTF-8 mode */ - if (utf8) - { - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len); - if (c > 255) - { - if (op == OP_CLASS) break; - } - else - { - if ((data[c/8] & (1 << (c&7))) == 0) break; - } - eptr += len; - } - for (;;) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM18); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr-- == pp) break; /* Stop if tried at original pos */ - BACKCHAR(eptr); - } - } - else -#endif - /* Not UTF-8 mode */ - { - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject) break; - c = *eptr; - if ((data[c/8] & (1 << (c&7))) == 0) break; - eptr++; - } - while (eptr >= pp) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM19); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - eptr--; - } - } - - RRETURN(MATCH_NOMATCH); - } - } - /* Control never gets here */ - - - /* Match an extended character class. This opcode is encountered only - in UTF-8 mode, because that's the only time it is compiled. */ - -#ifdef SUPPORT_UTF8 - case OP_XCLASS: - { - data = ecode + 1 + LINK_SIZE; /* Save for matching */ - ecode += GET(ecode, 1); /* Advance past the item */ - - switch (*ecode) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - c = *ecode++ - OP_CRSTAR; - minimize = (c & 1) != 0; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - minimize = (*ecode == OP_CRMINRANGE); - min = GET2(ecode, 1); - max = GET2(ecode, 3); - if (max == 0) max = INT_MAX; - ecode += 5; - break; - - default: /* No repeat follows */ - min = max = 1; - break; - } - - /* First, ensure the minimum number of matches are present. */ - - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(c, eptr); - if (!_pcre_xclass(c, data)) RRETURN(MATCH_NOMATCH); - } - - /* If max == min we can continue with the main loop without the - need to recurse. */ - - if (min == max) continue; - - /* If minimizing, keep testing the rest of the expression and advancing - the pointer while it matches the class. */ - - if (minimize) - { - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM20); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(c, eptr); - if (!_pcre_xclass(c, data)) RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - } - - /* If maximizing, find the longest possible run, then work backwards. */ - - else - { - pp = eptr; - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len); - if (!_pcre_xclass(c, data)) break; - eptr += len; - } - for(;;) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM21); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr-- == pp) break; /* Stop if tried at original pos */ - if (utf8) BACKCHAR(eptr); - } - RRETURN(MATCH_NOMATCH); - } - - /* Control never gets here */ - } -#endif /* End of XCLASS */ - - /* Match a single character, casefully */ - - case OP_CHAR: -#ifdef SUPPORT_UTF8 - if (utf8) - { - length = 1; - ecode++; - GETCHARLEN(fc, ecode, length); - if (length > md->end_subject - eptr) RRETURN(MATCH_NOMATCH); - while (length-- > 0) if (*ecode++ != *eptr++) RRETURN(MATCH_NOMATCH); - } - else -#endif - - /* Non-UTF-8 mode */ - { - if (md->end_subject - eptr < 1) RRETURN(MATCH_NOMATCH); - if (ecode[1] != *eptr++) RRETURN(MATCH_NOMATCH); - ecode += 2; - } - break; - - /* Match a single character, caselessly */ - - case OP_CHARNC: -#ifdef SUPPORT_UTF8 - if (utf8) - { - length = 1; - ecode++; - GETCHARLEN(fc, ecode, length); - - if (length > md->end_subject - eptr) RRETURN(MATCH_NOMATCH); - - /* If the pattern character's value is < 128, we have only one byte, and - can use the fast lookup table. */ - - if (fc < 128) - { - if (md->lcc[*ecode++] != md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH); - } - - /* Otherwise we must pick up the subject character */ - - else - { - unsigned int dc; - GETCHARINC(dc, eptr); - ecode += length; - - /* If we have Unicode property support, we can use it to test the other - case of the character, if there is one. */ - - if (fc != dc) - { -#ifdef SUPPORT_UCP - if (dc != UCD_OTHERCASE(fc)) -#endif - RRETURN(MATCH_NOMATCH); - } - } - } - else -#endif /* SUPPORT_UTF8 */ - - /* Non-UTF-8 mode */ - { - if (md->end_subject - eptr < 1) RRETURN(MATCH_NOMATCH); - if (md->lcc[ecode[1]] != md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH); - ecode += 2; - } - break; - - /* Match a single character repeatedly. */ - - case OP_EXACT: - min = max = GET2(ecode, 1); - ecode += 3; - goto REPEATCHAR; - - case OP_POSUPTO: - possessive = TRUE; - /* Fall through */ - - case OP_UPTO: - case OP_MINUPTO: - min = 0; - max = GET2(ecode, 1); - minimize = *ecode == OP_MINUPTO; - ecode += 3; - goto REPEATCHAR; - - case OP_POSSTAR: - possessive = TRUE; - min = 0; - max = INT_MAX; - ecode++; - goto REPEATCHAR; - - case OP_POSPLUS: - possessive = TRUE; - min = 1; - max = INT_MAX; - ecode++; - goto REPEATCHAR; - - case OP_POSQUERY: - possessive = TRUE; - min = 0; - max = 1; - ecode++; - goto REPEATCHAR; - - case OP_STAR: - case OP_MINSTAR: - case OP_PLUS: - case OP_MINPLUS: - case OP_QUERY: - case OP_MINQUERY: - c = *ecode++ - OP_STAR; - minimize = (c & 1) != 0; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - - /* Common code for all repeated single-character matches. We can give - up quickly if there are fewer than the minimum number of characters left in - the subject. */ - - REPEATCHAR: -#ifdef SUPPORT_UTF8 - if (utf8) - { - length = 1; - charptr = ecode; - GETCHARLEN(fc, ecode, length); - if (min * length > md->end_subject - eptr) RRETURN(MATCH_NOMATCH); - ecode += length; - - /* Handle multibyte character matching specially here. There is - support for caseless matching if UCP support is present. */ - - if (length > 1) - { -#ifdef SUPPORT_UCP - unsigned int othercase; - if ((ims & PCRE_CASELESS) != 0 && - (othercase = UCD_OTHERCASE(fc)) != fc) - oclength = _pcre_ord2utf8(othercase, occhars); - else oclength = 0; -#endif /* SUPPORT_UCP */ - - for (i = 1; i <= min; i++) - { - if (memcmp(eptr, charptr, length) == 0) eptr += length; -#ifdef SUPPORT_UCP - /* Need braces because of following else */ - else if (oclength == 0) { RRETURN(MATCH_NOMATCH); } - else - { - if (memcmp(eptr, occhars, oclength) != 0) RRETURN(MATCH_NOMATCH); - eptr += oclength; - } -#else /* without SUPPORT_UCP */ - else { RRETURN(MATCH_NOMATCH); } -#endif /* SUPPORT_UCP */ - } - - if (min == max) continue; - - if (minimize) - { - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM22); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - if (memcmp(eptr, charptr, length) == 0) eptr += length; -#ifdef SUPPORT_UCP - /* Need braces because of following else */ - else if (oclength == 0) { RRETURN(MATCH_NOMATCH); } - else - { - if (memcmp(eptr, occhars, oclength) != 0) RRETURN(MATCH_NOMATCH); - eptr += oclength; - } -#else /* without SUPPORT_UCP */ - else { RRETURN (MATCH_NOMATCH); } -#endif /* SUPPORT_UCP */ - } - /* Control never gets here */ - } - - else /* Maximize */ - { - pp = eptr; - for (i = min; i < max; i++) - { - if (eptr > md->end_subject - length) break; - if (memcmp(eptr, charptr, length) == 0) eptr += length; -#ifdef SUPPORT_UCP - else if (oclength == 0) break; - else - { - if (memcmp(eptr, occhars, oclength) != 0) break; - eptr += oclength; - } -#else /* without SUPPORT_UCP */ - else break; -#endif /* SUPPORT_UCP */ - } - - if (possessive) continue; - for(;;) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM23); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr == pp) RRETURN(MATCH_NOMATCH); -#ifdef SUPPORT_UCP - eptr--; - BACKCHAR(eptr); -#else /* without SUPPORT_UCP */ - eptr -= length; -#endif /* SUPPORT_UCP */ - } - } - /* Control never gets here */ - } - - /* If the length of a UTF-8 character is 1, we fall through here, and - obey the code as for non-UTF-8 characters below, though in this case the - value of fc will always be < 128. */ - } - else -#endif /* SUPPORT_UTF8 */ - - /* When not in UTF-8 mode, load a single-byte character. */ - { - if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH); - fc = *ecode++; - } - - /* The value of fc at this point is always less than 256, though we may or - may not be in UTF-8 mode. The code is duplicated for the caseless and - caseful cases, for speed, since matching characters is likely to be quite - common. First, ensure the minimum number of matches are present. If min = - max, continue at the same level without recursing. Otherwise, if - minimizing, keep trying the rest of the expression and advancing one - matching character if failing, up to the maximum. Alternatively, if - maximizing, find the maximum number of characters and work backwards. */ - - DPRINTF(("matching %c{%d,%d} against subject %.*s\n", fc, min, max, - max, eptr)); - - if ((ims & PCRE_CASELESS) != 0) - { - fc = md->lcc[fc]; - for (i = 1; i <= min; i++) - if (fc != md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH); - if (min == max) continue; - if (minimize) - { - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM24); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject || - fc != md->lcc[*eptr++]) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - } - else /* Maximize */ - { - pp = eptr; - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || fc != md->lcc[*eptr]) break; - eptr++; - } - if (possessive) continue; - while (eptr >= pp) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM25); - eptr--; - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - } - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - } - - /* Caseful comparisons (includes all multi-byte characters) */ - - else - { - for (i = 1; i <= min; i++) if (fc != *eptr++) RRETURN(MATCH_NOMATCH); - if (min == max) continue; - if (minimize) - { - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM26); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject || fc != *eptr++) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - } - else /* Maximize */ - { - pp = eptr; - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || fc != *eptr) break; - eptr++; - } - if (possessive) continue; - while (eptr >= pp) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM27); - eptr--; - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - } - RRETURN(MATCH_NOMATCH); - } - } - /* Control never gets here */ - - /* Match a negated single one-byte character. The character we are - checking can be multibyte. */ - - case OP_NOT: - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - ecode++; - GETCHARINCTEST(c, eptr); - if ((ims & PCRE_CASELESS) != 0) - { -#ifdef SUPPORT_UTF8 - if (c < 256) -#endif - c = md->lcc[c]; - if (md->lcc[*ecode++] == c) RRETURN(MATCH_NOMATCH); - } - else - { - if (*ecode++ == c) RRETURN(MATCH_NOMATCH); - } - break; - - /* Match a negated single one-byte character repeatedly. This is almost a - repeat of the code for a repeated single character, but I haven't found a - nice way of commoning these up that doesn't require a test of the - positive/negative option for each character match. Maybe that wouldn't add - very much to the time taken, but character matching *is* what this is all - about... */ - - case OP_NOTEXACT: - min = max = GET2(ecode, 1); - ecode += 3; - goto REPEATNOTCHAR; - - case OP_NOTUPTO: - case OP_NOTMINUPTO: - min = 0; - max = GET2(ecode, 1); - minimize = *ecode == OP_NOTMINUPTO; - ecode += 3; - goto REPEATNOTCHAR; - - case OP_NOTPOSSTAR: - possessive = TRUE; - min = 0; - max = INT_MAX; - ecode++; - goto REPEATNOTCHAR; - - case OP_NOTPOSPLUS: - possessive = TRUE; - min = 1; - max = INT_MAX; - ecode++; - goto REPEATNOTCHAR; - - case OP_NOTPOSQUERY: - possessive = TRUE; - min = 0; - max = 1; - ecode++; - goto REPEATNOTCHAR; - - case OP_NOTPOSUPTO: - possessive = TRUE; - min = 0; - max = GET2(ecode, 1); - ecode += 3; - goto REPEATNOTCHAR; - - case OP_NOTSTAR: - case OP_NOTMINSTAR: - case OP_NOTPLUS: - case OP_NOTMINPLUS: - case OP_NOTQUERY: - case OP_NOTMINQUERY: - c = *ecode++ - OP_NOTSTAR; - minimize = (c & 1) != 0; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - - /* Common code for all repeated single-byte matches. We can give up quickly - if there are fewer than the minimum number of bytes left in the - subject. */ - - REPEATNOTCHAR: - if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH); - fc = *ecode++; - - /* The code is duplicated for the caseless and caseful cases, for speed, - since matching characters is likely to be quite common. First, ensure the - minimum number of matches are present. If min = max, continue at the same - level without recursing. Otherwise, if minimizing, keep trying the rest of - the expression and advancing one matching character if failing, up to the - maximum. Alternatively, if maximizing, find the maximum number of - characters and work backwards. */ - - DPRINTF(("negative matching %c{%d,%d} against subject %.*s\n", fc, min, max, - max, eptr)); - - if ((ims & PCRE_CASELESS) != 0) - { - fc = md->lcc[fc]; - -#ifdef SUPPORT_UTF8 - /* UTF-8 mode */ - if (utf8) - { - register unsigned int d; - for (i = 1; i <= min; i++) - { - GETCHARINC(d, eptr); - if (d < 256) d = md->lcc[d]; - if (fc == d) RRETURN(MATCH_NOMATCH); - } - } - else -#endif - - /* Not UTF-8 mode */ - { - for (i = 1; i <= min; i++) - if (fc == md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH); - } - - if (min == max) continue; - - if (minimize) - { -#ifdef SUPPORT_UTF8 - /* UTF-8 mode */ - if (utf8) - { - register unsigned int d; - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM28); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(d, eptr); - if (d < 256) d = md->lcc[d]; - if (fc == d) RRETURN(MATCH_NOMATCH); - - } - } - else -#endif - /* Not UTF-8 mode */ - { - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM29); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject || fc == md->lcc[*eptr++]) - RRETURN(MATCH_NOMATCH); - } - } - /* Control never gets here */ - } - - /* Maximize case */ - - else - { - pp = eptr; - -#ifdef SUPPORT_UTF8 - /* UTF-8 mode */ - if (utf8) - { - register unsigned int d; - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(d, eptr, len); - if (d < 256) d = md->lcc[d]; - if (fc == d) break; - eptr += len; - } - if (possessive) continue; - for(;;) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM30); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr-- == pp) break; /* Stop if tried at original pos */ - BACKCHAR(eptr); - } - } - else -#endif - /* Not UTF-8 mode */ - { - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || fc == md->lcc[*eptr]) break; - eptr++; - } - if (possessive) continue; - while (eptr >= pp) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM31); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - eptr--; - } - } - - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - } - - /* Caseful comparisons */ - - else - { -#ifdef SUPPORT_UTF8 - /* UTF-8 mode */ - if (utf8) - { - register unsigned int d; - for (i = 1; i <= min; i++) - { - GETCHARINC(d, eptr); - if (fc == d) RRETURN(MATCH_NOMATCH); - } - } - else -#endif - /* Not UTF-8 mode */ - { - for (i = 1; i <= min; i++) - if (fc == *eptr++) RRETURN(MATCH_NOMATCH); - } - - if (min == max) continue; - - if (minimize) - { -#ifdef SUPPORT_UTF8 - /* UTF-8 mode */ - if (utf8) - { - register unsigned int d; - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM32); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(d, eptr); - if (fc == d) RRETURN(MATCH_NOMATCH); - } - } - else -#endif - /* Not UTF-8 mode */ - { - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM33); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject || fc == *eptr++) - RRETURN(MATCH_NOMATCH); - } - } - /* Control never gets here */ - } - - /* Maximize case */ - - else - { - pp = eptr; - -#ifdef SUPPORT_UTF8 - /* UTF-8 mode */ - if (utf8) - { - register unsigned int d; - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(d, eptr, len); - if (fc == d) break; - eptr += len; - } - if (possessive) continue; - for(;;) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM34); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr-- == pp) break; /* Stop if tried at original pos */ - BACKCHAR(eptr); - } - } - else -#endif - /* Not UTF-8 mode */ - { - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || fc == *eptr) break; - eptr++; - } - if (possessive) continue; - while (eptr >= pp) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM35); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - eptr--; - } - } - - RRETURN(MATCH_NOMATCH); - } - } - /* Control never gets here */ - - /* Match a single character type repeatedly; several different opcodes - share code. This is very similar to the code for single characters, but we - repeat it in the interests of efficiency. */ - - case OP_TYPEEXACT: - min = max = GET2(ecode, 1); - minimize = TRUE; - ecode += 3; - goto REPEATTYPE; - - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - min = 0; - max = GET2(ecode, 1); - minimize = *ecode == OP_TYPEMINUPTO; - ecode += 3; - goto REPEATTYPE; - - case OP_TYPEPOSSTAR: - possessive = TRUE; - min = 0; - max = INT_MAX; - ecode++; - goto REPEATTYPE; - - case OP_TYPEPOSPLUS: - possessive = TRUE; - min = 1; - max = INT_MAX; - ecode++; - goto REPEATTYPE; - - case OP_TYPEPOSQUERY: - possessive = TRUE; - min = 0; - max = 1; - ecode++; - goto REPEATTYPE; - - case OP_TYPEPOSUPTO: - possessive = TRUE; - min = 0; - max = GET2(ecode, 1); - ecode += 3; - goto REPEATTYPE; - - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - c = *ecode++ - OP_TYPESTAR; - minimize = (c & 1) != 0; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - - /* Common code for all repeated single character type matches. Note that - in UTF-8 mode, '.' matches a character of any length, but for the other - character types, the valid characters are all one-byte long. */ - - REPEATTYPE: - ctype = *ecode++; /* Code for the character type */ - -#ifdef SUPPORT_UCP - if (ctype == OP_PROP || ctype == OP_NOTPROP) - { - prop_fail_result = ctype == OP_NOTPROP; - prop_type = *ecode++; - prop_value = *ecode++; - } - else prop_type = -1; -#endif - - /* First, ensure the minimum number of matches are present. Use inline - code for maximizing the speed, and do the type test once at the start - (i.e. keep it out of the loop). Also we can test that there are at least - the minimum number of bytes before we start. This isn't as effective in - UTF-8 mode, but it does no harm. Separate the UTF-8 code completely as that - is tidier. Also separate the UCP code, which can be the same for both UTF-8 - and single-bytes. */ - - if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH); - if (min > 0) - { -#ifdef SUPPORT_UCP - if (prop_type >= 0) - { - switch(prop_type) - { - case PT_ANY: - if (prop_fail_result) RRETURN(MATCH_NOMATCH); - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - } - break; - - case PT_LAMP: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - prop_chartype = UCD_CHARTYPE(c); - if ((prop_chartype == ucp_Lu || - prop_chartype == ucp_Ll || - prop_chartype == ucp_Lt) == prop_fail_result) - RRETURN(MATCH_NOMATCH); - } - break; - - case PT_GC: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - prop_category = UCD_CATEGORY(c); - if ((prop_category == prop_value) == prop_fail_result) - RRETURN(MATCH_NOMATCH); - } - break; - - case PT_PC: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - prop_chartype = UCD_CHARTYPE(c); - if ((prop_chartype == prop_value) == prop_fail_result) - RRETURN(MATCH_NOMATCH); - } - break; - - case PT_SC: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - prop_script = UCD_SCRIPT(c); - if ((prop_script == prop_value) == prop_fail_result) - RRETURN(MATCH_NOMATCH); - } - break; - - default: - RRETURN(PCRE_ERROR_INTERNAL); - } - } - - /* Match extended Unicode sequences. We will get here only if the - support is in the binary; otherwise a compile-time error occurs. */ - - else if (ctype == OP_EXTUNI) - { - for (i = 1; i <= min; i++) - { - GETCHARINCTEST(c, eptr); - prop_category = UCD_CATEGORY(c); - if (prop_category == ucp_M) RRETURN(MATCH_NOMATCH); - while (eptr < md->end_subject) - { - int len = 1; - if (!utf8) c = *eptr; else - { - GETCHARLEN(c, eptr, len); - } - prop_category = UCD_CATEGORY(c); - if (prop_category != ucp_M) break; - eptr += len; - } - } - } - - else -#endif /* SUPPORT_UCP */ - -/* Handle all other cases when the coding is UTF-8 */ - -#ifdef SUPPORT_UTF8 - if (utf8) switch(ctype) - { - case OP_ANY: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject || IS_NEWLINE(eptr)) - RRETURN(MATCH_NOMATCH); - eptr++; - while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; - } - break; - - case OP_ALLANY: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - eptr++; - while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; - } - break; - - case OP_ANYBYTE: - eptr += min; - break; - - case OP_ANYNL: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(c, eptr); - switch(c) - { - default: RRETURN(MATCH_NOMATCH); - case 0x000d: - if (eptr < md->end_subject && *eptr == 0x0a) eptr++; - break; - - case 0x000a: - break; - - case 0x000b: - case 0x000c: - case 0x0085: - case 0x2028: - case 0x2029: - if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); - break; - } - } - break; - - case OP_NOT_HSPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(c, eptr); - switch(c) - { - default: break; - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - RRETURN(MATCH_NOMATCH); - } - } - break; - - case OP_HSPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(c, eptr); - switch(c) - { - default: RRETURN(MATCH_NOMATCH); - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - break; - } - } - break; - - case OP_NOT_VSPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(c, eptr); - switch(c) - { - default: break; - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ - RRETURN(MATCH_NOMATCH); - } - } - break; - - case OP_VSPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(c, eptr); - switch(c) - { - default: RRETURN(MATCH_NOMATCH); - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ - break; - } - } - break; - - case OP_NOT_DIGIT: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(c, eptr); - if (c < 128 && (md->ctypes[c] & ctype_digit) != 0) - RRETURN(MATCH_NOMATCH); - } - break; - - case OP_DIGIT: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject || - *eptr >= 128 || (md->ctypes[*eptr++] & ctype_digit) == 0) - RRETURN(MATCH_NOMATCH); - /* No need to skip more bytes - we know it's a 1-byte character */ - } - break; - - case OP_NOT_WHITESPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject || - (*eptr < 128 && (md->ctypes[*eptr] & ctype_space) != 0)) - RRETURN(MATCH_NOMATCH); - while (++eptr < md->end_subject && (*eptr & 0xc0) == 0x80); - } - break; - - case OP_WHITESPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject || - *eptr >= 128 || (md->ctypes[*eptr++] & ctype_space) == 0) - RRETURN(MATCH_NOMATCH); - /* No need to skip more bytes - we know it's a 1-byte character */ - } - break; - - case OP_NOT_WORDCHAR: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject || - (*eptr < 128 && (md->ctypes[*eptr] & ctype_word) != 0)) - RRETURN(MATCH_NOMATCH); - while (++eptr < md->end_subject && (*eptr & 0xc0) == 0x80); - } - break; - - case OP_WORDCHAR: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject || - *eptr >= 128 || (md->ctypes[*eptr++] & ctype_word) == 0) - RRETURN(MATCH_NOMATCH); - /* No need to skip more bytes - we know it's a 1-byte character */ - } - break; - - default: - RRETURN(PCRE_ERROR_INTERNAL); - } /* End switch(ctype) */ - - else -#endif /* SUPPORT_UTF8 */ - - /* Code for the non-UTF-8 case for minimum matching of operators other - than OP_PROP and OP_NOTPROP. We can assume that there are the minimum - number of bytes present, as this was tested above. */ - - switch(ctype) - { - case OP_ANY: - for (i = 1; i <= min; i++) - { - if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); - eptr++; - } - break; - - case OP_ALLANY: - eptr += min; - break; - - case OP_ANYBYTE: - eptr += min; - break; - - /* Because of the CRLF case, we can't assume the minimum number of - bytes are present in this case. */ - - case OP_ANYNL: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - switch(*eptr++) - { - default: RRETURN(MATCH_NOMATCH); - case 0x000d: - if (eptr < md->end_subject && *eptr == 0x0a) eptr++; - break; - case 0x000a: - break; - - case 0x000b: - case 0x000c: - case 0x0085: - if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); - break; - } - } - break; - - case OP_NOT_HSPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - switch(*eptr++) - { - default: break; - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - RRETURN(MATCH_NOMATCH); - } - } - break; - - case OP_HSPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - switch(*eptr++) - { - default: RRETURN(MATCH_NOMATCH); - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - break; - } - } - break; - - case OP_NOT_VSPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - switch(*eptr++) - { - default: break; - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - RRETURN(MATCH_NOMATCH); - } - } - break; - - case OP_VSPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - switch(*eptr++) - { - default: RRETURN(MATCH_NOMATCH); - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - break; - } - } - break; - - case OP_NOT_DIGIT: - for (i = 1; i <= min; i++) - if ((md->ctypes[*eptr++] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH); - break; - - case OP_DIGIT: - for (i = 1; i <= min; i++) - if ((md->ctypes[*eptr++] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH); - break; - - case OP_NOT_WHITESPACE: - for (i = 1; i <= min; i++) - if ((md->ctypes[*eptr++] & ctype_space) != 0) RRETURN(MATCH_NOMATCH); - break; - - case OP_WHITESPACE: - for (i = 1; i <= min; i++) - if ((md->ctypes[*eptr++] & ctype_space) == 0) RRETURN(MATCH_NOMATCH); - break; - - case OP_NOT_WORDCHAR: - for (i = 1; i <= min; i++) - if ((md->ctypes[*eptr++] & ctype_word) != 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_WORDCHAR: - for (i = 1; i <= min; i++) - if ((md->ctypes[*eptr++] & ctype_word) == 0) - RRETURN(MATCH_NOMATCH); - break; - - default: - RRETURN(PCRE_ERROR_INTERNAL); - } - } - - /* If min = max, continue at the same level without recursing */ - - if (min == max) continue; - - /* If minimizing, we have to test the rest of the pattern before each - subsequent match. Again, separate the UTF-8 case for speed, and also - separate the UCP cases. */ - - if (minimize) - { -#ifdef SUPPORT_UCP - if (prop_type >= 0) - { - switch(prop_type) - { - case PT_ANY: - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM36); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(c, eptr); - if (prop_fail_result) RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - case PT_LAMP: - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM37); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(c, eptr); - prop_chartype = UCD_CHARTYPE(c); - if ((prop_chartype == ucp_Lu || - prop_chartype == ucp_Ll || - prop_chartype == ucp_Lt) == prop_fail_result) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - case PT_GC: - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM38); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(c, eptr); - prop_category = UCD_CATEGORY(c); - if ((prop_category == prop_value) == prop_fail_result) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - case PT_PC: - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM39); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(c, eptr); - prop_chartype = UCD_CHARTYPE(c); - if ((prop_chartype == prop_value) == prop_fail_result) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - case PT_SC: - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM40); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINC(c, eptr); - prop_script = UCD_SCRIPT(c); - if ((prop_script == prop_value) == prop_fail_result) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - default: - RRETURN(PCRE_ERROR_INTERNAL); - } - } - - /* Match extended Unicode sequences. We will get here only if the - support is in the binary; otherwise a compile-time error occurs. */ - - else if (ctype == OP_EXTUNI) - { - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM41); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); - GETCHARINCTEST(c, eptr); - prop_category = UCD_CATEGORY(c); - if (prop_category == ucp_M) RRETURN(MATCH_NOMATCH); - while (eptr < md->end_subject) - { - int len = 1; - if (!utf8) c = *eptr; else - { - GETCHARLEN(c, eptr, len); - } - prop_category = UCD_CATEGORY(c); - if (prop_category != ucp_M) break; - eptr += len; - } - } - } - - else -#endif /* SUPPORT_UCP */ - -#ifdef SUPPORT_UTF8 - /* UTF-8 mode */ - if (utf8) - { - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM42); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject || - (ctype == OP_ANY && IS_NEWLINE(eptr))) - RRETURN(MATCH_NOMATCH); - - GETCHARINC(c, eptr); - switch(ctype) - { - case OP_ANY: /* This is the non-NL case */ - case OP_ALLANY: - case OP_ANYBYTE: - break; - - case OP_ANYNL: - switch(c) - { - default: RRETURN(MATCH_NOMATCH); - case 0x000d: - if (eptr < md->end_subject && *eptr == 0x0a) eptr++; - break; - case 0x000a: - break; - - case 0x000b: - case 0x000c: - case 0x0085: - case 0x2028: - case 0x2029: - if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); - break; - } - break; - - case OP_NOT_HSPACE: - switch(c) - { - default: break; - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - RRETURN(MATCH_NOMATCH); - } - break; - - case OP_HSPACE: - switch(c) - { - default: RRETURN(MATCH_NOMATCH); - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - break; - } - break; - - case OP_NOT_VSPACE: - switch(c) - { - default: break; - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ - RRETURN(MATCH_NOMATCH); - } - break; - - case OP_VSPACE: - switch(c) - { - default: RRETURN(MATCH_NOMATCH); - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ - break; - } - break; - - case OP_NOT_DIGIT: - if (c < 256 && (md->ctypes[c] & ctype_digit) != 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_DIGIT: - if (c >= 256 || (md->ctypes[c] & ctype_digit) == 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_NOT_WHITESPACE: - if (c < 256 && (md->ctypes[c] & ctype_space) != 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_WHITESPACE: - if (c >= 256 || (md->ctypes[c] & ctype_space) == 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_NOT_WORDCHAR: - if (c < 256 && (md->ctypes[c] & ctype_word) != 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_WORDCHAR: - if (c >= 256 || (md->ctypes[c] & ctype_word) == 0) - RRETURN(MATCH_NOMATCH); - break; - - default: - RRETURN(PCRE_ERROR_INTERNAL); - } - } - } - else -#endif - /* Not UTF-8 mode */ - { - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM43); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max || eptr >= md->end_subject || - (ctype == OP_ANY && IS_NEWLINE(eptr))) - RRETURN(MATCH_NOMATCH); - - c = *eptr++; - switch(ctype) - { - case OP_ANY: /* This is the non-NL case */ - case OP_ALLANY: - case OP_ANYBYTE: - break; - - case OP_ANYNL: - switch(c) - { - default: RRETURN(MATCH_NOMATCH); - case 0x000d: - if (eptr < md->end_subject && *eptr == 0x0a) eptr++; - break; - - case 0x000a: - break; - - case 0x000b: - case 0x000c: - case 0x0085: - if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); - break; - } - break; - - case OP_NOT_HSPACE: - switch(c) - { - default: break; - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - RRETURN(MATCH_NOMATCH); - } - break; - - case OP_HSPACE: - switch(c) - { - default: RRETURN(MATCH_NOMATCH); - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - break; - } - break; - - case OP_NOT_VSPACE: - switch(c) - { - default: break; - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - RRETURN(MATCH_NOMATCH); - } - break; - - case OP_VSPACE: - switch(c) - { - default: RRETURN(MATCH_NOMATCH); - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - break; - } - break; - - case OP_NOT_DIGIT: - if ((md->ctypes[c] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH); - break; - - case OP_DIGIT: - if ((md->ctypes[c] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH); - break; - - case OP_NOT_WHITESPACE: - if ((md->ctypes[c] & ctype_space) != 0) RRETURN(MATCH_NOMATCH); - break; - - case OP_WHITESPACE: - if ((md->ctypes[c] & ctype_space) == 0) RRETURN(MATCH_NOMATCH); - break; - - case OP_NOT_WORDCHAR: - if ((md->ctypes[c] & ctype_word) != 0) RRETURN(MATCH_NOMATCH); - break; - - case OP_WORDCHAR: - if ((md->ctypes[c] & ctype_word) == 0) RRETURN(MATCH_NOMATCH); - break; - - default: - RRETURN(PCRE_ERROR_INTERNAL); - } - } - } - /* Control never gets here */ - } - - /* If maximizing, it is worth using inline code for speed, doing the type - test once at the start (i.e. keep it out of the loop). Again, keep the - UTF-8 and UCP stuff separate. */ - - else - { - pp = eptr; /* Remember where we started */ - -#ifdef SUPPORT_UCP - if (prop_type >= 0) - { - switch(prop_type) - { - case PT_ANY: - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len); - if (prop_fail_result) break; - eptr+= len; - } - break; - - case PT_LAMP: - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len); - prop_chartype = UCD_CHARTYPE(c); - if ((prop_chartype == ucp_Lu || - prop_chartype == ucp_Ll || - prop_chartype == ucp_Lt) == prop_fail_result) - break; - eptr+= len; - } - break; - - case PT_GC: - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len); - prop_category = UCD_CATEGORY(c); - if ((prop_category == prop_value) == prop_fail_result) - break; - eptr+= len; - } - break; - - case PT_PC: - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len); - prop_chartype = UCD_CHARTYPE(c); - if ((prop_chartype == prop_value) == prop_fail_result) - break; - eptr+= len; - } - break; - - case PT_SC: - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len); - prop_script = UCD_SCRIPT(c); - if ((prop_script == prop_value) == prop_fail_result) - break; - eptr+= len; - } - break; - } - - /* eptr is now past the end of the maximum run */ - - if (possessive) continue; - for(;;) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM44); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr-- == pp) break; /* Stop if tried at original pos */ - if (utf8) BACKCHAR(eptr); - } - } - - /* Match extended Unicode sequences. We will get here only if the - support is in the binary; otherwise a compile-time error occurs. */ - - else if (ctype == OP_EXTUNI) - { - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject) break; - GETCHARINCTEST(c, eptr); - prop_category = UCD_CATEGORY(c); - if (prop_category == ucp_M) break; - while (eptr < md->end_subject) - { - int len = 1; - if (!utf8) c = *eptr; else - { - GETCHARLEN(c, eptr, len); - } - prop_category = UCD_CATEGORY(c); - if (prop_category != ucp_M) break; - eptr += len; - } - } - - /* eptr is now past the end of the maximum run */ - - if (possessive) continue; - for(;;) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM45); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr-- == pp) break; /* Stop if tried at original pos */ - for (;;) /* Move back over one extended */ - { - int len = 1; - if (!utf8) c = *eptr; else - { - BACKCHAR(eptr); - GETCHARLEN(c, eptr, len); - } - prop_category = UCD_CATEGORY(c); - if (prop_category != ucp_M) break; - eptr--; - } - } - } - - else -#endif /* SUPPORT_UCP */ - -#ifdef SUPPORT_UTF8 - /* UTF-8 mode */ - - if (utf8) - { - switch(ctype) - { - case OP_ANY: - if (max < INT_MAX) - { - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || IS_NEWLINE(eptr)) break; - eptr++; - while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; - } - } - - /* Handle unlimited UTF-8 repeat */ - - else - { - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || IS_NEWLINE(eptr)) break; - eptr++; - while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; - } - } - break; - - case OP_ALLANY: - if (max < INT_MAX) - { - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject) break; - eptr++; - while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; - } - } - else eptr = md->end_subject; /* Unlimited UTF-8 repeat */ - break; - - /* The byte case is the same as non-UTF8 */ - - case OP_ANYBYTE: - c = max - min; - if (c > (unsigned int)(md->end_subject - eptr)) - c = md->end_subject - eptr; - eptr += c; - break; - - case OP_ANYNL: - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len); - if (c == 0x000d) - { - if (++eptr >= md->end_subject) break; - if (*eptr == 0x000a) eptr++; - } - else - { - if (c != 0x000a && - (md->bsr_anycrlf || - (c != 0x000b && c != 0x000c && - c != 0x0085 && c != 0x2028 && c != 0x2029))) - break; - eptr += len; - } - } - break; - - case OP_NOT_HSPACE: - case OP_HSPACE: - for (i = min; i < max; i++) - { - BOOL gotspace; - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len); - switch(c) - { - default: gotspace = FALSE; break; - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - gotspace = TRUE; - break; - } - if (gotspace == (ctype == OP_NOT_HSPACE)) break; - eptr += len; - } - break; - - case OP_NOT_VSPACE: - case OP_VSPACE: - for (i = min; i < max; i++) - { - BOOL gotspace; - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len); - switch(c) - { - default: gotspace = FALSE; break; - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ - gotspace = TRUE; - break; - } - if (gotspace == (ctype == OP_NOT_VSPACE)) break; - eptr += len; - } - break; - - case OP_NOT_DIGIT: - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len); - if (c < 256 && (md->ctypes[c] & ctype_digit) != 0) break; - eptr+= len; - } - break; - - case OP_DIGIT: - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len); - if (c >= 256 ||(md->ctypes[c] & ctype_digit) == 0) break; - eptr+= len; - } - break; - - case OP_NOT_WHITESPACE: - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len); - if (c < 256 && (md->ctypes[c] & ctype_space) != 0) break; - eptr+= len; - } - break; - - case OP_WHITESPACE: - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len); - if (c >= 256 ||(md->ctypes[c] & ctype_space) == 0) break; - eptr+= len; - } - break; - - case OP_NOT_WORDCHAR: - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len); - if (c < 256 && (md->ctypes[c] & ctype_word) != 0) break; - eptr+= len; - } - break; - - case OP_WORDCHAR: - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len); - if (c >= 256 || (md->ctypes[c] & ctype_word) == 0) break; - eptr+= len; - } - break; - - default: - RRETURN(PCRE_ERROR_INTERNAL); - } - - /* eptr is now past the end of the maximum run */ - - if (possessive) continue; - for(;;) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM46); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr-- == pp) break; /* Stop if tried at original pos */ - BACKCHAR(eptr); - } - } - else -#endif /* SUPPORT_UTF8 */ - - /* Not UTF-8 mode */ - { - switch(ctype) - { - case OP_ANY: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || IS_NEWLINE(eptr)) break; - eptr++; - } - break; - - case OP_ALLANY: - case OP_ANYBYTE: - c = max - min; - if (c > (unsigned int)(md->end_subject - eptr)) - c = md->end_subject - eptr; - eptr += c; - break; - - case OP_ANYNL: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject) break; - c = *eptr; - if (c == 0x000d) - { - if (++eptr >= md->end_subject) break; - if (*eptr == 0x000a) eptr++; - } - else - { - if (c != 0x000a && - (md->bsr_anycrlf || - (c != 0x000b && c != 0x000c && c != 0x0085))) - break; - eptr++; - } - } - break; - - case OP_NOT_HSPACE: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject) break; - c = *eptr; - if (c == 0x09 || c == 0x20 || c == 0xa0) break; - eptr++; - } - break; - - case OP_HSPACE: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject) break; - c = *eptr; - if (c != 0x09 && c != 0x20 && c != 0xa0) break; - eptr++; - } - break; - - case OP_NOT_VSPACE: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject) break; - c = *eptr; - if (c == 0x0a || c == 0x0b || c == 0x0c || c == 0x0d || c == 0x85) - break; - eptr++; - } - break; - - case OP_VSPACE: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject) break; - c = *eptr; - if (c != 0x0a && c != 0x0b && c != 0x0c && c != 0x0d && c != 0x85) - break; - eptr++; - } - break; - - case OP_NOT_DIGIT: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) != 0) - break; - eptr++; - } - break; - - case OP_DIGIT: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) == 0) - break; - eptr++; - } - break; - - case OP_NOT_WHITESPACE: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) != 0) - break; - eptr++; - } - break; - - case OP_WHITESPACE: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) == 0) - break; - eptr++; - } - break; - - case OP_NOT_WORDCHAR: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) != 0) - break; - eptr++; - } - break; - - case OP_WORDCHAR: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) == 0) - break; - eptr++; - } - break; - - default: - RRETURN(PCRE_ERROR_INTERNAL); - } - - /* eptr is now past the end of the maximum run */ - - if (possessive) continue; - while (eptr >= pp) - { - RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM47); - eptr--; - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - } - } - - /* Get here if we can't make it match with any permitted repetitions */ - - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - /* There's been some horrible disaster. Arrival here can only mean there is - something seriously wrong in the code above or the OP_xxx definitions. */ - - default: - DPRINTF(("Unknown opcode %d\n", *ecode)); - RRETURN(PCRE_ERROR_UNKNOWN_OPCODE); - } - - /* Do not stick any code in here without much thought; it is assumed - that "continue" in the code above comes out to here to repeat the main - loop. */ - - } /* End of main loop */ -/* Control never reaches here */ - - -/* When compiling to use the heap rather than the stack for recursive calls to -match(), the RRETURN() macro jumps here. The number that is saved in -frame->Xwhere indicates which label we actually want to return to. */ - -#ifdef NO_RECURSE -#define LBL(val) case val: goto L_RM##val; -HEAP_RETURN: -switch (frame->Xwhere) - { - LBL( 1) LBL( 2) LBL( 3) LBL( 4) LBL( 5) LBL( 6) LBL( 7) LBL( 8) - LBL( 9) LBL(10) LBL(11) LBL(12) LBL(13) LBL(14) LBL(15) LBL(17) - LBL(19) LBL(24) LBL(25) LBL(26) LBL(27) LBL(29) LBL(31) LBL(33) - LBL(35) LBL(43) LBL(47) LBL(48) LBL(49) LBL(50) LBL(51) LBL(52) - LBL(53) LBL(54) -#ifdef SUPPORT_UTF8 - LBL(16) LBL(18) LBL(20) LBL(21) LBL(22) LBL(23) LBL(28) LBL(30) - LBL(32) LBL(34) LBL(42) LBL(46) -#ifdef SUPPORT_UCP - LBL(36) LBL(37) LBL(38) LBL(39) LBL(40) LBL(41) LBL(44) LBL(45) -#endif /* SUPPORT_UCP */ -#endif /* SUPPORT_UTF8 */ - default: - DPRINTF(("jump error in pcre match: label %d non-existent\n", frame->Xwhere)); - return PCRE_ERROR_INTERNAL; - } -#undef LBL -#endif /* NO_RECURSE */ -} - - -/*************************************************************************** -**************************************************************************** - RECURSION IN THE match() FUNCTION - -Undefine all the macros that were defined above to handle this. */ - -#ifdef NO_RECURSE -#undef eptr -#undef ecode -#undef mstart -#undef offset_top -#undef ims -#undef eptrb -#undef flags - -#undef callpat -#undef charptr -#undef data -#undef next -#undef pp -#undef prev -#undef saved_eptr - -#undef new_recursive - -#undef cur_is_word -#undef condition -#undef prev_is_word - -#undef original_ims - -#undef ctype -#undef length -#undef max -#undef min -#undef number -#undef offset -#undef op -#undef save_capture_last -#undef save_offset1 -#undef save_offset2 -#undef save_offset3 -#undef stacksave - -#undef newptrb - -#endif - -/* These two are defined as macros in both cases */ - -#undef fc -#undef fi - -/*************************************************************************** -***************************************************************************/ - - - -/************************************************* -* Execute a Regular Expression * -*************************************************/ - -/* This function applies a compiled re to a subject string and picks out -portions of the string if it matches. Two elements in the vector are set for -each substring: the offsets to the start and end of the substring. - -Arguments: - argument_re points to the compiled expression - extra_data points to extra data or is NULL - subject points to the subject string - length length of subject string (may contain binary zeros) - start_offset where to start in the subject string - options option bits - offsets points to a vector of ints to be filled in with offsets - offsetcount the number of elements in the vector - -Returns: > 0 => success; value is the number of elements filled in - = 0 => success, but offsets is not big enough - -1 => failed to match - < -1 => some kind of unexpected problem -*/ - -PCRE_EXP_DEFN int PCRE_CALL_CONVENTION -pcre_exec(const pcre *argument_re, const pcre_extra *extra_data, - PCRE_SPTR subject, int length, int start_offset, int options, int *offsets, - int offsetcount) -{ -int rc, resetcount, ocount; -int first_byte = -1; -int req_byte = -1; -int req_byte2 = -1; -int newline; -unsigned long int ims; -BOOL using_temporary_offsets = FALSE; -BOOL anchored; -BOOL startline; -BOOL firstline; -BOOL first_byte_caseless = FALSE; -BOOL req_byte_caseless = FALSE; -BOOL utf8; -match_data match_block; -match_data *md = &match_block; -const uschar *tables; -const uschar *start_bits = NULL; -USPTR start_match = (USPTR)subject + start_offset; -USPTR end_subject; -USPTR req_byte_ptr = start_match - 1; - -pcre_study_data internal_study; -const pcre_study_data *study; - -real_pcre internal_re; -const real_pcre *external_re = (const real_pcre *)argument_re; -const real_pcre *re = external_re; - -/* Plausibility checks */ - -if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION; -if (re == NULL || subject == NULL || - (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL; -if (offsetcount < 0) return PCRE_ERROR_BADCOUNT; - -/* Fish out the optional data from the extra_data structure, first setting -the default values. */ - -study = NULL; -md->match_limit = MATCH_LIMIT; -md->match_limit_recursion = MATCH_LIMIT_RECURSION; -md->callout_data = NULL; - -/* The table pointer is always in native byte order. */ - -tables = external_re->tables; - -if (extra_data != NULL) - { - register unsigned int flags = extra_data->flags; - if ((flags & PCRE_EXTRA_STUDY_DATA) != 0) - study = (const pcre_study_data *)extra_data->study_data; - if ((flags & PCRE_EXTRA_MATCH_LIMIT) != 0) - md->match_limit = extra_data->match_limit; - if ((flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION) != 0) - md->match_limit_recursion = extra_data->match_limit_recursion; - if ((flags & PCRE_EXTRA_CALLOUT_DATA) != 0) - md->callout_data = extra_data->callout_data; - if ((flags & PCRE_EXTRA_TABLES) != 0) tables = extra_data->tables; - } - -/* If the exec call supplied NULL for tables, use the inbuilt ones. This -is a feature that makes it possible to save compiled regex and re-use them -in other programs later. */ - -if (tables == NULL) tables = _pcre_default_tables; - -/* Check that the first field in the block is the magic number. If it is not, -test for a regex that was compiled on a host of opposite endianness. If this is -the case, flipped values are put in internal_re and internal_study if there was -study data too. */ - -if (re->magic_number != MAGIC_NUMBER) - { - re = _pcre_try_flipped(re, &internal_re, study, &internal_study); - if (re == NULL) return PCRE_ERROR_BADMAGIC; - if (study != NULL) study = &internal_study; - } - -/* Set up other data */ - -anchored = ((re->options | options) & PCRE_ANCHORED) != 0; -startline = (re->flags & PCRE_STARTLINE) != 0; -firstline = (re->options & PCRE_FIRSTLINE) != 0; - -/* The code starts after the real_pcre block and the capture name table. */ - -md->start_code = (const uschar *)external_re + re->name_table_offset + - re->name_count * re->name_entry_size; - -md->start_subject = (USPTR)subject; -md->start_offset = start_offset; -md->end_subject = md->start_subject + length; -end_subject = md->end_subject; - -md->endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0; -utf8 = md->utf8 = (re->options & PCRE_UTF8) != 0; -md->jscript_compat = (re->options & PCRE_JAVASCRIPT_COMPAT) != 0; - -md->notbol = (options & PCRE_NOTBOL) != 0; -md->noteol = (options & PCRE_NOTEOL) != 0; -md->notempty = (options & PCRE_NOTEMPTY) != 0; -md->partial = (options & PCRE_PARTIAL) != 0; -md->hitend = FALSE; - -md->recursive = NULL; /* No recursion at top level */ - -md->lcc = tables + lcc_offset; -md->ctypes = tables + ctypes_offset; - -/* Handle different \R options. */ - -switch (options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) - { - case 0: - if ((re->options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) != 0) - md->bsr_anycrlf = (re->options & PCRE_BSR_ANYCRLF) != 0; - else -#ifdef BSR_ANYCRLF - md->bsr_anycrlf = TRUE; -#else - md->bsr_anycrlf = FALSE; -#endif - break; - - case PCRE_BSR_ANYCRLF: - md->bsr_anycrlf = TRUE; - break; - - case PCRE_BSR_UNICODE: - md->bsr_anycrlf = FALSE; - break; - - default: return PCRE_ERROR_BADNEWLINE; - } - -/* Handle different types of newline. The three bits give eight cases. If -nothing is set at run time, whatever was used at compile time applies. */ - -switch ((((options & PCRE_NEWLINE_BITS) == 0)? re->options : - (pcre_uint32)options) & PCRE_NEWLINE_BITS) - { - case 0: newline = NEWLINE; break; /* Compile-time default */ - case PCRE_NEWLINE_CR: newline = '\r'; break; - case PCRE_NEWLINE_LF: newline = '\n'; break; - case PCRE_NEWLINE_CR+ - PCRE_NEWLINE_LF: newline = ('\r' << 8) | '\n'; break; - case PCRE_NEWLINE_ANY: newline = -1; break; - case PCRE_NEWLINE_ANYCRLF: newline = -2; break; - default: return PCRE_ERROR_BADNEWLINE; - } - -if (newline == -2) - { - md->nltype = NLTYPE_ANYCRLF; - } -else if (newline < 0) - { - md->nltype = NLTYPE_ANY; - } -else - { - md->nltype = NLTYPE_FIXED; - if (newline > 255) - { - md->nllen = 2; - md->nl[0] = (newline >> 8) & 255; - md->nl[1] = newline & 255; - } - else - { - md->nllen = 1; - md->nl[0] = newline; - } - } - -/* Partial matching is supported only for a restricted set of regexes at the -moment. */ - -if (md->partial && (re->flags & PCRE_NOPARTIAL) != 0) - return PCRE_ERROR_BADPARTIAL; - -/* Check a UTF-8 string if required. Unfortunately there's no way of passing -back the character offset. */ - -#ifdef SUPPORT_UTF8 -if (utf8 && (options & PCRE_NO_UTF8_CHECK) == 0) - { - if (_pcre_valid_utf8((uschar *)subject, length) >= 0) - return PCRE_ERROR_BADUTF8; - if (start_offset > 0 && start_offset < length) - { - int tb = ((uschar *)subject)[start_offset]; - if (tb > 127) - { - tb &= 0xc0; - if (tb != 0 && tb != 0xc0) return PCRE_ERROR_BADUTF8_OFFSET; - } - } - } -#endif - -/* The ims options can vary during the matching as a result of the presence -of (?ims) items in the pattern. They are kept in a local variable so that -restoring at the exit of a group is easy. */ - -ims = re->options & (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL); - -/* If the expression has got more back references than the offsets supplied can -hold, we get a temporary chunk of working store to use during the matching. -Otherwise, we can use the vector supplied, rounding down its size to a multiple -of 3. */ - -ocount = offsetcount - (offsetcount % 3); - -if (re->top_backref > 0 && re->top_backref >= ocount/3) - { - ocount = re->top_backref * 3 + 3; - md->offset_vector = (int *)(pcre_malloc)(ocount * sizeof(int)); - if (md->offset_vector == NULL) return PCRE_ERROR_NOMEMORY; - using_temporary_offsets = TRUE; - DPRINTF(("Got memory to hold back references\n")); - } -else md->offset_vector = offsets; - -md->offset_end = ocount; -md->offset_max = (2*ocount)/3; -md->offset_overflow = FALSE; -md->capture_last = -1; - -/* Compute the minimum number of offsets that we need to reset each time. Doing -this makes a huge difference to execution time when there aren't many brackets -in the pattern. */ - -resetcount = 2 + re->top_bracket * 2; -if (resetcount > offsetcount) resetcount = ocount; - -/* Reset the working variable associated with each extraction. These should -never be used unless previously set, but they get saved and restored, and so we -initialize them to avoid reading uninitialized locations. */ - -if (md->offset_vector != NULL) - { - register int *iptr = md->offset_vector + ocount; - register int *iend = iptr - resetcount/2 + 1; - while (--iptr >= iend) *iptr = -1; - } - -/* Set up the first character to match, if available. The first_byte value is -never set for an anchored regular expression, but the anchoring may be forced -at run time, so we have to test for anchoring. The first char may be unset for -an unanchored pattern, of course. If there's no first char and the pattern was -studied, there may be a bitmap of possible first characters. */ - -if (!anchored) - { - if ((re->flags & PCRE_FIRSTSET) != 0) - { - first_byte = re->first_byte & 255; - if ((first_byte_caseless = ((re->first_byte & REQ_CASELESS) != 0)) == TRUE) - first_byte = md->lcc[first_byte]; - } - else - if (!startline && study != NULL && - (study->options & PCRE_STUDY_MAPPED) != 0) - start_bits = study->start_bits; - } - -/* For anchored or unanchored matches, there may be a "last known required -character" set. */ - -if ((re->flags & PCRE_REQCHSET) != 0) - { - req_byte = re->req_byte & 255; - req_byte_caseless = (re->req_byte & REQ_CASELESS) != 0; - req_byte2 = (tables + fcc_offset)[req_byte]; /* case flipped */ - } - - -/* ==========================================================================*/ - -/* Loop for handling unanchored repeated matching attempts; for anchored regexs -the loop runs just once. */ - -for(;;) - { - USPTR save_end_subject = end_subject; - USPTR new_start_match; - - /* Reset the maximum number of extractions we might see. */ - - if (md->offset_vector != NULL) - { - register int *iptr = md->offset_vector; - register int *iend = iptr + resetcount; - while (iptr < iend) *iptr++ = -1; - } - - /* Advance to a unique first char if possible. If firstline is TRUE, the - start of the match is constrained to the first line of a multiline string. - That is, the match must be before or at the first newline. Implement this by - temporarily adjusting end_subject so that we stop scanning at a newline. If - the match fails at the newline, later code breaks this loop. */ - - if (firstline) - { - USPTR t = start_match; -#ifdef SUPPORT_UTF8 - if (utf8) - { - while (t < md->end_subject && !IS_NEWLINE(t)) - { - t++; - while (t < end_subject && (*t & 0xc0) == 0x80) t++; - } - } - else -#endif - while (t < md->end_subject && !IS_NEWLINE(t)) t++; - end_subject = t; - } - - /* Now advance to a unique first byte if there is one. */ - - if (first_byte >= 0) - { - if (first_byte_caseless) - while (start_match < end_subject && md->lcc[*start_match] != first_byte) - start_match++; - else - while (start_match < end_subject && *start_match != first_byte) - start_match++; - } - - /* Or to just after a linebreak for a multiline match */ - - else if (startline) - { - if (start_match > md->start_subject + start_offset) - { -#ifdef SUPPORT_UTF8 - if (utf8) - { - while (start_match < end_subject && !WAS_NEWLINE(start_match)) - { - start_match++; - while(start_match < end_subject && (*start_match & 0xc0) == 0x80) - start_match++; - } - } - else -#endif - while (start_match < end_subject && !WAS_NEWLINE(start_match)) - start_match++; - - /* If we have just passed a CR and the newline option is ANY or ANYCRLF, - and we are now at a LF, advance the match position by one more character. - */ - - if (start_match[-1] == '\r' && - (md->nltype == NLTYPE_ANY || md->nltype == NLTYPE_ANYCRLF) && - start_match < end_subject && - *start_match == '\n') - start_match++; - } - } - - /* Or to a non-unique first byte after study */ - - else if (start_bits != NULL) - { - while (start_match < end_subject) - { - register unsigned int c = *start_match; - if ((start_bits[c/8] & (1 << (c&7))) == 0) start_match++; - else break; - } - } - - /* Restore fudged end_subject */ - - end_subject = save_end_subject; - -#ifdef DEBUG /* Sigh. Some compilers never learn. */ - printf(">>>> Match against: "); - pchars(start_match, end_subject - start_match, TRUE, md); - printf("\n"); -#endif - - /* If req_byte is set, we know that that character must appear in the subject - for the match to succeed. If the first character is set, req_byte must be - later in the subject; otherwise the test starts at the match point. This - optimization can save a huge amount of backtracking in patterns with nested - unlimited repeats that aren't going to match. Writing separate code for - cased/caseless versions makes it go faster, as does using an autoincrement - and backing off on a match. - - HOWEVER: when the subject string is very, very long, searching to its end can - take a long time, and give bad performance on quite ordinary patterns. This - showed up when somebody was matching something like /^\d+C/ on a 32-megabyte - string... so we don't do this when the string is sufficiently long. - - ALSO: this processing is disabled when partial matching is requested. - */ - - if (req_byte >= 0 && - end_subject - start_match < REQ_BYTE_MAX && - !md->partial) - { - register USPTR p = start_match + ((first_byte >= 0)? 1 : 0); - - /* We don't need to repeat the search if we haven't yet reached the - place we found it at last time. */ - - if (p > req_byte_ptr) - { - if (req_byte_caseless) - { - while (p < end_subject) - { - register int pp = *p++; - if (pp == req_byte || pp == req_byte2) { p--; break; } - } - } - else - { - while (p < end_subject) - { - if (*p++ == req_byte) { p--; break; } - } - } - - /* If we can't find the required character, break the matching loop, - forcing a match failure. */ - - if (p >= end_subject) - { - rc = MATCH_NOMATCH; - break; - } - - /* If we have found the required character, save the point where we - found it, so that we don't search again next time round the loop if - the start hasn't passed this character yet. */ - - req_byte_ptr = p; - } - } - - /* OK, we can now run the match. */ - - md->start_match_ptr = start_match; - md->match_call_count = 0; - rc = match(start_match, md->start_code, start_match, 2, md, ims, NULL, 0, 0); - - switch(rc) - { - /* NOMATCH and PRUNE advance by one character. THEN at this level acts - exactly like PRUNE. */ - - case MATCH_NOMATCH: - case MATCH_PRUNE: - case MATCH_THEN: - new_start_match = start_match + 1; -#ifdef SUPPORT_UTF8 - if (utf8) - while(new_start_match < end_subject && (*new_start_match & 0xc0) == 0x80) - new_start_match++; -#endif - break; - - /* SKIP passes back the next starting point explicitly. */ - - case MATCH_SKIP: - new_start_match = md->start_match_ptr; - break; - - /* COMMIT disables the bumpalong, but otherwise behaves as NOMATCH. */ - - case MATCH_COMMIT: - rc = MATCH_NOMATCH; - goto ENDLOOP; - - /* Any other return is some kind of error. */ - - default: - goto ENDLOOP; - } - - /* Control reaches here for the various types of "no match at this point" - result. Reset the code to MATCH_NOMATCH for subsequent checking. */ - - rc = MATCH_NOMATCH; - - /* If PCRE_FIRSTLINE is set, the match must happen before or at the first - newline in the subject (though it may continue over the newline). Therefore, - if we have just failed to match, starting at a newline, do not continue. */ - - if (firstline && IS_NEWLINE(start_match)) break; - - /* Advance to new matching position */ - - start_match = new_start_match; - - /* Break the loop if the pattern is anchored or if we have passed the end of - the subject. */ - - if (anchored || start_match > end_subject) break; - - /* If we have just passed a CR and we are now at a LF, and the pattern does - not contain any explicit matches for \r or \n, and the newline option is CRLF - or ANY or ANYCRLF, advance the match position by one more character. */ - - if (start_match[-1] == '\r' && - start_match < end_subject && - *start_match == '\n' && - (re->flags & PCRE_HASCRORLF) == 0 && - (md->nltype == NLTYPE_ANY || - md->nltype == NLTYPE_ANYCRLF || - md->nllen == 2)) - start_match++; - - } /* End of for(;;) "bumpalong" loop */ - -/* ==========================================================================*/ - -/* We reach here when rc is not MATCH_NOMATCH, or if one of the stopping -conditions is true: - -(1) The pattern is anchored or the match was failed by (*COMMIT); - -(2) We are past the end of the subject; - -(3) PCRE_FIRSTLINE is set and we have failed to match at a newline, because - this option requests that a match occur at or before the first newline in - the subject. - -When we have a match and the offset vector is big enough to deal with any -backreferences, captured substring offsets will already be set up. In the case -where we had to get some local store to hold offsets for backreference -processing, copy those that we can. In this case there need not be overflow if -certain parts of the pattern were not used, even though there are more -capturing parentheses than vector slots. */ - -ENDLOOP: - -if (rc == MATCH_MATCH) - { - if (using_temporary_offsets) - { - if (offsetcount >= 4) - { - memcpy(offsets + 2, md->offset_vector + 2, - (offsetcount - 2) * sizeof(int)); - DPRINTF(("Copied offsets from temporary memory\n")); - } - if (md->end_offset_top > offsetcount) md->offset_overflow = TRUE; - DPRINTF(("Freeing temporary memory\n")); - (pcre_free)(md->offset_vector); - } - - /* Set the return code to the number of captured strings, or 0 if there are - too many to fit into the vector. */ - - rc = md->offset_overflow? 0 : md->end_offset_top/2; - - /* If there is space, set up the whole thing as substring 0. The value of - md->start_match_ptr might be modified if \K was encountered on the success - matching path. */ - - if (offsetcount < 2) rc = 0; else - { - offsets[0] = md->start_match_ptr - md->start_subject; - offsets[1] = md->end_match_ptr - md->start_subject; - } - - DPRINTF((">>>> returning %d\n", rc)); - return rc; - } - -/* Control gets here if there has been an error, or if the overall match -attempt has failed at all permitted starting positions. */ - -if (using_temporary_offsets) - { - DPRINTF(("Freeing temporary memory\n")); - (pcre_free)(md->offset_vector); - } - -if (rc != MATCH_NOMATCH) - { - DPRINTF((">>>> error: returning %d\n", rc)); - return rc; - } -else if (md->partial && md->hitend) - { - DPRINTF((">>>> returning PCRE_ERROR_PARTIAL\n")); - return PCRE_ERROR_PARTIAL; - } -else - { - DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n")); - return PCRE_ERROR_NOMATCH; - } -} - -/* End of pcre_exec.c */ diff --git a/glib/pcre/pcre_fullinfo.c b/glib/pcre/pcre_fullinfo.c deleted file mode 100644 index 30566bbc0..000000000 --- a/glib/pcre/pcre_fullinfo.c +++ /dev/null @@ -1,165 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains the external function pcre_fullinfo(), which returns -information about a compiled pattern. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre_internal.h" - - -/************************************************* -* Return info about compiled pattern * -*************************************************/ - -/* This is a newer "info" function which has an extensible interface so -that additional items can be added compatibly. - -Arguments: - argument_re points to compiled code - extra_data points extra data, or NULL - what what information is required - where where to put the information - -Returns: 0 if data returned, negative on error -*/ - -PCRE_EXP_DEFN int PCRE_CALL_CONVENTION -pcre_fullinfo(const pcre *argument_re, const pcre_extra *extra_data, int what, - void *where) -{ -real_pcre internal_re; -pcre_study_data internal_study; -const real_pcre *re = (const real_pcre *)argument_re; -const pcre_study_data *study = NULL; - -if (re == NULL || where == NULL) return PCRE_ERROR_NULL; - -if (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_STUDY_DATA) != 0) - study = (const pcre_study_data *)extra_data->study_data; - -if (re->magic_number != MAGIC_NUMBER) - { - re = _pcre_try_flipped(re, &internal_re, study, &internal_study); - if (re == NULL) return PCRE_ERROR_BADMAGIC; - if (study != NULL) study = &internal_study; - } - -switch (what) - { - case PCRE_INFO_OPTIONS: - *((unsigned long int *)where) = re->options & PUBLIC_OPTIONS; - break; - - case PCRE_INFO_SIZE: - *((size_t *)where) = re->size; - break; - - case PCRE_INFO_STUDYSIZE: - *((size_t *)where) = (study == NULL)? 0 : study->size; - break; - - case PCRE_INFO_CAPTURECOUNT: - *((int *)where) = re->top_bracket; - break; - - case PCRE_INFO_BACKREFMAX: - *((int *)where) = re->top_backref; - break; - - case PCRE_INFO_FIRSTBYTE: - *((int *)where) = - ((re->flags & PCRE_FIRSTSET) != 0)? re->first_byte : - ((re->flags & PCRE_STARTLINE) != 0)? -1 : -2; - break; - - /* Make sure we pass back the pointer to the bit vector in the external - block, not the internal copy (with flipped integer fields). */ - - case PCRE_INFO_FIRSTTABLE: - *((const uschar **)where) = - (study != NULL && (study->options & PCRE_STUDY_MAPPED) != 0)? - ((const pcre_study_data *)extra_data->study_data)->start_bits : NULL; - break; - - case PCRE_INFO_LASTLITERAL: - *((int *)where) = - ((re->flags & PCRE_REQCHSET) != 0)? re->req_byte : -1; - break; - - case PCRE_INFO_NAMEENTRYSIZE: - *((int *)where) = re->name_entry_size; - break; - - case PCRE_INFO_NAMECOUNT: - *((int *)where) = re->name_count; - break; - - case PCRE_INFO_NAMETABLE: - *((const uschar **)where) = (const uschar *)re + re->name_table_offset; - break; - - case PCRE_INFO_DEFAULT_TABLES: - *((const uschar **)where) = (const uschar *)(_pcre_default_tables); - break; - - case PCRE_INFO_OKPARTIAL: - *((int *)where) = (re->flags & PCRE_NOPARTIAL) == 0; - break; - - case PCRE_INFO_JCHANGED: - *((int *)where) = (re->flags & PCRE_JCHANGED) != 0; - break; - - case PCRE_INFO_HASCRORLF: - *((int *)where) = (re->flags & PCRE_HASCRORLF) != 0; - break; - - default: return PCRE_ERROR_BADOPTION; - } - -return 0; -} - -/* End of pcre_fullinfo.c */ diff --git a/glib/pcre/pcre_get.c b/glib/pcre/pcre_get.c deleted file mode 100644 index 611778640..000000000 --- a/glib/pcre/pcre_get.c +++ /dev/null @@ -1,465 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains some convenience functions for extracting substrings -from the subject string after a regex match has succeeded. The original idea -for these functions came from Scott Wimer. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre_internal.h" - - -/************************************************* -* Find number for named string * -*************************************************/ - -/* This function is used by the get_first_set() function below, as well -as being generally available. It assumes that names are unique. - -Arguments: - code the compiled regex - stringname the name whose number is required - -Returns: the number of the named parentheses, or a negative number - (PCRE_ERROR_NOSUBSTRING) if not found -*/ - -PCRE_EXP_DEFN int PCRE_CALL_CONVENTION -pcre_get_stringnumber(const pcre *code, const char *stringname) -{ -int rc; -int entrysize; -int top, bot; -uschar *nametable; - -if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0) - return rc; -if (top <= 0) return PCRE_ERROR_NOSUBSTRING; - -if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0) - return rc; -if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0) - return rc; - -bot = 0; -while (top > bot) - { - int mid = (top + bot) / 2; - uschar *entry = nametable + entrysize*mid; - int c = strcmp(stringname, (char *)(entry + 2)); - if (c == 0) return (entry[0] << 8) + entry[1]; - if (c > 0) bot = mid + 1; else top = mid; - } - -return PCRE_ERROR_NOSUBSTRING; -} - - - -/************************************************* -* Find (multiple) entries for named string * -*************************************************/ - -/* This is used by the get_first_set() function below, as well as being -generally available. It is used when duplicated names are permitted. - -Arguments: - code the compiled regex - stringname the name whose entries required - firstptr where to put the pointer to the first entry - lastptr where to put the pointer to the last entry - -Returns: the length of each entry, or a negative number - (PCRE_ERROR_NOSUBSTRING) if not found -*/ - -PCRE_EXP_DEFN int PCRE_CALL_CONVENTION -pcre_get_stringtable_entries(const pcre *code, const char *stringname, - char **firstptr, char **lastptr) -{ -int rc; -int entrysize; -int top, bot; -uschar *nametable, *lastentry; - -if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0) - return rc; -if (top <= 0) return PCRE_ERROR_NOSUBSTRING; - -if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0) - return rc; -if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0) - return rc; - -lastentry = nametable + entrysize * (top - 1); -bot = 0; -while (top > bot) - { - int mid = (top + bot) / 2; - uschar *entry = nametable + entrysize*mid; - int c = strcmp(stringname, (char *)(entry + 2)); - if (c == 0) - { - uschar *first = entry; - uschar *last = entry; - while (first > nametable) - { - if (strcmp(stringname, (char *)(first - entrysize + 2)) != 0) break; - first -= entrysize; - } - while (last < lastentry) - { - if (strcmp(stringname, (char *)(last + entrysize + 2)) != 0) break; - last += entrysize; - } - *firstptr = (char *)first; - *lastptr = (char *)last; - return entrysize; - } - if (c > 0) bot = mid + 1; else top = mid; - } - -return PCRE_ERROR_NOSUBSTRING; -} - - - -/************************************************* -* Find first set of multiple named strings * -*************************************************/ - -/* This function allows for duplicate names in the table of named substrings. -It returns the number of the first one that was set in a pattern match. - -Arguments: - code the compiled regex - stringname the name of the capturing substring - ovector the vector of matched substrings - -Returns: the number of the first that is set, - or the number of the last one if none are set, - or a negative number on error -*/ - -static int -get_first_set(const pcre *code, const char *stringname, int *ovector) -{ -const real_pcre *re = (const real_pcre *)code; -int entrysize; -char *first, *last; -uschar *entry; -if ((re->options & PCRE_DUPNAMES) == 0 && (re->flags & PCRE_JCHANGED) == 0) - return pcre_get_stringnumber(code, stringname); -entrysize = pcre_get_stringtable_entries(code, stringname, &first, &last); -if (entrysize <= 0) return entrysize; -for (entry = (uschar *)first; entry <= (uschar *)last; entry += entrysize) - { - int n = (entry[0] << 8) + entry[1]; - if (ovector[n*2] >= 0) return n; - } -return (first[0] << 8) + first[1]; -} - - - - -/************************************************* -* Copy captured string to given buffer * -*************************************************/ - -/* This function copies a single captured substring into a given buffer. -Note that we use memcpy() rather than strncpy() in case there are binary zeros -in the string. - -Arguments: - subject the subject string that was matched - ovector pointer to the offsets table - stringcount the number of substrings that were captured - (i.e. the yield of the pcre_exec call, unless - that was zero, in which case it should be 1/3 - of the offset table size) - stringnumber the number of the required substring - buffer where to put the substring - size the size of the buffer - -Returns: if successful: - the length of the copied string, not including the zero - that is put on the end; can be zero - if not successful: - PCRE_ERROR_NOMEMORY (-6) buffer too small - PCRE_ERROR_NOSUBSTRING (-7) no such captured substring -*/ - -PCRE_EXP_DEFN int PCRE_CALL_CONVENTION -pcre_copy_substring(const char *subject, int *ovector, int stringcount, - int stringnumber, char *buffer, int size) -{ -int yield; -if (stringnumber < 0 || stringnumber >= stringcount) - return PCRE_ERROR_NOSUBSTRING; -stringnumber *= 2; -yield = ovector[stringnumber+1] - ovector[stringnumber]; -if (size < yield + 1) return PCRE_ERROR_NOMEMORY; -memcpy(buffer, subject + ovector[stringnumber], yield); -buffer[yield] = 0; -return yield; -} - - - -/************************************************* -* Copy named captured string to given buffer * -*************************************************/ - -/* This function copies a single captured substring into a given buffer, -identifying it by name. If the regex permits duplicate names, the first -substring that is set is chosen. - -Arguments: - code the compiled regex - subject the subject string that was matched - ovector pointer to the offsets table - stringcount the number of substrings that were captured - (i.e. the yield of the pcre_exec call, unless - that was zero, in which case it should be 1/3 - of the offset table size) - stringname the name of the required substring - buffer where to put the substring - size the size of the buffer - -Returns: if successful: - the length of the copied string, not including the zero - that is put on the end; can be zero - if not successful: - PCRE_ERROR_NOMEMORY (-6) buffer too small - PCRE_ERROR_NOSUBSTRING (-7) no such captured substring -*/ - -PCRE_EXP_DEFN int PCRE_CALL_CONVENTION -pcre_copy_named_substring(const pcre *code, const char *subject, int *ovector, - int stringcount, const char *stringname, char *buffer, int size) -{ -int n = get_first_set(code, stringname, ovector); -if (n <= 0) return n; -return pcre_copy_substring(subject, ovector, stringcount, n, buffer, size); -} - - - -/************************************************* -* Copy all captured strings to new store * -*************************************************/ - -/* This function gets one chunk of store and builds a list of pointers and all -of the captured substrings in it. A NULL pointer is put on the end of the list. - -Arguments: - subject the subject string that was matched - ovector pointer to the offsets table - stringcount the number of substrings that were captured - (i.e. the yield of the pcre_exec call, unless - that was zero, in which case it should be 1/3 - of the offset table size) - listptr set to point to the list of pointers - -Returns: if successful: 0 - if not successful: - PCRE_ERROR_NOMEMORY (-6) failed to get store -*/ - -PCRE_EXP_DEFN int PCRE_CALL_CONVENTION -pcre_get_substring_list(const char *subject, int *ovector, int stringcount, - const char ***listptr) -{ -int i; -int size = sizeof(char *); -int double_count = stringcount * 2; -char **stringlist; -char *p; - -for (i = 0; i < double_count; i += 2) - size += sizeof(char *) + ovector[i+1] - ovector[i] + 1; - -stringlist = (char **)(pcre_malloc)(size); -if (stringlist == NULL) return PCRE_ERROR_NOMEMORY; - -*listptr = (const char **)stringlist; -p = (char *)(stringlist + stringcount + 1); - -for (i = 0; i < double_count; i += 2) - { - int len = ovector[i+1] - ovector[i]; - memcpy(p, subject + ovector[i], len); - *stringlist++ = p; - p += len; - *p++ = 0; - } - -*stringlist = NULL; -return 0; -} - - - -/************************************************* -* Free store obtained by get_substring_list * -*************************************************/ - -/* This function exists for the benefit of people calling PCRE from non-C -programs that can call its functions, but not free() or (pcre_free)() directly. - -Argument: the result of a previous pcre_get_substring_list() -Returns: nothing -*/ - -PCRE_EXP_DEFN void PCRE_CALL_CONVENTION -pcre_free_substring_list(const char **pointer) -{ -(pcre_free)((void *)pointer); -} - - - -/************************************************* -* Copy captured string to new store * -*************************************************/ - -/* This function copies a single captured substring into a piece of new -store - -Arguments: - subject the subject string that was matched - ovector pointer to the offsets table - stringcount the number of substrings that were captured - (i.e. the yield of the pcre_exec call, unless - that was zero, in which case it should be 1/3 - of the offset table size) - stringnumber the number of the required substring - stringptr where to put a pointer to the substring - -Returns: if successful: - the length of the string, not including the zero that - is put on the end; can be zero - if not successful: - PCRE_ERROR_NOMEMORY (-6) failed to get store - PCRE_ERROR_NOSUBSTRING (-7) substring not present -*/ - -PCRE_EXP_DEFN int PCRE_CALL_CONVENTION -pcre_get_substring(const char *subject, int *ovector, int stringcount, - int stringnumber, const char **stringptr) -{ -int yield; -char *substring; -if (stringnumber < 0 || stringnumber >= stringcount) - return PCRE_ERROR_NOSUBSTRING; -stringnumber *= 2; -yield = ovector[stringnumber+1] - ovector[stringnumber]; -substring = (char *)(pcre_malloc)(yield + 1); -if (substring == NULL) return PCRE_ERROR_NOMEMORY; -memcpy(substring, subject + ovector[stringnumber], yield); -substring[yield] = 0; -*stringptr = substring; -return yield; -} - - - -/************************************************* -* Copy named captured string to new store * -*************************************************/ - -/* This function copies a single captured substring, identified by name, into -new store. If the regex permits duplicate names, the first substring that is -set is chosen. - -Arguments: - code the compiled regex - subject the subject string that was matched - ovector pointer to the offsets table - stringcount the number of substrings that were captured - (i.e. the yield of the pcre_exec call, unless - that was zero, in which case it should be 1/3 - of the offset table size) - stringname the name of the required substring - stringptr where to put the pointer - -Returns: if successful: - the length of the copied string, not including the zero - that is put on the end; can be zero - if not successful: - PCRE_ERROR_NOMEMORY (-6) couldn't get memory - PCRE_ERROR_NOSUBSTRING (-7) no such captured substring -*/ - -PCRE_EXP_DEFN int PCRE_CALL_CONVENTION -pcre_get_named_substring(const pcre *code, const char *subject, int *ovector, - int stringcount, const char *stringname, const char **stringptr) -{ -int n = get_first_set(code, stringname, ovector); -if (n <= 0) return n; -return pcre_get_substring(subject, ovector, stringcount, n, stringptr); -} - - - - -/************************************************* -* Free store obtained by get_substring * -*************************************************/ - -/* This function exists for the benefit of people calling PCRE from non-C -programs that can call its functions, but not free() or (pcre_free)() directly. - -Argument: the result of a previous pcre_get_substring() -Returns: nothing -*/ - -PCRE_EXP_DEFN void PCRE_CALL_CONVENTION -pcre_free_substring(const char *pointer) -{ -(pcre_free)((void *)pointer); -} - -/* End of pcre_get.c */ diff --git a/glib/pcre/pcre_globals.c b/glib/pcre/pcre_globals.c deleted file mode 100644 index e759ed5ce..000000000 --- a/glib/pcre/pcre_globals.c +++ /dev/null @@ -1,57 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains global variables that are exported by the PCRE library. -PCRE is thread-clean and doesn't use any global variables in the normal sense. -However, it calls memory allocation and freeing functions via the four -indirections below, and it can optionally do callouts, using the fifth -indirection. These values can be changed by the caller, but are shared between -all threads. However, when compiling for Virtual Pascal, things are done -differently, and global variables are not used (see pcre.in). */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre_internal.h" - -PCRE_EXP_DATA_DEFN int (*pcre_callout)(pcre_callout_block *) = NULL; - -/* End of pcre_globals.c */ diff --git a/glib/pcre/pcre_info.c b/glib/pcre/pcre_info.c deleted file mode 100644 index 02cf1c91d..000000000 --- a/glib/pcre/pcre_info.c +++ /dev/null @@ -1,93 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains the external function pcre_info(), which gives some -information about a compiled pattern. However, use of this function is now -deprecated, as it has been superseded by pcre_fullinfo(). */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre_internal.h" - - -/************************************************* -* (Obsolete) Return info about compiled pattern * -*************************************************/ - -/* This is the original "info" function. It picks potentially useful data out -of the private structure, but its interface was too rigid. It remains for -backwards compatibility. The public options are passed back in an int - though -the re->options field has been expanded to a long int, all the public options -at the low end of it, and so even on 16-bit systems this will still be OK. -Therefore, I haven't changed the API for pcre_info(). - -Arguments: - argument_re points to compiled code - optptr where to pass back the options - first_byte where to pass back the first character, - or -1 if multiline and all branches start ^, - or -2 otherwise - -Returns: number of capturing subpatterns - or negative values on error -*/ - -PCRE_EXP_DEFN int PCRE_CALL_CONVENTION -pcre_info(const pcre *argument_re, int *optptr, int *first_byte) -{ -real_pcre internal_re; -const real_pcre *re = (const real_pcre *)argument_re; -if (re == NULL) return PCRE_ERROR_NULL; -if (re->magic_number != MAGIC_NUMBER) - { - re = _pcre_try_flipped(re, &internal_re, NULL, NULL); - if (re == NULL) return PCRE_ERROR_BADMAGIC; - } -if (optptr != NULL) *optptr = (int)(re->options & PUBLIC_OPTIONS); -if (first_byte != NULL) - *first_byte = ((re->flags & PCRE_FIRSTSET) != 0)? re->first_byte : - ((re->flags & PCRE_STARTLINE) != 0)? -1 : -2; -return re->top_bracket; -} - -/* End of pcre_info.c */ diff --git a/glib/pcre/pcre_internal.h b/glib/pcre/pcre_internal.h deleted file mode 100644 index 519b8712a..000000000 --- a/glib/pcre/pcre_internal.h +++ /dev/null @@ -1,1157 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - -/* This header contains definitions that are shared between the different -modules, but which are not relevant to the exported API. This includes some -functions whose names all begin with "_pcre_". */ - -#ifndef PCRE_INTERNAL_H -#define PCRE_INTERNAL_H - -/* Define DEBUG to get debugging output on stdout. */ - -#if 0 -#define DEBUG -#endif - -/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef -inline, and there are *still* stupid compilers about that don't like indented -pre-processor statements, or at least there were when I first wrote this. After -all, it had only been about 10 years then... - -It turns out that the Mac Debugging.h header also defines the macro DPRINTF, so -be absolutely sure we get our version. */ - -#undef DPRINTF -#ifdef DEBUG -#define DPRINTF(p) printf p -#else -#define DPRINTF(p) /* Nothing */ -#endif - - -/* Standard C headers plus the external interface definition. The only time -setjmp and stdarg are used is when NO_RECURSE is set. */ - -#include <ctype.h> -#include <limits.h> -#include <setjmp.h> -#include <stdarg.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -/* When compiling a DLL for Windows, the exported symbols have to be declared -using some MS magic. I found some useful information on this web page: -http://msdn2.microsoft.com/en-us/library/y4h7bcy6(VS.80).aspx. According to the -information there, using __declspec(dllexport) without "extern" we have a -definition; with "extern" we have a declaration. The settings here override the -setting in pcre.h (which is included below); it defines only PCRE_EXP_DECL, -which is all that is needed for applications (they just import the symbols). We -use: - - PCRE_EXP_DECL for declarations - PCRE_EXP_DEFN for definitions of exported functions - PCRE_EXP_DATA_DEFN for definitions of exported variables - -The reason for the two DEFN macros is that in non-Windows environments, one -does not want to have "extern" before variable definitions because it leads to -compiler warnings. So we distinguish between functions and variables. In -Windows, the two should always be the same. - -The reason for wrapping this in #ifndef PCRE_EXP_DECL is so that pcretest, -which is an application, but needs to import this file in order to "peek" at -internals, can #include pcre.h first to get an application's-eye view. - -In principle, people compiling for non-Windows, non-Unix-like (i.e. uncommon, -special-purpose environments) might want to stick other stuff in front of -exported symbols. That's why, in the non-Windows case, we set PCRE_EXP_DEFN and -PCRE_EXP_DATA_DEFN only if they are not already set. */ - -#ifndef PCRE_EXP_DECL -# ifdef _WIN32 -# ifndef PCRE_STATIC -# define PCRE_EXP_DECL extern __declspec(dllexport) -# define PCRE_EXP_DEFN __declspec(dllexport) -# define PCRE_EXP_DATA_DEFN __declspec(dllexport) -# else -# define PCRE_EXP_DECL extern -# define PCRE_EXP_DEFN -# define PCRE_EXP_DATA_DEFN -# endif -# else -# ifdef __cplusplus -# define PCRE_EXP_DECL extern "C" -# else -# define PCRE_EXP_DECL extern -# endif -# ifndef PCRE_EXP_DEFN -# define PCRE_EXP_DEFN PCRE_EXP_DECL -# endif -# ifndef PCRE_EXP_DATA_DEFN -# define PCRE_EXP_DATA_DEFN -# endif -# endif -#endif - -/* When compiling with the MSVC compiler, it is sometimes necessary to include -a "calling convention" before exported function names. (This is secondhand -information; I know nothing about MSVC myself). For example, something like - - void __cdecl function(....) - -might be needed. In order so make this easy, all the exported functions have -PCRE_CALL_CONVENTION just before their names. It is rarely needed; if not -set, we ensure here that it has no effect. */ - -#ifndef PCRE_CALL_CONVENTION -#define PCRE_CALL_CONVENTION -#endif - -/* We need to have types that specify unsigned 16-bit and 32-bit integers. We -cannot determine these outside the compilation (e.g. by running a program as -part of "configure") because PCRE is often cross-compiled for use on other -systems. Instead we make use of the maximum sizes that are available at -preprocessor time in standard C environments. */ - -#if USHRT_MAX == 65535 - typedef unsigned short pcre_uint16; - typedef short pcre_int16; -#elif UINT_MAX == 65535 - typedef unsigned int pcre_uint16; - typedef int pcre_int16; -#else - #error Cannot determine a type for 16-bit unsigned integers -#endif - -#if UINT_MAX == 4294967295 - typedef unsigned int pcre_uint32; - typedef int pcre_int32; -#elif ULONG_MAX == 4294967295 - typedef unsigned long int pcre_uint32; - typedef long int pcre_int32; -#else - #error Cannot determine a type for 32-bit unsigned integers -#endif - -/* All character handling must be done as unsigned characters. Otherwise there -are problems with top-bit-set characters and functions such as isspace(). -However, we leave the interface to the outside world as char *, because that -should make things easier for callers. We define a short type for unsigned char -to save lots of typing. I tried "uchar", but it causes problems on Digital -Unix, where it is defined in sys/types, so use "uschar" instead. */ - -typedef unsigned char uschar; - -/* This is an unsigned int value that no character can ever have. UTF-8 -characters only go up to 0x7fffffff (though Unicode doesn't go beyond -0x0010ffff). */ - -#define NOTACHAR 0xffffffff - -/* PCRE is able to support several different kinds of newline (CR, LF, CRLF, -"any" and "anycrlf" at present). The following macros are used to package up -testing for newlines. NLBLOCK, PSSTART, and PSEND are defined in the various -modules to indicate in which datablock the parameters exist, and what the -start/end of string field names are. */ - -#define NLTYPE_FIXED 0 /* Newline is a fixed length string */ -#define NLTYPE_ANY 1 /* Newline is any Unicode line ending */ -#define NLTYPE_ANYCRLF 2 /* Newline is CR, LF, or CRLF */ - -/* This macro checks for a newline at the given position */ - -#define IS_NEWLINE(p) \ - ((NLBLOCK->nltype != NLTYPE_FIXED)? \ - ((p) < NLBLOCK->PSEND && \ - _pcre_is_newline((p), NLBLOCK->nltype, NLBLOCK->PSEND, &(NLBLOCK->nllen),\ - utf8)) \ - : \ - ((p) <= NLBLOCK->PSEND - NLBLOCK->nllen && \ - (p)[0] == NLBLOCK->nl[0] && \ - (NLBLOCK->nllen == 1 || (p)[1] == NLBLOCK->nl[1]) \ - ) \ - ) - -/* This macro checks for a newline immediately preceding the given position */ - -#define WAS_NEWLINE(p) \ - ((NLBLOCK->nltype != NLTYPE_FIXED)? \ - ((p) > NLBLOCK->PSSTART && \ - _pcre_was_newline((p), NLBLOCK->nltype, NLBLOCK->PSSTART, \ - &(NLBLOCK->nllen), utf8)) \ - : \ - ((p) >= NLBLOCK->PSSTART + NLBLOCK->nllen && \ - (p)[-NLBLOCK->nllen] == NLBLOCK->nl[0] && \ - (NLBLOCK->nllen == 1 || (p)[-NLBLOCK->nllen+1] == NLBLOCK->nl[1]) \ - ) \ - ) - -/* When PCRE is compiled as a C++ library, the subject pointer can be replaced -with a custom type. This makes it possible, for example, to allow pcre_exec() -to process subject strings that are discontinuous by using a smart pointer -class. It must always be possible to inspect all of the subject string in -pcre_exec() because of the way it backtracks. Two macros are required in the -normal case, for sign-unspecified and unsigned char pointers. The former is -used for the external interface and appears in pcre.h, which is why its name -must begin with PCRE_. */ - -#ifdef CUSTOM_SUBJECT_PTR -#define PCRE_SPTR CUSTOM_SUBJECT_PTR -#define USPTR CUSTOM_SUBJECT_PTR -#else -#define PCRE_SPTR const char * -#define USPTR const unsigned char * -#endif - - - -/* Include the public PCRE header and the definitions of UCP character property -values. */ - -#include "pcre.h" -#include "ucp.h" - -/* When compiling for use with the Virtual Pascal compiler, these functions -need to have their names changed. PCRE must be compiled with the -DVPCOMPAT -option on the command line. */ - -#ifdef VPCOMPAT -#define strlen(s) _strlen(s) -#define strncmp(s1,s2,m) _strncmp(s1,s2,m) -#define memcmp(s,c,n) _memcmp(s,c,n) -#define memcpy(d,s,n) _memcpy(d,s,n) -#define memset(s,c,n) _memset(s,c,n) -#else /* VPCOMPAT */ - -/* To cope with SunOS4 and other systems that lack memmove() but have bcopy(), -define a macro for memmove() if HAVE_MEMMOVE is false, provided that HAVE_BCOPY -is set. Otherwise, include an emulating function for those systems that have -neither (there some non-Unix environments where this is the case). */ - -#ifndef HAVE_MEMMOVE -#undef memmove /* some systems may have a macro */ -#ifdef HAVE_BCOPY -#define memmove(a, b, c) bcopy(b, a, c) -#else /* HAVE_BCOPY */ -static void * -pcre_memmove(void *d, const void *s, size_t n) -{ -size_t i; -unsigned char *dest = (unsigned char *)d; -const unsigned char *src = (const unsigned char *)s; -if (dest > src) - { - dest += n; - src += n; - for (i = 0; i < n; ++i) *(--dest) = *(--src); - return (void *)dest; - } -else - { - for (i = 0; i < n; ++i) *dest++ = *src++; - return (void *)(dest - n); - } -} -#define memmove(a, b, c) pcre_memmove(a, b, c) -#endif /* not HAVE_BCOPY */ -#endif /* not HAVE_MEMMOVE */ -#endif /* not VPCOMPAT */ - - -/* PCRE keeps offsets in its compiled code as 2-byte quantities (always stored -in big-endian order) by default. These are used, for example, to link from the -start of a subpattern to its alternatives and its end. The use of 2 bytes per -offset limits the size of the compiled regex to around 64K, which is big enough -for almost everybody. However, I received a request for an even bigger limit. -For this reason, and also to make the code easier to maintain, the storing and -loading of offsets from the byte string is now handled by the macros that are -defined here. - -The macros are controlled by the value of LINK_SIZE. This defaults to 2 in -the config.h file, but can be overridden by using -D on the command line. This -is automated on Unix systems via the "configure" command. */ - -#if LINK_SIZE == 2 - -#define PUT(a,n,d) \ - (a[n] = (d) >> 8), \ - (a[(n)+1] = (d) & 255) - -#define GET(a,n) \ - (((a)[n] << 8) | (a)[(n)+1]) - -#define MAX_PATTERN_SIZE (1 << 16) - - -#elif LINK_SIZE == 3 - -#define PUT(a,n,d) \ - (a[n] = (d) >> 16), \ - (a[(n)+1] = (d) >> 8), \ - (a[(n)+2] = (d) & 255) - -#define GET(a,n) \ - (((a)[n] << 16) | ((a)[(n)+1] << 8) | (a)[(n)+2]) - -#define MAX_PATTERN_SIZE (1 << 24) - - -#elif LINK_SIZE == 4 - -#define PUT(a,n,d) \ - (a[n] = (d) >> 24), \ - (a[(n)+1] = (d) >> 16), \ - (a[(n)+2] = (d) >> 8), \ - (a[(n)+3] = (d) & 255) - -#define GET(a,n) \ - (((a)[n] << 24) | ((a)[(n)+1] << 16) | ((a)[(n)+2] << 8) | (a)[(n)+3]) - -#define MAX_PATTERN_SIZE (1 << 30) /* Keep it positive */ - - -#else -#error LINK_SIZE must be either 2, 3, or 4 -#endif - - -/* Convenience macro defined in terms of the others */ - -#define PUTINC(a,n,d) PUT(a,n,d), a += LINK_SIZE - - -/* PCRE uses some other 2-byte quantities that do not change when the size of -offsets changes. There are used for repeat counts and for other things such as -capturing parenthesis numbers in back references. */ - -#define PUT2(a,n,d) \ - a[n] = (d) >> 8; \ - a[(n)+1] = (d) & 255 - -#define GET2(a,n) \ - (((a)[n] << 8) | (a)[(n)+1]) - -#define PUT2INC(a,n,d) PUT2(a,n,d), a += 2 - - -/* When UTF-8 encoding is being used, a character is no longer just a single -byte. The macros for character handling generate simple sequences when used in -byte-mode, and more complicated ones for UTF-8 characters. BACKCHAR should -never be called in byte mode. To make sure it can never even appear when UTF-8 -support is omitted, we don't even define it. */ - -#ifndef SUPPORT_UTF8 -#define GETCHAR(c, eptr) c = *eptr; -#define GETCHARTEST(c, eptr) c = *eptr; -#define GETCHARINC(c, eptr) c = *eptr++; -#define GETCHARINCTEST(c, eptr) c = *eptr++; -#define GETCHARLEN(c, eptr, len) c = *eptr; -/* #define BACKCHAR(eptr) */ - -#else /* SUPPORT_UTF8 */ - -/* Get the next UTF-8 character, not advancing the pointer. This is called when -we know we are in UTF-8 mode. */ - -#define GETCHAR(c, eptr) \ - c = *eptr; \ - if (c >= 0xc0) \ - { \ - int gcii; \ - int gcaa = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ - int gcss = 6*gcaa; \ - c = (c & _pcre_utf8_table3[gcaa]) << gcss; \ - for (gcii = 1; gcii <= gcaa; gcii++) \ - { \ - gcss -= 6; \ - c |= (eptr[gcii] & 0x3f) << gcss; \ - } \ - } - -/* Get the next UTF-8 character, testing for UTF-8 mode, and not advancing the -pointer. */ - -#define GETCHARTEST(c, eptr) \ - c = *eptr; \ - if (utf8 && c >= 0xc0) \ - { \ - int gcii; \ - int gcaa = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ - int gcss = 6*gcaa; \ - c = (c & _pcre_utf8_table3[gcaa]) << gcss; \ - for (gcii = 1; gcii <= gcaa; gcii++) \ - { \ - gcss -= 6; \ - c |= (eptr[gcii] & 0x3f) << gcss; \ - } \ - } - -/* Get the next UTF-8 character, advancing the pointer. This is called when we -know we are in UTF-8 mode. */ - -#define GETCHARINC(c, eptr) \ - c = *eptr++; \ - if (c >= 0xc0) \ - { \ - int gcaa = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ - int gcss = 6*gcaa; \ - c = (c & _pcre_utf8_table3[gcaa]) << gcss; \ - while (gcaa-- > 0) \ - { \ - gcss -= 6; \ - c |= (*eptr++ & 0x3f) << gcss; \ - } \ - } - -/* Get the next character, testing for UTF-8 mode, and advancing the pointer */ - -#define GETCHARINCTEST(c, eptr) \ - c = *eptr++; \ - if (utf8 && c >= 0xc0) \ - { \ - int gcaa = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ - int gcss = 6*gcaa; \ - c = (c & _pcre_utf8_table3[gcaa]) << gcss; \ - while (gcaa-- > 0) \ - { \ - gcss -= 6; \ - c |= (*eptr++ & 0x3f) << gcss; \ - } \ - } - -/* Get the next UTF-8 character, not advancing the pointer, incrementing length -if there are extra bytes. This is called when we know we are in UTF-8 mode. */ - -#define GETCHARLEN(c, eptr, len) \ - c = *eptr; \ - if (c >= 0xc0) \ - { \ - int gcii; \ - int gcaa = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ - int gcss = 6*gcaa; \ - c = (c & _pcre_utf8_table3[gcaa]) << gcss; \ - for (gcii = 1; gcii <= gcaa; gcii++) \ - { \ - gcss -= 6; \ - c |= (eptr[gcii] & 0x3f) << gcss; \ - } \ - len += gcaa; \ - } - -/* If the pointer is not at the start of a character, move it back until -it is. This is called only in UTF-8 mode - we don't put a test within the macro -because almost all calls are already within a block of UTF-8 only code. */ - -#define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr-- - -#endif - - -/* In case there is no definition of offsetof() provided - though any proper -Standard C system should have one. */ - -#ifndef offsetof -#define offsetof(p_type,field) ((size_t)&(((p_type *)0)->field)) -#endif - - -/* These are the public options that can change during matching. */ - -#define PCRE_IMS (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL) - -/* Private flags containing information about the compiled regex. They used to -live at the top end of the options word, but that got almost full, so now they -are in a 16-bit flags word. */ - -#define PCRE_NOPARTIAL 0x0001 /* can't use partial with this regex */ -#define PCRE_FIRSTSET 0x0002 /* first_byte is set */ -#define PCRE_REQCHSET 0x0004 /* req_byte is set */ -#define PCRE_STARTLINE 0x0008 /* start after \n for multiline */ -#define PCRE_JCHANGED 0x0010 /* j option used in regex */ -#define PCRE_HASCRORLF 0x0020 /* explicit \r or \n in pattern */ - -/* Options for the "extra" block produced by pcre_study(). */ - -#define PCRE_STUDY_MAPPED 0x01 /* a map of starting chars exists */ - -/* Masks for identifying the public options that are permitted at compile -time, run time, or study time, respectively. */ - -#define PCRE_NEWLINE_BITS (PCRE_NEWLINE_CR|PCRE_NEWLINE_LF|PCRE_NEWLINE_ANY| \ - PCRE_NEWLINE_ANYCRLF) - -#define PUBLIC_OPTIONS \ - (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \ - PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8| \ - PCRE_NO_AUTO_CAPTURE|PCRE_NO_UTF8_CHECK|PCRE_AUTO_CALLOUT|PCRE_FIRSTLINE| \ - PCRE_DUPNAMES|PCRE_NEWLINE_BITS|PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE| \ - PCRE_JAVASCRIPT_COMPAT) - -#define PUBLIC_EXEC_OPTIONS \ - (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NO_UTF8_CHECK| \ - PCRE_PARTIAL|PCRE_NEWLINE_BITS|PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE) - -#define PUBLIC_DFA_EXEC_OPTIONS \ - (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NO_UTF8_CHECK| \ - PCRE_PARTIAL|PCRE_DFA_SHORTEST|PCRE_DFA_RESTART|PCRE_NEWLINE_BITS| \ - PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE) - -#define PUBLIC_STUDY_OPTIONS 0 /* None defined */ - -/* Magic number to provide a small check against being handed junk. Also used -to detect whether a pattern was compiled on a host of different endianness. */ - -#define MAGIC_NUMBER 0x50435245UL /* 'PCRE' */ - -/* Negative values for the firstchar and reqchar variables */ - -#define REQ_UNSET (-2) -#define REQ_NONE (-1) - -/* The maximum remaining length of subject we are prepared to search for a -req_byte match. */ - -#define REQ_BYTE_MAX 1000 - -/* Flags added to firstbyte or reqbyte; a "non-literal" item is either a -variable-length repeat, or a anything other than literal characters. */ - -#define REQ_CASELESS 0x0100 /* indicates caselessness */ -#define REQ_VARY 0x0200 /* reqbyte followed non-literal item */ - -/* Miscellaneous definitions. The #ifndef is to pacify compiler warnings in -environments where these macros are defined elsewhere. */ - -typedef gboolean BOOL; - -/* Escape items that are just an encoding of a particular data value. */ - -#ifndef ESC_e -#define ESC_e 27 -#endif - -#ifndef ESC_f -#define ESC_f '\f' -#endif - -#ifndef ESC_n -#define ESC_n '\n' -#endif - -#ifndef ESC_r -#define ESC_r '\r' -#endif - -/* We can't officially use ESC_t because it is a POSIX reserved identifier -(presumably because of all the others like size_t). */ - -#ifndef ESC_tee -#define ESC_tee '\t' -#endif - -/* Codes for different types of Unicode property */ - -#define PT_ANY 0 /* Any property - matches all chars */ -#define PT_LAMP 1 /* L& - the union of Lu, Ll, Lt */ -#define PT_GC 2 /* General characteristic (e.g. L) */ -#define PT_PC 3 /* Particular characteristic (e.g. Lu) */ -#define PT_SC 4 /* Script (e.g. Han) */ - -/* Flag bits and data types for the extended class (OP_XCLASS) for classes that -contain UTF-8 characters with values greater than 255. */ - -#define XCL_NOT 0x01 /* Flag: this is a negative class */ -#define XCL_MAP 0x02 /* Flag: a 32-byte map is present */ - -#define XCL_END 0 /* Marks end of individual items */ -#define XCL_SINGLE 1 /* Single item (one multibyte char) follows */ -#define XCL_RANGE 2 /* A range (two multibyte chars) follows */ -#define XCL_PROP 3 /* Unicode property (2-byte property code follows) */ -#define XCL_NOTPROP 4 /* Unicode inverted property (ditto) */ - -/* These are escaped items that aren't just an encoding of a particular data -value such as \n. They must have non-zero values, as check_escape() returns -their negation. Also, they must appear in the same order as in the opcode -definitions below, up to ESC_z. There's a dummy for OP_ANY because it -corresponds to "." rather than an escape sequence, and another for OP_ALLANY -(which is used for [^] in JavaScript compatibility mode). - -The final escape must be ESC_REF as subsequent values are used for -backreferences (\1, \2, \3, etc). There are two tests in the code for an escape -greater than ESC_b and less than ESC_Z to detect the types that may be -repeated. These are the types that consume characters. If any new escapes are -put in between that don't consume a character, that code will have to change. -*/ - -enum { ESC_A = 1, ESC_G, ESC_K, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, - ESC_W, ESC_w, ESC_dum1, ESC_dum2, ESC_C, ESC_P, ESC_p, ESC_R, ESC_H, - ESC_h, ESC_V, ESC_v, ESC_X, ESC_Z, ESC_z, ESC_E, ESC_Q, ESC_g, ESC_k, - ESC_REF }; - - -/* Opcode table: Starting from 1 (i.e. after OP_END), the values up to -OP_EOD must correspond in order to the list of escapes immediately above. - -*** NOTE NOTE NOTE *** Whenever this list is updated, the two macro definitions -that follow must also be updated to match. There is also a table called -"coptable" in pcre_dfa_exec.c that must be updated. */ - -enum { - OP_END, /* 0 End of pattern */ - - /* Values corresponding to backslashed metacharacters */ - - OP_SOD, /* 1 Start of data: \A */ - OP_SOM, /* 2 Start of match (subject + offset): \G */ - OP_SET_SOM, /* 3 Set start of match (\K) */ - OP_NOT_WORD_BOUNDARY, /* 4 \B */ - OP_WORD_BOUNDARY, /* 5 \b */ - OP_NOT_DIGIT, /* 6 \D */ - OP_DIGIT, /* 7 \d */ - OP_NOT_WHITESPACE, /* 8 \S */ - OP_WHITESPACE, /* 9 \s */ - OP_NOT_WORDCHAR, /* 10 \W */ - OP_WORDCHAR, /* 11 \w */ - OP_ANY, /* 12 Match any character (subject to DOTALL) */ - OP_ALLANY, /* 13 Match any character (not subject to DOTALL) */ - OP_ANYBYTE, /* 14 Match any byte (\C); different to OP_ANY for UTF-8 */ - OP_NOTPROP, /* 15 \P (not Unicode property) */ - OP_PROP, /* 16 \p (Unicode property) */ - OP_ANYNL, /* 17 \R (any newline sequence) */ - OP_NOT_HSPACE, /* 18 \H (not horizontal whitespace) */ - OP_HSPACE, /* 19 \h (horizontal whitespace) */ - OP_NOT_VSPACE, /* 20 \V (not vertical whitespace) */ - OP_VSPACE, /* 21 \v (vertical whitespace) */ - OP_EXTUNI, /* 22 \X (extended Unicode sequence */ - OP_EODN, /* 23 End of data or \n at end of data: \Z. */ - OP_EOD, /* 24 End of data: \z */ - - OP_OPT, /* 25 Set runtime options */ - OP_CIRC, /* 26 Start of line - varies with multiline switch */ - OP_DOLL, /* 27 End of line - varies with multiline switch */ - OP_CHAR, /* 28 Match one character, casefully */ - OP_CHARNC, /* 29 Match one character, caselessly */ - OP_NOT, /* 30 Match one character, not the following one */ - - OP_STAR, /* 31 The maximizing and minimizing versions of */ - OP_MINSTAR, /* 32 these six opcodes must come in pairs, with */ - OP_PLUS, /* 33 the minimizing one second. */ - OP_MINPLUS, /* 34 This first set applies to single characters.*/ - OP_QUERY, /* 35 */ - OP_MINQUERY, /* 36 */ - - OP_UPTO, /* 37 From 0 to n matches */ - OP_MINUPTO, /* 38 */ - OP_EXACT, /* 39 Exactly n matches */ - - OP_POSSTAR, /* 40 Possessified star */ - OP_POSPLUS, /* 41 Possessified plus */ - OP_POSQUERY, /* 42 Posesssified query */ - OP_POSUPTO, /* 43 Possessified upto */ - - OP_NOTSTAR, /* 44 The maximizing and minimizing versions of */ - OP_NOTMINSTAR, /* 45 these six opcodes must come in pairs, with */ - OP_NOTPLUS, /* 46 the minimizing one second. They must be in */ - OP_NOTMINPLUS, /* 47 exactly the same order as those above. */ - OP_NOTQUERY, /* 48 This set applies to "not" single characters. */ - OP_NOTMINQUERY, /* 49 */ - - OP_NOTUPTO, /* 50 From 0 to n matches */ - OP_NOTMINUPTO, /* 51 */ - OP_NOTEXACT, /* 52 Exactly n matches */ - - OP_NOTPOSSTAR, /* 53 Possessified versions */ - OP_NOTPOSPLUS, /* 54 */ - OP_NOTPOSQUERY, /* 55 */ - OP_NOTPOSUPTO, /* 56 */ - - OP_TYPESTAR, /* 57 The maximizing and minimizing versions of */ - OP_TYPEMINSTAR, /* 58 these six opcodes must come in pairs, with */ - OP_TYPEPLUS, /* 59 the minimizing one second. These codes must */ - OP_TYPEMINPLUS, /* 60 be in exactly the same order as those above. */ - OP_TYPEQUERY, /* 61 This set applies to character types such as \d */ - OP_TYPEMINQUERY, /* 62 */ - - OP_TYPEUPTO, /* 63 From 0 to n matches */ - OP_TYPEMINUPTO, /* 64 */ - OP_TYPEEXACT, /* 65 Exactly n matches */ - - OP_TYPEPOSSTAR, /* 66 Possessified versions */ - OP_TYPEPOSPLUS, /* 67 */ - OP_TYPEPOSQUERY, /* 68 */ - OP_TYPEPOSUPTO, /* 69 */ - - OP_CRSTAR, /* 70 The maximizing and minimizing versions of */ - OP_CRMINSTAR, /* 71 all these opcodes must come in pairs, with */ - OP_CRPLUS, /* 72 the minimizing one second. These codes must */ - OP_CRMINPLUS, /* 73 be in exactly the same order as those above. */ - OP_CRQUERY, /* 74 These are for character classes and back refs */ - OP_CRMINQUERY, /* 75 */ - OP_CRRANGE, /* 76 These are different to the three sets above. */ - OP_CRMINRANGE, /* 77 */ - - OP_CLASS, /* 78 Match a character class, chars < 256 only */ - OP_NCLASS, /* 79 Same, but the bitmap was created from a negative - class - the difference is relevant only when a UTF-8 - character > 255 is encountered. */ - - OP_XCLASS, /* 80 Extended class for handling UTF-8 chars within the - class. This does both positive and negative. */ - - OP_REF, /* 81 Match a back reference */ - OP_RECURSE, /* 82 Match a numbered subpattern (possibly recursive) */ - OP_CALLOUT, /* 83 Call out to external function if provided */ - - OP_ALT, /* 84 Start of alternation */ - OP_KET, /* 85 End of group that doesn't have an unbounded repeat */ - OP_KETRMAX, /* 86 These two must remain together and in this */ - OP_KETRMIN, /* 87 order. They are for groups the repeat for ever. */ - - /* The assertions must come before BRA, CBRA, ONCE, and COND.*/ - - OP_ASSERT, /* 88 Positive lookahead */ - OP_ASSERT_NOT, /* 89 Negative lookahead */ - OP_ASSERTBACK, /* 90 Positive lookbehind */ - OP_ASSERTBACK_NOT, /* 91 Negative lookbehind */ - OP_REVERSE, /* 92 Move pointer back - used in lookbehind assertions */ - - /* ONCE, BRA, CBRA, and COND must come after the assertions, with ONCE first, - as there's a test for >= ONCE for a subpattern that isn't an assertion. */ - - OP_ONCE, /* 93 Atomic group */ - OP_BRA, /* 94 Start of non-capturing bracket */ - OP_CBRA, /* 95 Start of capturing bracket */ - OP_COND, /* 96 Conditional group */ - - /* These three must follow the previous three, in the same order. There's a - check for >= SBRA to distinguish the two sets. */ - - OP_SBRA, /* 97 Start of non-capturing bracket, check empty */ - OP_SCBRA, /* 98 Start of capturing bracket, check empty */ - OP_SCOND, /* 99 Conditional group, check empty */ - - OP_CREF, /* 100 Used to hold a capture number as condition */ - OP_RREF, /* 101 Used to hold a recursion number as condition */ - OP_DEF, /* 102 The DEFINE condition */ - - OP_BRAZERO, /* 103 These two must remain together and in this */ - OP_BRAMINZERO, /* 104 order. */ - - /* These are backtracking control verbs */ - - OP_PRUNE, /* 105 */ - OP_SKIP, /* 106 */ - OP_THEN, /* 107 */ - OP_COMMIT, /* 108 */ - - /* These are forced failure and success verbs */ - - OP_FAIL, /* 109 */ - OP_ACCEPT, /* 110 */ - - /* This is used to skip a subpattern with a {0} quantifier */ - - OP_SKIPZERO /* 111 */ -}; - - -/* This macro defines textual names for all the opcodes. These are used only -for debugging. The macro is referenced only in pcre_printint.c. */ - -#define OP_NAME_LIST \ - "End", "\\A", "\\G", "\\K", "\\B", "\\b", "\\D", "\\d", \ - "\\S", "\\s", "\\W", "\\w", "Any", "AllAny", "Anybyte", \ - "notprop", "prop", "\\R", "\\H", "\\h", "\\V", "\\v", \ - "extuni", "\\Z", "\\z", \ - "Opt", "^", "$", "char", "charnc", "not", \ - "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ - "*+","++", "?+", "{", \ - "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ - "*+","++", "?+", "{", \ - "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ - "*+","++", "?+", "{", \ - "*", "*?", "+", "+?", "?", "??", "{", "{", \ - "class", "nclass", "xclass", "Ref", "Recurse", "Callout", \ - "Alt", "Ket", "KetRmax", "KetRmin", "Assert", "Assert not", \ - "AssertB", "AssertB not", "Reverse", \ - "Once", "Bra", "CBra", "Cond", "SBra", "SCBra", "SCond", \ - "Cond ref", "Cond rec", "Cond def", "Brazero", "Braminzero", \ - "*PRUNE", "*SKIP", "*THEN", "*COMMIT", "*FAIL", "*ACCEPT", \ - "Skip zero" - - -/* This macro defines the length of fixed length operations in the compiled -regex. The lengths are used when searching for specific things, and also in the -debugging printing of a compiled regex. We use a macro so that it can be -defined close to the definitions of the opcodes themselves. - -As things have been extended, some of these are no longer fixed lenths, but are -minima instead. For example, the length of a single-character repeat may vary -in UTF-8 mode. The code that uses this table must know about such things. */ - -#define OP_LENGTHS \ - 1, /* End */ \ - 1, 1, 1, 1, 1, /* \A, \G, \K, \B, \b */ \ - 1, 1, 1, 1, 1, 1, /* \D, \d, \S, \s, \W, \w */ \ - 1, 1, 1, /* Any, AllAny, Anybyte */ \ - 3, 3, 1, /* NOTPROP, PROP, EXTUNI */ \ - 1, 1, 1, 1, 1, /* \R, \H, \h, \V, \v */ \ - 1, 1, 2, 1, 1, /* \Z, \z, Opt, ^, $ */ \ - 2, /* Char - the minimum length */ \ - 2, /* Charnc - the minimum length */ \ - 2, /* not */ \ - /* Positive single-char repeats ** These are */ \ - 2, 2, 2, 2, 2, 2, /* *, *?, +, +?, ?, ?? ** minima in */ \ - 4, 4, 4, /* upto, minupto, exact ** UTF-8 mode */ \ - 2, 2, 2, 4, /* *+, ++, ?+, upto+ */ \ - /* Negative single-char repeats - only for chars < 256 */ \ - 2, 2, 2, 2, 2, 2, /* NOT *, *?, +, +?, ?, ?? */ \ - 4, 4, 4, /* NOT upto, minupto, exact */ \ - 2, 2, 2, 4, /* Possessive *, +, ?, upto */ \ - /* Positive type repeats */ \ - 2, 2, 2, 2, 2, 2, /* Type *, *?, +, +?, ?, ?? */ \ - 4, 4, 4, /* Type upto, minupto, exact */ \ - 2, 2, 2, 4, /* Possessive *+, ++, ?+, upto+ */ \ - /* Character class & ref repeats */ \ - 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ \ - 5, 5, /* CRRANGE, CRMINRANGE */ \ - 33, /* CLASS */ \ - 33, /* NCLASS */ \ - 0, /* XCLASS - variable length */ \ - 3, /* REF */ \ - 1+LINK_SIZE, /* RECURSE */ \ - 2+2*LINK_SIZE, /* CALLOUT */ \ - 1+LINK_SIZE, /* Alt */ \ - 1+LINK_SIZE, /* Ket */ \ - 1+LINK_SIZE, /* KetRmax */ \ - 1+LINK_SIZE, /* KetRmin */ \ - 1+LINK_SIZE, /* Assert */ \ - 1+LINK_SIZE, /* Assert not */ \ - 1+LINK_SIZE, /* Assert behind */ \ - 1+LINK_SIZE, /* Assert behind not */ \ - 1+LINK_SIZE, /* Reverse */ \ - 1+LINK_SIZE, /* ONCE */ \ - 1+LINK_SIZE, /* BRA */ \ - 3+LINK_SIZE, /* CBRA */ \ - 1+LINK_SIZE, /* COND */ \ - 1+LINK_SIZE, /* SBRA */ \ - 3+LINK_SIZE, /* SCBRA */ \ - 1+LINK_SIZE, /* SCOND */ \ - 3, /* CREF */ \ - 3, /* RREF */ \ - 1, /* DEF */ \ - 1, 1, /* BRAZERO, BRAMINZERO */ \ - 1, 1, 1, 1, /* PRUNE, SKIP, THEN, COMMIT, */ \ - 1, 1, 1 /* FAIL, ACCEPT, SKIPZERO */ - - -/* A magic value for OP_RREF to indicate the "any recursion" condition. */ - -#define RREF_ANY 0xffff - -/* Error code numbers. They are given names so that they can more easily be -tracked. */ - -enum { ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, - ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19, - ERR20, ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR28, ERR29, - ERR30, ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39, - ERR40, ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47, ERR48, ERR49, - ERR50, ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59, - ERR60, ERR61, ERR62, ERR63, ERR64 }; - -/* The real format of the start of the pcre block; the index of names and the -code vector run on as long as necessary after the end. We store an explicit -offset to the name table so that if a regex is compiled on one host, saved, and -then run on another where the size of pointers is different, all might still -be well. For the case of compiled-on-4 and run-on-8, we include an extra -pointer that is always NULL. For future-proofing, a few dummy fields were -originally included - even though you can never get this planning right - but -there is only one left now. - -NOTE NOTE NOTE: -Because people can now save and re-use compiled patterns, any additions to this -structure should be made at the end, and something earlier (e.g. a new -flag in the options or one of the dummy fields) should indicate that the new -fields are present. Currently PCRE always sets the dummy fields to zero. -NOTE NOTE NOTE: -*/ - -typedef struct real_pcre { - pcre_uint32 magic_number; - pcre_uint32 size; /* Total that was malloced */ - pcre_uint32 options; /* Public options */ - pcre_uint16 flags; /* Private flags */ - pcre_uint16 dummy1; /* For future use */ - pcre_uint16 top_bracket; - pcre_uint16 top_backref; - pcre_uint16 first_byte; - pcre_uint16 req_byte; - pcre_uint16 name_table_offset; /* Offset to name table that follows */ - pcre_uint16 name_entry_size; /* Size of any name items */ - pcre_uint16 name_count; /* Number of name items */ - pcre_uint16 ref_count; /* Reference count */ - - const unsigned char *tables; /* Pointer to tables or NULL for std */ - const unsigned char *nullpad; /* NULL padding */ -} real_pcre; - -/* The format of the block used to store data from pcre_study(). The same -remark (see NOTE above) about extending this structure applies. */ - -typedef struct pcre_study_data { - pcre_uint32 size; /* Total that was malloced */ - pcre_uint32 options; - uschar start_bits[32]; -} pcre_study_data; - -/* Structure for passing "static" information around between the functions -doing the compiling, so that they are thread-safe. */ - -typedef struct compile_data { - const uschar *lcc; /* Points to lower casing table */ - const uschar *fcc; /* Points to case-flipping table */ - const uschar *cbits; /* Points to character type table */ - const uschar *ctypes; /* Points to table of type maps */ - const uschar *start_workspace;/* The start of working space */ - const uschar *start_code; /* The start of the compiled code */ - const uschar *start_pattern; /* The start of the pattern */ - const uschar *end_pattern; /* The end of the pattern */ - uschar *hwm; /* High watermark of workspace */ - uschar *name_table; /* The name/number table */ - int names_found; /* Number of entries so far */ - int name_entry_size; /* Size of each entry */ - int bracount; /* Count of capturing parens as we compile */ - int final_bracount; /* Saved value after first pass */ - int top_backref; /* Maximum back reference */ - unsigned int backref_map; /* Bitmap of low back refs */ - int external_options; /* External (initial) options */ - int external_flags; /* External flag bits to be set */ - int req_varyopt; /* "After variable item" flag for reqbyte */ - BOOL had_accept; /* (*ACCEPT) encountered */ - int nltype; /* Newline type */ - int nllen; /* Newline string length */ - uschar nl[4]; /* Newline string when fixed length */ -} compile_data; - -/* Structure for maintaining a chain of pointers to the currently incomplete -branches, for testing for left recursion. */ - -typedef struct branch_chain { - struct branch_chain *outer; - uschar *current; -} branch_chain; - -/* Structure for items in a linked list that represents an explicit recursive -call within the pattern. */ - -typedef struct recursion_info { - struct recursion_info *prevrec; /* Previous recursion record (or NULL) */ - int group_num; /* Number of group that was called */ - const uschar *after_call; /* "Return value": points after the call in the expr */ - USPTR save_start; /* Old value of mstart */ - int *offset_save; /* Pointer to start of saved offsets */ - int saved_max; /* Number of saved offsets */ -} recursion_info; - -/* Structure for building a chain of data for holding the values of the subject -pointer at the start of each subpattern, so as to detect when an empty string -has been matched by a subpattern - to break infinite loops. */ - -typedef struct eptrblock { - struct eptrblock *epb_prev; - USPTR epb_saved_eptr; -} eptrblock; - - -/* Structure for passing "static" information around between the functions -doing traditional NFA matching, so that they are thread-safe. */ - -typedef struct match_data { - unsigned long int match_call_count; /* As it says */ - unsigned long int match_limit; /* As it says */ - unsigned long int match_limit_recursion; /* As it says */ - int *offset_vector; /* Offset vector */ - int offset_end; /* One past the end */ - int offset_max; /* The maximum usable for return data */ - int nltype; /* Newline type */ - int nllen; /* Newline string length */ - uschar nl[4]; /* Newline string when fixed */ - const uschar *lcc; /* Points to lower casing table */ - const uschar *ctypes; /* Points to table of type maps */ - BOOL offset_overflow; /* Set if too many extractions */ - BOOL notbol; /* NOTBOL flag */ - BOOL noteol; /* NOTEOL flag */ - BOOL utf8; /* UTF8 flag */ - BOOL jscript_compat; /* JAVASCRIPT_COMPAT flag */ - BOOL endonly; /* Dollar not before final \n */ - BOOL notempty; /* Empty string match not wanted */ - BOOL partial; /* PARTIAL flag */ - BOOL hitend; /* Hit the end of the subject at some point */ - BOOL bsr_anycrlf; /* \R is just any CRLF, not full Unicode */ - const uschar *start_code; /* For use when recursing */ - USPTR start_subject; /* Start of the subject string */ - USPTR end_subject; /* End of the subject string */ - USPTR start_match_ptr; /* Start of matched string */ - USPTR end_match_ptr; /* Subject position at end match */ - int end_offset_top; /* Highwater mark at end of match */ - int capture_last; /* Most recent capture number */ - int start_offset; /* The start offset value */ - eptrblock *eptrchain; /* Chain of eptrblocks for tail recursions */ - int eptrn; /* Next free eptrblock */ - recursion_info *recursive; /* Linked list of recursion data */ - void *callout_data; /* To pass back to callouts */ -} match_data; - -/* A similar structure is used for the same purpose by the DFA matching -functions. */ - -typedef struct dfa_match_data { - const uschar *start_code; /* Start of the compiled pattern */ - const uschar *start_subject; /* Start of the subject string */ - const uschar *end_subject; /* End of subject string */ - const uschar *tables; /* Character tables */ - int moptions; /* Match options */ - int poptions; /* Pattern options */ - int nltype; /* Newline type */ - int nllen; /* Newline string length */ - uschar nl[4]; /* Newline string when fixed */ - void *callout_data; /* To pass back to callouts */ -} dfa_match_data; - -/* Bit definitions for entries in the pcre_ctypes table. */ - -#define ctype_space 0x01 -#define ctype_letter 0x02 -#define ctype_digit 0x04 -#define ctype_xdigit 0x08 -#define ctype_word 0x10 /* alphanumeric or '_' */ -#define ctype_meta 0x80 /* regexp meta char or zero (end pattern) */ - -/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set -of bits for a class map. Some classes are built by combining these tables. */ - -#define cbit_space 0 /* [:space:] or \s */ -#define cbit_xdigit 32 /* [:xdigit:] */ -#define cbit_digit 64 /* [:digit:] or \d */ -#define cbit_upper 96 /* [:upper:] */ -#define cbit_lower 128 /* [:lower:] */ -#define cbit_word 160 /* [:word:] or \w */ -#define cbit_graph 192 /* [:graph:] */ -#define cbit_print 224 /* [:print:] */ -#define cbit_punct 256 /* [:punct:] */ -#define cbit_cntrl 288 /* [:cntrl:] */ -#define cbit_length 320 /* Length of the cbits table */ - -/* Offsets of the various tables from the base tables pointer, and -total length. */ - -#define lcc_offset 0 -#define fcc_offset 256 -#define cbits_offset 512 -#define ctypes_offset (cbits_offset + cbit_length) -#define tables_length (ctypes_offset + 256) - -/* Layout of the UCP type table that translates property names into types and -codes. Each entry used to point directly to a name, but to reduce the number of -relocations in shared libraries, it now has an offset into a single string -instead. */ - -typedef struct { - pcre_uint16 name_offset; - pcre_uint16 type; - pcre_uint16 value; -} ucp_type_table; - - -/* Internal shared data tables. These are tables that are used by more than one -of the exported public functions. They have to be "external" in the C sense, -but are not part of the PCRE public API. The data for these tables is in the -pcre_tables.c module. */ - -extern const int _pcre_utf8_table1[]; -extern const int _pcre_utf8_table2[]; -extern const int _pcre_utf8_table3[]; -extern const uschar _pcre_utf8_table4[]; - -extern const int _pcre_utf8_table1_size; - -extern const char _pcre_utt_names[]; -extern const ucp_type_table _pcre_utt[]; -extern const int _pcre_utt_size; - -extern const uschar _pcre_default_tables[]; - -extern const uschar _pcre_OP_lengths[]; - - -/* Internal shared functions. These are functions that are used by more than -one of the exported public functions. They have to be "external" in the C -sense, but are not part of the PCRE public API. */ - -extern BOOL _pcre_is_newline(const uschar *, int, const uschar *, - int *, BOOL); -extern int _pcre_ord2utf8(int, uschar *); -extern real_pcre *_pcre_try_flipped(const real_pcre *, real_pcre *, - const pcre_study_data *, pcre_study_data *); -extern int _pcre_valid_utf8(const uschar *, int); -extern BOOL _pcre_was_newline(const uschar *, int, const uschar *, - int *, BOOL); -extern BOOL _pcre_xclass(int, const uschar *); -extern unsigned int _pcre_ucp_othercase(unsigned int); - - -extern const int _pcre_ucp_gentype[]; - - -/* UCD access macros */ - -#include "../glib.h" - -#define UCD_CHARTYPE(ch) g_unichar_type(ch) -#define UCD_SCRIPT(ch) g_unichar_get_script(ch) -#define UCD_CATEGORY(ch) _pcre_ucp_gentype[UCD_CHARTYPE(ch)] -#define UCD_OTHERCASE(ch) _pcre_ucp_othercase(ch) - -#endif - -/* End of pcre_internal.h */ diff --git a/glib/pcre/pcre_maketables.c b/glib/pcre/pcre_maketables.c deleted file mode 100644 index 219973e37..000000000 --- a/glib/pcre/pcre_maketables.c +++ /dev/null @@ -1,143 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains the external function pcre_maketables(), which builds -character tables for PCRE in the current locale. The file is compiled on its -own as part of the PCRE library. However, it is also included in the -compilation of dftables.c, in which case the macro DFTABLES is defined. */ - - -#ifndef DFTABLES -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif -# include "pcre_internal.h" -#endif - - -/************************************************* -* Create PCRE character tables * -*************************************************/ - -/* This function builds a set of character tables for use by PCRE and returns -a pointer to them. They are build using the ctype functions, and consequently -their contents will depend upon the current locale setting. When compiled as -part of the library, the store is obtained via pcre_malloc(), but when compiled -inside dftables, use malloc(). - -Arguments: none -Returns: pointer to the contiguous block of data -*/ - -const unsigned char * -pcre_maketables(void) -{ -unsigned char *yield, *p; -int i; - -#ifndef DFTABLES -yield = (unsigned char*)(pcre_malloc)(tables_length); -#else -yield = (unsigned char*)malloc(tables_length); -#endif - -if (yield == NULL) return NULL; -p = yield; - -/* First comes the lower casing table */ - -for (i = 0; i < 256; i++) *p++ = tolower(i); - -/* Next the case-flipping table */ - -for (i = 0; i < 256; i++) *p++ = islower(i)? toupper(i) : tolower(i); - -/* Then the character class tables. Don't try to be clever and save effort on -exclusive ones - in some locales things may be different. Note that the table -for "space" includes everything "isspace" gives, including VT in the default -locale. This makes it work for the POSIX class [:space:]. Note also that it is -possible for a character to be alnum or alpha without being lower or upper, -such as "male and female ordinals" (\xAA and \xBA) in the fr_FR locale (at -least under Debian Linux's locales as of 12/2005). So we must test for alnum -specially. */ - -memset(p, 0, cbit_length); -for (i = 0; i < 256; i++) - { - if (isdigit(i)) p[cbit_digit + i/8] |= 1 << (i&7); - if (isupper(i)) p[cbit_upper + i/8] |= 1 << (i&7); - if (islower(i)) p[cbit_lower + i/8] |= 1 << (i&7); - if (isalnum(i)) p[cbit_word + i/8] |= 1 << (i&7); - if (i == '_') p[cbit_word + i/8] |= 1 << (i&7); - if (isspace(i)) p[cbit_space + i/8] |= 1 << (i&7); - if (isxdigit(i))p[cbit_xdigit + i/8] |= 1 << (i&7); - if (isgraph(i)) p[cbit_graph + i/8] |= 1 << (i&7); - if (isprint(i)) p[cbit_print + i/8] |= 1 << (i&7); - if (ispunct(i)) p[cbit_punct + i/8] |= 1 << (i&7); - if (iscntrl(i)) p[cbit_cntrl + i/8] |= 1 << (i&7); - } -p += cbit_length; - -/* Finally, the character type table. In this, we exclude VT from the white -space chars, because Perl doesn't recognize it as such for \s and for comments -within regexes. */ - -for (i = 0; i < 256; i++) - { - int x = 0; - if (i != 0x0b && isspace(i)) x += ctype_space; - if (isalpha(i)) x += ctype_letter; - if (isdigit(i)) x += ctype_digit; - if (isxdigit(i)) x += ctype_xdigit; - if (isalnum(i) || i == '_') x += ctype_word; - - /* Note: strchr includes the terminating zero in the characters it considers. - In this instance, that is ok because we want binary zero to be flagged as a - meta-character, which in this sense is any character that terminates a run - of data characters. */ - - if (strchr("\\*+?{^.$|()[", i) != 0) x += ctype_meta; - *p++ = x; - } - -return yield; -} - -/* End of pcre_maketables.c */ diff --git a/glib/pcre/pcre_newline.c b/glib/pcre/pcre_newline.c deleted file mode 100644 index 58885760e..000000000 --- a/glib/pcre/pcre_newline.c +++ /dev/null @@ -1,164 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains internal functions for testing newlines when more than -one kind of newline is to be recognized. When a newline is found, its length is -returned. In principle, we could implement several newline "types", each -referring to a different set of newline characters. At present, PCRE supports -only NLTYPE_FIXED, which gets handled without these functions, NLTYPE_ANYCRLF, -and NLTYPE_ANY. The full list of Unicode newline characters is taken from -http://unicode.org/unicode/reports/tr18/. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre_internal.h" - - - -/************************************************* -* Check for newline at given position * -*************************************************/ - -/* It is guaranteed that the initial value of ptr is less than the end of the -string that is being processed. - -Arguments: - ptr pointer to possible newline - type the newline type - endptr pointer to the end of the string - lenptr where to return the length - utf8 TRUE if in utf8 mode - -Returns: TRUE or FALSE -*/ - -BOOL -_pcre_is_newline(const uschar *ptr, int type, const uschar *endptr, - int *lenptr, BOOL utf8) -{ -int c; -if (utf8) { GETCHAR(c, ptr); } else c = *ptr; - -if (type == NLTYPE_ANYCRLF) switch(c) - { - case 0x000a: *lenptr = 1; return TRUE; /* LF */ - case 0x000d: *lenptr = (ptr < endptr - 1 && ptr[1] == 0x0a)? 2 : 1; - return TRUE; /* CR */ - default: return FALSE; - } - -/* NLTYPE_ANY */ - -else switch(c) - { - case 0x000a: /* LF */ - case 0x000b: /* VT */ - case 0x000c: *lenptr = 1; return TRUE; /* FF */ - case 0x000d: *lenptr = (ptr < endptr - 1 && ptr[1] == 0x0a)? 2 : 1; - return TRUE; /* CR */ - case 0x0085: *lenptr = utf8? 2 : 1; return TRUE; /* NEL */ - case 0x2028: /* LS */ - case 0x2029: *lenptr = 3; return TRUE; /* PS */ - default: return FALSE; - } -} - - - -/************************************************* -* Check for newline at previous position * -*************************************************/ - -/* It is guaranteed that the initial value of ptr is greater than the start of -the string that is being processed. - -Arguments: - ptr pointer to possible newline - type the newline type - startptr pointer to the start of the string - lenptr where to return the length - utf8 TRUE if in utf8 mode - -Returns: TRUE or FALSE -*/ - -BOOL -_pcre_was_newline(const uschar *ptr, int type, const uschar *startptr, - int *lenptr, BOOL utf8) -{ -int c; -ptr--; -#ifdef SUPPORT_UTF8 -if (utf8) - { - BACKCHAR(ptr); - GETCHAR(c, ptr); - } -else c = *ptr; -#else /* no UTF-8 support */ -c = *ptr; -#endif /* SUPPORT_UTF8 */ - -if (type == NLTYPE_ANYCRLF) switch(c) - { - case 0x000a: *lenptr = (ptr > startptr && ptr[-1] == 0x0d)? 2 : 1; - return TRUE; /* LF */ - case 0x000d: *lenptr = 1; return TRUE; /* CR */ - default: return FALSE; - } - -else switch(c) - { - case 0x000a: *lenptr = (ptr > startptr && ptr[-1] == 0x0d)? 2 : 1; - return TRUE; /* LF */ - case 0x000b: /* VT */ - case 0x000c: /* FF */ - case 0x000d: *lenptr = 1; return TRUE; /* CR */ - case 0x0085: *lenptr = utf8? 2 : 1; return TRUE; /* NEL */ - case 0x2028: /* LS */ - case 0x2029: *lenptr = 3; return TRUE; /* PS */ - default: return FALSE; - } -} - -/* End of pcre_newline.c */ diff --git a/glib/pcre/pcre_ord2utf8.c b/glib/pcre/pcre_ord2utf8.c deleted file mode 100644 index 6f4eb9ebe..000000000 --- a/glib/pcre/pcre_ord2utf8.c +++ /dev/null @@ -1,87 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This file contains a private PCRE function that converts an ordinal -character value into a UTF8 string. */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre_internal.h" - - -/************************************************* -* Convert character value to UTF-8 * -*************************************************/ - -/* This function takes an integer value in the range 0 - 0x7fffffff -and encodes it as a UTF-8 character in 0 to 6 bytes. - -Arguments: - cvalue the character value - buffer pointer to buffer for result - at least 6 bytes long - -Returns: number of characters placed in the buffer -*/ - -int -_pcre_ord2utf8(int cvalue, uschar *buffer) -{ -#ifdef SUPPORT_UTF8 -register int i, j; -for (i = 0; i < _pcre_utf8_table1_size; i++) - if (cvalue <= _pcre_utf8_table1[i]) break; -buffer += i; -for (j = i; j > 0; j--) - { - *buffer-- = 0x80 | (cvalue & 0x3f); - cvalue >>= 6; - } -*buffer = _pcre_utf8_table2[i] | cvalue; -return i + 1; -#else -(void)(cvalue); /* Keep compiler happy; this function won't ever be */ -(void)(buffer); /* called when SUPPORT_UTF8 is not defined. */ -return 0; -#endif -} - -/* End of pcre_ord2utf8.c */ diff --git a/glib/pcre/pcre_refcount.c b/glib/pcre/pcre_refcount.c deleted file mode 100644 index 92e4b8505..000000000 --- a/glib/pcre/pcre_refcount.c +++ /dev/null @@ -1,82 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains the external function pcre_refcount(), which is an -auxiliary function that can be used to maintain a reference count in a compiled -pattern data block. This might be helpful in applications where the block is -shared by different users. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre_internal.h" - - -/************************************************* -* Maintain reference count * -*************************************************/ - -/* The reference count is a 16-bit field, initialized to zero. It is not -possible to transfer a non-zero count from one host to a different host that -has a different byte order - though I can't see why anyone in their right mind -would ever want to do that! - -Arguments: - argument_re points to compiled code - adjust value to add to the count - -Returns: the (possibly updated) count value (a non-negative number), or - a negative error number -*/ - -PCRE_EXP_DEFN int PCRE_CALL_CONVENTION -pcre_refcount(pcre *argument_re, int adjust) -{ -real_pcre *re = (real_pcre *)argument_re; -if (re == NULL) return PCRE_ERROR_NULL; -re->ref_count = (-adjust > re->ref_count)? 0 : - (adjust + re->ref_count > 65535)? 65535 : - re->ref_count + adjust; -return re->ref_count; -} - -/* End of pcre_refcount.c */ diff --git a/glib/pcre/pcre_study.c b/glib/pcre/pcre_study.c deleted file mode 100644 index 778851d24..000000000 --- a/glib/pcre/pcre_study.c +++ /dev/null @@ -1,588 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains the external function pcre_study(), along with local -supporting functions. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre_internal.h" - - -/* Returns from set_start_bits() */ - -enum { SSB_FAIL, SSB_DONE, SSB_CONTINUE }; - - -/************************************************* -* Set a bit and maybe its alternate case * -*************************************************/ - -/* Given a character, set its bit in the table, and also the bit for the other -version of a letter if we are caseless. - -Arguments: - start_bits points to the bit map - c is the character - caseless the caseless flag - cd the block with char table pointers - -Returns: nothing -*/ - -static void -set_bit(uschar *start_bits, unsigned int c, BOOL caseless, compile_data *cd) -{ -start_bits[c/8] |= (1 << (c&7)); -if (caseless && (cd->ctypes[c] & ctype_letter) != 0) - start_bits[cd->fcc[c]/8] |= (1 << (cd->fcc[c]&7)); -} - - - -/************************************************* -* Create bitmap of starting bytes * -*************************************************/ - -/* This function scans a compiled unanchored expression recursively and -attempts to build a bitmap of the set of possible starting bytes. As time goes -by, we may be able to get more clever at doing this. The SSB_CONTINUE return is -useful for parenthesized groups in patterns such as (a*)b where the group -provides some optional starting bytes but scanning must continue at the outer -level to find at least one mandatory byte. At the outermost level, this -function fails unless the result is SSB_DONE. - -Arguments: - code points to an expression - start_bits points to a 32-byte table, initialized to 0 - caseless the current state of the caseless flag - utf8 TRUE if in UTF-8 mode - cd the block with char table pointers - -Returns: SSB_FAIL => Failed to find any starting bytes - SSB_DONE => Found mandatory starting bytes - SSB_CONTINUE => Found optional starting bytes -*/ - -static int -set_start_bits(const uschar *code, uschar *start_bits, BOOL caseless, - BOOL utf8, compile_data *cd) -{ -register int c; -int yield = SSB_DONE; - -#if 0 -/* ========================================================================= */ -/* The following comment and code was inserted in January 1999. In May 2006, -when it was observed to cause compiler warnings about unused values, I took it -out again. If anybody is still using OS/2, they will have to put it back -manually. */ - -/* This next statement and the later reference to dummy are here in order to -trick the optimizer of the IBM C compiler for OS/2 into generating correct -code. Apparently IBM isn't going to fix the problem, and we would rather not -disable optimization (in this module it actually makes a big difference, and -the pcre module can use all the optimization it can get). */ - -volatile int dummy; -/* ========================================================================= */ -#endif - -do - { - const uschar *tcode = code + (((int)*code == OP_CBRA)? 3:1) + LINK_SIZE; - BOOL try_next = TRUE; - - while (try_next) /* Loop for items in this branch */ - { - int rc; - switch(*tcode) - { - /* Fail if we reach something we don't understand */ - - default: - return SSB_FAIL; - - /* If we hit a bracket or a positive lookahead assertion, recurse to set - bits from within the subpattern. If it can't find anything, we have to - give up. If it finds some mandatory character(s), we are done for this - branch. Otherwise, carry on scanning after the subpattern. */ - - case OP_BRA: - case OP_SBRA: - case OP_CBRA: - case OP_SCBRA: - case OP_ONCE: - case OP_ASSERT: - rc = set_start_bits(tcode, start_bits, caseless, utf8, cd); - if (rc == SSB_FAIL) return SSB_FAIL; - if (rc == SSB_DONE) try_next = FALSE; else - { - do tcode += GET(tcode, 1); while (*tcode == OP_ALT); - tcode += 1 + LINK_SIZE; - } - break; - - /* If we hit ALT or KET, it means we haven't found anything mandatory in - this branch, though we might have found something optional. For ALT, we - continue with the next alternative, but we have to arrange that the final - result from subpattern is SSB_CONTINUE rather than SSB_DONE. For KET, - return SSB_CONTINUE: if this is the top level, that indicates failure, - but after a nested subpattern, it causes scanning to continue. */ - - case OP_ALT: - yield = SSB_CONTINUE; - try_next = FALSE; - break; - - case OP_KET: - case OP_KETRMAX: - case OP_KETRMIN: - return SSB_CONTINUE; - - /* Skip over callout */ - - case OP_CALLOUT: - tcode += 2 + 2*LINK_SIZE; - break; - - /* Skip over lookbehind and negative lookahead assertions */ - - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - do tcode += GET(tcode, 1); while (*tcode == OP_ALT); - tcode += 1 + LINK_SIZE; - break; - - /* Skip over an option setting, changing the caseless flag */ - - case OP_OPT: - caseless = (tcode[1] & PCRE_CASELESS) != 0; - tcode += 2; - break; - - /* BRAZERO does the bracket, but carries on. */ - - case OP_BRAZERO: - case OP_BRAMINZERO: - if (set_start_bits(++tcode, start_bits, caseless, utf8, cd) == SSB_FAIL) - return SSB_FAIL; -/* ========================================================================= - See the comment at the head of this function concerning the next line, - which was an old fudge for the benefit of OS/2. - dummy = 1; - ========================================================================= */ - do tcode += GET(tcode,1); while (*tcode == OP_ALT); - tcode += 1 + LINK_SIZE; - break; - - /* SKIPZERO skips the bracket. */ - - case OP_SKIPZERO: - tcode++; - do tcode += GET(tcode,1); while (*tcode == OP_ALT); - tcode += 1 + LINK_SIZE; - break; - - /* Single-char * or ? sets the bit and tries the next item */ - - case OP_STAR: - case OP_MINSTAR: - case OP_POSSTAR: - case OP_QUERY: - case OP_MINQUERY: - case OP_POSQUERY: - set_bit(start_bits, tcode[1], caseless, cd); - tcode += 2; -#ifdef SUPPORT_UTF8 - if (utf8 && tcode[-1] >= 0xc0) - tcode += _pcre_utf8_table4[tcode[-1] & 0x3f]; -#endif - break; - - /* Single-char upto sets the bit and tries the next */ - - case OP_UPTO: - case OP_MINUPTO: - case OP_POSUPTO: - set_bit(start_bits, tcode[3], caseless, cd); - tcode += 4; -#ifdef SUPPORT_UTF8 - if (utf8 && tcode[-1] >= 0xc0) - tcode += _pcre_utf8_table4[tcode[-1] & 0x3f]; -#endif - break; - - /* At least one single char sets the bit and stops */ - - case OP_EXACT: /* Fall through */ - tcode += 2; - - case OP_CHAR: - case OP_CHARNC: - case OP_PLUS: - case OP_MINPLUS: - case OP_POSPLUS: - set_bit(start_bits, tcode[1], caseless, cd); - try_next = FALSE; - break; - - /* Single character type sets the bits and stops */ - - case OP_NOT_DIGIT: - for (c = 0; c < 32; c++) - start_bits[c] |= ~cd->cbits[c+cbit_digit]; - try_next = FALSE; - break; - - case OP_DIGIT: - for (c = 0; c < 32; c++) - start_bits[c] |= cd->cbits[c+cbit_digit]; - try_next = FALSE; - break; - - /* The cbit_space table has vertical tab as whitespace; we have to - discard it. */ - - case OP_NOT_WHITESPACE: - for (c = 0; c < 32; c++) - { - int d = cd->cbits[c+cbit_space]; - if (c == 1) d &= ~0x08; - start_bits[c] |= ~d; - } - try_next = FALSE; - break; - - /* The cbit_space table has vertical tab as whitespace; we have to - discard it. */ - - case OP_WHITESPACE: - for (c = 0; c < 32; c++) - { - int d = cd->cbits[c+cbit_space]; - if (c == 1) d &= ~0x08; - start_bits[c] |= d; - } - try_next = FALSE; - break; - - case OP_NOT_WORDCHAR: - for (c = 0; c < 32; c++) - start_bits[c] |= ~cd->cbits[c+cbit_word]; - try_next = FALSE; - break; - - case OP_WORDCHAR: - for (c = 0; c < 32; c++) - start_bits[c] |= cd->cbits[c+cbit_word]; - try_next = FALSE; - break; - - /* One or more character type fudges the pointer and restarts, knowing - it will hit a single character type and stop there. */ - - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - tcode++; - break; - - case OP_TYPEEXACT: - tcode += 3; - break; - - /* Zero or more repeats of character types set the bits and then - try again. */ - - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEPOSUPTO: - tcode += 2; /* Fall through */ - - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPOSSTAR: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSQUERY: - switch(tcode[1]) - { - case OP_ANY: - case OP_ALLANY: - return SSB_FAIL; - - case OP_NOT_DIGIT: - for (c = 0; c < 32; c++) - start_bits[c] |= ~cd->cbits[c+cbit_digit]; - break; - - case OP_DIGIT: - for (c = 0; c < 32; c++) - start_bits[c] |= cd->cbits[c+cbit_digit]; - break; - - /* The cbit_space table has vertical tab as whitespace; we have to - discard it. */ - - case OP_NOT_WHITESPACE: - for (c = 0; c < 32; c++) - { - int d = cd->cbits[c+cbit_space]; - if (c == 1) d &= ~0x08; - start_bits[c] |= ~d; - } - break; - - /* The cbit_space table has vertical tab as whitespace; we have to - discard it. */ - - case OP_WHITESPACE: - for (c = 0; c < 32; c++) - { - int d = cd->cbits[c+cbit_space]; - if (c == 1) d &= ~0x08; - start_bits[c] |= d; - } - break; - - case OP_NOT_WORDCHAR: - for (c = 0; c < 32; c++) - start_bits[c] |= ~cd->cbits[c+cbit_word]; - break; - - case OP_WORDCHAR: - for (c = 0; c < 32; c++) - start_bits[c] |= cd->cbits[c+cbit_word]; - break; - } - - tcode += 2; - break; - - /* Character class where all the information is in a bit map: set the - bits and either carry on or not, according to the repeat count. If it was - a negative class, and we are operating with UTF-8 characters, any byte - with a value >= 0xc4 is a potentially valid starter because it starts a - character with a value > 255. */ - - case OP_NCLASS: -#ifdef SUPPORT_UTF8 - if (utf8) - { - start_bits[24] |= 0xf0; /* Bits for 0xc4 - 0xc8 */ - memset(start_bits+25, 0xff, 7); /* Bits for 0xc9 - 0xff */ - } -#endif - /* Fall through */ - - case OP_CLASS: - { - tcode++; - - /* In UTF-8 mode, the bits in a bit map correspond to character - values, not to byte values. However, the bit map we are constructing is - for byte values. So we have to do a conversion for characters whose - value is > 127. In fact, there are only two possible starting bytes for - characters in the range 128 - 255. */ - -#ifdef SUPPORT_UTF8 - if (utf8) - { - for (c = 0; c < 16; c++) start_bits[c] |= tcode[c]; - for (c = 128; c < 256; c++) - { - if ((tcode[c/8] && (1 << (c&7))) != 0) - { - int d = (c >> 6) | 0xc0; /* Set bit for this starter */ - start_bits[d/8] |= (1 << (d&7)); /* and then skip on to the */ - c = (c & 0xc0) + 0x40 - 1; /* next relevant character. */ - } - } - } - - /* In non-UTF-8 mode, the two bit maps are completely compatible. */ - - else -#endif - { - for (c = 0; c < 32; c++) start_bits[c] |= tcode[c]; - } - - /* Advance past the bit map, and act on what follows */ - - tcode += 32; - switch (*tcode) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRQUERY: - case OP_CRMINQUERY: - tcode++; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - if (((tcode[1] << 8) + tcode[2]) == 0) tcode += 5; - else try_next = FALSE; - break; - - default: - try_next = FALSE; - break; - } - } - break; /* End of bitmap class handling */ - - } /* End of switch */ - } /* End of try_next loop */ - - code += GET(code, 1); /* Advance to next branch */ - } -while (*code == OP_ALT); -return yield; -} - - - -/************************************************* -* Study a compiled expression * -*************************************************/ - -/* This function is handed a compiled expression that it must study to produce -information that will speed up the matching. It returns a pcre_extra block -which then gets handed back to pcre_exec(). - -Arguments: - re points to the compiled expression - options contains option bits - errorptr points to where to place error messages; - set NULL unless error - -Returns: pointer to a pcre_extra block, with study_data filled in and the - appropriate flag set; - NULL on error or if no optimization possible -*/ - -PCRE_EXP_DEFN pcre_extra * PCRE_CALL_CONVENTION -pcre_study(const pcre *external_re, int options, const char **errorptr) -{ -uschar start_bits[32]; -pcre_extra *extra; -pcre_study_data *study; -const uschar *tables; -uschar *code; -compile_data compile_block; -const real_pcre *re = (const real_pcre *)external_re; - -*errorptr = NULL; - -if (re == NULL || re->magic_number != MAGIC_NUMBER) - { - *errorptr = "argument is not a compiled regular expression"; - return NULL; - } - -if ((options & ~PUBLIC_STUDY_OPTIONS) != 0) - { - *errorptr = "unknown or incorrect option bit(s) set"; - return NULL; - } - -code = (uschar *)re + re->name_table_offset + - (re->name_count * re->name_entry_size); - -/* For an anchored pattern, or an unanchored pattern that has a first char, or -a multiline pattern that matches only at "line starts", no further processing -at present. */ - -if ((re->options & PCRE_ANCHORED) != 0 || - (re->flags & (PCRE_FIRSTSET|PCRE_STARTLINE)) != 0) - return NULL; - -/* Set the character tables in the block that is passed around */ - -tables = re->tables; -if (tables == NULL) - (void)pcre_fullinfo(external_re, NULL, PCRE_INFO_DEFAULT_TABLES, - (void *)(&tables)); - -compile_block.lcc = tables + lcc_offset; -compile_block.fcc = tables + fcc_offset; -compile_block.cbits = tables + cbits_offset; -compile_block.ctypes = tables + ctypes_offset; - -/* See if we can find a fixed set of initial characters for the pattern. */ - -memset(start_bits, 0, 32 * sizeof(uschar)); -if (set_start_bits(code, start_bits, (re->options & PCRE_CASELESS) != 0, - (re->options & PCRE_UTF8) != 0, &compile_block) != SSB_DONE) return NULL; - -/* Get a pcre_extra block and a pcre_study_data block. The study data is put in -the latter, which is pointed to by the former, which may also get additional -data set later by the calling program. At the moment, the size of -pcre_study_data is fixed. We nevertheless save it in a field for returning via -the pcre_fullinfo() function so that if it becomes variable in the future, we -don't have to change that code. */ - -extra = (pcre_extra *)(pcre_malloc) - (sizeof(pcre_extra) + sizeof(pcre_study_data)); - -if (extra == NULL) - { - *errorptr = "failed to get memory"; - return NULL; - } - -study = (pcre_study_data *)((char *)extra + sizeof(pcre_extra)); -extra->flags = PCRE_EXTRA_STUDY_DATA; -extra->study_data = study; - -study->size = sizeof(pcre_study_data); -study->options = PCRE_STUDY_MAPPED; -memcpy(study->start_bits, start_bits, sizeof(start_bits)); - -return extra; -} - -/* End of pcre_study.c */ diff --git a/glib/pcre/pcre_tables.c b/glib/pcre/pcre_tables.c deleted file mode 100644 index 160bc5d53..000000000 --- a/glib/pcre/pcre_tables.c +++ /dev/null @@ -1,356 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains some fixed tables that are used by more than one of the -PCRE code modules. The tables are also #included by the pcretest program, which -uses macros to change their names from _pcre_xxx to xxxx, thereby avoiding name -clashes with the library. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre_internal.h" - - -/* Table of sizes for the fixed-length opcodes. It's defined in a macro so that -the definition is next to the definition of the opcodes in pcre_internal.h. */ - -const uschar _pcre_OP_lengths[] = { OP_LENGTHS }; - - - -/************************************************* -* Tables for UTF-8 support * -*************************************************/ - -/* These are the breakpoints for different numbers of bytes in a UTF-8 -character. */ - -#ifdef SUPPORT_UTF8 - -const int _pcre_utf8_table1[] = - { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff}; - -const int _pcre_utf8_table1_size = sizeof(_pcre_utf8_table1)/sizeof(int); - -/* These are the indicator bits and the mask for the data bits to set in the -first byte of a character, indexed by the number of additional bytes. */ - -const int _pcre_utf8_table2[] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; -const int _pcre_utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; - -/* Table of the number of extra bytes, indexed by the first byte masked with -0x3f. The highest number for a valid UTF-8 first byte is in fact 0x3d. */ - -const uschar _pcre_utf8_table4[] = { - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; - -/* Table to translate from particular type value to the general value. */ - -const int _pcre_ucp_gentype[] = { - ucp_C, ucp_C, ucp_C, ucp_C, ucp_C, /* Cc, Cf, Cn, Co, Cs */ - ucp_L, ucp_L, ucp_L, ucp_L, ucp_L, /* Ll, Lu, Lm, Lo, Lt */ - ucp_M, ucp_M, ucp_M, /* Mc, Me, Mn */ - ucp_N, ucp_N, ucp_N, /* Nd, Nl, No */ - ucp_P, ucp_P, ucp_P, ucp_P, ucp_P, /* Pc, Pd, Pe, Pf, Pi */ - ucp_P, ucp_P, /* Ps, Po */ - ucp_S, ucp_S, ucp_S, ucp_S, /* Sc, Sk, Sm, So */ - ucp_Z, ucp_Z, ucp_Z /* Zl, Zp, Zs */ -}; - -/* The pcre_utt[] table below translates Unicode property names into type and -code values. It is searched by binary chop, so must be in collating sequence of -name. Originally, the table contained pointers to the name strings in the first -field of each entry. However, that leads to a large number of relocations when -a shared library is dynamically loaded. A significant reduction is made by -putting all the names into a single, large string and then using offsets in the -table itself. Maintenance is more error-prone, but frequent changes to this -data are unlikely. - -July 2008: There is now a script called maint/GenerateUtt.py which can be used -to generate this data instead of maintaining it entirely by hand. */ - -const char _pcre_utt_names[] = - "Any\0" - "Arabic\0" - "Armenian\0" - "Balinese\0" - "Bengali\0" - "Bopomofo\0" - "Braille\0" - "Buginese\0" - "Buhid\0" - "C\0" - "Canadian_Aboriginal\0" - "Carian\0" - "Cc\0" - "Cf\0" - "Cham\0" - "Cherokee\0" - "Cn\0" - "Co\0" - "Common\0" - "Coptic\0" - "Cs\0" - "Cuneiform\0" - "Cypriot\0" - "Cyrillic\0" - "Deseret\0" - "Devanagari\0" - "Ethiopic\0" - "Georgian\0" - "Glagolitic\0" - "Gothic\0" - "Greek\0" - "Gujarati\0" - "Gurmukhi\0" - "Han\0" - "Hangul\0" - "Hanunoo\0" - "Hebrew\0" - "Hiragana\0" - "Inherited\0" - "Kannada\0" - "Katakana\0" - "Kayah_Li\0" - "Kharoshthi\0" - "Khmer\0" - "L\0" - "L&\0" - "Lao\0" - "Latin\0" - "Lepcha\0" - "Limbu\0" - "Linear_B\0" - "Ll\0" - "Lm\0" - "Lo\0" - "Lt\0" - "Lu\0" - "Lycian\0" - "Lydian\0" - "M\0" - "Malayalam\0" - "Mc\0" - "Me\0" - "Mn\0" - "Mongolian\0" - "Myanmar\0" - "N\0" - "Nd\0" - "New_Tai_Lue\0" - "Nko\0" - "Nl\0" - "No\0" - "Ogham\0" - "Ol_Chiki\0" - "Old_Italic\0" - "Old_Persian\0" - "Oriya\0" - "Osmanya\0" - "P\0" - "Pc\0" - "Pd\0" - "Pe\0" - "Pf\0" - "Phags_Pa\0" - "Phoenician\0" - "Pi\0" - "Po\0" - "Ps\0" - "Rejang\0" - "Runic\0" - "S\0" - "Saurashtra\0" - "Sc\0" - "Shavian\0" - "Sinhala\0" - "Sk\0" - "Sm\0" - "So\0" - "Sundanese\0" - "Syloti_Nagri\0" - "Syriac\0" - "Tagalog\0" - "Tagbanwa\0" - "Tai_Le\0" - "Tamil\0" - "Telugu\0" - "Thaana\0" - "Thai\0" - "Tibetan\0" - "Tifinagh\0" - "Ugaritic\0" - "Vai\0" - "Yi\0" - "Z\0" - "Zl\0" - "Zp\0" - "Zs\0"; - -const ucp_type_table _pcre_utt[] = { - { 0, PT_ANY, 0 }, - { 4, PT_SC, ucp_Arabic }, - { 11, PT_SC, ucp_Armenian }, - { 20, PT_SC, ucp_Balinese }, - { 29, PT_SC, ucp_Bengali }, - { 37, PT_SC, ucp_Bopomofo }, - { 46, PT_SC, ucp_Braille }, - { 54, PT_SC, ucp_Buginese }, - { 63, PT_SC, ucp_Buhid }, - { 69, PT_GC, ucp_C }, - { 71, PT_SC, ucp_Canadian_Aboriginal }, - { 91, PT_SC, ucp_Carian }, - { 98, PT_PC, ucp_Cc }, - { 101, PT_PC, ucp_Cf }, - { 104, PT_SC, ucp_Cham }, - { 109, PT_SC, ucp_Cherokee }, - { 118, PT_PC, ucp_Cn }, - { 121, PT_PC, ucp_Co }, - { 124, PT_SC, ucp_Common }, - { 131, PT_SC, ucp_Coptic }, - { 138, PT_PC, ucp_Cs }, - { 141, PT_SC, ucp_Cuneiform }, - { 151, PT_SC, ucp_Cypriot }, - { 159, PT_SC, ucp_Cyrillic }, - { 168, PT_SC, ucp_Deseret }, - { 176, PT_SC, ucp_Devanagari }, - { 187, PT_SC, ucp_Ethiopic }, - { 196, PT_SC, ucp_Georgian }, - { 205, PT_SC, ucp_Glagolitic }, - { 216, PT_SC, ucp_Gothic }, - { 223, PT_SC, ucp_Greek }, - { 229, PT_SC, ucp_Gujarati }, - { 238, PT_SC, ucp_Gurmukhi }, - { 247, PT_SC, ucp_Han }, - { 251, PT_SC, ucp_Hangul }, - { 258, PT_SC, ucp_Hanunoo }, - { 266, PT_SC, ucp_Hebrew }, - { 273, PT_SC, ucp_Hiragana }, - { 282, PT_SC, ucp_Inherited }, - { 292, PT_SC, ucp_Kannada }, - { 300, PT_SC, ucp_Katakana }, - { 309, PT_SC, ucp_Kayah_Li }, - { 318, PT_SC, ucp_Kharoshthi }, - { 329, PT_SC, ucp_Khmer }, - { 335, PT_GC, ucp_L }, - { 337, PT_LAMP, 0 }, - { 340, PT_SC, ucp_Lao }, - { 344, PT_SC, ucp_Latin }, - { 350, PT_SC, ucp_Lepcha }, - { 357, PT_SC, ucp_Limbu }, - { 363, PT_SC, ucp_Linear_B }, - { 372, PT_PC, ucp_Ll }, - { 375, PT_PC, ucp_Lm }, - { 378, PT_PC, ucp_Lo }, - { 381, PT_PC, ucp_Lt }, - { 384, PT_PC, ucp_Lu }, - { 387, PT_SC, ucp_Lycian }, - { 394, PT_SC, ucp_Lydian }, - { 401, PT_GC, ucp_M }, - { 403, PT_SC, ucp_Malayalam }, - { 413, PT_PC, ucp_Mc }, - { 416, PT_PC, ucp_Me }, - { 419, PT_PC, ucp_Mn }, - { 422, PT_SC, ucp_Mongolian }, - { 432, PT_SC, ucp_Myanmar }, - { 440, PT_GC, ucp_N }, - { 442, PT_PC, ucp_Nd }, - { 445, PT_SC, ucp_New_Tai_Lue }, - { 457, PT_SC, ucp_Nko }, - { 461, PT_PC, ucp_Nl }, - { 464, PT_PC, ucp_No }, - { 467, PT_SC, ucp_Ogham }, - { 473, PT_SC, ucp_Ol_Chiki }, - { 482, PT_SC, ucp_Old_Italic }, - { 493, PT_SC, ucp_Old_Persian }, - { 505, PT_SC, ucp_Oriya }, - { 511, PT_SC, ucp_Osmanya }, - { 519, PT_GC, ucp_P }, - { 521, PT_PC, ucp_Pc }, - { 524, PT_PC, ucp_Pd }, - { 527, PT_PC, ucp_Pe }, - { 530, PT_PC, ucp_Pf }, - { 533, PT_SC, ucp_Phags_Pa }, - { 542, PT_SC, ucp_Phoenician }, - { 553, PT_PC, ucp_Pi }, - { 556, PT_PC, ucp_Po }, - { 559, PT_PC, ucp_Ps }, - { 562, PT_SC, ucp_Rejang }, - { 569, PT_SC, ucp_Runic }, - { 575, PT_GC, ucp_S }, - { 577, PT_SC, ucp_Saurashtra }, - { 588, PT_PC, ucp_Sc }, - { 591, PT_SC, ucp_Shavian }, - { 599, PT_SC, ucp_Sinhala }, - { 607, PT_PC, ucp_Sk }, - { 610, PT_PC, ucp_Sm }, - { 613, PT_PC, ucp_So }, - { 616, PT_SC, ucp_Sundanese }, - { 626, PT_SC, ucp_Syloti_Nagri }, - { 639, PT_SC, ucp_Syriac }, - { 646, PT_SC, ucp_Tagalog }, - { 654, PT_SC, ucp_Tagbanwa }, - { 663, PT_SC, ucp_Tai_Le }, - { 670, PT_SC, ucp_Tamil }, - { 676, PT_SC, ucp_Telugu }, - { 683, PT_SC, ucp_Thaana }, - { 690, PT_SC, ucp_Thai }, - { 695, PT_SC, ucp_Tibetan }, - { 703, PT_SC, ucp_Tifinagh }, - { 712, PT_SC, ucp_Ugaritic }, - { 721, PT_SC, ucp_Vai }, - { 725, PT_SC, ucp_Yi }, - { 728, PT_GC, ucp_Z }, - { 730, PT_PC, ucp_Zl }, - { 733, PT_PC, ucp_Zp }, - { 736, PT_PC, ucp_Zs } -}; - -const int _pcre_utt_size = sizeof(_pcre_utt)/sizeof(ucp_type_table); - -#endif /* SUPPORT_UTF8 */ - -/* End of pcre_tables.c */ diff --git a/glib/pcre/pcre_try_flipped.c b/glib/pcre/pcre_try_flipped.c deleted file mode 100644 index 0d2f3a2d3..000000000 --- a/glib/pcre/pcre_try_flipped.c +++ /dev/null @@ -1,137 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains an internal function that tests a compiled pattern to -see if it was compiled with the opposite endianness. If so, it uses an -auxiliary local function to flip the appropriate bytes. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre_internal.h" - - -/************************************************* -* Flip bytes in an integer * -*************************************************/ - -/* This function is called when the magic number in a regex doesn't match, in -order to flip its bytes to see if we are dealing with a pattern that was -compiled on a host of different endianness. If so, this function is used to -flip other byte values. - -Arguments: - value the number to flip - n the number of bytes to flip (assumed to be 2 or 4) - -Returns: the flipped value -*/ - -static unsigned long int -byteflip(unsigned long int value, int n) -{ -if (n == 2) return ((value & 0x00ff) << 8) | ((value & 0xff00) >> 8); -return ((value & 0x000000ff) << 24) | - ((value & 0x0000ff00) << 8) | - ((value & 0x00ff0000) >> 8) | - ((value & 0xff000000) >> 24); -} - - - -/************************************************* -* Test for a byte-flipped compiled regex * -*************************************************/ - -/* This function is called from pcre_exec(), pcre_dfa_exec(), and also from -pcre_fullinfo(). Its job is to test whether the regex is byte-flipped - that -is, it was compiled on a system of opposite endianness. The function is called -only when the native MAGIC_NUMBER test fails. If the regex is indeed flipped, -we flip all the relevant values into a different data block, and return it. - -Arguments: - re points to the regex - study points to study data, or NULL - internal_re points to a new regex block - internal_study points to a new study block - -Returns: the new block if is is indeed a byte-flipped regex - NULL if it is not -*/ - -real_pcre * -_pcre_try_flipped(const real_pcre *re, real_pcre *internal_re, - const pcre_study_data *study, pcre_study_data *internal_study) -{ -if (byteflip(re->magic_number, sizeof(re->magic_number)) != MAGIC_NUMBER) - return NULL; - -*internal_re = *re; /* To copy other fields */ -internal_re->size = byteflip(re->size, sizeof(re->size)); -internal_re->options = byteflip(re->options, sizeof(re->options)); -internal_re->flags = (pcre_uint16)byteflip(re->flags, sizeof(re->flags)); -internal_re->top_bracket = - (pcre_uint16)byteflip(re->top_bracket, sizeof(re->top_bracket)); -internal_re->top_backref = - (pcre_uint16)byteflip(re->top_backref, sizeof(re->top_backref)); -internal_re->first_byte = - (pcre_uint16)byteflip(re->first_byte, sizeof(re->first_byte)); -internal_re->req_byte = - (pcre_uint16)byteflip(re->req_byte, sizeof(re->req_byte)); -internal_re->name_table_offset = - (pcre_uint16)byteflip(re->name_table_offset, sizeof(re->name_table_offset)); -internal_re->name_entry_size = - (pcre_uint16)byteflip(re->name_entry_size, sizeof(re->name_entry_size)); -internal_re->name_count = - (pcre_uint16)byteflip(re->name_count, sizeof(re->name_count)); - -if (study != NULL) - { - *internal_study = *study; /* To copy other fields */ - internal_study->size = byteflip(study->size, sizeof(study->size)); - internal_study->options = byteflip(study->options, sizeof(study->options)); - } - -return internal_re; -} - -/* End of pcre_tryflipped.c */ diff --git a/glib/pcre/pcre_ucp_searchfuncs.c b/glib/pcre/pcre_ucp_searchfuncs.c deleted file mode 100644 index 9060fbccd..000000000 --- a/glib/pcre/pcre_ucp_searchfuncs.c +++ /dev/null @@ -1,81 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - -/* This file has been modified to use glib instead of the internal table - * in ucptable.c -- Marco Barisione */ - -/* This module contains code for searching the table of Unicode character -properties. */ - -#include "pcre_internal.h" - -#include "ucp.h" /* Category definitions */ - - -/************************************************* -* Search table and return other case * -*************************************************/ - -/* If the given character is a letter, and there is another case for the -letter, return the other case. Otherwise, return -1. - -Arguments: - c the character value - -Returns: the other case or NOTACHAR if none -*/ - -unsigned int -_pcre_ucp_othercase(const unsigned int c) -{ -unsigned int other_case = NOTACHAR; - -if (g_unichar_islower(c)) - other_case = g_unichar_toupper(c); -else if (g_unichar_isupper(c)) - other_case = g_unichar_tolower(c); - -if (other_case == c) - other_case = NOTACHAR; - -return other_case; -} - - -/* End of pcre_ucp_searchfuncs.c */ diff --git a/glib/pcre/pcre_valid_utf8.c b/glib/pcre/pcre_valid_utf8.c deleted file mode 100644 index a5766b454..000000000 --- a/glib/pcre/pcre_valid_utf8.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "pcre_internal.h" - -/* - * This function is not needed by GRegex, so print an error and - * return always -1, that is the string is a valid UTF-8 encoded - * string. - */ -int -_pcre_valid_utf8(const uschar *string, int length) -{ -g_warning ("%s: this function should not be called", G_STRLOC); -return -1; -} diff --git a/glib/pcre/pcre_version.c b/glib/pcre/pcre_version.c deleted file mode 100644 index 7067cd4ae..000000000 --- a/glib/pcre/pcre_version.c +++ /dev/null @@ -1,90 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains the external function pcre_version(), which returns a -string that identifies the PCRE version that is in use. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre_internal.h" - - -/************************************************* -* Return version string * -*************************************************/ - -/* These macros are the standard way of turning unquoted text into C strings. -They allow macros like PCRE_MAJOR to be defined without quotes, which is -convenient for user programs that want to test its value. */ - -#define STRING(a) # a -#define XSTRING(s) STRING(s) - -/* A problem turned up with PCRE_PRERELEASE, which is defined empty for -production releases. Originally, it was used naively in this code: - - return XSTRING(PCRE_MAJOR) - "." XSTRING(PCRE_MINOR) - XSTRING(PCRE_PRERELEASE) - " " XSTRING(PCRE_DATE); - -However, when PCRE_PRERELEASE is empty, this leads to an attempted expansion of -STRING(). The C standard states: "If (before argument substitution) any -argument consists of no preprocessing tokens, the behavior is undefined." It -turns out the gcc treats this case as a single empty string - which is what we -really want - but Visual C grumbles about the lack of an argument for the -macro. Unfortunately, both are within their rights. To cope with both ways of -handling this, I had resort to some messy hackery that does a test at run time. -I could find no way of detecting that a macro is defined as an empty string at -pre-processor time. This hack uses a standard trick for avoiding calling -the STRING macro with an empty argument when doing the test. */ - -PCRE_EXP_DEFN const char * PCRE_CALL_CONVENTION -pcre_version(void) -{ -return (XSTRING(Z PCRE_PRERELEASE)[1] == 0)? - XSTRING(PCRE_MAJOR.PCRE_MINOR PCRE_DATE) : - XSTRING(PCRE_MAJOR.PCRE_MINOR) XSTRING(PCRE_PRERELEASE PCRE_DATE); -} - -/* End of pcre_version.c */ diff --git a/glib/pcre/pcre_xclass.c b/glib/pcre/pcre_xclass.c deleted file mode 100644 index e8e7a5049..000000000 --- a/glib/pcre/pcre_xclass.c +++ /dev/null @@ -1,146 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2008 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains an internal function that is used to match an extended -class (one that contains characters whose values are > 255). It is used by both -pcre_exec() and pcre_def_exec(). */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre_internal.h" - - -/************************************************* -* Match character against an XCLASS * -*************************************************/ - -/* This function is called to match a character against an extended class that -might contain values > 255. - -Arguments: - c the character - data points to the flag byte of the XCLASS data - -Returns: TRUE if character matches, else FALSE -*/ - -BOOL -_pcre_xclass(int c, const uschar *data) -{ -int t; -BOOL negated = (*data & XCL_NOT) != 0; - -/* Character values < 256 are matched against a bitmap, if one is present. If -not, we still carry on, because there may be ranges that start below 256 in the -additional data. */ - -if (c < 256) - { - if ((*data & XCL_MAP) != 0 && (data[1 + c/8] & (1 << (c&7))) != 0) - return !negated; /* char found */ - } - -/* First skip the bit map if present. Then match against the list of Unicode -properties or large chars or ranges that end with a large char. We won't ever -encounter XCL_PROP or XCL_NOTPROP when UCP support is not compiled. */ - -if ((*data++ & XCL_MAP) != 0) data += 32; - -while ((t = *data++) != XCL_END) - { - int x, y; - if (t == XCL_SINGLE) - { - GETCHARINC(x, data); - if (c == x) return !negated; - } - else if (t == XCL_RANGE) - { - GETCHARINC(x, data); - GETCHARINC(y, data); - if (c >= x && c <= y) return !negated; - } - -#ifdef SUPPORT_UCP - else /* XCL_PROP & XCL_NOTPROP */ - { - int chartype = UCD_CHARTYPE(c); - switch(*data) - { - case PT_ANY: - if (t == XCL_PROP) return !negated; - break; - - case PT_LAMP: - if ((chartype == ucp_Lu || chartype == ucp_Ll || chartype == ucp_Lt) == - (t == XCL_PROP)) return !negated; - break; - - case PT_GC: - if ((data[1] == _pcre_ucp_gentype[chartype]) == (t == XCL_PROP)) return !negated; - break; - - case PT_PC: - if ((data[1] == chartype) == (t == XCL_PROP)) return !negated; - break; - - case PT_SC: - if ((data[1] == UCD_SCRIPT(c)) == (t == XCL_PROP)) return !negated; - break; - - /* This should never occur, but compilers may mutter if there is no - default. */ - - default: - return FALSE; - } - - data += 2; - } -#endif /* SUPPORT_UCP */ - } - -return negated; /* char did not match */ -} - -/* End of pcre_xclass.c */ diff --git a/glib/pcre/ucp.h b/glib/pcre/ucp.h deleted file mode 100644 index fe910ce00..000000000 --- a/glib/pcre/ucp.h +++ /dev/null @@ -1,144 +0,0 @@ -/************************************************* -* Unicode Property Table handler * -*************************************************/ - -#ifndef _UCP_H -#define _UCP_H - -/* This file contains definitions of the property values that are returned by -the function _pcre_ucp_findprop(). New values that are added for new releases -of Unicode should always be at the end of each enum, for backwards -compatibility. */ - -/* These are the general character categories. */ - -enum { - ucp_C, /* Other */ - ucp_L, /* Letter */ - ucp_M, /* Mark */ - ucp_N, /* Number */ - ucp_P, /* Punctuation */ - ucp_S, /* Symbol */ - ucp_Z /* Separator */ -}; - -/* These are the particular character types. */ - -enum { - ucp_Cc, /* Control */ - ucp_Cf, /* Format */ - ucp_Cn, /* Unassigned */ - ucp_Co, /* Private use */ - ucp_Cs, /* Surrogate */ - ucp_Ll, /* Lower case letter */ - ucp_Lm, /* Modifier letter */ - ucp_Lo, /* Other letter */ - ucp_Lt, /* Title case letter */ - ucp_Lu, /* Upper case letter */ - ucp_Mc, /* Spacing mark */ - ucp_Me, /* Enclosing mark */ - ucp_Mn, /* Non-spacing mark */ - ucp_Nd, /* Decimal number */ - ucp_Nl, /* Letter number */ - ucp_No, /* Other number */ - ucp_Pc, /* Connector punctuation */ - ucp_Pd, /* Dash punctuation */ - ucp_Pe, /* Close punctuation */ - ucp_Pf, /* Final punctuation */ - ucp_Pi, /* Initial punctuation */ - ucp_Po, /* Other punctuation */ - ucp_Ps, /* Open punctuation */ - ucp_Sc, /* Currency symbol */ - ucp_Sk, /* Modifier symbol */ - ucp_Sm, /* Mathematical symbol */ - ucp_So, /* Other symbol */ - ucp_Zl, /* Line separator */ - ucp_Zp, /* Paragraph separator */ - ucp_Zs /* Space separator */ -}; - -/* These are the script identifications. */ - -enum { - ucp_Arabic = G_UNICODE_SCRIPT_ARABIC, - ucp_Armenian = G_UNICODE_SCRIPT_ARMENIAN, - ucp_Bengali = G_UNICODE_SCRIPT_BENGALI, - ucp_Bopomofo = G_UNICODE_SCRIPT_BOPOMOFO, - ucp_Braille = G_UNICODE_SCRIPT_BRAILLE, - ucp_Buginese = G_UNICODE_SCRIPT_BUGINESE, - ucp_Buhid = G_UNICODE_SCRIPT_BUHID, - ucp_Canadian_Aboriginal = G_UNICODE_SCRIPT_CANADIAN_ABORIGINAL, - ucp_Cherokee = G_UNICODE_SCRIPT_CHEROKEE, - ucp_Common = G_UNICODE_SCRIPT_COMMON, - ucp_Coptic = G_UNICODE_SCRIPT_COPTIC, - ucp_Cypriot = G_UNICODE_SCRIPT_CYPRIOT, - ucp_Cyrillic = G_UNICODE_SCRIPT_CYRILLIC, - ucp_Deseret = G_UNICODE_SCRIPT_DESERET, - ucp_Devanagari = G_UNICODE_SCRIPT_DEVANAGARI, - ucp_Ethiopic = G_UNICODE_SCRIPT_ETHIOPIC, - ucp_Georgian = G_UNICODE_SCRIPT_GEORGIAN, - ucp_Glagolitic = G_UNICODE_SCRIPT_GLAGOLITIC, - ucp_Gothic = G_UNICODE_SCRIPT_GOTHIC, - ucp_Greek = G_UNICODE_SCRIPT_GREEK, - ucp_Gujarati = G_UNICODE_SCRIPT_GUJARATI, - ucp_Gurmukhi = G_UNICODE_SCRIPT_GURMUKHI, - ucp_Han = G_UNICODE_SCRIPT_HAN, - ucp_Hangul = G_UNICODE_SCRIPT_HANGUL, - ucp_Hanunoo = G_UNICODE_SCRIPT_HANUNOO, - ucp_Hebrew = G_UNICODE_SCRIPT_HEBREW, - ucp_Hiragana = G_UNICODE_SCRIPT_HIRAGANA, - ucp_Inherited = G_UNICODE_SCRIPT_INHERITED, - ucp_Kannada = G_UNICODE_SCRIPT_KANNADA, - ucp_Katakana = G_UNICODE_SCRIPT_KATAKANA, - ucp_Kharoshthi = G_UNICODE_SCRIPT_KHAROSHTHI, - ucp_Khmer = G_UNICODE_SCRIPT_KHMER, - ucp_Lao = G_UNICODE_SCRIPT_LAO, - ucp_Latin = G_UNICODE_SCRIPT_LATIN, - ucp_Limbu = G_UNICODE_SCRIPT_LIMBU, - ucp_Linear_B = G_UNICODE_SCRIPT_LINEAR_B, - ucp_Malayalam = G_UNICODE_SCRIPT_MALAYALAM, - ucp_Mongolian = G_UNICODE_SCRIPT_MONGOLIAN, - ucp_Myanmar = G_UNICODE_SCRIPT_MYANMAR, - ucp_New_Tai_Lue = G_UNICODE_SCRIPT_NEW_TAI_LUE, - ucp_Ogham = G_UNICODE_SCRIPT_OGHAM, - ucp_Old_Italic = G_UNICODE_SCRIPT_OLD_ITALIC, - ucp_Old_Persian = G_UNICODE_SCRIPT_OLD_PERSIAN, - ucp_Oriya = G_UNICODE_SCRIPT_ORIYA, - ucp_Osmanya = G_UNICODE_SCRIPT_OSMANYA, - ucp_Runic = G_UNICODE_SCRIPT_RUNIC, - ucp_Shavian = G_UNICODE_SCRIPT_SHAVIAN, - ucp_Sinhala = G_UNICODE_SCRIPT_SINHALA, - ucp_Syloti_Nagri = G_UNICODE_SCRIPT_SYLOTI_NAGRI, - ucp_Syriac = G_UNICODE_SCRIPT_SYRIAC, - ucp_Tagalog = G_UNICODE_SCRIPT_TAGALOG, - ucp_Tagbanwa = G_UNICODE_SCRIPT_TAGBANWA, - ucp_Tai_Le = G_UNICODE_SCRIPT_TAI_LE, - ucp_Tamil = G_UNICODE_SCRIPT_TAMIL, - ucp_Telugu = G_UNICODE_SCRIPT_TELUGU, - ucp_Thaana = G_UNICODE_SCRIPT_THAANA, - ucp_Thai = G_UNICODE_SCRIPT_THAI, - ucp_Tibetan = G_UNICODE_SCRIPT_TIBETAN, - ucp_Tifinagh = G_UNICODE_SCRIPT_TIFINAGH, - ucp_Ugaritic = G_UNICODE_SCRIPT_UGARITIC, - ucp_Yi = G_UNICODE_SCRIPT_YI, - ucp_Balinese = G_UNICODE_SCRIPT_BALINESE, /* New for Unicode 5.0.0 */ - ucp_Cuneiform = G_UNICODE_SCRIPT_CUNEIFORM, /* New for Unicode 5.0.0 */ - ucp_Nko = G_UNICODE_SCRIPT_NKO, /* New for Unicode 5.0.0 */ - ucp_Phags_Pa = G_UNICODE_SCRIPT_PHAGS_PA, /* New for Unicode 5.0.0 */ - ucp_Phoenician = G_UNICODE_SCRIPT_PHOENICIAN, /* New for Unicode 5.0.0 */ - ucp_Carian = G_UNICODE_SCRIPT_CARIAN, /* New for Unicode 5.1 */ - ucp_Cham = G_UNICODE_SCRIPT_CHAM, /* New for Unicode 5.1 */ - ucp_Kayah_Li = G_UNICODE_SCRIPT_KAYAH_LI, /* New for Unicode 5.1 */ - ucp_Lepcha = G_UNICODE_SCRIPT_LEPCHA, /* New for Unicode 5.1 */ - ucp_Lycian = G_UNICODE_SCRIPT_LYCIAN, /* New for Unicode 5.1 */ - ucp_Lydian = G_UNICODE_SCRIPT_LYDIAN, /* New for Unicode 5.1 */ - ucp_Ol_Chiki = G_UNICODE_SCRIPT_OL_CHIKI, /* New for Unicode 5.1 */ - ucp_Rejang = G_UNICODE_SCRIPT_REJANG, /* New for Unicode 5.1 */ - ucp_Saurashtra = G_UNICODE_SCRIPT_SAURASHTRA, /* New for Unicode 5.1 */ - ucp_Sundanese = G_UNICODE_SCRIPT_SUNDANESE, /* New for Unicode 5.1 */ - ucp_Vai = G_UNICODE_SCRIPT_VAI /* New for Unicode 5.1 */ -}; - -#endif - -/* End of ucp.h */ diff --git a/glib/pcre/ucpinternal.h b/glib/pcre/ucpinternal.h deleted file mode 100644 index a96667b0a..000000000 --- a/glib/pcre/ucpinternal.h +++ /dev/null @@ -1,92 +0,0 @@ -/************************************************* -* Unicode Property Table handler * -*************************************************/ - -#ifndef _UCPINTERNAL_H -#define _UCPINTERNAL_H - -/* Internal header file defining the layout of the bits in each pair of 32-bit -words that form a data item in the table. */ - -typedef struct cnode { - pcre_uint32 f0; - pcre_uint32 f1; -} cnode; - -/* Things for the f0 field */ - -#define f0_scriptmask 0xff000000 /* Mask for script field */ -#define f0_scriptshift 24 /* Shift for script value */ -#define f0_rangeflag 0x00800000 /* Flag for a range item */ -#define f0_charmask 0x001fffff /* Mask for code point value */ - -/* Things for the f1 field */ - -#define f1_typemask 0xfc000000 /* Mask for char type field */ -#define f1_typeshift 26 /* Shift for the type field */ -#define f1_rangemask 0x0000ffff /* Mask for a range offset */ -#define f1_casemask 0x0000ffff /* Mask for a case offset */ -#define f1_caseneg 0xffff8000 /* Bits for negation */ - -/* The data consists of a vector of structures of type cnode. The two unsigned -32-bit integers are used as follows: - -(f0) (1) The most significant byte holds the script number. The numbers are - defined by the enum in ucp.h. - - (2) The 0x00800000 bit is set if this entry defines a range of characters. - It is not set if this entry defines a single character - - (3) The 0x00600000 bits are spare. - - (4) The 0x001fffff bits contain the code point. No Unicode code point will - ever be greater than 0x0010ffff, so this should be OK for ever. - -(f1) (1) The 0xfc000000 bits contain the character type number. The numbers are - defined by an enum in ucp.h. - - (2) The 0x03ff0000 bits are spare. - - (3) The 0x0000ffff bits contain EITHER the unsigned offset to the top of - range if this entry defines a range, OR the *signed* offset to the - character's "other case" partner if this entry defines a single - character. There is no partner if the value is zero. - -------------------------------------------------------------------------------- -| script (8) |.|.|.| codepoint (21) || type (6) |.|.| spare (8) | offset (16) | -------------------------------------------------------------------------------- - | | | | | - | | |-> spare | |-> spare - | | | - | |-> spare |-> spare - | - |-> range flag - -The upper/lower casing information is set only for characters that come in -pairs. The non-one-to-one mappings in the Unicode data are ignored. - -When searching the data, proceed as follows: - -(1) Set up for a binary chop search. - -(2) If the top is not greater than the bottom, the character is not in the - table. Its type must therefore be "Cn" ("Undefined"). - -(3) Find the middle vector element. - -(4) Extract the code point and compare. If equal, we are done. - -(5) If the test character is smaller, set the top to the current point, and - goto (2). - -(6) If the current entry defines a range, compute the last character by adding - the offset, and see if the test character is within the range. If it is, - we are done. - -(7) Otherwise, set the bottom to one element past the current point and goto - (2). -*/ - -#endif /* _UCPINTERNAL_H */ - -/* End of ucpinternal.h */ diff --git a/glib/pltcheck.sh b/glib/pltcheck.sh deleted file mode 100755 index 236eeb141..000000000 --- a/glib/pltcheck.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -LANG=C - -status=0 - -if ! which readelf 2>/dev/null >/dev/null; then - echo "'readelf' not found; skipping test" - exit 0 -fi - -for so in .libs/lib*.so; do - echo Checking $so for local PLT entries - # g_string_insert_c is used in g_string_append_c_inline - # unaliased. Couldn't find a way to fix it. - # Same for g_once_init_enter - readelf -r $so | grep 'JU\?MP_SLOT\?' | \ - grep -v '\<g_string_insert_c\>' | \ - grep -v '\<g_atomic_[a-z]*_[sg]et\>' | \ - grep -v '\<g_once_init_enter_impl\>' | \ - grep -v '\<g_bit_' | \ - grep '\<g_' && status=1 -done - -exit $status diff --git a/glib/tests/.gitignore b/glib/tests/.gitignore deleted file mode 100644 index 5e917297e..000000000 --- a/glib/tests/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -array-test -fileutils -keyfile -markup-subparser -option-context -printf -rand -strfuncs -string -testing -tmpsample.xml diff --git a/glib/tests/4096-random-bytes b/glib/tests/4096-random-bytes deleted file mode 100644 index 3e7a7db31..000000000 --- a/glib/tests/4096-random-bytes +++ /dev/null @@ -1,45 +0,0 @@ -MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXOxdolodx0WMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWMMMMMMMMMMMMMMMMMM0l' :NMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM0c. .:KMMMMMMMMMMMWd. ,MMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN, XMMMMMMMMMk. .MMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM' oMMMMMMMMc oMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMMMNklclkWMMMMMM0 lMMMMMMMc ;MMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMW: .XMMMMMk OMMMMMMx ;WMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMc 'MMMMMK .MMMMMMW. dMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMM. KMMMMM' 0MMMMMM0 ,KMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMM: OMMMMMK OMMMMMMM0 .OMMMMMMMMMMMMMMMM -MMMMMMMMMMMMW0kONMMMMMK KMMMMMMX, ,KMMMMMMMMW. ,kMMMMMMMMMMMMMMMMMM -MMMMMMMMMMWc lWMMMMO .MMMMMMMMMKxxXMMMMMMMMMMM0. .lXMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMM; 'WMMMMN: 0MMMMMMMMMMMMMMMMMMMMMMMMMNl'. ..:xXMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMM. oMMMMMMXdldNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMx .MMMMMMMMMMMMMMMMMMMMMMMWXK0OkkkkkkO0XNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMx NMMMMMMMMMMMMMMWKko:'. .;d0WMMMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMK, .MMMMMMMMMMW0o;. :KMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMXo;';KMMMMMMMKo' cMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMMMXl. xMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMk' :MMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMO. dMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMWc ,WMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMN. cWMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMW' '0MMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMd :KMMMMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMM. 'dNMMMMMMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMM 'oXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMM. ,xNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMM; .:kNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMO .l0MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMM, :KMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMN. oNMMMMMMMMMMMMMXkoc:,,,,:lOWMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMX. .XMMMMMMMMMMMM0:. .XMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMN. xMMMMMMMMMMMM0 OMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMWc 'NMMMMMMMMMMMO 'WMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMO. .kMMMMMMMMMMc .XMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMMWl .l0WMMMW0; .KMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMMMMNl ... ;NMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMMMMMMWd. .OMMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM0c. 'xWMMMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM0l. .cKMMMMMMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNOo;. .;dKMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNKOxxdddkOXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM -MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM. diff --git a/glib/tests/Makefile.am b/glib/tests/Makefile.am deleted file mode 100644 index 3d497ac23..000000000 --- a/glib/tests/Makefile.am +++ /dev/null @@ -1,62 +0,0 @@ -include $(top_srcdir)/Makefile.decl - -INCLUDES = -g -I$(top_srcdir) -I$(top_srcdir)/glib $(GLIB_DEBUG_FLAGS) - -noinst_PROGRAMS = $(TEST_PROGS) -progs_ldadd = $(top_builddir)/glib/libglib-2.0.la - - -TEST_PROGS += testing -testing_SOURCES = testing.c -testing_LDADD = $(progs_ldadd) - -TEST_PROGS += option-context -option_context_SOURCES = option-context.c -option_context_LDADD = $(progs_ldadd) - -TEST_PROGS += keyfile -keyfile_SOURCES = keyfile.c -keyfile_LDADD = $(progs_ldadd) - -TEST_PROGS += fileutils -fileutils_SOURCES = fileutils.c -fileutils_LDADD = $(progs_ldadd) - -TEST_PROGS += printf -printf_SOURCES = printf.c -printf_LDADD = $(progs_ldadd) -lm - -TEST_PROGS += rand -rand_SOURCES = rand.c -rand_LDADD = $(progs_ldadd) -lm - -TEST_PROGS += strfuncs -strfuncs_SOURCES = strfuncs.c -strfuncs_LDADD = $(progs_ldadd) -lm - -TEST_PROGS += string -string_SOURCES = string.c -string_LDADD = $(progs_ldadd) -lm - -TEST_PROGS += markup-subparser -markup_subparser_LDADD = $(progs_ldadd) - -TEST_PROGS += array-test -array_test_LDADD = $(progs_ldadd) - -if OS_UNIX - -# some testing of gtester funcitonality -XMLLINT=xmllint -gtester-xmllint-check: # check testreport xml with xmllint if present - ${GTESTER} -k --quiet -o tmpsample.xml --test-arg=--gtester-selftest ${GTESTER} - ${XMLLINT} --version 2>/dev/null; test "$$?" != 0 || ${XMLLINT} --noout tmpsample.xml -check-am: gtester-xmllint-check - -endif - -CLEANFILES = \ - tmpsample.xml - -EXTRA_DIST += \ - 4096-random-bytes diff --git a/glib/tests/array-test.c b/glib/tests/array-test.c deleted file mode 100644 index 6f83a2762..000000000 --- a/glib/tests/array-test.c +++ /dev/null @@ -1,133 +0,0 @@ -/* 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 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, 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/. - */ - -#undef G_DISABLE_ASSERT -#undef G_LOG_DOMAIN - -#include <stdio.h> -#include <string.h> -#include "glib.h" - -static void -sum_up (gpointer data, - gpointer user_data) -{ - gint *sum = (gint *)user_data; - - *sum += GPOINTER_TO_INT (data); -} - -static void -array_append (void) -{ - GArray *garray; - gint i; - - garray = g_array_new (FALSE, FALSE, sizeof (gint)); - for (i = 0; i < 10000; i++) - g_array_append_val (garray, i); - - for (i = 0; i < 10000; i++) - g_assert_cmpint (g_array_index (garray, gint, i), ==, i); - - g_array_free (garray, TRUE); -} - -static void -array_prepend (void) -{ - GArray *garray; - gint i; - - garray = g_array_new (FALSE, FALSE, sizeof (gint)); - for (i = 0; i < 100; i++) - g_array_prepend_val (garray, i); - - for (i = 0; i < 100; i++) - g_assert_cmpint (g_array_index (garray, gint, i), ==, (100 - i - 1)); - - g_array_free (garray, TRUE); -} - -static void -pointer_array_add (void) -{ - GPtrArray *gparray; - gint i; - gint sum = 0; - - gparray = g_ptr_array_new (); - for (i = 0; i < 10000; i++) - g_ptr_array_add (gparray, GINT_TO_POINTER (i)); - - for (i = 0; i < 10000; i++) - g_assert (g_ptr_array_index (gparray, i) == GINT_TO_POINTER (i)); - - g_ptr_array_foreach (gparray, sum_up, &sum); - g_assert (sum == 49995000); - - g_ptr_array_free (gparray, TRUE); -} - -static void -byte_array_append (void) -{ - GByteArray *gbarray; - gint i; - - gbarray = g_byte_array_new (); - for (i = 0; i < 10000; i++) - g_byte_array_append (gbarray, (guint8*) "abcd", 4); - - for (i = 0; i < 10000; i++) - { - g_assert (gbarray->data[4*i] == 'a'); - g_assert (gbarray->data[4*i+1] == 'b'); - g_assert (gbarray->data[4*i+2] == 'c'); - g_assert (gbarray->data[4*i+3] == 'd'); - } - - g_byte_array_free (gbarray, TRUE); -} - -int -main (int argc, char *argv[]) -{ - g_test_init (&argc, &argv, NULL); - - /* array tests */ - g_test_add_func ("/array/append", array_append); - g_test_add_func ("/array/prepend", array_prepend); - - /* pointer arrays */ - g_test_add_func ("/pointerarray/add", pointer_array_add); - - /* byte arrays */ - g_test_add_func ("/bytearray/append", byte_array_append); - - return g_test_run (); -} - diff --git a/glib/tests/fileutils.c b/glib/tests/fileutils.c deleted file mode 100644 index 225c6ce35..000000000 --- a/glib/tests/fileutils.c +++ /dev/null @@ -1,508 +0,0 @@ -/* Unit tests for gfileutils - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * This work is provided "as is"; redistribution and modification - * in whole or in part, in any medium, physical or electronic is - * permitted without restriction. - * - * This work 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. - */ - -#include <string.h> -#include <errno.h> -#include <glib.h> -#include <glib/gstdio.h> - -#define S G_DIR_SEPARATOR_S - -static void -check_string (gchar *str, gchar *expected) -{ - g_assert (str != NULL); - g_assert_cmpstr (str, ==, expected); - g_free (str); -} - -static void -test_build_path (void) -{ -/* check_string (g_build_path ("", NULL), "");*/ - check_string (g_build_path ("", "", NULL), ""); - check_string (g_build_path ("", "x", NULL), "x"); - check_string (g_build_path ("", "x", "y", NULL), "xy"); - check_string (g_build_path ("", "x", "y", "z", NULL), "xyz"); - -/* check_string (g_build_path (":", NULL), "");*/ - check_string (g_build_path (":", ":", NULL), ":"); - check_string (g_build_path (":", ":x", NULL), ":x"); - check_string (g_build_path (":", "x:", NULL), "x:"); - check_string (g_build_path (":", "", "x", NULL), "x"); - check_string (g_build_path (":", "", ":x", NULL), ":x"); - check_string (g_build_path (":", ":", "x", NULL), ":x"); - check_string (g_build_path (":", "::", "x", NULL), "::x"); - check_string (g_build_path (":", "x", "", NULL), "x"); - check_string (g_build_path (":", "x:", "", NULL), "x:"); - check_string (g_build_path (":", "x", ":", NULL), "x:"); - check_string (g_build_path (":", "x", "::", NULL), "x::"); - check_string (g_build_path (":", "x", "y", NULL), "x:y"); - check_string (g_build_path (":", ":x", "y", NULL), ":x:y"); - check_string (g_build_path (":", "x", "y:", NULL), "x:y:"); - check_string (g_build_path (":", ":x:", ":y:", NULL), ":x:y:"); - check_string (g_build_path (":", ":x::", "::y:", NULL), ":x:y:"); - check_string (g_build_path (":", "x", "","y", NULL), "x:y"); - check_string (g_build_path (":", "x", ":", "y", NULL), "x:y"); - check_string (g_build_path (":", "x", "::", "y", NULL), "x:y"); - check_string (g_build_path (":", "x", "y", "z", NULL), "x:y:z"); - check_string (g_build_path (":", ":x:", ":y:", ":z:", NULL), ":x:y:z:"); - check_string (g_build_path (":", "::x::", "::y::", "::z::", NULL), "::x:y:z::"); - -/* check_string (g_build_path ("::", NULL), "");*/ - check_string (g_build_path ("::", "::", NULL), "::"); - check_string (g_build_path ("::", ":::", NULL), ":::"); - check_string (g_build_path ("::", "::x", NULL), "::x"); - check_string (g_build_path ("::", "x::", NULL), "x::"); - check_string (g_build_path ("::", "", "x", NULL), "x"); - check_string (g_build_path ("::", "", "::x", NULL), "::x"); - check_string (g_build_path ("::", "::", "x", NULL), "::x"); - check_string (g_build_path ("::", "::::", "x", NULL), "::::x"); - check_string (g_build_path ("::", "x", "", NULL), "x"); - check_string (g_build_path ("::", "x::", "", NULL), "x::"); - check_string (g_build_path ("::", "x", "::", NULL), "x::"); - - /* This following is weird, but keeps the definition simple */ - check_string (g_build_path ("::", "x", ":::", NULL), "x:::::"); - check_string (g_build_path ("::", "x", "::::", NULL), "x::::"); - check_string (g_build_path ("::", "x", "y", NULL), "x::y"); - check_string (g_build_path ("::", "::x", "y", NULL), "::x::y"); - check_string (g_build_path ("::", "x", "y::", NULL), "x::y::"); - check_string (g_build_path ("::", "::x::", "::y::", NULL), "::x::y::"); - check_string (g_build_path ("::", "::x:::", ":::y::", NULL), "::x::::y::"); - check_string (g_build_path ("::", "::x::::", "::::y::", NULL), "::x::y::"); - check_string (g_build_path ("::", "x", "", "y", NULL), "x::y"); - check_string (g_build_path ("::", "x", "::", "y", NULL), "x::y"); - check_string (g_build_path ("::", "x", "::::", "y", NULL), "x::y"); - check_string (g_build_path ("::", "x", "y", "z", NULL), "x::y::z"); - check_string (g_build_path ("::", "::x::", "::y::", "::z::", NULL), "::x::y::z::"); - check_string (g_build_path ("::", ":::x:::", ":::y:::", ":::z:::", NULL), ":::x::::y::::z:::"); - check_string (g_build_path ("::", "::::x::::", "::::y::::", "::::z::::", NULL), "::::x::y::z::::"); -} - -static void -test_build_pathv (void) -{ - gchar *args[10]; - - args[0] = NULL; - check_string (g_build_pathv ("", args), ""); - args[0] = ""; args[1] = NULL; - check_string (g_build_pathv ("", args), ""); - args[0] = "x"; args[1] = NULL; - check_string (g_build_pathv ("", args), "x"); - args[0] = "x"; args[1] = "y"; args[2] = NULL; - check_string (g_build_pathv ("", args), "xy"); - args[0] = "x"; args[1] = "y"; args[2] = "z", args[3] = NULL; - check_string (g_build_pathv ("", args), "xyz"); - - args[0] = NULL; - check_string (g_build_pathv (":", args), ""); - args[0] = ":"; args[1] = NULL; - check_string (g_build_pathv (":", args), ":"); - args[0] = ":x"; args[1] = NULL; - check_string (g_build_pathv (":", args), ":x"); - args[0] = "x:"; args[1] = NULL; - check_string (g_build_pathv (":", args), "x:"); - args[0] = ""; args[1] = "x"; args[2] = NULL; - check_string (g_build_pathv (":", args), "x"); - args[0] = ""; args[1] = ":x"; args[2] = NULL; - check_string (g_build_pathv (":", args), ":x"); - args[0] = ":"; args[1] = "x"; args[2] = NULL; - check_string (g_build_pathv (":", args), ":x"); - args[0] = "::"; args[1] = "x"; args[2] = NULL; - check_string (g_build_pathv (":", args), "::x"); - args[0] = "x"; args[1] = ""; args[2] = NULL; - check_string (g_build_pathv (":", args), "x"); - args[0] = "x:"; args[1] = ""; args[2] = NULL; - check_string (g_build_pathv (":", args), "x:"); - args[0] = "x"; args[1] = ":"; args[2] = NULL; - check_string (g_build_pathv (":", args), "x:"); - args[0] = "x"; args[1] = "::"; args[2] = NULL; - check_string (g_build_pathv (":", args), "x::"); - args[0] = "x"; args[1] = "y"; args[2] = NULL; - check_string (g_build_pathv (":", args), "x:y"); - args[0] = ":x"; args[1] = "y"; args[2] = NULL; - check_string (g_build_pathv (":", args), ":x:y"); - args[0] = "x"; args[1] = "y:"; args[2] = NULL; - check_string (g_build_pathv (":", args), "x:y:"); - args[0] = ":x:"; args[1] = ":y:"; args[2] = NULL; - check_string (g_build_pathv (":", args), ":x:y:"); - args[0] = ":x::"; args[1] = "::y:"; args[2] = NULL; - check_string (g_build_pathv (":", args), ":x:y:"); - args[0] = "x"; args[1] = ""; args[2] = "y"; args[3] = NULL; - check_string (g_build_pathv (":", args), "x:y"); - args[0] = "x"; args[1] = ":"; args[2] = "y"; args[3] = NULL; - check_string (g_build_pathv (":", args), "x:y"); - args[0] = "x"; args[1] = "::"; args[2] = "y"; args[3] = NULL; - check_string (g_build_pathv (":", args), "x:y"); - args[0] = "x"; args[1] = "y"; args[2] = "z"; args[3] = NULL; - check_string (g_build_pathv (":", args), "x:y:z"); - args[0] = ":x:"; args[1] = ":y:"; args[2] = ":z:"; args[3] = NULL; - check_string (g_build_pathv (":", args), ":x:y:z:"); - args[0] = "::x::"; args[1] = "::y::"; args[2] = "::z::"; args[3] = NULL; - check_string (g_build_pathv (":", args), "::x:y:z::"); - - args[0] = NULL; - check_string (g_build_pathv ("::", args), ""); - args[0] = "::"; args[1] = NULL; - check_string (g_build_pathv ("::", args), "::"); - args[0] = ":::"; args[1] = NULL; - check_string (g_build_pathv ("::", args), ":::"); - args[0] = "::x"; args[1] = NULL; - check_string (g_build_pathv ("::", args), "::x"); - args[0] = "x::"; args[1] = NULL; - check_string (g_build_pathv ("::", args), "x::"); - args[0] = ""; args[1] = "x"; args[2] = NULL; - check_string (g_build_pathv ("::", args), "x"); - args[0] = ""; args[1] = "::x"; args[2] = NULL; - check_string (g_build_pathv ("::", args), "::x"); - args[0] = "::"; args[1] = "x"; args[2] = NULL; - check_string (g_build_pathv ("::", args), "::x"); - args[0] = "::::"; args[1] = "x"; args[2] = NULL; - check_string (g_build_pathv ("::", args), "::::x"); - args[0] = "x"; args[1] = ""; args[2] = NULL; - check_string (g_build_pathv ("::", args), "x"); - args[0] = "x::"; args[1] = ""; args[2] = NULL; - check_string (g_build_pathv ("::", args), "x::"); - args[0] = "x"; args[1] = "::"; args[2] = NULL; - check_string (g_build_pathv ("::", args), "x::"); - /* This following is weird, but keeps the definition simple */ - args[0] = "x"; args[1] = ":::"; args[2] = NULL; - check_string (g_build_pathv ("::", args), "x:::::"); - args[0] = "x"; args[1] = "::::"; args[2] = NULL; - check_string (g_build_pathv ("::", args), "x::::"); - args[0] = "x"; args[1] = "y"; args[2] = NULL; - check_string (g_build_pathv ("::", args), "x::y"); - args[0] = "::x"; args[1] = "y"; args[2] = NULL; - check_string (g_build_pathv ("::", args), "::x::y"); - args[0] = "x"; args[1] = "y::"; args[2] = NULL; - check_string (g_build_pathv ("::", args), "x::y::"); - args[0] = "::x::"; args[1] = "::y::"; args[2] = NULL; - check_string (g_build_pathv ("::", args), "::x::y::"); - args[0] = "::x:::"; args[1] = ":::y::"; args[2] = NULL; - check_string (g_build_pathv ("::", args), "::x::::y::"); - args[0] = "::x::::"; args[1] = "::::y::"; args[2] = NULL; - check_string (g_build_pathv ("::", args), "::x::y::"); - args[0] = "x"; args[1] = ""; args[2] = "y"; args[3] = NULL; - check_string (g_build_pathv ("::", args), "x::y"); - args[0] = "x"; args[1] = "::"; args[2] = "y"; args[3] = NULL; - check_string (g_build_pathv ("::", args), "x::y"); - args[0] = "x"; args[1] = "::::"; args[2] = "y"; args[3] = NULL; - check_string (g_build_pathv ("::", args), "x::y"); - args[0] = "x"; args[1] = "y"; args[2] = "z"; args[3] = NULL; - check_string (g_build_pathv ("::", args), "x::y::z"); - args[0] = "::x::"; args[1] = "::y::"; args[2] = "::z::"; args[3] = NULL; - check_string (g_build_pathv ("::", args), "::x::y::z::"); - args[0] = ":::x:::"; args[1] = ":::y:::"; args[2] = ":::z:::"; args[3] = NULL; - check_string (g_build_pathv ("::", args), ":::x::::y::::z:::"); - args[0] = "::::x::::"; args[1] = "::::y::::"; args[2] = "::::z::::"; args[3] = NULL; - check_string (g_build_pathv ("::", args), "::::x::y::z::::"); -} - -static void -test_build_filename (void) -{ -/* check_string (g_build_filename (NULL), "");*/ - check_string (g_build_filename (S, NULL), S); - check_string (g_build_filename (S"x", NULL), S"x"); - check_string (g_build_filename ("x"S, NULL), "x"S); - check_string (g_build_filename ("", "x", NULL), "x"); - check_string (g_build_filename ("", S"x", NULL), S"x"); - check_string (g_build_filename (S, "x", NULL), S"x"); - check_string (g_build_filename (S S, "x", NULL), S S"x"); - check_string (g_build_filename ("x", "", NULL), "x"); - check_string (g_build_filename ("x"S, "", NULL), "x"S); - check_string (g_build_filename ("x", S, NULL), "x"S); - check_string (g_build_filename ("x", S S, NULL), "x"S S); - check_string (g_build_filename ("x", "y", NULL), "x"S"y"); - check_string (g_build_filename (S"x", "y", NULL), S"x"S"y"); - check_string (g_build_filename ("x", "y"S, NULL), "x"S"y"S); - check_string (g_build_filename (S"x"S, S"y"S, NULL), S"x"S"y"S); - check_string (g_build_filename (S"x"S S, S S"y"S, NULL), S"x"S"y"S); - check_string (g_build_filename ("x", "", "y", NULL), "x"S"y"); - check_string (g_build_filename ("x", S, "y", NULL), "x"S"y"); - check_string (g_build_filename ("x", S S, "y", NULL), "x"S"y"); - check_string (g_build_filename ("x", "y", "z", NULL), "x"S"y"S"z"); - check_string (g_build_filename (S"x"S, S"y"S, S"z"S, NULL), S"x"S"y"S"z"S); - check_string (g_build_filename (S S"x"S S, S S"y"S S, S S"z"S S, NULL), S S"x"S"y"S"z"S S); - -#ifdef G_OS_WIN32 - - /* Test also using the slash as file name separator */ -#define U "/" - check_string (g_build_filename (NULL), ""); - check_string (g_build_filename (U, NULL), U); - check_string (g_build_filename (U"x", NULL), U"x"); - check_string (g_build_filename ("x"U, NULL), "x"U); - check_string (g_build_filename ("", U"x", NULL), U"x"); - check_string (g_build_filename ("", U"x", NULL), U"x"); - check_string (g_build_filename (U, "x", NULL), U"x"); - check_string (g_build_filename (U U, "x", NULL), U U"x"); - check_string (g_build_filename (U S, "x", NULL), U S"x"); - check_string (g_build_filename ("x"U, "", NULL), "x"U); - check_string (g_build_filename ("x"S"y", "z"U"a", NULL), "x"S"y"S"z"U"a"); - check_string (g_build_filename ("x", U, NULL), "x"U); - check_string (g_build_filename ("x", U U, NULL), "x"U U); - check_string (g_build_filename ("x", S U, NULL), "x"S U); - check_string (g_build_filename (U"x", "y", NULL), U"x"U"y"); - check_string (g_build_filename ("x", "y"U, NULL), "x"U"y"U); - check_string (g_build_filename (U"x"U, U"y"U, NULL), U"x"U"y"U); - check_string (g_build_filename (U"x"U U, U U"y"U, NULL), U"x"U"y"U); - check_string (g_build_filename ("x", U, "y", NULL), "x"U"y"); - check_string (g_build_filename ("x", U U, "y", NULL), "x"U"y"); - check_string (g_build_filename ("x", U S, "y", NULL), "x"S"y"); - check_string (g_build_filename ("x", S U, "y", NULL), "x"U"y"); - check_string (g_build_filename ("x", U "y", "z", NULL), "x"U"y"U"z"); - check_string (g_build_filename ("x", S "y", "z", NULL), "x"S"y"S"z"); - check_string (g_build_filename ("x", S "y", "z", U, "a", "b", NULL), "x"S"y"S"z"U"a"U"b"); - check_string (g_build_filename (U"x"U, U"y"U, U"z"U, NULL), U"x"U"y"U"z"U); - check_string (g_build_filename (U U"x"U U, U U"y"U U, U U"z"U U, NULL), U U"x"U"y"U"z"U U); - -#undef U - -#endif /* G_OS_WIN32 */ - -} - -static void -test_build_filenamev (void) -{ - gchar *args[10]; - - args[0] = NULL; - check_string (g_build_filenamev (args), ""); - args[0] = S; args[1] = NULL; - check_string (g_build_filenamev (args), S); - args[0] = S"x"; args[1] = NULL; - check_string (g_build_filenamev (args), S"x"); - args[0] = "x"S; args[1] = NULL; - check_string (g_build_filenamev (args), "x"S); - args[0] = ""; args[1] = "x"; args[2] = NULL; - check_string (g_build_filenamev (args), "x"); - args[0] = ""; args[1] = S"x"; args[2] = NULL; - check_string (g_build_filenamev (args), S"x"); - args[0] = S; args[1] = "x"; args[2] = NULL; - check_string (g_build_filenamev (args), S"x"); - args[0] = S S; args[1] = "x"; args[2] = NULL; - check_string (g_build_filenamev (args), S S"x"); - args[0] = "x"; args[1] = ""; args[2] = NULL; - check_string (g_build_filenamev (args), "x"); - args[0] = "x"S; args[1] = ""; args[2] = NULL; - check_string (g_build_filenamev (args), "x"S); - args[0] = "x"; args[1] = S; args[2] = NULL; - check_string (g_build_filenamev (args), "x"S); - args[0] = "x"; args[1] = S S; args[2] = NULL; - check_string (g_build_filenamev (args), "x"S S); - args[0] = "x"; args[1] = "y"; args[2] = NULL; - check_string (g_build_filenamev (args), "x"S"y"); - args[0] = S"x"; args[1] = "y"; args[2] = NULL; - check_string (g_build_filenamev (args), S"x"S"y"); - args[0] = "x"; args[1] = "y"S; args[2] = NULL; - check_string (g_build_filenamev (args), "x"S"y"S); - args[0] = S"x"S; args[1] = S"y"S; args[2] = NULL; - check_string (g_build_filenamev (args), S"x"S"y"S); - args[0] = S"x"S S; args[1] = S S"y"S; args[2] = NULL; - check_string (g_build_filenamev (args), S"x"S"y"S); - args[0] = "x"; args[1] = ""; args[2] = "y"; args[3] = NULL; - check_string (g_build_filenamev (args), "x"S"y"); - args[0] = "x"; args[1] = S; args[2] = "y"; args[3] = NULL; - check_string (g_build_filenamev (args), "x"S"y"); - args[0] = "x"; args[1] = S S; args[2] = "y"; args[3] = NULL; - check_string (g_build_filenamev (args), "x"S"y"); - args[0] = "x"; args[1] = "y"; args[2] = "z"; args[3] = NULL; - check_string (g_build_filenamev (args), "x"S"y"S"z"); - args[0] = S"x"S; args[1] = S"y"S; args[2] = S"z"S; args[3] = NULL; - check_string (g_build_filenamev (args), S"x"S"y"S"z"S); - args[0] = S S"x"S S; args[1] = S S"y"S S; args[2] = S S"z"S S; args[3] = NULL; - check_string (g_build_filenamev (args), S S"x"S"y"S"z"S S); - -#ifdef G_OS_WIN32 - - /* Test also using the slash as file name separator */ -#define U "/" - args[0] = NULL; - check_string (g_build_filenamev (args), ""); - args[0] = U; args[1] = NULL; - check_string (g_build_filenamev (args), U); - args[0] = U"x"; args[1] = NULL; - check_string (g_build_filenamev (args), U"x"); - args[0] = "x"U; args[1] = NULL; - check_string (g_build_filenamev (args), "x"U); - args[0] = ""; args[1] = U"x"; args[2] = NULL; - check_string (g_build_filenamev (args), U"x"); - args[0] = ""; args[1] = U"x"; args[2] = NULL; - check_string (g_build_filenamev (args), U"x"); - args[0] = U; args[1] = "x"; args[2] = NULL; - check_string (g_build_filenamev (args), U"x"); - args[0] = U U; args[1] = "x"; args[2] = NULL; - check_string (g_build_filenamev (args), U U"x"); - args[0] = U S; args[1] = "x"; args[2] = NULL; - check_string (g_build_filenamev (args), U S"x"); - args[0] = "x"U; args[1] = ""; args[2] = NULL; - check_string (g_build_filenamev (args), "x"U); - args[0] = "x"S"y"; args[1] = "z"U"a"; args[2] = NULL; - check_string (g_build_filenamev (args), "x"S"y"S"z"U"a"); - args[0] = "x"; args[1] = U; args[2] = NULL; - check_string (g_build_filenamev (args), "x"U); - args[0] = "x"; args[1] = U U; args[2] = NULL; - check_string (g_build_filenamev (args), "x"U U); - args[0] = "x"; args[1] = S U; args[2] = NULL; - check_string (g_build_filenamev (args), "x"S U); - args[0] = U"x"; args[1] = "y"; args[2] = NULL; - check_string (g_build_filenamev (args), U"x"U"y"); - args[0] = "x"; args[1] = "y"U; args[2] = NULL; - check_string (g_build_filenamev (args), "x"U"y"U); - args[0] = U"x"U; args[1] = U"y"U; args[2] = NULL; - check_string (g_build_filenamev (args), U"x"U"y"U); - args[0] = U"x"U U; args[1] = U U"y"U; args[2] = NULL; - check_string (g_build_filenamev (args), U"x"U"y"U); - args[0] = "x"; args[1] = U; args[2] = "y", args[3] = NULL; - check_string (g_build_filenamev (args), "x"U"y"); - args[0] = "x"; args[1] = U U; args[2] = "y", args[3] = NULL; - check_string (g_build_filenamev (args), "x"U"y"); - args[0] = "x"; args[1] = U S; args[2] = "y", args[3] = NULL; - check_string (g_build_filenamev (args), "x"S"y"); - args[0] = "x"; args[1] = S U; args[2] = "y", args[3] = NULL; - check_string (g_build_filenamev (args), "x"U"y"); - args[0] = "x"; args[1] = U "y"; args[2] = "z", args[3] = NULL; - check_string (g_build_filenamev (args), "x"U"y"U"z"); - args[0] = "x"; args[1] = S "y"; args[2] = "z", args[3] = NULL; - check_string (g_build_filenamev (args), "x"S"y"S"z"); - args[0] = "x"; args[1] = S "y"; args[2] = "z", args[3] = U; - args[4] = "a"; args[5] = "b"; args[6] = NULL; - check_string (g_build_filenamev (args), "x"S"y"S"z"U"a"U"b"); - args[0] = U"x"U; args[1] = U"y"U; args[2] = U"z"U, args[3] = NULL; - check_string (g_build_filenamev (args), U"x"U"y"U"z"U); - args[0] = U U"x"U U; args[1] = U U"y"U U; args[2] = U U"z"U U, args[3] = NULL; - check_string (g_build_filenamev (args), U U"x"U"y"U"z"U U); - -#undef U - -#endif /* G_OS_WIN32 */ -} - -#undef S - -static void -test_mkdir_with_parents_1 (const gchar *base) -{ - char *p0 = g_build_filename (base, "fum", NULL); - char *p1 = g_build_filename (p0, "tem", NULL); - char *p2 = g_build_filename (p1, "zap", NULL); - FILE *f; - - g_remove (p2); - g_remove (p1); - g_remove (p0); - - if (g_file_test (p0, G_FILE_TEST_EXISTS)) - g_error ("failed, %s exists, cannot test g_mkdir_with_parents\n", p0); - - if (g_file_test (p1, G_FILE_TEST_EXISTS)) - g_error ("failed, %s exists, cannot test g_mkdir_with_parents\n", p1); - - if (g_file_test (p2, G_FILE_TEST_EXISTS)) - g_error ("failed, %s exists, cannot test g_mkdir_with_parents\n", p2); - - if (g_mkdir_with_parents (p2, 0777) == -1) - g_error ("failed, g_mkdir_with_parents(%s) failed: %s\n", p2, g_strerror (errno)); - - if (!g_file_test (p2, G_FILE_TEST_IS_DIR)) - g_error ("failed, g_mkdir_with_parents(%s) succeeded, but %s is not a directory\n", p2, p2); - - if (!g_file_test (p1, G_FILE_TEST_IS_DIR)) - g_error ("failed, g_mkdir_with_parents(%s) succeeded, but %s is not a directory\n", p2, p1); - - if (!g_file_test (p0, G_FILE_TEST_IS_DIR)) - g_error ("failed, g_mkdir_with_parents(%s) succeeded, but %s is not a directory\n", p2, p0); - - g_rmdir (p2); - if (g_file_test (p2, G_FILE_TEST_EXISTS)) - g_error ("failed, did g_rmdir(%s), but %s is still there\n", p2, p2); - - g_rmdir (p1); - if (g_file_test (p1, G_FILE_TEST_EXISTS)) - g_error ("failed, did g_rmdir(%s), but %s is still there\n", p1, p1); - - f = g_fopen (p1, "w"); - if (f == NULL) - g_error ("failed, couldn't create file %s\n", p1); - fclose (f); - - if (g_mkdir_with_parents (p1, 0666) == 0) - g_error ("failed, g_mkdir_with_parents(%s) succeeded, even if %s is a file\n", p1, p1); - - if (g_mkdir_with_parents (p2, 0666) == 0) - g_error("failed, g_mkdir_with_parents(%s) succeeded, even if %s is a file\n", p2, p1); - - g_remove (p2); - g_remove (p1); - g_remove (p0); -} - -static void -test_mkdir_with_parents (void) -{ - gchar *cwd; - if (g_test_verbose()) - g_print ("checking g_mkdir_with_parents() in subdir ./hum/"); - test_mkdir_with_parents_1 ("hum"); - g_remove ("hum"); - if (g_test_verbose()) - g_print ("checking g_mkdir_with_parents() in subdir ./hii///haa/hee/"); - test_mkdir_with_parents_1 ("hii///haa/hee"); - g_remove ("hii/haa/hee"); - g_remove ("hii/haa"); - g_remove ("hii"); - cwd = g_get_current_dir (); - if (g_test_verbose()) - g_print ("checking g_mkdir_with_parents() in cwd: %s", cwd); - test_mkdir_with_parents_1 (cwd); - g_free (cwd); -} - -static void -test_format_size_for_display (void) -{ - check_string (g_format_size_for_display (0), "0 bytes"); - check_string (g_format_size_for_display (1), "1 byte"); - check_string (g_format_size_for_display (2), "2 bytes"); - check_string (g_format_size_for_display (1024), "1.0 KB"); - check_string (g_format_size_for_display (1024 * 1024), "1.0 MB"); - check_string (g_format_size_for_display (1024 * 1024 * 1024), "1.0 GB"); -} - -int -main (int argc, - char *argv[]) -{ - g_test_init (&argc, &argv, NULL); - - g_test_add_func ("/fileutils/build-path", test_build_path); - g_test_add_func ("/fileutils/build-pathv", test_build_pathv); - g_test_add_func ("/fileutils/build-filename", test_build_filename); - g_test_add_func ("/fileutils/build-filenamev", test_build_filenamev); - g_test_add_func ("/fileutils/mkdir-with-parents", test_mkdir_with_parents); - g_test_add_func ("/fileutils/format-size-for-display", test_format_size_for_display); - - return g_test_run(); -} diff --git a/glib/tests/keyfile.c b/glib/tests/keyfile.c deleted file mode 100644 index ba8cd1e61..000000000 --- a/glib/tests/keyfile.c +++ /dev/null @@ -1,1262 +0,0 @@ -#include <glib.h> -#include <locale.h> -#include <string.h> -#include <stdlib.h> - -static GKeyFile * -load_data (const gchar *data, - GKeyFileFlags flags) -{ - GKeyFile *keyfile; - GError *error = NULL; - - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, data, -1, flags, &error); - g_assert_no_error (error); - return keyfile; -} - -static void -check_error (GError **error, - GQuark domain, - gint code) -{ - g_assert_error (*error, domain, code); - g_error_free (*error); - *error = NULL; -} - -static void -check_no_error (GError **error) -{ - g_assert_no_error (*error); -} - -static void -check_string_value (GKeyFile *keyfile, - const gchar *group, - const gchar *key, - const gchar *expected) -{ - GError *error = NULL; - gchar *value; - - value = g_key_file_get_string (keyfile, group, key, &error); - check_no_error (&error); - g_assert (value != NULL); - g_assert_cmpstr (value, ==, expected); - g_free (value); -} - -static void -check_locale_string_value (GKeyFile *keyfile, - const gchar *group, - const gchar *key, - const gchar *locale, - const gchar *expected) -{ - GError *error = NULL; - gchar *value; - - value = g_key_file_get_locale_string (keyfile, group, key, locale, &error); - check_no_error (&error); - g_assert (value != NULL); - g_assert_cmpstr (value, ==, expected); - g_free (value); -} - -static void -check_string_list_value (GKeyFile *keyfile, - const gchar *group, - const gchar *key, - ...) -{ - gint i; - gchar *v, **value; - va_list args; - gsize len; - GError *error = NULL; - - value = g_key_file_get_string_list (keyfile, group, key, &len, &error); - check_no_error (&error); - g_assert (value != NULL); - - va_start (args, key); - i = 0; - v = va_arg (args, gchar*); - while (v) - { - g_assert (value[i] != NULL); - g_assert_cmpstr (v, ==, value[i]); - i++; - v = va_arg (args, gchar*); - } - - va_end (args); - - g_strfreev (value); -} - -static void -check_locale_string_list_value (GKeyFile *keyfile, - const gchar *group, - const gchar *key, - const gchar *locale, - ...) -{ - gint i; - gchar *v, **value; - va_list args; - gsize len; - GError *error = NULL; - - value = g_key_file_get_locale_string_list (keyfile, group, key, locale, &len, &error); - check_no_error (&error); - g_assert (value != NULL); - - va_start (args, locale); - i = 0; - v = va_arg (args, gchar*); - while (v) - { - g_assert (value[i] != NULL); - g_assert_cmpstr (v, ==, value[i]); - i++; - v = va_arg (args, gchar*); - } - - va_end (args); - - g_strfreev (value); -} - -static void -check_integer_list_value (GKeyFile *keyfile, - const gchar *group, - const gchar *key, - ...) -{ - gint i; - gint v, *value; - va_list args; - gsize len; - GError *error = NULL; - - value = g_key_file_get_integer_list (keyfile, group, key, &len, &error); - check_no_error (&error); - g_assert (value != NULL); - - va_start (args, key); - i = 0; - v = va_arg (args, gint); - while (v != -100) - { - g_assert_cmpint (i, <, len); - g_assert_cmpint (value[i], ==, v); - i++; - v = va_arg (args, gint); - } - - va_end (args); - - g_free (value); -} - -static void -check_double_list_value (GKeyFile *keyfile, - const gchar *group, - const gchar *key, - ...) -{ - gint i; - gdouble v, *value; - va_list args; - gsize len; - GError *error = NULL; - - value = g_key_file_get_double_list (keyfile, group, key, &len, &error); - check_no_error (&error); - g_assert (value != NULL); - - va_start (args, key); - i = 0; - v = va_arg (args, gdouble); - while (v != -100) - { - g_assert_cmpint (i, <, len); - g_assert_cmpfloat (value[i], ==, v); - i++; - v = va_arg (args, gdouble); - } - - va_end (args); - - g_free (value); -} - -static void -check_boolean_list_value (GKeyFile *keyfile, - const gchar *group, - const gchar *key, - ...) -{ - gint i; - gboolean v, *value; - va_list args; - gsize len; - GError *error = NULL; - - value = g_key_file_get_boolean_list (keyfile, group, key, &len, &error); - check_no_error (&error); - g_assert (value != NULL); - - va_start (args, key); - i = 0; - v = va_arg (args, gboolean); - while (v != -100) - { - g_assert_cmpint (i, <, len); - g_assert_cmpint (value[i], ==, v); - i++; - v = va_arg (args, gboolean); - } - - va_end (args); - - g_free (value); -} - -static void -check_boolean_value (GKeyFile *keyfile, - const gchar *group, - const gchar *key, - gboolean expected) -{ - GError *error = NULL; - gboolean value; - - value = g_key_file_get_boolean (keyfile, group, key, &error); - check_no_error (&error); - g_assert_cmpint (value, ==, expected); -} - -static void -check_integer_value (GKeyFile *keyfile, - const gchar *group, - const gchar *key, - gint expected) -{ - GError *error = NULL; - gint value; - - value = g_key_file_get_integer (keyfile, group, key, &error); - check_no_error (&error); - g_assert_cmpint (value, ==, expected); -} - -static void -check_double_value (GKeyFile *keyfile, - const gchar *group, - const gchar *key, - gdouble expected) -{ - GError *error = NULL; - gdouble value; - - value = g_key_file_get_double (keyfile, group, key, &error); - check_no_error (&error); - g_assert_cmpfloat (value, ==, expected); -} - -static void -check_name (const gchar *what, - const gchar *value, - const gchar *expected, - gint position) -{ - g_assert_cmpstr (value, ==, expected); -} - -static void -check_length (const gchar *what, - gint n_items, - gint length, - gint expected) -{ - g_assert_cmpint (n_items, ==, length); - g_assert_cmpint (n_items, ==, expected); -} - - -/* check that both \n and \r\n are accepted as line ends, - * and that stray \r are passed through - */ -static void -test_line_ends (void) -{ - GKeyFile *keyfile; - - const gchar *data = - "[group1]\n" - "key1=value1\n" - "key2=value2\r\n" - "[group2]\r\n" - "key3=value3\r\r\n" - "key4=value4\n"; - - keyfile = load_data (data, 0); - - check_string_value (keyfile, "group1", "key1", "value1"); - check_string_value (keyfile, "group1", "key2", "value2"); - check_string_value (keyfile, "group2", "key3", "value3\r"); - check_string_value (keyfile, "group2", "key4", "value4"); - - g_key_file_free (keyfile); -} - -/* check handling of whitespace - */ -static void -test_whitespace (void) -{ - GKeyFile *keyfile; - - const gchar *data = - "[group1]\n" - "key1 = value1\n" - "key2\t=\tvalue2\n" - " [ group2 ] \n" - "key3 = value3 \n" - "key4 = value \t4\n" - " key5 = value5\n"; - - keyfile = load_data (data, 0); - - check_string_value (keyfile, "group1", "key1", "value1"); - check_string_value (keyfile, "group1", "key2", "value2"); - check_string_value (keyfile, " group2 ", "key3", "value3 "); - check_string_value (keyfile, " group2 ", "key4", "value \t4"); - check_string_value (keyfile, " group2 ", "key5", "value5"); - - g_key_file_free (keyfile); -} - -/* check handling of comments - */ -static void -test_comments (void) -{ - GKeyFile *keyfile; - gchar **names; - gsize len; - GError *error = NULL; - gchar *comment; - - const gchar *data = - "# top comment\n" - "# top comment, continued\n" - "[group1]\n" - "key1 = value1\n" - "# key comment\n" - "# key comment, continued\n" - "key2 = value2\n" - "# line end check\r\n" - "key3 = value3\n" - "key4 = value4\n" - "# group comment\n" - "# group comment, continued\n" - "[group2]\n"; - - const gchar *top_comment= " top comment\n top comment, continued\n"; - const gchar *group_comment= " group comment\n group comment, continued\n"; - const gchar *key_comment= " key comment\n key comment, continued\n"; - - keyfile = load_data (data, 0); - - check_string_value (keyfile, "group1", "key1", "value1"); - check_string_value (keyfile, "group1", "key2", "value2"); - check_string_value (keyfile, "group1", "key3", "value3"); - check_string_value (keyfile, "group1", "key4", "value4"); - - names = g_key_file_get_keys (keyfile, "group1", &len, &error); - check_no_error (&error); - - check_length ("keys", g_strv_length (names), len, 4); - check_name ("key", names[0], "key1", 0); - check_name ("key", names[1], "key2", 1); - check_name ("key", names[2], "key3", 2); - check_name ("key", names[3], "key4", 3); - - g_strfreev (names); - - g_key_file_free (keyfile); - - keyfile = load_data (data, G_KEY_FILE_KEEP_COMMENTS); - - names = g_key_file_get_keys (keyfile, "group1", &len, &error); - check_no_error (&error); - - check_length ("keys", g_strv_length (names), len, 4); - check_name ("key", names[0], "key1", 0); - check_name ("key", names[1], "key2", 1); - check_name ("key", names[2], "key3", 2); - check_name ("key", names[3], "key4", 3); - - g_strfreev (names); - - comment = g_key_file_get_comment (keyfile, NULL, NULL, &error); - check_no_error (&error); - check_name ("top comment", comment, top_comment, 0); - g_free (comment); - - comment = g_key_file_get_comment (keyfile, "group1", "key2", &error); - check_no_error (&error); - check_name ("key comment", comment, key_comment, 0); - g_free (comment); - - comment = g_key_file_get_comment (keyfile, "group2", NULL, &error); - check_no_error (&error); - check_name ("group comment", comment, group_comment, 0); - g_free (comment); - - comment = g_key_file_get_comment (keyfile, "group3", NULL, &error); - check_error (&error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_GROUP_NOT_FOUND); - g_assert (comment == NULL); - - g_key_file_free (keyfile); -} - - -/* check key and group listing */ -static void -test_listing (void) -{ - GKeyFile *keyfile; - gchar **names; - gsize len; - gchar *start; - GError *error = NULL; - - const gchar *data = - "[group1]\n" - "key1=value1\n" - "key2=value2\n" - "[group2]\n" - "key3=value3\n" - "key4=value4\n"; - - keyfile = load_data (data, 0); - - names = g_key_file_get_groups (keyfile, &len); - g_assert (names != NULL); - - check_length ("groups", g_strv_length (names), len, 2); - check_name ("group name", names[0], "group1", 0); - check_name ("group name", names[1], "group2", 1); - - g_strfreev (names); - - names = g_key_file_get_keys (keyfile, "group1", &len, &error); - check_no_error (&error); - - check_length ("keys", g_strv_length (names), len, 2); - check_name ("key", names[0], "key1", 0); - check_name ("key", names[1], "key2", 1); - - g_strfreev (names); - - names = g_key_file_get_keys (keyfile, "no-such-group", &len, &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND); - - g_strfreev (names); - - g_assert (g_key_file_has_group (keyfile, "group1")); - g_assert (g_key_file_has_group (keyfile, "group2")); - g_assert (!g_key_file_has_group (keyfile, "group10")); - g_assert (!g_key_file_has_group (keyfile, "group20")); - - start = g_key_file_get_start_group (keyfile); - g_assert_cmpstr (start, ==, "group1"); - g_free (start); - - g_assert (g_key_file_has_key (keyfile, "group1", "key1", &error)); - check_no_error (&error); - g_assert (g_key_file_has_key (keyfile, "group2", "key3", &error)); - check_no_error (&error); - g_assert (!g_key_file_has_key (keyfile, "group2", "no-such-key", NULL)); - - g_key_file_has_key (keyfile, "no-such-group", "key", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND); - - g_key_file_free (keyfile); -} - -/* check parsing of string values */ -static void -test_string (void) -{ - GKeyFile *keyfile; - GError *error = NULL; - gchar *value; - - const gchar *data = - "[valid]\n" - "key1=\\s\\n\\t\\r\\\\\n" - "key2=\"quoted\"\n" - "key3='quoted'\n" - "key4=\xe2\x89\xa0\xe2\x89\xa0\n" - "[invalid]\n" - "key1=\\a\\b\\0800xff\n" - "key2=blabla\\\n"; - - keyfile = load_data (data, 0); - - check_string_value (keyfile, "valid", "key1", " \n\t\r\\"); - check_string_value (keyfile, "valid", "key2", "\"quoted\""); - check_string_value (keyfile, "valid", "key3", "'quoted'"); - check_string_value (keyfile, "valid", "key4", "\xe2\x89\xa0\xe2\x89\xa0"); - - value = g_key_file_get_string (keyfile, "invalid", "key1", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); - g_free (value); - - value = g_key_file_get_string (keyfile, "invalid", "key2", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); - g_free (value); - - g_key_file_free (keyfile); -} - -/* check parsing of boolean values */ -static void -test_boolean (void) -{ - GKeyFile *keyfile; - GError *error = NULL; - - const gchar *data = - "[valid]\n" - "key1=true\n" - "key2=false\n" - "key3=1\n" - "key4=0\n" - "[invalid]\n" - "key1=t\n" - "key2=f\n" - "key3=yes\n" - "key4=no\n"; - - keyfile = load_data (data, 0); - - check_boolean_value (keyfile, "valid", "key1", TRUE); - check_boolean_value (keyfile, "valid", "key2", FALSE); - check_boolean_value (keyfile, "valid", "key3", TRUE); - check_boolean_value (keyfile, "valid", "key4", FALSE); - - g_key_file_get_boolean (keyfile, "invalid", "key1", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); - - g_key_file_get_boolean (keyfile, "invalid", "key2", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); - - g_key_file_get_boolean (keyfile, "invalid", "key3", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); - - g_key_file_get_boolean (keyfile, "invalid", "key4", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); - - g_key_file_free (keyfile); -} - -/* check parsing of integer and double values */ -static void -test_number (void) -{ - GKeyFile *keyfile; - GError *error = NULL; - - const gchar *data = - "[valid]\n" - "key1=0\n" - "key2=1\n" - "key3=-1\n" - "key4=2324431\n" - "key5=-2324431\n" - "key6=000111\n" - "dkey1=000111\n" - "dkey2=145.45\n" - "dkey3=-3453.7\n" - "[invalid]\n" - "key1=0xffff\n" - "key2=0.5\n" - "key3=1e37\n" - "key4=ten\n" - "key5=\n" - "key6=1.0.0\n" - "key7=2x2\n" - "key8=abc\n"; - - keyfile = load_data (data, 0); - - check_integer_value (keyfile, "valid", "key1", 0); - check_integer_value (keyfile, "valid", "key2", 1); - check_integer_value (keyfile, "valid", "key3", -1); - check_integer_value (keyfile, "valid", "key4", 2324431); - check_integer_value (keyfile, "valid", "key5", -2324431); - check_integer_value (keyfile, "valid", "key6", 111); - check_double_value (keyfile, "valid", "dkey1", 111.0); - check_double_value (keyfile, "valid", "dkey2", 145.45); - check_double_value (keyfile, "valid", "dkey3", -3453.7); - - g_key_file_get_integer (keyfile, "invalid", "key1", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); - - g_key_file_get_integer (keyfile, "invalid", "key2", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); - - g_key_file_get_integer (keyfile, "invalid", "key3", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); - - g_key_file_get_integer (keyfile, "invalid", "key4", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); - - g_key_file_get_double (keyfile, "invalid", "key5", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); - - g_key_file_get_double (keyfile, "invalid", "key6", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); - - g_key_file_get_double (keyfile, "invalid", "key7", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); - - g_key_file_get_double (keyfile, "invalid", "key8", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); - - g_key_file_free (keyfile); -} - -/* check handling of translated strings */ -static void -test_locale_string (void) -{ - GKeyFile *keyfile; - - const gchar *data = - "[valid]\n" - "key1=v1\n" - "key1[de]=v1-de\n" - "key1[de_DE]=v1-de_DE\n" - "key1[de_DE.UTF8]=v1-de_DE.UTF8\n" - "key1[fr]=v1-fr\n" - "key1[en] =v1-en\n" - "key1[sr@Latn]=v1-sr\n"; - - keyfile = load_data (data, G_KEY_FILE_KEEP_TRANSLATIONS); - - check_locale_string_value (keyfile, "valid", "key1", "it", "v1"); - check_locale_string_value (keyfile, "valid", "key1", "de", "v1-de"); - check_locale_string_value (keyfile, "valid", "key1", "de_DE", "v1-de_DE"); - check_locale_string_value (keyfile, "valid", "key1", "de_DE.UTF8", "v1-de_DE.UTF8"); - check_locale_string_value (keyfile, "valid", "key1", "fr", "v1-fr"); - check_locale_string_value (keyfile, "valid", "key1", "fr_FR", "v1-fr"); - check_locale_string_value (keyfile, "valid", "key1", "en", "v1-en"); - check_locale_string_value (keyfile, "valid", "key1", "sr@Latn", "v1-sr"); - - g_key_file_free (keyfile); - - /* now test that translations are thrown away */ - - g_setenv ("LANGUAGE", "de", TRUE); - setlocale (LC_ALL, ""); - - keyfile = load_data (data, 0); - - check_locale_string_value (keyfile, "valid", "key1", "it", "v1"); - check_locale_string_value (keyfile, "valid", "key1", "de", "v1-de"); - check_locale_string_value (keyfile, "valid", "key1", "de_DE", "v1-de"); - check_locale_string_value (keyfile, "valid", "key1", "de_DE.UTF8", "v1-de"); - check_locale_string_value (keyfile, "valid", "key1", "fr", "v1"); - check_locale_string_value (keyfile, "valid", "key1", "fr_FR", "v1"); - check_locale_string_value (keyfile, "valid", "key1", "en", "v1"); - - g_key_file_free (keyfile); -} - -static void -test_lists (void) -{ - GKeyFile *keyfile; - - const gchar *data = - "[valid]\n" - "key1=v1;v2\n" - "key2=v1;v2;\n" - "key3=v1,v2\n" - "key4=v1\\;v2\n" - "key5=true;false\n" - "key6=1;0;-1\n" - "key7= 1 ; 0 ; -1 \n" - "key8=v1\\,v2\n" - "key9=0;1.3456;-76532.456\n"; - - keyfile = load_data (data, 0); - - check_string_list_value (keyfile, "valid", "key1", "v1", "v2", NULL); - check_string_list_value (keyfile, "valid", "key2", "v1", "v2", NULL); - check_string_list_value (keyfile, "valid", "key3", "v1,v2", NULL); - check_string_list_value (keyfile, "valid", "key4", "v1;v2", NULL); - check_boolean_list_value (keyfile, "valid", "key5", TRUE, FALSE, -100); - check_integer_list_value (keyfile, "valid", "key6", 1, 0, -1, -100); - check_double_list_value (keyfile, "valid", "key9", 0.0, 1.3456, -76532.456, -100.0); - /* maybe these should be valid */ - /* check_integer_list_value (keyfile, "valid", "key7", 1, 0, -1, -100);*/ - /* check_string_list_value (keyfile, "valid", "key8", "v1\\,v2", NULL);*/ - - g_key_file_free (keyfile); - - /* Now check an alternate separator */ - - keyfile = load_data (data, 0); - g_key_file_set_list_separator (keyfile, ','); - - check_string_list_value (keyfile, "valid", "key1", "v1;v2", NULL); - check_string_list_value (keyfile, "valid", "key2", "v1;v2;", NULL); - check_string_list_value (keyfile, "valid", "key3", "v1", "v2", NULL); - - g_key_file_free (keyfile); -} - -static void -test_lists_set_get (void) -{ - GKeyFile *keyfile; - static const char * const strings[] = { "v1", "v2" }; - static const char * const locale_strings[] = { "v1-l", "v2-l" }; - static int integers[] = { 1, -1, 2 }; - static gdouble doubles[] = { 3.14, 2.71 }; - - keyfile = g_key_file_new (); - g_key_file_set_string_list (keyfile, "group0", "key1", strings, G_N_ELEMENTS (strings)); - g_key_file_set_locale_string_list (keyfile, "group0", "key1", "de", locale_strings, G_N_ELEMENTS (locale_strings)); - g_key_file_set_integer_list (keyfile, "group0", "key2", integers, G_N_ELEMENTS (integers)); - g_key_file_set_double_list (keyfile, "group0", "key3", doubles, G_N_ELEMENTS (doubles)); - - check_string_list_value (keyfile, "group0", "key1", strings[0], strings[1], NULL); - check_locale_string_list_value (keyfile, "group0", "key1", "de", locale_strings[0], locale_strings[1], NULL); - check_integer_list_value (keyfile, "group0", "key2", integers[0], integers[1], -100); - check_double_list_value (keyfile, "group0", "key3", doubles[0], doubles[1], -100.0); - g_key_file_free (keyfile); - - /* and again with a different list separator */ - keyfile = g_key_file_new (); - g_key_file_set_list_separator (keyfile, ','); - g_key_file_set_string_list (keyfile, "group0", "key1", strings, G_N_ELEMENTS (strings)); - g_key_file_set_locale_string_list (keyfile, "group0", "key1", "de", locale_strings, G_N_ELEMENTS (locale_strings)); - g_key_file_set_integer_list (keyfile, "group0", "key2", integers, G_N_ELEMENTS (integers)); - g_key_file_set_double_list (keyfile, "group0", "key3", doubles, G_N_ELEMENTS (doubles)); - - check_string_list_value (keyfile, "group0", "key1", strings[0], strings[1], NULL); - check_locale_string_list_value (keyfile, "group0", "key1", "de", locale_strings[0], locale_strings[1], NULL); - check_integer_list_value (keyfile, "group0", "key2", integers[0], integers[1], -100); - check_double_list_value (keyfile, "group0", "key3", doubles[0], doubles[1], -100.0); - g_key_file_free (keyfile); -} - -static void -test_group_remove (void) -{ - GKeyFile *keyfile; - gchar **names; - gsize len; - GError *error = NULL; - - const gchar *data = - "[group1]\n" - "[group2]\n" - "key1=bla\n" - "key2=bla\n" - "[group3]\n" - "key1=bla\n" - "key2=bla\n"; - - g_test_bug ("165887"); - - keyfile = load_data (data, 0); - - names = g_key_file_get_groups (keyfile, &len); - g_assert (names != NULL); - - check_length ("groups", g_strv_length (names), len, 3); - check_name ("group name", names[0], "group1", 0); - check_name ("group name", names[1], "group2", 1); - check_name ("group name", names[2], "group3", 2); - - g_key_file_remove_group (keyfile, "group1", &error); - check_no_error (&error); - - g_strfreev (names); - - names = g_key_file_get_groups (keyfile, &len); - g_assert (names != NULL); - - check_length ("groups", g_strv_length (names), len, 2); - check_name ("group name", names[0], "group2", 0); - check_name ("group name", names[1], "group3", 1); - - g_key_file_remove_group (keyfile, "group2", &error); - check_no_error (&error); - - g_strfreev (names); - - names = g_key_file_get_groups (keyfile, &len); - g_assert (names != NULL); - - check_length ("groups", g_strv_length (names), len, 1); - check_name ("group name", names[0], "group3", 0); - - g_key_file_remove_group (keyfile, "no such group", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND); - - g_strfreev (names); - - g_key_file_free (keyfile); -} - -static void -test_key_remove (void) -{ - GKeyFile *keyfile; - gchar *value; - GError *error = NULL; - - const gchar *data = - "[group1]\n" - "key1=bla\n" - "key2=bla\n"; - - g_test_bug ("165980"); - - keyfile = load_data (data, 0); - - check_string_value (keyfile, "group1", "key1", "bla"); - - g_key_file_remove_key (keyfile, "group1", "key1", &error); - check_no_error (&error); - - value = g_key_file_get_string (keyfile, "group1", "key1", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND); - g_free (value); - - g_key_file_remove_key (keyfile, "group1", "key1", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND); - - g_key_file_remove_key (keyfile, "no such group", "key1", &error); - check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND); - - g_key_file_free (keyfile); -} - - -static void -test_groups (void) -{ - GKeyFile *keyfile; - - const gchar *data = - "[1]\n" - "key1=123\n" - "[2]\n" - "key2=123\n"; - - g_test_bug ("316309"); - - keyfile = load_data (data, 0); - - check_string_value (keyfile, "1", "key1", "123"); - check_string_value (keyfile, "2", "key2", "123"); - - g_key_file_free (keyfile); -} - -static void -test_group_names (void) -{ - GKeyFile *keyfile; - GError *error = NULL; - const gchar *data; - gchar *value; - - /* [ in group name */ - data = "[a[b]\n" - "key1=123\n"; - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, data, -1, 0, &error); - g_key_file_free (keyfile); - check_error (&error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_PARSE); - - /* ] in group name */ - data = "[a]b]\n" - "key1=123\n"; - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, data, -1, 0, &error); - g_key_file_free (keyfile); - check_error (&error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_PARSE); - - /* control char in group name */ - data = "[a\tb]\n" - "key1=123\n"; - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, data, -1, 0, &error); - g_key_file_free (keyfile); - check_error (&error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_PARSE); - - /* empty group name */ - data = "[]\n" - "key1=123\n"; - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, data, -1, 0, &error); - g_key_file_free (keyfile); - check_error (&error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_PARSE); - - /* Unicode in group name */ - data = "[\xc2\xbd]\n" - "key1=123\n"; - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, data, -1, 0, &error); - g_key_file_free (keyfile); - check_no_error (&error); - - keyfile = g_key_file_new (); - /*g_key_file_set_string (keyfile, "a[b", "key1", "123");*/ - value = g_key_file_get_string (keyfile, "a[b", "key1", &error); - check_error (&error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_GROUP_NOT_FOUND); - g_key_file_free (keyfile); - - keyfile = g_key_file_new (); - /*g_key_file_set_string (keyfile, "a]b", "key1", "123");*/ - value = g_key_file_get_string (keyfile, "a]b", "key1", &error); - check_error (&error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_GROUP_NOT_FOUND); - g_key_file_free (keyfile); - - keyfile = g_key_file_new (); - /*g_key_file_set_string (keyfile, "a\tb", "key1", "123");*/ - value = g_key_file_get_string (keyfile, "a\tb", "key1", &error); - check_error (&error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_GROUP_NOT_FOUND); - g_key_file_free (keyfile); - - keyfile = g_key_file_new (); - g_key_file_set_string (keyfile, "\xc2\xbd", "key1", "123"); - check_string_value (keyfile, "\xc2\xbd", "key1", "123"); - g_key_file_free (keyfile); -} - -static void -test_key_names (void) -{ - GKeyFile *keyfile; - GError *error = NULL; - const gchar *data; - gchar *value; - - /* [ in key name */ - data = "[a]\n" - "key[=123\n"; - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, data, -1, 0, &error); - g_key_file_free (keyfile); - check_error (&error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_PARSE); - - /* empty key name */ - data = "[a]\n" - " =123\n"; - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, data, -1, 0, &error); - g_key_file_free (keyfile); - check_error (&error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_PARSE); - - /* empty key name */ - data = "[a]\n" - " [de] =123\n"; - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, data, -1, 0, &error); - g_key_file_free (keyfile); - check_error (&error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_PARSE); - - /* bad locale suffix */ - data = "[a]\n" - "foo[@#!&%]=123\n"; - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, data, -1, 0, &error); - g_key_file_free (keyfile); - check_error (&error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_PARSE); - - /* initial space */ - data = "[a]\n" - " foo=123\n"; - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, data, -1, 0, &error); - check_no_error (&error); - check_string_value (keyfile, "a", "foo", "123"); - g_key_file_free (keyfile); - - /* final space */ - data = "[a]\n" - "foo =123\n"; - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, data, -1, 0, &error); - check_no_error (&error); - check_string_value (keyfile, "a", "foo", "123"); - g_key_file_free (keyfile); - - /* inner space */ - data = "[a]\n" - "foo bar=123\n"; - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, data, -1, 0, &error); - check_no_error (&error); - check_string_value (keyfile, "a", "foo bar", "123"); - g_key_file_free (keyfile); - - /* inner space */ - data = "[a]\n" - "foo [de] =123\n"; - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, data, -1, 0, &error); - check_error (&error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_PARSE); - g_key_file_free (keyfile); - - /* control char in key name */ - data = "[a]\n" - "key\tfoo=123\n"; - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, data, -1, 0, &error); - g_key_file_free (keyfile); - check_no_error (&error); - - /* Unicode in key name */ - data = "[a]\n" - "\xc2\xbd=123\n"; - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, data, -1, 0, &error); - g_key_file_free (keyfile); - check_no_error (&error); - - keyfile = g_key_file_new (); - g_key_file_set_string (keyfile, "a", "x", "123"); - /*g_key_file_set_string (keyfile, "a", "key=", "123");*/ - value = g_key_file_get_string (keyfile, "a", "key=", &error); - check_error (&error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_KEY_NOT_FOUND); - g_key_file_free (keyfile); - - keyfile = g_key_file_new (); - g_key_file_set_string (keyfile, "a", "x", "123"); - /*g_key_file_set_string (keyfile, "a", "key[", "123");*/ - value = g_key_file_get_string (keyfile, "a", "key[", &error); - check_error (&error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_KEY_NOT_FOUND); - g_key_file_free (keyfile); - - keyfile = g_key_file_new (); - g_key_file_set_string (keyfile, "a", "x", "123"); - g_key_file_set_string (keyfile, "a", "key\tfoo", "123"); - value = g_key_file_get_string (keyfile, "a", "key\tfoo", &error); - check_no_error (&error); - g_key_file_free (keyfile); - - keyfile = g_key_file_new (); - g_key_file_set_string (keyfile, "a", "x", "123"); - /*g_key_file_set_string (keyfile, "a", " key", "123");*/ - value = g_key_file_get_string (keyfile, "a", " key", &error); - check_error (&error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_KEY_NOT_FOUND); - g_key_file_free (keyfile); - - keyfile = g_key_file_new (); - g_key_file_set_string (keyfile, "a", "x", "123"); - - /* Unicode key */ - g_key_file_set_string (keyfile, "a", "\xc2\xbd", "123"); - check_string_value (keyfile, "a", "\xc2\xbd", "123"); - - /* Keys with / + . (as used by the gnome-vfs mime cache) */ - g_key_file_set_string (keyfile, "a", "foo/bar", "/"); - check_string_value (keyfile, "a", "foo/bar", "/"); - g_key_file_set_string (keyfile, "a", "foo+bar", "+"); - check_string_value (keyfile, "a", "foo+bar", "+"); - g_key_file_set_string (keyfile, "a", "foo.bar", "."); - check_string_value (keyfile, "a", "foo.bar", "."); - - g_key_file_free (keyfile); -} - -static void -test_duplicate_keys (void) -{ - GKeyFile *keyfile; - const gchar *data = - "[1]\n" - "key1=123\n" - "key1=345\n"; - - keyfile = load_data (data, 0); - check_string_value (keyfile, "1", "key1", "345"); - - g_key_file_free (keyfile); -} - -static void -test_duplicate_groups (void) -{ - GKeyFile *keyfile; - const gchar *data = - "[Desktop Entry]\n" - "key1=123\n" - "[Desktop Entry]\n" - "key2=123\n"; - - g_test_bug ("157877"); - - keyfile = load_data (data, 0); - check_string_value (keyfile, "Desktop Entry", "key1", "123"); - check_string_value (keyfile, "Desktop Entry", "key2", "123"); - - g_key_file_free (keyfile); -} - -static void -test_duplicate_groups2 (void) -{ - GKeyFile *keyfile; - const gchar *data = - "[A]\n" - "foo=bar\n" - "[B]\n" - "foo=baz\n" - "[A]\n" - "foo=bang\n"; - - g_test_bug ("385910"); - - keyfile = load_data (data, 0); - check_string_value (keyfile, "A", "foo", "bang"); - check_string_value (keyfile, "B", "foo", "baz"); - - g_key_file_free (keyfile); -} - -static void -test_reload_idempotency (void) -{ - static const gchar *original_data="" - "# Top comment\n" - "\n" - "# First comment\n" - "[first]\n" - "key=value\n" - "# A random comment in the first group\n" - "anotherkey=anothervalue\n" - "# Second comment - one line\n" - "[second]\n" - "# Third comment - two lines\n" - "# Third comment - two lines\n" - "[third]\n" - "blank_line=1\n" - "\n" - "blank_lines=2\n" - "\n\n" - "[fourth]\n" - "[fifth]\n"; - GKeyFile *keyfile; - GError *error = NULL; - gchar *data1, *data2; - gsize len1, len2; - - g_test_bug ("420686"); - - /* check that we only insert a single new line between groups */ - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, - original_data, strlen(original_data), - G_KEY_FILE_KEEP_COMMENTS, - &error); - check_no_error (&error); - - data1 = g_key_file_to_data (keyfile, &len1, &error); - g_assert (data1 != NULL); - g_key_file_free (keyfile); - - keyfile = g_key_file_new (); - g_key_file_load_from_data (keyfile, - data1, len1, - G_KEY_FILE_KEEP_COMMENTS, - &error); - check_no_error (&error); - - data2 = g_key_file_to_data (keyfile, &len2, &error); - g_assert (data2 != NULL); - g_key_file_free (keyfile); - - g_assert_cmpstr (data1, ==, data2); - - g_free (data2); - g_free (data1); -} - -int -main (int argc, char *argv[]) -{ - g_test_init (&argc, &argv, NULL); - g_test_bug_base ("http://bugzilla.gnome.org/"); - - g_test_add_func ("/keyfile/line-ends", test_line_ends); - g_test_add_func ("/keyfile/whitespace", test_whitespace); - g_test_add_func ("/keyfile/comments", test_comments); - g_test_add_func ("/keyfile/listing", test_listing); - g_test_add_func ("/keyfile/string", test_string); - g_test_add_func ("/keyfile/boolean", test_boolean); - g_test_add_func ("/keyfile/number", test_number); - g_test_add_func ("/keyfile/locale-string", test_locale_string); - g_test_add_func ("/keyfile/lists", test_lists); - g_test_add_func ("/keyfile/lists-set-get", test_lists_set_get); - g_test_add_func ("/keyfile/group-remove", test_group_remove); - g_test_add_func ("/keyfile/key-remove", test_key_remove); - g_test_add_func ("/keyfile/groups", test_groups); - g_test_add_func ("/keyfile/duplicate-keys", test_duplicate_keys); - g_test_add_func ("/keyfile/duplicate-groups", test_duplicate_groups); - g_test_add_func ("/keyfile/duplicate-groups2", test_duplicate_groups2); - g_test_add_func ("/keyfile/group-names", test_group_names); - g_test_add_func ("/keyfile/key-names", test_key_names); - g_test_add_func ("/keyfile/reload", test_reload_idempotency); - - return g_test_run (); -} diff --git a/glib/tests/markup-subparser.c b/glib/tests/markup-subparser.c deleted file mode 100644 index 0b3c746d2..000000000 --- a/glib/tests/markup-subparser.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright © 2008 Ryan Lortie - * - * This program 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 of the - * License, or (at your option) any later version. - * - * See the included COPYING file for more information. - */ - -#include <string.h> -#include <stdio.h> -#include <glib.h> - -/* keep track of GString instances to make sure nothing leaks */ -static int strings_allocated; - -/* === the GMarkupParser functions === */ -static void -subparser_start_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - gpointer user_data, - GError **error) -{ - g_string_append_printf (user_data, "{%s}", element_name); - - /* we don't like trouble... */ - if (strcmp (element_name, "trouble") == 0) - g_set_error (error, 0, 0, "we don't like trouble"); -} - -static void -subparser_end_element (GMarkupParseContext *context, - const gchar *element_name, - gpointer user_data, - GError **error) -{ - g_string_append_printf (user_data, "{/%s}", element_name); -} - -static void -subparser_error (GMarkupParseContext *context, - GError *error, - gpointer user_data) -{ - g_string_free (user_data, TRUE); - strings_allocated--; -} - -static GMarkupParser subparser_parser = -{ - subparser_start_element, - subparser_end_element, - NULL, - NULL, - subparser_error -}; - -/* convenience functions for a parser that does not - * replay the starting tag into the subparser... - */ -static void -subparser_start (GMarkupParseContext *ctx) -{ - gpointer user_data; - - user_data = g_string_new (NULL); - strings_allocated++; - g_markup_parse_context_push (ctx, &subparser_parser, user_data); -} - -static char * -subparser_end (GMarkupParseContext *ctx, - GError **error) -{ - GString *string; - char *result; - - string = g_markup_parse_context_pop (ctx); - result = string->str; - - g_string_free (string, FALSE); - strings_allocated--; - - if (result == NULL || result[0] == '\0') - { - g_free (result); - g_set_error (error, 0, 0, "got no data"); - - return NULL; - } - - return result; -} - -/* convenience functions for a parser that -does- - * replay the starting tag into the subparser... - */ -static gboolean -replay_parser_start (GMarkupParseContext *ctx, - const char *element_name, - const char **attribute_names, - const char **attribute_values, - GError **error) -{ - GError *tmp_error = NULL; - gpointer user_data; - - user_data = g_string_new (NULL); - strings_allocated++; - - subparser_parser.start_element (ctx, element_name, - attribute_names, attribute_values, - user_data, &tmp_error); - - if (tmp_error) - { - g_propagate_error (error, tmp_error); - g_string_free (user_data, TRUE); - strings_allocated--; - - return FALSE; - } - - g_markup_parse_context_push (ctx, &subparser_parser, user_data); - - return TRUE; -} - -static char * -replay_parser_end (GMarkupParseContext *ctx, - GError **error) -{ - GError *tmp_error = NULL; - GString *string; - char *result; - - string = g_markup_parse_context_pop (ctx); - - subparser_parser.end_element (ctx, g_markup_parse_context_get_element (ctx), - string, &tmp_error); - - if (tmp_error) - { - g_propagate_error (error, tmp_error); - g_string_free (string, TRUE); - strings_allocated--; - - return FALSE; - } - - result = string->str; - - g_string_free (string, FALSE); - strings_allocated--; - - if (result == NULL || result[0] == '\0') - { - g_free (result); - g_set_error (error, 0, 0, "got no data"); - - return NULL; - } - - return result; -} - - -/* === start interface between subparser and calling parser === */ -static void subparser_start (GMarkupParseContext *ctx); -static char *subparser_end (GMarkupParseContext *ctx, - GError **error); -/* === end interface between subparser and calling parser === */ - -/* === start interface between replay parser and calling parser === */ -static gboolean replay_parser_start (GMarkupParseContext *ctx, - const char *element_name, - const char **attribute_names, - const char **attribute_values, - GError **error); -static char *replay_parser_end (GMarkupParseContext *ctx, - GError **error); -/* === end interface between replay parser and calling parser === */ - - - -/* now comes our parser for the test. - * - * we recognise the tags <test> and <sub>. - * <test> is ignored. - * <sub> invokes the subparser (no replay). - * - * "unknown tags" are passed to the reply subparser - * (so the unknown tag is fed to the subparser...) - */ -static void -start_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - gpointer user_data, - GError **error) -{ - g_string_append_printf (user_data, "<%s>", element_name); - - if (strcmp (element_name, "test") == 0) - { - /* do nothing */ - } - else if (strcmp (element_name, "sub") == 0) - { - /* invoke subparser */ - subparser_start (context); - } - else - { - /* unknown tag. invoke replay subparser */ - if (!replay_parser_start (context, element_name, - attribute_names, attribute_values, - error)) - return; - } -} - -static void -end_element (GMarkupParseContext *context, - const gchar *element_name, - gpointer user_data, - GError **error) -{ - if (strcmp (element_name, "test") == 0) - { - /* do nothing */ - } - else if (strcmp (element_name, "sub") == 0) - { - char *result; - - if ((result = subparser_end (context, error)) == NULL) - return; - - g_string_append_printf (user_data, "<<%s>>", result); - g_free (result); - } - else - { - char *result; - - if ((result = replay_parser_end (context, error)) == NULL) - return; - - g_string_append_printf (user_data, "[[%s]]", result); - g_free (result); - } - - g_string_append_printf (user_data, "</%s>", element_name); -} - -static GMarkupParser parser = -{ - start_element, - end_element -}; - -typedef struct -{ - const char *markup; - const char *result; - const char *error_message; -} TestCase; - -void -test (gconstpointer user_data) -{ - const TestCase *tc = user_data; - GMarkupParseContext *ctx; - GString *string; - gboolean result; - GError *error; - - error = NULL; - string = g_string_new (NULL); - ctx = g_markup_parse_context_new (&parser, 0, string, NULL); - result = g_markup_parse_context_parse (ctx, tc->markup, - strlen (tc->markup), &error); - if (result) - result = g_markup_parse_context_end_parse (ctx, &error); - g_markup_parse_context_free (ctx); - g_assert (strings_allocated == 0); - - if (result) - { - if (tc->error_message) - g_error ("expected failure (about '%s') passed!\n" - " in: %s\n out: %s", - tc->error_message, tc->markup, string->str); - } - else - { - if (!tc->error_message) - g_error ("unexpected failure: '%s'\n" - " in: %s\n out: %s", - error->message, tc->markup, string->str); - - if (!strstr (error->message, tc->error_message)) - g_error ("failed for the wrong reason.\n" - " expecting message about '%s'\n" - " got message '%s'\n" - " in: %s\n out: %s", - tc->error_message, error->message, tc->markup, string->str); - } - - if (strcmp (string->str, tc->result) != 0) - g_error ("got the wrong result.\n" - " expected: '%s'\n" - " got: '%s'\n" - " input: %s", - tc->result, string->str, tc->markup); - - if (error) - g_error_free (error); - - g_string_free (string, TRUE); -} - -TestCase test_cases[] = /* successful runs */ -{ - /* in */ /* out */ - { "<test/>", "<test></test>" }, - { "<sub><foo/></sub>", "<sub><<{foo}{/foo}>></sub>" }, - { "<sub><foo/><bar/></sub>", "<sub><<{foo}{/foo}{bar}{/bar}>></sub>" }, - { "<foo><bar/></foo>", "<foo>[[{foo}{bar}{/bar}{/foo}]]</foo>" }, - { "<foo><x/><y/></foo>", "<foo>[[{foo}{x}{/x}{y}{/y}{/foo}]]</foo>" }, - { "<foo/>", "<foo>[[{foo}{/foo}]]</foo>" }, - { "<sub><foo/></sub><bar/>", "<sub><<{foo}{/foo}>></sub>" - "<bar>[[{bar}{/bar}]]</bar>" } -}; - -TestCase error_cases[] = /* error cases */ -{ - /* in */ /* out */ /* error */ - { "<foo><>", "<foo>", ">"}, - { "", "", "empty" }, - { "<trouble/>", "<trouble>", "trouble" }, - { "<sub><trouble>", "<sub>", "trouble" }, - { "<foo><trouble>", "<foo>", "trouble" }, - { "<sub></sub>", "<sub>", "no data" }, - { "<sub/>", "<sub>", "no data" } -}; - -#define add_tests(func, basename, array) \ - G_STMT_START { \ - int __add_tests_i; \ - \ - for (__add_tests_i = 0; \ - __add_tests_i < G_N_ELEMENTS (array); \ - __add_tests_i++) \ - { \ - char *testname; \ - \ - testname = g_strdup_printf ("%s/%d", basename, __add_tests_i); \ - g_test_add_data_func (testname, &array[__add_tests_i], func); \ - g_free (testname); \ - } \ - } G_STMT_END - -int -main (int argc, char **argv) -{ - g_test_init (&argc, &argv, NULL); - add_tests (test, "/glib/markup/subparser/success", test_cases); - add_tests (test, "/glib/markup/subparser/failure", error_cases); - return g_test_run (); -} diff --git a/glib/tests/option-context.c b/glib/tests/option-context.c deleted file mode 100644 index 913ad5c84..000000000 --- a/glib/tests/option-context.c +++ /dev/null @@ -1,1794 +0,0 @@ -/* Unit tests for GOptionContext - * Copyright (C) 2007 Openismus GmbH - * Authors: Mathias Hasselmann - * - * This work is provided "as is"; redistribution and modification - * in whole or in part, in any medium, physical or electronic is - * permitted without restriction. - * - * This work 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. - */ - -#include <glib.h> - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <locale.h> - -static void -group_captions (void) -{ - gchar *help_variants[] = { "--help", "--help-all", "--help-test" }; - - GOptionEntry main_entries[] = { - { "main-switch", 0, - G_OPTION_FLAG_NO_ARG, - G_OPTION_ARG_NONE, NULL, - "A switch that is in the main group", NULL }, - { NULL } - }; - - GOptionEntry group_entries[] = { - { "test-switch", 0, - G_OPTION_FLAG_NO_ARG, - G_OPTION_ARG_NONE, NULL, - "A switch that is in the test group", NULL }, - { NULL } - }; - - gint i, j; - - g_test_bug ("504142"); - - for (i = 0; i < 4; ++i) - { - gboolean have_main_entries = (0 != (i & 1)); - gboolean have_test_entries = (0 != (i & 2)); - - GOptionContext *options; - GOptionGroup *group = NULL; - - options = g_option_context_new (NULL); - - if (have_main_entries) - g_option_context_add_main_entries (options, main_entries, NULL); - if (have_test_entries) - { - group = g_option_group_new ("test", "Test Options", - "Show all test options", - NULL, NULL); - g_option_context_add_group (options, group); - g_option_group_add_entries (group, group_entries); - } - - for (j = 0; j < G_N_ELEMENTS (help_variants); ++j) - { - GTestTrapFlags trap_flags = 0; - gchar *args[3]; - - args[0] = __FILE__; - args[1] = help_variants[j]; - args[2] = NULL; - - if (!g_test_verbose ()) - trap_flags |= G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR; - - g_test_message ("test setup: args='%s', main-entries=%d, test-entries=%d", - args[1], have_main_entries, have_test_entries); - - if (g_test_trap_fork (0, trap_flags)) - { - gchar **argv = args; - gint argc = 2; - GError *error = NULL; - - g_setenv ("LANG", "C", TRUE); - - g_option_context_parse (options, &argc, &argv, &error); - exit(0); - } - else - { - gboolean expect_main_description = FALSE; - gboolean expect_main_switch = FALSE; - - gboolean expect_test_description = FALSE; - gboolean expect_test_switch = FALSE; - gboolean expect_test_group = FALSE; - - g_test_trap_assert_passed (); - g_test_trap_assert_stderr (""); - - switch (j) - { - case 0: - g_assert_cmpstr ("--help", ==, args[1]); - expect_main_switch = have_main_entries; - expect_test_group = have_test_entries; - break; - - case 1: - g_assert_cmpstr ("--help-all", ==, args[1]); - expect_main_switch = have_main_entries; - expect_test_switch = have_test_entries; - expect_test_group = have_test_entries; - break; - - case 2: - g_assert_cmpstr ("--help-test", ==, args[1]); - expect_test_switch = have_test_entries; - break; - - default: - g_assert_not_reached (); - break; - } - - expect_main_description |= expect_main_switch; - expect_test_description |= expect_test_switch; - - if (expect_main_description) - g_test_trap_assert_stdout ("*Application Options*"); - else - g_test_trap_assert_stdout_unmatched ("*Application Options*"); - if (expect_main_switch) - g_test_trap_assert_stdout ("*--main-switch*"); - else - g_test_trap_assert_stdout_unmatched ("*--main-switch*"); - - if (expect_test_description) - g_test_trap_assert_stdout ("*Test Options*"); - else - g_test_trap_assert_stdout_unmatched ("*Test Options*"); - if (expect_test_switch) - g_test_trap_assert_stdout ("*--test-switch*"); - else - g_test_trap_assert_stdout_unmatched ("*--test-switch*"); - - if (expect_test_group) - g_test_trap_assert_stdout ("*--help-test*"); - else - g_test_trap_assert_stdout_unmatched ("*--help-test*"); - } - } - } -} - -int error_test1_int; -char *error_test2_string; -gboolean error_test3_boolean; - -int arg_test1_int; -gchar *arg_test2_string; -gchar *arg_test3_filename; -gdouble arg_test4_double; -gdouble arg_test5_double; -gint64 arg_test6_int64; -gint64 arg_test6_int64_2; - -gchar *callback_test1_string; -int callback_test2_int; - -gchar *callback_test_optional_string; -gboolean callback_test_optional_boolean; - -gchar **array_test1_array; - -gboolean ignore_test1_boolean; -gboolean ignore_test2_boolean; -gchar *ignore_test3_string; - -gchar ** -split_string (const char *str, int *argc) -{ - gchar **argv; - int len; - - argv = g_strsplit (str, " ", 0); - - for (len = 0; argv[len] != NULL; len++); - - if (argc) - *argc = len; - - return argv; -} - -gchar * -join_stringv (int argc, char **argv) -{ - int i; - GString *str; - - str = g_string_new (NULL); - - for (i = 0; i < argc; i++) - { - g_string_append (str, argv[i]); - - if (i < argc - 1) - g_string_append_c (str, ' '); - } - - return g_string_free (str, FALSE); -} - -/* Performs a shallow copy */ -char ** -copy_stringv (char **argv, int argc) -{ - return g_memdup (argv, sizeof (char *) * (argc + 1)); -} - - -static gboolean -error_test1_pre_parse (GOptionContext *context, - GOptionGroup *group, - gpointer data, - GError **error) -{ - g_assert (error_test1_int == 0x12345678); - - return TRUE; -} - -static gboolean -error_test1_post_parse (GOptionContext *context, - GOptionGroup *group, - gpointer data, - GError **error) -{ - g_assert (error_test1_int == 20); - - /* Set an error in the post hook */ - g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, " "); - - return FALSE; -} - -void -error_test1 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionGroup *main_group; - GOptionEntry entries [] = - { { "test", 0, 0, G_OPTION_ARG_INT, &error_test1_int, NULL, NULL }, - { NULL } }; - - error_test1_int = 0x12345678; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Set pre and post parse hooks */ - main_group = g_option_context_get_main_group (context); - g_option_group_set_parse_hooks (main_group, - error_test1_pre_parse, error_test1_post_parse); - - /* Now try parsing */ - argv = split_string ("program --test 20", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - g_assert (retval == FALSE); - - /* On failure, values should be reset */ - g_assert (error_test1_int == 0x12345678); - - g_strfreev (argv); - g_option_context_free (context); -} - -static gboolean -error_test2_pre_parse (GOptionContext *context, - GOptionGroup *group, - gpointer data, - GError **error) -{ - g_assert (strcmp (error_test2_string, "foo") == 0); - - return TRUE; -} - -static gboolean -error_test2_post_parse (GOptionContext *context, - GOptionGroup *group, - gpointer data, - GError **error) -{ - g_assert (strcmp (error_test2_string, "bar") == 0); - - /* Set an error in the post hook */ - g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, " "); - - return FALSE; -} - -void -error_test2 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionGroup *main_group; - GOptionEntry entries [] = - { { "test", 0, 0, G_OPTION_ARG_STRING, &error_test2_string, NULL, NULL }, - { NULL } }; - - error_test2_string = "foo"; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Set pre and post parse hooks */ - main_group = g_option_context_get_main_group (context); - g_option_group_set_parse_hooks (main_group, - error_test2_pre_parse, error_test2_post_parse); - - /* Now try parsing */ - argv = split_string ("program --test bar", &argc); - retval = g_option_context_parse (context, &argc, &argv, &error); - - g_error_free (error); - g_assert (retval == FALSE); - - g_assert (strcmp (error_test2_string, "foo") == 0); - - g_strfreev (argv); - g_option_context_free (context); -} - -static gboolean -error_test3_pre_parse (GOptionContext *context, - GOptionGroup *group, - gpointer data, - GError **error) -{ - g_assert (!error_test3_boolean); - - return TRUE; -} - -static gboolean -error_test3_post_parse (GOptionContext *context, - GOptionGroup *group, - gpointer data, - GError **error) -{ - g_assert (error_test3_boolean); - - /* Set an error in the post hook */ - g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, " "); - - return FALSE; -} - -void -error_test3 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionGroup *main_group; - GOptionEntry entries [] = - { { "test", 0, 0, G_OPTION_ARG_NONE, &error_test3_boolean, NULL, NULL }, - { NULL } }; - - error_test3_boolean = FALSE; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Set pre and post parse hooks */ - main_group = g_option_context_get_main_group (context); - g_option_group_set_parse_hooks (main_group, - error_test3_pre_parse, error_test3_post_parse); - - /* Now try parsing */ - argv = split_string ("program --test", &argc); - retval = g_option_context_parse (context, &argc, &argv, &error); - - g_error_free (error); - g_assert (retval == FALSE); - - g_assert (!error_test3_boolean); - - g_strfreev (argv); - g_option_context_free (context); -} - -static void -assert_no_error (GError *error) -{ - if (error) - { - fprintf (stderr, "unexpected error: %s, %d, %s\n", g_quark_to_string (error->domain), error->code, error->message); - exit (1); - } -} - -void -arg_test1 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "test", 0, 0, G_OPTION_ARG_INT, &arg_test1_int, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test 20 --test 30", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Last arg specified is the one that should be stored */ - g_assert (arg_test1_int == 30); - - g_strfreev (argv); - g_option_context_free (context); -} - -void -arg_test2 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "test", 0, 0, G_OPTION_ARG_STRING, &arg_test2_string, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test foo --test bar", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Last arg specified is the one that should be stored */ - g_assert (strcmp (arg_test2_string, "bar") == 0); - - g_free (arg_test2_string); - - g_strfreev (argv); - g_option_context_free (context); -} - -void -arg_test3 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "test", 0, 0, G_OPTION_ARG_FILENAME, &arg_test3_filename, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test foo.txt", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Last arg specified is the one that should be stored */ - g_assert (strcmp (arg_test3_filename, "foo.txt") == 0); - - g_free (arg_test3_filename); - - g_strfreev (argv); - g_option_context_free (context); -} - - -void -arg_test4 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "test", 0, 0, G_OPTION_ARG_DOUBLE, &arg_test4_double, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test 20.0 --test 30.03", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Last arg specified is the one that should be stored */ - g_assert (arg_test4_double == 30.03); - - g_strfreev (argv); - g_option_context_free (context); -} - -void -arg_test5 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - char *old_locale, *current_locale; - const char *locale = "de_DE"; - GOptionEntry entries [] = - { { "test", 0, 0, G_OPTION_ARG_DOUBLE, &arg_test5_double, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test 20,0 --test 30,03", &argc); - - /* set it to some locale that uses commas instead of decimal points */ - - old_locale = g_strdup (setlocale (LC_NUMERIC, locale)); - current_locale = setlocale (LC_NUMERIC, NULL); - if (strcmp (current_locale, locale) != 0) - { - fprintf (stderr, "Cannot set locale to %s, skipping\n", locale); - goto cleanup; - } - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Last arg specified is the one that should be stored */ - g_assert (arg_test5_double == 30.03); - - cleanup: - setlocale (LC_NUMERIC, old_locale); - g_free (old_locale); - - g_strfreev (argv); - g_option_context_free (context); -} - -void -arg_test6 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "test", 0, 0, G_OPTION_ARG_INT64, &arg_test6_int64, NULL, NULL }, - { "test2", 0, 0, G_OPTION_ARG_INT64, &arg_test6_int64_2, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test 4294967297 --test 4294967296 --test2 0xfffffffff", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Last arg specified is the one that should be stored */ - g_assert (arg_test6_int64 == G_GINT64_CONSTANT(4294967296)); - g_assert (arg_test6_int64_2 == G_GINT64_CONSTANT(0xfffffffff)); - - g_strfreev (argv); - g_option_context_free (context); -} - -static gboolean -callback_parse1 (const gchar *option_name, const gchar *value, - gpointer data, GError **error) -{ - callback_test1_string = g_strdup (value); - return TRUE; -} - -void -callback_test1 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "test", 0, 0, G_OPTION_ARG_CALLBACK, callback_parse1, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test foo.txt", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - g_assert (strcmp (callback_test1_string, "foo.txt") == 0); - - g_free (callback_test1_string); - - g_strfreev (argv); - g_option_context_free (context); -} - -static gboolean -callback_parse2 (const gchar *option_name, const gchar *value, - gpointer data, GError **error) -{ - callback_test2_int++; - return TRUE; -} - -void -callback_test2 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "test", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, callback_parse2, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test --test", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - g_assert (callback_test2_int == 2); - - g_strfreev (argv); - g_option_context_free (context); -} - -static gboolean -callback_parse_optional (const gchar *option_name, const gchar *value, - gpointer data, GError **error) -{ - callback_test_optional_boolean = TRUE; - if (value) - callback_test_optional_string = g_strdup (value); - else - callback_test_optional_string = NULL; - return TRUE; -} - -void -callback_test_optional_1 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "test", 0, G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, - callback_parse_optional, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test foo.txt", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - g_assert (strcmp (callback_test_optional_string, "foo.txt") == 0); - - g_assert (callback_test_optional_boolean); - - g_free (callback_test_optional_string); - - g_strfreev (argv); - g_option_context_free (context); -} - -void -callback_test_optional_2 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "test", 0, G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, - callback_parse_optional, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - g_assert (callback_test_optional_string == NULL); - - g_assert (callback_test_optional_boolean); - - g_free (callback_test_optional_string); - - g_strfreev (argv); - g_option_context_free (context); -} - -void -callback_test_optional_3 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "test", 't', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, - callback_parse_optional, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program -t foo.txt", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - g_assert (strcmp (callback_test_optional_string, "foo.txt") == 0); - - g_assert (callback_test_optional_boolean); - - g_free (callback_test_optional_string); - - g_strfreev (argv); - g_option_context_free (context); -} - - -void -callback_test_optional_4 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "test", 't', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, - callback_parse_optional, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program -t", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - g_assert (callback_test_optional_string == NULL); - - g_assert (callback_test_optional_boolean); - - g_free (callback_test_optional_string); - - g_strfreev (argv); - g_option_context_free (context); -} - -void -callback_test_optional_5 (void) -{ - GOptionContext *context; - gboolean dummy; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "dummy", 'd', 0, G_OPTION_ARG_NONE, &dummy, NULL }, - { "test", 't', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, - callback_parse_optional, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test --dummy", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - g_assert (callback_test_optional_string == NULL); - - g_assert (callback_test_optional_boolean); - - g_free (callback_test_optional_string); - - g_strfreev (argv); - g_option_context_free (context); -} - -void -callback_test_optional_6 (void) -{ - GOptionContext *context; - gboolean dummy; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "dummy", 'd', 0, G_OPTION_ARG_NONE, &dummy, NULL }, - { "test", 't', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, - callback_parse_optional, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program -t -d", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - g_assert (callback_test_optional_string == NULL); - - g_assert (callback_test_optional_boolean); - - g_free (callback_test_optional_string); - - g_strfreev (argv); - g_option_context_free (context); -} - -void -callback_test_optional_7 (void) -{ - GOptionContext *context; - gboolean dummy; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "dummy", 'd', 0, G_OPTION_ARG_NONE, &dummy, NULL }, - { "test", 't', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, - callback_parse_optional, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program -td", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - g_assert (callback_test_optional_string == NULL); - - g_assert (callback_test_optional_boolean); - - g_free (callback_test_optional_string); - - g_strfreev (argv); - g_option_context_free (context); -} - -void -callback_test_optional_8 (void) -{ - GOptionContext *context; - gboolean dummy; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "dummy", 'd', 0, G_OPTION_ARG_NONE, &dummy, NULL }, - { "test", 't', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, - callback_parse_optional, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program -dt foo.txt", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - g_assert (callback_test_optional_string); - - g_assert (callback_test_optional_boolean); - - g_free (callback_test_optional_string); - - g_strfreev (argv); - g_option_context_free (context); -} - -static GPtrArray *callback_remaining_args; -static gboolean -callback_remaining_test1_callback (const gchar *option_name, const gchar *value, - gpointer data, GError **error) -{ - g_ptr_array_add (callback_remaining_args, g_strdup (value)); - return TRUE; -} - -void -callback_remaining_test1 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_CALLBACK, callback_remaining_test1_callback, NULL, NULL }, - { NULL } }; - - callback_remaining_args = g_ptr_array_new (); - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program foo.txt blah.txt", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - g_assert (callback_remaining_args->len == 2); - g_assert (strcmp (callback_remaining_args->pdata[0], "foo.txt") == 0); - g_assert (strcmp (callback_remaining_args->pdata[1], "blah.txt") == 0); - - g_ptr_array_foreach (callback_remaining_args, (GFunc) g_free, NULL); - g_ptr_array_free (callback_remaining_args, TRUE); - - g_strfreev (argv); - g_option_context_free (context); -} - -static gboolean -callback_error (const gchar *option_name, const gchar *value, - gpointer data, GError **error) -{ - g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "42"); - return FALSE; -} - -static void -callback_returns_false (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "error", 0, 0, G_OPTION_ARG_CALLBACK, callback_error, NULL, NULL }, - { "error-no-arg", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, callback_error, NULL, NULL }, - { "error-optional-arg", 0, G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, callback_error, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --error value", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - g_assert_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE); - g_assert (retval == FALSE); - - g_option_context_free (context); - g_clear_error (&error); - - /* And again, this time with a no-arg variant */ - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - argv = split_string ("program --error-no-arg", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - g_assert_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE); - g_assert (retval == FALSE); - - g_option_context_free (context); - g_clear_error (&error); - - /* And again, this time with a optional arg variant, with argument */ - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - argv = split_string ("program --error-optional-arg value", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - g_assert_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE); - g_assert (retval == FALSE); - - g_option_context_free (context); - g_clear_error (&error); - - /* And again, this time with a optional arg variant, without argument */ - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - argv = split_string ("program --error-optional-arg", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - g_assert_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE); - g_assert (retval == FALSE); - - g_option_context_free (context); - g_clear_error (&error); -} - - -void -ignore_test1 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv, **argv_copy; - int argc; - gchar *arg; - GOptionEntry entries [] = - { { "test", 0, 0, G_OPTION_ARG_NONE, &ignore_test1_boolean, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_set_ignore_unknown_options (context, TRUE); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test --hello", &argc); - argv_copy = copy_stringv (argv, argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Check array */ - arg = join_stringv (argc, argv); - g_assert (strcmp (arg, "program --hello") == 0); - - g_free (arg); - g_strfreev (argv_copy); - g_free (argv); - g_option_context_free (context); -} - -void -ignore_test2 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - gchar *arg; - GOptionEntry entries [] = - { { "test", 't', 0, G_OPTION_ARG_NONE, &ignore_test2_boolean, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_set_ignore_unknown_options (context, TRUE); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program -test", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Check array */ - arg = join_stringv (argc, argv); - g_assert (strcmp (arg, "program -es") == 0); - - g_free (arg); - g_strfreev (argv); - g_option_context_free (context); -} - -void -ignore_test3 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv, **argv_copy; - int argc; - gchar *arg; - GOptionEntry entries [] = - { { "test", 0, 0, G_OPTION_ARG_STRING, &ignore_test3_string, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_set_ignore_unknown_options (context, TRUE); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test foo --hello", &argc); - argv_copy = copy_stringv (argv, argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Check array */ - arg = join_stringv (argc, argv); - g_assert (strcmp (arg, "program --hello") == 0); - - g_assert (strcmp (ignore_test3_string, "foo") == 0); - g_free (ignore_test3_string); - - g_free (arg); - g_strfreev (argv_copy); - g_free (argv); - g_option_context_free (context); -} - -void -array_test1 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = - { { "test", 0, 0, G_OPTION_ARG_STRING_ARRAY, &array_test1_array, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test foo --test bar", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Check array */ - g_assert (strcmp (array_test1_array[0], "foo") == 0); - g_assert (strcmp (array_test1_array[1], "bar") == 0); - g_assert (array_test1_array[2] == NULL); - - g_strfreev (array_test1_array); - - g_strfreev (argv); - g_option_context_free (context); -} - -void -add_test1 (void) -{ - GOptionContext *context; - - GOptionEntry entries1 [] = - { { "test1", 0, 0, G_OPTION_ARG_STRING_ARRAY, NULL, NULL, NULL }, - { NULL } }; - GOptionEntry entries2 [] = - { { "test2", 0, 0, G_OPTION_ARG_STRING_ARRAY, NULL, NULL, NULL }, - { NULL } }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries1, NULL); - g_option_context_add_main_entries (context, entries2, NULL); - - g_option_context_free (context); -} - -void -empty_test1 (void) -{ - GOptionContext *context; - GOptionEntry entries [] = - { { NULL } }; - char *prgname; - - g_set_prgname (NULL); - context = g_option_context_new (NULL); - - g_option_context_add_main_entries (context, entries, NULL); - - g_option_context_parse (context, NULL, NULL, NULL); - - prgname = g_get_prgname (); - g_assert (prgname && strcmp (prgname, "<unknown>") == 0); - - g_option_context_free (context); -} - -void -empty_test2 (void) -{ - GOptionContext *context; - - context = g_option_context_new (NULL); - g_option_context_parse (context, NULL, NULL, NULL); - - g_option_context_free (context); -} - -void -empty_test3 (void) -{ - GOptionContext *context; - gint argc; - gchar **argv; - - argc = 0; - argv = NULL; - - context = g_option_context_new (NULL); - g_option_context_parse (context, &argc, &argv, NULL); - - g_option_context_free (context); -} - -/* check that non-option arguments are left in argv by default */ -void -rest_test1 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = { - { "test", 0, 0, G_OPTION_ARG_NONE, &ignore_test1_boolean, NULL, NULL }, - { NULL } - }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program foo --test bar", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Check array */ - g_assert (ignore_test1_boolean); - g_assert (strcmp (argv[0], "program") == 0); - g_assert (strcmp (argv[1], "foo") == 0); - g_assert (strcmp (argv[2], "bar") == 0); - g_assert (argv[3] == NULL); - - g_strfreev (argv); - g_option_context_free (context); -} - -/* check that -- works */ -void -rest_test2 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = { - { "test", 0, 0, G_OPTION_ARG_NONE, &ignore_test1_boolean, NULL, NULL }, - { NULL } - }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program foo --test -- -bar", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Check array */ - g_assert (ignore_test1_boolean); - g_assert (strcmp (argv[0], "program") == 0); - g_assert (strcmp (argv[1], "foo") == 0); - g_assert (strcmp (argv[2], "--") == 0); - g_assert (strcmp (argv[3], "-bar") == 0); - g_assert (argv[4] == NULL); - - g_strfreev (argv); - g_option_context_free (context); -} - -/* check that -- stripping works */ -void -rest_test2a (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = { - { "test", 0, 0, G_OPTION_ARG_NONE, &ignore_test1_boolean, NULL, NULL }, - { NULL } - }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program foo --test -- bar", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Check array */ - g_assert (ignore_test1_boolean); - g_assert (strcmp (argv[0], "program") == 0); - g_assert (strcmp (argv[1], "foo") == 0); - g_assert (strcmp (argv[2], "bar") == 0); - g_assert (argv[3] == NULL); - - g_strfreev (argv); - g_option_context_free (context); -} - -void -rest_test2b (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = { - { "test", 0, 0, G_OPTION_ARG_NONE, &ignore_test1_boolean, NULL, NULL }, - { NULL } - }; - - context = g_option_context_new (NULL); - g_option_context_set_ignore_unknown_options (context, TRUE); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program foo --test -bar --", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Check array */ - g_assert (ignore_test1_boolean); - g_assert (strcmp (argv[0], "program") == 0); - g_assert (strcmp (argv[1], "foo") == 0); - g_assert (strcmp (argv[2], "-bar") == 0); - g_assert (argv[3] == NULL); - - g_strfreev (argv); - g_option_context_free (context); -} - -void -rest_test2c (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = { - { "test", 0, 0, G_OPTION_ARG_NONE, &ignore_test1_boolean, NULL, NULL }, - { NULL } - }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test foo -- bar", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Check array */ - g_assert (ignore_test1_boolean); - g_assert (strcmp (argv[0], "program") == 0); - g_assert (strcmp (argv[1], "foo") == 0); - g_assert (strcmp (argv[2], "bar") == 0); - g_assert (argv[3] == NULL); - - g_strfreev (argv); - g_option_context_free (context); -} - -void -rest_test2d (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = { - { "test", 0, 0, G_OPTION_ARG_NONE, &ignore_test1_boolean, NULL, NULL }, - { NULL } - }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test -- -bar", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Check array */ - g_assert (ignore_test1_boolean); - g_assert (strcmp (argv[0], "program") == 0); - g_assert (strcmp (argv[1], "--") == 0); - g_assert (strcmp (argv[2], "-bar") == 0); - g_assert (argv[3] == NULL); - - g_strfreev (argv); - g_option_context_free (context); -} - - -/* check that G_OPTION_REMAINING collects non-option arguments */ -void -rest_test3 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = { - { "test", 0, 0, G_OPTION_ARG_NONE, &ignore_test1_boolean, NULL, NULL }, - { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &array_test1_array, NULL, NULL }, - { NULL } - }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program foo --test bar", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Check array */ - g_assert (ignore_test1_boolean); - g_assert (strcmp (array_test1_array[0], "foo") == 0); - g_assert (strcmp (array_test1_array[1], "bar") == 0); - g_assert (array_test1_array[2] == NULL); - - g_strfreev (array_test1_array); - - g_strfreev (argv); - g_option_context_free (context); -} - - -/* check that G_OPTION_REMAINING and -- work together */ -void -rest_test4 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = { - { "test", 0, 0, G_OPTION_ARG_NONE, &ignore_test1_boolean, NULL, NULL }, - { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &array_test1_array, NULL, NULL }, - { NULL } - }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program foo --test -- -bar", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Check array */ - g_assert (ignore_test1_boolean); - g_assert (strcmp (array_test1_array[0], "foo") == 0); - g_assert (strcmp (array_test1_array[1], "-bar") == 0); - g_assert (array_test1_array[2] == NULL); - - g_strfreev (array_test1_array); - - g_strfreev (argv); - g_option_context_free (context); -} - -/* test that G_OPTION_REMAINING works with G_OPTION_ARG_FILENAME_ARRAY */ -void -rest_test5 (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = { - { "test", 0, 0, G_OPTION_ARG_NONE, &ignore_test1_boolean, NULL, NULL }, - { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &array_test1_array, NULL, NULL }, - { NULL } - }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program foo --test bar", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - /* Check array */ - g_assert (ignore_test1_boolean); - g_assert (strcmp (array_test1_array[0], "foo") == 0); - g_assert (strcmp (array_test1_array[1], "bar") == 0); - g_assert (array_test1_array[2] == NULL); - - g_strfreev (array_test1_array); - - g_strfreev (argv); - g_option_context_free (context); -} - -void -unknown_short_test (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - GOptionEntry entries [] = { { NULL } }; - - g_test_bug ("166609"); - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program -0", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - g_assert (!retval); - - g_strfreev (argv); - g_option_context_free (context); -} - -/* test that lone dashes are treated as non-options */ -void lonely_dash_test (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - - g_test_bug ("168008"); - - context = g_option_context_new (NULL); - - /* Now try parsing */ - argv = split_string ("program -", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - assert_no_error (error); - g_assert (retval); - - g_assert (argv[1] && strcmp (argv[1], "-") == 0); - - g_strfreev (argv); - g_option_context_free (context); -} - -void -missing_arg_test (void) -{ - GOptionContext *context; - gboolean retval; - GError *error = NULL; - gchar **argv; - int argc; - gchar *arg = NULL; - GOptionEntry entries [] = - { { "test", 't', 0, G_OPTION_ARG_STRING, &arg, NULL, NULL }, - { NULL } }; - - g_test_bug ("305576"); - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - - /* Now try parsing */ - argv = split_string ("program --test", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - g_assert (retval == FALSE); - g_clear_error (&error); - - g_strfreev (argv); - - /* Try parsing again */ - argv = split_string ("program --t", &argc); - - retval = g_option_context_parse (context, &argc, &argv, &error); - g_assert (retval == FALSE); - - g_strfreev (argv); - g_option_context_free (context); -} - -int -main (int argc, - char *argv[]) -{ - g_test_init (&argc, &argv, NULL); - - g_test_bug_base ("http://bugzilla.gnome.org/"); - g_test_add_func ("/group/captions", group_captions); - - /* Test that restoration on failure works */ - g_test_add_func ("/restoration/int", error_test1); - g_test_add_func ("/restoration/string", error_test2); - g_test_add_func ("/restoration/boolean", error_test3); - - /* Test that special argument parsing works */ - g_test_add_func ("/arg/repetition/int", arg_test1); - g_test_add_func ("/arg/repetition/string", arg_test2); - g_test_add_func ("/arg/repetition/filename", arg_test3); - g_test_add_func ("/arg/repetition/double", arg_test4); - g_test_add_func ("/arg/repetition/locale", arg_test5); - g_test_add_func ("/arg/repetition/int64", arg_test6); - - /* Test string arrays */ - g_test_add_func ("/arg/array/string", array_test1); - - /* Test callback args */ - g_test_add_func ("/arg/callback/string", callback_test1); - g_test_add_func ("/arg/callback/count", callback_test2); - - /* Test optional arg flag for callback */ - g_test_add_func ("/arg/callback/optional1", callback_test_optional_1); - g_test_add_func ("/arg/callback/optional2", callback_test_optional_2); - g_test_add_func ("/arg/callback/optional3", callback_test_optional_3); - g_test_add_func ("/arg/callback/optional4", callback_test_optional_4); - g_test_add_func ("/arg/callback/optional5", callback_test_optional_5); - g_test_add_func ("/arg/callback/optional6", callback_test_optional_6); - g_test_add_func ("/arg/callback/optional7", callback_test_optional_7); - g_test_add_func ("/arg/callback/optional8", callback_test_optional_8); - - /* Test callback with G_OPTION_REMAINING */ - g_test_add_func ("/arg/remaining/callback", callback_remaining_test1); - - /* Test callbacks which return FALSE */ - g_test_add_func ("/arg/remaining/callback-false", callback_returns_false); - - /* Test ignoring options */ - g_test_add_func ("/arg/ignore/long", ignore_test1); - g_test_add_func ("/arg/ignore/short", ignore_test2); - g_test_add_func ("/arg/ignore/arg", ignore_test3); - - g_test_add_func ("/context/add", add_test1); - - /* Test parsing empty args */ - g_test_add_func ("/context/empty1", empty_test1); - g_test_add_func ("/context/empty2", empty_test2); - g_test_add_func ("/context/empty3", empty_test3); - - /* Test handling of rest args */ - g_test_add_func ("/arg/rest/non-option", rest_test1); - g_test_add_func ("/arg/rest/separator1", rest_test2); - g_test_add_func ("/arg/rest/separator2", rest_test2a); - g_test_add_func ("/arg/rest/separator3", rest_test2b); - g_test_add_func ("/arg/rest/separator4", rest_test2c); - g_test_add_func ("/arg/rest/separator5", rest_test2d); - g_test_add_func ("/arg/remaining/non-option", rest_test3); - g_test_add_func ("/arg/remaining/separator", rest_test4); - g_test_add_func ("/arg/remaining/array", rest_test5); - - /* regression tests for individual bugs */ - g_test_add_func ("/bug/unknown-short", unknown_short_test); - g_test_add_func ("/bug/lonely-dash", lonely_dash_test); - g_test_add_func ("/bug/missing-arg", missing_arg_test); - - return g_test_run(); -} diff --git a/glib/tests/printf.c b/glib/tests/printf.c deleted file mode 100644 index ff8eee275..000000000 --- a/glib/tests/printf.c +++ /dev/null @@ -1,711 +0,0 @@ -/* Unit tests for gstring - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * This work is provided "as is"; redistribution and modification - * in whole or in part, in any medium, physical or electronic is - * permitted without restriction. - * - * This work 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. - */ - -#include <stdio.h> -#include <string.h> -#include "glib.h" - -static void -test_retval_and_trunc (void) -{ - gchar buf[128]; - gint res; - - res = g_snprintf (buf, 0, "abc"); - g_assert_cmpint (res, ==, 3); - - res = g_snprintf (NULL, 0, "abc"); - g_assert_cmpint (res, ==, 3); - - res = g_snprintf (buf, 5, "abc"); - g_assert_cmpint (res, ==, 3); - - res = g_snprintf (buf, 1, "abc"); - g_assert_cmpint (res, ==, 3); - g_assert (buf[0] == '\0'); - g_assert_cmpstr (buf, ==, ""); - - res = g_snprintf (buf, 2, "abc"); - g_assert_cmpint (res, ==, 3); - g_assert (buf[1] == '\0'); - g_assert_cmpstr (buf, ==, "a"); - - res = g_snprintf (buf, 3, "abc"); - g_assert_cmpint (res, ==, 3); - g_assert (buf[2] == '\0'); - g_assert_cmpstr (buf, ==, "ab"); - - res = g_snprintf (buf, 4, "abc"); - g_assert_cmpint (res, ==, 3); - g_assert (buf[3] == '\0'); - g_assert_cmpstr (buf, ==, "abc"); - - res = g_snprintf (buf, 5, "abc"); - g_assert_cmpint (res, ==, 3); - g_assert (buf[3] == '\0'); - g_assert_cmpstr (buf, ==, "abc"); -} - -static void -test_d (void) -{ - gchar buf[128]; - gint res; - const gchar *fmt; - - /* %d basic formatting */ - - res = g_snprintf (buf, 128, "%d", 5); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "5"); - - res = g_snprintf (buf, 128, "%d", 0); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "0"); - - res = g_snprintf (buf, 128, "%.0d", 0); - g_assert_cmpint (res, ==, 0); - g_assert_cmpstr (buf, ==, ""); - - res = g_snprintf (buf, 128, "%.0d", 1); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "1"); - - res = g_snprintf (buf, 128, "%.d", 2); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "2"); - - res = g_snprintf (buf, 128, "%d", -1); - g_assert_cmpint (res, ==, 2); - g_assert_cmpstr (buf, ==, "-1"); - - res = g_snprintf (buf, 128, "%.3d", 5); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "005"); - - res = g_snprintf (buf, 128, "%.3d", -5); - g_assert_cmpint (res, ==, 4); - g_assert_cmpstr (buf, ==, "-005"); - - res = g_snprintf (buf, 128, "%5.3d", 5); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, " 005"); - - res = g_snprintf (buf, 128, "%-5.3d", -5); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, "-005 "); - - /* %d, length modifiers */ - - res = g_snprintf (buf, 128, "%" G_GINT16_FORMAT, (gint16)-5); - g_assert_cmpint (res, ==, 2); - g_assert_cmpstr (buf, ==, "-5"); - - res = g_snprintf (buf, 128, "%" G_GUINT16_FORMAT, (guint16)5); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "5"); - - res = g_snprintf (buf, 128, "%" G_GINT32_FORMAT, (gint32)-5); - g_assert_cmpint (res, ==, 2); - g_assert_cmpstr (buf, ==, "-5"); - - res = g_snprintf (buf, 128, "%" G_GUINT32_FORMAT, (guint32)5); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "5"); - - res = g_snprintf (buf, 128, "%" G_GINT64_FORMAT, (gint64)-5); - g_assert_cmpint (res, ==, 2); - g_assert_cmpstr (buf, ==, "-5"); - - res = g_snprintf (buf, 128, "%" G_GUINT64_FORMAT, (guint64)5); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "5"); - - res = g_snprintf (buf, 128, "%" G_GSSIZE_FORMAT, (gssize)-5); - g_assert_cmpint (res, ==, 2); - g_assert_cmpstr (buf, ==, "-5"); - - res = g_snprintf (buf, 128, "%" G_GSIZE_FORMAT, (gsize)5); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "5"); - - /* %d, flags */ - - res = g_snprintf (buf, 128, "%-d", 5); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "5"); - - res = g_snprintf (buf, 128, "%-+d", 5); - g_assert_cmpint (res, ==, 2); - g_assert_cmpstr (buf, ==, "+5"); - - res = g_snprintf (buf, 128, "%+-d", 5); - g_assert_cmpint (res, ==, 2); - g_assert_cmpstr (buf, ==, "+5"); - - res = g_snprintf (buf, 128, "%+d", -5); - g_assert_cmpint (res, ==, 2); - g_assert_cmpstr (buf, ==, "-5"); - - res = g_snprintf (buf, 128, "% d", 5); - g_assert_cmpint (res, ==, 2); - g_assert_cmpstr (buf, ==, " 5"); - - res = g_snprintf (buf, 128, "% .0d", 0); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, " "); - - res = g_snprintf (buf, 128, "%03d", 5); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "005"); - - res = g_snprintf (buf, 128, "%03d", -5); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "-05"); - - /* gcc emits warnings for the following formats, since the C spec - * says some of the flags must be ignored. (The " " in "% +d" and - * the "0" in "%-03d".) But we need to test that our printf gets - * those rules right. So we fool gcc into not warning. - */ - fmt = "% +d"; - res = g_snprintf (buf, 128, fmt, 5); - g_assert_cmpint (res, ==, 2); - g_assert_cmpstr (buf, ==, "+5"); - - fmt = "%-03d"; - res = g_snprintf (buf, 128, fmt, -5); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "-5 "); -} - -static void -test_o (void) -{ - gchar buf[128]; - gint res; - - /* %o basic formatting */ - - res = g_snprintf (buf, 128, "%o", 5); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "5"); - - res = g_snprintf (buf, 128, "%o", 8); - g_assert_cmpint (res, ==, 2); - g_assert_cmpstr (buf, ==, "10"); - - res = g_snprintf (buf, 128, "%o", 0); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "0"); - - res = g_snprintf (buf, 128, "%.0o", 0); - g_assert_cmpint (res, ==, 0); - g_assert_cmpstr (buf, ==, ""); - - res = g_snprintf (buf, 128, "%.0o", 1); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "1"); - - res = g_snprintf (buf, 128, "%.3o", 5); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "005"); - - res = g_snprintf (buf, 128, "%.3o", 8); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "010"); - - res = g_snprintf (buf, 128, "%5.3o", 5); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, " 005"); -} - -static void -test_u (void) -{ - gchar buf[128]; - gint res; - - /* %u, basic formatting */ - - res = g_snprintf (buf, 128, "%u", 5); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "5"); - - res = g_snprintf (buf, 128, "%u", 0); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "0"); - - res = g_snprintf (buf, 128, "%.0u", 0); - g_assert_cmpint (res, ==, 0); - g_assert_cmpstr (buf, ==, ""); - - res = g_snprintf (buf, 128, "%.0u", 1); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "1"); - - res = g_snprintf (buf, 128, "%.3u", 5); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "005"); - - res = g_snprintf (buf, 128, "%5.3u", 5); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, " 005"); -} - -static void -test_x (void) -{ - gchar buf[128]; - gint res; - - /* %x, basic formatting */ - - res = g_snprintf (buf, 128, "%x", 5); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "5"); - - res = g_snprintf (buf, 128, "%x", 31); - g_assert_cmpint (res, ==, 2); - g_assert_cmpstr (buf, ==, "1f"); - - res = g_snprintf (buf, 128, "%x", 0); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "0"); - - res = g_snprintf (buf, 128, "%.0x", 0); - g_assert_cmpint (res, ==, 0); - g_assert_cmpstr (buf, ==, ""); - - res = g_snprintf (buf, 128, "%.0x", 1); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "1"); - - res = g_snprintf (buf, 128, "%.3x", 5); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "005"); - - res = g_snprintf (buf, 128, "%.3x", 31); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "01f"); - - res = g_snprintf (buf, 128, "%5.3x", 5); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, " 005"); - - /* %x, flags */ - - res = g_snprintf (buf, 128, "%-x", 5); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "5"); - - res = g_snprintf (buf, 128, "%03x", 5); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "005"); - - res = g_snprintf (buf, 128, "%#x", 31); - g_assert_cmpint (res, ==, 4); - g_assert_cmpstr (buf, ==, "0x1f"); - - res = g_snprintf (buf, 128, "%#x", 0); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "0"); -} - -static void -test_X (void) -{ - gchar buf[128]; - gint res; - - /* %X, basic formatting */ - - res = g_snprintf (buf, 128, "%X", 5); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "5"); - - res = g_snprintf (buf, 128, "%X", 31); - g_assert_cmpint (res, ==, 2); - g_assert_cmpstr (buf, ==, "1F"); - - res = g_snprintf (buf, 128, "%X", 0); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "0"); - - res = g_snprintf (buf, 128, "%.0X", 0); - g_assert_cmpint (res, ==, 0); - g_assert_cmpstr (buf, ==, ""); - - res = g_snprintf (buf, 128, "%.0X", 1); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "1"); - - res = g_snprintf (buf, 128, "%.3X", 5); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "005"); - - res = g_snprintf (buf, 128, "%.3X", 31); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "01F"); - - res = g_snprintf (buf, 128, "%5.3X", 5); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, " 005"); - - /* %X, flags */ - - res = g_snprintf (buf, 128, "%-X", 5); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "5"); - - res = g_snprintf (buf, 128, "%03X", 5); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "005"); - - res = g_snprintf (buf, 128, "%#X", 31); - g_assert_cmpint (res, ==, 4); - g_assert_cmpstr (buf, ==, "0X1F"); - - res = g_snprintf (buf, 128, "%#X", 0); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "0"); -} - -static void -test_f (void) -{ - gchar buf[128]; - gint res; - - /* %f, basic formattting */ - - res = g_snprintf (buf, 128, "%f", G_PI); - g_assert_cmpint (res, ==, 8); - g_assert (0 == strncmp (buf, "3.14159", 7)); - - res = g_snprintf (buf, 128, "%.8f", G_PI); - g_assert_cmpint (res, ==, 10); - g_assert (0 == strncmp (buf, "3.1415926", 9)); - - res = g_snprintf (buf, 128, "%.0f", G_PI); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "3"); - - res = g_snprintf (buf, 128, "%1.f", G_PI); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "3"); - - res = g_snprintf (buf, 128, "%3.f", G_PI); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, " 3"); - - /* %f, flags */ - - res = g_snprintf (buf, 128, "%+f", G_PI); - g_assert_cmpint (res, ==, 9); - g_assert (0 == strncmp (buf, "+3.14159", 8)); - - res = g_snprintf (buf, 128, "% f", G_PI); - g_assert_cmpint (res, ==, 9); - g_assert (0 == strncmp (buf, " 3.14159", 8)); - - res = g_snprintf (buf, 128, "%#.0f", G_PI); - g_assert_cmpint (res, ==, 2); - g_assert_cmpstr (buf, ==, "3."); - - res = g_snprintf (buf, 128, "%05.2f", G_PI); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, "03.14"); -} - -static gboolean -same_value (const gchar *actual, - const gchar *expected) -{ - gdouble actual_value, expected_value; - - actual_value = g_ascii_strtod (actual, NULL); - expected_value = g_ascii_strtod (expected, NULL); - - return actual_value == expected_value; -} - -static void -test_e (void) -{ - gchar buf[128]; - gint res; - - /* %e, basic formatting */ - /* for %e we can't expect to reproduce exact strings and lengths, since SUS - * only guarantees that the exponent shall always contain at least two - * digits. On Windows, it seems to be at least three digits long. - * Therefore, we compare the results of parsing the expected result and the - * actual result. - */ - - res = g_snprintf (buf, 128, "%e", G_PI); - g_assert_cmpint (res, >=, 12); - g_assert (same_value (buf, "3.141593e+00")); - - res = g_snprintf (buf, 128, "%.8e", G_PI); - g_assert_cmpint (res, >=, 14); - g_assert (same_value (buf, "3.14159265e+00")); - - res = g_snprintf (buf, 128, "%.0e", G_PI); - g_assert_cmpint (res, >=, 5); - g_assert (same_value (buf, "3e+00")); - - res = g_snprintf (buf, 128, "%.1e", 0.0); - g_assert_cmpint (res, >=, 7); - g_assert (same_value (buf, "0.0e+00")); - - res = g_snprintf (buf, 128, "%.1e", 0.00001); - g_assert_cmpint (res, >=, 7); - g_assert (same_value (buf, "1.0e-05")); - - res = g_snprintf (buf, 128, "%.1e", 10000.0); - g_assert_cmpint (res, >=, 7); - g_assert (same_value (buf, "1.0e+04")); - - /* %e, flags */ - - res = g_snprintf (buf, 128, "%+e", G_PI); - g_assert_cmpint (res, >=, 13); - g_assert (same_value (buf, "+3.141593e+00")); - - res = g_snprintf (buf, 128, "% e", G_PI); - g_assert_cmpint (res, >=, 13); - g_assert (same_value (buf, " 3.141593e+00")); - - res = g_snprintf (buf, 128, "%#.0e", G_PI); - g_assert_cmpint (res, >=, 6); - g_assert (same_value (buf, "3.e+00")); - - res = g_snprintf (buf, 128, "%09.2e", G_PI); - g_assert_cmpint (res, >=, 9); - g_assert (same_value (buf, "03.14e+00")); -} - -static void -test_c (void) -{ - gchar buf[128]; - gint res; - - res = g_snprintf (buf, 128, "%c", 'a'); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "a"); -} - -static void -test_s (void) -{ - gchar buf[128]; - gint res; - - res = g_snprintf (buf, 128, "%.2s", "abc"); - g_assert_cmpint (res, ==, 2); - g_assert_cmpstr (buf, ==, "ab"); - - res = g_snprintf (buf, 128, "%.6s", "abc"); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "abc"); - - res = g_snprintf (buf, 128, "%5s", "abc"); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, " abc"); - - res = g_snprintf (buf, 128, "%-5s", "abc"); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, "abc "); - - res = g_snprintf (buf, 128, "%5.2s", "abc"); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, " ab"); - - res = g_snprintf (buf, 128, "%*s", 5, "abc"); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, " abc"); - -#if 0 /* HP-UX doesn't get this right */ - res = g_snprintf (buf, 128, "%*s", -5, "abc"); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, "abc "); -#endif - - res = g_snprintf (buf, 128, "%*.*s", 5, 2, "abc"); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, " ab"); -} - -static void -test_n (void) -{ - gchar buf[128]; - gint res; - gint i; - glong l; - - res = g_snprintf (buf, 128, "abc%n", &i); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "abc"); - g_assert_cmpint (i, ==, 3); - - res = g_snprintf (buf, 128, "abc%ln", &l); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "abc"); - g_assert_cmpint (l, ==, 3); -} - -static void -test_percent (void) -{ - gchar buf[128]; - gint res; - - res = g_snprintf (buf, 128, "%%"); - g_assert_cmpint (res, ==, 1); - g_assert_cmpstr (buf, ==, "%"); -} - -static void -test_positional_params (void) -{ - gchar buf[128]; - gint res; - - res = g_snprintf (buf, 128, "%2$c %1$c", 'b', 'a'); - g_assert_cmpint (res, ==, 3); - g_assert_cmpstr (buf, ==, "a b"); - - res = g_snprintf (buf, 128, "%1$*2$.*3$s", "abc", 5, 2); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, " ab"); - - res = g_snprintf (buf, 128, "%1$s%1$s", "abc"); - g_assert_cmpint (res, ==, 6); - g_assert_cmpstr (buf, ==, "abcabc"); -} - -static void -test_64bit (void) -{ - gchar buf[128]; - gint res; - - res = g_snprintf (buf, 128, "%" G_GINT64_FORMAT, (gint64)123456); - g_assert_cmpint (res, ==, 6); - g_assert_cmpstr (buf, ==, "123456"); - - res = g_snprintf (buf, 128, "%" G_GINT64_FORMAT, (gint64)-123456); - g_assert_cmpint (res, ==, 7); - g_assert_cmpstr (buf, ==, "-123456"); - - res = g_snprintf (buf, 128, "%" G_GUINT64_FORMAT, (guint64)123456); - g_assert_cmpint (res, ==, 6); - g_assert_cmpstr (buf, ==, "123456"); - - res = g_snprintf (buf, 128, "%" G_GINT64_MODIFIER "o", (gint64)123456); - g_assert_cmpint (res, ==, 6); - g_assert_cmpstr (buf, ==, "361100"); - - res = g_snprintf (buf, 128, "%#" G_GINT64_MODIFIER "o", (gint64)123456); - g_assert_cmpint (res, ==, 7); - g_assert_cmpstr (buf, ==, "0361100"); - - res = g_snprintf (buf, 128, "%" G_GINT64_MODIFIER "x", (gint64)123456); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, "1e240"); - - res = g_snprintf (buf, 128, "%#" G_GINT64_MODIFIER "x", (gint64)123456); - g_assert_cmpint (res, ==, 7); - g_assert_cmpstr (buf, ==, "0x1e240"); - - res = g_snprintf (buf, 128, "%" G_GINT64_MODIFIER "X", (gint64)123456); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, "1E240"); - -#ifdef G_OS_WIN32 - /* On Win32, test that the "ll" modifier also works, for backward - * compatibility. One really should use the G_GINT64_MODIFIER (which - * on Win32 is the "I64" that the (msvcrt) C library's printf uses), - * but "ll" used to work with the "trio" g_printf implementation in - * GLib 2.2, so it's best if it continues to work. - */ - - res = g_snprintf (buf, 128, "%" "lli", (gint64)123456); - g_assert_cmpint (res, ==, 6); - g_assert_cmpstr (buf, ==, "123456"); - - res = g_snprintf (buf, 128, "%" "lli", (gint64)-123456); - g_assert_cmpint (res, ==, 7); - g_assert_cmpstr (buf, ==, "-123456"); - - res = g_snprintf (buf, 128, "%" "llu", (guint64)123456); - g_assert_cmpint (res, ==, 6); - g_assert_cmpstr (buf, ==, "123456"); - - res = g_snprintf (buf, 128, "%" "ll" "o", (gint64)123456); - g_assert_cmpint (res, ==, 6); - g_assert_cmpstr (buf, ==, "361100"); - - res = g_snprintf (buf, 128, "%#" "ll" "o", (gint64)123456); - g_assert_cmpint (res, ==, 7); - g_assert_cmpstr (buf, ==, "0361100"); - - res = g_snprintf (buf, 128, "%" "ll" "x", (gint64)123456); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, "1e240"); - - res = g_snprintf (buf, 128, "%#" "ll" "x", (gint64)123456); - g_assert_cmpint (res, ==, 7); - g_assert_cmpstr (buf, ==, "0x1e240"); - - res = g_snprintf (buf, 128, "%" "ll" "X", (gint64)123456); - g_assert_cmpint (res, ==, 5); - g_assert_cmpstr (buf, ==, "1E240"); -#endif -} - -int -main (int argc, - char *argv[]) -{ - g_test_init (&argc, &argv, NULL); - - g_test_add_func ("/printf/test-retval-and-trunc", test_retval_and_trunc); - g_test_add_func ("/printf/test-d", test_d); - g_test_add_func ("/printf/test-o", test_o); - g_test_add_func ("/printf/test-u", test_u); - g_test_add_func ("/printf/test-x", test_x); - g_test_add_func ("/printf/test-X", test_X); - g_test_add_func ("/printf/test-f", test_f); - g_test_add_func ("/printf/test-e", test_e); - g_test_add_func ("/printf/test-c", test_c); - g_test_add_func ("/printf/test-s", test_s); - g_test_add_func ("/printf/test-n", test_n); - g_test_add_func ("/printf/test-percent", test_percent); - g_test_add_func ("/printf/test-positional-params", test_positional_params); - g_test_add_func ("/printf/test-64bit", test_64bit); - - return g_test_run(); -} diff --git a/glib/tests/rand.c b/glib/tests/rand.c deleted file mode 100644 index 0bddfbf4d..000000000 --- a/glib/tests/rand.c +++ /dev/null @@ -1,160 +0,0 @@ -/* Unit tests for gstring - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * This work is provided "as is"; redistribution and modification - * in whole or in part, in any medium, physical or electronic is - * permitted without restriction. - * - * This work 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. - */ - -#include "glib.h" - -/* Outputs tested against the reference implementation mt19937ar.c from - http://www.math.keio.ac.jp/~matumoto/MT2002/emt19937ar.html */ - -/* Tests for a simple seed, first number is the seed */ -const guint32 first_numbers[] = -{ - 0x7a7a7a7a, - 0xfdcc2d54, - 0x3a279ceb, - 0xc4d39c33, - 0xf31895cd, - 0x46ca0afc, - 0x3f5484ff, - 0x54bc9557, - 0xed2c24b1, - 0x84062503, - 0x8f6404b3, - 0x599a94b3, - 0xe46d03d5, - 0x310beb78, - 0x7bee5d08, - 0x760d09be, - 0x59b6e163, - 0xbf6d16ec, - 0xcca5fb54, - 0x5de7259b, - 0x1696330c, -}; - -/* array seed */ -const guint32 seed_array[] = -{ - 0x6553375f, - 0xd6b8d43b, - 0xa1e7667f, - 0x2b10117c -}; - -/* tests for the array seed */ -const guint32 array_outputs[] = -{ - 0xc22b7dc3, - 0xfdecb8ae, - 0xb4af0738, - 0x516bc6e1, - 0x7e372e91, - 0x2d38ff80, - 0x6096494a, - 0xd162d5a8, - 0x3c0aaa0d, - 0x10e736ae -}; - -static void -test_rand (void) -{ - guint n; - guint ones; - double proportion; - GRand *rand; - GRand *copy; - - rand = g_rand_new_with_seed (first_numbers[0]); - - for (n = 1; n < G_N_ELEMENTS (first_numbers); n++) - g_assert (first_numbers[n] == g_rand_int (rand)); - - g_rand_set_seed (rand, 2); - g_rand_set_seed_array (rand, seed_array, G_N_ELEMENTS (seed_array)); - - for (n = 0; n < G_N_ELEMENTS (array_outputs); n++) - g_assert (array_outputs[n] == g_rand_int (rand)); - - copy = g_rand_copy (rand); - for (n = 0; n < 100; n++) - g_assert (g_rand_int (copy) == g_rand_int (rand)); - - for (n = 1; n < 100000; n++) - { - gint32 i; - gdouble d; - gboolean b; - - i = g_rand_int_range (rand, 8,16); - g_assert (i >= 8 && i < 16); - - i = g_random_int_range (8,16); - g_assert (i >= 8 && i < 16); - - d = g_rand_double (rand); - g_assert (d >= 0 && d < 1); - - d = g_random_double (); - g_assert (d >= 0 && d < 1); - - d = g_rand_double_range (rand, -8, 32); - g_assert (d >= -8 && d < 32); - - d = g_random_double_range (-8, 32); - g_assert (d >= -8 && d < 32); - - b = g_random_boolean (); - g_assert (b == TRUE || b == FALSE); - - b = g_rand_boolean (rand); - g_assert (b == TRUE || b == FALSE); - } - - /* Statistical sanity check, count the number of ones - * when getting random numbers in range [0,3) and see - * that it must be semi-close to 0.25 with a VERY large - * probability */ - ones = 0; - for (n = 1; n < 100000; n++) - { - if (g_random_int_range (0, 4) == 1) - ones ++; - } - - proportion = (double)ones / (double)100000; - /* 0.025 is overkill, but should suffice to test for some unreasonability */ - g_assert (ABS (proportion - 0.25) < 0.025); - - g_rand_free (rand); - g_rand_free (copy); -} - -int -main (int argc, - char *argv[]) -{ - g_test_init (&argc, &argv, NULL); - - g_test_add_func ("/rand/test-rand", test_rand); - - return g_test_run(); -} diff --git a/glib/tests/strfuncs.c b/glib/tests/strfuncs.c deleted file mode 100644 index 8928ae658..000000000 --- a/glib/tests/strfuncs.c +++ /dev/null @@ -1,1241 +0,0 @@ -/* Unit tests for gstrfuncs - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * This work is provided "as is"; redistribution and modification - * in whole or in part, in any medium, physical or electronic is - * permitted without restriction. - * - * This work 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. - */ - -#include <ctype.h> -#include <errno.h> -#include <locale.h> -#include <math.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "glib.h" - -#define GLIB_TEST_STRING "el dorado " - -#define FOR_ALL_CTYPE(macro) \ - macro(isalnum) \ - macro(isalpha) \ - macro(iscntrl) \ - macro(isdigit) \ - macro(isgraph) \ - macro(islower) \ - macro(isprint) \ - macro(ispunct) \ - macro(isspace) \ - macro(isupper) \ - macro(isxdigit) - -#define DEFINE_CALL_CTYPE(function) \ - static int \ - call_##function (int c) \ - { \ - return function (c); \ - } - -#define DEFINE_CALL_G_ASCII_CTYPE(function) \ - static gboolean \ - call_g_ascii_##function (gchar c) \ - { \ - return g_ascii_##function (c); \ - } - -FOR_ALL_CTYPE (DEFINE_CALL_CTYPE) -FOR_ALL_CTYPE (DEFINE_CALL_G_ASCII_CTYPE) - -static void -test_is_function (const char *name, - gboolean (* ascii_function) (gchar), - int (* c_library_function) (int), - gboolean (* unicode_function) (gunichar)) -{ - int c; - - for (c = 0; c <= 0x7F; c++) - { - gboolean ascii_result = ascii_function ((gchar)c); - gboolean c_library_result = c_library_function (c) != 0; - gboolean unicode_result = unicode_function ((gunichar) c); - if (ascii_result != c_library_result && c != '\v') - { - g_error ("g_ascii_%s returned %d and %s returned %d for 0x%X", - name, ascii_result, name, c_library_result, c); - } - if (ascii_result != unicode_result) - { - g_error ("g_ascii_%s returned %d and g_unichar_%s returned %d for 0x%X", - name, ascii_result, name, unicode_result, c); - } - } - for (c = 0x80; c <= 0xFF; c++) - { - gboolean ascii_result = ascii_function ((gchar)c); - if (ascii_result) - { - g_error ("g_ascii_%s returned TRUE for 0x%X", name, c); - } - } -} - -static void -test_to_function (const char *name, - gchar (* ascii_function) (gchar), - int (* c_library_function) (int), - gunichar (* unicode_function) (gunichar)) -{ - int c; - - for (c = 0; c <= 0x7F; c++) - { - int ascii_result = (guchar) ascii_function ((gchar) c); - int c_library_result = c_library_function (c); - int unicode_result = unicode_function ((gunichar) c); - if (ascii_result != c_library_result) - { - g_error ("g_ascii_%s returned 0x%X and %s returned 0x%X for 0x%X", - name, ascii_result, name, c_library_result, c); - } - if (ascii_result != unicode_result) - { - g_error ("g_ascii_%s returned 0x%X and g_unichar_%s returned 0x%X for 0x%X", - name, ascii_result, name, unicode_result, c); - } - } - for (c = 0x80; c <= 0xFF; c++) - { - int ascii_result = (guchar) ascii_function ((gchar) c); - if (ascii_result != c) - { - g_error ("g_ascii_%s returned 0x%X for 0x%X", - name, ascii_result, c); - } - } -} - -static void -test_digit_function (const char *name, - int (* ascii_function) (gchar), - int (* unicode_function) (gunichar)) -{ - int c; - - for (c = 0; c <= 0x7F; c++) - { - int ascii_result = ascii_function ((gchar) c); - int unicode_result = unicode_function ((gunichar) c); - if (ascii_result != unicode_result) - { - g_error ("g_ascii_%s_value returned %d and g_unichar_%s_value returned %d for 0x%X", - name, ascii_result, name, unicode_result, c); - } - } - for (c = 0x80; c <= 0xFF; c++) - { - int ascii_result = ascii_function ((gchar) c); - if (ascii_result != -1) - { - g_error ("g_ascii_%s_value returned %d for 0x%X", - name, ascii_result, c); - } - } -} - -static void -test_is_to_digit (void) -{ - #define TEST_IS(name) test_is_function (#name, call_g_ascii_##name, call_##name, g_unichar_##name); - - FOR_ALL_CTYPE(TEST_IS) - - #undef TEST_IS - - #define TEST_TO(name) test_to_function (#name, g_ascii_##name, name, g_unichar_##name) - - TEST_TO (tolower); - TEST_TO (toupper); - - #undef TEST_TO - - #define TEST_DIGIT(name) test_digit_function (#name, g_ascii_##name##_value, g_unichar_##name##_value) - - TEST_DIGIT (digit); - TEST_DIGIT (xdigit); - - #undef TEST_DIGIT -} - -static void -test_strdup (void) -{ - gchar *str; - - str = g_strdup (NULL); - g_assert (str == NULL); - - str = g_strdup (GLIB_TEST_STRING); - g_assert (str != NULL); - g_assert_cmpstr (str, ==, GLIB_TEST_STRING); - g_free (str); -} - -static void -test_strndup (void) -{ - gchar *str; - - str = g_strndup (NULL, 3); - g_assert (str == NULL); - - str = g_strndup ("aaaa", 5); - g_assert (str != NULL); - g_assert_cmpstr (str, ==, "aaaa"); - g_free (str); - - str = g_strndup ("aaaa", 2); - g_assert (str != NULL); - g_assert_cmpstr (str, ==, "aa"); - g_free (str); -} - -static void -test_strdup_printf (void) -{ - gchar *str; - - str = g_strdup_printf ("%05d %-5s", 21, "test"); - g_assert (str != NULL); - g_assert_cmpstr (str, ==, "00021 test "); - g_free (str); -} - -static void -test_strdupv (void) -{ - gchar *vec[] = { "Foo", "Bar", NULL }; - gchar **copy; - - copy = g_strdupv (NULL); - g_assert (copy == NULL); - - copy = g_strdupv (vec); - g_assert (copy != NULL); - g_assert_cmpstr (copy[0], ==, "Foo"); - g_assert_cmpstr (copy[1], ==, "Bar"); - g_assert (copy[2] == NULL); - g_strfreev (copy); -} - -static void -test_strnfill (void) -{ - gchar *str; - - str = g_strnfill (0, 'a'); - g_assert (str != NULL); - g_assert (*str == '\0'); - g_free (str); - - str = g_strnfill (5, 'a'); - g_assert (str != NULL); - g_assert_cmpstr (str, ==, "aaaaa"); - g_free (str); -} - -static void -test_strconcat (void) -{ - gchar *str; - - str = g_strconcat (GLIB_TEST_STRING, NULL); - g_assert (str != NULL); - g_assert_cmpstr (str, ==, GLIB_TEST_STRING); - g_free (str); - - str = g_strconcat (GLIB_TEST_STRING, - GLIB_TEST_STRING, - GLIB_TEST_STRING, - NULL); - g_assert (str != NULL); - g_assert_cmpstr (str, ==, GLIB_TEST_STRING GLIB_TEST_STRING GLIB_TEST_STRING); - g_free (str); -} - -static void -test_strjoin (void) -{ - gchar *str; - - str = g_strjoin (NULL, NULL); - g_assert (str != NULL); - g_assert (*str == '\0'); - g_free (str); - - str = g_strjoin (":", NULL); - g_assert (str != NULL); - g_assert (*str == '\0'); - g_free (str); - - str = g_strjoin (NULL, GLIB_TEST_STRING, NULL); - g_assert (str != NULL); - g_assert_cmpstr (str, ==, GLIB_TEST_STRING); - g_free (str); - - str = g_strjoin (NULL, - GLIB_TEST_STRING, - GLIB_TEST_STRING, - GLIB_TEST_STRING, - NULL); - g_assert (str != NULL); - g_assert_cmpstr (str, ==, GLIB_TEST_STRING GLIB_TEST_STRING GLIB_TEST_STRING); - g_free (str); - - str = g_strjoin (":", - GLIB_TEST_STRING, - GLIB_TEST_STRING, - GLIB_TEST_STRING, - NULL); - g_assert (str != NULL); - g_assert_cmpstr (str, ==, GLIB_TEST_STRING ":" GLIB_TEST_STRING ":" GLIB_TEST_STRING); - g_free (str); -} - -static void -test_strcanon (void) -{ - gchar *str; - - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) - { - str = g_strcanon (NULL, "ab", 'y'); - } - g_test_trap_assert_failed (); - - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) - { - str = g_strdup ("abxabxab"); - str = g_strcanon (str, NULL, 'y'); - g_free (str); - } - g_test_trap_assert_failed (); - - str = g_strdup ("abxabxab"); - str = g_strcanon (str, "ab", 'y'); - g_assert (str != NULL); - g_assert_cmpstr (str, ==, "abyabyab"); - g_free (str); -} - -static void -test_strcompress_strescape (void) -{ - gchar *str; - gchar *tmp; - - /* test compress */ - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) - { - str = g_strcompress (NULL); - } - g_test_trap_assert_failed (); - - /* trailing slashes are not allowed */ - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) - { - str = g_strcompress ("abc\\"); - } - g_test_trap_assert_failed (); - - str = g_strcompress ("abc\\\\\\\"\\b\\f\\n\\r\\t\\003\\177\\234\\313\\12345z"); - g_assert (str != NULL); - g_assert_cmpstr (str, ==, "abc\\\"\b\f\n\r\t\003\177\234\313\12345z"); - g_free (str); - - /* test escape */ - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) - { - str = g_strescape (NULL, NULL); - } - g_test_trap_assert_failed (); - - str = g_strescape ("abc\\\"\b\f\n\r\t\003\177\234\313", NULL); - g_assert (str != NULL); - g_assert_cmpstr (str, ==, "abc\\\\\\\"\\b\\f\\n\\r\\t\\003\\177\\234\\313"); - g_free (str); - - str = g_strescape ("abc\\\"\b\f\n\r\t\003\177\234\313", - "\b\f\001\002\003\004"); - g_assert (str != NULL); - g_assert_cmpstr (str, ==, "abc\\\\\\\"\b\f\\n\\r\\t\003\\177\\234\\313"); - g_free (str); - - /* round trip */ - tmp = g_strescape ("abc\\\"\b\f\n\r\t\003\177\234\313", NULL); - str = g_strcompress (tmp); - g_assert (str != NULL); - g_assert_cmpstr (str, ==, "abc\\\"\b\f\n\r\t\003\177\234\313"); - g_free (str); - g_free (tmp); -} - -static void -test_ascii_strcasecmp (void) -{ - gboolean res; - - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) - { - res = g_ascii_strcasecmp ("foo", NULL); - } - g_test_trap_assert_failed (); - - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) - { - res = g_ascii_strcasecmp (NULL, "foo"); - } - g_test_trap_assert_failed (); - - res = g_ascii_strcasecmp ("FroboZZ", "frobozz"); - g_assert_cmpint (res, ==, 0); - - res = g_ascii_strcasecmp ("frobozz", "frobozz"); - g_assert_cmpint (res, ==, 0); - - res = g_ascii_strcasecmp ("frobozz", "FROBOZZ"); - g_assert_cmpint (res, ==, 0); - - res = g_ascii_strcasecmp ("FROBOZZ", "froboz"); - g_assert_cmpint (res, !=, 0); - - res = g_ascii_strcasecmp ("", ""); - g_assert_cmpint (res, ==, 0); - - res = g_ascii_strcasecmp ("!#%&/()", "!#%&/()"); - g_assert_cmpint (res, ==, 0); - - res = g_ascii_strcasecmp ("a", "b"); - g_assert_cmpint (res, <, 0); - - res = g_ascii_strcasecmp ("a", "B"); - g_assert_cmpint (res, <, 0); - - res = g_ascii_strcasecmp ("A", "b"); - g_assert_cmpint (res, <, 0); - - res = g_ascii_strcasecmp ("A", "B"); - g_assert_cmpint (res, <, 0); - - res = g_ascii_strcasecmp ("b", "a"); - g_assert_cmpint (res, >, 0); - - res = g_ascii_strcasecmp ("b", "A"); - g_assert_cmpint (res, >, 0); - - res = g_ascii_strcasecmp ("B", "a"); - g_assert_cmpint (res, >, 0); - - res = g_ascii_strcasecmp ("B", "A"); - g_assert_cmpint (res, >, 0); -} - -static void -do_test_strchug (const gchar *str, const gchar *expected) -{ - gchar *tmp; - gboolean res; - - tmp = g_strdup (str); - - g_strchug (tmp); - res = (strcmp (tmp, expected) == 0); - g_free (tmp); - - g_assert_cmpint (res, ==, TRUE); -} - -static void -test_strchug (void) -{ - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) - { - g_strchug (NULL); - } - g_test_trap_assert_failed (); - - do_test_strchug ("", ""); - do_test_strchug (" ", ""); - do_test_strchug ("\t\r\n ", ""); - do_test_strchug (" a", "a"); - do_test_strchug (" a", "a"); - do_test_strchug ("a a", "a a"); - do_test_strchug (" a a", "a a"); -} - -static void -do_test_strchomp (const gchar *str, const gchar *expected) -{ - gchar *tmp; - gboolean res; - - tmp = g_strdup (str); - - g_strchomp (tmp); - res = (strcmp (tmp, expected) == 0); - g_free (tmp); - - g_assert_cmpint (res, ==, TRUE); -} - -static void -test_strchomp (void) -{ - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) - { - g_strchomp (NULL); - } - g_test_trap_assert_failed (); - - do_test_strchomp ("", ""); - do_test_strchomp (" ", ""); - do_test_strchomp (" \t\r\n", ""); - do_test_strchomp ("a ", "a"); - do_test_strchomp ("a ", "a"); - do_test_strchomp ("a a", "a a"); - do_test_strchomp ("a a ", "a a"); -} - -static void -test_strreverse (void) -{ - gchar *str; - gchar *p; - - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) - { - str = g_strreverse (NULL); - } - g_test_trap_assert_failed (); - - str = p = g_strdup ("abcde"); - str = g_strreverse (str); - g_assert (str != NULL); - g_assert (p == str); - g_assert_cmpstr (str, ==, "edcba"); - g_free (str); -} - -static void -test_strstr (void) -{ - gchar *haystack; - gchar *res; - - haystack = g_strdup ("FooBarFooBarFoo"); - - /* strstr_len */ - res = g_strstr_len (haystack, 6, "xxx"); - g_assert (res == NULL); - - res = g_strstr_len (haystack, 6, "FooBarFooBarFooBar"); - g_assert (res == NULL); - - res = g_strstr_len (haystack, 3, "Bar"); - g_assert (res == NULL); - - res = g_strstr_len (haystack, 6, ""); - g_assert (res == haystack); - g_assert_cmpstr (res, ==, "FooBarFooBarFoo"); - - res = g_strstr_len (haystack, 6, "Bar"); - g_assert (res == haystack + 3); - g_assert_cmpstr (res, ==, "BarFooBarFoo"); - - res = g_strstr_len (haystack, -1, "Bar"); - g_assert (res == haystack + 3); - g_assert_cmpstr (res, ==, "BarFooBarFoo"); - - /* strrstr */ - res = g_strrstr (haystack, "xxx"); - g_assert (res == NULL); - - res = g_strrstr (haystack, "FooBarFooBarFooBar"); - g_assert (res == NULL); - - res = g_strrstr (haystack, ""); - g_assert (res == haystack); - g_assert_cmpstr (res, ==, "FooBarFooBarFoo"); - - res = g_strrstr (haystack, "Bar"); - g_assert (res == haystack + 9); - g_assert_cmpstr (res, ==, "BarFoo"); - - /* strrstr_len */ - res = g_strrstr_len (haystack, 14, "xxx"); - g_assert (res == NULL); - - res = g_strrstr_len (haystack, 14, "FooBarFooBarFooBar"); - g_assert (res == NULL); - - res = g_strrstr_len (haystack, 3, "Bar"); - g_assert (res == NULL); - - res = g_strrstr_len (haystack, 14, "BarFoo"); - g_assert (res == haystack + 3); - g_assert_cmpstr (res, ==, "BarFooBarFoo"); - - res = g_strrstr_len (haystack, 15, "BarFoo"); - g_assert (res == haystack + 9); - g_assert_cmpstr (res, ==, "BarFoo"); - - res = g_strrstr_len (haystack, -1, "BarFoo"); - g_assert (res == haystack + 9); - g_assert_cmpstr (res, ==, "BarFoo"); - - /* test case for strings with \0 in the middle */ - *(haystack + 7) = '\0'; - res = g_strstr_len (haystack, 15, "BarFoo"); - g_assert (res == NULL); - - g_free (haystack); -} - -static void -test_has_prefix (void) -{ - gboolean res; - - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) - { - res = g_str_has_prefix ("foo", NULL); - } - g_test_trap_assert_failed (); - - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) - { - res = g_str_has_prefix (NULL, "foo"); - } - g_test_trap_assert_failed (); - - res = g_str_has_prefix ("foo", "bar"); - g_assert_cmpint (res, ==, FALSE); - - res = g_str_has_prefix ("foo", "foobar"); - g_assert_cmpint (res, ==, FALSE); - - res = g_str_has_prefix ("foobar", "bar"); - g_assert_cmpint (res, ==, FALSE); - - res = g_str_has_prefix ("foobar", "foo"); - g_assert_cmpint (res, ==, TRUE); - - res = g_str_has_prefix ("foo", ""); - g_assert_cmpint (res, ==, TRUE); - - res = g_str_has_prefix ("foo", "foo"); - g_assert_cmpint (res, ==, TRUE); - - res = g_str_has_prefix ("", ""); - g_assert_cmpint (res, ==, TRUE); -} - -static void -test_has_suffix (void) -{ - gboolean res; - - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) - { - res = g_str_has_suffix ("foo", NULL); - } - g_test_trap_assert_failed (); - - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) - { - res = g_str_has_suffix (NULL, "foo"); - } - g_test_trap_assert_failed (); - - res = g_str_has_suffix ("foo", "bar"); - g_assert_cmpint (res, ==, FALSE); - - res = g_str_has_suffix ("bar", "foobar"); - g_assert_cmpint (res, ==, FALSE); - - res = g_str_has_suffix ("foobar", "foo"); - g_assert_cmpint (res, ==, FALSE); - - res = g_str_has_suffix ("foobar", "bar"); - g_assert_cmpint (res, ==, TRUE); - - res = g_str_has_suffix ("foo", ""); - g_assert_cmpint (res, ==, TRUE); - - res = g_str_has_suffix ("foo", "foo"); - g_assert_cmpint (res, ==, TRUE); - - res = g_str_has_suffix ("", ""); - g_assert_cmpint (res, ==, TRUE); -} - -static void -strv_check (gchar **strv, ...) -{ - gboolean ok = TRUE; - gint i = 0; - va_list list; - - va_start (list, strv); - while (ok) - { - const gchar *str = va_arg (list, const char *); - if (strv[i] == NULL) - { - g_assert (str == NULL); - break; - } - if (str == NULL) - { - ok = FALSE; - } - else - { - g_assert_cmpstr (strv[i], ==, str); - } - i++; - } - va_end (list); - - g_strfreev (strv); -} - -static void -test_strsplit (void) -{ - strv_check (g_strsplit ("", ",", 0), NULL); - strv_check (g_strsplit ("x", ",", 0), "x", NULL); - strv_check (g_strsplit ("x,y", ",", 0), "x", "y", NULL); - strv_check (g_strsplit ("x,y,", ",", 0), "x", "y", "", NULL); - strv_check (g_strsplit (",x,y", ",", 0), "", "x", "y", NULL); - strv_check (g_strsplit (",x,y,", ",", 0), "", "x", "y", "", NULL); - strv_check (g_strsplit ("x,y,z", ",", 0), "x", "y", "z", NULL); - strv_check (g_strsplit ("x,y,z,", ",", 0), "x", "y", "z", "", NULL); - strv_check (g_strsplit (",x,y,z", ",", 0), "", "x", "y", "z", NULL); - strv_check (g_strsplit (",x,y,z,", ",", 0), "", "x", "y", "z", "", NULL); - strv_check (g_strsplit (",,x,,y,,z,,", ",", 0), "", "", "x", "", "y", "", "z", "", "", NULL); - strv_check (g_strsplit (",,x,,y,,z,,", ",,", 0), "", "x", "y", "z", "", NULL); - - strv_check (g_strsplit ("", ",", 1), NULL); - strv_check (g_strsplit ("x", ",", 1), "x", NULL); - strv_check (g_strsplit ("x,y", ",", 1), "x,y", NULL); - strv_check (g_strsplit ("x,y,", ",", 1), "x,y,", NULL); - strv_check (g_strsplit (",x,y", ",", 1), ",x,y", NULL); - strv_check (g_strsplit (",x,y,", ",", 1), ",x,y,", NULL); - strv_check (g_strsplit ("x,y,z", ",", 1), "x,y,z", NULL); - strv_check (g_strsplit ("x,y,z,", ",", 1), "x,y,z,", NULL); - strv_check (g_strsplit (",x,y,z", ",", 1), ",x,y,z", NULL); - strv_check (g_strsplit (",x,y,z,", ",", 1), ",x,y,z,", NULL); - strv_check (g_strsplit (",,x,,y,,z,,", ",", 1), ",,x,,y,,z,,", NULL); - strv_check (g_strsplit (",,x,,y,,z,,", ",,", 1), ",,x,,y,,z,,", NULL); - - strv_check (g_strsplit ("", ",", 2), NULL); - strv_check (g_strsplit ("x", ",", 2), "x", NULL); - strv_check (g_strsplit ("x,y", ",", 2), "x", "y", NULL); - strv_check (g_strsplit ("x,y,", ",", 2), "x", "y,", NULL); - strv_check (g_strsplit (",x,y", ",", 2), "", "x,y", NULL); - strv_check (g_strsplit (",x,y,", ",", 2), "", "x,y,", NULL); - strv_check (g_strsplit ("x,y,z", ",", 2), "x", "y,z", NULL); - strv_check (g_strsplit ("x,y,z,", ",", 2), "x", "y,z,", NULL); - strv_check (g_strsplit (",x,y,z", ",", 2), "", "x,y,z", NULL); - strv_check (g_strsplit (",x,y,z,", ",", 2), "", "x,y,z,", NULL); - strv_check (g_strsplit (",,x,,y,,z,,", ",", 2), "", ",x,,y,,z,,", NULL); - strv_check (g_strsplit (",,x,,y,,z,,", ",,", 2), "", "x,,y,,z,,", NULL); -} - -static void -test_strsplit_set (void) -{ - strv_check (g_strsplit_set ("", ",/", 0), NULL); - strv_check (g_strsplit_set (":def/ghi:", ":/", -1), "", "def", "ghi", "", NULL); - strv_check (g_strsplit_set ("abc:def/ghi", ":/", -1), "abc", "def", "ghi", NULL); - strv_check (g_strsplit_set (",;,;,;,;", ",;", -1), "", "", "", "", "", "", "", "", "", NULL); - strv_check (g_strsplit_set (",,abc.def", ".,", -1), "", "", "abc", "def", NULL); - - strv_check (g_strsplit_set (",x.y", ",.", 0), "", "x", "y", NULL); - strv_check (g_strsplit_set (".x,y,", ",.", 0), "", "x", "y", "", NULL); - strv_check (g_strsplit_set ("x,y.z", ",.", 0), "x", "y", "z", NULL); - strv_check (g_strsplit_set ("x.y,z,", ",.", 0), "x", "y", "z", "", NULL); - strv_check (g_strsplit_set (",x.y,z", ",.", 0), "", "x", "y", "z", NULL); - strv_check (g_strsplit_set (",x,y,z,", ",.", 0), "", "x", "y", "z", "", NULL); - strv_check (g_strsplit_set (",.x,,y,;z..", ".,;", 0), "", "", "x", "", "y", "", "z", "", "", NULL); - strv_check (g_strsplit_set (",,x,,y,,z,,", ",,", 0), "", "", "x", "", "y", "", "z", "", "", NULL); - - strv_check (g_strsplit_set ("x,y.z", ",.", 1), "x,y.z", NULL); - strv_check (g_strsplit_set ("x.y,z,", ",.", 1), "x.y,z,", NULL); - strv_check (g_strsplit_set (",x,y,z", ",.", 1), ",x,y,z", NULL); - strv_check (g_strsplit_set (",x,y.z,", ",.", 1), ",x,y.z,", NULL); - strv_check (g_strsplit_set (",,x,.y,,z,,", ",.", 1), ",,x,.y,,z,,", NULL); - strv_check (g_strsplit_set (",.x,,y,,z,,", ",,..", 1), ",.x,,y,,z,,", NULL); - - strv_check (g_strsplit_set ("", ",", 0), NULL); - strv_check (g_strsplit_set ("x", ",", 0), "x", NULL); - strv_check (g_strsplit_set ("x,y", ",", 0), "x", "y", NULL); - strv_check (g_strsplit_set ("x,y,", ",", 0), "x", "y", "", NULL); - strv_check (g_strsplit_set (",x,y", ",", 0), "", "x", "y", NULL); - strv_check (g_strsplit_set (",x,y,", ",", 0), "", "x", "y", "", NULL); - strv_check (g_strsplit_set ("x,y,z", ",", 0), "x", "y", "z", NULL); - strv_check (g_strsplit_set ("x,y,z,", ",", 0), "x", "y", "z", "", NULL); - strv_check (g_strsplit_set (",x,y,z", ",", 0), "", "x", "y", "z", NULL); - strv_check (g_strsplit_set (",x,y,z,", ",", 0), "", "x", "y", "z", "", NULL); - strv_check (g_strsplit_set (",,x,,y,,z,,", ",", 0), "", "", "x", "", "y", "", "z", "", "", NULL); - - strv_check (g_strsplit_set ("", ",", 1), NULL); - strv_check (g_strsplit_set ("x", ",", 1), "x", NULL); - strv_check (g_strsplit_set ("x,y", ",", 1), "x,y", NULL); - strv_check (g_strsplit_set ("x,y,", ",", 1), "x,y,", NULL); - strv_check (g_strsplit_set (",x,y", ",", 1), ",x,y", NULL); - strv_check (g_strsplit_set (",x,y,", ",", 1), ",x,y,", NULL); - strv_check (g_strsplit_set ("x,y,z", ",", 1), "x,y,z", NULL); - strv_check (g_strsplit_set ("x,y,z,", ",", 1), "x,y,z,", NULL); - strv_check (g_strsplit_set (",x,y,z", ",", 1), ",x,y,z", NULL); - strv_check (g_strsplit_set (",x,y,z,", ",", 1), ",x,y,z,", NULL); - strv_check (g_strsplit_set (",,x,,y,,z,,", ",", 1), ",,x,,y,,z,,", NULL); - strv_check (g_strsplit_set (",,x,,y,,z,,", ",,", 1), ",,x,,y,,z,,", NULL); - - strv_check (g_strsplit_set ("", ",", 2), NULL); - strv_check (g_strsplit_set ("x", ",", 2), "x", NULL); - strv_check (g_strsplit_set ("x,y", ",", 2), "x", "y", NULL); - strv_check (g_strsplit_set ("x,y,", ",", 2), "x", "y,", NULL); - strv_check (g_strsplit_set (",x,y", ",", 2), "", "x,y", NULL); - strv_check (g_strsplit_set (",x,y,", ",", 2), "", "x,y,", NULL); - strv_check (g_strsplit_set ("x,y,z", ",", 2), "x", "y,z", NULL); - strv_check (g_strsplit_set ("x,y,z,", ",", 2), "x", "y,z,", NULL); - strv_check (g_strsplit_set (",x,y,z", ",", 2), "", "x,y,z", NULL); - strv_check (g_strsplit_set (",x,y,z,", ",", 2), "", "x,y,z,", NULL); - strv_check (g_strsplit_set (",,x,,y,,z,,", ",", 2), "", ",x,,y,,z,,", NULL); - - strv_check (g_strsplit_set (",,x,.y,..z,,", ",.", 3), "", "", "x,.y,..z,,", NULL); -} - -static void -test_strv_length (void) -{ - guint l; - - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) - { - l = g_strv_length (NULL); - } - g_test_trap_assert_failed (); - - l = g_strv_length (g_strsplit ("1,2,3,4", ",", -1)); - g_assert_cmpuint (l, ==, 4); -} - -static char *locales[] = {"sv_SE", "en_US", "fa_IR", "C", "ru_RU"}; - -void -check_strtod_string (gchar *number, - double res, - gboolean check_end, - gint correct_len) -{ - double d; - gint l; - gchar *dummy; - - /* we try a copy of number, with some free space for malloc before that. - * This is supposed to smash the some wrong pointer calculations. */ - - dummy = g_malloc (100000); - number = g_strdup (number); - g_free (dummy); - - for (l = 0; l < G_N_ELEMENTS (locales); l++) - { - gboolean ok; - gchar *end = "(unset)"; - - setlocale (LC_NUMERIC, locales[l]); - d = g_ascii_strtod (number, &end); - ok = isnan (res) ? isnan (d) : (d == res); - if (!ok) - { - g_error ("g_ascii_strtod on \"%s\" for locale %s failed\n" \ - "expected %f (nan %d) actual %f (nan %d)\n", - number, locales[l], - res, isnan (res), - d, isnan (d)); - } - - ok = (end - number) == (check_end ? correct_len : strlen (number)); - if (!ok) { - if (end == NULL) - g_error ("g_ascii_strtod on \"%s\" for locale %s endptr was NULL\n", - number, locales[l]); - else if (end >= number && end <= number + strlen (number)) - g_error ("g_ascii_strtod on \"%s\" for locale %s endptr was wrong, leftover: \"%s\"\n", - number, locales[l], end); - else - g_error ("g_ascii_strtod on \"%s\" for locale %s endptr was REALLY wrong (number=%p, end=%p)\n", - number, locales[l], number, end); - } - } - - g_free (number); -} - -static void -check_strtod_number (gdouble num, gchar *fmt, gchar *str) -{ - int l; - gchar buf[G_ASCII_DTOSTR_BUF_SIZE]; - - for (l = 0; l < G_N_ELEMENTS (locales); l++) - { - g_ascii_formatd (buf, G_ASCII_DTOSTR_BUF_SIZE, fmt, num); - g_assert_cmpstr (buf, ==, str); - } -} - -static void -test_strtod (void) -{ - gdouble d, our_nan, our_inf; - char buffer[G_ASCII_DTOSTR_BUF_SIZE]; - -#ifdef NAN - our_nan = NAN; -#else - /* Do this before any call to setlocale. */ - our_nan = atof ("NaN"); -#endif - g_assert (isnan (our_nan)); - -#ifdef INFINITY - our_inf = INFINITY; -#else - our_inf = atof ("Infinity"); -#endif - g_assert (our_inf > 1 && our_inf == our_inf / 2); - - check_strtod_string ("123.123", 123.123, FALSE, 0); - check_strtod_string ("123.123e2", 123.123e2, FALSE, 0); - check_strtod_string ("123.123e-2", 123.123e-2, FALSE, 0); - check_strtod_string ("-123.123", -123.123, FALSE, 0); - check_strtod_string ("-123.123e2", -123.123e2, FALSE, 0); - check_strtod_string ("-123.123e-2", -123.123e-2, FALSE, 0); - check_strtod_string ("5.4", 5.4, TRUE, 3); - check_strtod_string ("5.4,5.5", 5.4, TRUE, 3); - check_strtod_string ("5,4", 5.0, TRUE, 1); - /* the following are for #156421 */ - check_strtod_string ("1e1", 1e1, FALSE, 0); - check_strtod_string ("NAN", our_nan, FALSE, 0); - check_strtod_string ("-nan", -our_nan, FALSE, 0); - check_strtod_string ("INF", our_inf, FALSE, 0); - check_strtod_string ("-infinity", -our_inf, FALSE, 0); - check_strtod_string ("-.75,0", -0.75, TRUE, 4); - - d = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0; - g_assert (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL)); - - d = -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0; - g_assert (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL)); - - d = pow (2.0, -1024.1); - g_assert (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL)); - - d = -pow (2.0, -1024.1); - g_assert (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL)); - - /* for #343899 */ - check_strtod_string (" 0.75", 0.75, FALSE, 0); - check_strtod_string (" +0.75", 0.75, FALSE, 0); - check_strtod_string (" -0.75", -0.75, FALSE, 0); - check_strtod_string ("\f0.75", 0.75, FALSE, 0); - check_strtod_string ("\n0.75", 0.75, FALSE, 0); - check_strtod_string ("\r0.75", 0.75, FALSE, 0); - check_strtod_string ("\t0.75", 0.75, FALSE, 0); - -#if 0 - /* g_ascii_isspace() returns FALSE for vertical tab, see #59388 */ - check_strtod_string ("\v0.75", 0.75, FALSE, 0); -#endif - - /* for #343899 */ - check_strtod_number (0.75, "%0.2f", "0.75"); - check_strtod_number (0.75, "%5.2f", " 0.75"); - check_strtod_number (-0.75, "%0.2f", "-0.75"); - check_strtod_number (-0.75, "%5.2f", "-0.75"); - check_strtod_number (1e99, "%.0e", "1e+99"); -} - -static void -check_uint64 (const gchar *str, - const gchar *end, - gint base, - guint64 result, - gint error) -{ - guint64 actual; - gchar *endptr = NULL; - gint err; - - errno = 0; - actual = g_ascii_strtoull (str, &endptr, base); - err = errno; - - g_assert (actual == result); - g_assert_cmpstr (end, ==, endptr); - g_assert (err == error); -} - -static void -check_int64 (const gchar *str, - const gchar *end, - gint base, - gint64 result, - gint error) -{ - gint64 actual; - gchar *endptr = NULL; - gint err; - - errno = 0; - actual = g_ascii_strtoll (str, &endptr, base); - err = errno; - - g_assert (actual == result); - g_assert_cmpstr (end, ==, endptr); - g_assert (err == error); -} - -static void -test_strtoll (void) -{ - check_uint64 ("0", "", 10, 0, 0); - check_uint64 ("+0", "", 10, 0, 0); - check_uint64 ("-0", "", 10, 0, 0); - check_uint64 ("18446744073709551615", "", 10, G_MAXUINT64, 0); - check_uint64 ("18446744073709551616", "", 10, G_MAXUINT64, ERANGE); - check_uint64 ("20xyz", "xyz", 10, 20, 0); - check_uint64 ("-1", "", 10, G_MAXUINT64, 0); - - check_int64 ("0", "", 10, 0, 0); - check_int64 ("9223372036854775807", "", 10, G_MAXINT64, 0); - check_int64 ("9223372036854775808", "", 10, G_MAXINT64, ERANGE); - check_int64 ("-9223372036854775808", "", 10, G_MININT64, 0); - check_int64 ("-9223372036854775809", "", 10, G_MININT64, ERANGE); - check_int64 ("32768", "", 10, 32768, 0); - check_int64 ("-32768", "", 10, -32768, 0); - check_int64 ("001", "", 10, 1, 0); - check_int64 ("-001", "", 10, -1, 0); -} - -static void -test_bounds (void) -{ - GMappedFile *file, *before, *after; - char buffer[4097]; - char *tmp, *tmp2; - char **array; - char *string; - - /* if we allocate the file between two others and then free those - * other two, then hopefully we end up with unmapped memory on either - * side. - */ - before = g_mapped_file_new ("4096-random-bytes", TRUE, NULL); - - /* quick workaround until #549783 can be fixed */ - if (before == NULL) - return; - - file = g_mapped_file_new ("4096-random-bytes", TRUE, NULL); - after = g_mapped_file_new ("4096-random-bytes", TRUE, NULL); - g_mapped_file_free (before); - g_mapped_file_free (after); - - g_assert (file != NULL); - g_assert_cmpint (g_mapped_file_get_length (file), ==, 4096); - string = g_mapped_file_get_contents (file); - - /* ensure they're all non-nul */ - g_assert (memchr (string, '\0', 4096) == NULL); - - /* test set 1: ensure that nothing goes past its maximum length, even in - * light of a missing nul terminator. - * - * we try to test all of the 'n' functions here. - */ - tmp = g_strndup (string, 4096); - g_assert_cmpint (strlen (tmp), ==, 4096); - g_free (tmp); - - /* found no bugs in gnome, i hope :) */ - g_assert (g_strstr_len (string, 4096, "BUGS") == NULL); - g_strstr_len (string, 4096, "B"); - g_strstr_len (string, 4096, "."); - g_strstr_len (string, 4096, ""); - - g_strrstr_len (string, 4096, "BUGS"); - g_strrstr_len (string, 4096, "B"); - g_strrstr_len (string, 4096, "."); - g_strrstr_len (string, 4096, ""); - - g_ascii_strdown (string, 4096); - g_ascii_strdown (string, 4096); - g_ascii_strup (string, 4096); - g_ascii_strup (string, 4096); - - g_ascii_strncasecmp (string, string, 4096); - - tmp = g_markup_escape_text (string, 4096); - g_free (tmp); - - /* test set 2: ensure that nothing reads even one byte past a '\0'. - */ - g_assert_cmpint (string[4095], ==, '\n'); - string[4095] = '\0'; - - tmp = g_strdup (string); - g_assert_cmpint (strlen (tmp), ==, 4095); - g_free (tmp); - - tmp = g_strndup (string, 10000); - g_assert_cmpint (strlen (tmp), ==, 4095); - g_free (tmp); - - g_stpcpy (buffer, string); - g_assert_cmpint (strlen (buffer), ==, 4095); - - g_strstr_len (string, 10000, "BUGS"); - g_strstr_len (string, 10000, "B"); - g_strstr_len (string, 10000, "."); - g_strstr_len (string, 10000, ""); - - g_strrstr (string, "BUGS"); - g_strrstr (string, "B"); - g_strrstr (string, "."); - g_strrstr (string, ""); - - g_strrstr_len (string, 10000, "BUGS"); - g_strrstr_len (string, 10000, "B"); - g_strrstr_len (string, 10000, "."); - g_strrstr_len (string, 10000, ""); - - g_str_has_prefix (string, "this won't do very much..."); - g_str_has_suffix (string, "but maybe this will..."); - g_str_has_suffix (string, "HMMMM."); - g_str_has_suffix (string, "MMMM."); - g_str_has_suffix (string, "M."); - - g_strlcpy (buffer, string, sizeof buffer); - g_assert_cmpint (strlen (buffer), ==, 4095); - g_strlcpy (buffer, string, sizeof buffer); - buffer[0] = '\0'; - g_strlcat (buffer, string, sizeof buffer); - g_assert_cmpint (strlen (buffer), ==, 4095); - - tmp = g_strdup_printf ("<%s>", string); - g_assert_cmpint (strlen (tmp), ==, 4095 + 2); - g_free (tmp); - - g_ascii_strdown (string, -1); - g_ascii_strdown (string, -1); - g_ascii_strup (string, -1); - g_ascii_strup (string, -1); - - g_ascii_strcasecmp (string, string); - g_ascii_strncasecmp (string, string, 10000); - - g_strreverse (string); - g_strreverse (string); - g_strchug (string); - g_strchomp (string); - g_strstrip (string); - g_assert_cmpint (strlen (string), ==, 4095); - - g_strdelimit (string, "M", 'N'); - g_strcanon (string, " N.", ':'); - g_assert_cmpint (strlen (string), ==, 4095); - - array = g_strsplit (string, ".", -1); - tmp = g_strjoinv (".", array); - g_strfreev (array); - - g_assert_cmpint (strlen (tmp), ==, 4095); - g_assert (memcmp (tmp, string, 4095) == 0); - g_free (tmp); - - tmp = g_strconcat (string, string, string, NULL); - g_assert_cmpint (strlen (tmp), ==, 4095 * 3); - g_free (tmp); - - tmp = g_strjoin ("!", string, string, NULL); - g_assert_cmpint (strlen (tmp), ==, 4095 + 1 + 4095); - g_free (tmp); - - tmp = g_markup_escape_text (string, -1); - g_free (tmp); - - tmp = g_markup_printf_escaped ("%s", string); - g_free (tmp); - - tmp = g_strescape (string, NULL); - tmp2 = g_strcompress (tmp); - g_assert_cmpstr (string, ==, tmp2); - g_free (tmp2); - g_free (tmp); - - g_mapped_file_free (file); -} - -int -main (int argc, - char *argv[]) -{ - g_test_init (&argc, &argv, NULL); - - g_test_add_func ("/strfuncs/test-is-to-digit", test_is_to_digit); - g_test_add_func ("/strfuncs/strdup", test_strdup); - g_test_add_func ("/strfuncs/strndup", test_strndup); - g_test_add_func ("/strfuncs/strdup-printf", test_strdup_printf); - g_test_add_func ("/strfuncs/strdupv", test_strdupv); - g_test_add_func ("/strfuncs/strnfill", test_strnfill); - g_test_add_func ("/strfuncs/strconcat", test_strconcat); - g_test_add_func ("/strfuncs/strjoin", test_strjoin); - g_test_add_func ("/strfuncs/strcanon", test_strcanon); - g_test_add_func ("/strfuncs/strcompress-strescape", test_strcompress_strescape); - g_test_add_func ("/strfuncs/ascii-strcasecmp", test_ascii_strcasecmp); - g_test_add_func ("/strfuncs/strchug", test_strchug); - g_test_add_func ("/strfuncs/strchomp", test_strchomp); - g_test_add_func ("/strfuncs/strreverse", test_strreverse); - g_test_add_func ("/strfuncs/strstr", test_strstr); - g_test_add_func ("/strfuncs/has-prefix", test_has_prefix); - g_test_add_func ("/strfuncs/has-suffix", test_has_suffix); - g_test_add_func ("/strfuncs/strsplit", test_strsplit); - g_test_add_func ("/strfuncs/strsplit-set", test_strsplit_set); - g_test_add_func ("/strfuncs/strv-length", test_strv_length); - g_test_add_func ("/strfuncs/strtod", test_strtod); - g_test_add_func ("/strfuncs/strtoull-strtoll", test_strtoll); - g_test_add_func ("/strfuncs/bounds-check", test_bounds); - - return g_test_run(); -} diff --git a/glib/tests/string.c b/glib/tests/string.c deleted file mode 100644 index 3ee03c6d7..000000000 --- a/glib/tests/string.c +++ /dev/null @@ -1,394 +0,0 @@ -/* Unit tests for gstring - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * This work is provided "as is"; redistribution and modification - * in whole or in part, in any medium, physical or electronic is - * permitted without restriction. - * - * This work 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. - */ - -#include <stdio.h> -#include <string.h> -#include "glib.h" - - -static void -test_string_chunks (void) -{ - GStringChunk *string_chunk; - gchar *tmp_string, *tmp_string_2; - gint i; - - string_chunk = g_string_chunk_new (1024); - - for (i = 0; i < 100000; i ++) - { - tmp_string = g_string_chunk_insert (string_chunk, "hi pete"); - g_assert_cmpstr ("hi pete", ==, tmp_string); - } - - tmp_string_2 = g_string_chunk_insert_const (string_chunk, tmp_string); - g_assert (tmp_string_2 != tmp_string); - g_assert_cmpstr (tmp_string_2, ==, tmp_string); - - tmp_string = g_string_chunk_insert_const (string_chunk, tmp_string); - g_assert_cmpstr (tmp_string_2, ==, tmp_string); - - g_string_chunk_free (string_chunk); -} - -static void -test_string_new (void) -{ - GString *string1, *string2; - - string1 = g_string_new ("hi pete!"); - string2 = g_string_new (NULL); - - g_assert (string1 != NULL); - g_assert (string2 != NULL); - g_assert (strlen (string1->str) == string1->len); - g_assert (strlen (string2->str) == string2->len); - g_assert (string2->len == 0); - g_assert_cmpstr ("hi pete!", ==, string1->str); - g_assert_cmpstr ("", ==, string2->str); - - g_string_free (string1, TRUE); - g_string_free (string2, TRUE); -} - -static void -test_string_printf (void) -{ - GString *string; - - string = g_string_new (NULL); - -#ifndef G_OS_WIN32 - /* MSVC and mingw32 use the same run-time C library, which doesn't like - the %10000.10000f format... */ - g_string_printf (string, "%s|%0100d|%s|%0*d|%*.*f|%10000.10000f", - "this pete guy sure is a wuss, like he's the number ", - 1, - " wuss. everyone agrees.\n", - 10, 666, 15, 15, 666.666666666, 666.666666666); -#else - g_string_printf (string, "%s|%0100d|%s|%0*d|%*.*f|%100.100f", - "this pete guy sure is a wuss, like he's the number ", - 1, - " wuss. everyone agrees.\n", - 10, 666, 15, 15, 666.666666666, 666.666666666); -#endif - - g_string_free (string, TRUE); -} - -static void -test_string_assign (void) -{ - GString *string; - - string = g_string_new (NULL); - g_string_assign (string, "boring text"); - g_assert_cmpstr (string->str, ==, "boring text"); - g_string_free (string, TRUE); - - /* assign with string overlap */ - string = g_string_new ("textbeforetextafter"); - g_string_assign (string, string->str + 10); - g_assert_cmpstr (string->str, ==, "textafter"); - g_string_free (string, TRUE); - - string = g_string_new ("boring text"); - g_string_assign (string, string->str); - g_assert_cmpstr (string->str, ==, "boring text"); - g_string_free (string, TRUE); -} - -static void -test_string_append_c (void) -{ - GString *string; - gint i; - - string = g_string_new ("hi pete!"); - - for (i = 0; i < 10000; i++) - g_string_append_c (string, 'a'+(i%26)); - - g_assert((strlen("hi pete!") + 10000) == string->len); - g_assert((strlen("hi pete!") + 10000) == strlen(string->str)); - - g_string_free (string, TRUE); -} - -static void -test_string_append (void) -{ - GString *string; - - /* append */ - string = g_string_new ("firsthalf"); - g_string_append (string, "lasthalf"); - g_assert_cmpstr (string->str, ==, "firsthalflasthalf"); - g_string_free (string, TRUE); - - /* append_len */ - string = g_string_new ("firsthalf"); - g_string_append_len (string, "lasthalfjunkjunk", strlen ("lasthalf")); - g_assert_cmpstr (string->str, ==, "firsthalflasthalf"); - g_string_free (string, TRUE); -} - -static void -test_string_prepend_c (void) -{ - GString *string; - gint i; - - string = g_string_new ("hi pete!"); - - for (i = 0; i < 10000; i++) - g_string_prepend_c (string, 'a'+(i%26)); - - g_assert((strlen("hi pete!") + 10000) == string->len); - g_assert((strlen("hi pete!") + 10000) == strlen(string->str)); - - g_string_free (string, TRUE); -} - -static void -test_string_prepend (void) -{ - GString *string; - - /* prepend */ - string = g_string_new ("lasthalf"); - g_string_prepend (string, "firsthalf"); - g_assert_cmpstr (string->str, ==, "firsthalflasthalf"); - g_string_free (string, TRUE); - - /* prepend_len */ - string = g_string_new ("lasthalf"); - g_string_prepend_len (string, "firsthalfjunkjunk", strlen ("firsthalf")); - g_assert_cmpstr (string->str, ==, "firsthalflasthalf"); - g_string_free (string, TRUE); -} - -static void -test_string_insert (void) -{ - GString *string; - - /* insert */ - string = g_string_new ("firstlast"); - g_string_insert (string, 5, "middle"); - g_assert_cmpstr (string->str, ==, "firstmiddlelast"); - g_string_free (string, TRUE); - - /* insert with pos == end of the string */ - string = g_string_new ("firstmiddle"); - g_string_insert (string, strlen ("firstmiddle"), "last"); - g_assert_cmpstr (string->str, ==, "firstmiddlelast"); - g_string_free (string, TRUE); - - /* insert_len */ - string = g_string_new ("firstlast"); - g_string_insert_len (string, 5, "middlejunkjunk", strlen ("middle")); - g_assert_cmpstr (string->str, ==, "firstmiddlelast"); - g_string_free (string, TRUE); - - /* insert_len with magic -1 pos for append */ - string = g_string_new ("first"); - g_string_insert_len (string, -1, "lastjunkjunk", strlen ("last")); - g_assert_cmpstr (string->str, ==, "firstlast"); - g_string_free (string, TRUE); - - /* insert_len with magic -1 len for strlen-the-string */ - string = g_string_new ("first"); - g_string_insert_len (string, 5, "last", -1); - g_assert_cmpstr (string->str, ==, "firstlast"); - g_string_free (string, TRUE); - - /* insert_len with string overlap */ - string = g_string_new ("textbeforetextafter"); - g_string_insert_len (string, 10, string->str + 8, 5); - g_assert_cmpstr (string->str, ==, "textbeforeretextextafter"); - g_string_free (string, TRUE); -} - -static void -test_string_insert_unichar (void) -{ - GString *string; - - /* insert_unichar with insertion in middle */ - string = g_string_new ("firsthalf"); - g_string_insert_unichar (string, 5, 0x0041); - g_assert_cmpstr (string->str, ==, "first\x41half"); - g_string_free (string, TRUE); - - string = g_string_new ("firsthalf"); - g_string_insert_unichar (string, 5, 0x0298); - g_assert_cmpstr (string->str, ==, "first\xCA\x98half"); - g_string_free (string, TRUE); - - string = g_string_new ("firsthalf"); - g_string_insert_unichar (string, 5, 0xFFFD); - g_assert_cmpstr (string->str, ==, "first\xEF\xBF\xBDhalf"); - g_string_free (string, TRUE); - - string = g_string_new ("firsthalf"); - g_string_insert_unichar (string, 5, 0x1D100); - g_assert_cmpstr (string->str, ==, "first\xF0\x9D\x84\x80half"); - g_string_free (string, TRUE); - - /* insert_unichar with insertion at end */ - string = g_string_new ("start"); - g_string_insert_unichar (string, -1, 0x0041); - g_assert_cmpstr (string->str, ==, "start\x41"); - g_string_free (string, TRUE); - - string = g_string_new ("start"); - g_string_insert_unichar (string, -1, 0x0298); - g_assert_cmpstr (string->str, ==, "start\xCA\x98"); - g_string_free (string, TRUE); - - string = g_string_new ("start"); - g_string_insert_unichar (string, -1, 0xFFFD); - g_assert_cmpstr (string->str, ==, "start\xEF\xBF\xBD"); - g_string_free (string, TRUE); - - string = g_string_new ("start"); - g_string_insert_unichar (string, -1, 0x1D100); - g_assert_cmpstr (string->str, ==, "start\xF0\x9D\x84\x80"); - g_string_free (string, TRUE); -} - -static void -test_string_equal (void) -{ - GString *string1, *string2; - - string1 = g_string_new ("test"); - string2 = g_string_new ("te"); - g_assert (!g_string_equal(string1, string2)); - g_string_append (string2, "st"); - g_assert (g_string_equal(string1, string2)); - g_string_free (string1, TRUE); - g_string_free (string2, TRUE); -} - -static void -test_string_truncate (void) -{ - GString *string; - - string = g_string_new ("testing"); - - g_string_truncate (string, 1000); - g_assert (string->len == strlen("testing")); - g_assert_cmpstr (string->str, ==, "testing"); - - g_string_truncate (string, 4); - g_assert (string->len == 4); - g_assert_cmpstr (string->str, ==, "test"); - - g_string_truncate (string, 0); - g_assert (string->len == 0); - g_assert_cmpstr (string->str, ==, ""); - - g_string_free (string, TRUE); -} - -static void -test_string_overwrite (void) -{ - GString *string; - - /* overwriting functions */ - string = g_string_new ("testing"); - - g_string_overwrite (string, 4, " and expand"); - g_assert (15 == string->len); - g_assert ('\0' == string->str[15]); - g_assert (g_str_equal ("test and expand", string->str)); - - g_string_overwrite (string, 5, "NOT-"); - g_assert (15 == string->len); - g_assert ('\0' == string->str[15]); - g_assert (g_str_equal ("test NOT-expand", string->str)); - - g_string_overwrite_len (string, 9, "blablabla", 6); - g_assert (15 == string->len); - g_assert ('\0' == string->str[15]); - g_assert (g_str_equal ("test NOT-blabla", string->str)); - - g_string_free (string, TRUE); -} - -static void -test_string_nul_handling (void) -{ - GString *string1, *string2; - - /* Check handling of embedded ASCII 0 (NUL) characters in GString. */ - string1 = g_string_new ("fiddle"); - string2 = g_string_new ("fiddle"); - g_assert (g_string_equal (string1, string2)); - g_string_append_c (string1, '\0'); - g_assert (!g_string_equal (string1, string2)); - g_string_append_c (string2, '\0'); - g_assert (g_string_equal (string1, string2)); - g_string_append_c (string1, 'x'); - g_string_append_c (string2, 'y'); - g_assert (!g_string_equal (string1, string2)); - g_assert (string1->len == 8); - g_string_append (string1, "yzzy"); - g_assert (string1->len == 12); - g_assert (memcmp (string1->str, "fiddle\0xyzzy", 13) == 0); - g_string_insert (string1, 1, "QED"); - g_assert (memcmp (string1->str, "fQEDiddle\0xyzzy", 16) == 0); - g_string_printf (string1, "fiddle%cxyzzy", '\0'); - g_assert (string1->len == 12); - g_assert (memcmp (string1->str, "fiddle\0xyzzy", 13) == 0); - - g_string_free (string1, TRUE); - g_string_free (string2, TRUE); -} - -int -main (int argc, - char *argv[]) -{ - g_test_init (&argc, &argv, NULL); - - g_test_add_func ("/string/test-string-chunks", test_string_chunks); - g_test_add_func ("/string/test-string-new", test_string_new); - g_test_add_func ("/string/test-string-printf", test_string_printf); - g_test_add_func ("/string/test-string-assign", test_string_assign); - g_test_add_func ("/string/test-string-append-c", test_string_append_c); - g_test_add_func ("/string/test-string-append", test_string_append); - g_test_add_func ("/string/test-string-prepend-c", test_string_prepend_c); - g_test_add_func ("/string/test-string-prepend", test_string_prepend); - g_test_add_func ("/string/test-string-insert", test_string_insert); - g_test_add_func ("/string/test-string-insert-unichar", test_string_insert_unichar); - g_test_add_func ("/string/test-string-equal", test_string_equal); - g_test_add_func ("/string/test-string-truncate", test_string_truncate); - g_test_add_func ("/string/test-string-overwrite", test_string_overwrite); - g_test_add_func ("/string/test-string-nul-handling", test_string_nul_handling); - - return g_test_run(); -} diff --git a/glib/tests/testing.c b/glib/tests/testing.c deleted file mode 100644 index cfbf8d4d2..000000000 --- a/glib/tests/testing.c +++ /dev/null @@ -1,214 +0,0 @@ -/* GLib testing framework examples and tests - * Copyright (C) 2007 Imendio AB - * Authors: Tim Janik - * - * This work is provided "as is"; redistribution and modification - * in whole or in part, in any medium, physical or electronic is - * permitted without restriction. - * - * This work 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. - */ - -#include <glib.h> - -#include <stdlib.h> - -/* test assertion variants */ -static void -test_assertions (void) -{ - gchar *fuu; - g_assert_cmpint (1, >, 0); - g_assert_cmphex (2, ==, 2); - g_assert_cmpfloat (3.3, !=, 7); - g_assert_cmpfloat (7, <=, 3 + 4); - g_assert (TRUE); - g_assert_cmpstr ("foo", !=, "faa"); - fuu = g_strdup_printf ("f%s", "uu"); - g_test_queue_free (fuu); - g_assert_cmpstr ("foo", !=, fuu); - g_assert_cmpstr ("fuu", ==, fuu); - g_assert_cmpstr (NULL, <, ""); - g_assert_cmpstr (NULL, ==, NULL); - g_assert_cmpstr ("", >, NULL); - g_assert_cmpstr ("foo", <, "fzz"); - g_assert_cmpstr ("fzz", >, "faa"); - g_assert_cmpstr ("fzz", ==, "fzz"); -} - -/* test g_test_timer* API */ -static void -test_timer (void) -{ - double ttime; - g_test_timer_start(); - g_assert_cmpfloat (g_test_timer_last(), ==, 0); - g_usleep (25 * 1000); - ttime = g_test_timer_elapsed(); - g_assert_cmpfloat (ttime, >, 0); - g_assert_cmpfloat (g_test_timer_last(), ==, ttime); - g_test_minimized_result (ttime, "timer-test-time: %fsec", ttime); - g_test_maximized_result (5, "bogus-quantity: %ddummies", 5); /* simple API test */ -} - -/* fork out for a failing test */ -static void -test_fork_fail (void) -{ - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) - { - g_assert_not_reached(); - } - g_test_trap_assert_failed(); - g_test_trap_assert_stderr ("*ERROR*test_fork_fail*should not be reached*"); -} - -/* fork out to assert stdout and stderr patterns */ -static void -test_fork_patterns (void) -{ - if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR)) - { - g_print ("some stdout text: somagic17\n"); - g_printerr ("some stderr text: semagic43\n"); - exit (0); - } - g_test_trap_assert_passed(); - g_test_trap_assert_stdout ("*somagic17*"); - g_test_trap_assert_stderr ("*semagic43*"); -} - -/* fork out for a timeout test */ -static void -test_fork_timeout (void) -{ - /* allow child to run for only a fraction of a second */ - if (g_test_trap_fork (0.11 * 1000000, 0)) - { - /* loop and sleep forever */ - while (TRUE) - g_usleep (1000 * 1000); - } - g_test_trap_assert_failed(); - g_assert (g_test_trap_reached_timeout()); -} - -/* run a test with fixture setup and teardown */ -typedef struct { - guint seed; - guint prime; - gchar *msg; -} Fixturetest; -static void -fixturetest_setup (Fixturetest *fix, - gconstpointer test_data) -{ - g_assert (test_data == (void*) 0xc0cac01a); - fix->seed = 18; - fix->prime = 19; - fix->msg = g_strdup_printf ("%d", fix->prime); -} -static void -fixturetest_test (Fixturetest *fix, - gconstpointer test_data) -{ - guint prime = g_spaced_primes_closest (fix->seed); - g_assert_cmpint (prime, ==, fix->prime); - prime = g_ascii_strtoull (fix->msg, NULL, 0); - g_assert_cmpint (prime, ==, fix->prime); - g_assert (test_data == (void*) 0xc0cac01a); -} -static void -fixturetest_teardown (Fixturetest *fix, - gconstpointer test_data) -{ - g_assert (test_data == (void*) 0xc0cac01a); - g_free (fix->msg); -} - -static struct { - int bit, vint1, vint2, irange; - long double vdouble, drange; -} shared_rand_state; - -static void -test_rand1 (void) -{ - shared_rand_state.bit = g_test_rand_bit(); - shared_rand_state.vint1 = g_test_rand_int(); - shared_rand_state.vint2 = g_test_rand_int(); - g_assert_cmpint (shared_rand_state.vint1, !=, shared_rand_state.vint2); - shared_rand_state.irange = g_test_rand_int_range (17, 35); - g_assert_cmpint (shared_rand_state.irange, >=, 17); - g_assert_cmpint (shared_rand_state.irange, <=, 35); - shared_rand_state.vdouble = g_test_rand_double(); - shared_rand_state.drange = g_test_rand_double_range (-999, +17); - g_assert_cmpfloat (shared_rand_state.drange, >=, -999); - g_assert_cmpfloat (shared_rand_state.drange, <=, +17); -} - -static void -test_rand2 (void) -{ - /* this test only works if run after test1. - * we do this to check that random number generators - * are reseeded upon fixture setup. - */ - g_assert_cmpint (shared_rand_state.bit, ==, g_test_rand_bit()); - g_assert_cmpint (shared_rand_state.vint1, ==, g_test_rand_int()); - g_assert_cmpint (shared_rand_state.vint2, ==, g_test_rand_int()); - g_assert_cmpint (shared_rand_state.irange, ==, g_test_rand_int_range (17, 35)); - g_assert_cmpfloat (shared_rand_state.vdouble, ==, g_test_rand_double()); - g_assert_cmpfloat (shared_rand_state.drange, ==, g_test_rand_double_range (-999, +17)); -} - -static void -test_data_test (gconstpointer test_data) -{ - g_assert (test_data == (void*) 0xc0c0baba); -} - -static void -test_random_conversions (void) -{ - /* very simple conversion test using random numbers */ - int vint = g_test_rand_int(); - char *err, *str = g_strdup_printf ("%d", vint); - gint64 vint64 = g_ascii_strtoll (str, &err, 10); - g_assert_cmphex (vint, ==, vint64); - g_assert (!err || *err == 0); - g_free (str); -} - -int -main (int argc, - char *argv[]) -{ - g_test_init (&argc, &argv, NULL); - - g_test_add_func ("/random-generator/rand-1", test_rand1); - g_test_add_func ("/random-generator/rand-2", test_rand2); - g_test_add_func ("/random-generator/random-conversions", test_random_conversions); - g_test_add_func ("/misc/assertions", test_assertions); - g_test_add_data_func ("/misc/test-data", (void*) 0xc0c0baba, test_data_test); - g_test_add ("/misc/primetoul", Fixturetest, (void*) 0xc0cac01a, fixturetest_setup, fixturetest_test, fixturetest_teardown); - if (g_test_perf()) - g_test_add_func ("/misc/timer", test_timer); - g_test_add_func ("/forking/fail assertion", test_fork_fail); - g_test_add_func ("/forking/patterns", test_fork_patterns); - if (g_test_slow()) - g_test_add_func ("/forking/timeout", test_fork_timeout); - - return g_test_run(); -} diff --git a/glib/update-pcre/Makefile.am b/glib/update-pcre/Makefile.am deleted file mode 100644 index b7f80c61f..000000000 --- a/glib/update-pcre/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -include $(top_srcdir)/Makefile.decl - -EXTRA_DIST += \ - update.sh \ - Makefile.am-1 \ - Makefile.am-2 \ - digitab.patch \ - memory.patch \ - pcre_ucp_searchfuncs.c \ - pcre_valid_utf8.c diff --git a/glib/update-pcre/Makefile.am-1 b/glib/update-pcre/Makefile.am-1 deleted file mode 100644 index d4255b754..000000000 --- a/glib/update-pcre/Makefile.am-1 +++ /dev/null @@ -1,30 +0,0 @@ -INCLUDES = \ - -DG_LOG_DOMAIN=\"GLib-GRegex\" \ - -DSUPPORT_UCP \ - -DSUPPORT_UTF8 \ - -DNEWLINE=-1 \ - -DMATCH_LIMIT=10000000 \ - -DMATCH_LIMIT_RECURSION=10000000 \ - -DMAX_NAME_SIZE=32 \ - -DMAX_NAME_COUNT=10000 \ - -DMAX_DUPLENGTH=30000 \ - -DLINK_SIZE=2 \ - -DEBCDIC=0 \ - -DPOSIX_MALLOC_THRESHOLD=10 \ - -DPCRE_STATIC \ - -I$(top_srcdir) \ - -I$(srcdir) \ - -I$(top_srcdir)/glib \ - @GLIB_DEBUG_FLAGS@ \ - -DG_DISABLE_DEPRECATED \ - -DGLIB_COMPILATION \ - $(DEPRECATED_FLAGS)\ - $(WARN_CFLAGS) \ - $(PCRE_WARN_CFLAGS) \ - $(DEP_CFLAGS) - -noinst_LTLIBRARIES = libpcre.la - -libpcre_headers = - -libpcre_la_SOURCES = \ diff --git a/glib/update-pcre/Makefile.am-2 b/glib/update-pcre/Makefile.am-2 deleted file mode 100644 index 94d4d3c66..000000000 --- a/glib/update-pcre/Makefile.am-2 +++ /dev/null @@ -1,10 +0,0 @@ - $(libpcre_headers) - -libpcre_la_LIBADD = $(DEP_LIBS) - -libpcre_la_LDFLAGS = -no-undefined - -EXTRA_DIST = \ - COPYING \ - makefile.msc - diff --git a/glib/update-pcre/digitab.patch b/glib/update-pcre/digitab.patch deleted file mode 100644 index a745fbb42..000000000 --- a/glib/update-pcre/digitab.patch +++ /dev/null @@ -1,133 +0,0 @@ ---- pcre_compile.c 2006-10-10 12:00:00.000000000 +0200 -+++ pcre_compile.c 2006-10-10 12:00:00.000000000 +0200 -@@ -246,130 +246,6 @@ static const char *error_texts[] = { - }; - - --/* Table to identify digits and hex digits. This is used when compiling --patterns. Note that the tables in chartables are dependent on the locale, and --may mark arbitrary characters as digits - but the PCRE compiling code expects --to handle only 0-9, a-z, and A-Z as digits when compiling. That is why we have --a private table here. It costs 256 bytes, but it is a lot faster than doing --character value tests (at least in some simple cases I timed), and in some --applications one wants PCRE to compile efficiently as well as match --efficiently. -- --For convenience, we use the same bit definitions as in chartables: -- -- 0x04 decimal digit -- 0x08 hexadecimal digit -- --Then we can use ctype_digit and ctype_xdigit in the code. */ -- --#if !EBCDIC /* This is the "normal" case, for ASCII systems */ --static const unsigned char digitab[] = -- { -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8- 15 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - ' */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ( - / */ -- 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, /* 0 - 7 */ -- 0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, /* 8 - ? */ -- 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* @ - G */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* H - O */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* P - W */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* X - _ */ -- 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* ` - g */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* h - o */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p - w */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* x -127 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */ -- --#else /* This is the "abnormal" case, for EBCDIC systems */ --static const unsigned char digitab[] = -- { -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 0 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8- 15 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 10 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 32- 39 20 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 40- 47 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 48- 55 30 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 56- 63 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - 71 40 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 72- | */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* & - 87 50 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 88- ¬ */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - -103 60 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 104- ? */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 112-119 70 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 120- " */ -- 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* 128- g 80 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* h -143 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144- p 90 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* q -159 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160- x A0 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* y -175 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ^ -183 B0 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ -- 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* { - G C0 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* H -207 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* } - P D0 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Q -223 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* \ - X E0 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Y -239 */ -- 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, /* 0 - 7 F0 */ -- 0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00};/* 8 -255 */ -- --static const unsigned char ebcdic_chartab[] = { /* chartable partial dup */ -- 0x80,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /* 0- 7 */ -- 0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00, /* 8- 15 */ -- 0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /* 16- 23 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ -- 0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /* 32- 39 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 40- 47 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 48- 55 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 56- 63 */ -- 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - 71 */ -- 0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80, /* 72- | */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* & - 87 */ -- 0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00, /* 88- ¬ */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - -103 */ -- 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x80, /* 104- ? */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 112-119 */ -- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 120- " */ -- 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* 128- g */ -- 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* h -143 */ -- 0x00,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* 144- p */ -- 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* q -159 */ -- 0x00,0x00,0x12,0x12,0x12,0x12,0x12,0x12, /* 160- x */ -- 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* y -175 */ -- 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ^ -183 */ -- 0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ -- 0x80,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* { - G */ -- 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* H -207 */ -- 0x00,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* } - P */ -- 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* Q -223 */ -- 0x00,0x00,0x12,0x12,0x12,0x12,0x12,0x12, /* \ - X */ -- 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* Y -239 */ -- 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */ -- 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x00};/* 8 -255 */ --#endif -- -- - /* Definition to allow mutual recursion */ - - static BOOL diff --git a/glib/update-pcre/make_utt.py b/glib/update-pcre/make_utt.py deleted file mode 100644 index 20c720e08..000000000 --- a/glib/update-pcre/make_utt.py +++ /dev/null @@ -1,57 +0,0 @@ -#! /usr/bin/env python - -# Reduce the number of relocations using a single string for the -# keys in the _pcre_utt table. - -import re - -fin = open('pcre_tables.c') -data = fin.read() -fin.close() - -mo = re.search(r'const ucp_type_table _pcre_utt\[] = {', data) -assert mo, '_pcre_utt not found' -before = data[:mo.start()] -table_decl = data[mo.start():mo.end()] -table_start = mo.end() - -mo = re.compile('};').search(data, table_start) -assert mo, 'end of _pcre_utt not found' -after = data[mo.end():] -table_end = mo.start() - -table = data[table_start:table_end].strip() - -rs = '\s*\{\s*"(?P<name>[^"]*)",\s*(?P<type>PT_[A-Z]*),\s*(?P<value>(?:0|ucp_[A-Za-z_]*))\s*},?\s*$' -r = re.compile(rs) - -lines = [] -names = [] -pos = 0 -for line in table.split('\n'): - mo = r.match(line) - assert mo, 'line not recognized' - name, type, value = mo.groups() - lines.append(' { %d, %s, %s }' % (pos, type, value)) - names.append(name) - # +1 for the '\0' - pos += len(name) + 1 - -table = ',\n'.join(lines) - -names = [' "%s\\0"' % n for n in names] -names_string = ' \n'.join(names) + ';' - -data = before + \ - 'const char _pcre_ucp_names[] =\n' + \ - names_string + \ - '\n\n' + \ - table_decl + \ - '\n' + \ - table + \ - '\n};' + \ - after - -fout = open('pcre_tables.c', 'w') -fout.write(data) -fout.close() diff --git a/glib/update-pcre/memory.patch b/glib/update-pcre/memory.patch deleted file mode 100644 index 65b7b9790..000000000 --- a/glib/update-pcre/memory.patch +++ /dev/null @@ -1,87 +0,0 @@ -diff -r 0f4042339eb5 pcre/pcre.h ---- pcre/pcre.h Tue Jul 25 22:39:16 2006 +0200 -+++ pcre/pcre.h Tue Jul 25 22:52:10 2006 +0200 -@@ -233,25 +233,14 @@ typedef struct pcre_callout_block { - /* ------------------------------------------------------------------ */ - } pcre_callout_block; - --/* Indirection for store get and free functions. These can be set to --alternative malloc/free functions if required. Special ones are used in the --non-recursive case for "frames". There is also an optional callout function --that is triggered by the (?) regex item. For Virtual Pascal, these definitions --have to take another form. */ -- --#ifndef VPCOMPAT --PCRE_DATA_SCOPE void *(*pcre_malloc)(size_t); --PCRE_DATA_SCOPE void (*pcre_free)(void *); --PCRE_DATA_SCOPE void *(*pcre_stack_malloc)(size_t); --PCRE_DATA_SCOPE void (*pcre_stack_free)(void *); -+#include "glib.h" -+#include "galias.h" -+ -+#define pcre_malloc g_try_malloc -+#define pcre_free g_free -+#define pcre_stack_malloc g_try_malloc -+ - PCRE_DATA_SCOPE int (*pcre_callout)(pcre_callout_block *); --#else /* VPCOMPAT */ --PCRE_DATA_SCOPE void *pcre_malloc(size_t); --PCRE_DATA_SCOPE void pcre_free(void *); --PCRE_DATA_SCOPE void *pcre_stack_malloc(size_t); --PCRE_DATA_SCOPE void pcre_stack_free(void *); --PCRE_DATA_SCOPE int pcre_callout(pcre_callout_block *); --#endif /* VPCOMPAT */ - - /* Exported PCRE functions */ - -diff -r 0f4042339eb5 pcre/pcre_globals.c ---- pcre/pcre_globals.c Tue Jul 25 22:39:16 2006 +0200 -+++ pcre/pcre_globals.c Tue Jul 25 22:52:10 2006 +0200 -@@ -50,32 +50,9 @@ differently, and global variables are no - #include "pcre_internal.h" - - --#ifndef VPCOMPAT -- --/************************************************************************** --This code used to be here for use when compiling as a C++ library. However, --according to Dair Grant it is not needed: " -- -- Including 'extern "C"' in the declaration generates an "initialized and -- declared `extern'" warning from gcc 4.0.1. Since we include pcre_internal.h, -- which includes pcre.h, which declares these prototypes within an extern "C" {} -- block, we shouldn't need the prefix here. -- --So, from Release 7.0 I have cut this out. -- - #ifdef __cplusplus --extern "C" void *(*pcre_malloc)(size_t) = malloc; --extern "C" void (*pcre_free)(void *) = free; --extern "C" void *(*pcre_stack_malloc)(size_t) = malloc; --extern "C" void (*pcre_stack_free)(void *) = free; - extern "C" int (*pcre_callout)(pcre_callout_block *) = NULL; - #else --**************************************************************************/ -- --void *(*pcre_malloc)(size_t) = malloc; --void (*pcre_free)(void *) = free; --void *(*pcre_stack_malloc)(size_t) = malloc; --void (*pcre_stack_free)(void *) = free; - int (*pcre_callout)(pcre_callout_block *) = NULL; - #endif - -diff -r 0f4042339eb5 pcre/pcre_internal.h ---- pcre/pcre_internal.h Tue Jul 25 22:39:16 2006 +0200 -+++ pcre/pcre_internal.h Tue Jul 25 22:52:10 2006 +0200 -@@ -480,10 +480,7 @@ variable-length repeat, or a anything ot - - /* Miscellaneous definitions */ - --typedef int BOOL; -- --#define FALSE 0 --#define TRUE 1 -+typedef gboolean BOOL; - - /* Escape items that are just an encoding of a particular data value. */ - diff --git a/glib/update-pcre/pcre_ucp_searchfuncs.c b/glib/update-pcre/pcre_ucp_searchfuncs.c deleted file mode 100644 index b95d2794c..000000000 --- a/glib/update-pcre/pcre_ucp_searchfuncs.c +++ /dev/null @@ -1,126 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - ------------------------------------------------------------------------------ -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. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. ------------------------------------------------------------------------------ -*/ - -/* This file has been modified to use glib instead of the internal table - * in ucptable.c -- Marco Barisione */ - -/* This module contains code for searching the table of Unicode character -properties. */ - -#include "pcre_internal.h" - -#include "ucp.h" /* Category definitions */ -#include "ucpinternal.h" /* Internal table details */ - - -/* Table to translate from particular type value to the general value. */ - -static int ucp_gentype[] = { - ucp_C, ucp_C, ucp_C, ucp_C, ucp_C, /* Cc, Cf, Cn, Co, Cs */ - ucp_L, ucp_L, ucp_L, ucp_L, ucp_L, /* Ll, Lu, Lm, Lo, Lt */ - ucp_M, ucp_M, ucp_M, /* Mc, Me, Mn */ - ucp_N, ucp_N, ucp_N, /* Nd, Nl, No */ - ucp_P, ucp_P, ucp_P, ucp_P, ucp_P, /* Pc, Pd, Pe, Pf, Pi */ - ucp_P, ucp_P, /* Ps, Po */ - ucp_S, ucp_S, ucp_S, ucp_S, /* Sc, Sk, Sm, So */ - ucp_Z, ucp_Z, ucp_Z /* Zl, Zp, Zs */ -}; - - - -/************************************************* -* Search table and return type * -*************************************************/ - -/* Three values are returned: the category is ucp_C, ucp_L, etc. The detailed -character type is ucp_Lu, ucp_Nd, etc. The script is ucp_Latin, etc. - -Arguments: - c the character value - type_ptr the detailed character type is returned here - script_ptr the script is returned here - -Returns: the character type category -*/ - -int -_pcre_ucp_findprop(const unsigned int c, int *type_ptr, int *script_ptr) -{ -/* Note that the Unicode types have the same values in glib and in - * PCRE, so ucp_Ll == G_UNICODE_LOWERCASE_LETTER, - * ucp_Zs == G_UNICODE_SPACE_SEPARATOR, and so on. */ -*type_ptr = g_unichar_type(c); -*script_ptr = g_unichar_get_script(c); -return ucp_gentype[*type_ptr]; -} - - - - -/************************************************* -* Search table and return other case * -*************************************************/ - -/* If the given character is a letter, and there is another case for the -letter, return the other case. Otherwise, return -1. - -Arguments: - c the character value - -Returns: the other case or NOTACHAR if none -*/ - -unsigned int -_pcre_ucp_othercase(const unsigned int c) -{ -int other_case = NOTACHAR; - -if (g_unichar_islower(c)) - other_case = g_unichar_toupper(c); -else if (g_unichar_isupper(c)) - other_case = g_unichar_tolower(c); - -if (other_case == c) - other_case = NOTACHAR; - -return other_case; -} - - -/* End of pcre_ucp_searchfuncs.c */ diff --git a/glib/update-pcre/pcre_valid_utf8.c b/glib/update-pcre/pcre_valid_utf8.c deleted file mode 100644 index a5766b454..000000000 --- a/glib/update-pcre/pcre_valid_utf8.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "pcre_internal.h" - -/* - * This function is not needed by GRegex, so print an error and - * return always -1, that is the string is a valid UTF-8 encoded - * string. - */ -int -_pcre_valid_utf8(const uschar *string, int length) -{ -g_warning ("%s: this function should not be called", G_STRLOC); -return -1; -} diff --git a/glib/update-pcre/table-reduction.patch b/glib/update-pcre/table-reduction.patch deleted file mode 100644 index 7cc78192b..000000000 --- a/glib/update-pcre/table-reduction.patch +++ /dev/null @@ -1,269 +0,0 @@ ---- pcre_compile.c 2006-10-10 12:00:00.000000000 +0200 -+++ pcre_compile.c 2006-10-10 12:00:00.000000000 +0200 -@@ -129,10 +129,21 @@ - terminated by a zero length entry. The first three must be alpha, lower, upper, - as this is assumed for handling case independence. */ - --static const char *const posix_names[] = { -- "alpha", "lower", "upper", -- "alnum", "ascii", "blank", "cntrl", "digit", "graph", -- "print", "punct", "space", "word", "xdigit" }; -+static const char posix_names[] = -+ "alpha\0" -+ "lower\0" -+ "upper\0" -+ "alnum\0" -+ "ascii\0" -+ "blank\0" -+ "cntrl\0" -+ "digit\0" -+ "graph\0" -+ "print\0" -+ "punct\0" -+ "space\0" -+ "word\0" -+ "xdigit"; - - static const uschar posix_name_lengths[] = { - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 }; -@@ -173,76 +184,138 @@ - they are documented. Always add a new error instead. Messages marked DEAD below - are no longer used. */ - --static const char *error_texts[] = { -- "no error", -- "\\ at end of pattern", -- "\\c at end of pattern", -- "unrecognized character follows \\", -- "numbers out of order in {} quantifier", -+#define DEAD(s) "\0" -+ -+static const char error_texts[] = -+ "no error\0" -+ "\\ at end of pattern\0" -+ "\\c at end of pattern\0" -+ "unrecognized character follows \\\0" -+ "numbers out of order in {} quantifier\0" - /* 5 */ -- "number too big in {} quantifier", -- "missing terminating ] for character class", -- "invalid escape sequence in character class", -- "range out of order in character class", -- "nothing to repeat", -+ "number too big in {} quantifier\0" -+ "missing terminating ] for character class\0" -+ "invalid escape sequence in character class\0" -+ "range out of order in character class\0" -+ "nothing to repeat\0" - /* 10 */ -- "operand of unlimited repeat could match the empty string", /** DEAD **/ -- "internal error: unexpected repeat", -- "unrecognized character after (?", -- "POSIX named classes are supported only within a class", -- "missing )", -+ DEAD("operand of unlimited repeat could match the empty string") -+ "internal error: unexpected repeat\0" -+ "unrecognized character after (?\0" -+ "POSIX named classes are supported only within a class\0" -+ "missing )\0" - /* 15 */ -- "reference to non-existent subpattern", -- "erroffset passed as NULL", -- "unknown option bit(s) set", -- "missing ) after comment", -- "parentheses nested too deeply", /** DEAD **/ -+ "reference to non-existent subpattern\0" -+ "erroffset passed as NULL\0" -+ "unknown option bit(s) set\0" -+ "missing ) after comment\0" -+ DEAD("parentheses nested too deeply") - /* 20 */ -- "regular expression too large", -- "failed to get memory", -- "unmatched parentheses", -- "internal error: code overflow", -- "unrecognized character after (?<", -+ "regular expression too large\0" -+ "failed to get memory\0" -+ "unmatched parentheses\0" -+ "internal error: code overflow\0" -+ "unrecognized character after (?<\0" - /* 25 */ -- "lookbehind assertion is not fixed length", -- "malformed number or name after (?(", -- "conditional group contains more than two branches", -- "assertion expected after (?(", -- "(?R or (?digits must be followed by )", -+ "lookbehind assertion is not fixed length\0" -+ "malformed number or name after (?(\0" -+ "conditional group contains more than two branches\0" -+ "assertion expected after (?(\0" -+ "(?R or (?digits must be followed by )\0" - /* 30 */ -- "unknown POSIX class name", -- "POSIX collating elements are not supported", -- "this version of PCRE is not compiled with PCRE_UTF8 support", -- "spare error", /** DEAD **/ -- "character value in \\x{...} sequence is too large", -+ "unknown POSIX class name\0" -+ "POSIX collating elements are not supported\0" -+ "this version of PCRE is not compiled with PCRE_UTF8 support\0" -+ DEAD("spare error") -+ "character value in \\x{...} sequence is too large\0" - /* 35 */ -- "invalid condition (?(0)", -- "\\C not allowed in lookbehind assertion", -- "PCRE does not support \\L, \\l, \\N, \\U, or \\u", -- "number after (?C is > 255", -- "closing ) for (?C expected", -+ "invalid condition (?(0)\0" -+ "\\C not allowed in lookbehind assertion\0" -+ "PCRE does not support \\L, \\l, \\N, \\U, or \\u\0" -+ "number after (?C is > 255\0" -+ "closing ) for (?C expected\0" - /* 40 */ -- "recursive call could loop indefinitely", -- "unrecognized character after (?P", -- "syntax error in subpattern name (missing terminator)", -- "two named subpatterns have the same name", -- "invalid UTF-8 string", -+ "recursive call could loop indefinitely\0" -+ "unrecognized character after (?P\0" -+ "syntax error in subpattern name (missing terminator)\0" -+ "two named subpatterns have the same name\0" -+ "invalid UTF-8 string\0" - /* 45 */ -- "support for \\P, \\p, and \\X has not been compiled", -- "malformed \\P or \\p sequence", -- "unknown property name after \\P or \\p", -- "subpattern name is too long (maximum " XSTRING(MAX_NAME_SIZE) " characters)", -- "too many named subpatterns (maximum " XSTRING(MAX_NAME_COUNT) ")", -+ "support for \\P, \\p, and \\X has not been compiled\0" -+ "malformed \\P or \\p sequence\0" -+ "unknown property name after \\P or \\p\0" -+ "subpattern name is too long (maximum " XSTRING(MAX_NAME_SIZE) " characters)\0" -+ "too many named subpatterns (maximum " XSTRING(MAX_NAME_COUNT) ")\0" - /* 50 */ -- "repeated subpattern is too long", -- "octal value is greater than \\377 (not in UTF-8 mode)", -- "internal error: overran compiling workspace", -- "internal error: previously-checked referenced subpattern not found", -- "DEFINE group contains more than one branch", -+ "repeated subpattern is too long\0" -+ "octal value is greater than \\377 (not in UTF-8 mode)\0" -+ "internal error: overran compiling workspace\0" -+ "internal error: previously-checked referenced subpattern not found\0" -+ "DEFINE group contains more than one branch\0" - /* 55 */ -- "repeating a DEFINE group is not allowed", -- "inconsistent NEWLINE options", -- "\\g is not followed by an (optionally braced) non-zero number" -+ "repeating a DEFINE group is not allowed\0" -+ "inconsistent NEWLINE options\0" -+ "\\g is not followed by an (optionally braced) non-zero number"; -+ -+static const int error_texts_offsets[] = { -+ 0, -+ 9, -+ 29, -+ 50, -+ 83, -+ 121, -+ 153, -+ 195, -+ 238, -+ 276, -+ 294, -+ 295, -+ 329, -+ 361, -+ 415, -+ 425, -+ 462, -+ 487, -+ 513, -+ 537, -+ 538, -+ 567, -+ 588, -+ 610, -+ 640, -+ 673, -+ 714, -+ 749, -+ 799, -+ 828, -+ 866, -+ 891, -+ 934, -+ 994, -+ 995, -+ 1044, -+ 1068, -+ 1107, -+ 1151, -+ 1177, -+ 1204, -+ 1243, -+ 1276, -+ 1329, -+ 1370, -+ 1391, -+ 1440, -+ 1468, -+ 1505, -+ 1557, -+ 1600, -+ 1632, -+ 1685, -+ 1729, -+ 1796, -+ 1839, -+ 1879, -+ 1908 - }; - - -@@ -1453,14 +1526,16 @@ - static int - check_posix_name(const uschar *ptr, int len) - { --register int yield = 0; --while (posix_name_lengths[yield] != 0) -- { -- if (len == posix_name_lengths[yield] && -- strncmp((const char *)ptr, posix_names[yield], len) == 0) return yield; -- yield++; -- } --return -1; -+ int offset = 0; -+ int yield = 0; -+ while (posix_name_lengths[yield] != 0) -+ { -+ if (len == posix_name_lengths[yield] && -+ strcmp((const char *)ptr, posix_names + offset) == 0) return yield; -+ offset += posix_name_lengths[yield] + 1; -+ yield++; -+ } -+ return -1; - } - - -@@ -5200,7 +5275,7 @@ - #ifdef SUPPORT_UTF8 - PCRE_UTF8_ERROR_RETURN: - #endif -- *errorptr = error_texts[errorcode]; -+ *errorptr = error_texts + error_texts_offsets[errorcode]; - if (errorcodeptr != NULL) *errorcodeptr = errorcode; - return NULL; - } -@@ -5297,7 +5372,7 @@ - if (code - codestart > length) - { - (pcre_free)(re); -- *errorptr = error_texts[ERR23]; -+ *errorptr = error_texts + error_texts_offsets[ERR23]; - *erroroffset = ptr - (uschar *)pattern; - if (errorcodeptr != NULL) *errorcodeptr = ERR23; - return NULL; diff --git a/glib/update-pcre/ucp.patch b/glib/update-pcre/ucp.patch deleted file mode 100644 index 8abd812e5..000000000 --- a/glib/update-pcre/ucp.patch +++ /dev/null @@ -1,141 +0,0 @@ ---- pcre/ucp.h 2006-07-05 13:28:01.000000000 +0200 -+++ pcre/ucp.h 2006-10-09 16:27:19.000000000 +0200 -@@ -60,72 +60,72 @@ enum { - /* These are the script identifications. */ - - enum { -- ucp_Arabic, -- ucp_Armenian, -- ucp_Bengali, -- ucp_Bopomofo, -- ucp_Braille, -- ucp_Buginese, -- ucp_Buhid, -- ucp_Canadian_Aboriginal, -- ucp_Cherokee, -- ucp_Common, -- ucp_Coptic, -- ucp_Cypriot, -- ucp_Cyrillic, -- ucp_Deseret, -- ucp_Devanagari, -- ucp_Ethiopic, -- ucp_Georgian, -- ucp_Glagolitic, -- ucp_Gothic, -- ucp_Greek, -- ucp_Gujarati, -- ucp_Gurmukhi, -- ucp_Han, -- ucp_Hangul, -- ucp_Hanunoo, -- ucp_Hebrew, -- ucp_Hiragana, -- ucp_Inherited, -- ucp_Kannada, -- ucp_Katakana, -- ucp_Kharoshthi, -- ucp_Khmer, -- ucp_Lao, -- ucp_Latin, -- ucp_Limbu, -- ucp_Linear_B, -- ucp_Malayalam, -- ucp_Mongolian, -- ucp_Myanmar, -- ucp_New_Tai_Lue, -- ucp_Ogham, -- ucp_Old_Italic, -- ucp_Old_Persian, -- ucp_Oriya, -- ucp_Osmanya, -- ucp_Runic, -- ucp_Shavian, -- ucp_Sinhala, -- ucp_Syloti_Nagri, -- ucp_Syriac, -- ucp_Tagalog, -- ucp_Tagbanwa, -- ucp_Tai_Le, -- ucp_Tamil, -- ucp_Telugu, -- ucp_Thaana, -- ucp_Thai, -- ucp_Tibetan, -- ucp_Tifinagh, -- ucp_Ugaritic, -- ucp_Yi, -- ucp_Balinese, /* New for Unicode 5.0.0 */ -- ucp_Cuneiform, /* New for Unicode 5.0.0 */ -- ucp_Nko, /* New for Unicode 5.0.0 */ -- ucp_Phags_Pa, /* New for Unicode 5.0.0 */ -- ucp_Phoenician /* New for Unicode 5.0.0 */ -+ ucp_Arabic = G_UNICODE_SCRIPT_ARABIC, -+ ucp_Armenian = G_UNICODE_SCRIPT_ARMENIAN, -+ ucp_Bengali = G_UNICODE_SCRIPT_BENGALI, -+ ucp_Bopomofo = G_UNICODE_SCRIPT_BOPOMOFO, -+ ucp_Braille = G_UNICODE_SCRIPT_BRAILLE, -+ ucp_Buginese = G_UNICODE_SCRIPT_BUGINESE, -+ ucp_Buhid = G_UNICODE_SCRIPT_BUHID, -+ ucp_Canadian_Aboriginal = G_UNICODE_SCRIPT_CANADIAN_ABORIGINAL, -+ ucp_Cherokee = G_UNICODE_SCRIPT_CHEROKEE, -+ ucp_Common = G_UNICODE_SCRIPT_COMMON, -+ ucp_Coptic = G_UNICODE_SCRIPT_COPTIC, -+ ucp_Cypriot = G_UNICODE_SCRIPT_CYPRIOT, -+ ucp_Cyrillic = G_UNICODE_SCRIPT_CYRILLIC, -+ ucp_Deseret = G_UNICODE_SCRIPT_DESERET, -+ ucp_Devanagari = G_UNICODE_SCRIPT_DEVANAGARI, -+ ucp_Ethiopic = G_UNICODE_SCRIPT_ETHIOPIC, -+ ucp_Georgian = G_UNICODE_SCRIPT_GEORGIAN, -+ ucp_Glagolitic = G_UNICODE_SCRIPT_GLAGOLITIC, -+ ucp_Gothic = G_UNICODE_SCRIPT_GOTHIC, -+ ucp_Greek = G_UNICODE_SCRIPT_GREEK, -+ ucp_Gujarati = G_UNICODE_SCRIPT_GUJARATI, -+ ucp_Gurmukhi = G_UNICODE_SCRIPT_GURMUKHI, -+ ucp_Han = G_UNICODE_SCRIPT_HAN, -+ ucp_Hangul = G_UNICODE_SCRIPT_HANGUL, -+ ucp_Hanunoo = G_UNICODE_SCRIPT_HANUNOO, -+ ucp_Hebrew = G_UNICODE_SCRIPT_HEBREW, -+ ucp_Hiragana = G_UNICODE_SCRIPT_HIRAGANA, -+ ucp_Inherited = G_UNICODE_SCRIPT_INHERITED, -+ ucp_Kannada = G_UNICODE_SCRIPT_KANNADA, -+ ucp_Katakana = G_UNICODE_SCRIPT_KATAKANA, -+ ucp_Kharoshthi = G_UNICODE_SCRIPT_KHAROSHTHI, -+ ucp_Khmer = G_UNICODE_SCRIPT_KHMER, -+ ucp_Lao = G_UNICODE_SCRIPT_LAO, -+ ucp_Latin = G_UNICODE_SCRIPT_LATIN, -+ ucp_Limbu = G_UNICODE_SCRIPT_LIMBU, -+ ucp_Linear_B = G_UNICODE_SCRIPT_LINEAR_B, -+ ucp_Malayalam = G_UNICODE_SCRIPT_MALAYALAM, -+ ucp_Mongolian = G_UNICODE_SCRIPT_MONGOLIAN, -+ ucp_Myanmar = G_UNICODE_SCRIPT_MYANMAR, -+ ucp_New_Tai_Lue = G_UNICODE_SCRIPT_NEW_TAI_LUE, -+ ucp_Ogham = G_UNICODE_SCRIPT_OGHAM, -+ ucp_Old_Italic = G_UNICODE_SCRIPT_OLD_ITALIC, -+ ucp_Old_Persian = G_UNICODE_SCRIPT_OLD_PERSIAN, -+ ucp_Oriya = G_UNICODE_SCRIPT_ORIYA, -+ ucp_Osmanya = G_UNICODE_SCRIPT_OSMANYA, -+ ucp_Runic = G_UNICODE_SCRIPT_RUNIC, -+ ucp_Shavian = G_UNICODE_SCRIPT_SHAVIAN, -+ ucp_Sinhala = G_UNICODE_SCRIPT_SINHALA, -+ ucp_Syloti_Nagri = G_UNICODE_SCRIPT_SYLOTI_NAGRI, -+ ucp_Syriac = G_UNICODE_SCRIPT_SYRIAC, -+ ucp_Tagalog = G_UNICODE_SCRIPT_TAGALOG, -+ ucp_Tagbanwa = G_UNICODE_SCRIPT_TAGBANWA, -+ ucp_Tai_Le = G_UNICODE_SCRIPT_TAI_LE, -+ ucp_Tamil = G_UNICODE_SCRIPT_TAMIL, -+ ucp_Telugu = G_UNICODE_SCRIPT_TELUGU, -+ ucp_Thaana = G_UNICODE_SCRIPT_THAANA, -+ ucp_Thai = G_UNICODE_SCRIPT_THAI, -+ ucp_Tibetan = G_UNICODE_SCRIPT_TIBETAN, -+ ucp_Tifinagh = G_UNICODE_SCRIPT_TIFINAGH, -+ ucp_Ugaritic = G_UNICODE_SCRIPT_UGARITIC, -+ ucp_Yi = G_UNICODE_SCRIPT_YI, -+ ucp_Balinese = G_UNICODE_SCRIPT_BALINESE, /* New for Unicode 5.0.0 */ -+ ucp_Cuneiform = G_UNICODE_SCRIPT_CUNEIFORM, /* New for Unicode 5.0.0 */ -+ ucp_Nko = G_UNICODE_SCRIPT_NKO, /* New for Unicode 5.0.0 */ -+ ucp_Phags_Pa = G_UNICODE_SCRIPT_PHAGS_PA, /* New for Unicode 5.0.0 */ -+ ucp_Phoenician = G_UNICODE_SCRIPT_PHOENICIAN /* New for Unicode 5.0.0 */ - }; - - #endif diff --git a/glib/update-pcre/update.sh b/glib/update-pcre/update.sh deleted file mode 100644 index 960b4d21d..000000000 --- a/glib/update-pcre/update.sh +++ /dev/null @@ -1,159 +0,0 @@ -#! /bin/sh - -IN="../update-pcre" -PCRE=$1 - -if [ "x$PCRE" = x -o "x$PCRE" = x--help -o "x$PCRE" = x-h ]; then - cat >&2 << EOF - -$0 PCRE-DIR - - Updates the local PCRE copy with a different version of the library, - contained in the directory PCRE-DIR. - - This will delete the content of the local pcre directory, copy the - necessary files from PCRE-DIR, and generate other needed files, such - as Makefile.am -EOF - exit -fi - -if [ ! -f gregex.h ]; then - echo "This script should be executed from the directory containing gregex.c." 2> /dev/null - exit 1 -fi - -if [ ! -f $PCRE/Makefile.in -o ! -f $PCRE/pcre_compile.c ]; then - echo "'$PCRE' does not contain a valid PCRE version." 2> /dev/null - exit 1 -fi - - -echo "Deleting old PCRE library" -mv pcre/.svn tmp-pcre-svn -rm -R pcre 2> /dev/null -mkdir pcre -cd pcre - -# pcre_chartables.c is generated by dfatables. -# We do not want to compile and execute dfatables.c every time, because -# this could be a problem (e.g. when cross-compiling), so now generate -# the file and then distribuite it with GRegex. -echo "Generating pcre_chartables.c" -cp -R $PCRE tmp-build -cd tmp-build -./configure --enable-utf8 --enable-unicode-properties --disable-cpp > /dev/null -make pcre_chartables.c > /dev/null -cat > ../pcre_chartables.c << \EOF -/* This file is autogenerated by ../update-pcre/update.sh during - * the update of the local copy of PCRE. - */ -EOF -cat pcre_chartables.c >> ../pcre_chartables.c -cd .. -rm -R tmp-build - -# Compiled C files. -echo "Generating makefiles" -all_files=`awk '/^OBJ = /, /^\\s*$/ \ - { \ - sub("^OBJ = ", ""); \ - sub(".@OBJEXT@[[:blank:]]*\\\\\\\\", ""); \ - sub("\\\\$\\\\(POSIX_OBJ\\\\)", ""); \ - print; \ - }' \ - $PCRE/Makefile.in` - -# Headers. -included_files="pcre.h pcre_internal.h ucp.h ucpinternal.h" - -# Generate Makefile.am. -cat $IN/Makefile.am-1 > Makefile.am -for name in $all_files; do - echo " $name.c \\" >> Makefile.am - if [ $name != pcre_chartables ]; then - # pcre_chartables.c is a generated file. - cp $PCRE/$name.c . - fi -done -for f in $included_files; do - echo " $f \\" >> Makefile.am - cp $PCRE/$f . -done -cat $IN/Makefile.am-2 >> Makefile.am - -# Generate makefile.msc -cat > makefile.msc << EOF -TOP = ..\..\.. -!INCLUDE ..\..\build\win32\make.msc - -INCLUDES = \\ - -I ..\.. \\ - -I .. - -DEFINES = \\ - -DPCRE_STATIC \\ - -DHAVE_CONFIG_H \\ - -DHAVE_LONG_LONG_FORMAT \\ - -DSUPPORT_UCP \\ - -DSUPPORT_UTF8 \\ - -DNEWLINE=-1 \\ - -DMATCH_LIMIT=10000000 \\ - -DMATCH_LIMIT_RECURSION=10000000 \\ - -DMAX_NAME_SIZE=32 \\ - -DMAX_NAME_COUNT=10000 \\ - -DMAX_DUPLENGTH=30000 \\ - -DLINK_SIZE=2 \\ - -DEBCDIC=0 \\ - -DPOSIX_MALLOC_THRESHOLD=10 - -OBJECTS = \\ -` -for f in $all_files; do - echo " $f.obj \\\\" -done -` - -all : pcre.lib - -pcre.lib : \$(OBJECTS) - lib -out:pcre.lib \$(OBJECTS) -EOF - -echo "Patching PCRE" - -# Copy the license. -cp $PCRE/COPYING . - -# Use glib for memory allocation. -patch > /dev/null < $IN/memory.patch - -# Copy the modified version of pcre_valid_utf8.c. -cp $IN/pcre_valid_utf8.c . - -# Copy the modified version of pcre_ucp_searchfuncs.c that uses glib -# for Unicode properties. -cp $IN/pcre_ucp_searchfuncs.c . -patch > /dev/null < $IN/ucp.patch - -# Remove the digitab array in pcre_compile.c. -patch > /dev/null < $IN/digitab.patch -sed -i -e 's/(digitab\[\(.*\)\] & ctype_digit)/g_ascii_isdigit(\1)/' pcre_compile.c -sed -i -e 's/(digitab\[\(.*\)\] & ctype_xdigit)/g_ascii_isxdigit(\1)/' pcre_compile.c - -# Reduce the number of relocations. -python $IN/make_utt.py -patch > /dev/null < $IN/utt.patch -patch > /dev/null < $IN/table-reduction.patch - -# Copy back the old SVN directory. -mv ../tmp-pcre-svn .svn - - -cat << EOF - -Update completed. You now should check that everything is working. -Remember to update the regex syntax doc with the new features -(docs/reference/glib/regex-syntax.sgml) and to run the tests. -EOF - diff --git a/glib/update-pcre/utt.patch b/glib/update-pcre/utt.patch deleted file mode 100644 index 171445f71..000000000 --- a/glib/update-pcre/utt.patch +++ /dev/null @@ -1,30 +0,0 @@ ---- pcre_compile.c 2006-10-10 12:00:00.000000000 +0200 -+++ pcre_compile.c 2006-10-10 12:00:00.000000000 +0200 -@@ -589,7 +589,7 @@ while (bot < top) - while (bot < top) - { - i = (bot + top) >> 1; -- c = strcmp(name, _pcre_utt[i].name); -+ c = strcmp(name, &_pcre_ucp_names[_pcre_utt[i].offset]); - if (c == 0) - { - *dptr = _pcre_utt[i].value; ---- pcre_internal.h 2006-10-10 12:00:00.000000000 +0200 -+++ pcre_internal.h 2006-10-10 12:00:00.000000000 +0200 -@@ -993,7 +993,7 @@ codes. */ - codes. */ - - typedef struct { -- const char *name; -+ pcre_uint16 offset; - pcre_uint16 type; - pcre_uint16 value; - } ucp_type_table; -@@ -1011,6 +1011,7 @@ extern const uschar _pcre_utf8_table4[]; - - extern const int _pcre_utf8_table1_size; - -+extern const char _pcre_ucp_names[]; - extern const ucp_type_table _pcre_utt[]; - extern const int _pcre_utt_size; - diff --git a/glib/win_iconv.c b/glib/win_iconv.c deleted file mode 100644 index ea1924024..000000000 --- a/glib/win_iconv.c +++ /dev/null @@ -1,1956 +0,0 @@ -/*
- * iconv library implemented with Win32 API.
- *
- * This file is placed in the public domain.
- *
- * Maintainer: Yukihiro Nakadaira <yukihiro.nakadaira@gmail.com>
- *
- * If $WINICONV_LIBICONV_DLL environment variable was defined, win_iconv
- * loads the specified DLL dynamically and uses it. If loading the DLL
- * or iconv_open() failed, falls back to internal conversion.
- * $WINICONV_LIBICONV_DLL is a comma separated list. The first loadable
- * DLL is used. The specified DLL should have iconv_open(),
- * iconv_close() and iconv() functions. Or these functions can be
- * libiconv_open(), libiconv_close() and libiconv().
- *
- * Win32 API does not support strict encoding conversion for some
- * codepage. And MLang function drop or replace invalid bytes and does
- * not return useful error status as iconv. This implementation cannot
- * be used for encoding validation purpose.
- */
-
-/* for WC_NO_BEST_FIT_CHARS */
-#ifndef WINVER
-# define WINVER 0x0500
-#endif
-
-#define STRICT
-#include <windows.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-
-#if 0
-# define MAKE_EXE
-# define MAKE_DLL
-# define USE_LIBICONV_DLL
-#endif
-
-#if !defined(DEFAULT_LIBICONV_DLL)
-# define DEFAULT_LIBICONV_DLL ""
-#endif
-
-#define MB_CHAR_MAX 16
-
-#define UNICODE_MODE_BOM_DONE 1
-#define UNICODE_MODE_SWAPPED 2
-
-#define FLAG_USE_BOM_ENDIAN 1
-#define FLAG_TRANSLIT 2 /* //TRANSLIT */
-#define FLAG_IGNORE 4 /* //IGNORE (not implemented) */
-
-#define return_error(code) \
- do { \
- errno = code; \
- return -1; \
- } while (0)
-
-#define xstrlcpy(dst, src, size) \
- do { \
- strncpy(dst, src, size); \
- dst[size - 1] = 0; \
- } while (0)
-
-#define xstrlcpyn(dst, src, srclen, size) \
- xstrlcpy(dst, src, xmin((srclen) + 1, size))
-
-#define xmin(a, b) ((a) < (b) ? (a) : (b))
-#define xmax(a, b) ((a) > (b) ? (a) : (b))
-
-#define STATIC_STRLEN(arr) (sizeof(arr) - 1)
-
-typedef unsigned char uchar;
-typedef unsigned short ushort;
-typedef unsigned int uint;
-
-typedef void* iconv_t;
-
-iconv_t iconv_open(const char *tocode, const char *fromcode);
-int iconv_close(iconv_t cd);
-size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
-
-/* libiconv interface for vim */
-#if defined(MAKE_DLL)
-int
-iconvctl (iconv_t cd, int request, void* argument)
-{
- /* not supported */
- return 0;
-}
-#endif
-
-typedef struct compat_t compat_t;
-typedef struct csconv_t csconv_t;
-typedef struct rec_iconv_t rec_iconv_t;
-
-typedef iconv_t (*f_iconv_open)(const char *tocode, const char *fromcode);
-typedef int (*f_iconv_close)(iconv_t cd);
-typedef size_t (*f_iconv)(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
-typedef int* (*f_errno)(void);
-typedef int (*f_mbtowc)(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
-typedef int (*f_wctomb)(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
-typedef int (*f_mblen)(csconv_t *cv, const uchar *buf, int bufsize);
-typedef int (*f_flush)(csconv_t *cv, uchar *buf, int bufsize);
-
-#define COMPAT_IN 1
-#define COMPAT_OUT 2
-
-/* unicode mapping for compatibility with other conversion table. */
-struct compat_t {
- uint in;
- uint out;
- uint flag;
-};
-
-struct csconv_t {
- int codepage;
- int flags;
- f_mbtowc mbtowc;
- f_wctomb wctomb;
- f_mblen mblen;
- f_flush flush;
- DWORD mode;
- compat_t *compat;
-};
-
-struct rec_iconv_t {
- iconv_t cd;
- f_iconv_close iconv_close;
- f_iconv iconv;
- f_errno _errno;
- csconv_t from;
- csconv_t to;
-#if defined(USE_LIBICONV_DLL)
- HMODULE hlibiconv;
-#endif
-};
-
-static int win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);
-static int win_iconv_close(iconv_t cd);
-static size_t win_iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
-
-static int load_mlang();
-static csconv_t make_csconv(const char *name);
-static int name_to_codepage(const char *name);
-static uint utf16_to_ucs4(const ushort *wbuf);
-static void ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize);
-static int is_unicode(int codepage);
-static int mbtowc_flags(int codepage);
-static int must_use_null_useddefaultchar(int codepage);
-static void check_utf_bom(rec_iconv_t *cd, ushort *wbuf, int *wbufsize);
-static char *strrstr(const char *str, const char *token);
-
-#if defined(USE_LIBICONV_DLL)
-static int libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);
-static PVOID MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size);
-static HMODULE find_imported_module_by_funcname(HMODULE hModule, const char *funcname);
-
-static HMODULE hwiniconv;
-static HMODULE hlastdll; /* keep dll loaded for efficiency (unnecessary?) */
-#endif
-
-static int sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
-static int dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
-static int mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
-static int utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize);
-static int eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize);
-
-static int kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
-static int kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
-static int mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
-static int mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
-static int utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
-static int utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
-static int utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
-static int utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
-static int iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
-static int iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
-static int iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize);
-
-static struct {
- int codepage;
- const char *name;
-} codepage_alias[] = {
- {65001, "CP65001"},
- {65001, "UTF8"},
- {65001, "UTF-8"},
-
- {1200, "CP1200"},
- {1200, "UTF16LE"},
- {1200, "UTF-16LE"},
- {1200, "UCS2LE"},
- {1200, "UCS-2LE"},
-
- {1201, "CP1201"},
- {1201, "UTF16BE"},
- {1201, "UTF-16BE"},
- {1201, "UCS2BE"},
- {1201, "UCS-2BE"},
- {1201, "unicodeFFFE"},
-
- {12000, "CP12000"},
- {12000, "UTF32LE"},
- {12000, "UTF-32LE"},
- {12000, "UCS4LE"},
- {12000, "UCS-4LE"},
-
- {12001, "CP12001"},
- {12001, "UTF32BE"},
- {12001, "UTF-32BE"},
- {12001, "UCS4BE"},
- {12001, "UCS-4BE"},
-
-#ifndef GLIB_COMPILATION
- /*
- * Default is big endian.
- * See rfc2781 4.3 Interpreting text labelled as UTF-16.
- */
- {1201, "UTF16"},
- {1201, "UTF-16"},
- {12001, "UTF32"},
- {12001, "UTF-32"},
- {12001, "UCS-4"},
- {12001, "UCS4"},
-#else
- /* Default is little endian, because the platform is */
- {1200, "UTF16"},
- {1200, "UTF-16"},
- {1200, "UCS2"},
- {1200, "UCS-2"},
- {12000, "UTF32"},
- {12000, "UTF-32"},
- {12000, "UCS4"},
- {12000, "UCS-4"},
-#endif
-
- /* copy from libiconv `iconv -l` */
- /* !IsValidCodePage(367) */
- {20127, "ANSI_X3.4-1968"},
- {20127, "ANSI_X3.4-1986"},
- {20127, "ASCII"},
- {20127, "CP367"},
- {20127, "IBM367"},
- {20127, "ISO-IR-6"},
- {20127, "ISO646-US"},
- {20127, "ISO_646.IRV:1991"},
- {20127, "US"},
- {20127, "US-ASCII"},
- {20127, "CSASCII"},
-
- /* !IsValidCodePage(819) */
- {1252, "CP819"},
- {1252, "IBM819"},
- {28591, "ISO-8859-1"},
- {28591, "ISO-IR-100"},
- {28591, "ISO8859-1"},
- {28591, "ISO_8859-1"},
- {28591, "ISO_8859-1:1987"},
- {28591, "L1"},
- {28591, "LATIN1"},
- {28591, "CSISOLATIN1"},
-
- {1250, "CP1250"},
- {1250, "MS-EE"},
- {1250, "WINDOWS-1250"},
-
- {1251, "CP1251"},
- {1251, "MS-CYRL"},
- {1251, "WINDOWS-1251"},
-
- {1252, "CP1252"},
- {1252, "MS-ANSI"},
- {1252, "WINDOWS-1252"},
-
- {1253, "CP1253"},
- {1253, "MS-GREEK"},
- {1253, "WINDOWS-1253"},
-
- {1254, "CP1254"},
- {1254, "MS-TURK"},
- {1254, "WINDOWS-1254"},
-
- {1255, "CP1255"},
- {1255, "MS-HEBR"},
- {1255, "WINDOWS-1255"},
-
- {1256, "CP1256"},
- {1256, "MS-ARAB"},
- {1256, "WINDOWS-1256"},
-
- {1257, "CP1257"},
- {1257, "WINBALTRIM"},
- {1257, "WINDOWS-1257"},
-
- {1258, "CP1258"},
- {1258, "WINDOWS-1258"},
-
- {850, "850"},
- {850, "CP850"},
- {850, "IBM850"},
- {850, "CSPC850MULTILINGUAL"},
-
- /* !IsValidCodePage(862) */
- {862, "862"},
- {862, "CP862"},
- {862, "IBM862"},
- {862, "CSPC862LATINHEBREW"},
-
- {866, "866"},
- {866, "CP866"},
- {866, "IBM866"},
- {866, "CSIBM866"},
-
- /* !IsValidCodePage(154) */
- {154, "CP154"},
- {154, "CYRILLIC-ASIAN"},
- {154, "PT154"},
- {154, "PTCP154"},
- {154, "CSPTCP154"},
-
- /* !IsValidCodePage(1133) */
- {1133, "CP1133"},
- {1133, "IBM-CP1133"},
-
- {874, "CP874"},
- {874, "WINDOWS-874"},
-
- /* !IsValidCodePage(51932) */
- {51932, "CP51932"},
- {51932, "MS51932"},
- {51932, "WINDOWS-51932"},
- {51932, "EUC-JP"},
-
- {932, "CP932"},
- {932, "MS932"},
- {932, "SHIFFT_JIS"},
- {932, "SHIFFT_JIS-MS"},
- {932, "SJIS"},
- {932, "SJIS-MS"},
- {932, "SJIS-OPEN"},
- {932, "SJIS-WIN"},
- {932, "WINDOWS-31J"},
- {932, "WINDOWS-932"},
- {932, "CSWINDOWS31J"},
-
- {50221, "CP50221"},
- {50221, "ISO-2022-JP"},
- {50221, "ISO-2022-JP-MS"},
- {50221, "ISO2022-JP"},
- {50221, "ISO2022-JP-MS"},
- {50221, "MS50221"},
- {50221, "WINDOWS-50221"},
-
- {936, "CP936"},
- {936, "GBK"},
- {936, "MS936"},
- {936, "WINDOWS-936"},
-
- {950, "CP950"},
- {950, "BIG5"},
-
- {949, "CP949"},
- {949, "UHC"},
- {949, "EUC-KR"},
-
- {1361, "CP1361"},
- {1361, "JOHAB"},
-
- {437, "437"},
- {437, "CP437"},
- {437, "IBM437"},
- {437, "CSPC8CODEPAGE437"},
-
- {737, "CP737"},
-
- {775, "CP775"},
- {775, "IBM775"},
- {775, "CSPC775BALTIC"},
-
- {852, "852"},
- {852, "CP852"},
- {852, "IBM852"},
- {852, "CSPCP852"},
-
- /* !IsValidCodePage(853) */
- {853, "CP853"},
-
- {855, "855"},
- {855, "CP855"},
- {855, "IBM855"},
- {855, "CSIBM855"},
-
- {857, "857"},
- {857, "CP857"},
- {857, "IBM857"},
- {857, "CSIBM857"},
-
- /* !IsValidCodePage(858) */
- {858, "CP858"},
-
- {860, "860"},
- {860, "CP860"},
- {860, "IBM860"},
- {860, "CSIBM860"},
-
- {861, "861"},
- {861, "CP-IS"},
- {861, "CP861"},
- {861, "IBM861"},
- {861, "CSIBM861"},
-
- {863, "863"},
- {863, "CP863"},
- {863, "IBM863"},
- {863, "CSIBM863"},
-
- {864, "CP864"},
- {864, "IBM864"},
- {864, "CSIBM864"},
-
- {865, "865"},
- {865, "CP865"},
- {865, "IBM865"},
- {865, "CSIBM865"},
-
- {869, "869"},
- {869, "CP-GR"},
- {869, "CP869"},
- {869, "IBM869"},
- {869, "CSIBM869"},
-
- /* !IsValidCodePage(1152) */
- {1125, "CP1125"},
-
- /*
- * Code Page Identifiers
- * http://msdn2.microsoft.com/en-us/library/ms776446.aspx
- */
- {37, "IBM037"}, /* IBM EBCDIC US-Canada */
- {437, "IBM437"}, /* OEM United States */
- {500, "IBM500"}, /* IBM EBCDIC International */
- {708, "ASMO-708"}, /* Arabic (ASMO 708) */
- /* 709 Arabic (ASMO-449+, BCON V4) */
- /* 710 Arabic - Transparent Arabic */
- {720, "DOS-720"}, /* Arabic (Transparent ASMO); Arabic (DOS) */
- {737, "ibm737"}, /* OEM Greek (formerly 437G); Greek (DOS) */
- {775, "ibm775"}, /* OEM Baltic; Baltic (DOS) */
- {850, "ibm850"}, /* OEM Multilingual Latin 1; Western European (DOS) */
- {852, "ibm852"}, /* OEM Latin 2; Central European (DOS) */
- {855, "IBM855"}, /* OEM Cyrillic (primarily Russian) */
- {857, "ibm857"}, /* OEM Turkish; Turkish (DOS) */
- {858, "IBM00858"}, /* OEM Multilingual Latin 1 + Euro symbol */
- {860, "IBM860"}, /* OEM Portuguese; Portuguese (DOS) */
- {861, "ibm861"}, /* OEM Icelandic; Icelandic (DOS) */
- {862, "DOS-862"}, /* OEM Hebrew; Hebrew (DOS) */
- {863, "IBM863"}, /* OEM French Canadian; French Canadian (DOS) */
- {864, "IBM864"}, /* OEM Arabic; Arabic (864) */
- {865, "IBM865"}, /* OEM Nordic; Nordic (DOS) */
- {866, "cp866"}, /* OEM Russian; Cyrillic (DOS) */
- {869, "ibm869"}, /* OEM Modern Greek; Greek, Modern (DOS) */
- {870, "IBM870"}, /* IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 */
- {874, "windows-874"}, /* ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows) */
- {875, "cp875"}, /* IBM EBCDIC Greek Modern */
- {932, "shift_jis"}, /* ANSI/OEM Japanese; Japanese (Shift-JIS) */
- {932, "shift-jis"}, /* alternative name for it */
- {936, "gb2312"}, /* ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) */
- {949, "ks_c_5601-1987"}, /* ANSI/OEM Korean (Unified Hangul Code) */
- {950, "big5"}, /* ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) */
- {1026, "IBM1026"}, /* IBM EBCDIC Turkish (Latin 5) */
- {1047, "IBM01047"}, /* IBM EBCDIC Latin 1/Open System */
- {1140, "IBM01140"}, /* IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) */
- {1141, "IBM01141"}, /* IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) */
- {1142, "IBM01142"}, /* IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) */
- {1143, "IBM01143"}, /* IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) */
- {1144, "IBM01144"}, /* IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) */
- {1145, "IBM01145"}, /* IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) */
- {1146, "IBM01146"}, /* IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) */
- {1147, "IBM01147"}, /* IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) */
- {1148, "IBM01148"}, /* IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) */
- {1149, "IBM01149"}, /* IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) */
- {1250, "windows-1250"}, /* ANSI Central European; Central European (Windows) */
- {1251, "windows-1251"}, /* ANSI Cyrillic; Cyrillic (Windows) */
- {1252, "windows-1252"}, /* ANSI Latin 1; Western European (Windows) */
- {1253, "windows-1253"}, /* ANSI Greek; Greek (Windows) */
- {1254, "windows-1254"}, /* ANSI Turkish; Turkish (Windows) */
- {1255, "windows-1255"}, /* ANSI Hebrew; Hebrew (Windows) */
- {1256, "windows-1256"}, /* ANSI Arabic; Arabic (Windows) */
- {1257, "windows-1257"}, /* ANSI Baltic; Baltic (Windows) */
- {1258, "windows-1258"}, /* ANSI/OEM Vietnamese; Vietnamese (Windows) */
- {1361, "Johab"}, /* Korean (Johab) */
- {10000, "macintosh"}, /* MAC Roman; Western European (Mac) */
- {10001, "x-mac-japanese"}, /* Japanese (Mac) */
- {10002, "x-mac-chinesetrad"}, /* MAC Traditional Chinese (Big5); Chinese Traditional (Mac) */
- {10003, "x-mac-korean"}, /* Korean (Mac) */
- {10004, "x-mac-arabic"}, /* Arabic (Mac) */
- {10005, "x-mac-hebrew"}, /* Hebrew (Mac) */
- {10006, "x-mac-greek"}, /* Greek (Mac) */
- {10007, "x-mac-cyrillic"}, /* Cyrillic (Mac) */
- {10008, "x-mac-chinesesimp"}, /* MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac) */
- {10010, "x-mac-romanian"}, /* Romanian (Mac) */
- {10017, "x-mac-ukrainian"}, /* Ukrainian (Mac) */
- {10021, "x-mac-thai"}, /* Thai (Mac) */
- {10029, "x-mac-ce"}, /* MAC Latin 2; Central European (Mac) */
- {10079, "x-mac-icelandic"}, /* Icelandic (Mac) */
- {10081, "x-mac-turkish"}, /* Turkish (Mac) */
- {10082, "x-mac-croatian"}, /* Croatian (Mac) */
- {20000, "x-Chinese_CNS"}, /* CNS Taiwan; Chinese Traditional (CNS) */
- {20001, "x-cp20001"}, /* TCA Taiwan */
- {20002, "x_Chinese-Eten"}, /* Eten Taiwan; Chinese Traditional (Eten) */
- {20003, "x-cp20003"}, /* IBM5550 Taiwan */
- {20004, "x-cp20004"}, /* TeleText Taiwan */
- {20005, "x-cp20005"}, /* Wang Taiwan */
- {20105, "x-IA5"}, /* IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5) */
- {20106, "x-IA5-German"}, /* IA5 German (7-bit) */
- {20107, "x-IA5-Swedish"}, /* IA5 Swedish (7-bit) */
- {20108, "x-IA5-Norwegian"}, /* IA5 Norwegian (7-bit) */
- {20127, "us-ascii"}, /* US-ASCII (7-bit) */
- {20261, "x-cp20261"}, /* T.61 */
- {20269, "x-cp20269"}, /* ISO 6937 Non-Spacing Accent */
- {20273, "IBM273"}, /* IBM EBCDIC Germany */
- {20277, "IBM277"}, /* IBM EBCDIC Denmark-Norway */
- {20278, "IBM278"}, /* IBM EBCDIC Finland-Sweden */
- {20280, "IBM280"}, /* IBM EBCDIC Italy */
- {20284, "IBM284"}, /* IBM EBCDIC Latin America-Spain */
- {20285, "IBM285"}, /* IBM EBCDIC United Kingdom */
- {20290, "IBM290"}, /* IBM EBCDIC Japanese Katakana Extended */
- {20297, "IBM297"}, /* IBM EBCDIC France */
- {20420, "IBM420"}, /* IBM EBCDIC Arabic */
- {20423, "IBM423"}, /* IBM EBCDIC Greek */
- {20424, "IBM424"}, /* IBM EBCDIC Hebrew */
- {20833, "x-EBCDIC-KoreanExtended"}, /* IBM EBCDIC Korean Extended */
- {20838, "IBM-Thai"}, /* IBM EBCDIC Thai */
- {20866, "koi8-r"}, /* Russian (KOI8-R); Cyrillic (KOI8-R) */
- {20871, "IBM871"}, /* IBM EBCDIC Icelandic */
- {20880, "IBM880"}, /* IBM EBCDIC Cyrillic Russian */
- {20905, "IBM905"}, /* IBM EBCDIC Turkish */
- {20924, "IBM00924"}, /* IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) */
- {20932, "EUC-JP"}, /* Japanese (JIS 0208-1990 and 0121-1990) */
- {20936, "x-cp20936"}, /* Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) */
- {20949, "x-cp20949"}, /* Korean Wansung */
- {21025, "cp1025"}, /* IBM EBCDIC Cyrillic Serbian-Bulgarian */
- /* 21027 (deprecated) */
- {21866, "koi8-u"}, /* Ukrainian (KOI8-U); Cyrillic (KOI8-U) */
- {28591, "iso-8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */
- {28591, "iso8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */
- {28592, "iso-8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */
- {28592, "iso8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */
- {28593, "iso-8859-3"}, /* ISO 8859-3 Latin 3 */
- {28593, "iso8859-3"}, /* ISO 8859-3 Latin 3 */
- {28594, "iso-8859-4"}, /* ISO 8859-4 Baltic */
- {28594, "iso8859-4"}, /* ISO 8859-4 Baltic */
- {28595, "iso-8859-5"}, /* ISO 8859-5 Cyrillic */
- {28595, "iso8859-5"}, /* ISO 8859-5 Cyrillic */
- {28596, "iso-8859-6"}, /* ISO 8859-6 Arabic */
- {28596, "iso8859-6"}, /* ISO 8859-6 Arabic */
- {28597, "iso-8859-7"}, /* ISO 8859-7 Greek */
- {28597, "iso8859-7"}, /* ISO 8859-7 Greek */
- {28598, "iso-8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */
- {28598, "iso8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */
- {28599, "iso-8859-9"}, /* ISO 8859-9 Turkish */
- {28599, "iso8859-9"}, /* ISO 8859-9 Turkish */
- {28603, "iso-8859-13"}, /* ISO 8859-13 Estonian */
- {28603, "iso8859-13"}, /* ISO 8859-13 Estonian */
- {28605, "iso-8859-15"}, /* ISO 8859-15 Latin 9 */
- {28605, "iso8859-15"}, /* ISO 8859-15 Latin 9 */
- {29001, "x-Europa"}, /* Europa 3 */
- {38598, "iso-8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */
- {38598, "iso8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */
- {50220, "iso-2022-jp"}, /* ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) */
- {50221, "csISO2022JP"}, /* ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) */
- {50222, "iso-2022-jp"}, /* ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) */
- {50225, "iso-2022-kr"}, /* ISO 2022 Korean */
- {50225, "iso2022-kr"}, /* ISO 2022 Korean */
- {50227, "x-cp50227"}, /* ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022) */
- /* 50229 ISO 2022 Traditional Chinese */
- /* 50930 EBCDIC Japanese (Katakana) Extended */
- /* 50931 EBCDIC US-Canada and Japanese */
- /* 50933 EBCDIC Korean Extended and Korean */
- /* 50935 EBCDIC Simplified Chinese Extended and Simplified Chinese */
- /* 50936 EBCDIC Simplified Chinese */
- /* 50937 EBCDIC US-Canada and Traditional Chinese */
- /* 50939 EBCDIC Japanese (Latin) Extended and Japanese */
- {51932, "euc-jp"}, /* EUC Japanese */
- {51936, "EUC-CN"}, /* EUC Simplified Chinese; Chinese Simplified (EUC) */
- {51949, "euc-kr"}, /* EUC Korean */
- /* 51950 EUC Traditional Chinese */
- {52936, "hz-gb-2312"}, /* HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) */
- {54936, "GB18030"}, /* Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) */
- {57002, "x-iscii-de"}, /* ISCII Devanagari */
- {57003, "x-iscii-be"}, /* ISCII Bengali */
- {57004, "x-iscii-ta"}, /* ISCII Tamil */
- {57005, "x-iscii-te"}, /* ISCII Telugu */
- {57006, "x-iscii-as"}, /* ISCII Assamese */
- {57007, "x-iscii-or"}, /* ISCII Oriya */
- {57008, "x-iscii-ka"}, /* ISCII Kannada */
- {57009, "x-iscii-ma"}, /* ISCII Malayalam */
- {57010, "x-iscii-gu"}, /* ISCII Gujarati */
- {57011, "x-iscii-pa"}, /* ISCII Punjabi */
-
- {0, NULL}
-};
-
-/*
- * SJIS SHIFTJIS table CP932 table
- * ---- --------------------------- --------------------------------
- * 5C U+00A5 YEN SIGN U+005C REVERSE SOLIDUS
- * 7E U+203E OVERLINE U+007E TILDE
- * 815C U+2014 EM DASH U+2015 HORIZONTAL BAR
- * 815F U+005C REVERSE SOLIDUS U+FF3C FULLWIDTH REVERSE SOLIDUS
- * 8160 U+301C WAVE DASH U+FF5E FULLWIDTH TILDE
- * 8161 U+2016 DOUBLE VERTICAL LINE U+2225 PARALLEL TO
- * 817C U+2212 MINUS SIGN U+FF0D FULLWIDTH HYPHEN-MINUS
- * 8191 U+00A2 CENT SIGN U+FFE0 FULLWIDTH CENT SIGN
- * 8192 U+00A3 POUND SIGN U+FFE1 FULLWIDTH POUND SIGN
- * 81CA U+00AC NOT SIGN U+FFE2 FULLWIDTH NOT SIGN
- *
- * EUC-JP and ISO-2022-JP should be compatible with CP932.
- *
- * Kernel and MLang have different Unicode mapping table. Make sure
- * which API is used.
- */
-static compat_t cp932_compat[] = {
- {0x00A5, 0x005C, COMPAT_OUT},
- {0x203E, 0x007E, COMPAT_OUT},
- {0x2014, 0x2015, COMPAT_OUT},
- {0x301C, 0xFF5E, COMPAT_OUT},
- {0x2016, 0x2225, COMPAT_OUT},
- {0x2212, 0xFF0D, COMPAT_OUT},
- {0x00A2, 0xFFE0, COMPAT_OUT},
- {0x00A3, 0xFFE1, COMPAT_OUT},
- {0x00AC, 0xFFE2, COMPAT_OUT},
- {0, 0, 0}
-};
-
-static compat_t cp20932_compat[] = {
- {0x00A5, 0x005C, COMPAT_OUT},
- {0x203E, 0x007E, COMPAT_OUT},
- {0x2014, 0x2015, COMPAT_OUT},
- {0xFF5E, 0x301C, COMPAT_OUT|COMPAT_IN},
- {0x2225, 0x2016, COMPAT_OUT|COMPAT_IN},
- {0xFF0D, 0x2212, COMPAT_OUT|COMPAT_IN},
- {0xFFE0, 0x00A2, COMPAT_OUT|COMPAT_IN},
- {0xFFE1, 0x00A3, COMPAT_OUT|COMPAT_IN},
- {0xFFE2, 0x00AC, COMPAT_OUT|COMPAT_IN},
- {0, 0, 0}
-};
-
-static compat_t *cp51932_compat = cp932_compat;
-
-/* cp20932_compat for kernel. cp932_compat for mlang. */
-static compat_t *cp5022x_compat = cp932_compat;
-
-typedef HRESULT (WINAPI *CONVERTINETSTRING)(
- LPDWORD lpdwMode,
- DWORD dwSrcEncoding,
- DWORD dwDstEncoding,
- LPCSTR lpSrcStr,
- LPINT lpnSrcSize,
- LPBYTE lpDstStr,
- LPINT lpnDstSize
-);
-typedef HRESULT (WINAPI *CONVERTINETMULTIBYTETOUNICODE)(
- LPDWORD lpdwMode,
- DWORD dwSrcEncoding,
- LPCSTR lpSrcStr,
- LPINT lpnMultiCharCount,
- LPWSTR lpDstStr,
- LPINT lpnWideCharCount
-);
-typedef HRESULT (WINAPI *CONVERTINETUNICODETOMULTIBYTE)(
- LPDWORD lpdwMode,
- DWORD dwEncoding,
- LPCWSTR lpSrcStr,
- LPINT lpnWideCharCount,
- LPSTR lpDstStr,
- LPINT lpnMultiCharCount
-);
-typedef HRESULT (WINAPI *ISCONVERTINETSTRINGAVAILABLE)(
- DWORD dwSrcEncoding,
- DWORD dwDstEncoding
-);
-typedef HRESULT (WINAPI *LCIDTORFC1766A)(
- LCID Locale,
- LPSTR pszRfc1766,
- int nChar
-);
-typedef HRESULT (WINAPI *LCIDTORFC1766W)(
- LCID Locale,
- LPWSTR pszRfc1766,
- int nChar
-);
-typedef HRESULT (WINAPI *RFC1766TOLCIDA)(
- LCID *pLocale,
- LPSTR pszRfc1766
-);
-typedef HRESULT (WINAPI *RFC1766TOLCIDW)(
- LCID *pLocale,
- LPWSTR pszRfc1766
-);
-static CONVERTINETSTRING ConvertINetString;
-static CONVERTINETMULTIBYTETOUNICODE ConvertINetMultiByteToUnicode;
-static CONVERTINETUNICODETOMULTIBYTE ConvertINetUnicodeToMultiByte;
-static ISCONVERTINETSTRINGAVAILABLE IsConvertINetStringAvailable;
-static LCIDTORFC1766A LcidToRfc1766A;
-static RFC1766TOLCIDA Rfc1766ToLcidA;
-
-static int
-load_mlang()
-{
- HMODULE h;
- if (ConvertINetString != NULL)
- return TRUE;
- h = LoadLibrary("mlang.dll");
- if (!h)
- return FALSE;
- ConvertINetString = (CONVERTINETSTRING)GetProcAddress(h, "ConvertINetString");
- ConvertINetMultiByteToUnicode = (CONVERTINETMULTIBYTETOUNICODE)GetProcAddress(h, "ConvertINetMultiByteToUnicode");
- ConvertINetUnicodeToMultiByte = (CONVERTINETUNICODETOMULTIBYTE)GetProcAddress(h, "ConvertINetUnicodeToMultiByte");
- IsConvertINetStringAvailable = (ISCONVERTINETSTRINGAVAILABLE)GetProcAddress(h, "IsConvertINetStringAvailable");
- LcidToRfc1766A = (LCIDTORFC1766A)GetProcAddress(h, "LcidToRfc1766A");
- Rfc1766ToLcidA = (RFC1766TOLCIDA)GetProcAddress(h, "Rfc1766ToLcidA");
- return TRUE;
-}
-
-iconv_t
-iconv_open(const char *tocode, const char *fromcode)
-{
- rec_iconv_t *cd;
-
- cd = (rec_iconv_t *)calloc(1, sizeof(rec_iconv_t));
- if (cd == NULL)
- {
- errno = ENOMEM;
- return (iconv_t)(-1);
- }
-
-#if defined(USE_LIBICONV_DLL)
- if (libiconv_iconv_open(cd, tocode, fromcode))
- return (iconv_t)cd;
-#endif
-
- if (win_iconv_open(cd, tocode, fromcode))
- return (iconv_t)cd;
-
- free(cd);
- errno = EINVAL;
- return (iconv_t)(-1);
-}
-
-int
-iconv_close(iconv_t _cd)
-{
- rec_iconv_t *cd = (rec_iconv_t *)_cd;
- int r = cd->iconv_close(cd->cd);
- int e = *(cd->_errno());
-#if defined(USE_LIBICONV_DLL)
- if (cd->hlibiconv != NULL)
- FreeLibrary(cd->hlibiconv);
-#endif
- free(cd);
- errno = e;
- return r;
-}
-
-size_t
-iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
-{
- rec_iconv_t *cd = (rec_iconv_t *)_cd;
- size_t r = cd->iconv(cd->cd, inbuf, inbytesleft, outbuf, outbytesleft);
- errno = *(cd->_errno());
- return r;
-}
-
-static int
-win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode)
-{
- cd->from = make_csconv(fromcode);
- cd->to = make_csconv(tocode);
- if (cd->from.codepage == -1 || cd->to.codepage == -1)
- return FALSE;
- cd->iconv_close = win_iconv_close;
- cd->iconv = win_iconv;
- cd->_errno = _errno;
- cd->cd = (iconv_t)cd;
- return TRUE;
-}
-
-static int
-win_iconv_close(iconv_t cd)
-{
- return 0;
-}
-
-static size_t
-win_iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
-{
- rec_iconv_t *cd = (rec_iconv_t *)_cd;
- ushort wbuf[MB_CHAR_MAX]; /* enough room for one character */
- int insize;
- int outsize;
- int wsize;
- DWORD mode;
- uint wc;
- compat_t *cp;
- int i;
-
- if (inbuf == NULL || *inbuf == NULL)
- {
- if (outbuf != NULL && *outbuf != NULL && cd->to.flush != NULL)
- {
- outsize = cd->to.flush(&cd->to, (uchar *)*outbuf, *outbytesleft);
- if (outsize == -1)
- return (size_t)(-1);
- *outbuf += outsize;
- *outbytesleft -= outsize;
- }
- if (is_unicode(cd->from.codepage) && (cd->from.mode & UNICODE_MODE_SWAPPED))
- cd->from.codepage ^= 1;
- cd->from.mode = 0;
- cd->to.mode = 0;
- return 0;
- }
-
- while (*inbytesleft != 0)
- {
- mode = cd->from.mode;
- wsize = MB_CHAR_MAX;
-
- insize = cd->from.mbtowc(&cd->from, (const uchar *)*inbuf, *inbytesleft, wbuf, &wsize);
- if (insize == -1)
- return (size_t)(-1);
-
- if (is_unicode(cd->from.codepage) && !(cd->from.mode & UNICODE_MODE_BOM_DONE))
- {
- check_utf_bom(cd, wbuf, &wsize);
- cd->from.mode |= UNICODE_MODE_BOM_DONE;
- }
-
- if (wsize == 0)
- {
- *inbuf += insize;
- *inbytesleft -= insize;
- continue;
- }
-
- if (cd->from.compat != NULL)
- {
- wc = utf16_to_ucs4(wbuf);
- cp = cd->from.compat;
- for (i = 0; cp[i].in != 0; ++i)
- {
- if ((cp[i].flag & COMPAT_IN) && cp[i].out == wc)
- {
- ucs4_to_utf16(cp[i].in, wbuf, &wsize);
- break;
- }
- }
- }
-
- if (cd->to.compat != NULL)
- {
- wc = utf16_to_ucs4(wbuf);
- cp = cd->to.compat;
- for (i = 0; cp[i].in != 0; ++i)
- {
- if ((cp[i].flag & COMPAT_OUT) && cp[i].in == wc)
- {
- ucs4_to_utf16(cp[i].out, wbuf, &wsize);
- break;
- }
- }
- }
-
- outsize = cd->to.wctomb(&cd->to, wbuf, wsize, (uchar *)*outbuf, *outbytesleft);
- if (outsize == -1)
- {
- cd->from.mode = mode;
- return (size_t)(-1);
- }
-
- *inbuf += insize;
- *outbuf += outsize;
- *inbytesleft -= insize;
- *outbytesleft -= outsize;
- }
-
- return 0;
-}
-
-static csconv_t
-make_csconv(const char *_name)
-{
- CPINFOEX cpinfoex;
- csconv_t cv;
- int use_compat = TRUE;
- int flag = 0;
- char name[128];
- char *p;
-
- xstrlcpy(name, _name, sizeof(name));
-
- /* check for option "enc_name//opt1//opt2" */
- while ((p = strrstr(name, "//")) != NULL)
- {
- if (_stricmp(p + 2, "nocompat") == 0)
- use_compat = FALSE;
- else if (_stricmp(p + 2, "translit") == 0)
- flag |= FLAG_TRANSLIT;
- else if (_stricmp(p + 2, "ignore") == 0)
- flag |= FLAG_IGNORE;
- *p = 0;
- }
-
- cv.mode = 0;
- cv.flags = flag;
- cv.mblen = NULL;
- cv.flush = NULL;
- cv.compat = NULL;
- cv.codepage = name_to_codepage(name);
- if (cv.codepage == 1200 || cv.codepage == 1201)
- {
- cv.mbtowc = utf16_mbtowc;
- cv.wctomb = utf16_wctomb;
- if (_stricmp(name, "UTF-16") == 0 ||
- _stricmp(name, "UTF16") == 0 ||
- _stricmp(name, "UCS-2") == 0 ||
- _stricmp(name, "UCS2") == 0)
- cv.flags |= FLAG_USE_BOM_ENDIAN;
- }
- else if (cv.codepage == 12000 || cv.codepage == 12001)
- {
- cv.mbtowc = utf32_mbtowc;
- cv.wctomb = utf32_wctomb;
- if (_stricmp(name, "UTF-32") == 0 ||
- _stricmp(name, "UTF32") == 0 ||
- _stricmp(name, "UCS-4") == 0 ||
- _stricmp(name, "UCS4") == 0)
- cv.flags |= FLAG_USE_BOM_ENDIAN;
- }
- else if (cv.codepage == 65001)
- {
- cv.mbtowc = kernel_mbtowc;
- cv.wctomb = kernel_wctomb;
- cv.mblen = utf8_mblen;
- }
- else if ((cv.codepage == 50220 || cv.codepage == 50221 || cv.codepage == 50222) && load_mlang())
- {
- cv.mbtowc = iso2022jp_mbtowc;
- cv.wctomb = iso2022jp_wctomb;
- cv.flush = iso2022jp_flush;
- }
- else if (cv.codepage == 51932 && load_mlang())
- {
- cv.mbtowc = mlang_mbtowc;
- cv.wctomb = mlang_wctomb;
- cv.mblen = eucjp_mblen;
- }
- else if (IsValidCodePage(cv.codepage)
- && GetCPInfoEx(cv.codepage, 0, &cpinfoex) != 0)
- {
- cv.mbtowc = kernel_mbtowc;
- cv.wctomb = kernel_wctomb;
- if (cpinfoex.MaxCharSize == 1)
- cv.mblen = sbcs_mblen;
- else if (cpinfoex.MaxCharSize == 2)
- cv.mblen = dbcs_mblen;
- else
- cv.mblen = mbcs_mblen;
- }
- else
- {
- /* not supported */
- cv.codepage = -1;
- }
- if (use_compat)
- {
- switch (cv.codepage)
- {
- case 932: cv.compat = cp932_compat; break;
- case 20932: cv.compat = cp20932_compat; break;
- case 51932: cv.compat = cp51932_compat; break;
- case 50220: case 50221: case 50222: cv.compat = cp5022x_compat; break;
- }
- }
- return cv;
-}
-
-static int
-name_to_codepage(const char *name)
-{
- int i;
-
- if (*name == '\0' ||
- strcmp(name, "char") == 0)
- return GetACP();
- else if (strcmp(name, "wchar_t") == 0)
- return 1200;
- else if (_strnicmp(name, "cp", 2) == 0)
- return atoi(name + 2); /* CP123 */
- else if ('0' <= name[0] && name[0] <= '9')
- return atoi(name); /* 123 */
- else if (_strnicmp(name, "xx", 2) == 0)
- return atoi(name + 2); /* XX123 for debug */
-
- for (i = 0; codepage_alias[i].name != NULL; ++i)
- if (_stricmp(name, codepage_alias[i].name) == 0)
- return codepage_alias[i].codepage;
- return -1;
-}
-
-/*
- * http://www.faqs.org/rfcs/rfc2781.html
- */
-static uint
-utf16_to_ucs4(const ushort *wbuf)
-{
- uint wc = wbuf[0];
- if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
- wc = ((wbuf[0] & 0x3FF) << 10) + (wbuf[1] & 0x3FF) + 0x10000;
- return wc;
-}
-
-static void
-ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize)
-{
- if (wc < 0x10000)
- {
- wbuf[0] = wc;
- *wbufsize = 1;
- }
- else
- {
- wc -= 0x10000;
- wbuf[0] = 0xD800 | ((wc >> 10) & 0x3FF);
- wbuf[1] = 0xDC00 | (wc & 0x3FF);
- *wbufsize = 2;
- }
-}
-
-static int
-is_unicode(int codepage)
-{
- return (codepage == 1200 || codepage == 1201 ||
- codepage == 12000 || codepage == 12001 ||
- codepage == 65000 || codepage == 65001);
-}
-
-/*
- * Check if codepage is one of those for which the dwFlags parameter
- * to MultiByteToWideChar() must be zero. Return zero or
- * MB_ERR_INVALID_CHARS. The docs in Platform SDK for for Windows
- * Server 2003 R2 claims that also codepage 65001 is one of these, but
- * that doesn't seem to be the case. The MSDN docs for MSVS2008 leave
- * out 65001 (UTF-8), and that indeed seems to be the case on XP, it
- * works fine to pass MB_ERR_INVALID_CHARS in dwFlags when converting
- * from UTF-8.
- */
-static int
-mbtowc_flags(int codepage)
-{
- return (codepage == 50220 || codepage == 50221 ||
- codepage == 50222 || codepage == 50225 ||
- codepage == 50227 || codepage == 50229 ||
- codepage == 52936 || codepage == 54936 ||
- (codepage >= 57002 && codepage <= 57011) ||
- codepage == 65000 || codepage == 42) ? 0 : MB_ERR_INVALID_CHARS;
-}
-
-/*
- * Check if codepage is one those for which the lpUsedDefaultChar
- * parameter to WideCharToMultiByte() must be NULL. The docs in
- * Platform SDK for for Windows Server 2003 R2 claims that this is the
- * list below, while the MSDN docs for MSVS2008 claim that it is only
- * for 65000 (UTF-7) and 65001 (UTF-8). This time the earlier Platform
- * SDK seems to be correct, at least for XP.
- */
-static int
-must_use_null_useddefaultchar(int codepage)
-{
- return (codepage == 65000 || codepage == 65001 ||
- codepage == 50220 || codepage == 50221 ||
- codepage == 50222 || codepage == 50225 ||
- codepage == 50227 || codepage == 50229 ||
- codepage == 52936 || codepage == 54936 ||
- (codepage >= 57002 && codepage <= 57011) ||
- codepage == 42);
-}
-
-static void
-check_utf_bom(rec_iconv_t *cd, ushort *wbuf, int *wbufsize)
-{
- /* If we have a BOM, trust it, despite what the caller said */
- if (wbuf[0] == 0xFFFE && (cd->from.flags & FLAG_USE_BOM_ENDIAN))
- {
- /* swap endian: 1200 <-> 1201 or 12000 <-> 12001 */
- cd->from.codepage ^= 1;
- cd->from.mode |= UNICODE_MODE_SWAPPED;
- wbuf[0] = 0xFEFF;
- }
-
- /*
- * Remove BOM.
- * Don't do this if "to" is Unicode,
- * except if "to" is UTF-8.
- */
- if (wbuf[0] == 0xFEFF && (!is_unicode(cd->to.codepage) || cd->to.codepage == 65001))
- *wbufsize = 0;
-}
-
-static char *
-strrstr(const char *str, const char *token)
-{
- int len = strlen(token);
- const char *p = str + strlen(str);
-
- while (str <= --p)
- if (p[0] == token[0] && strncmp(p, token, len) == 0)
- return (char *)p;
- return NULL;
-}
-
-#if defined(USE_LIBICONV_DLL)
-static int
-libiconv_iconv_open(rec_iconv_t *cd, const char *fromcode, const char *tocode)
-{
- HMODULE hlibiconv = NULL;
- HMODULE hmsvcrt = NULL;
- char dllname[_MAX_PATH];
- const char *p;
- const char *e;
- f_iconv_open _iconv_open;
-
- /*
- * always try to load dll, so that we can switch dll in runtime.
- */
-
- /* XXX: getenv() can't get variable set by SetEnvironmentVariable() */
- p = getenv("WINICONV_LIBICONV_DLL");
- if (p == NULL)
- p = DEFAULT_LIBICONV_DLL;
- /* parse comma separated value */
- for ( ; *p != 0; p = (*e == ',') ? e + 1 : e)
- {
- e = strchr(p, ',');
- if (p == e)
- continue;
- else if (e == NULL)
- e = p + strlen(p);
- xstrlcpyn(dllname, p, e - p, sizeof(dllname));
- hlibiconv = LoadLibrary(dllname);
- if (hlibiconv != NULL)
- {
- if (hlibiconv == hwiniconv)
- {
- FreeLibrary(hlibiconv);
- hlibiconv = NULL;
- continue;
- }
- break;
- }
- }
-
- if (hlastdll != NULL)
- {
- /* decrement reference count */
- FreeLibrary(hlastdll);
- hlastdll = NULL;
- }
-
- if (hlibiconv == NULL)
- goto failed;
-
- hmsvcrt = find_imported_module_by_funcname(hlibiconv, "_errno");
- if (hmsvcrt == NULL)
- goto failed;
-
- _iconv_open = (f_iconv_open)GetProcAddress(hlibiconv, "libiconv_open");
- if (_iconv_open == NULL)
- _iconv_open = (f_iconv_open)GetProcAddress(hlibiconv, "iconv_open");
- cd->iconv_close = (f_iconv_close)GetProcAddress(hlibiconv, "libiconv_close");
- if (cd->iconv_close == NULL)
- cd->iconv_close = (f_iconv_close)GetProcAddress(hlibiconv, "iconv_close");
- cd->iconv = (f_iconv)GetProcAddress(hlibiconv, "libiconv");
- if (cd->iconv == NULL)
- cd->iconv = (f_iconv)GetProcAddress(hlibiconv, "iconv");
- cd->_errno = (f_errno)GetProcAddress(hmsvcrt, "_errno");
- if (_iconv_open == NULL || cd->iconv_close == NULL
- || cd->iconv == NULL || cd->_errno == NULL)
- goto failed;
-
- /* increment reference count */
- hlastdll = LoadLibrary(dllname);
-
- cd->cd = _iconv_open(tocode, fromcode);
- if (cd->cd == (iconv_t)(-1))
- goto failed;
-
- cd->hlibiconv = hlibiconv;
- return TRUE;
-
-failed:
- if (hlibiconv != NULL)
- FreeLibrary(hlibiconv);
- /* do not free hmsvcrt which is obtained by GetModuleHandle() */
- return FALSE;
-}
-
-/*
- * Reference:
- * http://forums.belution.com/ja/vc/000/234/78s.shtml
- * http://nienie.com/~masapico/api_ImageDirectoryEntryToData.html
- *
- * The formal way is
- * imagehlp.h or dbghelp.h
- * imagehlp.lib or dbghelp.lib
- * ImageDirectoryEntryToData()
- */
-#define TO_DOS_HEADER(base) ((PIMAGE_DOS_HEADER)(base))
-#define TO_NT_HEADERS(base) ((PIMAGE_NT_HEADERS)((LPBYTE)(base) + TO_DOS_HEADER(base)->e_lfanew))
-static PVOID
-MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size)
-{
- /* TODO: MappedAsImage? */
- PIMAGE_DATA_DIRECTORY p;
- p = TO_NT_HEADERS(Base)->OptionalHeader.DataDirectory + DirectoryEntry;
- if (p->VirtualAddress == 0) {
- *Size = 0;
- return NULL;
- }
- *Size = p->Size;
- return (PVOID)((LPBYTE)Base + p->VirtualAddress);
-}
-
-static HMODULE
-find_imported_module_by_funcname(HMODULE hModule, const char *funcname)
-{
- DWORD Base;
- ULONG Size;
- PIMAGE_IMPORT_DESCRIPTOR Imp;
- PIMAGE_THUNK_DATA Name; /* Import Name Table */
- PIMAGE_IMPORT_BY_NAME ImpName;
-
- Base = (DWORD)hModule;
- Imp = MyImageDirectoryEntryToData(
- (LPVOID)Base,
- TRUE,
- IMAGE_DIRECTORY_ENTRY_IMPORT,
- &Size);
- if (Imp == NULL)
- return NULL;
- for ( ; Imp->OriginalFirstThunk != 0; ++Imp)
- {
- Name = (PIMAGE_THUNK_DATA)(Base + Imp->OriginalFirstThunk);
- for ( ; Name->u1.Ordinal != 0; ++Name)
- {
- if (!IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal))
- {
- ImpName = (PIMAGE_IMPORT_BY_NAME)
- (Base + (DWORD)Name->u1.AddressOfData);
- if (strcmp((char *)ImpName->Name, funcname) == 0)
- return GetModuleHandle((char *)(Base + Imp->Name));
- }
- }
- }
- return NULL;
-}
-#endif
-
-static int
-sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
-{
- return 1;
-}
-
-static int
-dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
-{
- int len = IsDBCSLeadByteEx(cv->codepage, buf[0]) ? 2 : 1;
- if (bufsize < len)
- return_error(EINVAL);
- return len;
-}
-
-static int
-mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
-{
- int len = 0;
-
- if (cv->codepage == 54936) {
- if (buf[0] <= 0x7F) len = 1;
- else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&
- bufsize >= 2 &&
- ((buf[1] >= 0x40 && buf[1] <= 0x7E) ||
- (buf[1] >= 0x80 && buf[1] <= 0xFE))) len = 2;
- else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&
- bufsize >= 4 &&
- buf[1] >= 0x30 && buf[1] <= 0x39) len = 4;
- else
- return_error(EINVAL);
- return len;
- }
- else
- return_error(EINVAL);
-}
-
-static int
-utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize)
-{
- int len = 0;
-
- if (buf[0] < 0x80) len = 1;
- else if ((buf[0] & 0xE0) == 0xC0) len = 2;
- else if ((buf[0] & 0xF0) == 0xE0) len = 3;
- else if ((buf[0] & 0xF8) == 0xF0) len = 4;
- else if ((buf[0] & 0xFC) == 0xF8) len = 5;
- else if ((buf[0] & 0xFE) == 0xFC) len = 6;
-
- if (len == 0)
- return_error(EILSEQ);
- else if (bufsize < len)
- return_error(EINVAL);
- return len;
-}
-
-static int
-eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize)
-{
- if (buf[0] < 0x80) /* ASCII */
- return 1;
- else if (buf[0] == 0x8E) /* JIS X 0201 */
- {
- if (bufsize < 2)
- return_error(EINVAL);
- else if (!(0xA1 <= buf[1] && buf[1] <= 0xDF))
- return_error(EILSEQ);
- return 2;
- }
- else if (buf[0] == 0x8F) /* JIS X 0212 */
- {
- if (bufsize < 3)
- return_error(EINVAL);
- else if (!(0xA1 <= buf[1] && buf[1] <= 0xFE)
- || !(0xA1 <= buf[2] && buf[2] <= 0xFE))
- return_error(EILSEQ);
- return 3;
- }
- else /* JIS X 0208 */
- {
- if (bufsize < 2)
- return_error(EINVAL);
- else if (!(0xA1 <= buf[0] && buf[0] <= 0xFE)
- || !(0xA1 <= buf[1] && buf[1] <= 0xFE))
- return_error(EILSEQ);
- return 2;
- }
-}
-
-static int
-kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
-{
- int len;
-
- len = cv->mblen(cv, buf, bufsize);
- if (len == -1)
- return -1;
- /* If converting from ASCII, reject 8bit
- * chars. MultiByteToWideChar() doesn't. Note that for ASCII we
- * know that the mblen function is sbcs_mblen() so len is 1.
- */
- if (cv->codepage == 20127 && buf[0] >= 0x80)
- return_error(EILSEQ);
- *wbufsize = MultiByteToWideChar(cv->codepage, mbtowc_flags (cv->codepage),
- (const char *)buf, len, (wchar_t *)wbuf, *wbufsize);
- if (*wbufsize == 0)
- return_error(EILSEQ);
- return len;
-}
-
-static int
-kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
-{
- BOOL usedDefaultChar = 0;
- BOOL *p = NULL;
- int flags = 0;
- int len;
-
- if (bufsize == 0)
- return_error(E2BIG);
- if (!must_use_null_useddefaultchar(cv->codepage))
- {
- p = &usedDefaultChar;
-#ifdef WC_NO_BEST_FIT_CHARS
- if (!(cv->flags & FLAG_TRANSLIT))
- flags |= WC_NO_BEST_FIT_CHARS;
-#endif
- }
- len = WideCharToMultiByte(cv->codepage, flags,
- (const wchar_t *)wbuf, wbufsize, (char *)buf, bufsize, NULL, p);
- if (len == 0)
- {
- if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
- return_error(E2BIG);
- return_error(EILSEQ);
- }
- else if (usedDefaultChar)
- return_error(EILSEQ);
- else if (cv->mblen(cv, buf, len) != len) /* validate result */
- return_error(EILSEQ);
- return len;
-}
-
-/*
- * It seems that the mode (cv->mode) is fixnum.
- * For example, when converting iso-2022-jp(cp50221) to unicode:
- * in ascii sequence: mode=0xC42C0000
- * in jisx0208 sequence: mode=0xC42C0001
- * "C42C" is same for each convert session.
- * It should be: ((codepage-1)<<16)|state
- */
-static int
-mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
-{
- int len;
- int insize;
- HRESULT hr;
-
- len = cv->mblen(cv, buf, bufsize);
- if (len == -1)
- return -1;
- insize = len;
- hr = ConvertINetMultiByteToUnicode(&cv->mode, cv->codepage,
- (const char *)buf, &insize, (wchar_t *)wbuf, wbufsize);
- if (hr != S_OK || insize != len)
- return_error(EILSEQ);
- return len;
-}
-
-static int
-mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
-{
- char tmpbuf[MB_CHAR_MAX]; /* enough room for one character */
- int tmpsize = MB_CHAR_MAX;
- int insize = wbufsize;
- HRESULT hr;
-
- hr = ConvertINetUnicodeToMultiByte(&cv->mode, cv->codepage,
- (const wchar_t *)wbuf, &wbufsize, tmpbuf, &tmpsize);
- if (hr != S_OK || insize != wbufsize)
- return_error(EILSEQ);
- else if (bufsize < tmpsize)
- return_error(E2BIG);
- else if (cv->mblen(cv, (uchar *)tmpbuf, tmpsize) != tmpsize)
- return_error(EILSEQ);
- memcpy(buf, tmpbuf, tmpsize);
- return tmpsize;
-}
-
-static int
-utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
-{
- if (bufsize < 2)
- return_error(EINVAL);
- if (cv->codepage == 1200) /* little endian */
- wbuf[0] = (buf[1] << 8) | buf[0];
- else if (cv->codepage == 1201) /* big endian */
- wbuf[0] = (buf[0] << 8) | buf[1];
- if (0xDC00 <= wbuf[0] && wbuf[0] <= 0xDFFF)
- return_error(EILSEQ);
- if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
- {
- if (bufsize < 4)
- return_error(EINVAL);
- if (cv->codepage == 1200) /* little endian */
- wbuf[1] = (buf[3] << 8) | buf[2];
- else if (cv->codepage == 1201) /* big endian */
- wbuf[1] = (buf[2] << 8) | buf[3];
- if (!(0xDC00 <= wbuf[1] && wbuf[1] <= 0xDFFF))
- return_error(EILSEQ);
- *wbufsize = 2;
- return 4;
- }
- *wbufsize = 1;
- return 2;
-}
-
-static int
-utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
-{
- if (bufsize < 2)
- return_error(E2BIG);
- if (cv->codepage == 1200) /* little endian */
- {
- buf[0] = (wbuf[0] & 0x00FF);
- buf[1] = (wbuf[0] & 0xFF00) >> 8;
- }
- else if (cv->codepage == 1201) /* big endian */
- {
- buf[0] = (wbuf[0] & 0xFF00) >> 8;
- buf[1] = (wbuf[0] & 0x00FF);
- }
- if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
- {
- if (bufsize < 4)
- return_error(E2BIG);
- if (cv->codepage == 1200) /* little endian */
- {
- buf[2] = (wbuf[1] & 0x00FF);
- buf[3] = (wbuf[1] & 0xFF00) >> 8;
- }
- else if (cv->codepage == 1201) /* big endian */
- {
- buf[2] = (wbuf[1] & 0xFF00) >> 8;
- buf[3] = (wbuf[1] & 0x00FF);
- }
- return 4;
- }
- return 2;
-}
-
-static int
-utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
-{
- uint wc;
-
- if (bufsize < 4)
- return_error(EINVAL);
- if (cv->codepage == 12000) /* little endian */
- wc = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
- else if (cv->codepage == 12001) /* big endian */
- wc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
- if ((0xD800 <= wc && wc <= 0xDFFF) || 0x10FFFF < wc)
- return_error(EILSEQ);
- ucs4_to_utf16(wc, wbuf, wbufsize);
- return 4;
-}
-
-static int
-utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
-{
- uint wc;
-
- if (bufsize < 4)
- return_error(E2BIG);
- wc = utf16_to_ucs4(wbuf);
- if (cv->codepage == 12000) /* little endian */
- {
- buf[0] = wc & 0x000000FF;
- buf[1] = (wc & 0x0000FF00) >> 8;
- buf[2] = (wc & 0x00FF0000) >> 16;
- buf[3] = (wc & 0xFF000000) >> 24;
- }
- else if (cv->codepage == 12001) /* big endian */
- {
- buf[0] = (wc & 0xFF000000) >> 24;
- buf[1] = (wc & 0x00FF0000) >> 16;
- buf[2] = (wc & 0x0000FF00) >> 8;
- buf[3] = wc & 0x000000FF;
- }
- return 4;
-}
-
-/*
- * 50220: ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)
- * 50221: ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow
- * 1 byte Kana)
- * 50222: ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte
- * Kana - SO/SI)
- *
- * MultiByteToWideChar() and WideCharToMultiByte() behave differently
- * depending on Windows version. On XP, WideCharToMultiByte() doesn't
- * terminate result sequence with ascii escape. But Vista does.
- * Use MLang instead.
- */
-
-#define ISO2022_MODE(cs, shift) (((cs) << 8) | (shift))
-#define ISO2022_MODE_CS(mode) (((mode) >> 8) & 0xFF)
-#define ISO2022_MODE_SHIFT(mode) ((mode) & 0xFF)
-
-#define ISO2022_SI 0
-#define ISO2022_SO 1
-
-/* shift in */
-static const char iso2022_SI_seq[] = "\x0F";
-/* shift out */
-static const char iso2022_SO_seq[] = "\x0E";
-
-typedef struct iso2022_esc_t iso2022_esc_t;
-struct iso2022_esc_t {
- const char *esc;
- int esc_len;
- int len;
- int cs;
-};
-
-#define ISO2022JP_CS_ASCII 0
-#define ISO2022JP_CS_JISX0201_ROMAN 1
-#define ISO2022JP_CS_JISX0201_KANA 2
-#define ISO2022JP_CS_JISX0208_1978 3
-#define ISO2022JP_CS_JISX0208_1983 4
-#define ISO2022JP_CS_JISX0212 5
-
-static iso2022_esc_t iso2022jp_esc[] = {
- {"\x1B\x28\x42", 3, 1, ISO2022JP_CS_ASCII},
- {"\x1B\x28\x4A", 3, 1, ISO2022JP_CS_JISX0201_ROMAN},
- {"\x1B\x28\x49", 3, 1, ISO2022JP_CS_JISX0201_KANA},
- {"\x1B\x24\x40", 3, 2, ISO2022JP_CS_JISX0208_1983}, /* unify 1978 with 1983 */
- {"\x1B\x24\x42", 3, 2, ISO2022JP_CS_JISX0208_1983},
- {"\x1B\x24\x28\x44", 4, 2, ISO2022JP_CS_JISX0212},
- {NULL, 0, 0, 0}
-};
-
-static int
-iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
-{
- iso2022_esc_t *iesc = iso2022jp_esc;
- char tmp[MB_CHAR_MAX];
- int insize;
- HRESULT hr;
- DWORD dummy = 0;
- int len;
- int esc_len;
- int cs;
- int shift;
- int i;
-
- if (buf[0] == 0x1B)
- {
- for (i = 0; iesc[i].esc != NULL; ++i)
- {
- esc_len = iesc[i].esc_len;
- if (bufsize < esc_len)
- {
- if (strncmp((char *)buf, iesc[i].esc, bufsize) == 0)
- return_error(EINVAL);
- }
- else
- {
- if (strncmp((char *)buf, iesc[i].esc, esc_len) == 0)
- {
- cv->mode = ISO2022_MODE(iesc[i].cs, ISO2022_SI);
- *wbufsize = 0;
- return esc_len;
- }
- }
- }
- /* not supported escape sequence */
- return_error(EILSEQ);
- }
- else if (buf[0] == iso2022_SO_seq[0])
- {
- cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SO);
- *wbufsize = 0;
- return 1;
- }
- else if (buf[0] == iso2022_SI_seq[0])
- {
- cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SI);
- *wbufsize = 0;
- return 1;
- }
-
- cs = ISO2022_MODE_CS(cv->mode);
- shift = ISO2022_MODE_SHIFT(cv->mode);
-
- /* reset the mode for informal sequence */
- if (buf[0] < 0x20)
- {
- cs = ISO2022JP_CS_ASCII;
- shift = ISO2022_SI;
- }
-
- len = iesc[cs].len;
- if (bufsize < len)
- return_error(EINVAL);
- for (i = 0; i < len; ++i)
- if (!(buf[i] < 0x80))
- return_error(EILSEQ);
- esc_len = iesc[cs].esc_len;
- memcpy(tmp, iesc[cs].esc, esc_len);
- if (shift == ISO2022_SO)
- {
- memcpy(tmp + esc_len, iso2022_SO_seq, 1);
- esc_len += 1;
- }
- memcpy(tmp + esc_len, buf, len);
-
- if ((cv->codepage == 50220 || cv->codepage == 50221
- || cv->codepage == 50222) && shift == ISO2022_SO)
- {
- /* XXX: shift-out cannot be used for mbtowc (both kernel and
- * mlang) */
- esc_len = iesc[ISO2022JP_CS_JISX0201_KANA].esc_len;
- memcpy(tmp, iesc[ISO2022JP_CS_JISX0201_KANA].esc, esc_len);
- memcpy(tmp + esc_len, buf, len);
- }
-
- insize = len + esc_len;
- hr = ConvertINetMultiByteToUnicode(&dummy, cv->codepage,
- (const char *)tmp, &insize, (wchar_t *)wbuf, wbufsize);
- if (hr != S_OK || insize != len + esc_len)
- return_error(EILSEQ);
-
- /* Check for conversion error. Assuming defaultChar is 0x3F. */
- /* ascii should be converted from ascii */
- if (wbuf[0] == buf[0]
- && cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))
- return_error(EILSEQ);
-
- /* reset the mode for informal sequence */
- if (cv->mode != ISO2022_MODE(cs, shift))
- cv->mode = ISO2022_MODE(cs, shift);
-
- return len;
-}
-
-static int
-iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
-{
- iso2022_esc_t *iesc = iso2022jp_esc;
- char tmp[MB_CHAR_MAX];
- int tmpsize = MB_CHAR_MAX;
- int insize = wbufsize;
- HRESULT hr;
- DWORD dummy = 0;
- int len;
- int esc_len;
- int cs;
- int shift;
- int i;
-
- /*
- * MultiByte = [escape sequence] + character + [escape sequence]
- *
- * Whether trailing escape sequence is added depends on which API is
- * used (kernel or MLang, and its version).
- */
- hr = ConvertINetUnicodeToMultiByte(&dummy, cv->codepage,
- (const wchar_t *)wbuf, &wbufsize, tmp, &tmpsize);
- if (hr != S_OK || insize != wbufsize)
- return_error(EILSEQ);
- else if (bufsize < tmpsize)
- return_error(E2BIG);
-
- if (tmpsize == 1)
- {
- cs = ISO2022JP_CS_ASCII;
- esc_len = 0;
- }
- else
- {
- for (i = 1; iesc[i].esc != NULL; ++i)
- {
- esc_len = iesc[i].esc_len;
- if (strncmp(tmp, iesc[i].esc, esc_len) == 0)
- {
- cs = iesc[i].cs;
- break;
- }
- }
- if (iesc[i].esc == NULL)
- /* not supported escape sequence */
- return_error(EILSEQ);
- }
-
- shift = ISO2022_SI;
- if (tmp[esc_len] == iso2022_SO_seq[0])
- {
- shift = ISO2022_SO;
- esc_len += 1;
- }
-
- len = iesc[cs].len;
-
- /* Check for converting error. Assuming defaultChar is 0x3F. */
- /* ascii should be converted from ascii */
- if (cs == ISO2022JP_CS_ASCII && !(wbuf[0] < 0x80))
- return_error(EILSEQ);
- else if (tmpsize < esc_len + len)
- return_error(EILSEQ);
-
- if (cv->mode == ISO2022_MODE(cs, shift))
- {
- /* remove escape sequence */
- if (esc_len != 0)
- memmove(tmp, tmp + esc_len, len);
- esc_len = 0;
- }
- else
- {
- if (cs == ISO2022JP_CS_ASCII)
- {
- esc_len = iesc[ISO2022JP_CS_ASCII].esc_len;
- memmove(tmp + esc_len, tmp, len);
- memcpy(tmp, iesc[ISO2022JP_CS_ASCII].esc, esc_len);
- }
- if (ISO2022_MODE_SHIFT(cv->mode) == ISO2022_SO)
- {
- /* shift-in before changing to other mode */
- memmove(tmp + 1, tmp, len + esc_len);
- memcpy(tmp, iso2022_SI_seq, 1);
- esc_len += 1;
- }
- }
-
- if (bufsize < len + esc_len)
- return_error(E2BIG);
- memcpy(buf, tmp, len + esc_len);
- cv->mode = ISO2022_MODE(cs, shift);
- return len + esc_len;
-}
-
-static int
-iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize)
-{
- iso2022_esc_t *iesc = iso2022jp_esc;
- int esc_len;
-
- if (cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))
- {
- esc_len = 0;
- if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)
- esc_len += 1;
- if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)
- esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;
- if (bufsize < esc_len)
- return_error(E2BIG);
-
- esc_len = 0;
- if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)
- {
- memcpy(buf, iso2022_SI_seq, 1);
- esc_len += 1;
- }
- if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)
- {
- memcpy(buf + esc_len, iesc[ISO2022JP_CS_ASCII].esc,
- iesc[ISO2022JP_CS_ASCII].esc_len);
- esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;
- }
- return esc_len;
- }
- return 0;
-}
-
-#if defined(MAKE_DLL) && defined(USE_LIBICONV_DLL)
-BOOL WINAPI
-DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
-{
- switch( fdwReason )
- {
- case DLL_PROCESS_ATTACH:
- hwiniconv = (HMODULE)hinstDLL;
- break;
- case DLL_THREAD_ATTACH:
- case DLL_THREAD_DETACH:
- case DLL_PROCESS_DETACH:
- break;
- }
- return TRUE;
-}
-#endif
-
-#if defined(MAKE_EXE)
-#include <stdio.h>
-#include <fcntl.h>
-#include <io.h>
-int
-main(int argc, char **argv)
-{
- char *fromcode = NULL;
- char *tocode = NULL;
- int i;
- char inbuf[BUFSIZ];
- char outbuf[BUFSIZ];
- const char *pin;
- char *pout;
- size_t inbytesleft;
- size_t outbytesleft;
- size_t rest = 0;
- iconv_t cd;
- size_t r;
- FILE *in = stdin;
-
- _setmode(_fileno(stdin), _O_BINARY);
- _setmode(_fileno(stdout), _O_BINARY);
-
- for (i = 1; i < argc; ++i)
- {
- if (strcmp(argv[i], "-l") == 0)
- {
- for (i = 0; codepage_alias[i].name != NULL; ++i)
- printf("%s\n", codepage_alias[i].name);
- return 0;
- }
-
- if (strcmp(argv[i], "-f") == 0)
- fromcode = argv[++i];
- else if (strcmp(argv[i], "-t") == 0)
- tocode = argv[++i];
- else
- {
- in = fopen(argv[i], "rb");
- if (in == NULL)
- {
- fprintf(stderr, "cannot open %s\n", argv[i]);
- return 1;
- }
- break;
- }
- }
-
- if (fromcode == NULL || tocode == NULL)
- {
- printf("usage: %s -f from-enc -t to-enc [file]\n", argv[0]);
- return 0;
- }
-
- cd = iconv_open(tocode, fromcode);
- if (cd == (iconv_t)(-1))
- {
- perror("iconv_open error");
- return 1;
- }
-
- while ((inbytesleft = fread(inbuf + rest, 1, sizeof(inbuf) - rest, in)) != 0
- || rest != 0)
- {
- inbytesleft += rest;
- pin = inbuf;
- pout = outbuf;
- outbytesleft = sizeof(outbuf);
- r = iconv(cd, &pin, &inbytesleft, &pout, &outbytesleft);
- fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout);
- if (r == (size_t)(-1) && errno != EINVAL && errno != E2BIG)
- {
- perror("conversion error");
- return 1;
- }
- memmove(inbuf, pin, inbytesleft);
- rest = inbytesleft;
- }
- pout = outbuf;
- outbytesleft = sizeof(outbuf);
- r = iconv(cd, NULL, NULL, &pout, &outbytesleft);
- fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout);
- if (r == (size_t)(-1))
- {
- perror("conversion error");
- return 1;
- }
-
- iconv_close(cd);
-
- return 0;
-}
-#endif
-
|