Index: ossp-pkg/ex/Makefile RCS File: /v/ossp/cvs/ossp-pkg/ex/Attic/Makefile,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/ex/Attic/Makefile,v' | diff -u /dev/null - -L'ossp-pkg/ex/Makefile' 2>/dev/null --- ossp-pkg/ex/Makefile +++ - 2024-05-02 07:52:13.572793916 +0200 @@ -0,0 +1,23 @@ + +CC = /usr/opkg/bin/gcc +CFLAGS = -Wall -O2 -I. +LDFLAGS = +AR = ar +RANLIB = ranlib + +all: libex.a ex_test + +ex_test: ex_test.o libex.a + $(CC) $(LDFLAGS) -o ex_test ex_test.o libex.a + +libex.a: ex.o + rm -f $@ + $(AR) cr $@ ex.o + $(RANLIB) $@ + +clean: + rm -f ex_test *.a *.o *.core + +check: ex_test + ./ex_test + Index: ossp-pkg/ex/README RCS File: /v/ossp/cvs/ossp-pkg/ex/README,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/ex/README,v' | diff -u /dev/null - -L'ossp-pkg/ex/README' 2>/dev/null --- ossp-pkg/ex/README +++ - 2024-05-02 07:52:13.575501414 +0200 @@ -0,0 +1 @@ + Index: ossp-pkg/ex/TODO RCS File: /v/ossp/cvs/ossp-pkg/ex/Attic/TODO,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/ex/Attic/TODO,v' | diff -u /dev/null - -L'ossp-pkg/ex/TODO' 2>/dev/null --- ossp-pkg/ex/TODO +++ - 2024-05-02 07:52:13.578196522 +0200 @@ -0,0 +1,4 @@ +- default handler +- sigsetjmp (Why can't "real" exceptions be caught?) +- pth +- disable throwing Index: ossp-pkg/ex/ex.c RCS File: /v/ossp/cvs/ossp-pkg/ex/ex.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/ex/ex.c,v' | diff -u /dev/null - -L'ossp-pkg/ex/ex.c' 2>/dev/null --- ossp-pkg/ex/ex.c +++ - 2024-05-02 07:52:13.580803949 +0200 @@ -0,0 +1,29 @@ +/* +** Copyright (c) 2001-2002 The OSSP Project +** Copyright (c) 2001-2002 Cable & Wireless Deutschland +** +** This file is part of OSSP ex, an exception library +** which can be found at http://www.ossp.org/pkg/ex/. +** +** 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.0 of the License, 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 file; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +** USA, or contact the OSSP project . +** +** ex.c: exception handling (compiler part) +*/ + +#include "ex.h" + +ex_ctx_t __ex_ctx_global; + Index: ossp-pkg/ex/ex.h RCS File: /v/ossp/cvs/ossp-pkg/ex/ex.h,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/ex/ex.h,v' | diff -u /dev/null - -L'ossp-pkg/ex/ex.h' 2>/dev/null --- ossp-pkg/ex/ex.h +++ - 2024-05-02 07:52:13.583472122 +0200 @@ -0,0 +1,134 @@ +/* +** Copyright (c) 2001-2002 The OSSP Project +** Copyright (c) 2001-2002 Cable & Wireless Deutschland +** +** This file is part of OSSP ex, an exception library +** which can be found at http://www.ossp.org/pkg/ex/. +** +** 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.0 of the License, 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 file; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +** USA, or contact the OSSP project . +** +** ex.h: exception handling (pre-processor part) +*/ + +#ifndef __TEXAS_H__ +#define __TEXAS_H__ + +/* the required ISO-C standard facilities */ +#include /* for NULL */ +#include /* for jmp_buf, setjmp(3), longjmp(3) */ + +/* determine how the current function name can be fetched */ +#if ( defined(__STDC__) \ + && defined(__STDC_VERSION__) \ + && __STDC_VERSION__ >= 199901L) +#define __TEXAS_FUNC__ __func__ /* ISO C99 compliant */ +#elif ( defined(__GNUC__) \ + && defined(__GNUC_MINOR__) \ + && ( __GNUC__ > 2 \ + || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8))) +#define __TEXAS_FUNC__ __FUNCTION__ /* gcc >= 2.8 */ +#else +#define __TEXAS_FUNC__ "#NA#" /* not available */ +#endif + +/* declare the exception type (public) */ +typedef struct { + /* throw value */ + void *ex_class; + void *ex_object; + void *ex_value; + /* throw point */ + char *ex_file; + int ex_line; + char *ex_func; +} ex_t; + +/* declare the exception context type (private) */ +typedef struct { + jmp_buf *ctx_jbprev; /* previous jump buffer */ + int ctx_caught; /* flag whether exception was caught */ + volatile ex_t ctx_ex; /* the exception temporary storage */ +} ex_ctx_t; + +/* ex context (default requires linking against libex) */ +#ifndef __ex_ctx +#define __ex_ctx (&__ex_ctx_global) +extern ex_ctx_t __ex_ctx_global; +#endif + +/* block for trying execution */ +#define ex_try \ + { \ + jmp_buf *__ex_jbprev; \ + jmp_buf __ex_jbme; \ + __ex_jbprev = __ex_ctx->ctx_jbprev; \ + __ex_ctx->ctx_jbprev = &__ex_jbme; \ + if (setjmp(__ex_jbme) == 0) { \ + if (1) + +/* block for catching an exception */ +#define ex_catch(e) \ + else { \ + } \ + __ex_ctx->ctx_caught = 0; \ + } \ + else { \ + __ex_ctx->ctx_caught = 1; \ + } \ + __ex_ctx->ctx_jbprev = __ex_jbprev; \ + } \ + if (!__ex_ctx->ctx_caught || ((e) = __ex_ctx->ctx_ex, 0)) { \ + } \ + else + +/* throw a new exception */ +#define ex_throw(c,o,v) \ + (__ex_ctx->ctx_jbprev == NULL ? \ + (abort(), 0) : \ + ( __ex_ctx->ctx_ex.ex_class = (void *)(c), \ + __ex_ctx->ctx_ex.ex_object = (void *)(o), \ + __ex_ctx->ctx_ex.ex_value = (void *)(v), \ + __ex_ctx->ctx_ex.ex_file = __FILE__, \ + __ex_ctx->ctx_ex.ex_line = __LINE__, \ + __ex_ctx->ctx_ex.ex_func = __TEXAS_FUNC__, \ + longjmp(*(__ex_ctx->ctx_jbprev), 1), \ + 0 \ + ) \ + ) + +/* re-throw a caught exception */ +#define ex_rethrow \ + (__ex_ctx->ctx_jbprev == NULL ? \ + (abort(), 0) : \ + (longjmp(*(__ex_ctx->ctx_jbprev), 1), 0) \ + ) + +/* optional namespace mapping */ +#if !defined(__cplusplus) && !defined(__TEXAS_NO_CXX_NS__) +#define try ex_try +#define catch ex_catch +#define throw ex_throw +#define rethrow ex_rethrow +#endif +#if !defined(__TEXAS_NO_SIMPLE_NS__) +#define Try ex_try +#define Catch ex_catch +#define Throw ex_throw +#define Rethrow ex_rethrow +#endif + +#endif /* __TEXAS_H__ */ + Index: ossp-pkg/ex/ex.pod RCS File: /v/ossp/cvs/ossp-pkg/ex/ex.pod,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/ex/ex.pod,v' | diff -u /dev/null - -L'ossp-pkg/ex/ex.pod' 2>/dev/null --- ossp-pkg/ex/ex.pod +++ - 2024-05-02 07:52:13.586283812 +0200 @@ -0,0 +1,220 @@ +## +## Copyright (c) 2001-2002 The OSSP Project +## Copyright (c) 2001-2002 Cable & Wireless Deutschland +## +## This file is part of OSSP ex, an exception library +## which can be found at http://www.ossp.org/pkg/ex/. +## +## 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.0 of the License, 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 file; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +## USA, or contact the OSSP project . +## +## ex.pod: exception library manual page +## + +=pod + +=head1 NAME + +B - Exception Library + +=head1 SYNOPSIS + +B I; + +B { ... } B (I) { ... } + +B(I, I, I); + +B; + +=head1 DESCRIPTION + +B is a small ISO-C++ style exception handling library for use +in the ISO-C language. It allows you to use the paradigm of throwing +and catching exceptions in order to reduce the amount of error handling +code in without making your program less robust. This is achieved +by directly transferring exceptional return codes (and the program +control flow) from the location where it was raised (throw point) to +the location where it is handled (catch point) - usually from a deeply +nested sub-routine to a parent routine. All intermediate routines +no longer have to make sure that the exceptional return codes from +sub-routines are correctly passed back to the parent. + +=head2 EXCEPTIONS + +An exception is a triple EI,I,IE where +I identifies the class of the exception thrower, I +identifies the particular class instance of the exception thrower, and +I is the exceptional return code the thrower wants to send to the +catcher. All three parts are of type C internally, but every +value can be used which can be (automatically) casted to a C. +Exceptions are created on-the-fly by the B command. + +=head2 APPLICATION PROGRAMMER INTERFACE (API) + +The B API consists of four different elements: + +=over 4 + +=item B I; + +This is the declaration of an exception variable. It is usually never +initialized manually. Instead it is initialized by an B block +and just used read-only inside the block. Such a variable of type +B consists of six attributes: + +=over 2 + +=item CI + +This is the I argument of the B call which created +the exception. This globally and uniquely identifies the class of +I. Usually this is a pointer to a static object (variable, +structure or function) which identifies the thrower. + +=item CI + +This is the I argument of the B call which created +the exception. This globally and uniquely identifies the class instance +of I (in case multiple instances exists). Usually this a +pointer to a dynamic object (structure) which identifiers the particular +instance of the thrower. + +=item CI + +This is the I argument of the B call which created the +exception. This is the exceptional return code which uniquely identifies +the type of exception. Usually this is the value which is Ced +if no exceptions would be thrown. In the simple case this is just a +numerical return code. In the complex case this can be a pointer to an +arbitrary complex data structure describing the exception. + +=item CI + +This is the file name of the source where the B call +was performed. It is provided as an additional information about +the throw point and is intended mainly for tracing and debugging +purposes. + +=item C I + +This is the line number inside the source file name where the +B call was performed. It is provided as an additional +information about the throw point and is intended mainly for tracing and +debugging purposes. + +=item CI + +This is the function name (if determinable, else "C<#NA#>") inside +the source file name where the B call was performed. It is +provided as an additional information about the throw point and is +intended mainly for tracing and debugging purposes. + +=back + +=item B { ... } B (I) { ... } + +This is the main construct provided by B. It is modeled after +the ISO-C++ C-C construct which in turn is very similar to +an ISO-C C-C construct. It consists of an B block +which forms the dynamic scope of the exception handling (i.e. exceptions +thrown there are or from routines called from there are catched) and a +B block where the caught exceptions are handled. + +The B and B cannot be used seperately, they work only +in combination. In contrast to ISO-C++ there is only one B +block and not multiple ones (all B exceptions are of the +same ISO-C type B). If an exception is caught, it is stored in +I for inspection (or re-throwing) inside the B +block. Although declared outside, the I is only valid +within the B block. But it can be re-used in following +B/B constructs, of course. + +The B block is a regular ISO-C language block, but it is not +allowed to jump into it via C or C(3) or out of it via +C, C or C(3) because there is some hidden setup +and cleanup that needs to be done by B regardless of whether an +exception is caught. Jumping into an B clause would avoid doing +the setup, and jumping out of it would avoid doing the cleanup. In both +cases the result is a broken exception facility. + +The B block is a regular ISO-C language block without any +restrictions. + +=item B(I, I, I); + +This is second main construct. It builds an exception from the supplied +arguments and throws it. If an B/B clause exists in +the dynamic scope of the B call, this exception is copied into +the I of B and the program control flow is continued +in the B block. If no B/B clause exists in +the dynamic scope of the B call, the program C(3)s. The +B can be performed everywhere, including inside B and +B blocks. + +=item B; + +This is only valid within an B block and re-throws +the current exception (in I). It is similar to the +call B(I.ex_class, I.ex_object, +I.ex_value) but with the difference that the C, +C and C elements of the thrown exception are kept. + +=back + +=head1 EXAMPLE + + #include "ex.h" + + ex_t e; + + ex_try { + ... + ex_throw (..., ..., 123); + ... + } + ex_catch (e) { + ... + if ((int)e->ex_value == 123) + ... + else if ((int)e->ex_value == 456) + ... + else + ex_rethrow; + ... + } + +=head1 SEE ALSO + +C++ try/catch/throw language directives; +setjmp(3), longjmp(3), sigsetjmp(3), siglongjmp(3). + +=head1 HISTORY + +B was invented in January 2002 by Ralf S. Engelschall for use +inside the OSSP project. Its creation was prompted by the requirement to +reduce the error handling inside B. The implementation +is partly derived from B 2.0.0, a similar library written 2000 +by Adam M. Costello Eamc@cs.berkeley.eduE and Cosmin Truta +Ecosmin@cs.toronto.eduE. + +=head1 AUTHORS + + Ralf S. Engelschall + rse@engelschall.com + www.engelschall.com + +=cut + Index: ossp-pkg/ex/ex_test.c RCS File: /v/ossp/cvs/ossp-pkg/ex/ex_test.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/ex/ex_test.c,v' | diff -u /dev/null - -L'ossp-pkg/ex/ex_test.c' 2>/dev/null --- ossp-pkg/ex/ex_test.c +++ - 2024-05-02 07:52:13.589479828 +0200 @@ -0,0 +1,104 @@ + +#include +#include +#include + +#include "ex.h" + +/* === foo.h === */ + +typedef enum { + FOO_OK = 0, + FOO_ERR_1, + FOO_ERR_2, + FOO_ERR_3 +} foo_rc_t; + +#define FOO_TEXAS + +#ifdef FOO_TEXAS + +#include "ex.h" +#define FOO_ERR(err) \ + (ex_throw(FOO_CLASS, NULL, FOO_ERR_##err), FOO_ERR_##err) +#else +#define FOO_ERR(err) \ + (FOO_ERR_##err) +#endif + +#define FOO_EX2RC(e) \ + ((foo_rc_t)((e)->ex_value)) +#define FOO_CLASS (&foo_class) +extern int foo_class; + +foo_rc_t foo_func(void); + +/* === foo.c === */ + +int foo_class; + +static int foo_sub(void) +{ + fprintf(stderr, "mark4\n"); + if (random() % 2) + return FOO_OK; + return FOO_ERR(1); +} + +foo_rc_t foo_func(void) +{ + fprintf(stderr, "mark3\n"); + foo_sub(); + if (random() % 2) + return FOO_OK; + return FOO_ERR(2); +} + +/* === test.c === */ + +int main(int argc, char *argv[]) +{ + srandom((unsigned int)time(NULL)); + ex_t e; + + fprintf(stderr, "main-0\n"); + for (;;) { + fprintf(stderr, "main-1\n"); + try { + fprintf(stderr, "main-2\n"); + foo_func(); + fprintf(stderr, "main-3\n"); + for (;;) { + fprintf(stderr, "main-4\n"); + try { + fprintf(stderr, "main-5\n"); + foo_func(); + fprintf(stderr, "main-6\n"); + } + catch (e) { + fprintf(stderr, "main-7\n"); + fprintf(stderr, " %s@%s:%d class=0x%lx object=0x%lx value=0x%lx\n", + e.ex_func, e.ex_file, e.ex_line, (long)e.ex_class, (long)e.ex_object, (long)e.ex_value); + if (e.ex_class == FOO_CLASS && (foo_rc_t)(e.ex_value) == FOO_ERR_1) + fprintf(stderr, " exception handling\n"); + else { + fprintf(stderr, " exception rethrowing\n"); + ex_rethrow; + } + fprintf(stderr, "main-8\n"); + } + fprintf(stderr, "main-9\n"); + } + fprintf(stderr, "main-10\n"); + } + catch (e) { + fprintf(stderr, "main-11\n"); + fprintf(stderr, " %s@%s:%d class=0x%lx object=0x%lx value=0x%lx\n", + e.ex_func, e.ex_file, e.ex_line, (long)e.ex_class, (long)e.ex_object, (long)e.ex_value); + fprintf(stderr, "main-12\n"); + } + } + fprintf(stderr, "main-0\n"); + return 0; +} +