[FFmpeg-devel] [RFC][PATCH] avstring: Add new function av_for_each_pair
Alexander Strasser
eclipse7 at gmx.net
Sat Feb 25 22:43:51 CET 2012
This function takes a string and tokenizes it into pairs. The
caller will be called back for each pair.
Signed-off-by: Alexander Strasser <eclipse7 at gmx.net>
---
libavutil/avstring.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++
libavutil/avstring.h | 35 ++++++++++++
2 files changed, 178 insertions(+), 0 deletions(-)
diff --git a/libavutil/avstring.c b/libavutil/avstring.c
index 76f6bb2..c4ee2ed 100644
--- a/libavutil/avstring.c
+++ b/libavutil/avstring.c
@@ -25,6 +25,7 @@
#include <ctype.h>
#include "avstring.h"
#include "mem.h"
+#include "error.h"
int av_strstart(const char *str, const char *pfx, const char **ptr)
{
@@ -210,10 +211,114 @@ int av_strncasecmp(const char *a, const char *b, size_t n)
return c1 - c2;
}
+int av_for_each_pair(each_pair_fn cb, void *cb_data, const char * str,
+ char comp_delim, char pair_delim, char escape_char)
+{
+ size_t buf_size = 0, len = 0, buf_idx = 0, comp2_idx = 0;
+ char *buf = NULL;
+ int ret = 0, i = 0;
+
+ for (;;) {
+ const char *ptr;
+ char *tmp_ptr;
+ size_t off = 0;
+
+ while (str[off]
+ && str[off] != escape_char
+ && str[off] != comp_delim
+ && str[off] != pair_delim) {
+ ++off;
+ }
+ len += off + 1;
+
+ if (len >= buf_size) {
+ buf_size = len;
+
+ tmp_ptr = av_realloc(buf, buf_size);
+ if (!tmp_ptr) {
+ ret = AVERROR(ENOMEM);
+ break;
+ }
+ buf = tmp_ptr;
+ }
+
+ ptr = &str[off];
+
+ //av_log(NULL, 0, "\ni == %i, *ptr == 0x%x, off=%u, len == %u, str: %s\n", i, *ptr, (unsigned)off, (unsigned)len, str);
+
+ memcpy(&buf[buf_idx], str, off);
+ buf_idx += off;
+ if (*ptr == escape_char) {
+ if (ptr[1] == comp_delim ||
+ ptr[1] == pair_delim ||
+ ptr[1] == escape_char) {
+ buf[buf_idx++] = ptr[1];
+ str += off + 2; // advance over escape and escaped char
+
+ continue;
+ } else {
+ ret = AVERROR_INVALIDDATA;
+ break;
+ }
+ } else if (*ptr == comp_delim) {
+ if (i & 1) {
+ ret = AVERROR_INVALIDDATA;
+ break;
+ }
+
+ buf[buf_idx++] = 0;
+ comp2_idx = buf_idx;
+ } else if (*ptr == pair_delim) {
+ if (!(i & 1)) {
+ ret = AVERROR_INVALIDDATA;
+ break;
+ }
+
+ buf[buf_idx] = 0;
+ }
+
+ if (!ret && (i & 1)) {
+ if (!*ptr) // value part of the last pair has no delimiter
+ buf[buf_idx] = 0;
+ buf_idx = len = 0;
+
+ ret = cb(buf, &buf[comp2_idx], cb_data);
+ if (ret)
+ break;
+ }
+
+ ++i;
+
+ if (!*ptr)
+ break;
+
+ str = ptr + 1;
+ }
+
+ av_free(buf);
+
+ if (!ret && (i & 1)) // missing pair's second component
+ ret = AVERROR_INVALIDDATA;
+
+ return ret;
+}
+
+
#ifdef TEST
#undef printf
+static int print_pair(char *a, char *b, void *cb_data)
+{
+ printf(" -> |%s| + |%s|", a, b);
+
+ return 0;
+}
+static int return_averror(char *a, char *b, void *cb_data)
+{
+ return AVERROR_PATCHWELCOME;
+}
+
int main(void)
{
int i;
@@ -257,6 +362,44 @@ int main(void)
}
}
+ printf("Testing av_for_each_pair()\n");
+ {
+ int ret;
+ char err_str[128];
+ const char *strings[] = {
+ "",
+ ",",
+ "=",
+ "=\\",
+ "=\\\\",
+ "=,=",
+ "==",
+ "=,,",
+ "a=b",
+ "a=\\b",
+ "c=d,e=f",
+ "c=d,e=f,",
+ "\\==\\,",
+ "\\\\=1\\, 2\\, 3",
+ "1\\, 2\\, 3=\\\\",
+ "\\,=\\=",
+ };
+
+ for (i=0; i < FF_ARRAY_ELEMS(strings); i++) {
+ const char *p = strings[i];
+
+ printf("|%s|", p); fflush(stdout);
+ ret = av_for_each_pair(print_pair, NULL, p, '=', ',', '\\');
+ av_strerror(ret, err_str, sizeof(err_str));
+ printf(" (ret: %s)\n", err_str);
+ }
+
+ printf("|%s|", strings[4]); fflush(stdout);
+ ret = av_for_each_pair(return_averror, NULL, "k=v", '=', ',', '\\');
+ av_strerror(ret, err_str, sizeof(err_str));
+ printf(" (ret: %s)\n", err_str);
+ }
+
return 0;
}
diff --git a/libavutil/avstring.h b/libavutil/avstring.h
index f73d6e7..acb5c7a 100644
--- a/libavutil/avstring.h
+++ b/libavutil/avstring.h
@@ -202,6 +202,41 @@ int av_strcasecmp(const char *a, const char *b);
*/
int av_strncasecmp(const char *a, const char *b, size_t n);
+
+/**
+ * Will be called with a pair of strings a and b.
+ *
+ * Where a is the first component of the pair and b is the second.
+ *
+ * Each string can be modified at will, except you may never
+ * overwrite its zero terminator which denotes the end of the
+ * string. The strings are only guaranteed to exist for the time
+ * of the function call. Do never try to access them after the
+ * function returned.
+ *
+ * Any return code other than 0 (OK) will stop the calling function
+ * and that return code will be passed through.
+ *
+ */
+typedef int (*each_pair_fn)(char *a, char *b, void *cb_data);
+
+/**
+ * Split a string into pairs and loop through them.
+ *
+ * Calls the passed in function pointer cb for each tokenized pair.
+ * See the documentation of the callback function type for explanation
+ * of its function signature.
+ *
+ * @param cb callback function that gets executed for each pair in str
+ * @param cb_data pointer that will get passed to callback on each invocation
+ * @param str input string
+ * @param comp_delim ASCII character to separate the pairs components
+ * @param pair_delim ASCII character to delimit the pairs themselves
+ * @param escape_char ASCII character to escape comp_delim, pair_delim and itself
+ * @return 0 for success and <0 (AVERROR value) for failure
+ */
+int av_for_each_pair(each_pair_fn cb, void *cb_data, const char * str, char comp_delim, char delim, char escape_char);
+
/**
* @}
*/
--
1.7.5.4
More information about the ffmpeg-devel
mailing list