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