Commit 78c072be1c95c33e7c414024fa1360c5073709ce

Thomas de Grivel 2022-01-03T17:17:35

wip unquote

diff --git a/Makefile b/Makefile
index 3f5e205..e192bce 100644
--- a/Makefile
+++ b/Makefile
@@ -9,6 +9,7 @@ LIBKV_SRC = \
 	kv_parse.c \
 	kv_path.c \
 	kv_quote.c \
+	kv_unquote.c \
 	rope.c
 
 LIBKV_O = ${LIBKV_SRC:.c=.o}
diff --git a/kv.c b/kv.c
index f836bd1..6f01fb3 100644
--- a/kv.c
+++ b/kv.c
@@ -66,28 +66,36 @@ int get (int argc, char **argv)
   return r;
 }
 
-int quote (int argc, char **argv)
+int buffer_read_files (s_buffer *b, int argc, char **argv)
 {
-  s_buffer in;
-  char    *q;
-  size_t   q_size;
-  int      r;
-  if (buffer_init(&in, NULL))
+  int r;
+  if (buffer_init(b, NULL))
     return -1;
   while (argc--) {
     if (!strcmp(*argv, "-")) {
-      if (buffer_fp(&in, stdin, "stdin"))
+      if (buffer_fp(b, stdin, "stdin"))
         err(1, "stdin");
     }
     else
-      if (buffer_open(&in, *argv))
+      if (buffer_open(b, *argv))
         err(1, "%s", *argv);
-    while (!(r = buffer_fill(&in)))
+    while (!(r = buffer_fill(b)))
       ;
     if (r != -1)
-      err(1, "%s", in.file_path);
+      err(1, "%s", b->file_path);
     argv++;
   }
+  return 0;
+}
+
+int quote (int argc, char **argv)
+{
+  s_buffer in;
+  char    *q;
+  size_t   q_size;
+  int      r;
+  if (buffer_read_files(&in, argc, argv))
+    return -1;
   q = in.chars;
   q_size = in.wpos;
   if (!(r = kv_quote(&q, &q_size)) &&
@@ -98,12 +106,32 @@ int quote (int argc, char **argv)
   return r;
 }
 
+int unquote (int argc, char **argv)
+{
+  s_buffer in;
+  char    *str;
+  size_t   str_size;
+  int      r;
+  if (buffer_read_files(&in, argc, argv))
+    return -1;
+  str = in.chars;
+  str_size = in.wpos;
+  if (!(r = kv_unquote(&str, &str_size)) &&
+      fwrite(str, str_size, 1, stdout) != 1)
+    err(1, "stdout");
+  fflush(stdout);
+  free(str);
+  return r;
+}
+
 int usage (const char *argv0)
 {
   printf("Usage: %s OP [FILE ...]\n"
          "OP can be one of :\n"
-         "  -q | --quote    Quote files.\n"
-         "  -g | --get      Get keys passed on stdin in files.\n",
+         "  -g | --get      Get keys from stdin and print values from "
+         "files.\n"
+         "  -q | --quote    Quote concatenated files.\n"
+         "  -u | --unquote  Unquote concatenated files.\n",
          argv0);
   return 1;
 }
@@ -117,15 +145,20 @@ int main (int argc, char **argv)
   argc--;
   argv++;
   if (argc) {
+    if (!strcmp(*argv, "-g") || !strcmp(*argv, "--get")) {
+      argc--;
+      argv++;
+      return get(argc, argv);
+    }
     if (!strcmp(*argv, "-q") || !strcmp(*argv, "--quote")) {
       argc--;
       argv++;
       return quote(argc, argv);
     }
-    if (!strcmp(*argv, "-g") || !strcmp(*argv, "--get")) {
+    if (!strcmp(*argv, "-u") || !strcmp(*argv, "--unquote")) {
       argc--;
       argv++;
-      return get(argc, argv);
+      return unquote(argc, argv);
     }
   }
   return usage(argv0);
diff --git a/kv.h b/kv.h
index ce11756..46203be 100644
--- a/kv.h
+++ b/kv.h
@@ -29,5 +29,9 @@ int kv_quote (char **str, size_t *str_size);
 int kv_quote_delim (char **str, size_t *str_size, const char *delim);
 int kv_quote_double_quotes (char **str, size_t *str_size);
 int kv_quote_triple_double_quotes (char **str, size_t *str_size);
+int kv_unquote (char **str, size_t *str_size);
+int kv_unquote_delim (char **str, size_t *str_size, const char *delim);
+int kv_unquote_double_quotes (char **str, size_t *str_size);
+int kv_unquote_triple_double_quotes (char **str, size_t *str_size);
 
 #endif
diff --git a/kv_quote.c b/kv_quote.c
index bb06419..09f99aa 100644
--- a/kv_quote.c
+++ b/kv_quote.c
@@ -98,7 +98,6 @@ int kv_quote (char **str, size_t *str_size)
   char        *q;
   size_t       q_size;
   assert(str);
-  assert(*str);
   assert(str_size);
   if (!kv_needs_quoting(*str, *str_size))
     return 0;
diff --git a/kv_unquote.c b/kv_unquote.c
new file mode 100644
index 0000000..0ca85c5
--- /dev/null
+++ b/kv_unquote.c
@@ -0,0 +1,96 @@
+/*
+ * kv - key value text file format
+ *
+ * Copyright 2022 Thomas de Grivel
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "kv.h"
+
+int kv_unquote (s_buffer *b)
+{
+  
+}
+
+int kv_quote_delim (char **str, size_t *str_size, const char *delim)
+{
+  char  *s;
+  size_t delim_len;
+  size_t len;
+  assert(str);
+  assert(str_size);
+  assert(delim);
+  if (kv_check_delimiter(delim)) {
+    fprintf(stderr, "bad delimiter: %s\n", delim);
+    return 1;
+  }
+  if (kv_contains_delimiter(*str, *str_size, delim))
+    return 1;
+  delim_len = strlen(delim);
+  len = *str_size + delim_len * 2 + 3;
+  s = calloc(len + 1, 1);
+  if (!s)
+    return -1;
+  s[0] = '<'; s[1] = '<';
+  memcpy(s + 2, delim, delim_len);
+  s[2 + delim_len] = '\n';
+  memcpy(s + delim_len + 3, *str, *str_size);
+  memcpy(s + *str_size + delim_len + 3, delim, delim_len);
+  *str = s;
+  *str_size = len;
+  return 0;
+}
+
+int kv_quote_double_quotes (char **str, size_t *str_size)
+{
+  size_t i = 0;
+  size_t o = 0;
+  size_t res;
+  char  *s;
+  assert(str);
+  assert(str_size);
+  res = kv_count_quotable_chars(*str, *str_size);
+  s = calloc(*str_size + res + 3, 1);
+  if (!s)
+    return -1;
+  s[o++] = '"';
+  while (i < *str_size) {
+    int c = (*str)[i++];
+    if (kv_is_quotable_char(c))
+      s[o++] = '\\';
+    switch (c) {
+    case 0:    s[o++] = '0'; break;
+    case '\n': s[o++] = 'n'; break;
+    case '\r': s[o++] = 'r'; break;
+    case '\t': s[o++] = 't'; break;
+    case '\v': s[o++] = 'v'; break;
+    default: s[o++] = c;
+    }
+  }
+  s[o++] = '"';
+  assert(o == *str_size + res + 2);
+  s[o] = 0;
+  *str = s;
+  *str_size = o;
+  return 0;
+}
+
+int kv_quote_triple_double_quotes (char **str, size_t *str_size)
+{
+  char *e;
+  char *s;
+  if (kv_contains_triple_double_quotes(*str, *str_size))
+    return 1;
+  s = calloc(*str_size + 8, 1);
+  if (!s)
+    return -1;
+  s[0] = '"'; s[1] = '"'; s[2] = '"'; s[3] = '\n';
+  memcpy(s + 4, *str, *str_size);
+  e = s + 4 + *str_size;
+  e[0] = '"'; e[1] = '"'; e[2] = '"'; e[3] = 0;
+  *str = s;
+  *str_size = *str_size + 7;
+  return 0;
+}
diff --git a/test/delim b/test/delim
new file mode 100644
index 0000000..9fcfe3b
--- /dev/null
+++ b/test/delim
@@ -0,0 +1,97 @@
+Hello world !
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+"""
+
+
+
+
+
+
+
+
+
+
+
+
+
+"""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+"""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hello world !!