[Patch v7 04/14] notmuch-tag: factor out double quoting routine

2012-12-16 Thread Jani Nikula
On Fri, 14 Dec 2012, david at tethera.net wrote:
> From: David Bremner 
>
> This could live in tag-util as well, but it is really nothing specific
> to tags (although the conventions are arguable specific to Xapian).
>
> The API is changed from "caller-allocates" to "readline-like". The scan for
> max tag length is pushed down into the double quoting routine.
> ---
>  notmuch-tag.c  |   50 --
>  util/string-util.c |   34 ++
>  util/string-util.h |8 
>  3 files changed, 58 insertions(+), 34 deletions(-)
>
> diff --git a/notmuch-tag.c b/notmuch-tag.c
> index 0965ee7..13f2268 100644
> --- a/notmuch-tag.c
> +++ b/notmuch-tag.c
> @@ -20,6 +20,7 @@
>  
>  #include "notmuch-client.h"
>  #include "tag-util.h"
> +#include "string-util.h"
>  
>  static volatile sig_atomic_t interrupted;
>  
> @@ -37,25 +38,6 @@ handle_sigint (unused (int sig))
>  }
>  
>  static char *
> -_escape_tag (char *buf, const char *tag)
> -{
> -const char *in = tag;
> -char *out = buf;
> -
> -/* Boolean terms surrounded by double quotes can contain any
> - * character.  Double quotes are quoted by doubling them. */
> -*out++ = '"';
> -while (*in) {
> - if (*in == '"')
> - *out++ = '"';
> - *out++ = *in++;
> -}
> -*out++ = '"';
> -*out = 0;
> -return buf;
> -}
> -
> -static char *
>  _optimize_tag_query (void *ctx, const char *orig_query_string,
>const tag_op_list_t *list)
>  {
> @@ -67,44 +49,44 @@ _optimize_tag_query (void *ctx, const char 
> *orig_query_string,
>   * parenthesize and the exclusion part of the query must not use
>   * the '-' operator (though the NOT operator is fine). */
>  
> -char *escaped, *query_string;
> +char *escaped = NULL;
> +size_t escaped_len = 0;
> +char *query_string;
>  const char *join = "";
>  size_t i;
> -unsigned int max_tag_len = 0;
>  
>  /* Don't optimize if there are no tag changes. */
>  if (tag_op_list_size (list) == 0)
>   return talloc_strdup (ctx, orig_query_string);
>  
> -/* Allocate a buffer for escaping tags.  This is large enough to
> - * hold a fully escaped tag with every character doubled plus
> - * enclosing quotes and a NUL. */
> -for (i = 0; i < tag_op_list_size (list); i++)
> - if (strlen (tag_op_list_tag (list, i)) > max_tag_len)
> - max_tag_len = strlen (tag_op_list_tag (list, i));
> -
> -escaped = talloc_array (ctx, char, max_tag_len * 2 + 3);
> -if (! escaped)
> - return NULL;
> -
>  /* Build the new query string */
>  if (strcmp (orig_query_string, "*") == 0)
>   query_string = talloc_strdup (ctx, "(");
>  else
>   query_string = talloc_asprintf (ctx, "( %s ) and (", orig_query_string);
>  
> +
> +/* Boolean terms surrounded by double quotes can contain any
> + * character.  Double quotes are quoted by doubling them. */
> +
>  for (i = 0; i < tag_op_list_size (list) && query_string; i++) {
> + double_quote_str (ctx,
> +   tag_op_list_tag (list, i),
> +   , _len);

Check return value?

> +
>   query_string = talloc_asprintf_append_buffer (
>   query_string, "%s%stag:%s", join,
>   tag_op_list_isremove (list, i) ? "" : "not ",
> - _escape_tag (escaped, tag_op_list_tag (list, i)));
> + escaped);
>   join = " or ";
>  }
>  
>  if (query_string)
>   query_string = talloc_strdup_append_buffer (query_string, ")");
>  
> -talloc_free (escaped);
> +if (escaped)
> + talloc_free (escaped);
> +
>  return query_string;
>  }
>  
> diff --git a/util/string-util.c b/util/string-util.c
> index 44f8cd3..ea7c25b 100644
> --- a/util/string-util.c
> +++ b/util/string-util.c
> @@ -20,6 +20,7 @@
>  
>  
>  #include "string-util.h"
> +#include "talloc.h"
>  
>  char *
>  strtok_len (char *s, const char *delim, size_t *len)
> @@ -32,3 +33,36 @@ strtok_len (char *s, const char *delim, size_t *len)
>  
>  return *len ? s : NULL;
>  }
> +
> +
> +int
> +double_quote_str (void *ctx, const char *str,
> +   char **buf, size_t *len)
> +{
> +const char *in;
> +char *out;
> +size_t needed = 3;
> +
> +for (in = str; *in; in++)
> + needed += (*in == '"') ? 2 : 1;
> +
> +if (needed > *len)
> + *buf = talloc_realloc (ctx, *buf, char, 2*needed);

You fail to set *len to 2*needed, leading to doing realloc every time.

Also, I think you should follow the getline pattern like you did in
hex_encode: if *buf == NULL, the input value of *len is ignored.

BR,
Jani.

> +
> +if (! *buf)
> + return 1;
> +
> +out = *buf;
> +
> +*out++ = '"';
> +in = str;
> +while (*in) {
> + if (*in == '"')
> + *out++ = '"';
> + *out++ = *in++;
> +}
> +*out++ = '"';
> +*out = 0;
> +
> +return 0;
> +}
> diff --git a/util/string-util.h 

