[gnome-keyring] gcr: More record functionality.



commit 2383cf15f17f79240c442456488c2e4886e0811c
Author: Stef Walter <stefw collabora co uk>
Date:   Fri May 13 21:06:30 2011 +0200

    gcr: More record functionality.
    
     * Add boxed type for records
     * Allow parsing of space delimited records.
     * Lookup unsigned integers in records.
     * More tests for GcrRecord
    
    https://bugzilla.gnome.org/show_bug.cgi?id=650255

 docs/reference/gcr/gcr-sections.txt |    1 +
 gcr/gcr-record.c                    |  138 +++++++++++++++++++++++++++++++----
 gcr/gcr-record.h                    |   15 ++++
 gcr/tests/test-record.c             |  122 ++++++++++++++++++++++++++++++-
 4 files changed, 257 insertions(+), 19 deletions(-)
---
diff --git a/docs/reference/gcr/gcr-sections.txt b/docs/reference/gcr/gcr-sections.txt
index d4240e4..11f19dc 100644
--- a/docs/reference/gcr/gcr-sections.txt
+++ b/docs/reference/gcr/gcr-sections.txt
@@ -449,6 +449,7 @@ GCR_IS_GNUPG_KEY
 GCR_IS_GNUPG_KEY_CLASS
 GCR_TYPE_GNUPG_COLLECTION
 GCR_TYPE_GNUPG_KEY
+GCR_TYPE_RECORD
 GcrRecordColumns
 GcrRecordPubColumns
 GcrRecordUidColumns
diff --git a/gcr/gcr-record.c b/gcr/gcr-record.c
index 25a1bb2..b0a3924 100644
--- a/gcr/gcr-record.c
+++ b/gcr/gcr-record.c
@@ -27,31 +27,69 @@
 #define DEBUG_FLAG GCR_DEBUG_PARSE
 #include "gcr-debug.h"
 
+#include <stdlib.h>
 #include <string.h>
 
 #define MAX_COLUMNS 32
 
 struct _GcrRecord {
 	gchar *data;
+	gsize n_data;
 	gchar *columns[MAX_COLUMNS];
 	guint n_columns;
 };
 
+GType
+_gcr_record_get_boxed_type (void)
+{
+	static gsize initialization_value = 0;
+	static GType type = 0;
+
+	if (g_once_init_enter (&initialization_value)) {
+		type = g_boxed_type_register_static ("GcrRecord",
+		                                     (GBoxedCopyFunc)_gcr_record_copy,
+		                                     (GBoxedFreeFunc)_gcr_record_free);
+		g_once_init_leave (&initialization_value, 1);
+	}
+
+	return type;
+}
+
+GcrRecord*
+_gcr_record_copy (GcrRecord *record)
+{
+	GcrRecord *result;
+	gchar *column;
+	guint i;
+
+	result = g_slice_new0 (GcrRecord);
+	result->data = g_memdup (record->data, record->n_data);
+	result->n_data = record->n_data;
+
+	for (i = 0; i < record->n_columns; i++) {
+		column = (gchar*)record->columns[i];
+		g_assert (column >= record->data);
+		result->columns[i] = result->data + (column - record->data);
+	}
+	result->n_columns = record->n_columns;
+	return result;
+}
+
 static GcrRecord*
