Re: [WIP PATCH] emacs: query: completion for from: in searches
[notmuch-archives.git] / 9e / 8e9519ea0bcae2af91ee4e74acea2d72eba3d3
1 Return-Path: <bremner@tethera.net>\r
2 X-Original-To: notmuch@notmuchmail.org\r
3 Delivered-To: notmuch@notmuchmail.org\r
4 Received: from localhost (localhost [127.0.0.1])\r
5  by arlo.cworth.org (Postfix) with ESMTP id 08FEA6DE02C2\r
6  for <notmuch@notmuchmail.org>; Wed, 25 May 2016 03:52:12 -0700 (PDT)\r
7 X-Virus-Scanned: Debian amavisd-new at cworth.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -0.012\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-0.012 tagged_above=-999 required=5\r
12  tests=[AWL=-0.001, SPF_PASS=-0.001, T_RP_MATCHES_RCVD=-0.01]\r
13  autolearn=disabled\r
14 Received: from arlo.cworth.org ([127.0.0.1])\r
15  by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024)\r
16  with ESMTP id TM_W9WuigYCP for <notmuch@notmuchmail.org>;\r
17  Wed, 25 May 2016 03:52:04 -0700 (PDT)\r
18 Received: from fethera.tethera.net (fethera.tethera.net [198.245.60.197])\r
19  by arlo.cworth.org (Postfix) with ESMTPS id 44CB26DE02C3\r
20  for <notmuch@notmuchmail.org>; Wed, 25 May 2016 03:51:41 -0700 (PDT)\r
21 Received: from remotemail by fethera.tethera.net with local (Exim 4.84)\r
22  (envelope-from <bremner@tethera.net>)\r
23  id 1b5WPT-0004Uj-RS; Wed, 25 May 2016 06:51:31 -0400\r
24 Received: (nullmailer pid 23138 invoked by uid 1000);\r
25  Wed, 25 May 2016 10:51:31 -0000\r
26 From: David Bremner <david@tethera.net>\r
27 To: notmuch@notmuchmail.org\r
28 Subject: [Patch v6 2/7] lib: config list iterators\r
29 Date: Wed, 25 May 2016 07:51:21 -0300\r
30 Message-Id: <1464173486-23032-3-git-send-email-david@tethera.net>\r
31 X-Mailer: git-send-email 2.8.1\r
32 In-Reply-To: <1464173486-23032-1-git-send-email-david@tethera.net>\r
33 References: <1464173486-23032-1-git-send-email-david@tethera.net>\r
34 X-BeenThere: notmuch@notmuchmail.org\r
35 X-Mailman-Version: 2.1.20\r
36 Precedence: list\r
37 List-Id: "Use and development of the notmuch mail system."\r
38  <notmuch.notmuchmail.org>\r
39 List-Unsubscribe: <https://notmuchmail.org/mailman/options/notmuch>,\r
40  <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
41 List-Archive: <http://notmuchmail.org/pipermail/notmuch/>\r
42 List-Post: <mailto:notmuch@notmuchmail.org>\r
43 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
44 List-Subscribe: <https://notmuchmail.org/mailman/listinfo/notmuch>,\r
45  <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
46 X-List-Received-Date: Wed, 25 May 2016 10:52:12 -0000\r
47 \r
48 Since xapian provides the ability to restrict the iterator to a given\r
49 prefix, we expose this ability to the user. Otherwise we mimic the other\r
50 iterator interfances in notmuch (e.g. tags.c).\r
51 ---\r
52  lib/config.cc          | 106 +++++++++++++++++++++++++++++++++++++++++++++++++\r
53  lib/notmuch.h          |  44 ++++++++++++++++++++\r
54  test/T590-libconfig.sh |  60 ++++++++++++++++++++++++++++\r
55  3 files changed, 210 insertions(+)\r
56 \r
57 diff --git a/lib/config.cc b/lib/config.cc\r
58 index 9ca74bf..e05e50f 100644\r
59 --- a/lib/config.cc\r
60 +++ b/lib/config.cc\r
61 @@ -24,6 +24,21 @@\r
62  \r
63  static const std::string CONFIG_PREFIX = "C";\r
64  \r
65 +struct _notmuch_config_list {\r
66 +    notmuch_database_t *notmuch;\r
67 +    Xapian::TermIterator iterator;\r
68 +    char *current_key;\r
69 +    char *current_val;\r
70 +};\r
71 +\r
72 +static int\r
73 +_notmuch_config_list_destroy (notmuch_config_list_t *list)\r
74 +{\r
75 +    /* invoke destructor w/o deallocating memory */\r
76 +    list->iterator.~TermIterator();\r
77 +    return 0;\r
78 +}\r
79 +\r
80  notmuch_status_t\r
81  notmuch_database_set_config (notmuch_database_t *notmuch,\r
82                              const char *key,\r
83 @@ -85,3 +100,94 @@ notmuch_database_get_config (notmuch_database_t *notmuch,\r
84  \r
85      return NOTMUCH_STATUS_SUCCESS;\r
86  }\r
87 +\r
88 +notmuch_status_t\r
89 +notmuch_database_get_config_list (notmuch_database_t *notmuch,\r
90 +                                 const char *prefix,\r
91 +                                 notmuch_config_list_t **out)\r
92 +{\r
93 +    notmuch_config_list_t *list = NULL;\r
94 +    notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;\r
95 +\r
96 +    list = talloc (notmuch, notmuch_config_list_t);\r
97 +    if (! list) {\r
98 +       status = NOTMUCH_STATUS_OUT_OF_MEMORY;\r
99 +       goto DONE;\r
100 +    }\r
101 +\r
102 +    talloc_set_destructor (list, _notmuch_config_list_destroy);\r
103 +    list->notmuch = notmuch;\r
104 +    list->current_key = NULL;\r
105 +    list->current_val = NULL;\r
106 +\r
107 +    try {\r
108 +\r
109 +       new(&(list->iterator)) Xapian::TermIterator (notmuch->xapian_db->metadata_keys_begin\r
110 +                                                    (CONFIG_PREFIX + (prefix ? prefix : "")));\r
111 +\r
112 +    } catch (const Xapian::Error &error) {\r
113 +       _notmuch_database_log (notmuch, "A Xapian exception occurred getting metadata iterator: %s.\n",\r
114 +                              error.get_msg().c_str());\r
115 +       notmuch->exception_reported = TRUE;\r
116 +       status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;\r
117 +    }\r
118 +\r
119 +    *out = list;\r
120 +\r
121 +  DONE:\r
122 +    if (status && list)\r
123 +       talloc_free (list);\r
124 +\r
125 +    return status;\r
126 +}\r
127 +\r
128 +notmuch_bool_t\r
129 +notmuch_config_list_valid (notmuch_config_list_t *metadata)\r
130 +{\r
131 +    if (metadata->iterator == metadata->notmuch->xapian_db->metadata_keys_end ())\r
132 +       return FALSE;\r
133 +\r
134 +    return TRUE;\r
135 +}\r
136 +\r
137 +const char *\r
138 +notmuch_config_list_key (notmuch_config_list_t *list)\r
139 +{\r
140 +    if (list->current_key)\r
141 +       talloc_free (list->current_key);\r
142 +\r
143 +    list->current_key = talloc_strdup (list, (*list->iterator).c_str () + CONFIG_PREFIX.length ());\r
144 +\r
145 +    return list->current_key;\r
146 +}\r
147 +\r
148 +const char *\r
149 +notmuch_config_list_value (notmuch_config_list_t *list)\r
150 +{\r
151 +    std::string strval;\r
152 +    notmuch_status_t status;\r
153 +    const char *key = notmuch_config_list_key (list);\r
154 +\r
155 +    /* TODO: better error reporting?? */\r
156 +    status = _metadata_value (list->notmuch, key, strval);\r
157 +    if (status)\r
158 +       return NULL;\r
159 +\r
160 +    if (list->current_val)\r
161 +       talloc_free (list->current_val);\r
162 +\r
163 +    list->current_val = talloc_strdup (list, strval.c_str ());\r
164 +    return list->current_val;\r
165 +}\r
166 +\r
167 +void\r
168 +notmuch_config_list_move_to_next (notmuch_config_list_t *list)\r
169 +{\r
170 +    list->iterator++;\r
171 +}\r
172 +\r
173 +void\r
174 +notmuch_config_list_destroy (notmuch_config_list_t *list)\r
175 +{\r
176 +    talloc_free (list);\r
177 +}\r
178 diff --git a/lib/notmuch.h b/lib/notmuch.h\r
179 index c827e02..bd977c3 100644\r
180 --- a/lib/notmuch.h\r
181 +++ b/lib/notmuch.h\r
182 @@ -206,6 +206,7 @@ typedef struct _notmuch_message notmuch_message_t;\r
183  typedef struct _notmuch_tags notmuch_tags_t;\r
184  typedef struct _notmuch_directory notmuch_directory_t;\r
185  typedef struct _notmuch_filenames notmuch_filenames_t;\r
186 +typedef struct _notmuch_config_list notmuch_config_list_t;\r
187  #endif /* __DOXYGEN__ */\r
188  \r
189  /**\r
190 @@ -1859,6 +1860,49 @@ notmuch_status_t\r
191  notmuch_database_get_config (notmuch_database_t *db, const char *key, char **value);\r
192  \r
193  /**\r
194 + * Create an iterator for all config items with keys matching a given prefix\r
195 + */\r
196 +notmuch_status_t\r
197 +notmuch_database_get_config_list (notmuch_database_t *db, const char *prefix, notmuch_config_list_t **out);\r
198 +\r
199 +/**\r
200 + * Is 'config_list' iterator valid (i.e. _key, _value, _move_to_next can be called).\r
201 + */\r
202 +notmuch_bool_t\r
203 +notmuch_config_list_valid (notmuch_config_list_t *config_list);\r
204 +\r
205 +/**\r
206 + * return key for current config pair\r
207 + *\r
208 + * return value is owned by the iterator, and will be destroyed by the\r
209 + * next call to notmuch_config_list_key or notmuch_config_list_destroy.\r
210 + */\r
211 +const char *\r
212 +notmuch_config_list_key (notmuch_config_list_t *config_list);\r
213 +\r
214 +/**\r
215 + * return 'value' for current config pair\r
216 + *\r
217 + * return value is owned by the iterator, and will be destroyed by the\r
218 + * next call to notmuch_config_list_value or notmuch config_list_destroy\r
219 + */\r
220 +const char *\r
221 +notmuch_config_list_value (notmuch_config_list_t *config_list);\r
222 +\r
223 +\r
224 +/**\r
225 + * move 'config_list' iterator to the next pair\r
226 + */\r
227 +void\r
228 +notmuch_config_list_move_to_next (notmuch_config_list_t *config_list);\r
229 +\r
230 +/**\r
231 + * free any resources held by 'config_list'\r
232 + */\r
233 +void\r
234 +notmuch_config_list_destroy (notmuch_config_list_t *config_list);\r
235 +\r
236 +/**\r
237   * interrogate the library for compile time features\r
238   */\r
239  notmuch_bool_t\r
240 diff --git a/test/T590-libconfig.sh b/test/T590-libconfig.sh\r
241 index 85e4497..8ca6883 100755\r
242 --- a/test/T590-libconfig.sh\r
243 +++ b/test/T590-libconfig.sh\r
244 @@ -55,4 +55,64 @@ testkey2 = testvalue2\r
245  EOF\r
246  test_expect_equal_file EXPECTED OUTPUT\r
247  \r
248 +\r
249 +test_begin_subtest "notmuch_database_get_config_list: empty list"\r
250 +cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}\r
251 +{\r
252 +   notmuch_config_list_t *list;\r
253 +   RUN(notmuch_database_get_config_list (db, "nonexistent", &list));\r
254 +   printf("valid = %d\n", notmuch_config_list_valid (list));\r
255 +   notmuch_config_list_destroy (list);\r
256 +}\r
257 +EOF\r
258 +cat <<'EOF' >EXPECTED\r
259 +== stdout ==\r
260 +valid = 0\r
261 +== stderr ==\r
262 +EOF\r
263 +test_expect_equal_file EXPECTED OUTPUT\r
264 +\r
265 +\r
266 +test_begin_subtest "notmuch_database_get_config_list: all pairs"\r
267 +cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}\r
268 +{\r
269 +   notmuch_config_list_t *list;\r
270 +   RUN(notmuch_database_set_config (db, "zzzafter", "afterval"));\r
271 +   RUN(notmuch_database_set_config (db, "aaabefore", "beforeval"));\r
272 +   RUN(notmuch_database_get_config_list (db, "", &list));\r
273 +   for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {\r
274 +      printf("%s %s\n", notmuch_config_list_key (list), notmuch_config_list_value(list));\r
275 +   }\r
276 +   notmuch_config_list_destroy (list);\r
277 +}\r
278 +EOF\r
279 +cat <<'EOF' >EXPECTED\r
280 +== stdout ==\r
281 +aaabefore beforeval\r
282 +testkey1 testvalue1\r
283 +testkey2 testvalue2\r
284 +zzzafter afterval\r
285 +== stderr ==\r
286 +EOF\r
287 +test_expect_equal_file EXPECTED OUTPUT\r
288 +\r
289 +test_begin_subtest "notmuch_database_get_config_list: one prefix"\r
290 +cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}\r
291 +{\r
292 +   notmuch_config_list_t *list;\r
293 +   RUN(notmuch_database_get_config_list (db, "testkey", &list));\r
294 +   for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {\r
295 +      printf("%s %s\n", notmuch_config_list_key (list), notmuch_config_list_value(list));\r
296 +   }\r
297 +   notmuch_config_list_destroy (list);\r
298 +}\r
299 +EOF\r
300 +cat <<'EOF' >EXPECTED\r
301 +== stdout ==\r
302 +testkey1 testvalue1\r
303 +testkey2 testvalue2\r
304 +== stderr ==\r
305 +EOF\r
306 +test_expect_equal_file EXPECTED OUTPUT\r
307 +\r
308  test_done\r
309 -- \r
310 2.8.1\r
311 \r