[Patch v7 04/14] notmuch-tag: factor out double quoting routine

2012-12-15 Thread Mark Walters
On Fri, 14 Dec 2012, david at tethera.net wrote:
> From: David Bremner 
>
> This could live in tag-util as well, but it is really nothing specific
> to tags (although the conventions are arguable specific to Xapian).
>
> The API is changed from "caller-allocates" to "readline-like". The scan for
> max tag length is pushed down into the double quoting routine.
> ---
>  notmuch-tag.c  |   50 --
>  util/string-util.c |   34 ++
>  util/string-util.h |8 
>  3 files changed, 58 insertions(+), 34 deletions(-)
>
> diff --git a/notmuch-tag.c b/notmuch-tag.c
> index 0965ee7..13f2268 100644
> --- a/notmuch-tag.c
> +++ b/notmuch-tag.c
> @@ -20,6 +20,7 @@
>  
>  #include "notmuch-client.h"
>  #include "tag-util.h"
> +#include "string-util.h"
>  
>  static volatile sig_atomic_t interrupted;
>  
> @@ -37,25 +38,6 @@ handle_sigint (unused (int sig))
>  }
>  
>  static char *
> -_escape_tag (char *buf, const char *tag)
> -{
> -const char *in = tag;
> -char *out = buf;
> -
> -/* Boolean terms surrounded by double quotes can contain any
> - * character.  Double quotes are quoted by doubling them. */
> -*out++ = '"';
> -while (*in) {
> - if (*in == '"')
> - *out++ = '"';
> - *out++ = *in++;
> -}
> -*out++ = '"';
> -*out = 0;
> -return buf;
> -}
> -
> -static char *
>  _optimize_tag_query (void *ctx, const char *orig_query_string,
>const tag_op_list_t *list)
>  {
> @@ -67,44 +49,44 @@ _optimize_tag_query (void *ctx, const char 
> *orig_query_string,
>   * parenthesize and the exclusion part of the query must not use
>   * the '-' operator (though the NOT operator is fine). */
>  
> -char *escaped, *query_string;
> +char *escaped = NULL;
> +size_t escaped_len = 0;
> +char *query_string;
>  const char *join = "";
>  size_t i;
> -unsigned int max_tag_len = 0;
>  
>  /* Don't optimize if there are no tag changes. */
>  if (tag_op_list_size (list) == 0)
>   return talloc_strdup (ctx, orig_query_string);
>  
> -/* Allocate a buffer for escaping tags.  This is large enough to
> - * hold a fully escaped tag with every character doubled plus
> - * enclosing quotes and a NUL. */
> -for (i = 0; i < tag_op_list_size (list); i++)
> - if (strlen (tag_op_list_tag (list, i)) > max_tag_len)
> - max_tag_len = strlen (tag_op_list_tag (list, i));
> -
> -escaped = talloc_array (ctx, char, max_tag_len * 2 + 3);
> -if (! escaped)
> - return NULL;
> -
>  /* Build the new query string */
>  if (strcmp (orig_query_string, "*") == 0)
>   query_string = talloc_strdup (ctx, "(");
>  else
>   query_string = talloc_asprintf (ctx, "( %s ) and (", orig_query_string);
>  
> +
> +/* Boolean terms surrounded by double quotes can contain any
> + * character.  Double quotes are quoted by doubling them. */
> +
>  for (i = 0; i < tag_op_list_size (list) && query_string; i++) {
> + double_quote_str (ctx,
> +   tag_op_list_tag (list, i),
> +   , _len);
> +
>   query_string = talloc_asprintf_append_buffer (
>   query_string, "%s%stag:%s", join,
>   tag_op_list_isremove (list, i) ? "" : "not ",
> - _escape_tag (escaped, tag_op_list_tag (list, i)));
> + escaped);
>   join = " or ";
>  }
>  
>  if (query_string)
>   query_string = talloc_strdup_append_buffer (query_string, ")");
>  
> -talloc_free (escaped);
> +if (escaped)
> + talloc_free (escaped);
> +
>  return query_string;
>  }
>  
> diff --git a/util/string-util.c b/util/string-util.c
> index 44f8cd3..ea7c25b 100644
> --- a/util/string-util.c
> +++ b/util/string-util.c
> @@ -20,6 +20,7 @@
>  
>  
>  #include "string-util.h"
> +#include "talloc.h"
>  
>  char *
>  strtok_len (char *s, const char *delim, size_t *len)
> @@ -32,3 +33,36 @@ strtok_len (char *s, const char *delim, size_t *len)
>  
>  return *len ? s : NULL;
>  }
> +
> +
> +int
> +double_quote_str (void *ctx, const char *str,
> +   char **buf, size_t *len)
> +{
> +const char *in;
> +char *out;
> +size_t needed = 3;
> +
> +for (in = str; *in; in++)
> + needed += (*in == '"') ? 2 : 1;
> +
> +if (needed > *len)
> + *buf = talloc_realloc (ctx, *buf, char, 2*needed);
> +
> +if (! *buf)
> + return 1;
> +
> +out = *buf;
> +
> +*out++ = '"';
> +in = str;
> +while (*in) {
> + if (*in == '"')
> + *out++ = '"';
> + *out++ = *in++;
> +}
> +*out++ = '"';
> +*out = 0;

Just a triviality: isn't '\0' preferred?

Best wishes

Mark

> +
> +return 0;
> +}
> diff --git a/util/string-util.h b/util/string-util.h
> index ac7676c..b593bc7 100644
> --- a/util/string-util.h
> +++ b/util/string-util.h
> @@ -19,4 +19,12 @@
>  
>  char *strtok_len (char *s, const char *delim, size_t *len);

