#include <stddef.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>

#include "sysdep.h"
#include "memory.h"
#include "useful.h"
#include "opvalscan.h"

enum scan_state_en {
  SCAN_START,
  SCAN_OP,
  SCAN_VAL,
  SCAN_VAL_2,
  SCAN_QUOTED_VAL,
  SCAN_END
  };

/*--------------------------------------------------*/
NORET Alopvalscan2(input,operator,value,was_quoted)
     const char *input;
     char *operator;
     char *value;
     Bool *was_quoted;
{
  enum scan_state_en cur_state = SCAN_START;
  char ch;
  Bool Escaped;

  *was_quoted=Bool_FALSE;
  while (cur_state != SCAN_END) {
    Escaped=Bool_FALSE;
    ch = *input++;
    if (!ch) break;
    if (ch=='\\') {
      ch = *input++;
      Escaped=Bool_TRUE;
    }
    switch (cur_state) {
    case SCAN_START:
      if (isspace(ch))
	;			/* just keep scanning */
      else if (Escaped==Bool_FALSE) {
	if (ch == '"')
	  cur_state = SCAN_QUOTED_VAL;
	else if (ispunct(ch)) {
	  *operator++ = ch;
	  cur_state = SCAN_OP;
	} else {
	  *value++ = ch;
	  cur_state = SCAN_VAL;
	}
      }
      else {
	if (ispunct(ch)) {
	  *operator++ = ch;
	  cur_state = SCAN_OP;
	} else {
	  *value++ = ch;
	  cur_state = SCAN_VAL;
	}
      }
      break;
    case SCAN_OP:
      if (Escaped==Bool_FALSE) {
	if (ch == '"') {
	  cur_state = SCAN_QUOTED_VAL;
	} else if (ch == ' ')
	  cur_state = SCAN_VAL_2;
	else 
	  *operator++ = ch;
      }
      else
	  *operator++ = ch;
      break;
    case SCAN_VAL:
      if (!(Escaped==Bool_FALSE && ch=='"'))
	*value++ = ch;
      break;
    case SCAN_VAL_2:
      if (ch==' ') ;
      else if (ch=='"') 
	cur_state = SCAN_QUOTED_VAL;
      else {
	*value++ = ch;
	cur_state = SCAN_VAL;
      }
      break;
    case SCAN_QUOTED_VAL:
      *was_quoted=Bool_TRUE;
      if (Escaped==Bool_FALSE) {
	if (ch == '"')
	  cur_state = SCAN_END;
	else
	  *value++ = ch;
      }
      else 
	*value++ = ch;
      break;
    default:
      assert(0);
    }
  }
  *value = *operator = '\0';
  return;
}

/*--------------------------------------------------*/
NORET Alopvalscan(input,operator,value)
     const char *input;
     char *operator;
     char *value;
{
  enum scan_state_en cur_state = SCAN_START;
  char ch;
  Bool Escaped;

  while (cur_state != SCAN_END) {
    Escaped=Bool_FALSE;
    ch = *input++;
    if (!ch) break;
    if (ch=='\\') {
      ch = *input++;
      Escaped=Bool_TRUE;
    }
    switch (cur_state) {
    case SCAN_START:
      if (isspace(ch))
	;			/* just keep scanning */
      else if (Escaped==Bool_FALSE) {
	if (ch == '"')
	  cur_state = SCAN_QUOTED_VAL;
	else if (ispunct(ch)) {
	  *operator++ = ch;
	  cur_state = SCAN_OP;
	} else {
	  *value++ = ch;
	  cur_state = SCAN_VAL;
	}
      }
      else {
	if (ispunct(ch)) {
	  *operator++ = ch;
	  cur_state = SCAN_OP;
	} else {
	  *value++ = ch;
	  cur_state = SCAN_VAL;
	}
      }
      break;
    case SCAN_OP:
      if (Escaped==Bool_FALSE) {
	if (ch == '"') {
	  cur_state = SCAN_QUOTED_VAL;
	} else if (ch == ' ')
	  cur_state = SCAN_VAL_2;
	else 
	  *operator++ = ch;
      }
      else
	  *operator++ = ch;
      break;
    case SCAN_VAL:
      if (!(Escaped==Bool_FALSE && ch=='"'))
	*value++ = ch;
      break;
    case SCAN_VAL_2:
      if (ch==' ') ;
      else if (ch=='"') 
	cur_state = SCAN_QUOTED_VAL;
      else {
	*value++ = ch;
	cur_state = SCAN_VAL;
      }
      break;
    case SCAN_QUOTED_VAL:
      if (Escaped==Bool_FALSE) {
	if (ch == '"')
	  cur_state = SCAN_END;
	else
	  *value++ = ch;
      }
      else 
	*value++ = ch;
      break;
    default:
      assert(0);
    }
  }
  *value = *operator = '\0';
  return;
}

/*--------------------------------------------------*/
Bool Alopvalmake (buffer,buf_len,op,value)
char *buffer;
int buf_len;
const char *op, *value;
{
  char *buff, c;
  int i, size, opl, vl;

  if (op!=NULL)
    opl=strlen(op);
  else
    opl=0;
  vl=strlen(value);
  size=opl+vl+4;		/* 4 = 1 Space, 2 ", and 1 NUL */
  if (size>buf_len)
    return(Bool_FALSE);
  if (op!=NULL) {
    strcpy(buffer,op);
    buffer[opl]=' ';
    strcpy(buffer+opl+1,value);
    buffer[opl+vl+1]='\0';
  }
  else { /* op==NULL */
    if (ispunct(value[0])) {
      buff[0]='"';
      strcpy(buff+1,value);
      buffer[vl+1]='"';
      buffer[vl+2]='\0';
    }
    else {
      strcpy(buffer,value);
      buffer[vl+1]='\0';
    }
  }
  return(Bool_TRUE);
}
