exception.c
23.3 KB
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
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
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
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
/**
* \file exception.c
* \author Georg Steffers <georg@steffers.org>
* \brief The core of the exception system implemented within libscot.
*
* This file has all implementations for the exception system of scot.
* It defines the exception_t structure which holds basic information
* about an exception. Instances of this structure are organized
* in a queue that is part of excenv_t. That stucture describes the environment
* in which exceptions may occure, that is a TRY-CATCH block.
* Every TRY creates a new excenv_t instance and puts them in a stack,
* every CATCH get one excenv_t from that stack.
* To achive threadsaveness those excenv_t stack is organized within
* thread_excenv_t which associates a thread-id to an excenv_t stack.
* Thus every stack has its own exception stack.
*
* Copyright (C)2006 Georg Steffers <georg@steffers.org>
*
* 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 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 program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#include <string.h>
/**
* \internal
* \brief We need direct access to elements of struct excenv_t.
*/
#define USE_SCOT_STRUCT_EXCENV_T
/**
* \internal
* \brief We need direct access to elements of struct exception_t.
*/
#define USE_SCOT_STRUCT_EXCEPTION_T
#include <scot/exception.h>
#undef USE_SCOT_STRUCT_EXCENV_T
#undef USE_SCOT_STRUCT_EXCEPTION_T
#include <scot/thread.h> /* for SELF_THREAD and THREAD_T macro */
#include <scot/memory.h> /* for windows threadsafe memory functions */
/**
* \internal
* \brief Don't use exceptions in the list code.
*
* as the code here provides the exception system it is not very wise to
* use exceptions in this code, Thus this define deactivates exception
* support within the code generation macros defined in \link scot/list.h
* scot/list.h\endlink.
*/
#define USE_NO_EXCEPTION
/**
* \internal
* \brief make list functions static for this file.
*
* All list, stack and queue stuff for exception structures is only needed
* here and not very likely to be needed anywhere else in the code.
* Thus generate them static, (said with GEN_LOCAL)
*/
#define GEN_LOCAL
#include <scot/list.h>
#include <scot/stack.h>
#include <scot/queue.h>
#undef GEN_LOCAL
#undef USE_NO_EXCEPTION
#include <scot_common.h>
/************************************************************************
* Generation of typesafe functions to handle lists of the types *
************************************************************************/
GEN_LIST (exception_t);
GEN_QUEUE_FUNC_PROTO (exception_t);
GEN_QUEUE_IMPL (exception_t);
GEN_LIST (excenv_t);
GEN_STACK (excenv_t);
/**
* \internal
* Structure to assign every thread an own exception environment stack.
*/
struct thread_excenv_t
{
THREAD_T thread_handle; /**< Current thread-id */
stack_excenv_t_node_t *ee_stack; /**< The exception environment stack */
};
typedef struct thread_excenv_t thread_excenv_t;
GEN_LIST (thread_excenv_t);
/**
* \internal
* \brief If we use threads this is the root of all exception environments.
*/
list_thread_excenv_t_node_t *tee_list = NULL;
/**
* \internal
* \brief If we don't use threads this is the root of all exception
* environments.
*/
stack_excenv_t_node_t *ee_stack = NULL;
/************************************************************************
* static helper *
************************************************************************/
/**
* \internal
* \param a instance to be compared
* \param b instance to be compared
* \pre None
* \return A value greater than, equal or less than 0 as with strcmp.
* \retval <0 if a->thread_handle is less than b->thread_handle
* \retval >0 if a->thread_handle is greater than b->thread_handle
* \retval ==0 if a->thread_handle is equal to b->thread_handle
* \post None
*
* \brief Comparison for instances of thread_excenv_t.
*
* This is a comparison function for instances of thread_excenv_t. They are
* assumed equal if both thread_excenv_t::thread_handle are equal.
* The function follows the same scheme as for example strcmp.
*/
static
int
compare_thread_excenv_t (const thread_excenv_t *a , const thread_excenv_t *b)
{
return ! THREAD_EQUAL (a->thread_handle, b->thread_handle);
}
/**
* \internal
* \param e an instance of thread_excenv_t
* \pre \a e has to be initialize correctly previous to this call.
* \return Nothing
* \post The memory needed by \a e is correctly freed.
*
* \brief Destructor for thread_excenv_t instances.
*
* This cleanly frees an instance of thread_excenv_t.
*/
static
void
free_thread_excenv_t (thread_excenv_t *e)
{
stack_excenv_t_free (e->ee_stack);
SCOT_MEM_FREE (e);
}
/**
* \internal
* \param e an instance of excenv_t
* \pre \a e has to be initialize correctly previous to this call.
* \return Nothing
* \post The memory needed by \a e is correctly freed.
*
* \brief Destructor for excenv_t instances.
*
* This cleanly frees an instance of excenv_t.
*/
static
void
free_excenv_t (excenv_t *e)
{
queue_exception_t_free (e->e_queue);
SCOT_MEM_FREE (e);
}
/**
* \internal
* \param e an instance of exception_t
* \pre \a e has to be initialize correctly previous to this call.
* \return Nothing
* \post The memory needed by \a e is correctly freed.
*
* \brief Destructor for exception_t instances.
*
* This cleanly frees an instance of exception_t.
*/
static
void
free_exception_t (exception_t * e)
{
SCOT_MEM_FREE (e);
}
/************************************************************************
* interface implementtaion *
************************************************************************/
/**
* \internal
* \pre No threads are used.
* \return Nothing
* \post None
*
* \brief initializes the root of all exception environments for non
* threaded code.
*
* This is called within the TRY, CATCH macros to ensure that the correct
* exception environment stack for the current thread is used.
* \nWell, we don't have threads when this is used, so it just returns
* ee_stack if it has initialized it previously.
*/
void *
exc_init (void)
{
/*
* If threads are used already, use them further on.
* (If there is a threaded_exception list tee_list).
*/
if (tee_list != NULL)
return threaded_exc_init ();
if (ee_stack != NULL)
return (void *) ee_stack;
ee_stack = stack_excenv_t_new (ee_stack);
bindtextdomain (PACKAGE, LOCALEDIR);
if (ee_stack == NULL)
/* FIXME: make output to syslog or something... */
{
char buf[1024];
sprintf (
buf,
"[Fatal(exception.c:97)]\n%s",
D_("exc_init failed"));
perror (buf);
abort ();
}
return (void *) ee_stack;
}
/**
* \internal
* \pre Threads are used.
* \return Nothing
* \post None
*
* \brief initializes the root of all exception environments for non
* threaded code.
*
* This is called within the TRY, CATCH macros to ensure that the correct
* exception environment stack for the current thread is used.
*/
void *
threaded_exc_init (void)
{
list_thread_excenv_t_node_t *tee_l;
thread_excenv_t *tee;
THREAD_T t;
t = SELF_THREAD;
bindtextdomain (PACKAGE, LOCALEDIR);
/*
* First create the list if it does not exist at all and
* set the comparison function.
*/
if (tee_list == NULL)
{
tee_list = list_thread_excenv_t_new (tee_list);
list_thread_excenv_t_set_cmp (compare_thread_excenv_t);
}
/*
* Now a little trick: As i compare thread_excenv_t by comparing its
* first element thread_excenv_t->thread_handle and don't use any other part of
* this struct with a compare i can cast THREAD_T * to thread_excenv_t *
* to check for the existance of an entry in the list.
*/
tee_l = list_thread_excenv_t_find (tee_list, (thread_excenv_t *) &t);
/*
* if tee_l != NULL we have found a previosly initialized stack, good!
* Return the excenv_t we have to use.
*/
if (tee_l != NULL)
return (void *) list_thread_excenv_t_retrive (tee_l)->ee_stack;
/*
* else we must create a new entry.
*/
tee = (thread_excenv_t *) SCOT_MEM_GET (sizeof (struct thread_excenv_t));
if (tee == NULL)
{
char buf[1024];
sprintf (
buf,
"[Fatal(exception.c:97)]\n%s",
D_("exc_init failed, can't get memory for new list element."));
perror (buf);
abort ();
}
tee->thread_handle = SELF_THREAD;
tee->ee_stack = stack_excenv_t_new (tee->ee_stack);
if (tee->ee_stack == NULL)
/* FIXME: make output to syslog or something... */
{
char buf[1024];
sprintf (
buf,
"[Fatal(exception.c:97)]\n%s",
D_("exc_init failed"));
perror (buf);
abort ();
}
list_thread_excenv_t_insert (tee_list, tee);
return (void *) tee->ee_stack;
}
/**
* \internal
* \param ee_s the stack of exception environments for the actual
* thread.
* \pre The root of the exception environments must be initialized
* either by exc_init() (if no threads are used) or by
* threaded_exc_init() (if threads are used).
* \return Nothing
* \post A new exception environment is pushed int the stack of exception
* environment (previously called root sometimes) and thus became
* current.
*
* \brief creates a new exception environment and pushes it into the root.
*/
void
excenv_new (void *ee_s)
{
stack_excenv_t_node_t *ee_stack = (stack_excenv_t_node_t *) ee_s;
excenv_t *ee;
bindtextdomain (PACKAGE, LOCALEDIR);
ee = (excenv_t *) SCOT_MEM_GET (sizeof (excenv_t));
if (ee == NULL)
/* FIXME: make output to syslog or something... */
{
char buf[1024];
sprintf (
buf,
"[Fatal(exception.c:113)]\n%s",
D_("excenv_new failed"));
perror (buf);
abort ();
}
ee->e_queue = queue_exception_t_new (ee->e_queue);
if (ee->e_queue == NULL)
/* FIXME: make output to syslog or something... */
{
char buf[1024];
sprintf (
buf,
"[Fatal(exception.c:121)]\n%s",
D_("excenv_new failed"));
perror (buf);
abort ();
}
if (stack_excenv_t_push (ee_stack, ee) == NULL)
{
char *errmsg;
char buf[1024];
errmsg = strerror (errno);
stack_excenv_t_free (ee_stack);
SCOT_MEM_FREE (ee);
sprintf (
buf,
"[FATAL(exception.c:101)]\n%s%s",
D_("could not push the new excenv_t "
"into ee_stack:\n"),
errmsg);
fprintf (stderr, buf);
abort ();
}
}
/**
* \internal
* \param ee_s the stack of exception environments for the actual
* thread.
* \pre The root of the exception environments must be initialized
* either by exc_init() (if no threads are used) or by
* threaded_exc_init() (if threads are used).
* There must be an actual exception environment into the stack
* of exception environments.
* \return a pointer to the jmp_buf variable of the current exception
* environment.
* \post None
*
* \brief This returns a pointer to the jmp_buf variable of the current
* exception environment.
*
* A pointer to the jmp_buf variable of the current exception environment is
* returned for use by the setjmp call in TRY. I tried to call setjmp directly
* here, but that causes confusion when TRY-CATCH blocks are nested.
*/
jmp_buf *
excenv_jmp_buf (void *ee_s)
{
stack_excenv_t_node_t *ee_stack = (stack_excenv_t_node_t *) ee_s;
excenv_t *ee;
ee = stack_excenv_t_top (ee_stack);
if (ee == NULL)
{
fprintf (
stderr,
D_("invalid exception environment\n"));
abort ();
}
return & (ee->env);
}
/**
* \internal
* \param ee_s the stack of exception environments for the actual
* thread.
* \param e the exception to be thrown.
* \pre The root of the exception environments must be initialized
* either by exc_init() (if no threads are used) or by
* threaded_exc_init() (if threads are used).
* There must be an actual exception environment into the stack
* of exception environments.
* \return Nothing
* \post A new exception is stored within the actual exception environment.
*
* \brief The implementation of the THROW macro.
*
* This stores a new exception within the actual exception environment.
*/
void
exc_throw (void *ee_s, const exception_t *e)
{
stack_excenv_t_node_t *ee_stack = (stack_excenv_t_node_t *) ee_s;
excenv_t *ee;
bindtextdomain (PACKAGE, LOCALEDIR);
/* get the actual excenv */
ee = stack_excenv_t_top (ee_stack);
if (ee == NULL)
{
char buf[1024];
sprintf (
buf,
D_("any code that THROWs exeptions has to be\n"
"%s within a TRY block\n"),
" ");
fprintf (
stderr,
"[Fatal(exception.c:200)]\n%s",
buf);
abort ();
}
queue_exception_t_enqueue (ee->e_queue, e);
if (e->lvl == EXC_ERROR && e->was_catched == 0)
longjmp (ee->env, 1);
}
/**
* \internal
* \param ee_s the stack of exception environments for the actual
* thread.
* \pre The root of the exception environments must be initialized
* either by exc_init() (if no threads are used) or by
* threaded_exc_init() (if threads are used).
* There must be an actual exception environment into the stack
* of exception environments.
* \return The current exception environment.
* \post The current exception environment is removed from the stack, thus
* making the next one on the stack to the current exception
* environment.
*
* \brief Get the current exception environment.
*
* The is the core of the CATCH() macro. It retrieves the actual exception
* environment from the stack of exception environments and returns it. The
* actual exception environment is removed from the stack.
*/
excenv_t *
excenv_catch (void *ee_s)
{
stack_excenv_t_node_t *ee_stack = (stack_excenv_t_node_t *) ee_s;
excenv_t *ee;
bindtextdomain (PACKAGE, LOCALEDIR);
ee = stack_excenv_t_pop (ee_stack);
if (ee == NULL)
{
char buf[1024];
sprintf (
buf,
"[Fatal(exception.c:177)]\n%s",
D_("use of CATCH with no previous TRY"));
perror (buf);
abort ();
}
return ee;
}
/**
* \param ee The exception environment to be checked.
* \pre \a ee must be a valid exception environment.
* \return Boolean wether \a ee has exceptions or not.
* \retval ==0 there are no exceptions
* \retval !=0 there are exceptions
* \post None
*
* \brief Check for existent exceptions.
*
* This checks the given exception environment \a ee for existent
* exceptions.
*/
int
excenv_has_exception (const excenv_t *ee)
{
return ! list_exception_t_isempty (
(list_exception_t_node_t *)ee->e_queue);
}
/**
* \param lvl either ERROR or WARNING
* \param file the file where the exception was created.
* \param line the line in that file.
* \param errnum an identifier of the exception. This might be
* dublicated as it is normally just used as an
* index for the error message. So rely only on this
* if you check only a special kind of error.
* \param err_msg a string describing what happens.
* \pre None
* \return The newly created exception.
* \post None
*
* \brief Creates a new exception.
*
* This creates a new exception. Normally this function is called
* through the EXC() macro which fills in file and line automatically
* by using __FILE__ and __LINE__ but sometimes it is desirable to
* have direct control over those to values too. (For example with
* the templates of list functions.)
*/
exception_t *
exc_new (
const enum exclvl_t lvl,
const char *file,
const int line,
const int errnum,
const char *err_msg)
{
exception_t *e;
bindtextdomain (PACKAGE, LOCALEDIR);
e = (exception_t *) SCOT_MEM_GET (sizeof (exception_t));
if (e == NULL)
/* FIXME: make output to syslog or something... */
{
char buf[1024];
sprintf (
buf,
"[Fatal(exception.c:220)]\n%s",
D_("exc_new failed"));
perror (buf);
abort ();
}
/* This one time we write to lvl and id */
e->was_catched = 0;
* (enum exclvl_t *) & e->lvl = lvl;
e->file = file;
* (int *) & e->line = line;
* (int *) & e->errnum = errnum;
e->err_msg = err_msg;
return e;
}
/**
* \param ee The exception environment to be used.
* \pre \a ee must be a valid exception environment.
* \return The dequeued exception.
* \post The exception is removed from \a ee.
*
* \brief Get the actual exception.
*
* This dequeues the the next exception from the exception environment and
* returns it.
*/
exception_t *
retrive_exception (const excenv_t *ee)
{
exception_t *e;
e = queue_exception_t_dequeue (ee->e_queue);
if (e != NULL)
e->was_catched += 1;
return e;
}
/**
* \param ee The exception environment to be used.
* \pre Must be in a CATCH Block. So the exception environment is already
* removed from the stack of exception environments and only
* accessed by \a ee.
* \return Nothing
* \post All memory accessed over \a ee is freed, this includes all
* exceptions within it.
*
* \brief Frees the actually catched exception environment.
*/
void free_catched (excenv_t *ee)
{
free_excenv_t (ee);
}
/**
* \param e The exception to be used.
* \pre It is desirable to remove the exception first from the
* exception stack it is in, to keep from problems.
* \return Nothing
* \post All memory accessed over \a e is freed.
*
* \brief Frees an exception.
*/
void
free_exception (exception_t *e)
{
free_exception_t (e);
}
/**
* \pre None
* \return Nothing
* \post all memory allocated for any exception handling in the current
* thread is feed.
*
* \brief Ends exception handling for the actual thread.
*
* This should be called before ending a thread to avoid memory leaks.
*/
void
exc_end (void)
{
excenv_t *ee;
list_exception_t_set_elem_free (free_exception_t);
list_excenv_t_set_elem_free (free_excenv_t);
if (tee_list == NULL)
{
stack_excenv_t_free (ee_stack);
}
else
{
thread_exc_end (SELF_THREAD);
}
list_exception_t_set_elem_free (NULL);
list_excenv_t_set_elem_free (NULL);
}
void
thread_exc_end (THREAD_T t)
{
list_thread_excenv_t_node_t *tee_l;
list_exception_t_set_elem_free (free_exception_t);
list_excenv_t_set_elem_free (free_excenv_t);
list_thread_excenv_t_set_elem_free (free_thread_excenv_t);
tee_l = list_thread_excenv_t_find (tee_list, (thread_excenv_t *) &t);
list_thread_excenv_t_delete (tee_l);
/*
* well, maybe this has to have some syncronization with
* threaded_exc_init or i make a function exc_fini, that
* does this final step and should only be called in the
* main thread.
*/
if (list_thread_excenv_t_isempty (tee_list))
list_thread_excenv_t_free (tee_list);
list_thread_excenv_t_set_elem_free (NULL);
list_exception_t_set_elem_free (NULL);
list_excenv_t_set_elem_free (NULL);
}
/**
* \pre \a e must be a valid exception.
* \return Nothing
* \post \a e is freed.
*
* \brief Prints out the exception and frees it after that.
*/
void
print_exception (exception_t * e)
{
fprintf (
stderr,
"[%s(%s:%d)]\n(%d) %s\n",
(e->lvl==EXC_ERROR)?D_("ERROR"):D_("WARNING"),
e->file,
e->line,
e->errnum,
e->err_msg);
/* no more free at print...this is not intuitive usable. */
/* free_exception (e); */
}
/**
* \pre \a ee must be a valid exception environment.
* \return Nothing
* \post \a ee is freed.
*
* \brief Prints out all exceptions and frees them after that.
*
* This prints out all exception one by one using print_exception()
* and after that frees also the exception environment \a ee.
*/
void
print_all_exceptions (excenv_t *ee)
{
exception_t *e;
e = retrive_exception (ee);
while (e != NULL)
{
print_exception (e);
e = retrive_exception (ee);
}
free_catched (ee);
}
/**
* \param ee the exception environment to be used.
* \pre \a ee must be a valid exception environment.\n
* There must be at least one exception environment left in the
* stack of exception environments.
* \return Nothing
* \post All exception within \a ee are in the actual exception environment.
*
* \brief Forwards all exceptions in \a ee to the actual
* exception environment.
*
* This did not free any exception but throw the from \a ee into the
* actual exception environment.
*/
void
forward_all_exceptions (excenv_t *ee)
{
exception_t *e;
excenv_t *_ee;
if (tee_list != NULL)
/* we use threads */
_ee = threaded_exc_init ();
else
/* we don't use threads */
_ee = exc_init ();
e = retrive_exception (ee);
while (e != NULL)
{
exc_throw (_ee, e);
e = retrive_exception (ee);
}
free_catched (ee);
}
/**
* \param e the exception to be checked.
* \pre \a e must be a valid exception.
* \return Boolean indicating if the exception was thrown within the
* actual exception environment or just be forwarded from another one.
* \retval ==0 the exception was forwarded.
* \retval !=0 the exception was thrown.
* \post None
*
* \brief Checks wether \a e was thrown or forwarded.
*/
int
exc_in_this_try (exception_t *e)
{
return e->was_catched == 1;
}
/************************************************************************
* exception getter *
************************************************************************/
enum exclvl_t
exc_lvl_get (exception_t *e)
{
return e->lvl;
}
int
exc_errnum_get (exception_t *e)
{
return e->errnum;
}
char *
exc_err_msg_get (exception_t *e)
{
return (char *) e->err_msg;
}
char *
exc_file_get (exception_t *e)
{
return (char *) e->file;
}
int
exc_line_get (exception_t *e)
{
return e->line;
}