Re: [Patch v7 04/14] notmuch-tag: factor out double quoting routine

2012-12-15 Thread Mark Walters
On Fri, 14 Dec 2012, da...@tethera.net wrote:
 From: David Bremner brem...@debian.org

 This could live in tag-util as well, but it is really nothing specific
 to tags (although the conventions are arguable specific to Xapian).

 The API is changed from caller-allocates to readline-like. The scan for
 max tag length is pushed down into the double quoting routine.
 ---
  notmuch-tag.c  |   50 --
  util/string-util.c |   34 ++
  util/string-util.h |8 
  3 files changed, 58 insertions(+), 34 deletions(-)

 diff --git a/notmuch-tag.c b/notmuch-tag.c
 index 0965ee7..13f2268 100644
 --- a/notmuch-tag.c
 +++ b/notmuch-tag.c
 @@ -20,6 +20,7 @@
  
  #include notmuch-client.h
  #include tag-util.h
 +#include string-util.h
  
  static volatile sig_atomic_t interrupted;
  
 @@ -37,25 +38,6 @@ handle_sigint (unused (int sig))
  }
  
  static char *
 -_escape_tag (char *buf, const char *tag)
 -{
 -const char *in = tag;
 -char *out = buf;
 -
 -/* Boolean terms surrounded by double quotes can contain any
 - * character.  Double quotes are quoted by doubling them. */
 -*out++ = '';
 -while (*in) {
 - if (*in == '')
 - *out++ = '';
 - *out++ = *in++;
 -}
 -*out++ = '';
 -*out = 0;
 -return buf;
 -}
 -
 -static char *
  _optimize_tag_query (void *ctx, const char *orig_query_string,
const tag_op_list_t *list)
  {
 @@ -67,44 +49,44 @@ _optimize_tag_query (void *ctx, const char 
 *orig_query_string,
   * parenthesize and the exclusion part of the query must not use
   * the '-' operator (though the NOT operator is fine). */
  
 -char *escaped, *query_string;
 +char *escaped = NULL;
 +size_t escaped_len = 0;
 +char *query_string;
  const char *join = ;
  size_t i;
 -unsigned int max_tag_len = 0;
  
  /* Don't optimize if there are no tag changes. */
  if (tag_op_list_size (list) == 0)
   return talloc_strdup (ctx, orig_query_string);
  
 -/* Allocate a buffer for escaping tags.  This is large enough to
 - * hold a fully escaped tag with every character doubled plus
 - * enclosing quotes and a NUL. */
 -for (i = 0; i  tag_op_list_size (list); i++)
 - if (strlen (tag_op_list_tag (list, i))  max_tag_len)
 - max_tag_len = strlen (tag_op_list_tag (list, i));
 -
 -escaped = talloc_array (ctx, char, max_tag_len * 2 + 3);
 -if (! escaped)
 - return NULL;
 -
  /* Build the new query string */
  if (strcmp (orig_query_string, *) == 0)
   query_string = talloc_strdup (ctx, ();
  else
   query_string = talloc_asprintf (ctx, ( %s ) and (, orig_query_string);
  
 +
 +/* Boolean terms surrounded by double quotes can contain any
 + * character.  Double quotes are quoted by doubling them. */
 +
  for (i = 0; i  tag_op_list_size (list)  query_string; i++) {
 + double_quote_str (ctx,
 +   tag_op_list_tag (list, i),
 +   escaped, escaped_len);
 +
   query_string = talloc_asprintf_append_buffer (
   query_string, %s%stag:%s, join,
   tag_op_list_isremove (list, i) ?  : not ,
 - _escape_tag (escaped, tag_op_list_tag (list, i)));
 + escaped);
   join =  or ;
  }
  
  if (query_string)
   query_string = talloc_strdup_append_buffer (query_string, ));
  
 -talloc_free (escaped);
 +if (escaped)
 + talloc_free (escaped);
 +
  return query_string;
  }
  
 diff --git a/util/string-util.c b/util/string-util.c
 index 44f8cd3..ea7c25b 100644
 --- a/util/string-util.c
 +++ b/util/string-util.c
 @@ -20,6 +20,7 @@
  
  
  #include string-util.h
 +#include talloc.h
  
  char *
  strtok_len (char *s, const char *delim, size_t *len)
 @@ -32,3 +33,36 @@ strtok_len (char *s, const char *delim, size_t *len)
  
  return *len ? s : NULL;
  }
 +
 +
 +int
 +double_quote_str (void *ctx, const char *str,
 +   char **buf, size_t *len)
 +{
 +const char *in;
 +char *out;
 +size_t needed = 3;
 +
 +for (in = str; *in; in++)
 + needed += (*in == '') ? 2 : 1;
 +
 +if (needed  *len)
 + *buf = talloc_realloc (ctx, *buf, char, 2*needed);
 +
 +if (! *buf)
 + return 1;
 +
 +out = *buf;
 +
 +*out++ = '';
 +in = str;
 +while (*in) {
 + if (*in == '')
 + *out++ = '';
 + *out++ = *in++;
 +}
 +*out++ = '';
 +*out = 0;

Just a triviality: isn't '\0' preferred?

Best wishes

Mark

 +
 +return 0;
 +}
 diff --git a/util/string-util.h b/util/string-util.h
 index ac7676c..b593bc7 100644
 --- a/util/string-util.h
 +++ b/util/string-util.h
 @@ -19,4 +19,12 @@
  
  char *strtok_len (char *s, const char *delim, size_t *len);
  
 +/* Copy str to dest, surrounding with double quotes.
 + * Any internal double-quotes are doubled, i.e. ab - ab
 + *
 + * Output is into buf; it may be talloc_realloced
 + * return 

Re: [Patch v7 04/14] notmuch-tag: factor out double quoting routine

2012-12-15 Thread Jani Nikula
On Fri, 14 Dec 2012, da...@tethera.net wrote:
 From: David Bremner brem...@debian.org

 This could live in tag-util as well, but it is really nothing specific
 to tags (although the conventions are arguable specific to Xapian).

 The API is changed from caller-allocates to readline-like. The scan for
 max tag length is pushed down into the double quoting routine.
 ---
  notmuch-tag.c  |   50 --
  util/string-util.c |   34 ++
  util/string-util.h |8 
  3 files changed, 58 insertions(+), 34 deletions(-)

 diff --git a/notmuch-tag.c b/notmuch-tag.c
 index 0965ee7..13f2268 100644
 --- a/notmuch-tag.c
 +++ b/notmuch-tag.c
 @@ -20,6 +20,7 @@
  
  #include notmuch-client.h
  #include tag-util.h
 +#include string-util.h
  
  static volatile sig_atomic_t interrupted;
  
 @@ -37,25 +38,6 @@ handle_sigint (unused (int sig))
  }
  
  static char *
 -_escape_tag (char *buf, const char *tag)
 -{
 -const char *in = tag;
 -char *out = buf;
 -
 -/* Boolean terms surrounded by double quotes can contain any
 - * character.  Double quotes are quoted by doubling them. */
 -*out++ = '';
 -while (*in) {
 - if (*in == '')
 - *out++ = '';
 - *out++ = *in++;
 -}
 -*out++ = '';
 -*out = 0;
 -return buf;
 -}
 -
 -static char *
  _optimize_tag_query (void *ctx, const char *orig_query_string,
const tag_op_list_t *list)
  {
 @@ -67,44 +49,44 @@ _optimize_tag_query (void *ctx, const char 
 *orig_query_string,
   * parenthesize and the exclusion part of the query must not use
   * the '-' operator (though the NOT operator is fine). */
  
 -char *escaped, *query_string;
 +char *escaped = NULL;
 +size_t escaped_len = 0;
 +char *query_string;
  const char *join = ;
  size_t i;
 -unsigned int max_tag_len = 0;
  
  /* Don't optimize if there are no tag changes. */
  if (tag_op_list_size (list) == 0)
   return talloc_strdup (ctx, orig_query_string);
  
 -/* Allocate a buffer for escaping tags.  This is large enough to
 - * hold a fully escaped tag with every character doubled plus
 - * enclosing quotes and a NUL. */
 -for (i = 0; i  tag_op_list_size (list); i++)
 - if (strlen (tag_op_list_tag (list, i))  max_tag_len)
 - max_tag_len = strlen (tag_op_list_tag (list, i));
 -
 -escaped = talloc_array (ctx, char, max_tag_len * 2 + 3);
 -if (! escaped)
 - return NULL;
 -
  /* Build the new query string */
  if (strcmp (orig_query_string, *) == 0)
   query_string = talloc_strdup (ctx, ();
  else
   query_string = talloc_asprintf (ctx, ( %s ) and (, orig_query_string);
  
 +
 +/* Boolean terms surrounded by double quotes can contain any
 + * character.  Double quotes are quoted by doubling them. */
 +
  for (i = 0; i  tag_op_list_size (list)  query_string; i++) {
 + double_quote_str (ctx,
 +   tag_op_list_tag (list, i),
 +   escaped, escaped_len);

Check return value?

 +
   query_string = talloc_asprintf_append_buffer (
   query_string, %s%stag:%s, join,
   tag_op_list_isremove (list, i) ?  : not ,
 - _escape_tag (escaped, tag_op_list_tag (list, i)));
 + escaped);
   join =  or ;
  }
  
  if (query_string)
   query_string = talloc_strdup_append_buffer (query_string, ));
  
 -talloc_free (escaped);
 +if (escaped)
 + talloc_free (escaped);
 +
  return query_string;
  }
  
 diff --git a/util/string-util.c b/util/string-util.c
 index 44f8cd3..ea7c25b 100644
 --- a/util/string-util.c
 +++ b/util/string-util.c
 @@ -20,6 +20,7 @@
  
  
  #include string-util.h
 +#include talloc.h
  
  char *
  strtok_len (char *s, const char *delim, size_t *len)
 @@ -32,3 +33,36 @@ strtok_len (char *s, const char *delim, size_t *len)
  
  return *len ? s : NULL;
  }
 +
 +
 +int
 +double_quote_str (void *ctx, const char *str,
 +   char **buf, size_t *len)
 +{
 +const char *in;
 +char *out;
 +size_t needed = 3;
 +
 +for (in = str; *in; in++)
 + needed += (*in == '') ? 2 : 1;
 +
 +if (needed  *len)
 + *buf = talloc_realloc (ctx, *buf, char, 2*needed);

You fail to set *len to 2*needed, leading to doing realloc every time.

Also, I think you should follow the getline pattern like you did in
hex_encode: if *buf == NULL, the input value of *len is ignored.

BR,
Jani.

 +
 +if (! *buf)
 + return 1;
 +
 +out = *buf;
 +
 +*out++ = '';
 +in = str;
 +while (*in) {
 + if (*in == '')
 + *out++ = '';
 + *out++ = *in++;
 +}
 +*out++ = '';
 +*out = 0;
 +
 +return 0;
 +}
 diff --git a/util/string-util.h b/util/string-util.h
 index ac7676c..b593bc7 100644
 --- a/util/string-util.h
 +++ b/util/string-util.h
 @@ -19,4 +19,12 @@
  
  char *strtok_len (char *s, const char *delim, size_t *len);
  
 +/* 

[Patch v7 04/14] notmuch-tag: factor out double quoting routine

2012-12-14 Thread da...@tethera.net
From: David Bremner 

This could live in tag-util as well, but it is really nothing specific
to tags (although the conventions are arguable specific to Xapian).

The API is changed from "caller-allocates" to "readline-like". The scan for
max tag length is pushed down into the double quoting routine.
---
 notmuch-tag.c  |   50 --
 util/string-util.c |   34 ++
 util/string-util.h |8 
 3 files changed, 58 insertions(+), 34 deletions(-)

diff --git a/notmuch-tag.c b/notmuch-tag.c
index 0965ee7..13f2268 100644
--- a/notmuch-tag.c
+++ b/notmuch-tag.c
@@ -20,6 +20,7 @@

 #include "notmuch-client.h"
 #include "tag-util.h"
+#include "string-util.h"

 static volatile sig_atomic_t interrupted;

@@ -37,25 +38,6 @@ handle_sigint (unused (int sig))
 }

 static char *
-_escape_tag (char *buf, const char *tag)
-{
-const char *in = tag;
-char *out = buf;
-
-/* Boolean terms surrounded by double quotes can contain any
- * character.  Double quotes are quoted by doubling them. */
-*out++ = '"';
-while (*in) {
-   if (*in == '"')
-   *out++ = '"';
-   *out++ = *in++;
-}
-*out++ = '"';
-*out = 0;
-return buf;
-}
-
-static char *
 _optimize_tag_query (void *ctx, const char *orig_query_string,
 const tag_op_list_t *list)
 {
@@ -67,44 +49,44 @@ _optimize_tag_query (void *ctx, const char 
*orig_query_string,
  * parenthesize and the exclusion part of the query must not use
  * the '-' operator (though the NOT operator is fine). */

-char *escaped, *query_string;
+char *escaped = NULL;
+size_t escaped_len = 0;
+char *query_string;
 const char *join = "";
 size_t i;
-unsigned int max_tag_len = 0;

 /* Don't optimize if there are no tag changes. */
 if (tag_op_list_size (list) == 0)
return talloc_strdup (ctx, orig_query_string);

-/* Allocate a buffer for escaping tags.  This is large enough to
- * hold a fully escaped tag with every character doubled plus
- * enclosing quotes and a NUL. */
-for (i = 0; i < tag_op_list_size (list); i++)
-   if (strlen (tag_op_list_tag (list, i)) > max_tag_len)
-   max_tag_len = strlen (tag_op_list_tag (list, i));
-
-escaped = talloc_array (ctx, char, max_tag_len * 2 + 3);
-if (! escaped)
-   return NULL;
-
 /* Build the new query string */
 if (strcmp (orig_query_string, "*") == 0)
query_string = talloc_strdup (ctx, "(");
 else
query_string = talloc_asprintf (ctx, "( %s ) and (", orig_query_string);

+
+/* Boolean terms surrounded by double quotes can contain any
+ * character.  Double quotes are quoted by doubling them. */
+
 for (i = 0; i < tag_op_list_size (list) && query_string; i++) {
+   double_quote_str (ctx,
+ tag_op_list_tag (list, i),
+ , _len);
+
query_string = talloc_asprintf_append_buffer (
query_string, "%s%stag:%s", join,
tag_op_list_isremove (list, i) ? "" : "not ",
-   _escape_tag (escaped, tag_op_list_tag (list, i)));
+   escaped);
join = " or ";
 }

 if (query_string)
query_string = talloc_strdup_append_buffer (query_string, ")");

-talloc_free (escaped);
+if (escaped)
+   talloc_free (escaped);
+
 return query_string;
 }

