Add new g_string functions for reading from file/socket descriptors, and
authorBST 1999 Tony Gale <gale@gtk.org>
Sat, 17 Apr 1999 20:04:49 +0000 (20:04 +0000)
committerTony Gale <gale@src.gnome.org>
Sat, 17 Apr 1999 20:04:49 +0000 (20:04 +0000)
Sat Apr 17 20:55:13 BST 1999  Tony Gale <gale@gtk.org>

        * glib.h, gstring.c: Add new g_string functions for reading
          from file/socket descriptors, and tokenising strings.

          Added various g_string macros.

12 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
glib.h
glib/glib.h
glib/gstring.c
gstring.c

index bd0c2ca..b07bb28 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Sat Apr 17 20:55:13 BST 1999  Tony Gale <gale@gtk.org>
+
+       * glib.h, gstring.c: Add new g_string functions for reading
+         from file/socket descriptors, and tokenising strings.
+
+         Added various g_string macros.
+
 Tue Apr 13 23:28:32 1999  Tor Lillqvist  <tml@iki.fi>
 
        * README.win32: Mention the tests directory.
index bd0c2ca..b07bb28 100644 (file)
@@ -1,3 +1,10 @@
+Sat Apr 17 20:55:13 BST 1999  Tony Gale <gale@gtk.org>
+
+       * glib.h, gstring.c: Add new g_string functions for reading
+         from file/socket descriptors, and tokenising strings.
+
+         Added various g_string macros.
+
 Tue Apr 13 23:28:32 1999  Tor Lillqvist  <tml@iki.fi>
 
        * README.win32: Mention the tests directory.
index bd0c2ca..b07bb28 100644 (file)
@@ -1,3 +1,10 @@
+Sat Apr 17 20:55:13 BST 1999  Tony Gale <gale@gtk.org>
+
+       * glib.h, gstring.c: Add new g_string functions for reading
+         from file/socket descriptors, and tokenising strings.
+
+         Added various g_string macros.
+
 Tue Apr 13 23:28:32 1999  Tor Lillqvist  <tml@iki.fi>
 
        * README.win32: Mention the tests directory.
index bd0c2ca..b07bb28 100644 (file)
@@ -1,3 +1,10 @@
+Sat Apr 17 20:55:13 BST 1999  Tony Gale <gale@gtk.org>
+
+       * glib.h, gstring.c: Add new g_string functions for reading
+         from file/socket descriptors, and tokenising strings.
+
+         Added various g_string macros.
+
 Tue Apr 13 23:28:32 1999  Tor Lillqvist  <tml@iki.fi>
 
        * README.win32: Mention the tests directory.
index bd0c2ca..b07bb28 100644 (file)
@@ -1,3 +1,10 @@
+Sat Apr 17 20:55:13 BST 1999  Tony Gale <gale@gtk.org>
+
+       * glib.h, gstring.c: Add new g_string functions for reading
+         from file/socket descriptors, and tokenising strings.
+
+         Added various g_string macros.
+
 Tue Apr 13 23:28:32 1999  Tor Lillqvist  <tml@iki.fi>
 
        * README.win32: Mention the tests directory.
index bd0c2ca..b07bb28 100644 (file)
@@ -1,3 +1,10 @@
+Sat Apr 17 20:55:13 BST 1999  Tony Gale <gale@gtk.org>
+
+       * glib.h, gstring.c: Add new g_string functions for reading
+         from file/socket descriptors, and tokenising strings.
+
+         Added various g_string macros.
+
 Tue Apr 13 23:28:32 1999  Tor Lillqvist  <tml@iki.fi>
 
        * README.win32: Mention the tests directory.
index bd0c2ca..b07bb28 100644 (file)
@@ -1,3 +1,10 @@
+Sat Apr 17 20:55:13 BST 1999  Tony Gale <gale@gtk.org>
+
+       * glib.h, gstring.c: Add new g_string functions for reading
+         from file/socket descriptors, and tokenising strings.
+
+         Added various g_string macros.
+
 Tue Apr 13 23:28:32 1999  Tor Lillqvist  <tml@iki.fi>
 
        * README.win32: Mention the tests directory.
