Coding Guidelines/String Functions

From wiki.zmanda.com
Jump to navigation Jump to search

In general

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

Examples: string utility functions

GLib's string utilities contain a lot of very convenient functions, for example 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);

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

You should also favor GLib's versions of tolower/toupper, specifically the g_ascii_*() functions, since they are insensitive to the locale. Example:

/* Duplicate a string to a lower version of it */
char *low = g_ascii_tolower("HeLLo wOrlD"); /* low will be "hello world" */

Finally, use g_free() to free the strings.

More generally, if GLib has a replacement function to a C standard, you should use it.

Example: 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);

Example: 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);
}

Some more hints:

  • g_strjoinv() will, by default, NOT put the separator after the last line. If this is what you want, add the empty string (either "" or g_strdup("") to the end of the array before adding NULL;
  • 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);
}