kmx.io/kv/kv_quote.c

Branch

Thomas de Grivel d5556884c 2022-01-04T20:18:17
tests
/*
 * kv - key value text file format
 *
 * Copyright 2022 Thomas de Grivel
*/

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "kv.h"
#include "rope.h"

const char *g_delims[] = {
  "END",
  "---",
  "___",
  "===",
  "***",
  "+++",
  "!!!",
  "###",
  "-END-",
  "_END_",
  "=END=",
  "*END*",
  "+END+",
  "!END!",
  "#END#",
  NULL
};

int kv_check_delimiter (const char *delim)
{
  assert(delim);
  return kv_contains_reserved_char(delim, strlen(delim));
}

int kv_contains_delimiter (const char *str, size_t str_size,
                           const char *delim)
{
  size_t delim_len;
  assert(str);
  assert(delim);
  delim_len = strlen(delim);
  while (str_size >= delim_len) {
    if (!strcmp(str, delim))
      return 1;
    str++;
    str_size--;
  }
  return 0;
}

int kv_contains_reserved_char (const char *str, size_t str_size)
{
  while (str_size) {
    if (kv_is_reserved_char(str[0]))
      return 1;
    str++;
    str_size--;
  }
  return 0;
}

int kv_contains_triple_double_quotes (const char *str, size_t str_size)
{
  while (str_size >= 3) {
    if (str[0] == '"' && str[1] == '"' && str[2] == '"')
      return 1;
    str++;
    str_size--;
  }
  return 0;
}

size_t kv_count_quotable_chars (const char *str, size_t str_size)
{
  size_t c = 0;
  while (str_size--)
    if (kv_is_quotable_char(*str++))
      c++;
  return c;
}

int kv_needs_quoting (const char *str, size_t str_size)
{
  if (str_size == 0 ||
      (str[0] != '<' && !kv_contains_reserved_char(str, str_size)))
    return 0;
  return 1;
}

int kv_quote (char **str, size_t *str_size)
{
  const char **delim;
  int          r;
  s_rope      *rope = NULL;
  char        *q;
  size_t       q_size;
  assert(str);
  assert(str_size);
  if (!kv_needs_quoting(*str, *str_size))
    return 0;
  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];
  r = 1;
  while (*delim && r > 0) {
    r = kv_quote_delim(&q, &q_size, *delim);
    delim++;
  }
  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);
  fflush(stderr);
  *str = rope->str;
  *str_size = rope->size;
  rope = rope->next;
  rope_delete_all_free(rope);
  return 0;
}

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;
}
Download