[misc] Remove redundant error codes.
[vsc-common.git] / misc / error.c
1 /*
2  * error.c: Library of miscellaneous stuff for other libvsc* libraries
3  *
4  * Copyright (C) 2009 Matthias Bolte <matthias.bolte@googlemail.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
19  */
20
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25
26 #include "../include/libvscmisc/assert.h"
27 #include "../include/libvscmisc/error.h"
28 #include "../include/libvscmisc/list.h"
29 #include "../include/libvscmisc/memory.h"
30
31 #define _ERROR__MESSAGE_SIZE 4096
32
33 static const char *_error_default_message =
34    "Could not allocate memory for error message";
35
36 static struct VscError _error_default = {
37         .next = NULL,
38         .occured = TRUE,
39         .code = VSC__ERROR_CODE__OUT_OF_MEMORY,
40         .message = NULL,
41         .file = "none",
42         .line = -1,
43         .function = "none",
44 };
45
46 static void
47 _error_report_v (struct VscError *error, enum VscErrorCode code,
48                  const char *file, int line, const char *function,
49                  const char *message, va_list args)
50 {
51         VSC__ASSERT (error != NULL);
52         VSC__ASSERT (! error->occured);
53         VSC__ASSERT (error->message == NULL);
54         VSC__ASSERT (code != VSC__ERROR_CODE__UNDEFINED);
55
56         error->occured = TRUE;
57         error->code = code;
58         error->file = file;
59         error->line = line;
60         error->function = function;
61
62         if (message == NULL) {
63                 error->message = NULL;
64         } else {
65                 error->message = calloc (1, _ERROR__MESSAGE_SIZE);
66
67                 if (error->message == NULL) {
68                         error->message = (char *) _error_default_message;
69                 } else {
70                         vsnprintf (error->message, _ERROR__MESSAGE_SIZE, message, args);
71                 }
72         }
73
74         gettimeofday (&error->timestamp, NULL);
75 }
76
77 const char *
78 vsc_error_string (enum VscErrorCode code)
79 {
80         switch (code) {
81         case VSC__ERROR_CODE__INTERNAL_ERROR:
82                 return "Internal error";
83
84         case VSC__ERROR_CODE__OUT_OF_MEMORY:
85                 return "Out of memory";
86
87         case VSC__ERROR_CODE__XMLRPC_ERROR:
88                 return "XML-RPC error";
89
90         case VSC__ERROR_CODE__PTHREAD_ERROR:
91                 return "Pthread error";
92
93         case VSC__ERROR_CODE__LIBVIRT_ERROR:
94                 return "Libvirt error";
95
96         case VSC__ERROR_CODE__INVALID_ARGUMENT:
97                 return "Invalid argument";
98
99         case VSC__ERROR_CODE__INVALID_CALL:
100                 return "Invalid call";
101
102         case VSC__ERROR_CODE__NOT_INITIALIZED:
103                 return "Not initialized";
104
105         case VSC__ERROR_CODE__NOT_IMPLEMENTED_YET:
106                 return "Not implemented yet";
107
108         case VSC__ERROR_CODE__ERRNO:
109                 return "errno";
110
111         case VSC__ERROR_CODE__TRACE:
112                 return "Inherited error";
113
114         default:
115                 return "Undefined";
116         }
117 }
118
119 void
120 vsc_error_fprint (struct VscError *error, FILE *stream)
121 {
122         struct tm time_info;
123         struct VscError *error_next = NULL;
124
125         VSC__ASSERT (error != NULL);
126         VSC__ASSERT (error->occured);
127         VSC__ASSERT (stream != NULL);
128
129         if (! error->occured) {
130                 return;
131         }
132
133         localtime_r (&error->timestamp.tv_sec, &time_info);
134
135         fprintf (stream, "%02d:%02d:%02d.%03d %s:%d %s : error [%s]",
136                  time_info.tm_hour, time_info.tm_min, time_info.tm_sec,
137                  (int) error->timestamp.tv_usec / 1000, error->file,
138                  error->line, error->function,
139                  vsc_error_string (error->code));
140
141         if (error->message != NULL) {
142                 fprintf (stream, " %s\n", error->message);
143         } else {
144                 fprintf (stream, "\n");
145         }
146
147         for (error_next = error->next; error_next != NULL;
148              error_next = error_next->next) {
149                 fprintf (stream, "             %s:%d %s : error [%s]",
150                          error_next->file, error_next->line, error_next->function,
151                          vsc_error_string (error_next->code));
152
153                 if (error_next->message != NULL) {
154                         fprintf (stream, " %s\n", error_next->message);
155                 } else {
156                         fprintf (stream, "\n");
157                 }
158         }
159 }
160
161 void
162 vsc_error_init (struct VscError *error)
163 {
164         VSC__ASSERT (error != NULL);
165
166         error->next = NULL;
167         error->occured = FALSE;
168         error->code = VSC__ERROR_CODE__UNDEFINED;
169         error->file = NULL;
170         error->line = -1;
171         error->function = NULL;
172         error->message = NULL;
173
174         memset (&error->timestamp, 0, sizeof (struct timeval));
175 }
176
177 void
178 vsc_error_cleanup (struct VscError *error)
179 {
180         struct VscError *current;
181         struct VscError *next;
182
183         VSC__ASSERT (error != NULL);
184
185         if (error->message != _error_default_message) {
186                 vsc_free (&error->message);
187         } else {
188                 error->message = NULL;
189         }
190
191         /*
192          * Free the error list messages if they are allocated (not the default
193          * error message) and free the error structs too, if they are allocated
194          * (not the default error). But do not free the first element of the list
195          * because we do not "own" its memory.
196          */
197         current = error->next;
198
199         while (current != NULL) {
200                 next = current->next;
201
202                 if (current->message != _error_default_message) {
203                         vsc_free (&current->message);
204                 } else {
205                         current->message = NULL;
206                 }
207
208                 if (current != &_error_default) {
209                         vsc_free (&current);
210                 }
211
212                 current = next;
213         }
214 }
215
216 void
217 vsc_error_report (struct VscError *error, enum VscErrorCode code,
218                   const char *file, int line, const char *function,
219                   const char *message, ...)
220 {
221         va_list args;
222
223         va_start (args, message);
224         _error_report_v (error, code, file, line, function, message, args);
225         va_end (args);
226 }
227
228 void
229 vsc_error_append_report (struct VscError *error, enum VscErrorCode code,
230                          const char *file, int line, const char *function,
231                          const char *message, ...)
232 {
233         va_list args;
234         struct VscError *error_last;
235         struct VscError *error_next;
236
237         VSC__ASSERT (error != NULL);
238         VSC__ASSERT (error->occured);
239         VSC__ASSERT (code != VSC__ERROR_CODE__UNDEFINED);
240
241         error_last = (struct VscError *)
242                         vsc_list_get_last ((struct VscList *) error);
243
244         /*
245          * Do not append to the default error, because if it is appended we are
246          * already in an out-of-memory situation.
247          */
248         if (error_last == &_error_default) {
249                 return;
250         }
251
252         error_next = calloc (1, sizeof (struct VscError));
253
254         if (error_next == NULL) {
255                 error_next = &_error_default;
256         } else {
257                 va_start (args, message);
258                 _error_report_v (error_next, code, file, line, function, message,
259                                  args);
260                 va_end (args);
261         }
262
263         error_last->next = error_next;
264 }