1 /*++
2 
3 Copyright (c) 2004, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution.  The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8 
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 Module Name:
13 
14   Exceptions.c
15 
16 Abstract:
17 
18   Exception logging routines.
19 
20 --*/
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h> // for memset()
25 #include "Exceptions.h"
26 
27 //
28 // Max length of a saved exception message
29 //
30 #define MAX_EXCEPTION_MSG 200
31 
32 //
33 // We use this structure to track exceptions thrown. We nest deeper on
34 // TryException() calls, and come back out on CatchException() calls.
35 // We save off the first exception message for a given exception level,
36 // but we save the count of how many were thrown.
37 //
38 typedef struct {
39   int   ExceptionCount;
40   char  ExceptionMsg[MAX_EXCEPTION_MSG];
41 } EXCEPTION_LOG;
42 
43 static EXCEPTION_LOG  ExceptionLog[MAX_EXCEPTION_NESTING + 1];
44 static int            ExceptionLevel;
45 
46 //
47 // Initialize our data and structures for tracking exceptions.
48 //
49 int
InitExceptions(VOID)50 InitExceptions (
51   VOID
52   )
53 {
54   ExceptionLevel = -1;
55   memset ((char *) &ExceptionLog, 0, sizeof (ExceptionLog));
56   return 0;
57 }
58 //
59 // This function replaces the _try() exception macro. It sets the
60 // nesting level.
61 //
62 int
TryException(VOID)63 TryException (
64   VOID
65   )
66 {
67   //
68   // Boost our exception level if we would not go out of range
69   //
70   ExceptionLevel++;
71   if (ExceptionLevel >= MAX_EXCEPTION_NESTING) {
72     fprintf (stderr, "ERROR: Max exception nesting level exceeded\n");
73     ExceptionLevel--;
74     return 1;
75   }
76 
77   return 0;
78 }
79 //
80 // This function replaces the _catch() exception macro. It's used to decrement
81 // the nesting level and return any exeption error messages that were
82 // thrown at the current nesting level.
83 //
84 char *
CatchException(VOID)85 CatchException (
86   VOID
87   )
88 {
89   //
90   // Return a pointer to exception message. NULL if no exceptions at this level
91   //
92   if (ExceptionLevel >= 0) {
93     ExceptionLevel--;
94     if (ExceptionLog[ExceptionLevel + 1].ExceptionMsg[0]) {
95       return ExceptionLog[ExceptionLevel + 1].ExceptionMsg;
96     } else {
97       return NULL;
98     }
99   } else {
100     fprintf (stderr, "ERROR: Invalid nesting level call to CatchException()\n");
101     return NULL;
102   }
103 }
104 //
105 // This function can be used to test for exceptions between the TryException()
106 // and CatchException() calls in a given function.
107 //
108 int
ExceptionThrown(VOID)109 ExceptionThrown (
110   VOID
111   )
112 {
113   return ExceptionLog[ExceptionLevel].ExceptionCount;
114 }
115 //
116 // This function replaces the _throw() exception macro. It saves off the
117 // given error message at the current exeption level nesting.
118 //
119 int
ThrowException(char * Msg)120 ThrowException (
121   char *Msg
122   )
123 {
124   if (ExceptionLevel < 0) {
125     //
126     // fprintf (stderr, "ERROR: Exception thrown out of scope");
127     // Haven't yet enabled handling of exceptions, so just emit the message.
128     //
129     fprintf (stderr, Msg);
130     return 1;
131   }
132   //
133   // Only log the first
134   //
135   if (ExceptionLog[ExceptionLevel].ExceptionMsg[0] == 0) {
136     strncpy (ExceptionLog[ExceptionLevel].ExceptionMsg, Msg, MAX_EXCEPTION_MSG);
137   }
138 
139   ExceptionLog[ExceptionLevel].ExceptionCount++;
140   return 0;
141 }
142