/****************************************************************/
/*                                                              */
/*                FILE : PARSE.C                                */
/*                                                              */
/*        Updated :  8 - 6 - 87  R. de Vries                    */
/*                   2- 10 - 87  F. Groen                       */
/*                                                              */
/*      CONTENTS :                                              */
/*      getbool(), getchr(), gethex(), getint(), hexarg(),      */
/*      intarg(), stablk(), stlmatch(), prstab(), atox(),       */
/*      getstab(), boolarg(), chrarg(), stabarg(), getdouble(), */
/*      doublearg(), nxtarg(), skipover(), getstr(), strarg(),  */
/*      strchr(), getline()                                      */
/*                                                              */
/****************************************************************/

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "allegro.h"
#include "asm.h"
#include "parse.h"
#include "commnd.h"
#include "aimhelp.h"
#include "cmd_list.h"

//#define EOS '\0'           /* End Of String teken      */
#define BREAK ", \n"
#define ESC   0x27         /* Ascii waarde voor escape */

//extern char _argbreak;
extern int prompt_flag;
//extern char help_file[];
extern int max_col;
extern char command[ASM_COMMAND_LENGTH];




// long help_index[HEADSIZE];

/*--------------------------------------------------------------------*/
/* De functie verhoogt de pointer zolang hij ' ' (spatie) is          */

char* stpblk(char *p)
{
	for(; *p == ' '; p++);
	return (p);
}

/*--------------------------------------------------------------------*/

char* skipover(char *string, char *charset)
{
	char *s, *brk;
	s = string;
	while (*s != EOS)
	{
		brk = charset;
		while ( (*brk != EOS) && ( *s != *brk))
			brk++;
		if (*brk == EOS)
			return(s);
		s++;
	}
	return(s);
}

/*-----------------------------------------------------*/

int getbool(char *prompt, int deflt)
{
	char *p,s[128];

	while (TRUE)
	{
		asm_wprintf("%s [%c] >", prompt, deflt ? 'Y' : 'N');
		p = poll_loop(s,0);

		if ((p == NULL) || (*p == EOS)) return (deflt);

		p = skipover(s," \t");
		if (strchr ("yYtT", *p) != NULL) return TRUE;
		if (strchr ("nNfF", *p) != NULL) return FALSE;
	}
}

/*-----------------------------------------------------*/

int getchr(char *prompt, char *legals, int deflt)
{
	char *p, *w;
	char buffer[80];

	while ( TRUE)
	{
		asm_wprintf("%s [%c] >", prompt, legals[deflt]);
		p = poll_loop(buffer,0);

		if (( p == NULL) || (*p == EOS))
			return(deflt);
		w = strchr (legals, toupper(*p));
		if (w != NULL)
			return( (int) (w-legals));
	}
}

/*-----------------------------------------------------*/

double getdouble(char *prompt, double mn, double mx, double deflt)
{
	char *p,s[128];
	double   f;
	f=mn-1;

	while ( (f<mn) || (f>mx) )
	{
		asm_wprintf("%s [%g] >", prompt, deflt);
		p = poll_loop(s,0);

		if (p == NULL)  return(deflt);
		if (*p == EOS)   return(deflt);

		f = atof (p);
	}
	return(f);
}

/*-----------------------------------------------------*/

int atox(char *s)
{
	char *p;
	int i;
	p = skipover(s ," \t");
	sscanf( p ,"%o", &i);
	return(i);
}


/*-----------------------------------------------------*/

int gethex(char *prompt, int mn, int mx, int deflt)
{
	char *p,s[128];
	int   i;
	i=mn-1;

	while ( (i<mn) ||(i>mx) )
	{
		asm_wprintf("%s [%x] >", prompt, deflt);
		p = poll_loop(s,0);

		if (p == NULL) return (deflt);
		if (*p == EOS) return(deflt);

		i = atox (p);
	}
	return(i);
}

int
getint(char *prompt, int mn, int mx, int deflt)
{
	char *p,s[128];
	int   i;
	i=mn-1;

	while ( (i<mn) ||(i>mx) )
	{
		asm_wprintf("%s [%d] >", prompt, deflt);
		p = poll_loop(s,0);

		if (p == NULL) return (deflt);
		if (*p == EOS) return(deflt);

		i = atoi (p);
	}
	return(i);
}