-parse_internal (gchar *line, gsize n_line)
+take_and_parse_internal (gchar *line, gchar delimiter, gboolean allow_empty)
 {
 	GcrRecord *result;
-	gchar *p;
+	gchar *at, *beg, *end;
 
 	g_assert (line);
-	g_assert (n_line);
 
 	result = g_slice_new0 (GcrRecord);
 	result->data = line;
+	result->n_data = strlen (line) + 1;
 
-	_gcr_debug ("parsing line %.*s", (gint)n_line, line);
+	_gcr_debug ("parsing line %s", line);
 
-	p = result->data;
+	at = result->data;
 	for (;;) {
 		if (result->n_columns >= MAX_COLUMNS) {
 			_gcr_debug ("too many record (%d) in gnupg line", MAX_COLUMNS);
@@ -59,14 +97,23 @@ parse_internal (gchar *line, gsize n_line)
 			return NULL;
 		}
 
-		result->columns[result->n_columns] = p;
-		result->n_columns++;
+		beg = at;
+		result->columns[result->n_columns] = beg;
+
+		at = strchr (beg, delimiter);
+		if (at == NULL) {
+			end = (result->data + result->n_data) - 1;
+		} else {
+			at[0] = '\0';
+			end = at;
+			at++;
+		}
+
+		if (allow_empty || end > beg)
+			result->n_columns++;
 
-		p = strchr (p, ':');
-		if (p == NULL)
+		if (at == NULL)
 			break;
-		p[0] = '\0';
-		p++;
 	}
 
 	return result;
@@ -78,11 +125,32 @@ _gcr_record_parse_colons (const gchar *line, gssize n_line)
 	g_return_val_if_fail (line, NULL);
 	if (n_line < 0)
 		n_line = strlen (line);
+	return take_and_parse_internal (g_strndup (line, n_line), ':', TRUE);
+}
+
+GcrRecord*
+_gcr_record_take_colons (gchar *line)
+{
+	GcrRecord *record;
 
-	return parse_internal (g_strndup (line, n_line), n_line);
+	g_return_val_if_fail (line, NULL);
+	record = take_and_parse_internal (line, ':', TRUE);
+	if (record == NULL)
+		g_warning ("internal parsing of colons format failed");
+	return record;
 }
 
 GcrRecord*
+_gcr_record_parse_spaces (const gchar *line, gssize n_line)
+{
+	g_return_val_if_fail (line, NULL);
+	if (n_line < 0)
+		n_line = strlen (line);
+	return take_and_parse_internal (g_strndup (line, n_line), ' ', FALSE);
+}
+
+
+GcrRecord*
 _gcr_record_find (GPtrArray *records, GQuark schema)
 {
 	guint i;
@@ -98,6 +166,13 @@ _gcr_record_find (GPtrArray *records, GQuark schema)
 	return NULL;
 }
 