diff --git a/util/string-util.c b/util/string-util.c
index 44f8cd3..ea7c25b 100644
--- a/util/string-util.c
+++ b/util/string-util.c
@@ -20,6 +20,7 @@


 #include "string-util.h"
+#include "talloc.h"

 char *
 strtok_len (char *s, const char *delim, size_t *len)
@@ -32,3 +33,36 @@ strtok_len (char *s, const char *delim, size_t *len)

 return *len ? s : NULL;
 }
+
+
+int
+double_quote_str (void *ctx, const char *str,
+ char **buf, size_t *len)
+{
+const char *in;
+char *out;
+size_t needed = 3;
+
+for (in = str; *in; in++)
+   needed += (*in == '"') ? 2 : 1;
+
+if (needed > *len)
+   *buf = talloc_realloc (ctx, *buf, char, 2*needed);
+
+if (! *buf)
+   return 1;
+
+out = *buf;
+
+*out++ = '"';
+in = str;
+while (*in) {
+   if (*in == '"')
+   *out++ = '"';
+   *out++ = *in++;
+}
+*out++ = '"';
+*out = 0;
+
+return 0;
+}
diff --git a/util/string-util.h b/util/string-util.h
index ac7676c..b593bc7 100644
--- a/util/string-util.h
+++ b/util/string-util.h
@@ -19,4 +19,12 @@

 char *strtok_len (char *s, const char *delim, size_t *len);

