Coding Guidelines/String Functions: Difference between revisions

From wiki.zmanda.com
Jump to navigation Jump to search
No edit summary
Line 7: Line 7:
* [http://wiki.zmanda.com/glib-docs/glib/glib-Pointer-Arrays.html the GPtrArray data type].
* [http://wiki.zmanda.com/glib-docs/glib/glib-Pointer-Arrays.html the GPtrArray data type].


== Examples: string utility functions ==
== String utility functions: dynamically allocated strings ==


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


<pre>
<pre>
Line 19: Line 19:
char *p = g_strdup_printf("Hello %s", world);
char *p = g_strdup_printf("Hello %s", world);


/* Concatenate a list of random strings together */
char *p = g_strconcat(string1, string2, string3, NULL);
</pre>
Finally, use <tt>g_free()</tt> to free the strings.
== String utility functions: splitting and joining ==
Think before using <tt>strchr()</tt> or <tt>strstr()</tt>. GLib has <tt>g_strsplit()</tt>:
<pre>
/* Split a string against a separator */
/* Split a string against a separator */
gchar **strings = g_strsplit("\n", othervariablethere);
gchar **strings = g_strsplit("\n", thebigstring);
/* Work with strings, and, when done: */
/* Work with strings, and, when done: */
g_strfreev(strings);
g_strfreev(strings);
</pre>
</pre>


You should also favor GLib's versions of tolower/toupper, specifically the g_ascii_*() functions, since they are insensitive to the locale. Example:
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:


<pre>
<pre>
/* Duplicate a string to a lower version of it */
gchar **strings = g_strsplit(...);
char *low = g_ascii_tolower("HeLLo wOrlD"); /* low will be "hello world" */
gchar **ptr
 
for (ptr = strings; *ptr; ptr++)
    /* do something with *ptr here */
</pre>
</pre>


Finally, use <tt>g_free()</tt> to free the strings.
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 <tt>g_strjoin()</tt> and <tt>g_strjoinv()</tt>. The first uses a NULL-terminated list of arguments, while the second uses a NULL-terminated string array:
 
<pre>
char *p = g_strjoin(" ", str1, str2, NULL);


More generally, if GLib has a replacement function to a C standard, you <i>should</i> use it.
gchar **strings = ...;
char *p = g_strjoinv(" ", strings);
</pre>


== Example: GString ==
== 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 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:
Line 97: Line 118:
</pre>
</pre>


Some more hints:
ENSURE that your array contains either statically allocated strings or dynamically allocated strings, but NEVER both mixed!
* 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:
Here is another example which duplicates all of its inputs. Look at the differences:


<pre>
<pre>

Revision as of 11:28, 4 June 2011

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

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

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