/* definitions */
%x sComment
%x sID
%x sValue
%x sQStr
%option noyywrap

ID ([-[:alnum:]_]+)
SPACE ([[:space:]]{-}[\n])

%{
/* get rid of compiler warning */
#define YY_NO_INPUT 1

#include <string.h>
#include "cparse_def.h"
#include "cparse.h"

#define STR_BUF_INC 4096

static int node_deactivated = 0;
static char *str_buf = NULL;
static char *out_buf = NULL;
static char *str_ptr = NULL;
static size_t str_buf_len = 0;

static void
prepare_buffers(size_t add_len)
{
  size_t slen = str_ptr - str_buf;
  if (str_buf && (slen + add_len) < str_buf_len) {
    // nothing to do
    return;
  }

  str_buf_len += STR_BUF_INC;
  str_buf = realloc(str_buf, str_buf_len);
  out_buf = realloc(out_buf, str_buf_len);
  if (!str_buf || !out_buf) {
    printf("realloc failed\n");
    exit(1);
  }
  str_ptr = str_buf + slen;
}

static void
append_str(char *text)
{
  size_t tlen = strlen(text);
  prepare_buffers(tlen);
  strcpy(str_ptr, text);
  str_ptr += tlen;
}

static void
set_ret_str()
{
  prepare_buffers(0);
  *str_ptr = 0;
  strcpy(out_buf, str_buf);
  str_ptr = str_buf;
}

%}

%%

<INITIAL>"/*" {
  BEGIN(sComment);
}

<sComment>[^*\n]* {
  append_str(cparse_text);
}

<sComment>\*[^/] {
  append_str(cparse_text);
}

<sComment>\n {
  append_str(cparse_text);
  ++cparse_lineno;
}

<sComment>"*/" {
  char *tmp;
  size_t tlen;
  set_ret_str();

  /* need to strip out leading or trailing space */
  tmp = out_buf;
  tlen = strlen(tmp);
  if (tlen > 0 && tmp[tlen - 1] == ' ') {
    tmp[tlen - 1] = 0;
    --tlen;
  }
  if (tlen > 0 && tmp[0] == ' ') {
    ++tmp;
  }
  cparse_lval.str = strdup(tmp);
  BEGIN(INITIAL);
  return COMMENT;
}

<INITIAL>! {
  node_deactivated = 1;
}

<INITIAL>{SPACE}+ {
}

<INITIAL>\n {
  ++cparse_lineno;
}

<INITIAL>\} {
  node_deactivated = 0;
  return RIGHTB;
}

<INITIAL>{ID} {
  cparse_lval.str = strdup(cparse_text);
  cparse_lval.deactivated = node_deactivated;
  node_deactivated = 0;
  BEGIN(sID);
  return NODE;
}

<sID>:?{SPACE}+[^{\n] {
  unput(cparse_text[cparse_leng - 1]);
  BEGIN(sValue);
}

<sID>{SPACE}+ {
}

<sID>\{ {
  BEGIN(INITIAL);
  return LEFTB;
}

<sID>\n {
  ++cparse_lineno;
  BEGIN(INITIAL);
}

<sValue>{SPACE}+ {
  /* ignore spaces */
}

<sValue>\" {
  /* quoted string */
  BEGIN(sQStr);
}

<sQStr>[^\"\\\n]+ {
  append_str(cparse_text);
}

<sQStr>\\. {
  /* this will consume the \" sequence */
  append_str(cparse_text);
}

<sQStr>\n {
  append_str(cparse_text);
  ++cparse_lineno;
}

<sQStr>\" {
  set_ret_str();
  cparse_lval.str = strdup(out_buf);
  BEGIN(sValue);
  return VALUE;
}

<sValue>[^{"[:space:]][^{[:space:]]* {
  /* unquoted string */
  cparse_lval.str = strdup(cparse_text);
  return VALUE;
}

<sValue>\{ {
  BEGIN(INITIAL);
  return LEFTB;
}

<sValue>\n {
  ++cparse_lineno;
  BEGIN(INITIAL);
}

<*>. {
  return SYNTAX_ERROR;
}

%%

/* code */