+/* Copy str to dest, surrounding with double quotes.
+ * Any internal double-quotes are doubled, i.e. a"b -> "a""b"
+ *
+ * Output is into buf; it may be talloc_realloced
+ * return 0 on success, non-zero on failure.
+ */
+int double_quote_str (void *talloc_ctx, const char *str,
+ char **buf, size_t *len);
 #endif
-- 
1.7.10.4



[Patch v7 04/14] notmuch-tag: factor out double quoting routine

2012-12-14 Thread david
From: David Bremner brem...@debian.org

This could live in tag-util as well, but it is really nothing specific
to tags (although the conventions are arguable specific to Xapian).

The API is changed from caller-allocates to readline-like. The scan for
max tag length is pushed down into the double quoting routine.
---
 notmuch-tag.c  |   50 --
 util/string-util.c |   34 ++
 util/string-util.h |8 
 3 files changed, 58 insertions(+), 34 deletions(-)

diff --git a/notmuch-tag.c b/notmuch-tag.c
index 0965ee7..13f2268 100644
--- a/notmuch-tag.c
+++ b/notmuch-tag.c
@@ -20,6 +20,7 @@
 
 #include notmuch-client.h
 #include tag-util.h
+#include string-util.h
 
 static volatile sig_atomic_t interrupted;
 