+guint
+_gcr_record_get_count (GcrRecord *record)
+{
+	g_return_val_if_fail (record, 0);
+	return record->n_columns;
+}
+
 gchar*
 _gcr_record_get_string (GcrRecord *record, guint column)
 {
@@ -118,14 +193,45 @@ _gcr_record_get_string (GcrRecord *record, guint column)
 	converted = g_convert (text, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
 	g_free (text);
 
-	if (!converted) {
-		_gcr_debug ("failed to convert value from latin1 to utf-8: %s", text);
-		return NULL;
-	}
+	/*
+	 * latin1 to utf-8 conversion can't really fail, just produce
+	 * garbage... so there's no need to check here.
+	 */
 
 	return converted;
 }
 
+gboolean
+_gcr_record_get_uint (GcrRecord *record, guint column, guint *value)
+{
+	const gchar *raw;
+	glong result;
+	gchar *end = NULL;
+
+	g_return_val_if_fail (record, FALSE);
+
+	raw = _gcr_record_get_raw (record, column);
+	if (raw == NULL)
+		return FALSE;
+
+	result = strtol (raw, &end, 10);
+	if (!end || end[0]) {
+		_gcr_debug ("invalid unsigned integer value: %s", raw);
+		return FALSE;
+	}
+
+	if (result < 0 || result > G_MAXUINT32) {
+		_gcr_debug ("unsigned integer value is out of range: %s", raw);
+		return FALSE;
+	}
+
+	if (value)
+		*value = (guint)result;
+	return TRUE;
+}
+
+
+
 const gchar*
 _gcr_record_get_raw (GcrRecord *record, guint column)
 {
diff --git a/gcr/gcr-record.h b/gcr/gcr-record.h
index b3a54ae..268d5a8 100644
--- a/gcr/gcr-record.h
+++ b/gcr/gcr-record.h
@@ -29,6 +29,7 @@
 #define GCR_RECORD_H
 
 #include <glib.h>
+#include <glib-object.h>
 
 /*
  * Gnupg's official format for listing keys is in the '--with-colons' format.
@@ -85,9 +86,17 @@ typedef enum {
 
 typedef struct _GcrRecord GcrRecord;
 
+#define        GCR_TYPE_RECORD                  (_gcr_record_get_boxed_type ())
+
+GType          _gcr_record_get_boxed_type       (void) G_GNUC_CONST;
+
+GcrRecord*     _gcr_record_copy                 (GcrRecord *record);
+
 GcrRecord*     _gcr_record_parse_colons         (const gchar *line,
                                                  gssize n_line);
 
+GcrRecord*     _gcr_record_take_colons          (gchar *line);
+
 GcrRecord*     _gcr_record_parse_spaces         (const gchar *line,
                                                  gssize n_line);
 
@@ -96,9 +105,15 @@ void           _gcr_record_free                 (gpointer record);
 GcrRecord*     _gcr_record_find                 (GPtrArray *records,
                                                  GQuark schema);
 
+guint          _gcr_record_get_count            (GcrRecord *record);
+
 gchar*         _gcr_record_get_string           (GcrRecord *record,
                                                  guint column);
 
+gboolean       _gcr_record_get_uint             (GcrRecord *record,
+                                                 guint column,
+                                                 guint *value);
+
 const gchar*   _gcr_record_get_raw              (GcrRecord *record,
                                                  guint column);
 
diff --git a/gcr/tests/test-record.c b/gcr/tests/test-record.c
index 0cf91b8..7d7073f 100644
--- a/gcr/tests/test-record.c
+++ b/gcr/tests/test-record.c
@@ -35,7 +35,7 @@ typedef struct {
 static void
 setup (Test *test, gconstpointer unused)
 {
-	test->record = _gcr_record_parse_colons ("one:tab\\there::four:f\xfc""nf:", -1);
+	test->record = _gcr_record_parse_colons ("one:tab\\there::four:f\xfc""nf:3533333:-88", -1);
 }
 
 static void
@@ -45,7 +45,13 @@ teardown (Test *test, gconstpointer unused)
 }
 
 static void
-test_parse (void)
+test_count (Test *test, gconstpointer unused)
+{
+	g_assert_cmpuint (_gcr_record_get_count (test->record), ==, 7);
+}
+
+static void
+test_parse_colons (void)
 {
 	GcrRecord *record;
 
@@ -64,6 +70,45 @@ test_parse (void)
 }
 
 static void
+test_take_colons (void)
+{
+	GcrRecord *record;
+
+	record = _gcr_record_take_colons (g_strdup ("one:two::four::six"));
+	g_assert (record);
+
+	g_assert_cmpstr (_gcr_record_get_raw (record, 0), ==, "one");
+	g_assert_cmpstr (_gcr_record_get_raw (record, 1), ==, "two");
+	g_assert_cmpstr (_gcr_record_get_raw (record, 2), ==, "");
+	g_assert_cmpstr (_gcr_record_get_raw (record, 3), ==, "four");
+	g_assert_cmpstr (_gcr_record_get_raw (record, 4), ==, "");
+	g_assert_cmpstr (_gcr_record_get_raw (record, 5), ==, "six");
+	g_assert (_gcr_record_get_raw (record, 6) == NULL);
+	g_assert_cmpuint (_gcr_record_get_count (record), ==, 6);
+
+	_gcr_record_free (record);
+}
+
+
+static void
+test_parse_spaces (void)
+{
+	GcrRecord *record;
+
+	record = _gcr_record_parse_spaces (" one two  four six   ", -1);
+	g_assert (record);
+
+	g_assert_cmpstr (_gcr_record_get_raw (record, 0), ==, "one");
+	g_assert_cmpstr (_gcr_record_get_raw (record, 1), ==, "two");
+	g_assert_cmpstr (_gcr_record_get_raw (record, 2), ==, "four");
+	g_assert_cmpstr (_gcr_record_get_raw (record, 3), ==, "six");
+	g_assert (_gcr_record_get_raw (record, 4) == NULL);
+	g_assert_cmpuint (_gcr_record_get_count (record), ==, 4);
+
+	_gcr_record_free (record);
+}
+
+static void
 test_parse_part (void)
 {
 	GcrRecord *record;
@@ -142,6 +187,34 @@ test_get_string_latin1 (Test *test, gconstpointer unused)
 }
 
 static void
+test_get_uint (Test *test, gconstpointer unused)
+{
+	guint value = 0;
+
+	if (!_gcr_record_get_uint (test->record, 5, &value))
+		g_assert_not_reached ();
+	g_assert_cmpuint (value, ==, 3533333);
+}
+
+static void
+test_get_uint_range (Test *test, gconstpointer unused)
+{
+	guint value = 0;
+
+	if (_gcr_record_get_uint (test->record, 6, &value))
+		g_assert_not_reached ();
+}
+
+static void
+test_get_uint_invalid (Test *test, gconstpointer unused)
+{
+	guint value = 0;
+
+	if (_gcr_record_get_uint (test->record, 0, &value))
+		g_assert_not_reached ();
+}
+
+static void
 test_free_null (void)
 {
 	_gcr_record_free (NULL);
@@ -161,19 +234,62 @@ test_get_schema (Test *test, gconstpointer unused)
 	g_assert_cmpstr (g_quark_to_string (schema), ==, "one");
 }
 
+static void
+test_copy (Test *test, gconstpointer unused)
+{
+	GcrRecord *copy;
+	guint count, i;
+
+	copy = _gcr_record_copy (test->record);
+
+	count = _gcr_record_get_count (test->record);
+	g_assert_cmpuint (_gcr_record_get_count (copy), ==, count);
+	for (i = 0; i < count; i++) {
+		g_assert_cmpstr (_gcr_record_get_raw (copy, i), ==,
+		                 _gcr_record_get_raw (test->record, i));
+	}
+}
+
+static void
+test_boxed (Test *test, gconstpointer unused)
+{
+	GcrRecord *copy;
+	guint count, i;
+
+	copy = g_boxed_copy (GCR_TYPE_RECORD, test->record);
+
+	count = _gcr_record_get_count (test->record);
+	g_assert_cmpuint (_gcr_record_get_count (copy), ==, count);
+	for (i = 0; i < count; i++) {
+		g_assert_cmpstr (_gcr_record_get_raw (copy, i), ==,
+		                 _gcr_record_get_raw (test->record, i));
+	}
+
+	g_boxed_free (GCR_TYPE_RECORD, copy);
+}
+
 int
 main (int argc, char **argv)
 {
+	g_type_init ();
 	g_test_init (&argc, &argv, NULL);
 
-	g_test_add_func ("/gcr/record/parse", test_parse);
+	g_test_add_func ("/gcr/record/parse_colons", test_parse_colons);
+	g_test_add_func ("/gcr/record/take_colons", test_take_colons);
+	g_test_add_func ("/gcr/record/parse_colons", test_parse_spaces);
 	g_test_add_func ("/gcr/record/parse_part", test_parse_part);
 	g_test_add_func ("/gcr/record/parse_too_long", test_parse_too_long);
 	g_test_add_func ("/gcr/record/free_null", test_free_null);
 	g_test_add_func ("/gcr/record/find", test_find);
+	g_test_add ("/gcr/record/count", Test, NULL, setup, test_count, teardown);
+	g_test_add ("/gcr/record/copy", Test, NULL, setup, test_copy, teardown);
+	g_test_add ("/gcr/record/boxed", Test, NULL, setup, test_boxed, teardown);
 	g_test_add ("/gcr/record/get_string", Test, NULL, setup, test_get_string, teardown);
 	g_test_add ("/gcr/record/get_string_null", Test, NULL, setup, test_get_string_null, teardown);
 	g_test_add ("/gcr/record/get_string_latin1", Test, NULL, setup, test_get_string_latin1, teardown);
+	g_test_add ("/gcr/record/get_uint", Test, NULL, setup, test_get_uint, teardown);
+	g_test_add ("/gcr/record/get_uint_invalid", Test, NULL, setup, test_get_uint_invalid, teardown);
+	g_test_add ("/gcr/record/get_uint_range", Test, NULL, setup, test_get_uint_range, teardown);
 	g_test_add ("/gcr/record/get_schema", Test, NULL, setup, test_get_schema, teardown);
 
 	return g_test_run ();



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]