index bd0c2ca..b07bb28 100644 (file)
@@ -1,3 +1,10 @@
+Sat Apr 17 20:55:13 BST 1999  Tony Gale <gale@gtk.org>
+
+       * glib.h, gstring.c: Add new g_string functions for reading
+         from file/socket descriptors, and tokenising strings.
+
+         Added various g_string macros.
+
 Tue Apr 13 23:28:32 1999  Tor Lillqvist  <tml@iki.fi>
 
        * README.win32: Mention the tests directory.
diff --git a/glib.h b/glib.h
index bfd1f49..44d61fd 100644 (file)
--- a/glib.h
+++ b/glib.h
@@ -1689,39 +1689,82 @@ gchar*        g_string_chunk_insert_const  (GStringChunk *chunk,
 
 /* Strings
  */
-GString* g_string_new      (const gchar *init);
-GString* g_string_sized_new (guint       dfl_size);
-void    g_string_free      (GString     *string,
-                            gint         free_segment);
-GString* g_string_assign    (GString    *lval,
-                            const gchar *rval);
-GString* g_string_truncate  (GString    *string,
-                            gint         len);
-GString* g_string_append    (GString    *string,
-                            const gchar *val);
-GString* g_string_append_c  (GString    *string,
-                            gchar        c);
-GString* g_string_prepend   (GString    *string,
-                            const gchar *val);
-GString* g_string_prepend_c (GString    *string,
-                            gchar        c);
-GString* g_string_insert    (GString    *string,
-                            gint         pos,
-                            const gchar *val);
-GString* g_string_insert_c  (GString    *string,
-                            gint         pos,
-                            gchar        c);
-GString* g_string_erase            (GString     *string,
-                            gint         pos,
-                            gint         len);
-GString* g_string_down     (GString     *string);
-GString* g_string_up       (GString     *string);
-void    g_string_sprintf   (GString     *string,
-                            const gchar *format,
-                            ...) G_GNUC_PRINTF (2, 3);
-void    g_string_sprintfa  (GString     *string,
-                            const gchar *format,
-                            ...) G_GNUC_PRINTF (2, 3);
+typedef enum
+{
+  G_STRING_ERROR_NONE,    /* No error occurred */
+  G_STRING_ERROR_INVAL,   /* Invalid input value to function */ 
+  G_STRING_ERROR_READ,    /* read() returned an error - check errno */
+  G_STRING_ERROR_NODATA,  /* No more input data - result string may contain data */
+  G_STRING_ERROR_LENGTH   /* max_length reached */
+} GStringError;
+
+#define      g_string_length(fstring)   (fstring ? fstring->len : 0)
+#define      g_string_str(fstring)      (fstring ? fstring->str : NULL)
+#define      g_string_char(fstring, n)  (fstring->str[n])
+
+#define      g_string_copy(a,b)         (g_string_assign(a, b->str))
+#define      g_string_dup(fstring)      (fstring ? g_string_new(fstring->str) :\
+                                                   g_string_new(NULL))
+
+#define      g_string_cmp(a,b)          (strcmp(g_string_str(a), \
+                                                g_string_str(b)))
+#define      g_string_ncmp(a,b,n)       (strncmp(g_string_str(a), \
+                                                 g_string_str(b), n))
+#define      g_string_casecmp(a,b)      (g_strcasecmp(g_string_str(a), \
+                                                      g_string_str(b)))
+#define      g_string_ncasecmp(a,b)     (g_strncasecmp(g_string_str(a), \
+                                                       g_string_str(b), n))
+
+#define      g_string_strcmp(a,b)       (strcmp(g_string_str(a), b))
+#define      g_string_strcasecmp(a,b)   (g_strcasecmp(g_string_str(a), b))
+
+GString*     g_string_new              (const gchar     *init);
+GString*     g_string_sized_new         (guint           dfl_size);
+void        g_string_free              (GString         *string,
+                                        gint             free_segment);
+GString*     g_string_assign            (GString        *lval,
+                                        const gchar     *rval);
+GString*     g_string_truncate          (GString        *string,
+                                        gint             len);
+GString*     g_string_append            (GString        *string,
+                                        const gchar     *val);
+GString*     g_string_append_c          (GString        *string,
+                                        gchar            c);
+GString*     g_string_prepend           (GString        *string,
+                                        const gchar     *val);
+GString*     g_string_prepend_c         (GString        *string,
+                                        gchar            c);
+GString*     g_string_insert            (GString        *string,
+                                        gint             pos,
+                                        const gchar     *val);
+GString*     g_string_insert_c          (GString        *string,
+                                        gint             pos,
+                                        gchar            c);
+GString*     g_string_erase            (GString         *string,
+                                        gint             pos,
+                                        gint             len);
+GString*     g_string_down              (GString        *string);
+GString*     g_string_up                (GString        *string);
+void         g_string_sprintf           (GString        *string,
+                                        const gchar     *format,
+                                        ...) G_GNUC_PRINTF (2, 3);
+void         g_string_sprintfa          (GString        *string,
+                                        const gchar     *format,
+                                        ...) G_GNUC_PRINTF (2, 3);
+GStringError g_string_readline          (GString        *dest_str,
+                                        gint            max_length,
+                                        gint            fd);
+GStringError g_string_readline_buffered (GString        *dest_str,
+                                        GString         *buff_str,
+                                        gint             max_length,
+                                        gint             fd,
+                                        gint             match_bare_cr);
+GList*       g_string_tokenise          (GString        *string,
+                                        gchar           *delims,
+                                        gint             max_tokens,
+                                        gint             allow_empty);
+void         g_string_tokenise_free     (GList          *tokens,
+                                        gint             free_token);
 
 
 /* Resizable arrays, remove fills any cleared spot and shortens the
index bfd1f49..44d61fd 100644 (file)
@@ -1689,39 +1689,82 @@ gchar*        g_string_chunk_insert_const  (GStringChunk *chunk,
 
 /* Strings
  */
