Buy Foundations of GTK+ Development now for only $31.49!
Cover Foundations of GTK+ Development

Build sophisticated graphical applications using one of the world's most powerful cross-platform toolkits, learning from practical examples, full applications, and in-depth reference appendices!
Using GLib's GKeyFile Parser

© 2007 Andrew Krause
Revision Number: 2.0

The problem with writing a book on GTK+ is that the library is constantly changing and you cannot possibly fit every topic into the book. Therefore, I have created a series of tutorials that highlight topics that were not covered in the book. All of the examples in this tutorial are released for your use under the GNU General Public Licence version 2.

Key File Structure

Key files in GLib are much like .ini files used on Microsoft Windows machines. Data is split into groups, where the name appears between square bracket characters, and comments are started by the pound character.

Key files, parsed by GKeyFile, keep track of strings, localized strings, Boolean values, integers, doubles, and lists of each of these data types. An example key file can be viewed below in Listing 1.

Listing 1. Key-value file (keyfile.conf)

# This is an example key-value file

[username]

Name=Foundations of GTK+ Development

# A list of strings that are localized
Hi=Hello
Hi[fr]=Bonjour
Hi[de]=Hallo
Hi[es]=Hola

Bool=true;true;false
Nums=1;1;2;3;5;8
Strings=One;One;Two;Three;Five;Eight
Int=42
Doubles=0.0;1.0;50.4

Key files are very simple to use and are human-readable, so they are ideal for many types of configurations. Another option is to use GLib's simple XML parser, which is covered in Chapter 13 of Foundations of GTK+ Development.

Creating a New Key File

New GKeyFile objects are created with g_key_file_new(). This function creates an empty object. From there, you can either add groups and data manually or you can load data from a file. There will be more on that later.

GKeyFile* g_key_file_new ();

When you add or read lists of data, one character is used as a separator. Usually this is the semicolon character, which means that it must always be prefixed by a back slash if you want that character to actually appear in a list. You can use g_key_file_set_list_separator to change the character that is used to separate lists.

void g_key_file_set_list_separator (GKeyFile *file,
                                    gchar separator);

When you are done editing a GKeyFile object, you will usually want to save the file. You can use g_key_file_to_data() to convert the data held in the object into a string. This string will be allocated for you, so you should free it will g_free() when it is no longer needed.

gchar* g_key_file_to_data (GKeyFile *file,
                           gsize *length,
                           GError *error);

When you are done with a GKeyFile object, you should free it with g_key_file_free(). This will clean up any allocated resources that are no longer needed.

void g_key_file_free (GKeyFile *file);

Setting and Retrieving Data

As previously stated, data is held in groups. The g_key_file_get_groups() function returns a NULL-terminated list of strings, each corresponding to a group. The function also returns the length of the array.

gchar** g_key_file_get_groups (GKeyFile *file,
                               gsize *length);

In order to access a piece of data, you must first specify which group it belongs to. This allows each group to contain the same types. Table 1, located directly below, gives a complete list of functions that can be used to access data in a GKeyFile object. When you find the function you need, you should reference the GLib API documentation for more information about function parameters and the return value. Each of the functions found in Table 1 also has a corresponding g_key_file_get_*() function.

Table 1. Setting GKeyFile Values
Function Description
g_key_file_set_stringSet the value of a gchar* type object. If the key and/or group name cannot be found, they will be automatically created.
g_key_file_set_locale_stringSet the value of a localized gchar* type object. You can specify the locality for the string or leave it empty to write the default. If the key and/or group name cannot be found, they will be automatically created.
g_key_file_set_booleanSet the value of a gboolean type object. If the key and/or group name cannot be found, they will be automatically created.
g_key_file_set_integerSet the value of a gint type object. If the key and/or group name cannot be found, they will be automatically created.
g_key_file_set_doubleSet the value of a gdouble type object. If the key and/or group name cannot be found, they will be automatically created.
g_key_file_set_string_listSet a list of strings that are separated by the character that you previously set or the semicolon character. If the key and/or group name cannot be found, they will be automatically created.
g_key_file_set_locale_string_listSet a list of localized stringsthat are separated by the character that you previously set or the semicolon character. you can specify the locality for the string list or leave it empty to write the default. If the key and/or group name cannot be found, they will be automatically created.
g_key_file_set_boolean_listSet a list of Boolean values that are separated by the character that you previously set or the semicolon character. If the key and/or group name cannot be found, they will be automatically created.
g_key_file_set_integer_listSet a list of integers that are separated by the character that you previously set or the semicolon character. If the key and/or group name cannot be found, they will be automatically created.
g_key_file_set_double_listSet a list of doubles that are separated by the character that you previously set or the semicolon character. If the key and/or group name cannot be found, they will be automatically created.
g_key_file_set_comment Add a comment, which is placed based upon your data. If you specify a key, it will be placed above the key. If only a group is specified, it will be placed above the group. Otherwise, it will be placed at the top of the key file.

