diff --git a/kv_quote.c b/kv_quote.c
index b78c847..a25a091 100644
--- a/kv_quote.c
+++ b/kv_quote.c
@@ -8,6 +8,7 @@
#include <stdlib.h>
#include <string.h>
#include "kv.h"
+#include "rope.h"
const char *g_delims[] = {
"END",
@@ -85,43 +86,54 @@ int kv_needs_quoting (const char *str, size_t str_size)
int kv_quote (char **str, size_t *str_size)
{
const char **delim;
- int delim_r;
- char *delim_str;
- size_t delim_str_size;
- int double_r;
- char *double_str;
- size_t double_str_size;
- int triple_r;
- char *triple_str;
- size_t triple_str_size;
+ int r;
+ s_rope *rope = NULL;
+ char *q;
+ size_t q_size;
assert(str);
assert(*str);
assert(str_size);
if (!kv_needs_quoting(*str, *str_size))
return 0;
- double_str = *str;
- double_str_size = *str_size;
- double_r = kv_quote_double_quotes(&double_str, &double_str_size);
- if (double_r <= 0)
- return double_r;
- triple_str = *str;
- triple_str_size = *str_size;
- triple_r = kv_quote_triple_double_quotes(&triple_str, &triple_str_size);
- if (triple_r <= 0)
- return triple_r;
- delim_str = *str;
- delim_str_size = *str_size;
+ q = *str;
+ q_size = *str_size;
+ r = kv_quote_double_quotes(&q, &q_size);
+ if (r < 0)
+ return r;
+ if (r == 0 && rope_push(&rope, q, q_size))
+ return -3;
+ q = *str;
+ q_size = *str_size;
+ r = kv_quote_triple_double_quotes(&q, &q_size);
+ if (r < 0)
+ return r;
+ if (r == 0 && rope_push(&rope, q, q_size)) {
+ rope_delete_all_free(rope);
+ return -3;
+ }
+ q = *str;
+ q_size = *str_size;
delim = &g_delims[0];
- delim_r = kv_quote_delim(&delim_str, &delim_str_size, *delim);
+ r = kv_quote_delim(&q, &q_size, *delim);
delim++;
- while (*delim && delim_r > 0) {
- delim_r = kv_quote_delim(&delim_str, &delim_str_size, *delim);
+ while (*delim && r > 0) {
+ r = kv_quote_delim(&q, &q_size, *delim);
delim++;
}
- if (delim_r <= 0)
- return delim_r;
-
- return -1;
+ if (r < 0)
+ return r;
+ if (r == 0 && rope_push(&rope, q, q_size)) {
+ rope_delete_all_free(rope);
+ return -3;
+ }
+ if (!rope)
+ return 1;
+ rope_sort_by_size(rope);
+ *str = rope->str;
+ *str_size = rope->size;
+ rope = rope->next;
+ rope_delete_all_free(rope);
+ return 0;
}
size_t kv_count_reserved_chars (const char *str, size_t str_size)
diff --git a/rope.c b/rope.c
index 2f715a1..9f519de 100644
--- a/rope.c
+++ b/rope.c
@@ -39,3 +39,75 @@ void rope_delete_all (s_rope *r)
rope_delete(t);
}
}
+
+void rope_delete_all_free (s_rope *r)
+{
+ while (r) {
+ s_rope *t = r;
+ r = r->next;
+ free(t->str);
+ t->str = NULL;
+ t->size = 0;
+ rope_delete(t);
+ }
+}
+
+int rope_push (s_rope **r, char *str, size_t size)
+{
+ s_rope *n;
+ assert(r);
+ n = rope_new(str, size, *r);
+ if (n) {
+ *r = n;
+ return 0;
+ }
+ return -1;
+}
+
+size_t rope_length (const s_rope *r)
+{
+ size_t l = 0;
+ while (r) {
+ l++;
+ r = r->next;
+ }
+ return l;
+}
+
+void rope_swap (s_rope *a, s_rope *b)
+{
+ char *str;
+ size_t size;
+ assert(a);
+ assert(b);
+ str = a->str;
+ size = a->size;
+ a->str = b->str;
+ a->size = b->size;
+ b->str = str;
+ b->size = size;
+}
+
+void rope_sort_by_size (s_rope *r)
+{
+ s_rope *i;
+ size_t n;
+ assert(r);
+ n = rope_length(r);
+ while (n > 1) {
+ size_t k = n;
+ int swap = 0;
+ i = r;
+ while (k > 1) {
+ if (i->size > i->next->size) {
+ swap = 1;
+ rope_swap(i, i->next);
+ }
+ k--;
+ i = i->next;
+ }
+ if (!swap)
+ break;
+ n--;
+ }
+}
diff --git a/rope.h b/rope.h
index 41faafc..7c04be9 100644
--- a/rope.h
+++ b/rope.h
@@ -19,5 +19,8 @@ void rope_init (s_rope *r, char *str, size_t size, s_rope *next);
s_rope * rope_new (char *str, size_t size, s_rope *next);
void rope_delete (s_rope *r);
void rope_delete_all (s_rope *r);
+void rope_delete_all_free (s_rope *r);
+int rope_push (s_rope **r, char *str, size_t size);
+void rope_sort_by_size (s_rope *r);
#endif