Coding Guidelines/String Functions

From The Open Source Backup Wiki (Amanda, MySQL Backup, BackupPC)

Jump to: navigation, search

Contents

In general

Amanda uses GLib to manage strings. You should, in particular, see these pages:

String utility functions: dynamically allocated strings

GLib's string utilities contain a lot of very convenient functions to dynamically allocate strings. Examples:

/* Duplicate a plain string */
char *p = g_strdup("Hello world");
char *p = g_strdup(othervariablehere);

/* Allocate a directly formatted string */
char *p = g_strdup_printf("Hello %s", world);

/* Concatenate a list of random strings together */
char *p = g_strconcat(string1, string2, string3, NULL);

Finally, use g_free() to free the strings.

String utility functions: splitting and joining

Think before using strchr() or strstr(). GLib has g_strsplit():

/* Split a string against a separator */
gchar **strings = g_strsplit("\n", thebigstring);
/* Work with strings, and, when done: */
g_strfreev(strings);

The returned pointer array is guaranteed to be terminated with a NULL pointer. So, if you want to walk the resulting array, you will do:

gchar **strings = g_strsplit(...);
gchar **ptr

for (ptr = strings; *ptr; ptr++)
    /* do something with *ptr here */

One thing, though: if the string you are trying to split ends with the separator, then the last argument before NULL will be an empty string. So, you might want to test for it if you don't want to do anything with it - or, if you're so inclined, just remove the last separator from the string before proceeding.

In order to join, you have the choice between g_strjoin() and g_strjoinv(). The first uses a NULL-terminated list of arguments, while the second uses a NULL-terminated string array:

char *p = g_strjoin(" ", str1, str2, NULL);

gchar **strings = ...;
char *p = g_strjoinv(" ", strings);

Other string utility functions... =

GLib has "locale-safe" string functions, in the sense that they are guaranteed to behave the same, whatever your locale is set to. It is particularly useful, for instance, when trying to identify the real type of a character: the result of isalpha, for instance, will vary depending on the locale. GLib's g_ascii_isalpha, on the other hand, will always behave the same.

Also, have you ever been bitten by the behavior of the strcmp family of functions? Consider using g_str_equal...

GString

GString is the base string buffer to which you can append/allocate etc. Its usage is quite simple, however you must pay attention to what you want to do when finished with the object. Either you want to get the stored string back, or you don't:

GString *strbuf = g_string_new(NULL); /* This will spawn an empty string */
g_string_append(strbuf, "some string");
g_string_append_printf(strbuf, "Hello %s", "Mars");
g_string_append_c(strbuf, '\n');
/* g_string_prepend(), etc etc - see the link above */
/*
 * Getting the string stored in it while discarding the GString:
 */
char *p = g_string_free(strbuf, FALSE);
/*
 * Completely scratching the buffer, including its contents:
 */
g_string_free(strbuf, TRUE);

GPtrArray

While this data type can store ANY type of data, it is hugely convenient for building separator-based strings. For instance, here is how to build a space-separated string of a command line received as an argument:

#include <stdlib.h>
#include <glib.h>

int main(int argc, char **argv)
{
    int i;
    GPtrArray *array = g_ptr_array_new();
    gchar **strings;
    char *result;

    for (i = 0; i < argc; i++)
        g_ptr_array_add(array, argv[i]);

    /* NEVER FORGET THAT! */
    g_ptr_array_add(array, NULL);

    strings = (gchar **)g_ptr_array_free(array, FALSE);

    p = g_strjoinv(" ", strings);
    
    /*
     * BEWARE here: if your GPtrArray contains elements of dynamically allocated strings,
     * then you should use g_strfreev(). BUT if the pointers contain only statically
     * allocated strings, you MUST use g_free().
     */

    g_free(strings);

    g_fprintf(stderr, "My command line was: \"%s\"\n", p);

    g_free(p);

    exit(0);
}

ENSURE that your array contains either statically allocated strings or dynamically allocated strings, but NEVER both mixed!

Here is another example which duplicates all of its inputs. Look at the differences:

#include <stdlib.h>
#include <glib.h>

int main(int argc, char **argv)
{
    int i;
    GPtrArray *array = g_ptr_array_new();
    gchar **strings;
    char *result;

    for (i = 0; i < argc; i++)
        g_ptr_array_add(array, g_strdup(argv[i]));

    /* NEVER FORGET THAT! */
    g_ptr_array_add(array, NULL);

    strings = (gchar **)g_ptr_array_free(array, FALSE);

    p = g_strjoinv(" ", strings);
    
    /*
     * Note: g_strfreev(), not g_free()!
     */

    g_strfreev(strings);

    g_fprintf(stderr, "My command line was: \"%s\"\n", p);

    g_free(p);

    exit(0);
}
Personal tools