From 32aecf31a71601572137a1b6542bfcbc112c489b Mon Sep 17 00:00:00 2001 From: BST 1999 Tony Gale Date: Sat, 17 Apr 1999 20:04:49 +0000 Subject: [PATCH] Add new g_string functions for reading from file/socket descriptors, and Sat Apr 17 20:55:13 BST 1999 Tony Gale * glib.h, gstring.c: Add new g_string functions for reading from file/socket descriptors, and tokenising strings. Added various g_string macros. --- ChangeLog | 7 ++ ChangeLog.pre-2-0 | 7 ++ ChangeLog.pre-2-10 | 7 ++ ChangeLog.pre-2-12 | 7 ++ ChangeLog.pre-2-2 | 7 ++ ChangeLog.pre-2-4 | 7 ++ ChangeLog.pre-2-6 | 7 ++ ChangeLog.pre-2-8 | 7 ++ glib.h | 109 +++++++++++++++------- glib/glib.h | 109 +++++++++++++++------- glib/gstring.c | 222 ++++++++++++++++++++++++++++++++++++++++++++- gstring.c | 222 ++++++++++++++++++++++++++++++++++++++++++++- 12 files changed, 648 insertions(+), 70 deletions(-) diff --git a/ChangeLog b/ChangeLog index bd0c2cac2..b07bb2805 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Sat Apr 17 20:55:13 BST 1999 Tony Gale + + * 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 * README.win32: Mention the tests directory. diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index bd0c2cac2..b07bb2805 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,10 @@ +Sat Apr 17 20:55:13 BST 1999 Tony Gale + + * 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 * README.win32: Mention the tests directory. diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index bd0c2cac2..b07bb2805 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,10 @@ +Sat Apr 17 20:55:13 BST 1999 Tony Gale + + * 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 * README.win32: Mention the tests directory. diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index bd0c2cac2..b07bb2805 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,10 @@ +Sat Apr 17 20:55:13 BST 1999 Tony Gale + + * 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 * README.win32: Mention the tests directory. diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index bd0c2cac2..b07bb2805 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,10 @@ +Sat Apr 17 20:55:13 BST 1999 Tony Gale + + * 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 * README.win32: Mention the tests directory. diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index bd0c2cac2..b07bb2805 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,10 @@ +Sat Apr 17 20:55:13 BST 1999 Tony Gale + + * 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 * README.win32: Mention the tests directory. diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index bd0c2cac2..b07bb2805 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,10 @@ +Sat Apr 17 20:55:13 BST 1999 Tony Gale + + * 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 * README.win32: Mention the tests directory. diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index bd0c2cac2..b07bb2805 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,10 @@ +Sat Apr 17 20:55:13 BST 1999 Tony Gale + + * 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 * README.win32: Mention the tests directory. diff --git a/glib.h b/glib.h index bfd1f49bf..44d61fd0a 100644 --- 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 diff --git a/glib/glib.h b/glib/glib.h index bfd1f49bf..44d61fd0a 100644 --- a/glib/glib.h +++ b/glib/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 diff --git a/glib/gstring.c b/glib/gstring.c index fd8e5122c..f714b3a53 100644 --- a/glib/gstring.c +++ b/glib/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 @@ -28,6 +29,13 @@ * MT safe */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif #include #include #include @@ -35,6 +43,7 @@ #include #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); +} diff --git a/gstring.c b/gstring.c index fd8e5122c..f714b3a53 100644 --- 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 @@ -28,6 +29,13 @@ * MT safe */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif #include #include #include @@ -35,6 +43,7 @@ #include #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); +}