-GString* g_string_new      (const gchar *init);
-GString* g_string_sized_new (guint       dfl_size);
-void    g_string_free      (GString     *string,
-                            gint         free_segment);
-GString* g_string_assign    (GString    *lval,
-                            const gchar *rval);
-GString* g_string_truncate  (GString    *string,
-                            gint         len);
-GString* g_string_append    (GString    *string,
-                            const gchar *val);
-GString* g_string_append_c  (GString    *string,
-                            gchar        c);
-GString* g_string_prepend   (GString    *string,
-                            const gchar *val);
-GString* g_string_prepend_c (GString    *string,
-                            gchar        c);
-GString* g_string_insert    (GString    *string,
-                            gint         pos,
-                            const gchar *val);
-GString* g_string_insert_c  (GString    *string,
-                            gint         pos,
-                            gchar        c);
-GString* g_string_erase            (GString     *string,
-                            gint         pos,
-                            gint         len);
-GString* g_string_down     (GString     *string);
-GString* g_string_up       (GString     *string);
-void    g_string_sprintf   (GString     *string,
-                            const gchar *format,
-                            ...) G_GNUC_PRINTF (2, 3);
-void    g_string_sprintfa  (GString     *string,
-                            const gchar *format,
-                            ...) G_GNUC_PRINTF (2, 3);
+typedef enum
+{
+  G_STRING_ERROR_NONE,    /* No error occurred */
+  G_STRING_ERROR_INVAL,   /* Invalid input value to function */ 
+  G_STRING_ERROR_READ,    /* read() returned an error - check errno */
+  G_STRING_ERROR_NODATA,  /* No more input data - result string may contain data */
+  G_STRING_ERROR_LENGTH   /* max_length reached */
+} GStringError;
+
+#define      g_string_length(fstring)   (fstring ? fstring->len : 0)
+#define      g_string_str(fstring)      (fstring ? fstring->str : NULL)
+#define      g_string_char(fstring, n)  (fstring->str[n])
+
+#define      g_string_copy(a,b)         (g_string_assign(a, b->str))
+#define      g_string_dup(fstring)      (fstring ? g_string_new(fstring->str) :\
+                                                   g_string_new(NULL))
+
+#define      g_string_cmp(a,b)          (strcmp(g_string_str(a), \
+                                                g_string_str(b)))
+#define      g_string_ncmp(a,b,n)       (strncmp(g_string_str(a), \
+                                                 g_string_str(b), n))
+#define      g_string_casecmp(a,b)      (g_strcasecmp(g_string_str(a), \
+                                                      g_string_str(b)))
+#define      g_string_ncasecmp(a,b)     (g_strncasecmp(g_string_str(a), \
+                                                       g_string_str(b), n))
+
+#define      g_string_strcmp(a,b)       (strcmp(g_string_str(a), b))
+#define      g_string_strcasecmp(a,b)   (g_strcasecmp(g_string_str(a), b))
+
+GString*     g_string_new              (const gchar     *init);
+GString*     g_string_sized_new         (guint           dfl_size);
+void        g_string_free              (GString         *string,
+                                        gint             free_segment);
+GString*     g_string_assign            (GString        *lval,
+                                        const gchar     *rval);
+GString*     g_string_truncate          (GString        *string,
+                                        gint             len);
+GString*     g_string_append            (GString        *string,
+                                        const gchar     *val);
+GString*     g_string_append_c          (GString        *string,
+                                        gchar            c);
+GString*     g_string_prepend           (GString        *string,
+                                        const gchar     *val);
+GString*     g_string_prepend_c         (GString        *string,
+                                        gchar            c);
+GString*     g_string_insert            (GString        *string,
+                                        gint             pos,
+                                        const gchar     *val);
+GString*     g_string_insert_c          (GString        *string,
+                                        gint             pos,
+                                        gchar            c);
+GString*     g_string_erase            (GString         *string,
+                                        gint             pos,
+                                        gint             len);
+GString*     g_string_down              (GString        *string);
+GString*     g_string_up                (GString        *string);
+void         g_string_sprintf           (GString        *string,
+                                        const gchar     *format,
+                                        ...) G_GNUC_PRINTF (2, 3);
+void         g_string_sprintfa          (GString        *string,
+                                        const gchar     *format,
+                                        ...) G_GNUC_PRINTF (2, 3);
+GStringError g_string_readline          (GString        *dest_str,
+                                        gint            max_length,
+                                        gint            fd);
+GStringError g_string_readline_buffered (GString        *dest_str,
+                                        GString         *buff_str,
+                                        gint             max_length,
+                                        gint             fd,
+                                        gint             match_bare_cr);
+GList*       g_string_tokenise          (GString        *string,
+                                        gchar           *delims,
+                                        gint             max_tokens,
+                                        gint             allow_empty);
+void         g_string_tokenise_free     (GList          *tokens,
+                                        gint             free_token);
 
 
 /* Resizable arrays, remove fills any cleared spot and shortens the
index fd8e512..f714b3a 100644 (file)
@@ -1,5 +1,6 @@
 /* GLIB - Library of useful routines for C programming
  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Portions Copyright (C) 1999 Tony Gale
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  * MT safe
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -35,6 +43,7 @@
 #include <ctype.h>
 #include "glib.h"
 
+#define G_STRING_BLOCK_SIZE 512
 
 typedef struct _GRealStringChunk GRealStringChunk;
 typedef struct _GRealString      GRealString;
@@ -189,7 +198,7 @@ g_string_chunk_insert_const (GStringChunk *fchunk,
 /* Strings.
  */
 static gint