/*
int
getstab(char *prompt, char **table, int deflt)
{
   char *p,s[128];
   wimp_eventstr *evnt;
   int   i;
   i= -1;

   while ( i < 0 )
   {
      asm_wprintf(prompt);
      p = poll_loop(s,0,evnt);
      if (_argbreak == ESC) longjmp(main_loop, 1);

      if (p == NULL) return (deflt);
      if (*p == EOS) return(deflt);

      i = stablk (p , table, 0);
      if ( i >= 0 ) return(i);
    }
    return(0);
}
*/

char * getstr(char *prompt, char *deflt, char *buffer)
{
	char * p;

	asm_wprintf("%s [%s] >", prompt, deflt);
	p = poll_loop(buffer,0);
	if (p == NULL ||*p == EOS) return(deflt);
	return(p);
}

/*---------------------------------------------------------*/
/* Deze functie bepaald het argument uit een string        */
/*                                                         */

char* nxtarg(char **s_add, char *brk)
{
	char *p, *s, *pbrk;
	p = s = stpblk(*s_add);
	/* skip over blanks  */

	if (brk == NULL)
		brk = BREAK;
	while (*s != EOS)
	{
		pbrk = brk;
		while (*pbrk != EOS)
			if ( *s == (*pbrk++))
			{
				/*   _argbreak = *s; */
				*s = EOS;
				*s_add = ++s;
				return(p);
			}
		s++;
	}
	*s_add = s;
	return(p);
}

/*---------------------------------------------------------*/

int boolarg(char **s_add, char *brk, char *prompt, int deflt)
{
	char *p;


	p = nxtarg(s_add,brk);

	if (!prompt_flag && (*p != '?'))
	{
		if (*p == EOS) return(deflt);

		if (strchr("yYtT", *p) != NULL) return TRUE;
		if (strchr("nNfF", *p) != NULL) return FALSE;
	}
	return getbool(prompt, deflt);
}

int
chrarg(char **s_add, char *brk, char *prompt, char *legals, int deflt)
{
	char *p, *w;


	p = nxtarg(s_add,brk);

	if (!prompt_flag && (*p != '?'))
	{
		if (*p == EOS) return(deflt);
		w = strchr (legals, toupper(*p));
		if ( w != NULL )
			return ( (int) (w-legals));
	}
	return getchr(prompt,legals,deflt);
}

double
doublearg(char **s_add, char *brk, char *prompt, double mn, double mx, double deflt)
{
	char *p;
	double f;


	p = nxtarg(s_add,brk);

	if (!prompt_flag && (*p != '?'))
	{
		if (*p == EOS) return(deflt);

		f = atof(p);
		if ((f>=mn) && (f <= mx)) return f;
	}
	return getdouble(prompt,mn,mx,deflt);
}

int
hexarg(char **s_add, char *brk, char *prompt, int mn, int mx, int deflt)
{
	char *p;
	int i;


	p = nxtarg(s_add,brk);

	if ( !prompt_flag && (*p != '?'))
	{
		if (*p == EOS) return(deflt);

		i = atox(p);
		if ((i>=mn) && (i<=mn)) return i;
	}
	return getint(prompt,mn,mx,deflt);
}

int
intarg(char **s_add, char *brk, char *prompt, int mn, int mx, int deflt)
{
	char *p;
	int i;


	p = nxtarg(s_add,brk);

	if ( !prompt_flag && (*p != '?'))
	{
		if (*p == EOS) return(deflt);

		i = atoi(p);
		if ((i>=mn) && (i<=mx)) return i;
	}
	return getint(prompt,mn,mx,deflt);
}

/*
int
stabarg(char **s_add, char *brk, char *prompt, char **table, int deflt)
{
   char *p;
   int i;

   if (_argbreak == ESC) longjmp(main_loop, 1);

   p = nxtarg(s_add,brk);
   if ( !prompt_flag && (*p != '?'))
   {
      if (*p == EOS) return(deflt);

      i = stablk( p, table, 0);
      if ( i > 0 )  return (i);
   }
   return getstab(prompt,table,deflt);
}
*/

char* strarg(char **s_add, char *brk, char *prompt, char *deflt, char *buffer)
{
	char *p;


	p = nxtarg(s_add,brk);

	if ( !prompt_flag && (*p != '?'))
		if (*p != EOS)
			return(p);
	return getstr(prompt,deflt,buffer);
}


