1 /* -*- Mode: C -*-
2   ======================================================================
3   FILE: icalerror.c
4   CREATOR: eric 16 May 1999
5 
6   $Id: icalerror.c,v 1.22 2008-01-15 23:17:40 dothebart Exp $
7   $Locker:  $
8 
9 
10  (C) COPYRIGHT 2000, Eric Busboom <eric@softwarestudio.org>
11      http://www.softwarestudio.org
12 
13  This program is free software; you can redistribute it and/or modify
14  it under the terms of either:
15 
16     The LGPL as published by the Free Software Foundation, version
17     2.1, available at: http://www.fsf.org/copyleft/lesser.html
18 
19   Or:
20 
21     The Mozilla Public License Version 1.0. You may obtain a copy of
22     the License at http://www.mozilla.org/MPL/
23 
24   The original code is icalerror.c
25 
26  ======================================================================*/
27 
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #ifdef HAVE_BACKTRACE
34 #include <execinfo.h>
35 #endif
36 
37 #include <stdlib.h>		/* for malloc() */
38 #include <string.h>		/* for strcmp */
39 #include "icalerror.h"
40 
41 #ifdef HAVE_PTHREAD
42 #include <pthread.h>
43 
44 static pthread_key_t  icalerrno_key;
45 static pthread_once_t icalerrno_key_once = PTHREAD_ONCE_INIT;
46 
icalerrno_destroy(void * buf)47 static void icalerrno_destroy(void* buf) {
48   free(buf);
49   pthread_setspecific(icalerrno_key, NULL);
50 }
51 
icalerrno_key_alloc(void)52 static void icalerrno_key_alloc(void) {
53   pthread_key_create(&icalerrno_key, icalerrno_destroy);
54 }
55 
icalerrno_return(void)56 icalerrorenum *icalerrno_return(void) {
57   icalerrorenum *_errno;
58 
59   pthread_once(&icalerrno_key_once, icalerrno_key_alloc);
60 
61   _errno = (icalerrorenum*) pthread_getspecific(icalerrno_key);
62 
63   if (!_errno) {
64     _errno = malloc(sizeof(icalerrorenum));
65     *_errno = ICAL_NO_ERROR;
66     pthread_setspecific(icalerrno_key, _errno);
67   }
68   return _errno;
69 }
70 
71 #else
72 
73 static icalerrorenum icalerrno_storage = ICAL_NO_ERROR;
74 
icalerrno_return(void)75 icalerrorenum *icalerrno_return(void) {
76    return &icalerrno_storage;
77 }
78 
79 #endif
80 
81 
82 static int foo;
83 
icalerror_stop_here(void)84 void icalerror_stop_here(void)
85 {
86     foo++; /* Keep optimizers from removing routine */
87 }
88 
icalerror_crash_here(void)89 void icalerror_crash_here(void)
90 {
91     int *p=0;
92     *p = 1;
93 
94     assert( *p);
95 }
96 
97 #ifdef ICAL_SETERROR_ISFUNC
icalerror_set_errno(icalerrorenum x)98 void icalerror_set_errno(icalerrorenum x)
99 {
100     icalerrno = x;
101     if(icalerror_get_error_state(x)==ICAL_ERROR_FATAL ||
102        (icalerror_get_error_state(x)==ICAL_ERROR_DEFAULT &&
103         icalerror_errors_are_fatal == 1 )){
104         icalerror_warn(icalerror_strerror(x));
105 	ical_bt();
106         assert(0);
107     }
108 
109 }
110 #endif
111 
icalerror_clear_errno()112 void icalerror_clear_errno() {
113 
114     icalerrno = ICAL_NO_ERROR;
115 }
116 
117 #if ICAL_ERRORS_ARE_FATAL == 1
118 int icalerror_errors_are_fatal = 1;
119 #else
120 int icalerror_errors_are_fatal = 0;
121 #endif
122 
123 struct icalerror_state {
124     icalerrorenum error;
125     icalerrorstate state;
126 };
127 
128 static struct icalerror_state error_state_map[] =
129 {
130     { ICAL_BADARG_ERROR,ICAL_ERROR_DEFAULT},
131     { ICAL_NEWFAILED_ERROR,ICAL_ERROR_DEFAULT},
132     { ICAL_ALLOCATION_ERROR,ICAL_ERROR_DEFAULT},
133     { ICAL_MALFORMEDDATA_ERROR,ICAL_ERROR_DEFAULT},
134     { ICAL_PARSE_ERROR,ICAL_ERROR_DEFAULT},
135     { ICAL_INTERNAL_ERROR,ICAL_ERROR_DEFAULT},
136     { ICAL_FILE_ERROR,ICAL_ERROR_DEFAULT},
137     { ICAL_USAGE_ERROR,ICAL_ERROR_DEFAULT},
138     { ICAL_UNIMPLEMENTED_ERROR,ICAL_ERROR_DEFAULT},
139     { ICAL_UNKNOWN_ERROR,ICAL_ERROR_DEFAULT},
140     { ICAL_NO_ERROR,ICAL_ERROR_DEFAULT}
141 
142 };
143 
144 struct icalerror_string_map {
145     const char* str;
146     icalerrorenum error;
147     char name[160];
148 };
149 
150 static const struct icalerror_string_map string_map[] =
151 {
152     {"BADARG",ICAL_BADARG_ERROR,"BADARG: Bad argument to function"},
153     { "NEWFAILED",ICAL_NEWFAILED_ERROR,"NEWFAILED: Failed to create a new object via a *_new() routine"},
154     { "ALLOCATION",ICAL_ALLOCATION_ERROR,"ALLOCATION: Failed to allocate new memory"},
155     {"MALFORMEDDATA",ICAL_MALFORMEDDATA_ERROR,"MALFORMEDDATA: An input string was not correctly formed or a component has missing or extra properties"},
156     { "PARSE",ICAL_PARSE_ERROR,"PARSE: Failed to parse a part of an iCal component"},
157     {"INTERNAL",ICAL_INTERNAL_ERROR,"INTERNAL: Random internal error. This indicates an error in the library code, not an error in use"},
158     { "FILE",ICAL_FILE_ERROR,"FILE: An operation on a file failed. Check errno for more detail."},
159     { "USAGE",ICAL_USAGE_ERROR,"USAGE: Failed to propertyl sequence calls to a set of interfaces"},
160     { "UNIMPLEMENTED",ICAL_UNIMPLEMENTED_ERROR,"UNIMPLEMENTED: This feature has not been implemented"},
161     { "NO",ICAL_NO_ERROR,"NO: No error"},
162     {"UNKNOWN",ICAL_UNKNOWN_ERROR,"UNKNOWN: Unknown error type -- icalerror_strerror() was probably given bad input"}
163 };
164 
165 
icalerror_error_from_string(const char * str)166 icalerrorenum icalerror_error_from_string(const char* str){
167     int i;
168 
169     for( i = 0; string_map[i].error != ICAL_UNKNOWN_ERROR; i++)
170         if (strcmp(string_map[i].str,str) == 0)
171 	    break;
172 
173     return string_map[i].error;
174 }
175 
icalerror_supress(const char * error)176 icalerrorstate icalerror_supress(const char* error){
177 
178     icalerrorenum e = icalerror_error_from_string(error);
179     icalerrorstate es;
180 
181      if (e == ICAL_NO_ERROR){
182         return ICAL_ERROR_UNKNOWN;
183     }
184 
185 
186     es = icalerror_get_error_state(e);
187     icalerror_set_error_state(e,ICAL_ERROR_NONFATAL);
188 
189     return es;
190 }
191 
icalerror_perror(void)192 const char* icalerror_perror(void)
193 {
194     return icalerror_strerror(icalerrno);
195 }
196 
icalerror_restore(const char * error,icalerrorstate es)197 void icalerror_restore(const char* error, icalerrorstate es){
198 
199 
200     icalerrorenum e = icalerror_error_from_string(error);
201 
202     if (e != ICAL_NO_ERROR){
203         icalerror_set_error_state(e,es);
204     }
205 
206 }
207 
208 
209 
icalerror_set_error_state(icalerrorenum error,icalerrorstate state)210 void icalerror_set_error_state( icalerrorenum error,
211 				icalerrorstate state)
212 {
213     int i;
214 
215     for(i = 0; error_state_map[i].error!= ICAL_NO_ERROR;i++){
216 	if(error_state_map[i].error == error){
217 	    error_state_map[i].state = state;
218 	}
219     }
220 }
221 
icalerror_get_error_state(icalerrorenum error)222 icalerrorstate icalerror_get_error_state( icalerrorenum error)
223 {
224     int i;
225 
226     for(i = 0; error_state_map[i].error!= ICAL_NO_ERROR;i++){
227 	if(error_state_map[i].error == error){
228 	    return error_state_map[i].state;
229 	}
230     }
231 
232     return ICAL_ERROR_UNKNOWN;
233 }
234 
235 
236 
237 
icalerror_strerror(icalerrorenum e)238 const char* icalerror_strerror(icalerrorenum e) {
239 
240     int i;
241 
242     for (i=0; string_map[i].error != ICAL_UNKNOWN_ERROR; i++) {
243 	if (string_map[i].error == e) {
244 	    return string_map[i].name;
245 	}
246     }
247 
248     return string_map[i].name; /* Return string for ICAL_UNKNOWN_ERROR*/
249 
250 }
251 
252 
ical_bt(void)253 void ical_bt(void)
254 {
255 #ifdef HAVE_BACKTRACE
256         void *stack_frames[50];
257         size_t size, i;
258         char **strings;
259 
260         size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
261         strings = backtrace_symbols(stack_frames, size);
262         for (i = 0; i < size; i++) {
263                 if (strings != NULL)
264                         fprintf(stderr, "%s\n", strings[i]);
265                 else
266                         fprintf(stderr, "%p\n", stack_frames[i]);
267         }
268         free(strings);
269 #endif
270 }
271 
272