Helping with adding error handling support
Error handling scheme
It seems that adding a GError** parameter to every method that could issue an error is enough. This error mechanism is both simple and powerful
Documentation about GError
libtinymail/tny-error.h
The error domain is an unique number identifying the package where the error occurred or originated from. It's defined in the enumeration TnyErrorDomain.
enum _TnyErrorDomain
{
TNY_FOLDER_ERROR,
TNY_FOLDER_STORE_ERROR,
TNY_TRANSPORT_ERROR
};
The error itself is an unique number in the TnyError enumeration.
enum _TnyError
{
TNY_FOLDER_ERROR_EXPUNGE,
TNY_FOLDER_ERROR_REMOVE_MSG,
TNY_FOLDER_ERROR_ADD_MSG,
TNY_FOLDER_ERROR_REFRESH,
TNY_FOLDER_ERROR_GET_MSG,
TNY_FOLDER_ERROR_TRANSFER_MSGS,
TNY_FOLDER_ERROR_SET_NAME,
TNY_FOLDER_STORE_ERROR_REMOVE_FOLDER,
TNY_FOLDER_STORE_ERROR_GET_FOLDERS,
TNY_FOLDER_STORE_ERROR_CREATE_FOLDER,
TNY_TRANSPORT_ERROR_ACCOUNT_SEND
};
Making a method error-able
static TnyFolder*
tny_camel_folder_create_folder (TnyFolderStore *self, const gchar *name, GError **err)
{
return TNY_CAMEL_FOLDER_GET_CLASS (self)->create_folder_func (self, name, err);
}
static TnyFolder*
tny_camel_folder_create_folder_default (TnyFolderStore *self, const gchar *name, GError **err)
{
TnyFolder *folder;
if (error)
{
g_set_error (err, TNY_FOLDER_STORE_ERROR,
TNY_FOLDER_STORE_ERROR_CREATE_FOLDER,
_("Failed to create folder %s"), name);
return NULL;
}
folder = ...
return folder;
}
Try-Catch Free etc
The biggest problem consist of the implementation of a try-catch like structure in C. We can not just return whenever an error raises, because there could be memory to be freed.
The typical approach consist of doing all the memory allocations at the beginning, and then if an error happen to follow a goto to a label that will free all the allocated memory. A better technique is to wait with allocating for as long as possible and to free already allocated memory in case of error. What we want to avoid is unnecessary allocating leading to memory segmentation.
In case that isn't possible or for some reason very unpractical, the goto label method is permitted.
You are also advised to use assertions for certainties that would imply a software bug in the framework rather than an error that can legally occur. The difference is that assertions should check for something that should simply never ever occur. Like the type of an instance changing (most likely memory corruption, a to-early deallocation/destruction or pointer offset mistakes) and unless it's lazy-loadable cache a pointer being NULL or not.
static void tny_camel_folder_create_folder (TnyFolder *self, const gchar *name, GError **err)
{
TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
CamelException ex = CAMEL_EXCEPTION_INITIALISER;
CamelStore *store; gchar *folname;
TnyFolder *folder; CamelFolderInfo *info;
if (!priv->folder_name)
{
g_set_error (err, TNY_FOLDER_STORE_ERROR,
TNY_FOLDER_STORE_ERROR_CREATE_FOLDER,
_("Failed to create folder %s"), name);
return NULL;
}
store = (CamelStore*) _tny_camel_account_get_service (TNY_CAMEL_ACCOUNT (priv->account));
g_assert (CAMEL_IS_STORE (store));
folname = priv->folder_name;
info = camel_store_create_folder (store, priv->folder_name, name, &ex);
if (camel_exception_is_set (&ex))
{
g_set_error (err, TNY_FOLDER_STORE_ERROR,
TNY_FOLDER_STORE_ERROR_CREATE_FOLDER,
camel_exception_get_description (&ex));
camel_exception_clear (&ex);
if (info)
camel_store_free_folder_info (store, info);
return NULL;
}
folder = tny_camel_folder_new ();
tny_camel_folder_set_folder_info (self, TNY_CAMEL_FOLDER (folder), info);
_tny_camel_folder_set_subscribed (TNY_CAMEL_FOLDER (folder), FALSE);
return folder;
}
