From: David Bremner Date: Mon, 13 Jun 2016 01:05:52 +0000 (+2100) Subject: [PATCH 5/8] lib: iterator API for message properties X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=09a2f868c4b0ab03fc7914af52a4ca39420767e7;p=notmuch-archives.git [PATCH 5/8] lib: iterator API for message properties --- diff --git a/eb/5ad057444ece79a065a1ef4a3b1b3d303fdc9c b/eb/5ad057444ece79a065a1ef4a3b1b3d303fdc9c new file mode 100644 index 000000000..cc390ba24 --- /dev/null +++ b/eb/5ad057444ece79a065a1ef4a3b1b3d303fdc9c @@ -0,0 +1,336 @@ +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 C4B196DE02A6 + for ; Sun, 12 Jun 2016 18:06:33 -0700 (PDT) +X-Virus-Scanned: Debian amavisd-new at cworth.org +X-Spam-Flag: NO +X-Spam-Score: -0.011 +X-Spam-Level: +X-Spam-Status: No, score=-0.011 tagged_above=-999 required=5 + tests=[AWL=-0.000, 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 EhN9X2EVnluV for ; + Sun, 12 Jun 2016 18:06:26 -0700 (PDT) +Received: from fethera.tethera.net (fethera.tethera.net [198.245.60.197]) + by arlo.cworth.org (Postfix) with ESMTPS id 8D4F76DE02AD + for ; Sun, 12 Jun 2016 18:06:11 -0700 (PDT) +Received: from remotemail by fethera.tethera.net with local (Exim 4.84) + (envelope-from ) + id 1bCGKD-0003xL-CE; Sun, 12 Jun 2016 21:05:57 -0400 +Received: (nullmailer pid 5676 invoked by uid 1000); + Mon, 13 Jun 2016 01:06:04 -0000 +From: David Bremner +To: notmuch@notmuchmail.org +Subject: [PATCH 5/8] lib: iterator API for message properties +Date: Sun, 12 Jun 2016 22:05:52 -0300 +Message-Id: <1465779955-5539-6-git-send-email-david@tethera.net> +X-Mailer: git-send-email 2.8.1 +In-Reply-To: <1465779955-5539-1-git-send-email-david@tethera.net> +References: <1465779955-5539-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: Mon, 13 Jun 2016 01:06:33 -0000 + +This is a thin wrapper around the string map iterator API just introduced. +--- + lib/message-property.cc | 38 +++++++++++++++ + lib/notmuch.h | 95 +++++++++++++++++++++++++++++++++++++ + test/T610-message-property.sh | 107 ++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 240 insertions(+) + +diff --git a/lib/message-property.cc b/lib/message-property.cc +index ad2250f..4fa6cac 100644 +--- a/lib/message-property.cc ++++ b/lib/message-property.cc +@@ -99,3 +99,41 @@ notmuch_message_remove_all_properties (notmuch_message_t *message) + + return NOTMUCH_STATUS_SUCCESS; + } ++ ++notmuch_message_properties_t * ++notmuch_message_get_properties (notmuch_message_t *message, const char *key, notmuch_bool_t exact) ++{ ++ notmuch_string_map_t *map; ++ map = _notmuch_message_property_map (message); ++ return _notmuch_string_map_iterator_create (map, key, exact); ++} ++ ++notmuch_bool_t ++notmuch_message_properties_valid (notmuch_message_properties_t *properties) ++{ ++ return _notmuch_string_map_iterator_valid (properties); ++} ++ ++void ++notmuch_message_properties_move_to_next (notmuch_message_properties_t *properties) ++{ ++ return _notmuch_string_map_iterator_move_to_next (properties); ++} ++ ++const char * ++notmuch_message_properties_key (notmuch_message_properties_t *properties) ++{ ++ return _notmuch_string_map_iterator_key (properties); ++} ++ ++const char * ++notmuch_message_properties_value (notmuch_message_properties_t *properties) ++{ ++ return _notmuch_string_map_iterator_value (properties); ++} ++ ++void ++notmuch_message_properties_destroy (notmuch_message_properties_t *properties) ++{ ++ _notmuch_string_map_iterator_destroy (properties); ++} +diff --git a/lib/notmuch.h b/lib/notmuch.h +index afc48c6..cdf94fd 100644 +--- a/lib/notmuch.h ++++ b/lib/notmuch.h +@@ -1718,6 +1718,101 @@ notmuch_message_remove_property (notmuch_message_t *message, const char *key, co + notmuch_status_t + notmuch_message_remove_all_properties (notmuch_message_t *message); + ++/** ++ * Opaque message property iterator ++ */ ++typedef struct _notmuch_string_map_iterator notmuch_message_properties_t; ++ ++/** ++ * Get the properties for *message*, returning a ++ * notmuch_message_properties_t object which can be used to iterate ++ * over all properties. ++ * ++ * The notmuch_message_properties_t object is owned by the message and ++ * as such, will only be valid for as long as the message is valid, ++ * (which is until the query from which it derived is destroyed). ++ * ++ * @param[in] message The message to examine ++ * @param[in] key key or key prefix ++ * @param[in] exact if TRUE, require exact match with key. Otherwise ++ * treat as prefix. ++ * ++ * Typical usage might be: ++ * ++ * notmuch_message_properties_t *list; ++ * ++ * for (list = notmuch_message_get_properties (message, "testkey1", TRUE); ++ * notmuch_message_properties_valid (list); notmuch_message_properties_move_to_next (list)) { ++ * printf("%s\n", notmuch_message_properties_value(list)); ++ * } ++ * ++ * notmuch_message_properties_destroy (list); ++ * ++ * Note that there's no explicit destructor needed for the ++ * notmuch_message_properties_t object. (For consistency, we do ++ * provide a notmuch_message_properities_destroy function, but there's ++ * no good reason to call it if the message is about to be destroyed). ++ */ ++notmuch_message_properties_t * ++notmuch_message_get_properties (notmuch_message_t *message, const char *key, notmuch_bool_t exact); ++ ++/** ++ * Is the given *properties* iterator pointing at a valid (key,value) ++ * pair. ++ * ++ * When this function returns TRUE, ++ * notmuch_message_properties_{key,value} will return a valid string, ++ * and notmuch_message_properties_move_to_next will do what it ++ * says. Whereas when this function returns FALSE, calling any of ++ * these functions results in undefined behaviour. ++ * ++ * See the documentation of notmuch_message_properties_get for example ++ * code showing how to iterate over a notmuch_message_properties_t ++ * object. ++ */ ++notmuch_bool_t ++notmuch_message_properties_valid (notmuch_message_properties_t *properties); ++ ++/** ++ * Move the *properties* iterator to the next (key,value) pair ++ * ++ * If *properties* is already pointing at the last pair then the iterator ++ * will be moved to a point just beyond that last pair, (where ++ * notmuch_message_properties_valid will return FALSE). ++ * ++ * See the documentation of notmuch_message_get_properties for example ++ * code showing how to iterate over a notmuch_message_properties_t object. ++ */ ++void ++notmuch_message_properties_move_to_next (notmuch_message_properties_t *properties); ++ ++/** ++ * Return the key from the current (key,value) pair. ++ * ++ * this could be useful if iterating for a prefix ++ */ ++const char * ++notmuch_message_properties_key (notmuch_message_properties_t *properties); ++ ++/** ++ * Return the key from the current (key,value) pair. ++ * ++ * This could be useful if iterating for a prefix. ++ */ ++const char * ++notmuch_message_properties_value (notmuch_message_properties_t *properties); ++ ++ ++/** ++ * Destroy a notmuch_message_properties_t object. ++ * ++ * It's not strictly necessary to call this function. All memory from ++ * the notmuch_message_properties_t object will be reclaimed when the ++ * containing message object is destroyed. ++ */ ++void ++notmuch_message_properties_destroy (notmuch_message_properties_t *properties); ++ + /**@}*/ + + /** +diff --git a/test/T610-message-property.sh b/test/T610-message-property.sh +index 0217950..b5ddb7a 100755 +--- a/test/T610-message-property.sh ++++ b/test/T610-message-property.sh +@@ -9,8 +9,18 @@ cat < c_head + #include + #include + #include ++#include + #include + ++void print_properties (notmuch_message_t *message, const char *prefix, notmuch_bool_t exact) { ++ notmuch_message_properties_t *list; ++ for (list = notmuch_message_get_properties (message, prefix, exact); ++ notmuch_message_properties_valid (list); notmuch_message_properties_move_to_next (list)) { ++ printf("%s\n", notmuch_message_properties_value(list)); ++ } ++ notmuch_message_properties_destroy (list); ++} ++ + int main (int argc, char** argv) + { + notmuch_database_t *db; +@@ -79,6 +89,103 @@ testkey2 = NULL + EOF + test_expect_equal_file EXPECTED OUTPUT + ++test_begin_subtest "notmuch_message_get_properties: empty list" ++cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR} ++{ ++ notmuch_message_properties_t *list; ++ list = notmuch_message_get_properties (message, "nonexistent", TRUE); ++ printf("valid = %d\n", notmuch_message_properties_valid (list)); ++ notmuch_message_properties_destroy (list); ++} ++EOF ++cat <<'EOF' >EXPECTED ++== stdout == ++valid = 0 ++== stderr == ++EOF ++test_expect_equal_file EXPECTED OUTPUT + ++test_begin_subtest "notmuch_message_properties: one value" ++cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR} ++print_properties (message, "testkey1", TRUE); ++EOF ++cat <<'EOF' >EXPECTED ++== stdout == ++testvalue1 ++== stderr == ++EOF ++test_expect_equal_file EXPECTED OUTPUT ++ ++test_begin_subtest "notmuch_message_properties: multiple values" ++cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR} ++EXPECT0(notmuch_message_add_property (message, "testkey1", "bob")); ++EXPECT0(notmuch_message_add_property (message, "testkey1", "testvalue2")); ++EXPECT0(notmuch_message_add_property (message, "testkey1", "alice")); ++print_properties (message, "testkey1", TRUE); ++EOF ++cat <<'EOF' >EXPECTED ++== stdout == ++alice ++bob ++testvalue1 ++testvalue2 ++== stderr == ++EOF ++test_expect_equal_file EXPECTED OUTPUT ++ ++test_begin_subtest "notmuch_message_properties: prefix" ++cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR} ++EXPECT0(notmuch_message_add_property (message, "testkey3", "bob3")); ++EXPECT0(notmuch_message_add_property (message, "testkey3", "testvalue3")); ++EXPECT0(notmuch_message_add_property (message, "testkey3", "alice3")); ++print_properties (message, "testkey", FALSE); ++EOF ++cat <<'EOF' >EXPECTED ++== stdout == ++alice ++bob ++testvalue1 ++testvalue2 ++alice3 ++bob3 ++testvalue3 ++== stderr == ++EOF ++test_expect_equal_file EXPECTED OUTPUT ++ ++test_begin_subtest "notmuch_message_properties: modify during iteration" ++cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR} ++{ ++ const char *keys[1000] = {NULL}; ++ const char *vals[1000] = {NULL}; ++ notmuch_message_properties_t *properties; ++ int i; ++ ++ for (properties = notmuch_message_get_properties (message, "", FALSE), i=0; ++ notmuch_message_properties_valid (properties); ++ notmuch_message_properties_move_to_next (properties), i++) ++ { ++ const char *key, *value; ++ ++ keys[i]=talloc_strdup(message, ++ notmuch_message_properties_key (properties)); ++ vals[i]=talloc_strdup(message, ++ notmuch_message_properties_value (properties)); ++ ++ EXPECT0(notmuch_message_remove_property (message, keys[i], vals[i])); ++ } ++ ++ print_properties (message, "", FALSE); ++ ++ for (i = 0; keys[i] && vals[i]; i++) { ++ EXPECT0(notmuch_message_add_property (message, keys[i], vals[i])); ++ } ++} ++EOF ++cat <<'EOF' >EXPECTED ++== stdout == ++== stderr == ++EOF ++test_expect_equal_file EXPECTED OUTPUT + + test_done +-- +2.8.1 +