Return-Path: X-Original-To: notmuch@notmuchmail.org Delivered-To: notmuch@notmuchmail.org Received: from localhost (localhost [127.0.0.1]) by arlo.cworth.org (Postfix) with ESMTP id 5FC666DE18A8 for ; Sat, 12 Mar 2016 04:31:43 -0800 (PST) X-Virus-Scanned: Debian amavisd-new at cworth.org X-Spam-Flag: NO X-Spam-Score: -0.033 X-Spam-Level: X-Spam-Status: No, score=-0.033 tagged_above=-999 required=5 tests=[AWL=-0.022, SPF_PASS=-0.001, T_RP_MATCHES_RCVD=-0.01] autolearn=disabled Received: from arlo.cworth.org ([127.0.0.1]) by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id sesmktKokXHd for ; Sat, 12 Mar 2016 04:31:40 -0800 (PST) Received: from fethera.tethera.net (fethera.tethera.net [198.245.60.197]) by arlo.cworth.org (Postfix) with ESMTPS id 3E95B6DE13EF for ; Sat, 12 Mar 2016 04:31:39 -0800 (PST) Received: from remotemail by fethera.tethera.net with local (Exim 4.84) (envelope-from ) id 1aeiiN-0004zC-U6; Sat, 12 Mar 2016 07:32:15 -0500 Received: (nullmailer pid 17175 invoked by uid 1000); Sat, 12 Mar 2016 12:31:33 -0000 From: David Bremner To: David Bremner , notmuch@notmuchmail.org Subject: [PATCH 2/6] lib: config list iterators Date: Sat, 12 Mar 2016 08:31:26 -0400 Message-Id: <1457785890-17058-3-git-send-email-david@tethera.net> X-Mailer: git-send-email 2.7.0 In-Reply-To: <1457785890-17058-1-git-send-email-david@tethera.net> References: <1453561198-2893-1-git-send-email-david@tethera.net> <1457785890-17058-1-git-send-email-david@tethera.net> X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 12 Mar 2016 12:31:43 -0000 Since xapian provides the ability to restrict the iterator to a given prefix, we expose this ability to the user. Otherwise we mimic the other iterator interfances in notmuch (e.g. tags.c). --- lib/config.cc | 104 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/notmuch.h | 44 +++++++++++++++++++++ test/T590-libconfig.sh | 60 ++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+) diff --git a/lib/config.cc b/lib/config.cc index af00d6f..e581f32 100644 --- a/lib/config.cc +++ b/lib/config.cc @@ -24,6 +24,19 @@ static const std::string CONFIG_PREFIX="C"; +struct _notmuch_config_list { + notmuch_database_t *notmuch; + Xapian::TermIterator *iterator; + char *current_key; + char *current_val; +}; + +static int +_notmuch_config_list_destroy (notmuch_config_list_t *list) { + delete list->iterator; + return 0; +} + notmuch_status_t notmuch_database_set_config (notmuch_database_t *notmuch, const char *key, @@ -88,3 +101,94 @@ notmuch_database_get_config (notmuch_database_t *notmuch, return NOTMUCH_STATUS_SUCCESS; } + +notmuch_status_t +notmuch_database_get_config_list (notmuch_database_t *notmuch, + const char *prefix, + notmuch_config_list_t **out) +{ + notmuch_config_list_t *list = NULL; + notmuch_status_t status = NOTMUCH_STATUS_SUCCESS; + + list = talloc (notmuch, notmuch_config_list_t); + if (!list) { + status = NOTMUCH_STATUS_OUT_OF_MEMORY; + goto DONE; + } + + talloc_set_destructor (list, _notmuch_config_list_destroy); + list->iterator = new Xapian::TermIterator; + list->notmuch = notmuch; + list->current_key = NULL; + list->current_val = NULL; + + try { + + *list->iterator = notmuch->xapian_db->metadata_keys_begin (CONFIG_PREFIX + (prefix ? prefix : "")); + + } catch (const Xapian::Error &error) { + _notmuch_database_log (notmuch, "A Xapian exception occurred getting metadata iterator: %s.\n", + error.get_msg().c_str()); + notmuch->exception_reported = TRUE; + status = NOTMUCH_STATUS_XAPIAN_EXCEPTION; + } + + *out = list; + + DONE: + if (status && list) + talloc_free (list); + + return status; +} + +notmuch_bool_t +notmuch_config_list_valid (notmuch_config_list_t *metadata) +{ + if (*(metadata->iterator) == metadata->notmuch->xapian_db->metadata_keys_end()) + return FALSE; + + return TRUE; +} + +const char * +notmuch_config_list_key (notmuch_config_list_t *list) +{ + if (list->current_key) + talloc_free (list->current_key); + + list->current_key = talloc_strdup (list, (**(list->iterator)).c_str () + CONFIG_PREFIX.length ()); + + return list->current_key; +} + +const char * +notmuch_config_list_value (notmuch_config_list_t *list) +{ + std::string strval; + notmuch_status_t status; + const char *key = notmuch_config_list_key (list); + + /* TODO: better error reporting?? */ + status = _metadata_value (list->notmuch, key, strval); + if (status) + return NULL; + + if (list->current_val) + talloc_free(list->current_val); + + list->current_val = talloc_strdup(list, strval.c_str ()); + return list->current_val; +} + +void +notmuch_config_list_move_to_next (notmuch_config_list_t *list) +{ + (*(list->iterator))++; +} + +void +notmuch_config_list_destroy (notmuch_config_list_t *list) +{ + talloc_free (list); +} diff --git a/lib/notmuch.h b/lib/notmuch.h index c62223b..b439c88 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -197,6 +197,7 @@ typedef struct _notmuch_message notmuch_message_t; typedef struct _notmuch_tags notmuch_tags_t; typedef struct _notmuch_directory notmuch_directory_t; typedef struct _notmuch_filenames notmuch_filenames_t; +typedef struct _notmuch_config_list notmuch_config_list_t; #endif /* __DOXYGEN__ */ /** @@ -1849,6 +1850,49 @@ notmuch_database_set_config (notmuch_database_t *db, const char *key, const char notmuch_status_t notmuch_database_get_config (notmuch_database_t *db, const char *key, char **value); +/** + * Create an iterator for all config items with keys matching a given prefix + */ +notmuch_status_t +notmuch_database_get_config_list (notmuch_database_t *db, const char *prefix, notmuch_config_list_t **out); + +/** + * Is 'config_list' iterator valid (i.e. _key, _value, _move_to_next can be called). + */ +notmuch_bool_t +notmuch_config_list_valid (notmuch_config_list_t *config_list); + +/** + * return key for current config pair + * + * return value is owned by the iterator, and will be destroyed by the + * next call to notmuch_config_list_key or notmuch_config_list_destroy. + */ +const char * +notmuch_config_list_key (notmuch_config_list_t *config_list); + +/** + * return 'value' for current config pair + * + * return value is owned by the iterator, and will be destroyed by the + * next call to notmuch_config_list_value or notmuch config_list_destroy + */ +const char * +notmuch_config_list_value (notmuch_config_list_t *config_list); + + +/** + * move 'config_list' iterator to the next pair + */ +void +notmuch_config_list_move_to_next (notmuch_config_list_t *config_list); + +/** + * free any resources held by 'config_list' + */ +void +notmuch_config_list_destroy (notmuch_config_list_t *config_list); + /* @} */ NOTMUCH_END_DECLS diff --git a/test/T590-libconfig.sh b/test/T590-libconfig.sh index 85e4497..8ca6883 100755 --- a/test/T590-libconfig.sh +++ b/test/T590-libconfig.sh @@ -55,4 +55,64 @@ testkey2 = testvalue2 EOF test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "notmuch_database_get_config_list: empty list" +cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR} +{ + notmuch_config_list_t *list; + RUN(notmuch_database_get_config_list (db, "nonexistent", &list)); + printf("valid = %d\n", notmuch_config_list_valid (list)); + notmuch_config_list_destroy (list); +} +EOF +cat <<'EOF' >EXPECTED +== stdout == +valid = 0 +== stderr == +EOF +test_expect_equal_file EXPECTED OUTPUT + + +test_begin_subtest "notmuch_database_get_config_list: all pairs" +cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR} +{ + notmuch_config_list_t *list; + RUN(notmuch_database_set_config (db, "zzzafter", "afterval")); + RUN(notmuch_database_set_config (db, "aaabefore", "beforeval")); + RUN(notmuch_database_get_config_list (db, "", &list)); + for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) { + printf("%s %s\n", notmuch_config_list_key (list), notmuch_config_list_value(list)); + } + notmuch_config_list_destroy (list); +} +EOF +cat <<'EOF' >EXPECTED +== stdout == +aaabefore beforeval +testkey1 testvalue1 +testkey2 testvalue2 +zzzafter afterval +== stderr == +EOF +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "notmuch_database_get_config_list: one prefix" +cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR} +{ + notmuch_config_list_t *list; + RUN(notmuch_database_get_config_list (db, "testkey", &list)); + for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) { + printf("%s %s\n", notmuch_config_list_key (list), notmuch_config_list_value(list)); + } + notmuch_config_list_destroy (list); +} +EOF +cat <<'EOF' >EXPECTED +== stdout == +testkey1 testvalue1 +testkey2 testvalue2 +== stderr == +EOF +test_expect_equal_file EXPECTED OUTPUT + test_done -- 2.7.0