#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <glib.h>

void die(const gchar* err)
{
  perror(err);
  exit(1);
}

GSList* parse_buffer(const gchar* ptr, gsize len)
{
  const gchar* p = ptr;
  gchar field[1024*10]; /* enough for everybody */
  gchar* b = field;
  const gchar* stop = ptr+len;
  int i;
  
  GSList* flist = 0;
  GSList* rlist = 0;

  while (p < stop)
  {
    if (*p == '"') /* got " in normal context */
    {
      b = field; /* start new field */
      p++;
      while (p < stop)
      {
        if (*p == '"' && ((p+1) < stop) && *(p+1) == '"')
        {
          *b = '"';
          p++;
        }
        else if (*p == '"')
        {
          p++;
          goto got_end_quote;
        }
        else
          *b = *p;
        b++; p++;
      }
      die("eof in quoted context");
     got_end_quote:
      *b = '\0';
    }
    else if (*p == ',' || *p == '\n')
    {
      *b = '\0';
      b = field;
      if (!g_utf8_validate(field, 0, 0))
      {
        fprintf(stderr, "invalid utf8 string: %s\n", field);
        exit(1);
      }
      for (i=0; i<strlen(field); i++)
        if (field[i] == '\v')
          field[i] = ' ';
      flist = g_slist_prepend(flist, g_strdup(field));
      if (*p == '\n') // last field
      {
        rlist = g_slist_prepend(rlist, g_slist_reverse(flist));
        flist = 0;
      }
      p++;
    }
    else
    {
      *b = *p;
      b++; p++;
    }
  }
  return g_slist_reverse(rlist);
}

GSList* parse_file(const gchar* path)
{
  gint fd = open(path, O_RDONLY);
  if (fd == -1)
    die("open");
  gsize s = lseek(fd, 0, SEEK_END);
  gchar* a = (gchar*)mmap(0, s, PROT_READ, MAP_PRIVATE, fd, 0);
  if (a == (gchar*)-1)
  {
    close(fd);
    die("mmap");
  }
  GSList* l = parse_buffer(a, s);
  munmap(a, s);
  close(fd);
  return l;
}

void csv_to_php(GSList* csv)
{
  GSList *rec, *field;
  gint rec_i=0;
  printf("a:%d:{", g_slist_length(csv));
  for (rec=csv; rec!=0; rec=rec->next)
  {
    printf("i:%d;a:%d:{", rec_i, g_slist_length(rec->data));
    gint fld_i=0;
    for (field=rec->data; field!=0; field=field->next)
    {
      printf("i:%d;s:%d:\"%s\";", fld_i, strlen((gchar*)field->data), (gchar*)field->data);
      fld_i++;
    }
    rec_i++;
    printf("}");
  }
  printf("}");
}

gint main(gint ac, gchar* av[])
{
  if (ac != 2)
    die("bad param");
  GSList* csv = parse_file(av[1]);
  csv_to_php(csv);
  return 0;
}

