~youscribe/parted/3.1

« back to all changes in this revision

Viewing changes to libparted/exception.c

  • Committer: Guilhem Lettron
  • Date: 2012-10-22 14:37:59 UTC
  • Revision ID: guilhem+ubuntu@lettron.fr-20121022143759-m403kecgz13sknvp
3.1 from tarball

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    libparted - a library for manipulating disk partitions
 
3
    Copyright (C) 1999-2000, 2007-2012 Free Software Foundation, Inc.
 
4
 
 
5
    This program is free software; you can redistribute it and/or modify
 
6
    it under the terms of the GNU General Public License as published by
 
7
    the Free Software Foundation; either version 3 of the License, or
 
8
    (at your option) any later version.
 
9
 
 
10
    This program is distributed in the hope that it will be useful,
 
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
    GNU General Public License for more details.
 
14
 
 
15
    You should have received a copy of the GNU General Public License
 
16
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
17
*/
 
18
 
 
19
/** \file exception.c */
 
20
 
 
21
/**
 
22
 * \addtogroup PedException
 
23
 *
 
24
 * \brief Exception handling.
 
25
 *
 
26
 * There are a few types of exceptions: PED_EXCEPTION_INFORMATION,
 
27
 * PED_EXCEPTION_WARNING, PED_EXCEPTION_ERROR, PED_EXCEPTION_FATAL,
 
28
 * PED_EXCEPTION_BUG.
 
29
 *
 
30
 * They are "thrown" when one of the above events occur while executing
 
31
 * a libparted function. For example, if ped_device_open() fails
 
32
 * because the device doesn't exist, an exception will be thrown.
 
33
 * Exceptions contain text describing what the event was. It will give
 
34
 * at least one option for resolving the exception: PED_EXCEPTION_FIX,
 
35
 * PED_EXCEPTION_YES, PED_EXCEPTION_NO, PED_EXCEPTION_OK, PED_EXCEPTION_RETRY,
 
36
 * PED_EXCEPTION_IGNORE, PED_EXCEPTION_CANCEL. After an exception is thrown,
 
37
 * there are two things that can happen:
 
38
 *
 
39
 * -# an exception handler is called, which selects how the exception should be
 
40
 *    resolved (usually by asking the user). Also note: an exception handler may
 
41
 *    choose to return PED_EXCEPTION_UNHANDLED. In this case, a default action
 
42
 *    will be taken by libparted (respectively the code that threw the
 
43
 *    exception). In general, a default action will be "safe".
 
44
 * -# the exception is not handled, because the caller of the function wants to
 
45
 *    handle everything itself. In this case, PED_EXCEPTION_UNHANDLED is
 
46
 *    returned.
 
47
 *
 
48
 * @{
 
49
 */
 
50
 
 
51
#include <config.h>
 
52
 
 
53
#include <parted/parted.h>
 
54
#include <parted/debug.h>
 
55
#include <parted/exception.h>
 
56
 
 
57
#define N_(String) String
 
58
#if ENABLE_NLS
 
59
#  include <libintl.h>
 
60
#  define _(String) dgettext (PACKAGE, String)
 
61
#else
 
62
#  define _(String) (String)
 
63
#endif /* ENABLE_NLS */
 
64
 
 
65
#include <stdio.h>
 
66
#include <stdarg.h>
 
67
#include <stdlib.h>
 
68
 
 
69
int                             ped_exception = 0;
 
70
 
 
71
static PedExceptionOption default_handler (PedException* ex);
 
72
 
 
73
static PedExceptionHandler*     ex_handler = default_handler;
 
74
static PedException*            ex = NULL;
 
75
static int                      ex_fetch_count = 0;
 
76
 
 
77
static const char *const type_strings [] = {
 
78
        N_("Information"),
 
79
        N_("Warning"),
 
80
        N_("Error"),
 
81
        N_("Fatal"),
 
82
        N_("Bug"),
 
83
        N_("No Implementation")
 
84
};
 
