234 lines
5.7 KiB
C
234 lines
5.7 KiB
C
/* QuesoGLC
|
|
* A free implementation of the OpenGL Character Renderer (GLC)
|
|
* Copyright (c) 2002, 2004-2007, Bertrand Coconnier
|
|
*
|
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
/* $Id$ */
|
|
|
|
/** \file
|
|
* defines the functions needed for cleanup stack exception handling (CSEH)
|
|
* which concept is described in details at
|
|
* http://www.freetype.org/david/reliable-c.html
|
|
*/
|
|
|
|
#include "internal.h"
|
|
#include "except.h"
|
|
|
|
#include <assert.h>
|
|
#include <ft2build.h>
|
|
#include FT_FREETYPE_H
|
|
#include FT_LIST_H
|
|
|
|
/* Unhandled exceptions (when area->exceptionStack.tail == NULL)
|
|
* still need to be implemented. Such situations can occur if an exception
|
|
* is thrown out of a try/catch block.
|
|
*/
|
|
|
|
typedef struct __GLCcleanupStackNodeRec __GLCcleanupStackNode;
|
|
typedef struct __GLCexceptContextRec __GLCexceptContext;
|
|
|
|
struct __GLCcleanupStackNodeRec {
|
|
FT_ListNodeRec node;
|
|
|
|
void (*destructor) (void *);
|
|
void *data;
|
|
};
|
|
|
|
struct __GLCexceptContextRec {
|
|
FT_ListNodeRec node;
|
|
|
|
__glcException exception;
|
|
FT_ListRec cleanupStack;
|
|
jmp_buf env;
|
|
};
|
|
|
|
|
|
|
|
/* Create a context for exception handling */
|
|
jmp_buf* __glcExceptionCreateContext(void)
|
|
{
|
|
__GLCthreadArea *area = NULL;
|
|
__GLCexceptContext *xContext = NULL;
|
|
|
|
area = GLC_GET_THREAD_AREA();
|
|
assert(area);
|
|
|
|
xContext = (__GLCexceptContext*)malloc(sizeof(__GLCexceptContext));
|
|
if (!xContext) {
|
|
area->failedTry = GLC_MEMORY_EXC;
|
|
return NULL;
|
|
}
|
|
xContext->exception = GLC_NO_EXC;
|
|
xContext->cleanupStack.head = NULL;
|
|
xContext->cleanupStack.tail = NULL;
|
|
FT_List_Add(&area->exceptionStack, (FT_ListNode)xContext);
|
|
|
|
return &xContext->env;
|
|
}
|
|
|
|
|
|
|
|
/* Destroy the last context for exception handling */
|
|
void __glcExceptionReleaseContext(void)
|
|
{
|
|
__GLCthreadArea *area = NULL;
|
|
__GLCexceptContext *xContext = NULL;
|
|
|
|
area = GLC_GET_THREAD_AREA();
|
|
assert(area);
|
|
|
|
xContext = (__GLCexceptContext*)area->exceptionStack.tail;
|
|
assert(xContext);
|
|
/* The cleanup stack must be empty */
|
|
assert(!xContext->cleanupStack.head);
|
|
assert(!xContext->cleanupStack.tail);
|
|
|
|
FT_List_Remove(&area->exceptionStack, (FT_ListNode)xContext);
|
|
free(xContext);
|
|
}
|
|
|
|
|
|
|
|
/* Keep track of data to be destroyed in case of */
|
|
void __glcExceptionPush(void (*destructor)(void*), void *data)
|
|
{
|
|
__GLCthreadArea *area = NULL;
|
|
__GLCexceptContext *xContext = NULL;
|
|
__GLCcleanupStackNode *stackNode = NULL;
|
|
|
|
area = GLC_GET_THREAD_AREA();
|
|
assert(area);
|
|
|
|
xContext = (__GLCexceptContext*)area->exceptionStack.tail;
|
|
assert(xContext);
|
|
|
|
stackNode = (__GLCcleanupStackNode*) malloc(sizeof(__GLCcleanupStackNode));
|
|
if (!stackNode) {
|
|
destructor(data);
|
|
THROW(GLC_MEMORY_EXC);
|
|
}
|
|
|
|
stackNode->destructor = destructor;
|
|
stackNode->data = data;
|
|
FT_List_Add(&xContext->cleanupStack, (FT_ListNode)stackNode);
|
|
}
|
|
|
|
|
|
|
|
/* Remove the last entry of the cleanup stack, eventually destroying the
|
|
* corresponding data if destroy != 0
|
|
*/
|
|
void __glcExceptionPop(int destroy)
|
|
{
|
|
__GLCthreadArea *area = NULL;
|
|
__GLCexceptContext *xContext = NULL;
|
|
__GLCcleanupStackNode *stackNode = NULL;
|
|
|
|
area = GLC_GET_THREAD_AREA();
|
|
assert(area);
|
|
|
|
xContext = (__GLCexceptContext*)area->exceptionStack.tail;
|
|
assert(xContext);
|
|
|
|
stackNode = (__GLCcleanupStackNode*)xContext->cleanupStack.tail;
|
|
assert(stackNode);
|
|
|
|
if (destroy) {
|
|
assert(stackNode->destructor);
|
|
assert(stackNode->data);
|
|
stackNode->destructor(stackNode->data);
|
|
}
|
|
FT_List_Remove(&xContext->cleanupStack, (FT_ListNode)stackNode);
|
|
free(stackNode);
|
|
}
|
|
|
|
|
|
|
|
/* Empty the cleanup stack and destroy the corresponding data if
|
|
* destroy != 0
|
|
*/
|
|
void __glcExceptionUnwind(int destroy)
|
|
{
|
|
__GLCthreadArea *area = NULL;
|
|
__GLCexceptContext *xContext = NULL;
|
|
FT_ListNode next = NULL;
|
|
__GLCcleanupStackNode *stackNode = NULL;
|
|
|
|
area = GLC_GET_THREAD_AREA();
|
|
assert(area);
|
|
|
|
xContext = (__GLCexceptContext*)area->exceptionStack.tail;
|
|
assert(xContext);
|
|
|
|
stackNode = (__GLCcleanupStackNode*)xContext->cleanupStack.head;
|
|
|
|
while (stackNode) {
|
|
next = stackNode->node.next;
|
|
if (destroy) {
|
|
assert(stackNode->destructor);
|
|
assert(stackNode->data);
|
|
stackNode->destructor(stackNode->data);
|
|
}
|
|
free(stackNode);
|
|
stackNode = (__GLCcleanupStackNode*)next;
|
|
}
|
|
|
|
xContext->cleanupStack.head = NULL;
|
|
xContext->cleanupStack.tail = NULL;
|
|
}
|
|
|
|
|
|
|
|
/* Throw an exception */
|
|
jmp_buf* __glcExceptionThrow(__glcException exception)
|
|
{
|
|
__GLCthreadArea *area = NULL;
|
|
__GLCexceptContext *xContext = NULL;
|
|
|
|
area = GLC_GET_THREAD_AREA();
|
|
assert(area);
|
|
|
|
xContext = (__GLCexceptContext*)area->exceptionStack.tail;
|
|
assert(xContext);
|
|
|
|
xContext->exception = exception;
|
|
return &xContext->env;
|
|
}
|
|
|
|
|
|
|
|
/* Rethrow an exception that has already been catched */
|
|
__glcException __glcExceptionCatch(void)
|
|
{
|
|
__GLCthreadArea *area = NULL;
|
|
__GLCexceptContext *xContext = NULL;
|
|
|
|
area = GLC_GET_THREAD_AREA();
|
|
assert(area);
|
|
|
|
if (area->failedTry) {
|
|
__glcException exc = area->failedTry;
|
|
|
|
area->failedTry = GLC_NO_EXC;
|
|
return exc;
|
|
}
|
|
|
|
xContext = (__GLCexceptContext*)area->exceptionStack.tail;
|
|
assert(xContext);
|
|
|
|
return xContext->exception;
|
|
}
|