Error Tutorial

Introduction

The Eina error module provides a way to manage errors in a simple but powerful way in libraries and modules. It is also used in Eina itself. It provides facilities for displaying different kind of messages (warning, informations, errors, or debug), which can be tuned by the user, or for registering new errors messages.

Basic Usage

The first thing to do when using the error module is to initialize it with eina_error_init() and, when the error module is not used anymore, to shut down it with eina_error_shutdown(). So a basic program would look like that:

 #include <stdlib.h>
 #include <stdio.h>

 #include <eina_error.h>

 int main(void)
 {
    if (!eina_error_init())
    {
        printf ("Error during the initialization of eina_error module\n");
        return EXIT_FAILURE;
    }

    eina_error_shutdown();

    return EXIT_SUCCESS;
 }

All program using any module of eina must be compiled with the following command:

 gcc -Wall -o my_exe my_source.c `pkg-config --cflags --libs eina`

Now that the error module is initialized, error messages can be displayed. Helper macros are already defined for such purpose:

Here is an example:

 #include <stdlib.h>
 #include <stdio.h>

 #include <eina_error.h>

 void test(int i)
 {
    EINA_ERROR_PDBG("Entering test\n");

    if (i < 0)
    {
        EINA_ERROR_PERR("argument is negative\n");
        return;
    }

    EINA_ERROR_PINFO("argument non negative\n");

    EINA_ERROR_PDBG("Exiting test\n");
 }

 int main(void)
 {
    if (!eina_error_init())
    {
        printf ("Error during the initialization of eina_error module\n");
        return EXIT_FAILURE;
    }

    test(-1);
    test(0);

    eina_error_shutdown();

    return EXIT_SUCCESS;
 }

If you compiled Eina without debug mode, after executing that program, you will see only 1 message (the argument being negative). Why ? These macros are just wrappers around eina_error_print(). This function only dysplays messages if the current error level is lesser or equal than the one used by eina_error_print(). By default, the current error level is EINA_ERROR_LEVEL_ERR (in non debug mode), and the macro uses the error values defines by Eina_Error_Level. So as EINA_ERROR_LEVEL_ERR is the smallest value, only EINA_ERROR_PERR() will display the message.

To modify this behavior, you have two solutions:

So try using the environment variable like this:

 EINA_ERROR_LEVEL=2 ./my_app

To do the same with eina_error_log_level_set(), just add

 eina_error_log_level_set(EINA_ERROR_LEVEL_INFO);

before the calls of the tests in the above example.

Advanced usage of print callbacks

The error module allows the user to change the way eina_error_print() displays the messages. It suffices to pass to eina_error_print_cb_set() the function used to display the message. That function must be of type Eina_Error_Print_Cb. As a custom data can be passed to that callback, powerful display messages can be displayed.

It is suggested to not use __FILE__, __FUNCTION__ or __LINE__ when writing that callback, but when defining macros (like EINA_ERROR_PERR() and other macros).

Here is an example of custom callback, whose behavior can be changed at runtime:

 #include <stdlib.h>
 #include <stdio.h>

 #include <eina_error.h>

 #define ERROR(fmt, ...)                                    \
    eina_error_print(EINA_ERROR_LEVEL_ERR, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)

 typedef struct _Data Data;

 struct _Data
 {
    int to_stderr;
 };

 void print_cb(Eina_Error_Level level,
               const char *file,
               const char *fnc,
               int line,
               const char *fmt,
               void *data,
               va_list args)
 {
    Data *d;
    FILE *output;
    char *str;

    d = (Data *)data;
    if (d->to_stderr)
    {
       output = stderr;
       str = "stderr";
    }
    else
    {
       output = stdout;
       str = "stdout";
    }

    fprintf(output, "%s:%s (%d) %s: ", file, fnc, line, str);
    vfprintf(output, fmt, args);
 }

 void test(Data *data, int i)
 {
    if (i < 0)
       data->to_stderr = 0;
    else
       data->to_stderr = 1;

    ERROR("error message...\n");
 }

 int main(void)
 {
    Data *data;

    if (!eina_error_init())
    {
       printf ("Error during the initialization of eina_error module\n");
       return EXIT_FAILURE;
    }

    data = (Data *)malloc(sizeof(Data));
    if (!data)
    {
       printf ("Error during memory allocation\n");
       eina_error_shutdown();
       return EXIT_FAILURE;
    }

    eina_error_print_cb_set(print_cb, data);

    test(data, -1);
    test(data, 0);

    eina_error_shutdown();

    return EXIT_SUCCESS;
 }

Registering messages

The error module can provide a system that mimic the errno system of the C standard library. It consists in 2 parts:

So one has to fisrt register all the error messages that a program or a lib should manage. Then, when an error can occur, use eina_error_set(), and when errors are managed, use eina_error_get().

Here is an example of use:

 #include <stdlib.h>
 #include <stdio.h>

 #include <eina_error.h>

 Eina_Error MY_ERROR_NEGATIVE;
 Eina_Error MY_ERROR_NULL;

 voi *data_new()
 {
    eina_error_set(MY_ERROR_NULL);
    return NULL;
 }

 int test(int n)
 {
    if (n < 0)
    {
       eina_error_set(MY_ERROR_NEGATIVE);
       return 0;
    }

    return 1;
 }

 int main(void)
 {
    void *data;

    if (!eina_error_init())
    {
       printf ("Error during the initialization of eina_error module\n");
       return EXIT_FAILURE;
    }

    MY_ERROR_NEGATIVE = eina_error_msg_register("Negative number");
    MY_ERROR_NULL = eina_error_msg_register("NULL pointer");

    data = data_new();
    if (!data)
    {
       Eina_Error err;

       err = eina_error_get();
       if (err)
          printf("Error during memory allocation: %s\n",
                 eina_error_msg_get(err));
    }

    if (!test(-1))
    {
       Eina_Error err;

       err = eina_error_get();
       if (err)
          printf("Error during test function: %s\n",
                 eina_error_msg_get(err));
    }

    eina_error_shutdown();

    return EXIT_SUCCESS;
 }

Of course, instead of printf(), eina_error_print() can be used to have beautiful error messages.


Generated on Sat Sep 6 10:58:50 2008 for Eina by  doxygen 1.5.5