85
 
 
86
static const char *const option_strings [] = {
 
87
        N_("Fix"),
 
88
        N_("Yes"),
 
89
        N_("No"),
 
90
        N_("OK"),
 
91
        N_("Retry"),
 
92
        N_("Ignore"),
 
93
        N_("Cancel")
 
94
};
 
95
 
 
96
/**
 
97
 *  Return a string describing an exception type.
 
98
 */
 
99
char*
 
100
ped_exception_get_type_string (PedExceptionType ex_type)
 
101
{
 
102
        return (char *) type_strings [ex_type - 1];
 
103
}
 
104
 
 
105
/* FIXME: move this out to the prospective math.c */
 
106
/* FIXME: this can probably be done more efficiently */
 
107
static int _GL_ATTRIBUTE_PURE
 
108
ped_log2 (int n)
 
109
{
 
110
        int x;
 
111
 
 
112
        PED_ASSERT (n > 0);
 
113
 
 
114
        for (x=0; 1 << x <= n; x++);
 
115
 
 
116
        return x - 1;
 
117
}
 
118
 
 
119
/**
 
120
 * Return a string describing an exception option.
 
121
 */
 
122
char*
 
123
ped_exception_get_option_string (PedExceptionOption ex_opt)
 
124
{
 
125
        return (char *) option_strings [ped_log2 (ex_opt)];
 
126
}
 
127
 
 
128
static PedExceptionOption
 
129
default_handler (PedException* e)
 
130
{
 
131
        if (e->type == PED_EXCEPTION_BUG)
 
132
                fprintf (stderr,
 
133
                        _("A bug has been detected in GNU Parted.  "
 
134
                        "Refer to the web site of parted "
 
135
                        "http://www.gnu.org/software/parted/parted.html "
 
136
                        "for more information of what could be useful "
 
137
                        "for bug submitting!  "
 
138
                        "Please email a bug report to "
 
139
                        "%s containing at least the "
 
140
                        "version (%s) and the following message:  "),
 
141
                         PACKAGE_BUGREPORT, VERSION);
 
142
        else
 
143
                fprintf (stderr, "%s: ",
 
144
                         ped_exception_get_type_string (e->type));
 
145
        fprintf (stderr, "%s\n", e->message);
 
146
 
 
147
        switch (e->options) {
 
148
                case PED_EXCEPTION_OK:
 
149
                case PED_EXCEPTION_CANCEL:
 
150
                case PED_EXCEPTION_IGNORE:
 
151
                        return e->options;
 
152
 
 
153
                default:
 
154
                        return PED_EXCEPTION_UNHANDLED;
 
155
        }
 
156
}
 
157
 
 
158
/**
 
159
 * Set the exception handler.
 
160
 *
 
161
 * The exception handler should return ONE of the options set in ex->options,
 
162
 * indicating the way the event should be resolved.
 
163
 */
 
164
void
 
165
ped_exception_set_handler (PedExceptionHandler* handler)
 
166
{
 
167
        if (handler)
 
168
                ex_handler = handler;
 
169
        else
 
170
                ex_handler = default_handler;
 
171
}
 
172
 
 
173
/**
 
174
 * Get the current exception handler.
 
175
 */
 
176
PedExceptionHandler *
 
177
ped_exception_get_handler (void)
 
178
{
 
179
        if (ex_handler)
 
180
                return ex_handler;
 
181
        return default_handler;
 
182
}
 
183
 
 
184
/**
 
185
 * Assert that the current exception has been resolved.
 
186
 */
 
187
void
 
188
ped_exception_catch ()
 
189
{
 
190
        if (ped_exception) {
 
191
                ped_exception = 0;
 
192
                free (ex->message);
 
193
                free (ex);
 
194
                ex = NULL;
 
195
        }
 
196
}
 
197
 
 
198
static PedExceptionOption
 
199
do_throw ()
 
