kmx.io/kv/buffer.c

Branch

Thomas de Grivel f1843fc12 2022-01-03T14:06:48
quote
/*
 * kv - key value text file format
 *
 * Copyright 2022 Thomas de Grivel
*/

#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "buffer.h"

int buffer_init (s_buffer *b, void *state)
{
  assert(b);
  b->chars = calloc(BUFFER_SIZE, 1);
  if (!b->chars)
    return -1;
  b->col = 0;
  b->file_path = NULL;
  b->fp = NULL;
  b->line = 0;
  b->pos = 0;
  b->size = BUFFER_SIZE;
  b->state = state;
  b->wpos = 0;
  b->k = NULL;
  return 0;
}

s_buffer * buffer_new (void *state)
{
  s_buffer *b = calloc(1, sizeof(s_buffer));
  if (!b)
    return NULL;
  if (buffer_init(b, state))
    return NULL;
  return b;
}

int buffer_open (s_buffer *b, const char *file_path)
{
  FILE *fp;
  assert(b);
  assert(file_path);
  fp = fopen(file_path, "rb");
  if (!fp)
    return -1;
  if (b->fp)
    fclose(b->fp);
  b->fp = fp;
  b->file_path = file_path;
  return 0;
}

int buffer_close (s_buffer *b)
{
  assert(b);
  if (b->fp) {
    fclose(b->fp);
    b->fp = NULL;
    b->file_path = NULL;
  }
  return 0;
}

int buffer_fp (s_buffer *b, FILE *fp, const char *file_path)
{
  assert(b);
  if (b->fp)
    fclose(b->fp);
  b->fp = fp;
  b->file_path = file_path;
  return 0;
}

int buffer_resize (s_buffer *b, size_t new_size)
{
  void *ptr;
  assert(b);
  assert(new_size >= b->size);
  if (new_size == b->size)
    return 0;
  ptr = realloc(b->chars, new_size);
  if (!ptr)
    return -1;
  b->chars = ptr;
  b->size = new_size;
  return 0;
}

int buffer_fill (s_buffer *b)
{
  size_t r;
  assert(b);
  assert(b->fp);
  if (b->wpos == b->size &&
      buffer_resize(b, b->size + BUFFER_SIZE))
    return -1;
  assert(b->wpos < b->size);
  r = fread(b->chars + b->wpos, 1, b->size - b->wpos, b->fp);
  if (r < 0) {
    buffer_err(b, "%s", strerror(errno));
    return -2;
  }
  if (r == 0)
    return -1;
  b->wpos += r;
  return 0;
}

int buffer_peek (s_buffer *b)
{
  assert(b);
  if (b->pos == b->wpos) {
    int r = buffer_fill(b);
    if (r < 0)
      return r;
  }
  assert(b->pos < b->wpos);
  return b->chars[b->pos];
}

int buffer_peek_n (s_buffer *b, size_t n)
{
  assert(b);
  if (n == 0)
    return 0;
  while (b->pos + n >= b->wpos)
    if (buffer_fill(b))
      return -1;
  assert(b->pos + n < b->wpos);
  return 0;
}

int buffer_read (s_buffer *b)
{
  int c = buffer_peek(b);
  if (c >= 0)
    b->pos++;
  return c;
}

int buffer_read_n (s_buffer *b, size_t n)
{
  int r;
  assert(b);
  if (n == 0)
    return 0;
  r = buffer_peek_n(b, n);
  if (r < 0)
    return r;
  b->pos += n;
  return 0;
}

int buffer_flush (s_buffer *b)
{
  assert(b);
  if (b->pos == 0)
    return 0;
  memmove(b->chars, b->chars + b->pos, b->wpos - b->pos);
  b->pos = 0;
  b->wpos -= b->pos;
  return 0;
}

int buffer_destroy (s_buffer *b)
{
  if (!b)
    return 0;
  free(b->chars);
  b->chars = NULL;
  b->pos = 0;
  b->size = 0;
  b->state = NULL;
  b->wpos = 0;
  return 0;
}

int buffer_delete (s_buffer *b)
{
  if (buffer_destroy(b))
    return -1;
  free(b);
  return 0;
}

void buffer_err (s_buffer *b, const char *fmt, ...)
{
  va_list va;
  va_start(va, fmt);
  printf("%s:%lu:%lu ",
         b->file_path,
         b->line,
         b->col);
  vprintf(fmt, va);
}

int buffer_eat (s_buffer *b, const char *str)
{
  size_t len;
  int r;
  assert(b);
  assert(str);
  len = strlen(str);
  r = buffer_peek_n(b, len);
  if (r) {
    if (r == -1)
      buffer_err(b, "unexpected EOF, expected \"%s\"", str);
    return r;
  }
  if (strncmp(str, b->chars + b->pos, len))
    buffer_err(b, "unexpected token, expected \"%s\"", str);
  return buffer_read_n(b, len);
}
Download