#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include "sys_util.h"
#include "err_handling.h"
#include "str_util.h"
#include "str_buf.h"

char *str_nget_str(Str_Buf *buf, char *result, int reslen)
{ char *b, *f, *e, quote;
  int res, l, ll;

  if (buf->rdpos < 0 || buf->rdpos >= buf->dsize) ERR_MSG("buffer corrupt");
  b=buf->buf + buf->rdpos;
  if (*b=='"' || *b=='\'') { /* take string within quotes (single or double) */
    quote=*b; b++;
    f=strchr(b, quote);
    if (f==NULL) ERR_MSG("missing '""'");
    l=f-b;
    e=strchr(f+1, buf->sep);
    if (e==NULL) {
      buf->rdpos = f - buf->buf + 1 + strlen(f+1);
    } else {
      buf->rdpos = e - buf->buf + 1;
    }
  } else {
    f=strchr(b, buf->sep);
    if (f==NULL) {
      l=strlen(b);
      f=b+l;
      buf->rdpos+=l;
    } else {
      l=f-b;
      buf->rdpos+=l+1;
    }
  }
  if (result==NULL) {
    *f='\0';
    return(b);
  } else {
    if (l>=reslen) ERR_MSG("result too short");
    strncpy(result, b, l);
    result[l]='\0';
    return(result);
  }
  OnError:
    buf->rdpos=-1;
    return(NULL);
}

int str_get_int(Str_Buf *buf, int *res)
{ char num[32];
  int i;

  ERR_P(str_get_str(buf, num));
  i=sscanf(num, "%d", res);
  if (i==0) ERR_MSG("illegal number");
  return(0);
  OnError:
    buf->rdpos=-1;
    return(0);
}

int str_get_float(Str_Buf *buf, float *res)
{ char num[32];
  int i;

  ERR_P(str_get_str(buf, num));
  i=sscanf(num, "%f", res);
  if (i==0) ERR_MSG("illegal number");
  return(0);
  OnError:
    buf->rdpos=-1;
    return(-1);
}

int str_get_end(Str_Buf *buf)
{
  if (buf->rdpos < 0 || buf->rdpos >= buf->dsize) ERR_MSG("buffer corrupt");
  if (buf->rdpos != buf->wrpos) ERR_MSG("superflous content in buffer");
  return(0);
  OnError:
    return(-1);
}

int str_put_str(Str_Buf *buf, const char *str)
{ int l, pos;
  char quote;

  pos=buf->wrpos;
  if (pos < 0 || pos >= buf->dsize) ERR_MSG("buffer corrupt");
  l=strlen(str);
  quote='\0';
  if (buf->sep>STR_NOSEPARATOR) {
    if (strchr(str, buf->sep)!=NULL) {
      if (strchr(str, '"')==NULL) {
        quote='"'; l+=2;
      } else if (strchr(str, '\'')==NULL) {
        quote='\''; l+=2;
      } else {
        ERR_MSG("str must not contain separator and both kind of quotes");
      }
    }
  }
  if (pos+l >= buf->dsize) ERR_MSG("buffer too short");
  if (quote!='\0') {
    buf->buf[pos]=quote; pos++;
    strcpy(buf->buf + pos, str);
    buf->buf[pos]=quote; pos++;
  } else {
    strcpy(buf->buf + pos, str);
  }
  pos+=l;
  if (buf->sep!=STR_NOSEPARATOR) {
    buf->buf[pos]=buf->sep;
    pos++;
  } else {
    buf->buf[pos]='\0';    
  }
  buf->wrpos=pos;
  return(0);
  OnError:
    buf->wrpos=-1;
    return(-1);
}

int str_put_int(Str_Buf *buf, int val)
{ char num[32];

  sprintf(num, "%d", val);
  ERR_I(str_put_str(buf, num));
  return(0);
  OnError:
    return(-1);
}

int str_put_float(Str_Buf *buf, float val)
{ char num[32];

  sprintf(num, "%f", val);
  ERR_I(str_put_str(buf, num));
  return(0);
  OnError:
    return(-1);
}

void str_get_start(Str_Buf *buf)
{ buf->rdpos=0;
}

void str_put_start(Str_Buf *buf)
{ buf->rdpos=0;
  buf->wrpos=0;
}

Str_Buf *str_create_buf(size_t size, char separator)
{ Str_Buf *buf;

  NEW(buf);
  ERR_P(buf->buf=MALLOC(size));
  buf->dsize=size;
  buf->sep=separator;
  buf->wrpos=0;
  buf->rdpos=0;
  return(buf);
  OnError:
    return(NULL);
}

void str_link_buf(Str_Buf *buf, char *str, int size, char separator) {
  buf->buf=str;
  buf->rdpos=0;
  if (size==0) {
    buf->wrpos=strlen(str);
    buf->dsize=buf->wrpos+1;
  } else {
    buf->wrpos=0;
    buf->dsize=size;
  }
  buf->sep=separator;
}

void str_free_buf(Str_Buf *buf)
{ FREE(buf->buf);
  FREE(buf);
}
