From 3dce2007887717ec4ec0a1e815591c957acd1ba1 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Mon, 26 Oct 2009 09:13:19 -0700 Subject: [PATCH] tags: Re-implement tags iterator to avoid having C++ in the interface We want to be able to iterate over tags stored in various ways, so the previous TermIterator-based tags object just wasn't general enough. The new interface is nice and simple, and involves only C datatypes. --- message.cc | 37 +++++++++- notmuch-private-cxx.h | 42 ----------- notmuch-private.h | 14 ++++ notmuch.c | 8 +-- tags.c | 104 ++++++++++++++++++++++++++++ tags.cc | 157 ------------------------------------------ 6 files changed, 157 insertions(+), 205 deletions(-) delete mode 100644 notmuch-private-cxx.h create mode 100644 tags.c delete mode 100644 tags.cc diff --git a/message.cc b/message.cc index 7fef60a5..b95f9d7f 100644 --- a/message.cc +++ b/message.cc @@ -18,7 +18,7 @@ * Author: Carl Worth */ -#include "notmuch-private-cxx.h" +#include "notmuch-private.h" #include "database-private.h" #include @@ -289,7 +289,40 @@ notmuch_message_get_filename (notmuch_message_t *message) notmuch_tags_t * notmuch_message_get_tags (notmuch_message_t *message) { - return _notmuch_tags_create_terms (message, message->doc, "tag"); + const char *prefix = _find_prefix ("tag"); + Xapian::TermIterator i, end; + notmuch_tags_t *tags; + std::string tag; + + /* Currently this iteration is written with the assumption that + * "tag" has a single-character prefix. */ + assert (strlen (prefix) == 1); + + tags = _notmuch_tags_create (message); + if (unlikely (tags == NULL)) + return NULL; + + i = message->doc.termlist_begin (); + end = message->doc.termlist_end (); + + i.skip_to (prefix); + + while (1) { + tag = *i; + + if (tag.empty () || tag[0] != *prefix) + break; + + _notmuch_tags_add_tag (tags, tag.c_str () + 1); + + i++; + } + + _notmuch_tags_sort (tags); + + _notmuch_tags_reset (tags); + + return tags; } void diff --git a/notmuch-private-cxx.h b/notmuch-private-cxx.h deleted file mode 100644 index c7aa97a6..00000000 --- a/notmuch-private-cxx.h +++ /dev/null @@ -1,42 +0,0 @@ -/* notmuch-private-cxx.h - Internal, C++ interfaces for notmuch. - * - * Copyright © 2009 Carl Worth - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/ . - * - * Author: Carl Worth - */ - -#ifndef NOTMUCH_PRIVATE_CXX_H -#define NOTMUCH_PRIVATE_CXX_H - -/* It's a bit annoying to have a separate C++ private header, but I - * don't yet have C wrappers for types like Xapian::Document and - * Xapian::PostingIterator. Maybe I'll write those to be able to fold - * this stuff back into notmuch-private.h */ - -#include "notmuch-private.h" - -#include - -/***********/ -/* tags.cc */ -/***********/ - -notmuch_tags_t * -_notmuch_tags_create_terms (void *ctx, - Xapian::Document doc, - const char *prefix_name); - -#endif diff --git a/notmuch-private.h b/notmuch-private.h index d257f2b9..3d2610ad 100644 --- a/notmuch-private.h +++ b/notmuch-private.h @@ -274,6 +274,20 @@ notmuch_sha1_of_string (const char *str); char * notmuch_sha1_of_file (const char *filename); +/* tags.c */ + +notmuch_tags_t * +_notmuch_tags_create (void *ctx); + +void +_notmuch_tags_add_tag (notmuch_tags_t *tags, const char *tag); + +void +_notmuch_tags_sort (notmuch_tags_t *tags); + +void +_notmuch_tags_reset (notmuch_tags_t *tags); + NOTMUCH_END_DECLS #endif diff --git a/notmuch.c b/notmuch.c index e2347524..cc53d1d6 100644 --- a/notmuch.c +++ b/notmuch.c @@ -924,11 +924,11 @@ main (int argc, char *argv[]) strcmp (argv[1], "--help") == 0) { fprintf (stderr, "The notmuch mail system.\n\n"); + usage (); + return 0; } else { fprintf (stderr, "Error: Unknown command '%s'\n\n", argv[1]); + usage (); + return 1; } - usage (); - exit (1); - - return 0; } diff --git a/tags.c b/tags.c new file mode 100644 index 00000000..36f3fa40 --- /dev/null +++ b/tags.c @@ -0,0 +1,104 @@ +/* tags.c - Iterator for tags returned from message or thread + * + * Copyright © 2009 Carl Worth + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . + * + * Author: Carl Worth + */ + +#include "notmuch-private.h" + +#include /* GList */ + +struct _notmuch_tags { + GList *tags; + GList *iterator; +}; + +/* XXX: Should write some talloc-friendly list to avoid the need for + * this. */ +static int +_notmuch_tags_destructor (notmuch_tags_t *tags) +{ + g_list_free (tags->tags); + + return 0; +} + +/* Create a new notmuch_tags_t object, with 'ctx' as its talloc owner. + * + * This function can return NULL in case of out-of-memory. + */ +notmuch_tags_t * +_notmuch_tags_create (void *ctx) +{ + notmuch_tags_t *tags; + + tags = talloc (ctx, notmuch_tags_t); + if (unlikely (tags == NULL)) + return NULL; + + talloc_set_destructor (tags, _notmuch_tags_destructor); + + tags->tags = NULL; + tags->iterator = NULL; + + return tags; +} + +void +_notmuch_tags_add_tag (notmuch_tags_t *tags, const char *tag) +{ + tags->tags = g_list_prepend (tags->tags, talloc_strdup (tags, tag)); +} + +void +_notmuch_tags_sort (notmuch_tags_t *tags) +{ + tags->tags = g_list_sort (tags->tags, (GCompareFunc) strcmp); +} + +void +_notmuch_tags_reset (notmuch_tags_t *tags) +{ + tags->iterator = tags->tags; +} + +notmuch_bool_t +notmuch_tags_has_more (notmuch_tags_t *tags) +{ + return tags->iterator != NULL; +} + +const char * +notmuch_tags_get (notmuch_tags_t *tags) +{ + if (tags->iterator) + return (char *) tags->iterator->data; + else + return NULL; +} + +void +notmuch_tags_advance (notmuch_tags_t *tags) +{ + tags->iterator = tags->iterator->next; +} + +void +notmuch_tags_destroy (notmuch_tags_t *tags) +{ + talloc_free (tags); +} diff --git a/tags.cc b/tags.cc deleted file mode 100644 index a921c606..00000000 --- a/tags.cc +++ /dev/null @@ -1,157 +0,0 @@ -/* tags.cc - Iterator for tags returned from message or thread - * - * Copyright © 2009 Carl Worth - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/ . - * - * Author: Carl Worth - */ - -#include "notmuch-private-cxx.h" -#include "database-private.h" - -#include - -typedef struct _notmuch_terms { - char prefix_char; - Xapian::TermIterator iterator; - Xapian::TermIterator iterator_end; -} notmuch_terms_t; - -struct _notmuch_tags { - notmuch_terms_t terms; -}; - -notmuch_terms_t * -_notmuch_terms_create (void *ctx, - Xapian::Document doc, - const char *prefix_name); - -/* The assertion is to ensure that 'type' is a derivative of - * notmuch_terms_t in that it contains a notmuch_terms_t as its first - * member. We do this by name of 'terms' as opposed to type, because - * that's as clever as I've been so far. */ -#define _notmuch_terms_create_type(ctx, doc, prefix_name, type) \ - (COMPILE_TIME_ASSERT(offsetof(type, terms) == 0), \ - (type *) _notmuch_terms_create (ctx, doc, prefix_name)) - -/* We end up having to call the destructors explicitly because we had - * to use "placement new" in order to initialize C++ objects within a - * block that we allocated with talloc. So C++ is making talloc - * slightly less simple to use, (we wouldn't need - * talloc_set_destructor at all otherwise). - */ -static int -_notmuch_terms_destructor (notmuch_terms_t *terms) -{ - terms->iterator.~TermIterator (); - terms->iterator_end.~TermIterator (); - - return 0; -} - -notmuch_terms_t * -_notmuch_terms_create (void *ctx, - Xapian::Document doc, - const char *prefix_name) -{ - notmuch_terms_t *terms; - const char *prefix = _find_prefix (prefix_name); - - /* Currently, notmuch_terms_t is written with the assumption that - * any prefix its derivatives use will be only a single - * character. */ - assert (strlen (prefix) == 1); - - terms = talloc (ctx, notmuch_terms_t); - if (unlikely (terms == NULL)) - return NULL; - - terms->prefix_char = *prefix; - new (&terms->iterator) Xapian::TermIterator; - new (&terms->iterator_end) Xapian::TermIterator; - - talloc_set_destructor (terms, _notmuch_terms_destructor); - - terms->iterator = doc.termlist_begin (); - terms->iterator.skip_to (prefix); - terms->iterator_end = doc.termlist_end (); - - return terms; -} - -static notmuch_bool_t -_notmuch_terms_has_more (notmuch_terms_t *terms) -{ - std::string s; - - if (terms->iterator == terms->iterator_end) - return FALSE; - - s = *terms->iterator; - if (! s.empty () && s[0] == terms->prefix_char) - return TRUE; - else - return FALSE; -} - -static const char * -_notmuch_terms_get (notmuch_terms_t *terms) -{ - return talloc_strdup (terms, (*terms->iterator).c_str () + 1); -} - -static void -_notmuch_terms_advance (notmuch_terms_t *terms) -{ - terms->iterator++; -} - -static void -_notmuch_terms_destroy (notmuch_terms_t *terms) -{ - talloc_free (terms); -} - -notmuch_tags_t * -_notmuch_tags_create_terms (void *ctx, - Xapian::Document doc, - const char *prefix_name) -{ - return _notmuch_terms_create_type (ctx, doc, prefix_name, notmuch_tags_t); -} - -notmuch_bool_t -notmuch_tags_has_more (notmuch_tags_t *tags) -{ - return _notmuch_terms_has_more (&tags->terms); -} - -const char * -notmuch_tags_get (notmuch_tags_t *tags) -{ - return _notmuch_terms_get (&tags->terms); -} - -void -notmuch_tags_advance (notmuch_tags_t *tags) -{ - return _notmuch_terms_advance (&tags->terms); -} - -void -notmuch_tags_destroy (notmuch_tags_t *tags) -{ - return _notmuch_terms_destroy (&tags->terms); -} -- 2.43.0