2003-03-12 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-errors.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-errors.c Error reporting
3  *
4  * Copyright (C) 2002  Red Hat Inc.
5  * Copyright (C) 2003  CodeFactory AB
6  *
7  * Licensed under the Academic Free License version 1.2
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24 #include "dbus-errors.h"
25 #include "dbus-internals.h"
26 #include <stdarg.h>
27 #include <stdio.h>
28
29 /**
30  * @defgroup DBusErrors Error reporting
31  * @ingroup  DBus
32  * @brief Error reporting
33  *
34  * Types and functions related to reporting errors.
35  *
36  *
37  * In essence D-BUS error reporting works as follows:
38  *
39  * @code
40  * DBusResultCode result = DBUS_RESULT_SUCCESS;
41  * dbus_some_function (arg1, arg2, &result);
42  * if (result != DBUS_RESULT_SUCCESS)
43  *   printf ("an error occurred\n");
44  * @endcode
45  *
46  * @todo add docs with DBusError
47  * 
48  * @{
49  */
50
51 typedef struct
52 {
53   const char *name; /**< error name */
54   char *message; /**< error message */
55
56   unsigned int const_message : 1; /** Message is not owned by DBusError */
57
58   unsigned int dummy2 : 1; /**< placeholder */
59   unsigned int dummy3 : 1; /**< placeholder */
60   unsigned int dummy4 : 1; /**< placeholder */
61   unsigned int dummy5 : 1; /**< placeholder */
62
63   void *padding1; /**< placeholder */
64   
65 } DBusRealError;
66
67 /**
68  * Set a result code at a result code location,
69  * if code_address is not #NULL.
70  *
71  * @param code_address place to store the result code.
72  * @param code the result code itself.
73  */
74 void
75 dbus_set_result (DBusResultCode *code_address,
76                  DBusResultCode  code)
77 {
78   if (code_address)
79     *code_address = code;
80 }
81
82 /**
83  * Returns a string describing the given result code.
84  *
85  * @param code the result code to describe.
86  * @returns a constant string describing the code.
87  */
88 const char*
89 dbus_result_to_string (DBusResultCode code)
90 {
91   /* This is a switch to the compiler will complain if we
92    * aren't handling some codes
93    */
94   switch (code)
95     {
96     case DBUS_RESULT_SUCCESS:
97       return "Success";
98     case DBUS_RESULT_FAILED:
99       return "Unknown error";
100     case DBUS_RESULT_NO_MEMORY:
101       return "Not enough memory available";
102     case DBUS_RESULT_IO_ERROR:
103       return "Error reading or writing data";
104     case DBUS_RESULT_BAD_ADDRESS:
105       return "Could not parse address";
106     case DBUS_RESULT_NOT_SUPPORTED:
107       return "Feature not supported";
108     case DBUS_RESULT_LIMITS_EXCEEDED:
109       return "Resource limits exceeded";
110     case DBUS_RESULT_ACCESS_DENIED:
111       return "Permission denied";
112     case DBUS_RESULT_AUTH_FAILED:
113       return "Could not authenticate to server";
114     case DBUS_RESULT_NO_SERVER:
115       return "No server";
116     case DBUS_RESULT_TIMEOUT:
117       return "Connection timed out";
118     case DBUS_RESULT_NO_NETWORK:
119       return "Network unavailable";
120     case DBUS_RESULT_ADDRESS_IN_USE:
121       return "Address already in use";
122     case DBUS_RESULT_DISCONNECTED:
123       return "Disconnected.";
124     case DBUS_RESULT_INVALID_ARGS:
125       return "Invalid argumemts.";
126     case DBUS_RESULT_NO_REPLY:
127       return "Did not get a reply message.";
128     case DBUS_RESULT_FILE_NOT_FOUND:
129       return "File doesn't exist.";
130       
131       /* no default, it would break our compiler warnings */
132     }
133
134   return "Invalid error code";
135 }
136
137 /**
138  * Initializes a DBusError structure. Does not allocate
139  * any memory; the error only needs to be freed
140  * if it is set at some point. 
141  *
142  * @param error the DBusError.
143  */
144 void
145 dbus_error_init (DBusError *error)
146 {
147   DBusRealError *real;
148
149   _dbus_assert (error != NULL);
150
151   _dbus_assert (sizeof (DBusError) == sizeof (DBusRealError));
152
153   real = (DBusRealError *)error;
154   
155   real->name = NULL;  
156   real->message = NULL;
157
158   real->const_message = TRUE;
159 }
160
161 /**
162  * Frees an error that's been set (or just initialized),
163  * then reinitializes the error as in dbus_error_init().
164  *
165  * @param error memory where the error is stored.
166  */
167 void
168 dbus_error_free (DBusError *error)
169 {
170   DBusRealError *real;
171
172   real = (DBusRealError *)error;
173
174   if (!real->const_message)
175     dbus_free (real->message);
176
177   dbus_error_init (error);
178 }
179
180 /**
181  * Assigns an error name and message to a DBusError.
182  * Does nothing if error is #NULL.
183  *
184  * @param error the error.
185  * @param name the error name (not copied!!!)
186  * @param message the error message (not copied!!!)
187  */
188 void
189 dbus_set_error_const (DBusError  *error,
190                       const char *name,
191                       const char *message)
192 {
193   DBusRealError *real;
194
195   if (error == NULL)
196     return;
197
198   /* it's a bug to pile up errors */
199   _dbus_assert (error->name == NULL);
200   _dbus_assert (error->message == NULL);
201   _dbus_assert (name != NULL);
202   _dbus_assert (message != NULL);
203   
204   real = (DBusRealError *)error;
205   
206   real->name = name;
207   real->message = (char *)message;
208   real->const_message = TRUE;
209 }
210
211 /**
212  * Moves an error src into dest, freeing src and
213  * overwriting dest. Both src and dest must be initialized.
214  * src is reinitialized to an empty error. dest may not
215  * contain an existing error. If the destination is
216  * #NULL, just frees and reinits the source error.
217  *
218  * @param src the source error
219  * @param dest the destination error or #NULL
220  */
221 void
222 dbus_move_error (DBusError *src,
223                  DBusError *dest)
224 {
225   _dbus_assert (!dbus_error_is_set (dest));
226
227   if (dest)
228     {
229       dbus_error_free (dest);
230       *dest = *src;
231       dbus_error_init (src);
232     }
233   else
234     dbus_error_free (src);
235 }
236
237 /**
238  * Checks whether the error is set and has the given
239  * name.
240  * @param error the error
241  * @param name the name
242  * @returns #TRUE if the given named error occurred
243  */
244 dbus_bool_t
245 dbus_error_has_name (const DBusError *error,
246                      const char      *name)
247 {
248   _dbus_assert (error != NULL);
249   _dbus_assert (name != NULL);
250   _dbus_assert ((error->name != NULL && error->message != NULL) ||
251                 (error->name == NULL && error->message == NULL));
252   
253   if (error->name != NULL)
254     {
255       DBusString str1, str2;
256       _dbus_string_init_const (&str1, error->name);
257       _dbus_string_init_const (&str2, name);
258       return _dbus_string_equal (&str1, &str2);
259     }
260   else
261     return FALSE;
262 }
263
264 /**
265  * Checks whether an error occurred (the error is set).
266  *
267  * @param error the error object
268  * @returns #TRUE if an error occurred
269  */
270 dbus_bool_t
271 dbus_error_is_set (const DBusError *error)
272 {
273   _dbus_assert (error != NULL);  
274   _dbus_assert ((error->name != NULL && error->message != NULL) ||
275                 (error->name == NULL && error->message == NULL));
276   return error->name != NULL;
277 }
278
279 /**
280  * Assigns an error name and message to a DBusError.
281  * Does nothing if error is #NULL.
282  *
283  * If no memory can be allocated for the error message, 
284  * an out-of-memory error message will be set instead.
285  *
286  * @todo stdio.h shouldn't be included in this file,
287  * should write _dbus_string_append_printf instead
288  * 
289  * @param error the error.
290  * @param name the error name (not copied!!!)
291  * @param format printf-style format string.
292  */
293 void
294 dbus_set_error (DBusError  *error,
295                 const char *name,
296                 const char *format,
297                 ...)
298 {
299   DBusRealError *real;
300   va_list args;
301   int message_length;
302   char *message;
303   char c;
304
305   if (error == NULL)
306     return;
307
308   /* it's a bug to pile up errors */
309   _dbus_assert (error->name == NULL);
310   _dbus_assert (error->message == NULL);
311   _dbus_assert (name != NULL);
312   _dbus_assert (format != NULL);
313   
314   va_start (args, format);
315   /* Measure the message length */
316   message_length = vsnprintf (&c, 1, format, args) + 1;
317   va_end (args);
318   
319   message = dbus_malloc (message_length);
320   
321   if (!message)
322     {
323       dbus_set_error_const (error, DBUS_ERROR_NO_MEMORY,
324                             "Failed to allocate memory for error message.");
325       return;
326     }
327   
328   va_start (args, format);  
329   vsprintf (message, format, args);  
330   va_end (args);
331
332   real = (DBusRealError *)error;
333   
334   real->name = name;
335   real->message = message;
336   real->const_message = FALSE;
337 }
338
339 /** @} */