[gmime] Replaced GMimeHeaderIter with an indexed API
- From: Jeffrey Stedfast <fejj src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gmime] Replaced GMimeHeaderIter with an indexed API
- Date: Tue, 31 Jan 2017 18:48:50 +0000 (UTC)
commit a7d9687d85c27bfed11616a599a5e89e1e06107b
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date: Tue Jan 31 13:48:03 2017 -0500
Replaced GMimeHeaderIter with an indexed API
TODO | 4 +
gmime.spec.in | 2 +-
gmime/Makefile.am | 40 ++--
gmime/gmime-header.c | 696 ++++++++++++-----------------------------
gmime/gmime-header.h | 90 +-----
gmime/gmime-message-partial.c | 30 +-
gmime/gmime-message.c | 70 ++---
tests/test-headers.c | 282 +++--------------
8 files changed, 333 insertions(+), 881 deletions(-)
---
diff --git a/TODO b/TODO
index e14f763..b79c13f 100644
--- a/TODO
+++ b/TODO
@@ -9,6 +9,10 @@ GMime 2.8 / 3.0 Planning:
- Drop the use of GMimeHeaderList's stream cache and instead solve
this problem by using a per-header cache of the original raw value.
+- Kill off GMimeHeaderIter - that API sucks. Let's provide an
+ index-based accessor for particular GMimeHeaders in GMimeHeaderList.
+ Something like g_mime_header_list_get_header_at(int index).
+
- Fix g_mime_message_[g,s]set_sender() to take/return an
InternetAddressList to be more consistent with the recipient
functions as well as being less error-prone.
diff --git a/gmime.spec.in b/gmime.spec.in
index 8f2bb69..614297d 100644
--- a/gmime.spec.in
+++ b/gmime.spec.in
@@ -80,7 +80,7 @@ rm -rf $RPM_BUILD_ROOT
%{prefix}/lib/*.sh
%{prefix}/lib/libgmime*
%{prefix}/lib/pkgconfig/*
-%{prefix}/include/gmime-2.6/gmime/*.h
+%{prefix}/include/gmime-3.0/gmime/*.h
%if %{enable_gtk_doc}
%{_datadir}/gtk-doc/html/*/*
%endif
diff --git a/gmime/Makefile.am b/gmime/Makefile.am
index 6808cc5..b4433f4 100644
--- a/gmime/Makefile.am
+++ b/gmime/Makefile.am
@@ -17,9 +17,9 @@ noinst_PROGRAMS = gen-table charset-map
EXTRA_DIST = gmime-version.h.in gmime-version.h
-lib_LTLIBRARIES = libgmime-2.6.la
+lib_LTLIBRARIES = libgmime-3.0.la
-libgmime_2_6_la_SOURCES = \
+libgmime_3_0_la_SOURCES = \
gmime.c \
gmime-certificate.c \
gmime-charset.c \
@@ -156,8 +156,8 @@ install-libtool-import-lib:
uninstall-libtool-import-lib:
endif
-libgmime_2_6_la_LIBADD = $(top_builddir)/util/libutil.la $(GLIB_LIBS)
-libgmime_2_6_la_LDFLAGS = \
+libgmime_3_0_la_LIBADD = $(top_builddir)/util/libutil.la $(GLIB_LIBS)
+libgmime_3_0_la_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
-export-dynamic $(no_undefined)
@@ -179,18 +179,18 @@ INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir)
INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
if HAVE_INTROSPECTION
-GMime-2.6.gir: libgmime-2.6.la
-GMime_2_6_gir_INCLUDES = GObject-2.0 Gio-2.0
-GMime_2_6_gir_CFLAGS = $(AM_CPPFLAGS)
-GMime_2_6_gir_LIBS = libgmime-2.6.la
-GMime_2_6_gir_FILES = $(gmimeinclude_HEADERS) $(libgmime_2_6_la_SOURCES)
-GMime_2_6_gir_EXPORT_PACKAGES = gmime-2.6
-GMime_2_6_gir_SCANNERFLAGS = \
+GMime-3.0.gir: libgmime-3.0.la
+GMime_3_0_gir_INCLUDES = GObject-2.0 Gio-2.0
+GMime_3_0_gir_CFLAGS = $(AM_CPPFLAGS)
+GMime_3_0_gir_LIBS = libgmime-3.0.la
+GMime_3_0_gir_FILES = $(gmimeinclude_HEADERS) $(libgmime_3_0_la_SOURCES)
+GMime_3_0_gir_EXPORT_PACKAGES = gmime-3.0
+GMime_3_0_gir_SCANNERFLAGS = \
--c-include="gmime/gmime.h" \
--accept-unprefixed \
--symbol-prefix "gmime_" \
--symbol-prefix "g_mime_"
-INTROSPECTION_GIRS += GMime-2.6.gir
+INTROSPECTION_GIRS += GMime-3.0.gir
girdir = $(datadir)/gir-1.0
gir_DATA = $(INTROSPECTION_GIRS)
@@ -204,21 +204,21 @@ endif
if ENABLE_VAPIGEN
-include $(VAPIGEN_MAKEFILE)
-gmime-2.6.vapi: GMime-2.6.gir GMime-2.6.metadata
+gmime-3.0.vapi: GMime-3.0.gir GMime-3.0.metadata
-VAPIGEN_VAPIS = gmime-2.6.vapi
-gmime_2_6_vapi_DEPS = gio-2.0
-gmime_2_6_vapi_METADATADIRS = $(srcdir)
-gmime_2_6_vapi_FILES = GMime-2.6.gir
+VAPIGEN_VAPIS = gmime-3.0.vapi
+gmime_3_0_vapi_DEPS = gio-2.0
+gmime_3_0_vapi_METADATADIRS = $(srcdir)
+gmime_3_0_vapi_FILES = GMime-3.0.gir
-gmime-2.6.deps:
- $(AM_V_GEN) for pkg in $(gmime_2_6_vapi_DEPS); do \
+gmime-3.0.deps:
+ $(AM_V_GEN) for pkg in $(gmime_3_0_vapi_DEPS); do \
echo $$pkg >> $@; \
done
vapidir = $(datadir)/vala/vapi
vapi_DATA = $(VAPIGEN_VAPIS) $(VAPIGEN_VAPIS:.vapi=.deps)
-EXTRA_DIST += GMime-2.6.metadata
+EXTRA_DIST += GMime-3.0.metadata
CLEANFILES += $(vapi_DATA)
endif
diff --git a/gmime/gmime-header.c b/gmime/gmime-header.c
index ba9eddc..4413fe2 100644
--- a/gmime/gmime-header.c
+++ b/gmime/gmime-header.c
@@ -46,8 +46,7 @@
**/
struct _GMimeHeader {
- GMimeHeader *next;
- GMimeHeader *prev;
+ GMimeHeaderList *list;
gint64 offset;
char *name;
char *value;
@@ -55,12 +54,10 @@ struct _GMimeHeader {
};
struct _GMimeHeaderList {
- GMimeStream *stream;
GHashTable *writers;
GMimeEvent *changed;
GHashTable *hash;
- guint32 version;
- List list;
+ GPtrArray *list;
};
@@ -76,17 +73,16 @@ struct _GMimeHeaderList {
* Returns: a new #GMimeHeader with the specified values.
**/
static GMimeHeader *
-g_mime_header_new (const char *name, const char *value, const char *raw_value, gint64 offset)
+g_mime_header_new (GMimeHeaderList *headers, const char *name, const char *value, const char *raw_value,
gint64 offset)
{
GMimeHeader *header;
header = g_slice_new (GMimeHeader);
+ header->list = headers;
header->name = g_strdup (name);
header->value = g_strdup (value);
header->raw_value = raw_value ? g_strdup (raw_value) : NULL;
header->offset = offset;
- header->next = NULL;
- header->prev = NULL;
return header;
}
@@ -110,421 +106,105 @@ g_mime_header_free (GMimeHeader *header)
/**
- * g_mime_header_iter_new:
- *
- * Dynamically allocates a #GMimeHeaderIter on the heap. This is
- * intended for use in language bindings but may also be useful in
- * applications as well. You must free this iter with
- * g_mime_header_iter_free().
- *
- * Returns: a newly-allocated #GMimeHeaderIter.
- **/
-GMimeHeaderIter *
-g_mime_header_iter_new (void)
-{
- GMimeHeaderIter *iter;
-
- iter = g_slice_new (GMimeHeaderIter);
- iter->hdrlist = NULL;
- iter->cursor = NULL;
- iter->version = 0;
-
- return iter;
-}
-
-
-/**
- * g_mime_header_iter_copy:
- * @iter: a #GMimeHeaderIter
- *
- * Creates a dynamically allocated header iterator as a copy of
- * @iter. You must free this iter with g_mime_header_iter_free().
- *
- * Returns: a newly-allocated copy of @iter.
- **/
-GMimeHeaderIter *
-g_mime_header_iter_copy (GMimeHeaderIter *iter)
-{
- GMimeHeaderIter *copy;
-
- g_return_val_if_fail (iter != NULL, NULL);
-
- copy = g_mime_header_iter_new ();
- memcpy (copy, iter, sizeof (GMimeHeaderIter));
-
- return copy;
-}
-
-
-/**
- * g_mime_header_iter_copy_to:
- * @src: a #GMimeHeaderIter
- * @dest: a #GMimeHeaderIter
- *
- * Copies @src to @dest.
- **/
-void
-g_mime_header_iter_copy_to (GMimeHeaderIter *src, GMimeHeaderIter *dest)
-{
- g_return_if_fail (dest != NULL);
- g_return_if_fail (src != NULL);
-
- memcpy (dest, src, sizeof (GMimeHeaderIter));
-}
-
-
-/**
- * g_mime_header_iter_free:
- * @iter: a #GMimeHeaderIter
- *
- * Frees a dynamically-allocated #GMimeHeaderIter as created by
- * g_mime_header_iter_new() or g_mime_header_iter_copy().
- **/
-void
-g_mime_header_iter_free (GMimeHeaderIter *iter)
-{
- g_return_if_fail (iter != NULL);
-
- g_slice_free (GMimeHeaderIter, iter);
-}
-
-
-/**
- * g_mime_header_iter_equal:
- * @iter1: a #GMimeHeaderIter
- * @iter2: a #GMimeHeaderIter
- *
- * Check that @iter1 and @iter2 reference the same header.
- *
- * Returns: %TRUE if @iter1 and @iter2 refer to the same header or
- * %FALSE otherwise.
- **/
-gboolean
-g_mime_header_iter_equal (GMimeHeaderIter *iter1, GMimeHeaderIter *iter2)
-{
- g_return_val_if_fail (iter1 != NULL, FALSE);
- g_return_val_if_fail (iter2 != NULL, FALSE);
-
- return iter1->hdrlist == iter2->hdrlist &&
- iter1->version == iter2->version &&
- iter1->cursor == iter2->cursor;
-}
-
-
-/**
- * g_mime_header_iter_is_valid:
- * @iter: a #GMimeHeaderIter
+ * g_mime_header_get_name:
+ * @header: a #GMimeHeader
*
- * Checks if a #GMimeHeaderIter is valid. An iterator may become
- * invalid if the #GMimeHeaderList that the iterator refers to
- * changes.
+ * Gets the header's name.
*
- * Returns: %TRUE if @iter is still valid or %FALSE otherwise.
+ * Returns: the header name or %NULL if invalid.
**/
-gboolean
-g_mime_header_iter_is_valid (GMimeHeaderIter *iter)
+const char *
+g_mime_header_get_name (GMimeHeader *header)
{
- g_return_val_if_fail (iter != NULL, FALSE);
-
- if (!iter->hdrlist || iter->version != iter->hdrlist->version)
- return FALSE;
-
- if (!iter->cursor || !iter->cursor->next)
- return FALSE;
+ g_return_val_if_fail (header != NULL, NULL);
- return TRUE;
+ return header->name;
}
/**
- * g_mime_header_iter_first:
- * @iter: a #GMimeHeaderIter
+ * g_mime_header_get_value:
+ * @header: a #GMimeHeader
*
- * Updates @iter to point to the first header.
+ * Gets the header's value.
*
- * Returns: %TRUE on success or %FALSE otherwise.
- **/
-gboolean
-g_mime_header_iter_first (GMimeHeaderIter *iter)
-{
- GMimeHeader *first;
-
- g_return_val_if_fail (iter != NULL, FALSE);
-
- /* make sure we can actually do as requested */
- if (!iter->hdrlist || list_is_empty (&iter->hdrlist->list))
- return FALSE;
-
- first = (GMimeHeader *) iter->hdrlist->list.head;
-
- iter->version = iter->hdrlist->version;
- iter->cursor = first;
-
- return TRUE;
-}
-
-
-/**
- * g_mime_header_iter_last:
- * @iter: a #GMimeHeaderIter
- *
- * Updates @iter to point to the last header.
+ * Returns: the header's raw, unprocessed value or %NULL if invalid.
*
- * Returns: %TRUE on success or %FALSE otherwise.
+ * Note: The returned value should be decoded with a function such as
+ * g_mime_utils_header_decode_text() before displaying to the user.
**/
-gboolean
-g_mime_header_iter_last (GMimeHeaderIter *iter)
+const char *
+g_mime_header_get_value (GMimeHeader *header)
{
- GMimeHeader *last;
-
- g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (header != NULL, NULL);
- /* make sure we can actually do as requested */
- if (!iter->hdrlist || list_is_empty (&iter->hdrlist->list))
- return FALSE;
-
- last = (GMimeHeader *) iter->hdrlist->list.tailpred;
-
- iter->version = iter->hdrlist->version;
- iter->cursor = last;
-
- return TRUE;
+ return header->value;
}
/**
- * g_mime_header_iter_next:
- * @iter: a #GMimeHeaderIter
+ * g_mime_header_set_value:
+ * @header: a #GMimeHeader
+ * @value: the new header value
*
- * Advances to the next header.
+ * Sets the header's value.
*
- * Returns: %TRUE on success or %FALSE otherwise.
+ * Note: @value should be encoded with a function such as
+ * g_mime_utils_header_encode_text().
**/
-gboolean
-g_mime_header_iter_next (GMimeHeaderIter *iter)
+void
+g_mime_header_set_value (GMimeHeader *header, const char *value)
{
- GMimeHeader *next;
-
- g_return_val_if_fail (iter != NULL, FALSE);
-
- /* make sure current cursor is valid */
- if (!g_mime_header_iter_is_valid (iter))
- return FALSE;
+ g_return_if_fail (header != NULL);
+ g_return_if_fail (value != NULL);
- /* make sure next item is valid */
- next = iter->cursor->next;
- if (!next->next)
- return FALSE;
-
- iter->cursor = next;
+ g_free (header->raw_value);
+ g_free (header->value);
- return TRUE;
+ header->value = g_strdup (value);
}
/**
- * g_mime_header_iter_prev:
- * @iter: a #GMimeHeaderIter
+ * g_mime_header_get_raw_value:
+ * @header: a #GMimeHeader
*
- * Advances to the previous header.
+ * Gets the header's raw (folded) value.
*
- * Returns: %TRUE on success or %FALSE otherwise.
+ * Returns: the header value or %NULL if invalid.
**/
-gboolean
-g_mime_header_iter_prev (GMimeHeaderIter *iter)
+const char *
+_g_mime_header_get_raw_value (GMimeHeader *header)
{
- GMimeHeader *prev;
-
- g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (header != NULL, NULL);
- /* make sure current cursor is valid */
- if (!g_mime_header_iter_is_valid (iter))
- return FALSE;
-
- /* make sure prev item is valid */
- prev = iter->cursor->prev;
- if (!prev || !prev->prev)
- return FALSE;
-
- iter->cursor = prev;
-
- return TRUE;
+ return header->raw_value;
}
/**
- * g_mime_header_iter_get_offset:
- * @iter: a #GMimeHeaderIter
+ * g_mime_header_get_offset:
+ * @header: a #GMimeHeader
*
- * Gets the current header's file/stream offset.
+ * Gets the header's stream offset if known.
*
- * Returns: the file/stream offset or %-1 if unknown or invalid.
+ * Returns: the header offset or %-1 if unknown.
**/
gint64
-g_mime_header_iter_get_offset (GMimeHeaderIter *iter)
+g_mime_header_get_offset (GMimeHeader *header)
{
- g_return_val_if_fail (iter != NULL, -1);
+ g_return_val_if_fail (header != NULL, -1);
- if (!g_mime_header_iter_is_valid (iter))
- return -1;
-
- return iter->cursor->offset;
+ return header->offset;
}
void
-_g_mime_header_iter_set_offset (GMimeHeaderIter *iter, gint64 offset)
-{
- iter->cursor->offset = offset;
-}
-
-
-/**
- * g_mime_header_iter_get_name:
- * @iter: a #GMimeHeaderIter
- *
- * Gets the current header's name.
- *
- * Returns: the header name or %NULL if invalid.
- **/
-const char *
-g_mime_header_iter_get_name (GMimeHeaderIter *iter)
-{
- g_return_val_if_fail (iter != NULL, NULL);
-
- if (!g_mime_header_iter_is_valid (iter))
- return NULL;
-
- return iter->cursor->name;
-}
-
-
-/**
- * g_mime_header_iter_set_value:
- * @iter: a #GMimeHeaderIter
- * @value: new header value
- *
- * Sets the current header's value to the new value.
- *
- * Returns: %TRUE if the value was set or %FALSE otherwise (indicates
- * invalid iter).
- *
- * Note: @value should be encoded with a function such as
- * g_mime_utils_header_encode_text().
- **/
-gboolean
-g_mime_header_iter_set_value (GMimeHeaderIter *iter, const char *value)
+_g_mime_header_set_offset (GMimeHeader *header, gint64 offset)
{
- g_return_val_if_fail (iter != NULL, FALSE);
-
- if (!g_mime_header_iter_is_valid (iter))
- return FALSE;
-
- g_free (iter->cursor->value);
- iter->cursor->value = g_strdup (value);
-
- g_free (iter->cursor->raw_value);
- iter->cursor->raw_value = NULL;
-
- return TRUE;
-}
-
-
-/**
- * g_mime_header_iter_get_value:
- * @iter: a #GMimeHeaderIter
- *
- * Gets the current header's value.
- *
- * Returns: the header's raw, unprocessed value or %NULL if invalid.
- *
- * Note: The returned value should be decoded with a function such as
- * g_mime_utils_header_decode_text() before displaying to the user.
- **/
-const char *
-g_mime_header_iter_get_value (GMimeHeaderIter *iter)
-{
- g_return_val_if_fail (iter != NULL, NULL);
-
- if (!g_mime_header_iter_is_valid (iter))
- return NULL;
-
- return iter->cursor->value;
-}
-
-
-const char *
-_g_mime_header_iter_get_raw_value (GMimeHeaderIter *iter)
-{
- g_return_val_if_fail (iter != NULL, NULL);
-
- if (!g_mime_header_iter_is_valid (iter))
- return NULL;
-
- return iter->cursor->raw_value;
-}
-
-
-/**
- * g_mime_header_iter_remove:
- * @iter: a #GMimeHeaderIter
- *
- * Removes the current header and advances to the next header.
- *
- * Note: If you remove the last header in the list, then @iter will
- * become invalid regardless of whether or not other headers remain.
- *
- * Returns: %TRUE on success or %FALSE otherwise.
- **/
-gboolean
-g_mime_header_iter_remove (GMimeHeaderIter *iter)
-{
- GMimeHeader *cursor, *header, *next;
- GMimeHeaderList *hdrlist;
-
- g_return_val_if_fail (iter != NULL, FALSE);
-
- if (!g_mime_header_iter_is_valid (iter))
- return FALSE;
-
- /* save iter state */
- hdrlist = iter->hdrlist;
- cursor = iter->cursor;
- next = cursor->next;
-
- if (!(header = g_hash_table_lookup (hdrlist->hash, cursor->name)))
- return FALSE;
-
- if (cursor == header) {
- /* update the header lookup table */
- GMimeHeader *node = next;
-
- g_hash_table_remove (hdrlist->hash, cursor->name);
-
- while (node->next) {
- if (!g_ascii_strcasecmp (node->name, cursor->name)) {
- /* enter this node into the lookup table */
- g_hash_table_insert (hdrlist->hash, node->name, node);
- break;
- }
-
- node = node->next;
- }
- }
-
- /* remove/free the header */
- list_unlink ((ListNode *) cursor);
- g_mime_header_free (cursor);
- hdrlist->version++;
-
- /* update iter state */
- iter->version = hdrlist->version;
- iter->cursor = next;
-
- return TRUE;
+ header->offset = offset;
}
-
static ssize_t
default_writer (GMimeStream *stream, const char *name, const char *value)
{
@@ -539,13 +219,25 @@ default_writer (GMimeStream *stream, const char *name, const char *value)
}
-static ssize_t
-g_mime_header_write_to_stream (GHashTable *writers, GMimeHeader *header, GMimeStream *stream)
+/**
+ * g_mime_header_write_to_stream:
+ * @header: a #GMimeHeader
+ * @stream: a #GMimeStream
+ *
+ * Write the header to the specified stream.
+ *
+ * Returns: the number of bytes written, or %-1 on fail.
+ **/
+ssize_t
+g_mime_header_write_to_stream (GMimeHeader *header, GMimeStream *stream)
{
ssize_t nwritten, total = 0;
GMimeHeaderWriter writer;
char *val;
+ g_return_val_if_fail (header != NULL, -1);
+ g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
+
if (header->raw_value) {
val = g_mime_utils_header_printf ("%s:%s", header->name, header->raw_value);
nwritten = g_mime_stream_write_string (stream, val);
@@ -556,7 +248,7 @@ g_mime_header_write_to_stream (GHashTable *writers, GMimeHeader *header, GMimeSt
total += nwritten;
} else if (header->value) {
- if (!(writer = g_hash_table_lookup (writers, header->name)))
+ if (!(writer = g_hash_table_lookup (header->list->writers, header->name)))
writer = default_writer;
if ((nwritten = writer (stream, header->name, header->value)) == -1)
@@ -570,27 +262,6 @@ g_mime_header_write_to_stream (GHashTable *writers, GMimeHeader *header, GMimeSt
/**
- * g_mime_header_iter_write_to_stream:
- * @iter: a #GMimeHeaderIter
- * @stream: a #GMimeStream
- *
- * Write the header to a stream.
- *
- * Returns: the number of bytes written or %-1 on fail.
- **/
-ssize_t
-g_mime_header_iter_write_to_stream (GMimeHeaderIter *iter, GMimeStream *stream)
-{
- g_return_val_if_fail (iter != NULL, -1);
-
- if (!g_mime_header_iter_is_valid (iter))
- return -1;
-
- return g_mime_header_write_to_stream (iter->hdrlist->writers, iter->cursor, stream);
-}
-
-
-/**
* g_mime_header_list_new:
*
* Creates a new #GMimeHeaderList object.
@@ -608,9 +279,8 @@ g_mime_header_list_new (void)
g_free, NULL);
headers->hash = g_hash_table_new (g_mime_strcase_hash,
g_mime_strcase_equal);
- list_init (&headers->list);
headers->changed = g_mime_event_new (headers);
- headers->version = 0;
+ headers->list = g_ptr_array_new ();
return headers;
}
@@ -625,17 +295,15 @@ g_mime_header_list_new (void)
void
g_mime_header_list_destroy (GMimeHeaderList *headers)
{
- GMimeHeader *header, *next;
+ guint i;
if (!headers)
return;
- header = (GMimeHeader *) headers->list.head;
- while (header->next) {
- next = header->next;
- g_mime_header_free (header);
- header = next;
- }
+ for (i = 0; i < headers->list->len; i++)
+ g_mime_header_free (headers->list->pdata[i]);
+
+ g_ptr_array_free (headers->list, TRUE);
g_hash_table_destroy (headers->writers);
g_hash_table_destroy (headers->hash);
@@ -655,19 +323,33 @@ g_mime_header_list_destroy (GMimeHeaderList *headers)
void
g_mime_header_list_clear (GMimeHeaderList *headers)
{
- GMimeHeader *header, *next;
+ guint i;
g_return_if_fail (headers != NULL);
- header = (GMimeHeader *) headers->list.head;
- while (header->next) {
- next = header->next;
- g_mime_header_free (header);
- header = next;
- }
+ for (i = 0; i < headers->list->len; i++)
+ g_mime_header_free (headers->list->pdata[i]);
g_hash_table_remove_all (headers->hash);
- list_init (&headers->list);
+
+ g_ptr_array_set_size (headers->list, 0);
+}
+
+
+/**
+ * g_mime_header_list_get_count:
+ * @headers: a #GMimeHeaderList
+ *
+ * Gets the number of headers contained within the header list.
+ *
+ * Returns: the number of headers in the header list.
+ **/
+int
+g_mime_header_list_get_count (GMimeHeaderList *headers)
+{
+ g_return_val_if_fail (headers != NULL, -1);
+
+ return headers->list->len;
}
@@ -710,11 +392,25 @@ _g_mime_header_list_has_raw_value (const GMimeHeaderList *headers, const char *n
void
_g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const char *value, const char
*raw_value, gint64 offset)
{
+ unsigned char *dest, *src;
GMimeHeader *header;
+ guint n;
- header = g_mime_header_new (name, value, raw_value, offset);
- list_prepend (&headers->list, (ListNode *) header);
+ header = g_mime_header_new (headers, name, value, raw_value, offset);
g_hash_table_replace (headers->hash, header->name, header);
+
+ if (headers->list->len > 0) {
+ g_ptr_array_set_size (headers->list, headers->list->len + 1);
+
+ dest = ((unsigned char *) headers->list->pdata) + sizeof (void *);
+ src = (unsigned char *) headers->list->pdata;
+ n = headers->list->len - 1;
+
+ g_memmove (dest, src, (sizeof (void *) * n));
+ headers->list->pdata[0] = header;
+ } else {
+ g_ptr_array_add (headers->list, header);
+ }
}
@@ -746,8 +442,8 @@ _g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const ch
{
GMimeHeader *header;
- header = g_mime_header_new (name, value, raw_value, offset);
- list_append (&headers->list, (ListNode *) header);
+ header = g_mime_header_new (headers, name, value, raw_value, offset);
+ g_ptr_array_add (headers->list, header);
if (!g_hash_table_lookup (headers->hash, name))
g_hash_table_insert (headers->hash, header->name, header);
@@ -807,34 +503,32 @@ g_mime_header_list_get (const GMimeHeaderList *headers, const char *name)
void
_g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *value, const char
*raw_value, gint64 offset)
{
- GMimeHeader *header, *next;
+ GMimeHeader *header, *hdr;
+ guint i;
if ((header = g_hash_table_lookup (headers->hash, name))) {
- g_free (header->value);
- header->value = g_strdup (value);
-
g_free (header->raw_value);
header->raw_value = raw_value ? g_strdup (raw_value) : NULL;
+ g_free (header->value);
+ header->value = g_strdup (value);
+
header->offset = offset;
- header = header->next;
- while (header->next) {
- next = header->next;
+ for (i = headers->list->len - 1; i > 0; i--) {
+ hdr = (GMimeHeader *) headers->list->pdata[i];
- if (!g_ascii_strcasecmp (header->name, name)) {
- /* remove/free the header */
- list_unlink ((ListNode *) header);
- g_mime_header_free (header);
- headers->version++;
- }
+ if (hdr == header)
+ break;
+
+ if (g_ascii_strcasecmp (header->name, hdr->name) != 0)
+ continue;
- header = next;
+ g_ptr_array_remove_index (headers->list, i);
+ g_mime_header_free (hdr);
}
} else {
- header = g_mime_header_new (name, value, raw_value, offset);
- list_append (&headers->list, (ListNode *) header);
- g_hash_table_insert (headers->hash, header->name, header);
+ _g_mime_header_list_append (headers, name, value, raw_value, offset);
}
}
@@ -868,11 +562,33 @@ g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *
/**
+ * g_mime_header_list_get_header:
+ * @headers: a #GMimeHeaderList
+ * @index: the 0-based index of the header
+ *
+ * Gets the header at the specified @index within the list.
+ *
+ * Returns: (transfer none): the header at position @index.
+ **/
+GMimeHeader *
+g_mime_header_list_get_header (GMimeHeaderList *headers, int index)
+{
+ g_return_val_if_fail (headers != NULL, NULL);
+ g_return_val_if_fail (index >= 0, NULL);
+
+ if ((guint) index >= headers->list->len)
+ return NULL;
+
+ return (GMimeHeader *) headers->list->pdata[index];
+}
+
+
+/**
* g_mime_header_list_remove:
* @headers: a #GMimeHeaderList
* @name: header name
*
- * Remove the specified header.
+ * Remove the first instance of the specified header.
*
* Returns: %TRUE if the header was successfully removed or %FALSE if
* the specified header could not be found.
@@ -881,6 +597,7 @@ gboolean
g_mime_header_list_remove (GMimeHeaderList *headers, const char *name)
{
GMimeHeader *header, *node;
+ guint i;
g_return_val_if_fail (headers != NULL, FALSE);
g_return_val_if_fail (name != NULL, FALSE);
@@ -888,80 +605,71 @@ g_mime_header_list_remove (GMimeHeaderList *headers, const char *name)
if (!(header = g_hash_table_lookup (headers->hash, name)))
return FALSE;
+ /* get the index of the header */
+ for (i = 0; i < headers->list->len; i++) {
+ if (headers->list->pdata[i] == header)
+ break;
+ }
+
+ g_ptr_array_remove_index (headers->list, i);
+ g_hash_table_remove (headers->hash, name);
+ g_mime_header_free (header);
+
/* look for another header with the same name... */
- node = header->next;
- while (node->next) {
- if (!g_ascii_strcasecmp (node->name, name)) {
+ while (i < headers->list->len) {
+ header = (GMimeHeader *) headers->list->pdata[i];
+
+ if (!g_ascii_strcasecmp (header->name, name)) {
/* enter this node into the lookup table */
- g_hash_table_replace (headers->hash, node->name, node);
+ g_hash_table_insert (headers->hash, header->name, header);
break;
}
- node = node->next;
+ i++;
}
- /* invalidate all our outstanding iterators matching @header */
- headers->version++;
-
- /* remove/free the header */
- list_unlink ((ListNode *) header);
- g_mime_header_free (header);
-
return TRUE;
}
/**
- * g_mime_header_list_get_iter:
+ * g_mime_header_list_remove_at:
* @headers: a #GMimeHeaderList
- * @iter: (out): a #GMimeHeaderIter
- *
- * Initializes an iterator for traversing @headers.
+ * @index: the 0-based index of the header to remove
*
- * Returns: a %TRUE if successful or %FALSE if there are no headers to
- * traverse.
+ * Removes the header at the specified @index from @headers.
**/
-gboolean
-g_mime_header_list_get_iter (GMimeHeaderList *headers, GMimeHeaderIter *iter)
-{
- GMimeHeader *cursor;
-
- g_return_val_if_fail (headers != NULL, FALSE);
-
- cursor = (GMimeHeader *) headers->list.head;
- if (!cursor->next)
- return FALSE;
-
- iter->version = headers->version;
- iter->hdrlist = headers;
- iter->cursor = cursor;
-
- return TRUE;
-}
-
-
-/**
- * g_mime_header_list_foreach:
- * @headers: A #GMimeHeaderList
- * @func: (scope call): function to be called for each header.
- * @user_data: User data to be passed to the func.
- *
- * Calls @func for each header name/value pair.
- */
void
-g_mime_header_list_foreach (const GMimeHeaderList *headers, GMimeHeaderForeachFunc func, gpointer user_data)
+g_mime_header_list_remove_at (GMimeHeaderList *headers, int index)
{
- const GMimeHeader *header;
+ GMimeHeader *header, *hdr;
+ guint i;
g_return_if_fail (headers != NULL);
- g_return_if_fail (func != NULL);
+ g_return_if_fail (index >= 0);
- header = (const GMimeHeader *) headers->list.head;
+ if ((guint) index >= headers->list->len)
+ return;
- while (header->next) {
- func (header->name, header->value, user_data);
- header = header->next;
+ header = (GMimeHeader *) headers->list->pdata[index];
+ g_ptr_array_remove_index (headers->list, index);
+
+ /* if this is the first instance of a header with this name, then we'll
+ * need to update the hash table to point to the next instance... */
+ if ((hdr = g_hash_table_lookup (headers->hash, header->name)) == header) {
+ g_hash_table_remove (headers->hash, header->name);
+
+ for (i = (guint) index; i < headers->list->len; i++) {
+ hdr = (GMimeHeader *) headers->list->pdata[i];
+
+ if (!g_ascii_strcasecmp (header->name, hdr->name)) {
+ g_hash_table_insert (headers->hash, hdr->name, hdr);
+ break;
+ }
+ }
}
+
+ g_mime_header_free (header);
}
@@ -978,23 +686,19 @@ ssize_t
g_mime_header_list_write_to_stream (const GMimeHeaderList *headers, GMimeStream *stream)
{
ssize_t nwritten, total = 0;
- GHashTable *writers;
GMimeHeader *header;
- char *val;
+ guint i;
g_return_val_if_fail (headers != NULL, -1);
g_return_val_if_fail (stream != NULL, -1);
- header = (GMimeHeader *) headers->list.head;
- writers = headers->writers;
-
- while (header->next) {
- if ((nwritten = g_mime_header_write_to_stream (writers, header, stream)) == -1)
+ for (i = 0; i < headers->list->len; i++) {
+ header = (GMimeHeader *) headers->list->pdata[i];
+
+ if ((nwritten = g_mime_header_write_to_stream (header, stream)) == -1)
return -1;
total += nwritten;
-
- header = header->next;
}
return total;
diff --git a/gmime/gmime-header.h b/gmime/gmime-header.h
index ce1ff8d..f088ef9 100644
--- a/gmime/gmime-header.h
+++ b/gmime/gmime-header.h
@@ -27,18 +27,19 @@
G_BEGIN_DECLS
-typedef struct _GMimeHeader GMimeHeader;
-
/**
- * GMimeHeaderForeachFunc:
+ * GMimeHeaderWriter:
+ * @stream: The output stream.
* @name: The field name.
* @value: The field value.
- * @user_data: The user-supplied callback data.
*
- * Function signature for the callback to g_mime_header_list_foreach().
+ * Function signature for the callback to
+ * g_mime_header_list_register_writer().
+ *
+ * Returns: the number of bytes written or %-1 on error.
**/
-typedef void (* GMimeHeaderForeachFunc) (const char *name, const char *value, gpointer user_data);
+typedef ssize_t (* GMimeHeaderWriter) (GMimeStream *stream, const char *name, const char *value);
/**
@@ -48,92 +49,37 @@ typedef void (* GMimeHeaderForeachFunc) (const char *name, const char *value, gp
**/
typedef struct _GMimeHeader GMimeHeader;
+const char *g_mime_header_get_name (GMimeHeader *header);
-/**
- * GMimeHeaderList:
- *
- * A message or mime-part header.
- **/
-typedef struct _GMimeHeaderList GMimeHeaderList;
-
-
-/**
- * GMimeHeaderIter:
- * @hdrlist: a #GMimeHeaderList
- * @cursor: a #GMimeHeader
- * @version: the version of @hdrlist when initialized
- *
- * A message or mime-part header iterator. All members should be
- * considered private.
- **/
-typedef struct _GMimeHeaderIter GMimeHeaderIter;
-
-struct _GMimeHeaderIter {
- GMimeHeaderList *hdrlist;
- GMimeHeader *cursor;
- guint32 version;
-};
-
-
-GMimeHeaderIter *g_mime_header_iter_new (void);
-void g_mime_header_iter_free (GMimeHeaderIter *iter);
+const char *g_mime_header_get_value (GMimeHeader *header);
+void g_mime_header_set_value (GMimeHeader *header, const char *value);
-GMimeHeaderIter *g_mime_header_iter_copy (GMimeHeaderIter *iter);
-void g_mime_header_iter_copy_to (GMimeHeaderIter *src, GMimeHeaderIter *dest);
+gint64 g_mime_header_get_offset (GMimeHeader *header);
-gboolean g_mime_header_iter_equal (GMimeHeaderIter *iter1, GMimeHeaderIter *iter2);
-
-gboolean g_mime_header_iter_is_valid (GMimeHeaderIter *iter);
-
-gboolean g_mime_header_iter_first (GMimeHeaderIter *iter);
-gboolean g_mime_header_iter_last (GMimeHeaderIter *iter);
-
-gboolean g_mime_header_iter_next (GMimeHeaderIter *iter);
-gboolean g_mime_header_iter_prev (GMimeHeaderIter *iter);
-
-const char *g_mime_header_iter_get_name (GMimeHeaderIter *iter);
-
-gboolean g_mime_header_iter_set_value (GMimeHeaderIter *iter, const char *value);
-const char *g_mime_header_iter_get_value (GMimeHeaderIter *iter);
-
-gint64 g_mime_header_iter_get_offset (GMimeHeaderIter *iter);
-
-gboolean g_mime_header_iter_remove (GMimeHeaderIter *iter);
-
-ssize_t g_mime_header_iter_write_to_stream (GMimeHeaderIter *iter, GMimeStream *stream);
+ssize_t g_mime_header_write_to_stream (GMimeHeader *header, GMimeStream *stream);
/**
- * GMimeHeaderWriter:
- * @stream: The output stream.
- * @name: The field name.
- * @value: The field value.
- *
- * Function signature for the callback to
- * g_mime_header_list_register_writer().
+ * GMimeHeaderList:
*
- * Returns: the number of bytes written or %-1 on error.
+ * A list of message or mime-part headers.
**/
-typedef ssize_t (* GMimeHeaderWriter) (GMimeStream *stream, const char *name, const char *value);
+typedef struct _GMimeHeaderList GMimeHeaderList;
GMimeHeaderList *g_mime_header_list_new (void);
void g_mime_header_list_destroy (GMimeHeaderList *headers);
-void g_mime_header_list_set_stream (GMimeHeaderList *headers, GMimeStream *stream);
-GMimeStream *g_mime_header_list_get_stream (GMimeHeaderList *headers);
-
void g_mime_header_list_clear (GMimeHeaderList *headers);
+int g_mime_header_list_get_count (GMimeHeaderList *headers);
gboolean g_mime_header_list_contains (const GMimeHeaderList *headers, const char *name);
void g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const char *value);
void g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const char *value);
void g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *value);
const char *g_mime_header_list_get (const GMimeHeaderList *headers, const char *name);
+GMimeHeader *g_mime_header_list_get_header (GMimeHeaderList *headers, int index);
gboolean g_mime_header_list_remove (GMimeHeaderList *headers, const char *name);
-
-gboolean g_mime_header_list_get_iter (GMimeHeaderList *headers, GMimeHeaderIter *iter);
-
-void g_mime_header_list_foreach (const GMimeHeaderList *headers, GMimeHeaderForeachFunc func, gpointer
user_data);
+void g_mime_header_list_remove_at (GMimeHeaderList *headers, int index);
void g_mime_header_list_register_writer (GMimeHeaderList *headers, const char *name, GMimeHeaderWriter
writer);
ssize_t g_mime_header_list_write_to_stream (const GMimeHeaderList *headers, GMimeStream *stream);
diff --git a/gmime/gmime-message-partial.c b/gmime/gmime-message-partial.c
index 098a8cf..32dbf02 100644
--- a/gmime/gmime-message-partial.c
+++ b/gmime/gmime-message-partial.c
@@ -41,7 +41,7 @@
* A #GMimeMessagePartial represents the message/partial MIME part.
**/
-extern const char *_g_mime_header_iter_get_raw_value (GMimeHeaderIter *iter);
+extern const char *_g_mime_header_get_raw_value (GMimeHeader *header);
extern void _g_mime_object_append_header (GMimeObject *object, const char *header, const char *value, const
char *raw_value, gint64 offset);
@@ -377,24 +377,26 @@ static GMimeMessage *
message_partial_message_new (GMimeMessage *base)
{
const char *name, *value, *raw_value;
+ GMimeHeaderList *headers;
GMimeMessage *message;
- GMimeHeaderList *list;
- GMimeHeaderIter iter;
+ GMimeHeader *header;
gint64 offset;
+ int count, i;
message = g_mime_message_new (FALSE);
- list = ((GMimeObject *) base)->headers;
+ headers = ((GMimeObject *) base)->headers;
- if (g_mime_header_list_get_iter (list, &iter)) {
- do {
- name = g_mime_header_iter_get_name (&iter);
- value = g_mime_header_iter_get_value (&iter);
- raw_value = _g_mime_header_iter_get_raw_value (&iter);
- offset = g_mime_header_iter_get_offset (&iter);
-
- _g_mime_object_append_header ((GMimeObject *) message, name, value, raw_value,
offset);
- } while (g_mime_header_iter_next (&iter));
+ count = g_mime_header_list_get_count (headers);
+
+ for (i = 0; i < count; i++) {
+ header = g_mime_header_list_get_header (headers, i);
+ raw_value = _g_mime_header_get_raw_value (header);
+ offset = g_mime_header_get_offset (header);
+ value = g_mime_header_get_value (header);
+ name = g_mime_header_get_name (header);
+
+ _g_mime_object_append_header ((GMimeObject *) message, name, value, raw_value, offset);
}
return message;
diff --git a/gmime/gmime-message.c b/gmime/gmime-message.c
index cec1fbe..3544d2a 100644
--- a/gmime/gmime-message.c
+++ b/gmime/gmime-message.c
@@ -53,7 +53,7 @@ extern void _g_mime_object_prepend_header (GMimeObject *object, const char *head
extern void _g_mime_object_append_header (GMimeObject *object, const char *header, const char *value, const
char *raw_value, gint64 offset);
extern void _g_mime_object_set_header (GMimeObject *object, const char *header, const char *value, const
char *raw_value, gint64 offset);
-extern void _g_mime_header_iter_set_offset (GMimeHeaderIter *iter, gint64 offset);
+extern void _g_mime_header_set_offset (GMimeHeader *header, gint64 offset);
extern void _g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const char *value,
const char *raw_value, gint64 offset);
extern void _g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const char *value, const
char *raw_value, gint64 offset);
@@ -978,57 +978,56 @@ write_headers_to_stream (GMimeObject *object, GMimeStream *stream)
GMimeMessage *message = (GMimeMessage *) object;
GMimeObject *mime_part = message->mime_part;
ssize_t nwritten, total = 0;
- GMimeHeaderIter mesg, body;
- if (!g_mime_header_list_get_iter (object->headers, &mesg))
- return -1;
-
- if (message->mime_part && g_mime_header_list_get_iter (mime_part->headers, &body)) {
- while (g_mime_header_iter_is_valid (&mesg) && g_mime_header_iter_is_valid (&body)) {
- gint64 mesg_offset, body_offset;
-
- if ((body_offset = g_mime_header_iter_get_offset (&body)) < 0)
+ if (mime_part != NULL) {
+ int body_count = g_mime_header_list_get_count (mime_part->headers);
+ int count = g_mime_header_list_get_count (object->headers);
+ GMimeHeader *header, *body_header;
+ gint64 body_offset, offset;
+ int body_index = 0;
+ int index = 0;
+
+ while (index < count && body_index < body_count) {
+ body_header = g_mime_header_list_get_header (mime_part->headers, body_index);
+ if ((body_offset = g_mime_header_get_offset (body_header)) < 0)
break;
- mesg_offset = g_mime_header_iter_get_offset (&mesg);
+ header = g_mime_header_list_get_header (object->headers, index);
+ offset = g_mime_header_get_offset (header);
- if (mesg_offset >= 0 && mesg_offset < body_offset) {
- if ((nwritten = g_mime_header_iter_write_to_stream (&mesg, stream)) == -1)
+ if (offset >= 0 && offset < body_offset) {
+ if ((nwritten = g_mime_header_write_to_stream (header, stream)) == -1)
return -1;
total += nwritten;
-
- if (!g_mime_header_iter_next (&mesg))
- break;
+ index++;
} else {
- if ((nwritten = g_mime_header_iter_write_to_stream (&body, stream)) == -1)
+ if ((nwritten = g_mime_header_write_to_stream (body_header, stream)) == -1)
return -1;
total += nwritten;
-
- if (!g_mime_header_iter_next (&body))
- break;
+ body_index++;
}
}
- while (g_mime_header_iter_is_valid (&mesg)) {
- if ((nwritten = g_mime_header_iter_write_to_stream (&mesg, stream)) == -1)
+ while (index < count) {
+ header = g_mime_header_list_get_header (object->headers, index);
+
+ if ((nwritten = g_mime_header_write_to_stream (header, stream)) == -1)
return -1;
total += nwritten;
-
- if (!g_mime_header_iter_next (&mesg))
- break;
+ index++;
}
- while (g_mime_header_iter_is_valid (&body)) {
- if ((nwritten = g_mime_header_iter_write_to_stream (&body, stream)) == -1)
+ while (body_index < body_count) {
+ header = g_mime_header_list_get_header (mime_part->headers, body_index);
+
+ if ((nwritten = g_mime_header_write_to_stream (header, stream)) == -1)
return -1;
total += nwritten;
-
- if (!g_mime_header_iter_next (&body))
- break;
+ body_index++;
}
return total;
@@ -1562,8 +1561,6 @@ g_mime_message_get_mime_part (GMimeMessage *message)
void
g_mime_message_set_mime_part (GMimeMessage *message, GMimeObject *mime_part)
{
- GMimeHeaderIter iter;
-
g_return_if_fail (mime_part == NULL || GMIME_IS_OBJECT (mime_part));
g_return_if_fail (GMIME_IS_MESSAGE (message));
@@ -1575,14 +1572,15 @@ g_mime_message_set_mime_part (GMimeMessage *message, GMimeObject *mime_part)
if (mime_part) {
GMimeHeaderList *headers = ((GMimeObject *) message)->headers;
+ GMimeHeader *header;
+ int i;
if (!g_mime_header_list_contains (headers, "MIME-Version"))
g_mime_header_list_append (headers, "MIME-Version", "1.0");
- if (g_mime_header_list_get_iter (mime_part->headers, &iter)) {
- do {
- _g_mime_header_iter_set_offset (&iter, -1);
- } while (g_mime_header_iter_next (&iter));
+ for (i = 0; i < g_mime_header_list_get_count (mime_part->headers); i++) {
+ header = g_mime_header_list_get_header (mime_part->headers, i);
+ _g_mime_header_set_offset (header, -1);
}
g_object_ref (mime_part);
diff --git a/tests/test-headers.c b/tests/test-headers.c
index b311d0d..4736359 100644
--- a/tests/test-headers.c
+++ b/tests/test-headers.c
@@ -65,211 +65,80 @@ header_list_new (void)
}
static void
-test_iter_forward_back (void)
+test_indexing (void)
{
const char *name, *value;
GMimeHeaderList *list;
- GMimeHeaderIter iter;
- guint i;
+ GMimeHeader *header;
+ int index, count;
list = header_list_new ();
- /* make sure initial iter is valid */
- testsuite_check ("initial iter");
- try {
- if (!g_mime_header_list_get_iter (list, &iter))
- throw (exception_new ("get_iter() failed"));
-
- if (!g_mime_header_iter_is_valid (&iter))
- throw (exception_new ("invalid iter"));
-
- name = g_mime_header_iter_get_name (&iter);
- value = g_mime_header_iter_get_value (&iter);
-
- if (strcmp (initial[0].name, name) != 0 || strcmp (initial[0].value, value) != 0)
- throw (exception_new ("resulted in unexpected header"));
- testsuite_check_passed ();
- } catch (ex) {
- testsuite_check_failed ("initial iter: %s", ex->message);
- } finally;
+ count = g_mime_header_list_get_count (list);
- /* make sure iter->next works as expected */
- for (i = 1; i < G_N_ELEMENTS (initial); i++) {
- testsuite_check ("next iter[%u]", i);
+ /* make sure indexing works as expected */
+ for (index = 0; index < G_N_ELEMENTS (initial); index++) {
+ testsuite_check ("headers[%d]", index);
try {
- if (!g_mime_header_iter_next (&iter))
- throw (exception_new ("failed to advance"));
-
- if (!g_mime_header_iter_is_valid (&iter))
- throw (exception_new ("advanced but is invalid"));
+ if (!(header = g_mime_header_list_get_header (list, index)))
+ throw (exception_new ("failed to get header at index"));
- name = g_mime_header_iter_get_name (&iter);
- value = g_mime_header_iter_get_value (&iter);
+ name = g_mime_header_get_name (header);
+ value = g_mime_header_get_value (header);
- if (strcmp (initial[i].name, name) != 0 ||
- strcmp (initial[i].value, value) != 0)
+ if (strcmp (initial[index].name, name) != 0 ||
+ strcmp (initial[index].value, value) != 0)
throw (exception_new ("resulted in unexpected header"));
testsuite_check_passed ();
} catch (ex) {
- testsuite_check_failed ("next iter[%u]: %s", i, ex->message);
+ testsuite_check_failed ("next iter[%d]: %s", index, ex->message);
} finally;
}
/* make sure trying to advance past the last header fails */
- testsuite_check ("iter->next past end of headers");
+ testsuite_check ("indexing past end of headers");
try {
- if (g_mime_header_iter_next (&iter))
+ if (g_mime_header_list_get_header (list, index) != NULL)
throw (exception_new ("should not have worked"));
testsuite_check_passed ();
} catch (ex) {
- testsuite_check_failed ("iter->next past end of headers: %s", ex->message);
- } finally;
-
- /* make sure iter->prev works as expected */
- i--;
- while (i > 0) {
- testsuite_check ("prev iter[%u]", i);
- try {
- if (!g_mime_header_iter_prev (&iter))
- throw (exception_new ("failed to advance"));
-
- if (!g_mime_header_iter_is_valid (&iter))
- throw (exception_new ("advanced but is invalid"));
-
- name = g_mime_header_iter_get_name (&iter);
- value = g_mime_header_iter_get_value (&iter);
-
- if (strcmp (initial[i - 1].name, name) != 0 ||
- strcmp (initial[i - 1].value, value) != 0)
- throw (exception_new ("resulted in unexpected header"));
- testsuite_check_passed ();
- } catch (ex) {
- testsuite_check_failed ("prev iter[%u]: %s", i, ex->message);
- } finally;
-
- i--;
- }
-
- /* make sure trying to advance prev of the first header fails */
- testsuite_check ("iter->prev past beginning of headers");
- try {
- if (g_mime_header_iter_prev (&iter))
- throw (exception_new ("should not have worked"));
- testsuite_check_passed ();
- } catch (ex) {
- testsuite_check_failed ("iter->prev past beginning of headers: %s", ex->message);
- } finally;
-
- g_mime_header_list_destroy (list);
-}
-
-static void
-test_iter_remove_all (void)
-{
- GMimeHeaderList *list;
- GMimeHeaderIter iter;
- guint i = 0;
-
- list = header_list_new ();
-
- g_mime_header_list_get_iter (list, &iter);
-
- testsuite_check ("removing all headers");
- try {
- while (g_mime_header_iter_remove (&iter))
- i++;
-
- if (i != G_N_ELEMENTS (initial))
- throw (exception_new ("only removed %u of %u", i, G_N_ELEMENTS (initial)));
-
- if (g_mime_header_iter_is_valid (&iter))
- throw (exception_new ("expected invalid iter"));
-
- testsuite_check_passed ();
- } catch (ex) {
- testsuite_check_failed ("removing all headers: %s", ex->message);
- } finally;
-
- g_mime_header_list_get_iter (list, &iter);
-
- testsuite_check ("empty list iter");
- try {
- if (g_mime_header_iter_is_valid (&iter))
- throw (exception_new ("expected invalid iter"));
-
- testsuite_check_passed ();
- } catch (ex) {
- testsuite_check_failed ("empty list iter: %s", ex->message);
+ testsuite_check_failed ("indexing past end of headers: %s", ex->message);
} finally;
g_mime_header_list_destroy (list);
}
static void
-test_iter_remove (void)
+test_remove_at (void)
{
- GMimeHeaderIter iter, iter1, iter2, iter3;
const char *name, *value;
GMimeHeaderList *list;
+ GMimeHeader *header;
+ int count;
guint i;
list = header_list_new ();
- g_mime_header_list_get_iter (list, &iter1);
-
- testsuite_check ("iter copying");
- try {
- /* make iter2 point to the second header */
- g_mime_header_iter_copy_to (&iter1, &iter2);
- if (!g_mime_header_iter_next (&iter2))
- throw (exception_new ("iter2->next failed"));
-
- name = g_mime_header_iter_get_name (&iter2);
- value = g_mime_header_iter_get_value (&iter2);
-
- if (strcmp (initial[1].name, name) != 0 ||
- strcmp (initial[1].value, value) != 0)
- throw (exception_new ("iter2 resulted in unexpected header"));
-
- /* make iter3 point to the third header */
- g_mime_header_iter_copy_to (&iter2, &iter3);
- if (!g_mime_header_iter_next (&iter3))
- throw (exception_new ("iter3->next failed"));
-
- name = g_mime_header_iter_get_name (&iter3);
- value = g_mime_header_iter_get_value (&iter3);
-
- if (strcmp (initial[2].name, name) != 0 ||
- strcmp (initial[2].value, value) != 0)
- throw (exception_new ("iter3 resulted in unexpected header"));
-
- testsuite_check_passed ();
- } catch (ex) {
- testsuite_check_failed ("iter copying: %s", ex->message);
- } finally;
-
testsuite_check ("remove first header");
try {
/* remove the first header */
- g_mime_header_iter_copy_to (&iter1, &iter);
- if (!g_mime_header_iter_remove (&iter))
- throw (exception_new ("iter::remove() failed"));
+ g_mime_header_list_remove_at (list, 0);
- /* make sure iter now points to the 2nd header */
- name = g_mime_header_iter_get_name (&iter);
- value = g_mime_header_iter_get_value (&iter);
+ /* make sure the first header is now the same as the second original header */
+ header = g_mime_header_list_get_header (list, 0);
+ name = g_mime_header_get_name (header);
+ value = g_mime_header_get_value (header);
if (strcmp (initial[1].name, name) != 0 ||
strcmp (initial[1].value, value) != 0)
- throw (exception_new ("iter doesn't point to 2nd header as expected"));
+ throw (exception_new ("expected second Received header"));
- /* make sure that the other iters have been invalidated */
- if (g_mime_header_iter_is_valid (&iter1))
- throw (exception_new ("iter::remove() iter1::isvalid() incorrect"));
- if (g_mime_header_iter_is_valid (&iter2))
- throw (exception_new ("iter::remove() iter2::isvalid() incorrect"));
- if (g_mime_header_iter_is_valid (&iter3))
- throw (exception_new ("iter::remove() iter3::isvalid() incorrect"));
+ /* make sure that the internal hash table was properly updated */
+ if (!(value = g_mime_header_list_get (list, "Received")))
+ throw (exception_new ("lookup of Received header failed"));
+
+ if (strcmp (initial[1].value, value) != 0)
+ throw (exception_new ("expected second Received header value"));
testsuite_check_passed ();
} catch (ex) {
@@ -279,84 +148,17 @@ test_iter_remove (void)
testsuite_check ("remove last header");
try {
/* remove the last header */
- g_mime_header_iter_last (&iter);
-
- if (!g_mime_header_iter_remove (&iter))
- throw (exception_new ("iter::remove() failed"));
+ count = g_mime_header_list_get_count (list);
+ g_mime_header_list_remove_at (list, count - 1);
- /* iter should be invalid now because it couldn't advance to a header beyond the last */
- if (g_mime_header_iter_is_valid (&iter))
- throw (exception_new ("iter::remove() iter is valid when it shouldn't be"));
+ if ((value = g_mime_header_list_get (list, "Message-Id")) != NULL)
+ throw (exception_new ("lookup of Message-Id should have failed"));
testsuite_check_passed ();
} catch (ex) {
testsuite_check_failed ("remove last header: %s", ex->message);
} finally;
- testsuite_check ("remove middle header");
- try {
- g_mime_header_list_get_iter (list, &iter);
-
- /* advance to a header in the middle somewhere... */
- g_mime_header_iter_next (&iter);
- g_mime_header_iter_next (&iter);
-
- /* we should now be pointing to the 3rd header (4th from the initial headers) */
- name = g_mime_header_iter_get_name (&iter);
- value = g_mime_header_iter_get_value (&iter);
-
- if (strcmp (initial[3].name, name) != 0 ||
- strcmp (initial[3].value, value) != 0)
- throw (exception_new ("iter doesn't point to 3rd header as expected"));
-
- /* remove it */
- if (!g_mime_header_iter_remove (&iter))
- throw (exception_new ("iter::remove() failed"));
-
- /* make sure the iter is still valid */
- if (!g_mime_header_iter_is_valid (&iter))
- throw (exception_new ("iter::remove() iter isn't valid when it should be"));
-
- /* make sure iter now points to the 4th header */
- name = g_mime_header_iter_get_name (&iter);
- value = g_mime_header_iter_get_value (&iter);
-
- if (strcmp (initial[4].name, name) != 0 ||
- strcmp (initial[4].value, value) != 0)
- throw (exception_new ("iter doesn't point to 4th header as expected"));
-
- testsuite_check_passed ();
- } catch (ex) {
- testsuite_check_failed ("remove first header: %s", ex->message);
- } finally;
-
- testsuite_check ("resulting lists match");
- try {
- g_mime_header_list_get_iter (list, &iter);
- i = 1;
-
- do {
- name = g_mime_header_iter_get_name (&iter);
- value = g_mime_header_iter_get_value (&iter);
-
- if (i == 3)
- i++;
-
- if (strcmp (initial[i].name, name) != 0 ||
- strcmp (initial[i].value, value) != 0)
- throw (exception_new ("iter vs array mismatch @ index %u", i));
-
- i++;
- } while (g_mime_header_iter_next (&iter));
-
- if (++i != G_N_ELEMENTS (initial))
- throw (exception_new ("iter didn't have as many headers as expected"));
-
- testsuite_check_passed ();
- } catch (ex) {
- testsuite_check_failed ("resulting lists match: %s", ex->message);
- } finally;
-
g_mime_header_list_destroy (list);
}
@@ -539,16 +341,12 @@ int main (int argc, char **argv)
testsuite_init (argc, argv);
- testsuite_start ("iterating forward and backward");
- test_iter_forward_back ();
- testsuite_end ();
-
- testsuite_start ("removing all headers");
- test_iter_remove_all ();
+ testsuite_start ("indexing");
+ test_indexing ();
testsuite_end ();
- testsuite_start ("removing individual headers");
- test_iter_remove ();
+ testsuite_start ("removing at an index");
+ test_remove_at ();
testsuite_end ();
testsuite_start ("header synchronization");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]