Removing Entries

In addition to the ability to add, edit, and retrieve information from a key file, it is also useful to be able to remove elements. The following three functions are used for removing information from a key file. The g_key_file_remove_group() function will remove the specified group from the file if it exists.

void g_key_file_remove_group (GKeyFile *file,
                              const gchar *group,
                              GError **error);

You can also remove a specific key with g_key_file_remove_key(). You should specify a group that the key will be removed from.

void g_key_file_remove_key (GKeyFile *file,
                            const gchar *group,
                            const gchar *key,
                            GError **error);

Lastly, you can use g_key_file_remove_comment() to remove a comment from the key file. If neither the group or key are specified, the comment at the top of the key file will be removed. If you specify a group, but not a key, the comment above the group will be removed. Specifying both the key and the group will remove the comment that is located above that specific key.

void g_key_file_remove_comment (GKeyFile *file,
                                const gchar *group,
                                const gchar *key,
                                GError **error);

Parsing an Existing Key File

Parsing a key file that already exists is a basic requirement for a utility such as this, so GLib provides g_key_file_load_from_file(). This function will parse the key file found at the given location, and returns TRUE if it was successfully parsed.

gboolean g_key_file_load_from_file (GKeyFile *file,
                                    const gchar *fn,
                                    GKeyFileFlags flags,
                                    GError *error);

The third parameter of this function is a bitwise list of GKeyFileFlags. The three values provided by this enumeration follow:

  • G_KEY_FILE_NONE: No flags for the key file will be set.
  • G_KEY_FILE_KEEP_COMMENTS: All of the comments in the key file should be read so that they can remain in the same position when the file is saved. If you do not set this flag, all comments will be lost.
  • G_KEY_FILE_KEEP_TRANSLATIONS: All of the translations in the key file should be read so that they will not be lost when you save the file.

If you have already read the content of the key file, you can parse a string with g_key_file_load_from_data(). You should specify the length of the string as the third parameter of this function.

gboolean g_key_file_load_from_data (GKeyFile *file,
                                    const gchar *data,
                                    gsize length,
                                    GKeyFileFlags flags,
                                    GError *error);

A Simple Example

The following example opens the key-value file from Listing 1. It creates a structure called Settings that holds all of the information that is read from the file. Both the G_KEY_FILE_KEEP_COMMENTS and G_KEY_FILE_KEEP_TRANSLATIONS flags are set when reading the key-value file so that comments and translations will not be lost.

Listing 2. GKeyFile Example

#include <glib.h>

typedef struct
{
  gchar *name, *hello;
  gboolean *boolean;
  int *nums;
  gchar **strings;
  int meaning_of_life;
  gdouble *doubles;
} Settings;

int main ()
{
  Settings *conf;
  GKeyFile *keyfile;
  GKeyFileFlags flags;
  GError *error = NULL;
  gsize length;
  
  /* Create a new GKeyFile object and a bitwise list of flags. */
  keyfile = g_key_file_new ();
  flags = G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS;
  
  /* Load the GKeyFile from keyfile.conf or return. */
  if (!g_key_file_load_from_file (keyfile, "keyfile.conf", flags, &error))
  {
    g_error (error->message);
    return -1;
  }
  
  /* Create a new Settings object. If you are using GTK+ 2.8 or below, you should
   * use g_new() or g_malloc() instead! */
  conf = g_slice_new (Settings);
  
  /* Read in data from the key file from the group "username". */
  conf->name = g_key_file_get_string             (keyfile, "username", 
                                                  "Name", NULL);
  conf->hello = g_key_file_get_locale_string     (keyfile, "username", 
                                                  "Hi", "es", NULL);
  conf->boolean = g_key_file_get_boolean_list    (keyfile, "username",  
                                                  "Bool", &length, NULL);
  conf->nums = g_key_file_get_integer_list       (keyfile, "username",  
                                                  "Nums", &length, NULL);
  conf->strings = g_key_file_get_string_list     (keyfile, "username",  
                                                  "Strings", &length, NULL);
  conf->meaning_of_life = g_key_file_get_integer (keyfile, "username",  
                                                  "Int", NULL);
  conf->doubles = g_key_file_get_double_list     (keyfile, "username",  
                                                  "Doubles", &length, NULL);
  
  return 0;
}

You should also take note of the initialization of conf with g_slice_new(). If you are using GTK+ 2.8 or below, you will have to initialize it with g_new() or g_malloc() since memory slices were introduced in GTK+ 2.10.

Conclusion

In this tutorial, you learned how to use GLib's key file parser. This utility can be a very great resources for simple configuration files where XML is overkill. You can find more information about GLib's simple XML parser in my book, Foundations of GTK+ Development.

If you find any mistakes in this tutorial, you can use the Contact Form to tell me. Also, if you are interested in GTK+ development, I would appreciate if you would check out my book, Foundations of GTK+ Development!

Copyright © 2007 Andrew Krause