1 /*
2  * This was the cpl_exceptions.i code.  But since python is the only one
3  * different (should support old method as well as new one)
4  * it was moved into this file.
5  */
6 %{
7 static int bUseExceptions=0;
8 static CPLErrorHandler pfnPreviousHandler = CPLDefaultErrorHandler;
9 
10 static void CPL_STDCALL
PythonBindingErrorHandler(CPLErr eclass,int code,const char * msg)11 PythonBindingErrorHandler(CPLErr eclass, int code, const char *msg )
12 {
13   /*
14   ** Generally we want to suppress error reporting if we have exceptions
15   ** enabled as the error message will be in the exception thrown in
16   ** Python.
17   */
18 
19   /* If the error class is CE_Fatal, we want to have a message issued
20      because the CPL support code does an abort() before any exception
21      can be generated */
22   if (eclass == CE_Fatal ) {
23     pfnPreviousHandler(eclass, code, msg );
24   }
25 
26   /*
27   ** We do not want to interfere with non-failure messages since
28   ** they won't be translated into exceptions.
29   */
30   else if (eclass != CE_Failure ) {
31     pfnPreviousHandler(eclass, code, msg );
32   }
33   else {
34     CPLSetThreadLocalConfigOption("__last_error_message", msg);
35     CPLSetThreadLocalConfigOption("__last_error_code", CPLSPrintf("%d", code));
36   }
37 }
38 %}
39 
40 %inline %{
41 
42 static
GetUseExceptions()43 int GetUseExceptions() {
44   CPLErrorReset();
45   return bUseExceptions;
46 }
47 
48 static
UseExceptions()49 void UseExceptions() {
50   CPLErrorReset();
51   if( !bUseExceptions )
52   {
53     bUseExceptions = 1;
54     char* pszNewValue = CPLStrdup(CPLSPrintf("%s %s",
55                    MODULE_NAME,
56                    CPLGetConfigOption("__chain_python_error_handlers", "")));
57     CPLSetConfigOption("__chain_python_error_handlers", pszNewValue);
58     CPLFree(pszNewValue);
59     // if the previous logger was custom, we need the user data available
60     pfnPreviousHandler =
61         CPLSetErrorHandlerEx( (CPLErrorHandler) PythonBindingErrorHandler, CPLGetErrorHandlerUserData() );
62   }
63 }
64 
65 static
DontUseExceptions()66 void DontUseExceptions() {
67   CPLErrorReset();
68   if( bUseExceptions )
69   {
70     const char* pszValue = CPLGetConfigOption("__chain_python_error_handlers", "");
71     if( strncmp(pszValue, MODULE_NAME, strlen(MODULE_NAME)) != 0 ||
72         pszValue[strlen(MODULE_NAME)] != ' ')
73     {
74         CPLError(CE_Failure, CPLE_NotSupported,
75                  "Cannot call %s.DontUseExceptions() at that point since the "
76                  "stack of error handlers is: %s", MODULE_NAME, pszValue);
77         return;
78     }
79     char* pszNewValue = CPLStrdup(pszValue + strlen(MODULE_NAME) + 1);
80     if( pszNewValue[0] == ' ' && pszNewValue[1] == '\0' )
81     {
82         CPLFree(pszNewValue);
83         pszNewValue = NULL;
84     }
85     CPLSetConfigOption("__chain_python_error_handlers", pszNewValue);
86     CPLFree(pszNewValue);
87     bUseExceptions = 0;
88     // if the previous logger was custom, we need the user data available. Preserve it.
89     CPLSetErrorHandlerEx( pfnPreviousHandler, CPLGetErrorHandlerUserData());
90   }
91 }
92 %}
93 
94 %{
95 /* Completely unrelated: just to avoid Coverity warnings */
96 
97 static int bReturnSame = 1;
98 
NeverCallMePlease()99 void NeverCallMePlease() {
100     bReturnSame = 0;
101 }
102 
103 /* Some SWIG code generates dead code, which Coverity warns about */
ReturnSame(T x)104 template<class T> static T ReturnSame(T x)
105 {
106     if( bReturnSame )
107         return x;
108     return 0;
109 }
110 
ClearErrorState()111 static void ClearErrorState()
112 {
113     CPLSetThreadLocalConfigOption("__last_error_message", NULL);
114     CPLSetThreadLocalConfigOption("__last_error_code", NULL);
115     CPLErrorReset();
116 }
117 
118 static void StoreLastException() CPL_UNUSED;
119 
120 // Note: this is also copy&pasted in gdal_array.i
StoreLastException()121 static void StoreLastException()
122 {
123     const char* pszLastErrorMessage =
124         CPLGetThreadLocalConfigOption("__last_error_message", NULL);
125     const char* pszLastErrorCode =
126         CPLGetThreadLocalConfigOption("__last_error_code", NULL);
127     if( pszLastErrorMessage != NULL && pszLastErrorCode != NULL )
128     {
129         CPLErrorSetState( CE_Failure,
130             static_cast<CPLErrorNum>(atoi(pszLastErrorCode)),
131             pszLastErrorMessage);
132     }
133 }
134 
135 %}
136 
137 %include exception.i
138 
139 %exception {
140 
141     if ( bUseExceptions ) {
142         ClearErrorState();
143     }
144     $action
145 %#ifndef SED_HACKS
146     if ( bUseExceptions ) {
147       CPLErr eclass = CPLGetLastErrorType();
148       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
149         SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
150       }
151     }
152 %#endif
153 }
154 
155 %feature("except") Open {
156     if ( bUseExceptions ) {
157         ClearErrorState();
158     }
159     $action
160 %#ifndef SED_HACKS
161     if( result == NULL && bUseExceptions ) {
162       CPLErr eclass = CPLGetLastErrorType();
163       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
164         SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
165       }
166     }
167 %#endif
168     if( result != NULL && bUseExceptions ) {
169         StoreLastException();
170 %#ifdef SED_HACKS
171         bLocalUseExceptionsCode = FALSE;
172 %#endif
173     }
174 }
175 
176 %feature("except") OpenShared {
177     if ( bUseExceptions ) {
178         ClearErrorState();
179     }
180     $action
181 %#ifndef SED_HACKS
182     if( result == NULL && bUseExceptions ) {
183       CPLErr eclass = CPLGetLastErrorType();
184       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
185         SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
186       }
187     }
188 %#endif
189     if( result != NULL && bUseExceptions ) {
190         StoreLastException();
191 %#ifdef SED_HACKS
192         bLocalUseExceptionsCode = FALSE;
193 %#endif
194     }
195 }
196 
197 %feature("except") OpenEx {
198     if ( bUseExceptions ) {
199         ClearErrorState();
200     }
201     $action
202 %#ifndef SED_HACKS
203     if( result == NULL && bUseExceptions ) {
204       CPLErr eclass = CPLGetLastErrorType();
205       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
206         SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
207       }
208     }
209 %#endif
210     if( result != NULL && bUseExceptions ) {
211         StoreLastException();
212 %#ifdef SED_HACKS
213         bLocalUseExceptionsCode = FALSE;
214 %#endif
215     }
216 }
217