@@ -37,25 +38,6 @@ handle_sigint (unused (int sig))
 }
 
 static char *
-_escape_tag (char *buf, const char *tag)
-{
-const char *in = tag;
-char *out = buf;
-
-/* Boolean terms surrounded by double quotes can contain any
- * character.  Double quotes are quoted by doubling them. */
-*out++ = '';
-while (*in) {
-   if (*in == '')
-   *out++ = '';
-   *out++ = *in++;
-}
-*out++ = '';
-*out = 0;
-return buf;
-}
-
-static char *
 _optimize_tag_query (void *ctx, const char *orig_query_string,
 const tag_op_list_t *list)
 {
@@ -67,44 +49,44 @@ _optimize_tag_query (void *ctx, const char 
*orig_query_string,
  * parenthesize and the exclusion part of the query must not use
  * the '-' operator (though the NOT operator is fine). */
 
-char *escaped, *query_string;
+char *escaped = NULL;
+size_t escaped_len = 0;
+char *query_string;
 const char *join = ;
 size_t i;
-unsigned int max_tag_len = 0;
 
 /* Don't optimize if there are no tag changes. */
 if (tag_op_list_size (list) == 0)
return talloc_strdup (ctx, orig_query_string);
 
-/* Allocate a buffer for escaping tags.  This is large enough to
- * hold a fully escaped tag with every character doubled plus
- * enclosing quotes and a NUL. */
-for (i = 0; i  tag_op_list_size (list); i++)
-   if (strlen (tag_op_list_tag (list, i))  max_tag_len)
-   max_tag_len = strlen (tag_op_list_tag (list, i));
-
-escaped = talloc_array (ctx, char, max_tag_len * 2 + 3);
-if (! escaped)
-   return NULL;
-
 /* Build the new query string */
 if (strcmp (orig_query_string, *) == 0)
query_string = talloc_strdup (ctx, ();
 else
query_string = talloc_asprintf (ctx, ( %s ) and (, orig_query_string);
 
+
+/* Boolean terms surrounded by double quotes can contain any
+ * character.  Double quotes are quoted by doubling them. */
+
 for (i = 0; i  tag_op_list_size (list)  query_string; i++) {
+   double_quote_str (ctx,
+ tag_op_list_tag (list, i),
+ escaped, escaped_len);
+
query_string = talloc_asprintf_append_buffer (
query_string, %s%stag:%s, join,
tag_op_list_isremove (list, i) ?  : not ,
-   _escape_tag (escaped, tag_op_list_tag (list, i)));
+   escaped);
join =  or ;
 }
 
 if (query_string)
query_string = talloc_strdup_append_buffer (query_string, ));
 
-talloc_free (escaped);
+if (escaped)
+   talloc_free (escaped);
+
 return query_string;
 }
 
diff --git a/util/string-util.c b/util/string-util.c
index 44f8cd3..ea7c25b 100644
--- a/util/string-util.c
+++ b/util/string-util.c
@@ -20,6 +20,7 @@
 
 
 #include string-util.h
+#include talloc.h
 
 char *
 strtok_len (char *s, const char *delim, size_t *len)
@@ -32,3 +33,36 @@ strtok_len (char *s, const char *delim, size_t *len)
 
 return *len ? s : NULL;
 }