-nearest_pow (gint num)
+nearest_power (gint num)
 {
   gint n = 1;
 
@@ -199,16 +208,36 @@ nearest_pow (gint num)
   return n;
 }
 
+static gint
+nearest_multiple (int num, const int block)
+{
+  gint n = block;
+
+  while (n < num)
+    n += block;
+
+  return n;
+}
+
 static void
 g_string_maybe_expand (GRealString* string, gint len)
 {
   if (string->len + len >= string->alloc)
     {
-      string->alloc = nearest_pow (string->len + len + 1);
+      string->alloc = nearest_power (string->len + len + 1);
       string->str = g_realloc (string->str, string->alloc);
     }
 }
 
+static void
+g_string_set_size (GRealString* string, gint size)
+{
+  if (string->alloc <= size) {
+    string->alloc = nearest_power(size + 1);
+    string->str = g_realloc (string->str, string->alloc);
+  }
+}
+
 GString*
 g_string_sized_new (guint dfl_size)
 {
@@ -512,3 +541,192 @@ g_string_sprintfa (GString *string,
   g_string_sprintfa_int (string, fmt, args);
   va_end (args);
 }
+
+GStringError
+g_string_readline (GString *dest_str,
+                  gint     max_length,
+                  gint     fd)
+{
+  gint count=0, retval;
+  gchar c;
+
+  g_return_val_if_fail (dest_str != NULL, G_STRING_ERROR_INVAL);
+  g_return_val_if_fail (max_length > 0, G_STRING_ERROR_INVAL);
+  g_string_truncate(dest_str, 0);
+
+  for (count = 0; count < max_length; count++) {
+    if ( (retval = read(fd, &c, 1)) == 1 ) {
+      if (c == '\r') {
+        continue;
+      }
+      if (c == '\n') {
+        return(G_STRING_ERROR_NONE);
+      }
+      g_string_maybe_expand ((GRealString *) dest_str, 1);
+      dest_str->str[dest_str->len++] = c;
+      dest_str->str[dest_str->len] = 0;
+    } else if (retval == 0) {
+       return(G_STRING_ERROR_NODATA);
+    } else {
+      return(G_STRING_ERROR_READ);
+    }
+  }
+  return(G_STRING_ERROR_LENGTH);
+}
+
+GStringError
+g_string_readline_buffered (GString *dest_str,
+                           GString *buff_str,
+                           gint     max_length,
+                           gint     fd,
+                           gint     match_bare_cr)
+{
+  guint count, i=0, buff_size;
+
+  g_return_val_if_fail (dest_str != NULL, G_STRING_ERROR_INVAL);
+  g_return_val_if_fail (buff_str != NULL, G_STRING_ERROR_INVAL);
+  g_return_val_if_fail (max_length > 0, G_STRING_ERROR_INVAL);
+
+  /* Make the buffer a multiple of G_STRING_BLOCK_SIZE and
+   * bigger then max_length */
+  buff_size = nearest_multiple(max_length, G_STRING_BLOCK_SIZE);
+  g_string_set_size( (GRealString *) buff_str, buff_size);
+
+  do {
+    /* Allow the buffer to empty before reading more data.
+     * Prevents blocking on read() when data in the buffer */
+
+    if (buff_str->len != 0) {
+      /* Search for a CRLF, CR or LF */
+      for (i = 0; i < max_length-1; i++) {
+
+       /* Look for a CR */
+       if (buff_str->str[i] == '\r') {
+
+         /* Check for CRLF */
+         if (buff_str->str[i+1] == '\n') {
+           buff_str->str[i] = '\0';
+           i++;
+         } else if (match_bare_cr) {
+           buff_str->str[i] = '\0';
+         } else {
+           continue;
+         }
+
+         /* Copy the line to the destination string and
+          * remove it from the buffer */
+         g_string_assign( dest_str, buff_str->str );
+         g_string_erase( buff_str, 0, i+1);
+         return (G_STRING_ERROR_NONE);
+       }
+
+       /* Look for LF */
+       if (buff_str->str[i] == '\n') {
+         buff_str->str[i] = '\0';
+
+         /* Copy the line to the destination string and
+          * remove it from the buffer */
+         g_string_assign( dest_str, buff_str->str );
+         g_string_erase( buff_str, 0, i+1);
+         return (G_STRING_ERROR_NONE);      
+       }
+
+       /* If we hit a '\0' then we've exhausted the buffer */
+       if (buff_str->str[i] == '\0') {
+         break;
+       }
+      }
+    }
+
+    /* Read in a block of data, appending it to the buffer */
+    if ( (count = read(fd, buff_str->str + buff_str->len,
+                      buff_size - buff_str->len - 1)) < 0) {
+      return (G_STRING_ERROR_READ);
+    } else if (count == 0) {
+      return (G_STRING_ERROR_NODATA);
+    } else {
+      /* Fix up the buffer */
+      buff_str->len += count;
+      buff_str->str[buff_str->len] = '\0';
+    }
+
+  } while (i != max_length-1);
+
+  /* If we get here then we have reached max_length */
+  g_string_assign (dest_str, buff_str->str);
+  g_string_truncate (dest_str, max_length-1);
+  g_string_erase (buff_str, 0, max_length-1);
+
+  return (G_STRING_ERROR_LENGTH);
+}
+
+GList*
+g_string_tokenise (GString *string,
+                  gchar   *delims,
+                  gint     max_tokens,
+                  gint     allow_empty)
+{
+  GList *tokens=NULL;
+  GString *token;
+  gchar *current, *start, c;
+  guint count=1;
+
+  g_return_val_if_fail (string != NULL, NULL);
+  g_return_val_if_fail (delims != NULL, NULL);
+
+  if (max_tokens < 1) {
+    max_tokens = G_MAXINT;
+  }
+
+  current = string->str;
+  while (*current) {
+    /* Remove any leading delimiters */
+    if (!allow_empty) {
+      while ( *current && (strchr(delims, *current) != NULL) ) {
+        current++;
+      }
+    }
+
+    /* If we've reached max_tokens, use the remaining input string
+     * as the last token */
+    if (count == max_tokens) {
+      token = g_string_new(current);
+      tokens = g_list_append(tokens, token);
+      return (tokens);
+    }
+
+    /* Find the extent of the current token */
+    if ( *current ) {
+      start = current;
+      while ( *current && (strchr(delims, *current) == NULL) ) {
+        current++;
+      }
+      c = *current;
+      *current = '\0';
+      token = g_string_new( start );
+      *current = c;
+      tokens = g_list_append(tokens, token);
+      count++;
+      if (*current) {
+        current++;
+      }
+    }
+  }
+
+  return (tokens);
+}
+
+void
+g_string_tokenise_free (GList *tokens,
+                       gint   free_token)
+{
+
+  if (free_token) {
+    while(tokens) {
+      g_string_free( (GString *) tokens->data, TRUE );
+      tokens = g_list_next(tokens);
+    }
+  }
+
+  g_list_free(tokens);
+}
index fd8e512..f714b3a 100644 (file)
--- a/gstring.c
+++ b/gstring.c
@@ -1,5 +1,6 @@
 /* GLIB - Library of useful routines for C programming
  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Portions Copyright (C) 1999 Tony Gale
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  * MT safe
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -35,6 +43,7 @@
 #include <ctype.h>
 #include "glib.h"
 
+#define G_STRING_BLOCK_SIZE 512
 
 typedef struct _GRealStringChunk GRealStringChunk;
 typedef struct _GRealString      GRealString;
@@ -189,7 +198,7 @@ g_string_chunk_insert_const (GStringChunk *fchunk,
 /* Strings.
  */
 static gint
-nearest_pow (gint num)
+nearest_power (gint num)
 {
   gint n = 1;
 
@@ -199,16 +208,36 @@ nearest_pow (gint num)
   return n;
 }
 
+static gint
+nearest_multiple (int num, const int block)
+{
+  gint n = block;
+
+  while (n < num)
+    n += block;
+
+  return n;
+}
+
 static void
 g_string_maybe_expand (GRealString* string, gint len)
 {
   if (string->len + len >= string->alloc)
     {
-      string->alloc = nearest_pow (string->len + len + 1);
+      string->alloc = nearest_power (string->len + len + 1);
       string->str = g_realloc (string->str, string->alloc);
     }
 }
 
+static void
+g_string_set_size (GRealString* string, gint size)
+{
+  if (string->alloc <= size) {
+    string->alloc = nearest_power(size + 1);
+    string->str = g_realloc (string->str, string->alloc);
+  }
+}
+
 GString*
 g_string_sized_new (guint dfl_size)
 {
@@ -512,3 +541,192 @@ g_string_sprintfa (GString *string,
   g_string_sprintfa_int (string, fmt, args);
   va_end (args);
 }
+
+GStringError
+g_string_readline (GString *dest_str,
+                  gint     max_length,
+                  gint     fd)
+{
+  gint count=0, retval;
+  gchar c;
+
+  g_return_val_if_fail (dest_str != NULL, G_STRING_ERROR_INVAL);
+  g_return_val_if_fail (max_length > 0, G_STRING_ERROR_INVAL);
+  g_string_truncate(dest_str, 0);
+
+  for (count = 0; count < max_length; count++) {
+    if ( (retval = read(fd, &c, 1)) == 1 ) {
+      if (c == '\r') {
+        continue;
+      }
+      if (c == '\n') {
+        return(G_STRING_ERROR_NONE);
+      }
+      g_string_maybe_expand ((GRealString *) dest_str, 1);
+      dest_str->str[dest_str->len++] = c;
+      dest_str->str[dest_str->len] = 0;
+    } else if (retval == 0) {
+       return(G_STRING_ERROR_NODATA);
+    } else {
+      return(G_STRING_ERROR_READ);
+    }
+  }
+  return(G_STRING_ERROR_LENGTH);
+}
+
+GStringError
+g_string_readline_buffered (GString *dest_str,
+                           GString *buff_str,
+                           gint     max_length,
+                           gint     fd,
+                           gint     match_bare_cr)
+{
+  guint count, i=0, buff_size;
+
+  g_return_val_if_fail (dest_str != NULL, G_STRING_ERROR_INVAL);
+  g_return_val_if_fail (buff_str != NULL, G_STRING_ERROR_INVAL);
+  g_return_val_if_fail (max_length > 0, G_STRING_ERROR_INVAL);
+
+  /* Make the buffer a multiple of G_STRING_BLOCK_SIZE and
+   * bigger then max_length */
+  buff_size = nearest_multiple(max_length, G_STRING_BLOCK_SIZE);
+  g_string_set_size( (GRealString *) buff_str, buff_size);
+
+  do {
+    /* Allow the buffer to empty before reading more data.
+     * Prevents blocking on read() when data in the buffer */
+
+    if (buff_str->len != 0) {
+      /* Search for a CRLF, CR or LF */
+      for (i = 0; i < max_length-1; i++) {
+
+       /* Look for a CR */
+       if (buff_str->str[i] == '\r') {
+
+         /* Check for CRLF */
+         if (buff_str->str[i+1] == '\n') {
+           buff_str->str[i] = '\0';
+           i++;
+         } else if (match_bare_cr) {
+           buff_str->str[i] = '\0';
+         } else {
+           continue;
+         }
+
+         /* Copy the line to the destination string and
+          * remove it from the buffer */
+         g_string_assign( dest_str, buff_str->str );
+         g_string_erase( buff_str, 0, i+1);
+         return (G_STRING_ERROR_NONE);
+       }
+
+       /* Look for LF */
+       if (buff_str->str[i] == '\n') {
+         buff_str->str[i] = '\0';
+
+         /* Copy the line to the destination string and
+          * remove it from the buffer */
+         g_string_assign( dest_str, buff_str->str );
+         g_string_erase( buff_str, 0, i+1);
+         return (G_STRING_ERROR_NONE);      
+       }
+
+       /* If we hit a '\0' then we've exhausted the buffer */
+       if (buff_str->str[i] == '\0') {
+         break;
+       }
+      }
+    }
+
+    /* Read in a block of data, appending it to the buffer */
+    if ( (count = read(fd, buff_str->str + buff_str->len,
+                      buff_size - buff_str->len - 1)) < 0) {
+      return (G_STRING_ERROR_READ);
+    } else if (count == 0) {
+      return (G_STRING_ERROR_NODATA);
+    } else {
+      /* Fix up the buffer */
+      buff_str->len += count;
+      buff_str->str[buff_str->len] = '\0';
+    }
+
+  } while (i != max_length-1);
+
+  /* If we get here then we have reached max_length */
+  g_string_assign (dest_str, buff_str->str);
+  g_string_truncate (dest_str, max_length-1);
+  g_string_erase (buff_str, 0, max_length-1);
+
+  return (G_STRING_ERROR_LENGTH);
+}
+
+GList*
+g_string_tokenise (GString *string,
+                  gchar   *delims,
+                  gint     max_tokens,
+                  gint     allow_empty)
+{
+  GList *tokens=NULL;
+  GString *token;
+  gchar *current, *start, c;
+  guint count=1;
+
+  g_return_val_if_fail (string != NULL, NULL);
+  g_return_val_if_fail (delims != NULL, NULL);
+
+  if (max_tokens < 1) {
+    max_tokens = G_MAXINT;
+  }
+
+  current = string->str;
+  while (*current) {
+    /* Remove any leading delimiters */
+    if (!allow_empty) {
+      while ( *current && (strchr(delims, *current) != NULL) ) {
+        current++;
+      }
+    }
+
+    /* If we've reached max_tokens, use the remaining input string
+     * as the last token */
+    if (count == max_tokens) {
+      token = g_string_new(current);
+      tokens = g_list_append(tokens, token);
+      return (tokens);
+    }
+
+    /* Find the extent of the current token */
+    if ( *current ) {
+      start = current;
+      while ( *current && (strchr(delims, *current) == NULL) ) {
+        current++;
+      }
+      c = *current;
+      *current = '\0';
+      token = g_string_new( start );
+      *current = c;
+      tokens = g_list_append(tokens, token);
+      count++;
+      if (*current) {
+        current++;
+      }
+    }
+  }
+
+  return (tokens);
+}
+
+void
+g_string_tokenise_free (GList *tokens,
+                       gint   free_token)
+{
+
+  if (free_token) {
+    while(tokens) {
+      g_string_free( (GString *) tokens->data, TRUE );
+      tokens = g_list_next(tokens);
+    }
+  }
+
+  g_list_free(tokens);
+}