//  Generalized simple lexical analizer.
//  It can be used for simple syntax parsers, like lyxrc,
//  texclass and others to come.   [asierra30/03/96]
//
//   (C) 1996 Lyx Team.

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "definitions.h"
#include "lyxlex.h"

LyXLexClass::LyXLexClass(keyword_item* tab, int num)
	: table(tab), no_items(num)
{
   file = NULL;
   status = 0;
   pushed = NULL;
}

void LyXLexClass::pushTable(keyword_item* tab, int num)
{
	pushed_table *tmppu = new pushed_table;
	tmppu->next = pushed;
	tmppu->table_elem = table;
	tmppu->table_siz = no_items;
	pushed = tmppu;
	table = tab;
	no_items = num;
}

void LyXLexClass::popTable()
{
	if (pushed == NULL)
		fprintf(stderr,"ERR: nothing to pop!\n");

	pushed_table *tmp;
	tmp = pushed;
	table = tmp->table_elem;
	no_items = tmp->table_siz;
	tmp->table_elem = NULL;
	pushed = tmp->next;
	delete tmp;
}

void LyXLexClass::printTable()
{
	fprintf(stderr,"\n Number of tags: %d\n",no_items);
	for(int i=0; i<no_items; i++)
		fprintf(stderr,"table[%d]:  tag: `%s'  code: %d\n", i, table[i].tag, table[i].code);
	fprintf(stderr,"\n");
			
}

void LyXLexClass::setFile(const char* filename)
{
   file = fopen(filename, "r");
   lineno = 0;   
}

int LyXLexClass::lex()
{
   if (next() && status==LEX_TOKEN)
       return search_kw(buff);
   else
       return status;
}

int LyXLexClass::GetInteger()
{
   if (buff[0]>' ')   
       return atoi(buff);
   else
     return -1;  //  Here an error should be reported
}

float LyXLexClass::GetFloat()
{
   if (buff[0]>' ')   
       return (float)strtod(buff, (char**)NULL);
   else
     return -1.;  //  Here an error should be reported
}

char *LyXLexClass::GetString(char *prev)
{
   if (prev)
     delete prev;
   if (buff[0]>' ') {
      char *s = new char[strlen(buff)+1];
      strcpy(s, buff);
      return s;
   } else
     return NULL;
}

bool LyXLexClass::GetBool()
{
   if (!strcmp(buff, "true"))
     return true;
   else
     return false;
}

bool LyXLexClass::EatLine()
{
   int i=-1;
   char c = '\0';
   
   while (!feof(file) && c!='\n') {
      c = getc(file);
      buff[++i] = c;
   }		
   if (c=='\n' && i>0) {
      lineno++;
      buff[i] = '\0';
      status = LEX_DATA;
      return true;
   } else
     return false;
}

int LyXLexClass::search_kw(char *tag)
{
	int m, k, l= 0, r=no_items;

	while (l < r) {
		m = (l+r)/2;
		
// 		if (lyx_debug_level & DEBUG_LEX_PARSER)
// 			fprintf(stdout,
// 				"LyXLexClass::search_kw: elem %d "
// 				" tag %s  search tag %s\n",
// 				m,table[m].tag,tag);

		k = strcasecmp(table[m].tag, tag);
		if (k==0)
			return table[m].code;
		else
			if (k<0) l = m+1; else r = m;
	}
	return -1;
}
 
bool LyXLexClass::next()
{
	//char c; 
	int c; // getc() returns an int
	int i;
        
        status = 0;
	while (!feof(file) && !status) { 
		c = getc(file);
		if (c=='#') 
		   do c = getc(file); while (c!='\n' && !feof(file));
	   
		if (c=='\"') {
		        i = -1;
		        do {
			        c = getc(file);
			        buff[++i] = c;
			} while (c!='\"' && c!='\n' && !feof(file));
		        if (c!='\"') {
			   fprintf(stderr,
				   "Line %d: Lex error: Missing quote!.\n",
				   GetLineNo());
			   if (c=='\n')
			     lineno++;
			}
		   		            
		        buff[i] = '\0';
		        status = LEX_DATA;
		        break; 
		}
	   
		if (c==',')
			continue;              /* Skip ','s */
	   
		if (c > ' ' && !feof(file))  {
			i = 0;
			do {
				buff[i++] = c;
				c = getc(file);
			} while (c > ' ' && c != ',' && !feof(file));
			buff[i] = '\0';
		        status = LEX_TOKEN;
		}
		  
		if (c=='\n')
			lineno++;
	
	}
        if (status)  return true;
        
        status = (feof(file)) ? LEX_FEOF: LEX_UNDEF;
        buff[0] = '\0';
        return false;
}


int LyXLexClass::FindToken(const char* string[])
{  
   int i = -1;
   
   if (next()) {
      if (strcmp(buff, "default")) {
	 for (i=0; string[i][0] && strcmp(string[i], buff); i++);
	 if (!string[i][0]) {
	    fprintf(stderr,
		    "Line %d: Lex Error: Unknown argument %s.\n",
		    GetLineNo(), buff); 
	    i = -1;
	 }
      }  
   } else
     fprintf(stderr,
	     "LyX Error: file ended while scanning string token\n");
   
   return i;
}