/*------------------------------------------------------*/
/* Deze functie toont de lijst met de commando's uit    */
/* MainList. Ze worden neergezet met asm_wprintf in drie    */
/* kolommen.                                            */

void prstab(void)
{
	char *s;
	static char space[] = "                   ";
	int i, col, maxlen, maxcol, len;

	maxlen =max_col;
	maxcol = maxlen/19;

	col = 0;
	for (i=0; i<N_CMDS; i++)
	{
		s = Mainlist[i].Ename;
		len = (int)strlen(s);
		asm_wprintf(s);
		col ++;
		if (col >= maxcol)
		{
			//         wvdu('\n');
			col = 0;
		}
		else asm_wprintf(space + len);
	}
	asm_wprintf("\n");
}


/*-----------------------------------------------------*/


typedef struct {
	char *search_string;
	size_t length;
} __attribute__ ((packed)) search_key;


int keycmp(const void *key, const void *elem)
{
	return strncmp(((search_key*)key)->search_string,
	    ((CIENTRY*)elem)->Ename, ((search_key*)key)->length);
}

/*------------------------------------------------------*/
/* Deze functie zoekt het commando op in de Mainlist en */
/* geeft de index ervan terug, of een error-waarde als  */
/* hij niet is gevonden (-2)                            */

int stablk(char *string, int prompt_flag)
{
	CIENTRY *res;
	int index, retval=0;
	search_key key;

	key.search_string = string;
	key.length = strlen(string);

	/* binary search naar het commando */
	    res = bsearch((const void *)&key, (const void *)Mainlist, (size_t)N_CMDS,
	    (size_t)sizeof(CIENTRY), keycmp);

	/* Als het resultaat niet gelijk is aan NULL -> found */

	    if (res != NULL)
	{
		/* compute index in CIENTRY table */
		    index = (int)(res - Mainlist);

/* check if it is an exact match, if it is:
		return it's index */
		      if (strcmp(string, res->Ename) == 0) return index;

		          /* check for ambiguity no. 1 */
		          if (index > 0)
		              if (strncmp((res-1)->Ename, string, key.length) == 0)
		                  retval = -2;

		                  /* check for ambiguity no. 2 */
		                  if (index < N_CMDS-1)
		                      if (strncmp((res+1)->Ename, string, key.length) == 0)
		                          retval = -2;

		                          /* everything is ok  */
		                          if (retval != -2) return index;
		    }

		    /* Als het resultaat gelijk is aan NULL dan: */
		    else retval = -1;

			if (prompt_flag)
			  prstab();

			return retval;
		}


		/*-------------------------------------------------------*/

		char* getline(char *s, FILE *fp)      /* get line into s, return s */
		{
		   int c,i;
		   i = 0;
		/*   if ((j=wkey())== 27) {
		   longjmp(main_loop,1);
		} */
		   while ( (c=getc(fp)) != EOF && c != '\n')
		      s[i++] = c;
		   s[i] = '\0';
		   return(s);
		}


		/*********************************************************/

		/* getline2 : gets a command line and returns a pointer to it */
		/*
		char * getline2(char *s, FILE *fp)
		{
		   interact(s,fp,0,NULL,NULL,NULL);
		   return(s);
		} */
		
		
		
		
		
		
		/*-------------------------------------------------------*/
		
		int cmdcmp(const void *p1, const void *p2)
		{
		 return strcmp(((CIENTRY*) p1)->Ename, ((CIENTRY*) p2)->Ename);
		}
		
		/*-------------------------------------------------------*/
		
		int init_cmds(void)
		{
		 qsort((void *)Mainlist,(size_t) N_CMDS, (size_t)sizeof(CIENTRY), cmdcmp);
		
		 return(1);
		}
		
		/*------------------------------------------------------*/
		/* Deze functie start DE routine met het gevonden       */
		/* commando. De return-waarde = 0 als er geen errors    */
		/* plaats hebben gevonden                               */
		
		int cmd_exec(int index, char* args)
		{
		 int ret;
		
		   ret=Mainlist[index].Estruct(args);
		
		 return(ret);
		}
		
		
		/*-----------------------------------------------------*/
		
		int cmd_help(int index)
		{
		 return Mainlist[index].Help;
		}
		
		/*-----------------------------------------------------*/
		
		char* strsave(char *s)
		{
		char *new = (char *)malloc(strlen(s)+1);
		
		 if (!new) return NULL;
		 strcpy(new, s);
		 return new;
		} 
