* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+/*
+ * MT safe
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <ctype.h> /* For tolower() */
+#if !defined (HAVE_STRSIGNAL) || !defined(NO_SYS_SIGLIST_DECL)
+#include <signal.h>
+#endif
#include "glib.h"
+
+#ifdef G_OS_WIN32
+#include <windows.h>
+#endif
+
/* do not include <unistd.h> in this place since it
* inteferes with g_strsignal() on some OSes
*/
g_strdup (const gchar *str)
{
gchar *new_str;
-
+
if (str)
{
new_str = g_new (char, strlen (str) + 1);
}
else
new_str = NULL;
-
+
return new_str;
}
va_list args;
gchar *s;
gchar *concat;
-
+
g_return_val_if_fail (string1 != NULL, NULL);
-
+
l = 1 + strlen (string1);
va_start (args, string1);
s = va_arg (args, gchar*);
s = va_arg (args, gchar*);
}
va_end (args);
-
+
concat = g_new (gchar, l);
concat[0] = 0;
-
+
strcat (concat, string1);
va_start (args, string1);
s = va_arg (args, gchar*);
s = va_arg (args, gchar*);
}
va_end (args);
-
+
return concat;
}
gchar *fail_pos_2;
gdouble val_1;
gdouble val_2 = 0;
-
+
g_return_val_if_fail (nptr != NULL, 0);
-
+
fail_pos_1 = NULL;
fail_pos_2 = NULL;
-
+
val_1 = strtod (nptr, &fail_pos_1);
-
+
if (fail_pos_1 && fail_pos_1[0] != 0)
{
gchar *old_locale;
-
- old_locale = setlocale (LC_NUMERIC, "C");
+
+ old_locale = g_strdup (setlocale (LC_NUMERIC, NULL));
+ setlocale (LC_NUMERIC, "C");
val_2 = strtod (nptr, &fail_pos_2);
setlocale (LC_NUMERIC, old_locale);
+ g_free (old_locale);
}
-
+
if (!fail_pos_1 || fail_pos_1[0] == 0 || fail_pos_1 >= fail_pos_2)
{
if (endptr)
gchar*
g_strerror (gint errnum)
{
- static char msg[64];
-
+ static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT;
+ char *msg;
+
#ifdef HAVE_STRERROR
return strerror (errnum);
#elif NO_SYS_ERRLIST
#else /* NO_SYS_ERRLIST */
extern int sys_nerr;
extern char *sys_errlist[];
-
+
if ((errnum > 0) && (errnum <= sys_nerr))
return sys_errlist [errnum];
#endif /* NO_SYS_ERRLIST */
-
+
+ msg = g_static_private_get (&msg_private);
+ if (!msg)
+ {
+ msg = g_new (gchar, 64);
+ g_static_private_set (&msg_private, msg, g_free);
+ }
+
sprintf (msg, "unknown error (%d)", errnum);
+
return msg;
}
gchar*
g_strsignal (gint signum)
{
- static char msg[64];
-
+ static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT;
+ char *msg;
+
#ifdef HAVE_STRSIGNAL
+#ifdef G_OS_BEOS
+extern const char * strsignal(int);
+#else /* !G_OS_BEOS */
+ /* this is declared differently (const) in string.h on BeOS */
extern char *strsignal (int sig);
+#endif /* !G_OS_BEOS */
return strsignal (signum);
#elif NO_SYS_SIGLIST
switch (signum)
#endif
}
#else /* NO_SYS_SIGLIST */
- extern char *sys_siglist[];
- return sys_siglist [signum];
+
+#ifdef NO_SYS_SIGLIST_DECL
+ extern char *sys_siglist[]; /*(see Tue Jan 19 00:44:24 1999 in changelog)*/
+#endif
+
+ return (char*) /* this function should return const --josh */ sys_siglist [signum];
#endif /* NO_SYS_SIGLIST */
-
+
+ msg = g_static_private_get (&msg_private);
+ if (!msg)
+ {
+ msg = g_new (gchar, 64);
+ g_static_private_set (&msg_private, msg, g_free);
+ }
+
sprintf (msg, "unknown signal (%d)", signum);
+
return msg;
}
-guint
-g_printf_string_upper_bound (const gchar* format,
- va_list args)
+/* Functions g_strlcpy and g_strlcat were originally developed by
+ * Todd C. Miller <Todd.Miller@courtesan.com> to simplify writing secure code.
+ * See ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/strlcpy.3
+ * for more information.
+ */
+
+#ifdef HAVE_STRLCPY
+/* Use the native ones, if available; they might be implemented in assembly */
+gsize
+g_strlcpy (gchar *dest,
+ const gchar *src,
+ gsize dest_size)
+{
+ g_return_val_if_fail (dest != NULL, NULL);
+ g_return_val_if_fail (src != NULL, NULL);
+
+ return strlcpy (dest, src, dest_size);
+}
+
+gsize
+g_strlcat (gchar *dest,
+ const gchar *src,
+ gsize dest_size)
+{
+ g_return_val_if_fail (dest != NULL, NULL);
+ g_return_val_if_fail (src != NULL, NULL);
+
+ return strlcat (dest, src, dest_size);
+}
+
+#else /* ! HAVE_STRLCPY */
+/* g_strlcpy
+ *
+ * Copy string src to buffer dest (of buffer size dest_size). At most
+ * dest_size-1 characters will be copied. Always NUL terminates
+ * (unless dest_size == 0). This function does NOT allocate memory.
+ * Unlike strncpy, this function doesn't pad dest (so it's often faster).
+ * Returns size of attempted result, strlen(src),
+ * so if retval >= dest_size, truncation occurred.
+ */
+gsize
+g_strlcpy (gchar *dest,
+ const gchar *src,
+ gsize dest_size)
+{
+ register gchar *d = dest;
+ register const gchar *s = src;
+ register gsize n = dest_size;
+
+ g_return_val_if_fail (dest != NULL, NULL);
+ g_return_val_if_fail (src != NULL, NULL);
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0)
+ do
+ {
+ register gchar c = *s++;
+
+ *d++ = c;
+ if (c == 0)
+ break;
+ }
+ while (--n != 0);
+
+ /* If not enough room in dest, add NUL and traverse rest of src */
+ if (n == 0)
+ {
+ if (dest_size != 0)
+ *d = 0;
+ while (*s++)
+ ;
+ }
+
+ return s - src - 1; /* count does not include NUL */
+}
+
+/* g_strlcat
+ *
+ * Appends string src to buffer dest (of buffer size dest_size).
+ * At most dest_size-1 characters will be copied.
+ * Unlike strncat, dest_size is the full size of dest, not the space left over.
+ * This function does NOT allocate memory.
+ * This always NUL terminates (unless siz == 0 or there were no NUL characters
+ * in the dest_size characters of dest to start with).
+ * Returns size of attempted result, which is
+ * MIN (dest_size, strlen (original dest)) + strlen (src),
+ * so if retval >= dest_size, truncation occurred.
+ */
+gsize
+g_strlcat (gchar *dest,
+ const gchar *src,
+ gsize dest_size)
{
- guint len = 1;
+ register gchar *d = dest;
+ register const gchar *s = src;
+ register gsize bytes_left = dest_size;
+ gsize dlength; /* Logically, MIN (strlen (d), dest_size) */
+
+ g_return_val_if_fail (dest != NULL, NULL);
+ g_return_val_if_fail (src != NULL, NULL);
- while (*format)
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (*d != 0 && bytes_left-- != 0)
+ d++;
+ dlength = d - dest;
+ bytes_left = dest_size - dlength;
+
+ if (bytes_left == 0)
+ return dlength + strlen (s);
+
+ while (*s != 0)
{
- gboolean long_int = FALSE;
- gboolean extra_long = FALSE;
- gchar c;
-
- c = *format++;
-
- if (c == '%')
+ if (bytes_left != 1)
{
- gboolean done = FALSE;
-
- while (*format && !done)
- {
- switch (*format++)
- {
- gchar *string_arg;
-
- case '*':
- len += va_arg (args, int);
- break;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- /* add specified format length, since it might exceed the
- * size we assume it to have.
- */
- format -= 1;
- len += strtol (format, (char**) &format, 10);
- break;
- case 'h':
- /* ignore short int flag, since all args have at least the
- * same size as an int
- */
- break;
- case 'l':
- if (long_int)
- extra_long = TRUE; /* linux specific */
- else
- long_int = TRUE;
- break;
- case 'q':
- case 'L':
- long_int = TRUE;
- extra_long = TRUE;
- break;
- case 's':
- string_arg = va_arg (args, char *);
- if (string_arg)
- len += strlen (string_arg);
- else
- {
- /* add enough padding to hold "(null)" identifier */
- len += 16;
- }
- done = TRUE;
- break;
- case 'd':
- case 'i':
- case 'o':
- case 'u':
- case 'x':
- case 'X':
-#ifdef HAVE_GINT64
- if (extra_long)
- (void) va_arg (args, gint64);
- else
-#endif /* HAVE_GINT64 */
- {
- if (long_int)
- (void) va_arg (args, long);
- else
- (void) va_arg (args, int);
- }
- len += extra_long ? 64 : 32;
- done = TRUE;
- break;
- case 'D':
- case 'O':
- case 'U':
- (void) va_arg (args, long);
- len += 32;
- done = TRUE;
- break;
- case 'e':
- case 'E':
- case 'f':
- case 'g':
-#ifdef HAVE_LONG_DOUBLE
- if (extra_long)
- (void) va_arg (args, long double);
- else
-#endif /* HAVE_LONG_DOUBLE */
- (void) va_arg (args, double);
- len += extra_long ? 64 : 32;
- done = TRUE;
- break;
- case 'c':
- (void) va_arg (args, int);
- len += 1;
- done = TRUE;
- break;
- case 'p':
- case 'n':
- (void) va_arg (args, void*);
- len += 32;
- done = TRUE;
- break;
- case '%':
- len += 1;
- done = TRUE;
- break;
- default:
- /* ignore unknow/invalid flags */
- break;
- }
- }
+ *d++ = *s;
+ bytes_left--;
}
- else
- len += 1;
+ s++;
}
+ *d = 0;
- return len;
+ return dlength + (s - src); /* count does not include NUL */
}
+#endif /* ! HAVE_STRLCPY */
-void
-g_strdown (gchar *string)
+gchar*
+g_strdown (gchar *string)
{
- register gchar *s;
+ register guchar *s;
- g_return_if_fail (string != NULL);
+ g_return_val_if_fail (string != NULL, NULL);
s = string;
*s = tolower (*s);
s++;
}
+
+ return string;
}
-void
-g_strup (gchar *string)
+gchar*
+g_strup (gchar *string)
{
- register gchar *s;
-
- g_return_if_fail (string != NULL);
-
+ register guchar *s;
+
+ g_return_val_if_fail (string != NULL, NULL);
+
s = string;
-
+
while (*s)
{
*s = toupper (*s);
s++;
}
+
+ return string;
}
-void
-g_strreverse (gchar *string)
+gchar*
+g_strreverse (gchar *string)
{
- g_return_if_fail (string != NULL);
-
+ g_return_val_if_fail (string != NULL, NULL);
+
if (*string)
{
register gchar *h, *t;
-
+
h = string;
t = string + strlen (string) - 1;
-
+
while (h < t)
{
register gchar c;
-
+
c = *h;
*h = *t;
h++;
t--;
}
}
+
+ return string;
}
gint
const gchar *s2)
{
#ifdef HAVE_STRCASECMP
+ g_return_val_if_fail (s1 != NULL, 0);
+ g_return_val_if_fail (s2 != NULL, 0);
+
return strcasecmp (s1, s2);
#else
gint c1, c2;
-
+
+ g_return_val_if_fail (s1 != NULL, 0);
+ g_return_val_if_fail (s2 != NULL, 0);
+
while (*s1 && *s2)
{
/* According to A. Cox, some platforms have islower's that
return (c1 - c2);
s1++; s2++;
}
-
+
return (((gint)(guchar) *s1) - ((gint)(guchar) *s2));
#endif
}
-void
+gint
+g_strncasecmp (const gchar *s1,
+ const gchar *s2,
+ guint n)
+{
+#ifdef HAVE_STRNCASECMP
+ return strncasecmp (s1, s2, n);
+#else
+ gint c1, c2;
+
+ g_return_val_if_fail (s1 != NULL, 0);
+ g_return_val_if_fail (s2 != NULL, 0);
+
+ while (n && *s1 && *s2)
+ {
+ n -= 1;
+ /* According to A. Cox, some platforms have islower's that
+ * don't work right on non-uppercase
+ */
+ c1 = isupper ((guchar)*s1) ? tolower ((guchar)*s1) : *s1;
+ c2 = isupper ((guchar)*s2) ? tolower ((guchar)*s2) : *s2;
+ if (c1 != c2)
+ return (c1 - c2);
+ s1++; s2++;
+ }
+
+ if (n)
+ return (((gint) (guchar) *s1) - ((gint) (guchar) *s2));
+ else
+ return 0;
+#endif
+}
+
+gchar*
g_strdelimit (gchar *string,
const gchar *delimiters,
gchar new_delim)
{
register gchar *c;
-
- g_return_if_fail (string != NULL);
-
+
+ g_return_val_if_fail (string != NULL, NULL);
+
if (!delimiters)
delimiters = G_STR_DELIMITERS;
-
+
for (c = string; *c; c++)
{
if (strchr (delimiters, *c))
*c = new_delim;
}
+
+ return string;
+}
+
+gchar*
+g_strcanon (gchar *string,
+ const gchar *valid_chars,
+ gchar subsitutor)
+{
+ register gchar *c;
+
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (valid_chars != NULL, NULL);
+
+ for (c = string; *c; c++)
+ {
+ if (!strchr (valid_chars, *c))
+ *c = subsitutor;
+ }
+
+ return string;
+}
+
+gchar*
+g_strcompress (const gchar *source)
+{
+ const gchar *p = source, *octal;
+ gchar *dest = g_malloc (strlen (source) + 1);
+ gchar *q = dest;
+
+ while (*p)
+ {
+ if (*p == '\\')
+ {
+ p++;
+ switch (*p)
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7':
+ *q = 0;
+ octal = p;
+ while ((p < octal + 3) && (*p >= '0') && (*p <= '7'))
+ {
+ *q = (*q * 8) + (*p - '0');
+ p++;
+ }
+ q++;
+ p--;
+ break;
+ case 'b':
+ *q++ = '\b';
+ break;
+ case 'f':
+ *q++ = '\f';
+ break;
+ case 'n':
+ *q++ = '\n';
+ break;
+ case 'r':
+ *q++ = '\r';
+ break;
+ case 't':
+ *q++ = '\t';
+ break;
+ default: /* Also handles \" and \\ */
+ *q++ = *p;
+ break;
+ }
+ }
+ else
+ *q++ = *p;
+ p++;
+ }
+ *q = 0;
+
+ return dest;
+}
+
+gchar *
+g_strescape (const gchar *source,
+ const gchar *exceptions)
+{
+ const guchar *p = (guchar *) source;
+ /* Each source byte needs maximally four destination chars (\777) */
+ gchar *dest = g_malloc (strlen (source) * 4 + 1);
+ gchar *q = dest;
+ guchar excmap[256];
+
+ memset (excmap, 0, 256);
+ if (exceptions)
+ {
+ guchar *e = (guchar *) exceptions;
+
+ while (*e)
+ {
+ excmap[*e] = 1;
+ e++;
+ }
+ }
+
+ while (*p)
+ {
+ if (excmap[*p])
+ *q++ = *p;
+ else
+ {
+ switch (*p)
+ {
+ case '\b':
+ *q++ = '\\';
+ *q++ = 'b';
+ break;
+ case '\f':
+ *q++ = '\\';
+ *q++ = 'f';
+ break;
+ case '\n':
+ *q++ = '\\';
+ *q++ = 'n';
+ break;
+ case '\r':
+ *q++ = '\\';
+ *q++ = 'r';
+ break;
+ case '\t':
+ *q++ = '\\';
+ *q++ = 't';
+ break;
+ case '\\':
+ *q++ = '\\';
+ *q++ = '\\';
+ break;
+ case '"':
+ *q++ = '\\';
+ *q++ = '"';
+ break;
+ default:
+ if ((*p < ' ') || (*p >= 0177))
+ {
+ *q++ = '\\';
+ *q++ = '0' + (((*p) >> 6) & 07);
+ *q++ = '0' + (((*p) >> 3) & 07);
+ *q++ = '0' + ((*p) & 07);
+ }
+ else
+ *q++ = *p;
+ break;
+ }
+ }
+ p++;
+ }
+ *q = 0;
+ return dest;
+}
+
+/*
+ * g_filename_to_utf8
+ *
+ * Converts a string which is in the encoding used for file names by
+ * the C runtime (usually the same as that used by the operating
+ * system) in the current locale into a UTF-8 string.
+ */
+
+gchar *
+g_filename_to_utf8 (const gchar *opsysstring)
+{
+#ifdef G_OS_WIN32
+
+ gint i, clen, wclen, first;
+ const gint len = strlen (opsysstring);
+ wchar_t *wcs, wc;
+ gchar *result, *bp;
+ const wchar_t *wcp;
+
+ wcs = g_new (wchar_t, len);
+ wclen = MultiByteToWideChar (CP_ACP, 0, opsysstring, len, wcs, len);
+
+ wcp = wcs;
+ clen = 0;
+ for (i = 0; i < wclen; i++)
+ {
+ wc = *wcp++;
+
+ if (wc < 0x80)
+ clen += 1;
+ else if (wc < 0x800)
+ clen += 2;
+ else if (wc < 0x10000)
+ clen += 3;
+ else if (wc < 0x200000)
+ clen += 4;
+ else if (wc < 0x4000000)
+ clen += 5;
+ else
+ clen += 6;
+ }
+
+ result = g_malloc (clen + 1);
+
+ wcp = wcs;
+ bp = result;
+ for (i = 0; i < wclen; i++)
+ {
+ wc = *wcp++;
+
+ if (wc < 0x80)
+ {
+ first = 0;
+ clen = 1;
+ }
+ else if (wc < 0x800)
+ {
+ first = 0xc0;
+ clen = 2;
+ }
+ else if (wc < 0x10000)
+ {
+ first = 0xe0;
+ clen = 3;
+ }
+ else if (wc < 0x200000)
+ {
+ first = 0xf0;
+ clen = 4;
+ }
+ else if (wc < 0x4000000)
+ {
+ first = 0xf8;
+ clen = 5;
+ }
+ else
+ {
+ first = 0xfc;
+ clen = 6;
+ }
+
+ /* Woo-hoo! */
+ switch (clen)
+ {
+ case 6: bp[5] = (wc & 0x3f) | 0x80; wc >>= 6; /* Fall through */
+ case 5: bp[4] = (wc & 0x3f) | 0x80; wc >>= 6; /* Fall through */
+ case 4: bp[3] = (wc & 0x3f) | 0x80; wc >>= 6; /* Fall through */
+ case 3: bp[2] = (wc & 0x3f) | 0x80; wc >>= 6; /* Fall through */
+ case 2: bp[1] = (wc & 0x3f) | 0x80; wc >>= 6; /* Fall through */
+ case 1: bp[0] = wc | first;
+ }
+
+ bp += clen;
+ }
+ *bp = 0;
+
+ g_free (wcs);
+
+ return result;
+
+#else
+
+ return g_strdup (opsysstring);
+
+#endif
+}
+
+/*
+ * g_filename_from_utf8
+ *
+ * The reverse of g_filename_to_utf8.
+ */
+
+gchar *
+g_filename_from_utf8 (const gchar *utf8string)
+{
+#ifdef G_OS_WIN32
+
+ gint i, mask, clen, wclen, mblen;
+ const gint len = strlen (utf8string);
+ wchar_t *wcs, *wcp;
+ gchar *result;
+ guchar *cp, *end, c;
+ gint n;
+
+ /* First convert to wide chars */
+ cp = (guchar *) utf8string;
+ end = cp + len;
+ n = 0;
+ wcs = g_new (wchar_t, len + 1);
+ wcp = wcs;
+ while (cp != end)
+ {
+ mask = 0;
+ c = *cp;
+
+ if (c < 0x80)
+ {
+ clen = 1;
+ mask = 0x7f;
+ }
+ else if ((c & 0xe0) == 0xc0)
+ {
+ clen = 2;
+ mask = 0x1f;
+ }
+ else if ((c & 0xf0) == 0xe0)
+ {
+ clen = 3;
+ mask = 0x0f;
+ }
+ else if ((c & 0xf8) == 0xf0)
+ {
+ clen = 4;
+ mask = 0x07;
+ }
+ else if ((c & 0xfc) == 0xf8)
+ {
+ clen = 5;
+ mask = 0x03;
+ }
+ else if ((c & 0xfc) == 0xfc)
+ {
+ clen = 6;
+ mask = 0x01;
+ }
+ else
+ {
+ g_free (wcs);
+ return NULL;
+ }
+
+ if (cp + clen > end)
+ {
+ g_free (wcs);
+ return NULL;
+ }
+
+ *wcp = (cp[0] & mask);
+ for (i = 1; i < clen; i++)
+ {
+ if ((cp[i] & 0xc0) != 0x80)
+ {
+ g_free (wcs);
+ return NULL;
+ }
+ *wcp <<= 6;
+ *wcp |= (cp[i] & 0x3f);
+ }
+
+ cp += clen;
+ wcp++;
+ n++;
+ }
+ if (cp != end)
+ {
+ g_free (wcs);
+ return NULL;
+ }
+
+ /* n is the number of wide chars constructed */
+
+ /* Convert to a string in the current ANSI codepage */
+
+ result = g_new (gchar, 3 * n + 1);
+ mblen = WideCharToMultiByte (CP_ACP, 0, wcs, n, result, 3*n, NULL, NULL);
+ result[mblen] = 0;
+ g_free (wcs);
+
+ return result;
+
+#else
+
+ return g_strdup (utf8string);
+
+#endif
+}
+
+gchar*
+g_strchug (gchar *string)
+{
+ guchar *start;
+
+ g_return_val_if_fail (string != NULL, NULL);
+
+ for (start = string; *start && isspace (*start); start++)
+ ;
+
+ g_memmove (string, start, strlen( start) + 1);
+
+ return string;
+}
+
+gchar*
+g_strchomp (gchar *string)
+{
+ gchar *s;
+
+ g_return_val_if_fail (string != NULL, NULL);
+
+ if (!*string)
+ return string;
+
+ for (s = string + strlen (string) - 1; s >= string && isspace ((guchar)*s);
+ s--)
+ *s = '\0';
+
+ return string;
+}
+
+gchar**
+g_strsplit (const gchar *string,
+ const gchar *delimiter,
+ gint max_tokens)
+{
+ GSList *string_list = NULL, *slist;
+ gchar **str_array, *s;
+ guint i, n = 1;
+
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (delimiter != NULL, NULL);
+
+ if (max_tokens < 1)
+ max_tokens = G_MAXINT;
+
+ s = strstr (string, delimiter);
+ if (s)
+ {
+ guint delimiter_len = strlen (delimiter);
+
+ do
+ {
+ guint len;
+ gchar *new_string;
+
+ len = s - string;
+ new_string = g_new (gchar, len + 1);
+ strncpy (new_string, string, len);
+ new_string[len] = 0;
+ string_list = g_slist_prepend (string_list, new_string);
+ n++;
+ string = s + delimiter_len;
+ s = strstr (string, delimiter);
+ }
+ while (--max_tokens && s);
+ }
+ if (*string)
+ {
+ n++;
+ string_list = g_slist_prepend (string_list, g_strdup (string));
+ }
+
+ str_array = g_new (gchar*, n);
+
+ i = n - 1;
+
+ str_array[i--] = NULL;
+ for (slist = string_list; slist; slist = slist->next)
+ str_array[i--] = slist->data;
+
+ g_slist_free (string_list);
+
+ return str_array;
+}
+
+void
+g_strfreev (gchar **str_array)
+{
+ if (str_array)
+ {
+ int i;
+
+ for(i = 0; str_array[i] != NULL; i++)
+ g_free(str_array[i]);
+
+ g_free (str_array);
+ }
+}
+
+gchar*
+g_strjoinv (const gchar *separator,
+ gchar **str_array)
+{
+ gchar *string;
+
+ g_return_val_if_fail (str_array != NULL, NULL);
+
+ if (separator == NULL)
+ separator = "";
+
+ if (*str_array)
+ {
+ guint i, len;
+ guint separator_len;
+
+ separator_len = strlen (separator);
+ len = 1 + strlen (str_array[0]);
+ for(i = 1; str_array[i] != NULL; i++)
+ len += separator_len + strlen(str_array[i]);
+
+ string = g_new (gchar, len);
+ *string = 0;
+ strcat (string, *str_array);
+ for (i = 1; str_array[i] != NULL; i++)
+ {
+ strcat (string, separator);
+ strcat (string, str_array[i]);
+ }
+ }
+ else
+ string = g_strdup ("");
+
+ return string;
+}
+
+gchar*
+g_strjoin (const gchar *separator,
+ ...)
+{
+ gchar *string, *s;
+ va_list args;
+ guint len;
+ guint separator_len;
+
+ if (separator == NULL)
+ separator = "";
+
+ separator_len = strlen (separator);
+
+ va_start (args, separator);
+
+ s = va_arg (args, gchar*);
+
+ if (s)
+ {
+ len = strlen (s);
+
+ s = va_arg (args, gchar*);
+ while (s)
+ {
+ len += separator_len + strlen (s);
+ s = va_arg (args, gchar*);
+ }
+ va_end (args);
+
+ string = g_new (gchar, len + 1);
+ *string = 0;
+
+ va_start (args, separator);
+
+ s = va_arg (args, gchar*);
+ strcat (string, s);
+
+ s = va_arg (args, gchar*);
+ while (s)
+ {
+ strcat (string, separator);
+ strcat (string, s);
+ s = va_arg (args, gchar*);
+ }
+ }
+ else
+ string = g_strdup ("");
+
+ va_end (args);
+
+ return string;
}