200
{
 
201
        PedExceptionOption      ex_opt;
 
202
 
 
203
        ped_exception = 1;
 
204
 
 
205
        if (ex_fetch_count) {
 
206
                return PED_EXCEPTION_UNHANDLED;
 
207
        } else {
 
208
                ex_opt = ex_handler (ex);
 
209
                ped_exception_catch ();
 
210
                return ex_opt;
 
211
        }
 
212
}
 
213
 
 
214
/**
 
215
 * Throw an exception.
 
216
 *
 
217
 * You can also use this in a program using libparted.
 
218
 * "message" is a printf-like format string, so you can do
 
219
 *
 
220
 * \code
 
221
 * ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_RETRY_CANCEL,
 
222
 *      "Can't open %s", file_name);
 
223
 * \endcode
 
224
 *
 
225
 * Returns the option selected to resolve the exception. If the exception was
 
226
 * unhandled, PED_EXCEPTION_UNHANDLED is returned.
 
227
 */
 
228
PedExceptionOption
 
229
ped_exception_throw (PedExceptionType ex_type,
 
230
                     PedExceptionOption ex_opts, const char* message, ...)
 
231
{
 
232
        va_list         arg_list;
 
233
        int result;
 
234
        static int size = 1000;
 
235
 
 
236
        if (ex)
 
237
                ped_exception_catch ();
 
238
 
 
239
        ex = (PedException*) malloc (sizeof (PedException));
 
240
        if (!ex)
 
241
                goto no_memory;
 
242
 
 
243
        ex->type = ex_type;
 
244
        ex->options = ex_opts;
 
245
 
 
246
        while (message) {
 
247
                        ex->message = (char*) malloc (size * sizeof (char));
 
248
                        if (!ex->message)
 
249
                                        goto no_memory;
 
250
 
 
251
                        va_start (arg_list, message);
 
252
                        result = vsnprintf (ex->message, size, message, arg_list);
 
253
                        va_end (arg_list);
 
254
 
 
255
                        if (result > -1 && result < size)
 
256
                                        break;
 
257
 
 
258
                        size += 10;
 
259
                        free (ex->message);
 
260
        }
 
261
 
 
262
        return do_throw ();
 
263
 
 
264
no_memory:
 
265
        fputs ("Out of memory in exception handler!\n", stderr);
 
266
 
 
267
        va_start (arg_list, message);
 
268
        vfprintf (stderr, message, arg_list);
 
269
        va_end (arg_list);
 
270
 
 
271
        return PED_EXCEPTION_UNHANDLED;
 
272
}
 
273
 
 
274
/**
 
275
 * Rethrow an unhandled exception.
 
276
 * This means repeating the last ped_exception_throw() statement.
 
277
 */
 
278
PedExceptionOption
 
279
ped_exception_rethrow ()
 
280
{
 
281
        return do_throw ();
 
282
}
 
283
 
 
284
/**
 
285
 * Indicates that exceptions should not go to the exception handler, but
 
286
 * passed up to the calling function(s).  All calls to
 
287
 * ped_exception_throw() will return PED_EXCEPTION_UNHANDLED.
 
288
 */
 
289
void
 
290
ped_exception_fetch_all ()
 
291
{
 
292
        ex_fetch_count++;
 
293
}
 
294
 
 
295
/**
 
296
 * Indicates that the calling function does not want to accept any
 
297
 * responsibility for exceptions any more.
 
298
 *
 
299
 * \note a caller of that function may still want responsibility, so
 
300
 *      ped_exception_throw() may not invoke the exception handler.
 
301
 *
 
302
 * \warning every call to this function must have a preceding
 
303
 *      ped_exception_fetch_all().
 
304
 */
 
305
void
 
306
ped_exception_leave_all ()
 
307
{
 
308
        PED_ASSERT (ex_fetch_count > 0);
 
309
        ex_fetch_count--;
 
310
}
 
311
 
 
312
/** @} */