+
+
+int
+double_quote_str (void *ctx, const char *str,
+ char **buf, size_t *len)
+{
+const char *in;
+char *out;
+size_t needed = 3;
+
+for (in = str; *in; in++)
+   needed += (*in == '') ? 2 : 1;
+
+if (needed  *len)
+   *buf = talloc_realloc (ctx, *buf, char, 2*needed);
+
+if (! *buf)
+   return 1;
+
+out = *buf;
+
+*out++ = '';
+in = str;
+while (*in) {
+   if (*in == '')
+   *out++ = '';
+   *out++ = *in++;
+}
+*out++ = '';
+*out = 0;
+
+return 0;
+}
diff --git a/util/string-util.h b/util/string-util.h
index ac7676c..b593bc7 100644
--- a/util/string-util.h
+++ b/util/string-util.h
@@ -19,4 +19,12 @@
 
 char *strtok_len (char *s, const char *delim, size_t *len);
 
+/* Copy str to dest, surrounding with double quotes.
+ * Any internal double-quotes are doubled, i.e. ab - ab
+ *
+ * Output is into buf; it may be talloc_realloced
+ * return 0 on success, non-zero on failure.
+ */
+int double_quote_str (void *talloc_ctx, const char *str,
+ char **buf, size_t *len);
 #endif
-- 
1.7.10.4

___
notmuch