/*
** Splint - annotation-assisted static program checker
** Copyright (C) 1994-2003 University of Virginia,
**         Massachusetts Institute of Technology
**
** This program is free software; you can redistribute it and/or modify it
** under the terms of the GNU General Public License as published by the
** Free Software Foundation; either version 2 of the License, or (at your
** option) any later version.
** 
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** The GNU General Public License is available from http://www.gnu.org/ or
** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
** MA 02111-1307, USA.
**
** For information on splint: info@splint.org
** To report a bug: splint-bug@splint.org
** For more information: http://www.splint.org
*/
/*
** reader.c
*/

# include "splintMacros.nf"
# include "basic.h"

int reader_getInt (char **s)
{
  bool gotOne = FALSE;
  int i = 0;

  while (**s == ' ')
    {
      (*s)++;
    }

  if (**s == '-')
    {
      (*s)++;
      if (**s < '0' || **s > '9')
	{
	  llbug (message ("getInt: bad int: %s", cstring_fromChars (*s))); 
	}
      else
	{
	  i = -1 * (int) (**s - '0');
	  gotOne = TRUE;
	}

      (*s)++;
    }

  while (**s >= '0' && **s <= '9')
    {
      i *= 10;
      i += (int) (**s - '0');
      (*s)++;
      gotOne = TRUE;
    }

  if (!gotOne)
    {
      llbug (message ("No int to read: %s", cstring_fromChars (*s)));
    }

  while (**s == '\n' || **s == ' ' || **s == '\t')
    {
      (*s)++;
    }

  return i;
}

char
reader_loadChar (char **s)
{
  char ret;

  while (**s == ' ')
    {
      (*s)++;
    }
  
  ret = **s;
  (*s)++;
  return ret;
}

/*
** not sure if this works...
*/

double
reader_getDouble (char **s)
{
  char *end = mstring_createEmpty ();
  double ret;

  ret = strtod (*s, &end);

  *s = end;
  return ret;
}

/*
** read to ' ', '\t'. '\n', '#', ',' or '\0'
*/

char *
reader_getWord (char **s)
{
  char *res;
  char *t = *s;
  char c;

  while ((c = **s) != '\0' && (c != ' ') && (c != ',') 
	 && (c != '\n') && (c != '\t') && (c != '#'))
    {
      (*s)++;
    }

  if (*s == t)  
    {
      return NULL;
    }

  **s = '\0';
  res = mstring_copy (t);
  **s = c;
  return res;
}

/*
** read up to x
*/

cstring
reader_readUntil (char **s, char x)
{
  cstring res;
  char *t = *s;
  char c;

  while ((c = **s) != '\0' && (c != x))
    {
      (*s)++;
    }

  llassert (**s != '\0');
  llassert (*s != t);

  **s = '\0';
  res = cstring_fromChars (mstring_copy (t));
  **s = c;
  return res;
}

cstring 
reader_readUntilOne (char **s, const char *x)
{
  cstring res;
  char *t = *s;
  char c;

  while ((c = **s) != '\0' && (!mstring_containsChar (x, c)))
    {
      (*s)++;
    }

  llassert (**s != '\0');
  llassert (*s != t);

  **s = '\0';
  res = cstring_fromChars (mstring_copy (t));
  **s = c;
  return res;
}

bool
reader_optCheckChar (char **s, char c)
{
  if (**s == c)
    {
      (*s)++;
      return TRUE;
    }
  else
    {
      return FALSE;
    }
}

void
reader_doCheckChar (char **s, char c, const char *file, int line)
{
  /*@unchecked@*/ static int nbadchars = 0;

  if (**s == c)
    {
      (*s)++;
    }
  else
    {
      nbadchars++;

      if (nbadchars > 5)
	{
	  llfatalbug (cstring_makeLiteral 
		      ("checkChar: Too many errors.  Check library is up to date."));
	}
      else
	{
	  llbug (message ("checkChar: %q: Bad char, expecting %h: %s",
			  fileloc_unparseRaw (cstring_fromChars (file), line),
			  c,
			  cstring_fromChars (*s)));
	}
    }
}

void reader_checkUngetc (int c, FILE *f)
{
  int res;

  llassert (c != EOF);
  res = ungetc (c, f);
  llassert (res == c);
}

char *reader_readLine (FILE *f, char *s, int max)
{
  char *res = fgets (s, MAX_DUMP_LINE_LENGTH, f);

  if (res != NULL) 
    {
      if (strlen (res) == size_fromInt (MAX_DUMP_LINE_LENGTH - 1))
	{
	  llfatalerrorLoc (message ("Maximum line length exceeded (%d): %s", max, 
				    cstring_fromChars (s)));
	}

      incLine ();
    }

  return res;
}
