/*******************************************************************************
*
*       This file is part of the General Hidden Markov Model Library,
*       GHMM version __VERSION__, see http://ghmm.org
*
*       Filename: ghmm/ghmm/scanner.c
*       Authors:  Frank Nübel
*
*       Copyright (C) 1998-2004 Alexander Schliep
*       Copyright (C) 1998-2001 ZAIK/ZPR, Universitaet zu Koeln
*       Copyright (C) 2002-2004 Max-Planck-Institut fuer Molekulare Genetik,
*                               Berlin
*
*       Contact: schliep@ghmm.org
*
*       This library is free software; you can redistribute it and/or
*       modify it under the terms of the GNU Library General Public
*       License as published by the Free Software Foundation; either
*       version 2 of the License, or (at your option) any later version.
*
*       This library 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
*       Library General Public License for more details.
*
*       You should have received a copy of the GNU Library General Public
*       License along with this library; if not, write to the Free
*       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
*       This file is version $Revision: 1977 $
*                       from $Date: 2007-11-16 10:49:06 -0500 (Fri, 16 Nov 2007) $
*             last change by $Author: grunau $.
*
*******************************************************************************/

#ifdef HAVE_CONFIG_H
#  include "../config.h"
#endif

#include "ghmmconfig.h"

#ifdef GHMM_OBSOLETE

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

#include "mprintf.h"
#include "mes.h"
#include "scanner.h"
#include "ghmm_internals.h"

#define SCANNER_TYPE_CHAR     1
#define SCANNER_TYPE_INT      2
#define SCANNER_TYPE_DOUBLE   3
#define SCANNER_TYPE_EDOUBLE  4
#define SCANNER_TYPE_STRING   5
#define SCANNER_TYPE_CSTRING  6

#define m_scanner_isdigit( c )  ( (c)>= '0' && (c) <= '9' )
#define m_scanner_isxdigit( c ) \
  ( m_scanner_isdigit(c) || ((c) >= 'a' && (c) <= 'f') || ((c)>='A' && (c)<= 'F') )
#define m_scanner_isalpha( c ) \
  ( ((c)>='a' && (c)<='z') || ((c)>='A' && (c)<='Z') )
#define m_scanner_isxalpha( c )\
  (m_scanner_isalpha(c)||((c)&0x80 || (c)=='_'))

/*----------------------------------------------------------------------------*/
static int scanner_type (char *type, int *size)
{
  if (!strcmp (type, "char")) {
    *size = sizeof (char);
    return (SCANNER_TYPE_CHAR);
  }
  if (!strcmp (type, "int")) {
    *size = sizeof (int);
    return (SCANNER_TYPE_INT);
  }
  if (!strcmp (type, "double")) {
    *size = sizeof (double);
    return (SCANNER_TYPE_DOUBLE);
  }
  if (!strcmp (type, "edouble")) {
    *size = sizeof (double);
    return (SCANNER_TYPE_EDOUBLE);
  }
  if (!strcmp (type, "string")) {
    *size = sizeof (char *);
    return (SCANNER_TYPE_STRING);
  }
  if (!strcmp (type, "cstring")) {
    *size = sizeof (char *);
    return (SCANNER_TYPE_CSTRING);
  }
  *size = 0;
  return (0);
}                               /* scanner_type */

/*----------------------------------------------------------------------------*/
static int scanner_digit (int *val, scanner_t * s, int radix, int expect)
{
  switch (radix) {
  case 10:
    if ('0' <= s->c && s->c <= '9')
      *val = *val * 10 + s->c - '0';
    else if (expect) {
      ighmm_scanner_error (s, "decimal digit expected");
      return (-1);
    }
    else
      return (1);
    break;
  case 16:
    if (s->c >= '0' && s->c <= '9')
      *val = *val * 16 + s->c - '0';
    else if ('A' <= s->c && s->c <= 'F')
      *val = *val * 16 + s->c - 'A' + 10;
    else if ('a' <= s->c && s->c <= 'f')
      *val = *val * 16 + s->c - 'a' + 10;
    else if (expect) {
      ighmm_scanner_error (s, "decimal digit expected");
      return (-1);
    }
    else
      return (1);
    break;
  case 2:
    if (s->c >= '0' && s->c <= '1')
      *val = *val * 2 + s->c - '0';
    else if (expect) {
      ighmm_scanner_error (s, "binary digit expected");
      return (-1);
    }
    else
      return (1);
    break;
  case 8:
    if (s->c >= '0' && s->c <= '7')
      *val = *val * 8 + s->c - '0';
    else if (expect) {
      ighmm_scanner_error (s, "octal digit expected");
      return (-1);
    }
    else
      return (1);
    break;
  default:
    return (1);
  }
  return (0);
}                               /* scanner_digit */

/*----------------------------------------------------------------------------*/
static int scanner_virtual_fgetc (scanner_t * s)
{
  int c;

  if (!s)
    return (EOF);
  c = fgetc (s->fp);            /* Don't use the mes-functions here */
  if (c == EOF)
    return (c);
  ungetc (c, s->fp);
  return (c);
}                               /* scanner_virtual_fgetc */

/*----------------------------------------------------------------------------*/
static void scanner_fgetc (scanner_t * s)
{
  int c;

  if (!s)
    return;
  c = fgetc (s->fp);            /* Don't use the mes-functions here */
  if (c == EOF) {
    s->c = 0;
    s->eof = 1;
  }
  else
    s->c = c;
}                               /* scanner_fgetc */

/*----------------------------------------------------------------------------*/
static int scanner_nextchar (scanner_t * s, int expect)
{
  if (!s || s->err || s->eof)
    return (0);
  while (s->pos + 1 >= s->txtlen) {
    int mes_stat = ighmm_mes_ability (0);
    int err = ighmm_realloc ((void**)&(s->txt), sizeof(*(s->txt))*(s->txtlen + 256));
    ighmm_mes_ability (mes_stat);

    if (err) {
      ighmm_scanner_error (s, "line too long");
      return (-1);
    }
    else
      s->txtlen += 256;
  }
  s->txt[s->pos] = s->c;
  if (s->c == '\n') {
    s->pos = 0;
    s->line++;
  }
  else
    s->pos++;
  s->txt[s->pos] = 0;

  scanner_fgetc (s);
  if (s->eof && expect) {
    ighmm_scanner_error (s, "unexpected end of file");
    return (-1);
  }
  return (0);
}                               /* scanner_nextchar */

/*----------------------------------------------------------------------------*/
static int scanner_nextcchar (scanner_t * s)
{
  if (!s || s->eof || s->err)
    return (0);
  if (s)
    s->esc = 0;
  if (scanner_nextchar (s, 1))
    return (-1);
  if (s->c - '\\')
    return (0);
  else {
    int radix = 0;
    int digits = 0;
    int val = 0;
    if (scanner_nextchar (s, 1))
      return (-1);
    s->esc = 1;
    if ('0' <= s->c && s->c <= '7') {
      radix = 8;
      val = s->c - '0';
      digits = 2;
    }
    else {
      switch (s->c) {
      case 'a':
        s->c = '\a';
        break;
      case 'b':
        s->c = '\b';
        break;
      case 'f':
        s->c = '\f';
        break;
      case 'n':
        s->c = '\n';
        break;
      case 'r':
        s->c = '\r';
        break;
      case 't':
        s->c = '\t';
        break;
      case 'v':
        s->c = '\v';
        break;
      case '\\':
        s->c = '\\';
        break;
      case '\'':
        s->c = '\'';
        break;
      case '"':
        s->c = '\"';
        break;
      case '?':
        s->c = '\?';
        break;
      case 'd':
        radix = 10;
        digits = 3;
        break;
      case 'x':
        radix = 16;
        digits = 2;
        break;
      case '_':
        radix = 2;
        digits = 8;
        break;
      default:
        return (0);
      }
      if (!radix)
        return (0);
    }
    while (digits--) {
      if (scanner_nextchar (s, 1))
        return (-1);
      if (scanner_digit (&val, s, radix, 1))
        return (-1);
    }
    s->c = val;
  }
  return (0);
}                               /* scanner_nextcchar */

/*----------------------------------------------------------------------------*/
static int scanner_skipspace (scanner_t * s)
{
  if (s->eof || s->err)
    return (0);
  while (!s->eof) {
    if (s->c == '#') {          /* skip comment */
      do {
        if (scanner_nextchar (s, 0))
          return (-1);
      } while (!s->eof && s->c - '\n');
    }

    /* New : C-Comment allowed */
    else if (s->c == '/' && scanner_virtual_fgetc (s) == '*') {
      do {
        if (scanner_nextchar (s, 0))
          return (-1);
      } while (!s->eof && (s->c - '*' || scanner_virtual_fgetc (s) - '/'));
      if (!s->eof && scanner_nextchar (s, 0))
        return (-1);
      if (!s->eof && scanner_nextchar (s, 0))
        return (-1);
    }                           /* FN: 22.10.97 */

    else if (strchr (" \n\r\t\f\v\b\a", s->c)) {
      if (scanner_nextchar (s, 0))
        return (-1);
    }

    else
      break;
  }
  return (0);
}                               /* scanner_skipspace */

/*----------------------------------------------------------------------------*/
static double scanner_get_length (scanner_t * s, double resolution)
{
  double val = ighmm_scanner_get_double (s);

  if (!s || s->err)
    return (0);
  if (s->eof) {
    ighmm_scanner_error (s, "length expected");
    return (0);
  }
  if (s->c - ';') {
    if (resolution <= 0.0) {
      ighmm_scanner_error (s, "resolution not set");
      return (0);
    }
    s->resolution_used = 1;
    if (ighmm_scanner_get_id (s))
      return (0);
    if (!strcmp (s->id, "INCH"))
      val *= resolution;
    else if (!strcmp (s->id, "CM"))
      val *= (resolution / 2.54);
    else if (!strcmp (s->id, "MM"))
      val *= (resolution / 25.4);
    else {
      ighmm_scanner_error (s, "unknown length unit");
      return (0);
    }
  }
  return val;
}                               /* scanner_get_length */


/*============================================================================*/
/*============================================================================*/
/*============================================================================*/
int ighmm_scanner_free (scanner_t ** s)
{
# define CUR_PROC "ighmm_scanner_free"
  mes_check_ptr (s, return (-1));
  if (!*s)
    return (0);
  m_free ((*s)->filename);
  m_free ((*s)->id);
  m_free ((*s)->txt);
  m_fclose ((*s)->fp);
  m_free (*s);
  return (0);
# undef CUR_PROC
}                               /* ighmm_scanner_free */

/*============================================================================*/
scanner_t *ighmm_scanner_alloc (const char *filename)
{
#define CUR_PROC "ighmm_scanner_alloc"
  scanner_t *s = NULL;

  mes_check_ptr (filename, return (NULL));
  ARRAY_CALLOC (s, 1);

  s->txtlen = 256;
  s->idlen = 256;
  if (!(s->fp = ighmm_mes_fopen (filename, "rt"))) {
    GHMM_LOG_QUEUED(LCONVERTED);
    goto STOP;
  }
  ARRAY_MALLOC (s->txt, s->txtlen);
  ARRAY_MALLOC (s->id, s->txtlen);
  ARRAY_CALLOC (s->filename, strlen (filename) + 1);

  memcpy (s->filename, filename, strlen (filename) + 1);
  s->line = 1;
  s->pos = 0;
  s->c = ' ';
  s->err = 0;

  /****************/
  s->resolution_used = 0;
  s->x_resolution = 0.0;
  s->y_resolution = 0.0;
  s->x_scale = 1.0;
  s->y_scale = 1.0;

  scanner_fgetc (s);
  if (scanner_skipspace (s))
    goto STOP;
  return (s);
STOP:     /* Label STOP from ARRAY_[CM]ALLOC */
  ighmm_scanner_free (&s);
  return (NULL);
#undef CUR_PROC
}                               /* ighmm_scanner_alloc */

/*============================================================================*/
int ighmm_scanner_error (scanner_t * s, char *message)
{
  int i, j;

  if (!s || s->err)
    return (0);
  j = s->pos;
  while (!s->eof && s->c - '\n' && !scanner_nextchar (s, 0));
  ighmm_mes_time ();
  mes_file_win (s->txt);
  mes_file_win ("\n");
  for (i = 0; i < j; i++) {
    if (s->txt[i] - '\t')
      s->txt[i] = ' ';
  }
  s->txt[j] = 0;
  mes_file_win (s->txt);
  mes_file_win ("^\n");
  if (message) {
    ighmm_mes (MES_FILE_WIN, "Error in file %s, line %d : %s\n",
         s->filename, s->line + 1, message);
  }
  else {
    ighmm_mes (MES_FILE_WIN, "Syntax error in file %s, line %d\n",
         s->filename, s->line + 1, message);
  }
  s->err = 1;
  s->c = 0;
  return (0);
}                               /* ighmm_scanner_error */

/*============================================================================*/
int ighmm_scanner_consume (scanner_t * s, char ch)
{
  if (s->err)
    return (0);
  if (s->eof || ch - s->c) {
    char txt[] = "' ' expected!";
    txt[1] = ch;
    ighmm_scanner_error (s, txt);
    return (-1);
  }
  else if (scanner_nextchar (s, 0))
    return (-1);
  if (scanner_skipspace (s))
    return (-1);
  return (0);
}                               /* ighmm_scanner_consume */

/*============================================================================*/
/* Reads over a block, that's enclosed in '{' and '}'. Other blocks, lying within
   this one will be skipped */
int ighmm_scanner_consume_block (scanner_t * s)
{
  int open_brackets = 0;
  if (s->err)
    return (0);
  ighmm_scanner_consume (s, '{');
  if (s->err)
    return (-1);
  open_brackets++;

  while (!s->eof && open_brackets) {
    if (!('{' - s->c))
      open_brackets++;
    else if (!('}' - s->c))
      open_brackets--;
    if (scanner_nextchar (s, 0))
      return (-1);
    if (scanner_skipspace (s))
      return (-1);
  }
  if (open_brackets) {
    ighmm_scanner_error (s, "Unexpected EOF! '}'expected");
    return (-1);
  }
  return (0);
}                               /* ighmm_scanner_consume_block */

/*============================================================================*/
int ighmm_scanner_get_name (scanner_t * s)
{
  int pos = 0;

  if (!s || s->err)
    return (0);
  while (m_scanner_isxalpha (s->c) || m_scanner_isdigit (s->c)) {
    while (pos + 1 >= s->idlen) {
      int mes_stat = ighmm_mes_ability (0);
      int err = ighmm_realloc ((void**)&(s->txt), sizeof(*(s->txt))*(s->txtlen + 256));
      ighmm_mes_ability (mes_stat);
      if (err) {
        ighmm_scanner_error (s, "identifier too long");
        return (-1);
      }
      else
        s->idlen += 256;
    }
    s->id[pos++] = s->c;
    if (scanner_nextchar (s, 0))
      return (-1);
  }
  if (!pos || m_scanner_isdigit (s->id[0]))
    ighmm_scanner_error (s, "identifier expected");
  s->id[pos] = 0;
  if (scanner_skipspace (s))
    return (-1);
  return (0);
}                               /* ighmm_scanner_get_name */

/*============================================================================*/
int ighmm_scanner_get_id (scanner_t * s)
{
  char *str;
  if (!s || s->err)
    return (0);
  if (ighmm_scanner_get_name (s))
    return (0);
  str = s->id;
  while (*str) {
    if ('a' <= *str && *str <= 'z')
      *str += 'A' - 'a';
    str++;
  }
  return (0);
}                               /* ighmm_scanner_get_id */

/*============================================================================*/
char *ighmm_scanner_get_str (scanner_t * s, int *len, int cmode)
{
# define CUR_PROC "scanner_get_string"
  int i = 0;
  int maxlen = 128;
  char *val = NULL;

  if (!s || s->err)
    return (NULL);
  if (s->eof || s->c - '"') {
    ighmm_scanner_error (s, "string expected");
    goto STOP;
  }
  ARRAY_MALLOC (val, maxlen);

  while (!s->eof && s->c == '"') {
    if (cmode) {
      if (scanner_nextcchar (s))
        goto STOP;
    }
    else {
      if (scanner_nextchar (s, 1))
        goto STOP;
    }
    while (s->c - '"' || s->esc) {
      if (s->eof || ((!s->c || s->c == '\n') && !s->esc)) {
        ighmm_scanner_error (s, "String not closed");
        goto STOP;
      }
      if (i + 1 == maxlen) {
        ARRAY_REALLOC (val, maxlen + 128);
        maxlen += 128;
      }
      if (s->c || len)
        val[i++] = s->c;
      if (cmode) {
        if (scanner_nextcchar (s))
          goto STOP;
      }
      else {
        if (scanner_nextchar (s, 1))
          goto STOP;
      }
    }

    if (ighmm_scanner_consume (s, '"'))
      goto STOP;
    if (scanner_skipspace (s))
      goto STOP;
  }
  val[i++] = 0;
  ARRAY_REALLOC (val, i);
  if (len)
    *len = i;
  return (val);

STOP:     /* Label STOP from ARRAY_[CM]ALLOC */
  m_free (val);
  return (NULL);
# undef CUR_PROC
}                               /* ighmm_scanner_get_str */

/*============================================================================*/
char *ighmm_scanner_get_path (scanner_t * s)
{
#define CUR_PROC "ighmm_scanner_get_path"
  char *res = scanner_get_string (s);
  char *p;
# if defined(_PPC) || defined(_DOS) || defined(_WINDOWS)
  if (res)
    for (p = res; *p; p++)
      if (*p == '/')
        *p = '\\';
# else
  if (res)
    for (p = res; *p; p++)
      if (*p == '\\')
        *p = '/';
# endif
  return (res);
#undef CUR_PROC
}                               /* ighmm_scanner_get_path */

/*============================================================================*/
int ighmm_scanner_get_int (scanner_t * s)
{
  int val = 0;
  int sign = 0;

  if (!s || s->err)
    return (0);
  if (s->eof) {
    ighmm_scanner_error (s, "integer expected");
    return (0);
  }

  if (s->c == '-') {
    if (scanner_nextchar (s, 1))
      return (0);
    sign = 1;
  }
  else if (s->c == '+') {
    if (scanner_nextchar (s, 1))
      return (0);
  }
  if (scanner_skipspace (s))
    return (0);

  if (s->c == '\'') {
    if (scanner_nextcchar (s))
      return (0);
    val = (unsigned char) (s->c);
    if (scanner_nextchar (s, 1))
      return (0);
    if (s->c - '\'') {
      if (!s->esc) {
        ighmm_scanner_error (s, " \' expected");
        return (0);
      }
      val = (unsigned char) '\\';
    }
    else if (scanner_nextchar (s, 1))
      return (0);
  }

  else if (!m_scanner_isdigit (s->c)) {
    if (ighmm_scanner_get_id (s))
      return (0);
    if (!strcmp (s->id, "TRUE"))
      return (sign ? 0 : 1);
    else if (!strcmp (s->id, "FALSE"))
      return (sign ? 1 : 0);
    if (!strcmp (s->id, "ON"))
      return (sign ? 0 : 1);
    else if (!strcmp (s->id, "OFF"))
      return (sign ? 1 : 0);
    ighmm_scanner_error (s, "integer value expected");
    return (0);
  }

  else {
    int radix = 10;

    if (s->c == '0') {
      if (scanner_nextchar (s, 1))
        return (0);
      if (m_scanner_isdigit (s->c)) {
        val = s->c - '0';
        if (scanner_nextchar (s, 1))
          return (0);
      }
      else
        switch (s->c) {
        case 'x':
        case 'X':
          radix = 16;
          break;
        case '_':
          radix = 2;
          break;
        case 'o':
          radix = 8;
          break;
        }
      if (radix - 10) {
        if (scanner_nextchar (s, 1))
          return (0);
        if (scanner_digit (&val, s, radix, 1))
          return (0);
        if (scanner_nextchar (s, 1))
          return (0);
      }
    }
    while (!scanner_digit (&val, s, radix, 0)) {
      if (scanner_nextchar (s, 1))
        return (0);
    }
  }
  if (scanner_skipspace (s))
    return (0);
  return (sign ? -val : val);
# undef CUR_PROC
}                               /* ighmm_scanner_get_int */


/*============================================================================*/
double ighmm_scanner_get_double (scanner_t * s)
{
  double val = 0;
  int sign = 0;

  if (!s || s->err)
    return (0);
  if (s->eof) {
    ighmm_scanner_error (s, "real number expected");
    return (0);
  }

  if (s->c == '-') {
    if (scanner_nextchar (s, 1))
      return (0);
    sign = 1;
  }
  else if (s->c == '+' && scanner_nextchar (s, 1))
    return (0);

  if (scanner_skipspace (s))
    return (0);

  if (!m_scanner_isdigit (s->c) && s->c - '.') {
    ighmm_scanner_error (s, "real number expected");
    return (0);
  }
  while (m_scanner_isdigit (s->c)) {
    val = 10 * val + (double) (s->c - '0');
    if (scanner_nextchar (s, 1))
      return (0);
  }
  if (s->c == '.') {
    double factor = 1;
    if (scanner_nextchar (s, 1))
      return (0);
    while (m_scanner_isdigit (s->c)) {
      val = 10 * val + (double) (s->c - '0');
      if (scanner_nextchar (s, 1))
        return (0);
      factor *= 10;
    }
    val /= factor;
  }
  if (scanner_skipspace (s))
    return (0);
  return (sign ? -val : val);
}                               /* ighmm_scanner_get_double */


/*============================================================================*/
double ighmm_scanner_get_edouble (scanner_t * s)
{
  double val = 0;
  int sign = 0;

  if (!s || s->err)
    return (0);
  if (s->eof) {
    ighmm_scanner_error (s, "real number expected");
    return (0);
  }

  if (s->c == '-') {
    if (scanner_nextchar (s, 1))
      return (0);
    sign = 1;
  }
  else if (s->c == '+' && scanner_nextchar (s, 1))
    return (0);

  if (scanner_skipspace (s))
    return (0);

  if (!m_scanner_isdigit (s->c) && s->c - '.') {
    ighmm_scanner_error (s, "real number expected");
    return (0);
  }
  while (m_scanner_isdigit (s->c)) {
    val = 10 * val + (double) (s->c - '0');
    if (scanner_nextchar (s, 1))
      return (0);
  }
  if (s->c == '.') {
    double factor = 1;
    if (scanner_nextchar (s, 1))
      return (0);
    while (m_scanner_isdigit (s->c)) {
      val = 10 * val + (double) (s->c - '0');
      if (scanner_nextchar (s, 1))
        return (0);
      factor *= 10;
    }
    val /= factor;
  }
  if (s->c == 'e' || s->c == 'E') {
    int i;
    double eval;
    double efactor = 1;
    int esign = 0;
    if (scanner_nextchar (s, 1))
      return (0);
    if (s->c == '-') {
      if (scanner_nextchar (s, 1))
        return (0);
      esign = 1;
    }
    else if (s->c == '+' && scanner_nextchar (s, 1))
      return (0);
    eval = ighmm_scanner_get_int (s);
    if (eval < 0)
      return (0);
    for (i = 0; i < eval; i++)
      efactor *= 10;
    if (esign)
      val /= efactor;
    else
      val *= efactor;
  }

  if (scanner_skipspace (s))
    return (0);
  return (sign ? -val : val);
}                               /* ighmm_scanner_get_edouble */


/*============================================================================*/
void *ighmm_scanner_get_array (scanner_t * s, int *len, char *type)
{
#define CUR_PROC "ighmm_scanner_get_array"
  int size = 0;
  int typ = scanner_type (type, &size);
  int maxlen = 16 * size;
  char *val = NULL;
  int i = 0;
  char txt[256];
  int err;
  int mes_stat;

  if (!s || !type || !len || s->err)
    goto STOP;
  if (!typ) {
    ighmm_scanner_error (s, ighmm_mprintf (txt, sizeof (txt), "unknown type %s ", type));
    goto STOP;
  }
  if (!len || !s || s->err)
    goto STOP;
  if (s->eof) {
    ighmm_scanner_error (s,
                   ighmm_mprintf (txt, sizeof (txt), "%s array expected ", type));
    goto STOP;
  }
  if (s->c == ';') {
    *len = 0;
    goto STOP;
  }
  mes_stat = ighmm_mes_ability (0);
  val = ighmm_malloc (sizeof (char *) * maxlen);
  err = !val;
  ighmm_mes_ability (mes_stat);
  if (err) {
    ighmm_mprintf (txt, sizeof (txt), "Not enough memory to read %s array", type);
    ighmm_scanner_error (s, txt);
    goto STOP;
  }

  while (s->c - ';') {
    /* Originally:
       if( i && ighmm_scanner_consume( s, ',' ) )  goto STOP; */
    /* Changed: read array without seperator now possible */
    if (s->c == ',')
      ighmm_scanner_consume (s, ',');
    switch (typ) {
    case SCANNER_TYPE_CHAR:
      val[i] = ighmm_scanner_get_int (s);
      break;
    case SCANNER_TYPE_INT:
      *(int *) (val + i) = ighmm_scanner_get_int (s);
      break;
    case SCANNER_TYPE_DOUBLE:
      *(double *) (val + i) = ighmm_scanner_get_double (s);
      break;
    case SCANNER_TYPE_EDOUBLE:
      *(double *) (val + i) = ighmm_scanner_get_edouble (s);
      break;
    case SCANNER_TYPE_STRING:
      *(char **) (val + i) = scanner_get_string (s);
      break;
    case SCANNER_TYPE_CSTRING:
      *(char **) (val + i) = scanner_get_cstring (s);
      break;
    default:
      goto STOP;
    }
    i += size;
    if (s->err)
      goto STOP;

    if (i == maxlen) {
      mes_stat = ighmm_mes_ability (0);
      err = ighmm_realloc ((void**)&val, sizeof (*val) * (maxlen + 16 * size));
      ighmm_mes_ability (mes_stat);
      if (err) {
        ighmm_mprintf (txt, sizeof (txt), "Not enough memory to read %s array", type);
        ighmm_scanner_error (s, txt);
        goto STOP;
      }
      maxlen += 16 * size;
    }
  }
  mes_stat = ighmm_mes_ability (0);
  ighmm_realloc ((void**)&val, sizeof (*val) * i);/* Do'nt worry if this fails!*/
  ighmm_mes_ability (mes_stat);

  *len = i / size;

  return (val);

STOP:     /* Label STOP from ARRAY_[CM]ALLOC */
  m_free (val);
  if (len)
    *len = 0;
  return (NULL);
# undef CUR_PROC
}                               /* ighmm_scanner_get_array */


/*============================================================================*/
int ighmm_scanner_free_array (int *len, void ***arr)
{
# define CUR_PROC "ighmm_scanner_free_array"
  mes_check_ptr (len, return (-1));
  mes_check_ptr (arr, return (-1));
  while ((*len)-- > 0) {
    m_free ((*arr)[*len]);
  }
  free (*arr);
  *len = 0;
  return (0);
# undef CUR_PROC
}                               /* ighmm_scanner_free_array */

/*============================================================================*/
int ighmm_scanner_get_index (scanner_t * s, int n)
{
  int index = n - 1;
  if (!s || s->err)
    return (0);
  if (s->eof || s->c - '@') {
    ighmm_scanner_error (s, "index expected");
    return (0);
  }
  if (ighmm_scanner_consume (s, '@'))
    return (0);
  index = ighmm_scanner_get_int (s);
  if (s->err)
    return (0);
  if (index >= n)
    ighmm_scanner_error (s, "index too high");
  if (ighmm_scanner_consume (s, ';'))
    return (0);
  return (index);
}                               /* ighmm_scanner_get_index */

/*============================================================================*/
double ighmm_scanner_get_resolution (scanner_t * s)
{
  double val;

  if (!s || s->err)
    return (0);
  val = ighmm_scanner_get_double (s);
  if (s->err)
    return (0);
  if (ighmm_scanner_get_id (s))
    return (0);
  if (strcmp (s->id, "DPI")) {
    ighmm_scanner_error (s, "dpi expected");
    return (0);
  }
  return (val);
}                               /* ighmm_scanner_get_resolution */

/*============================================================================*/
int ighmm_scanner_get_length_x (scanner_t * s)
{
  return (s->x_scale * scanner_get_length (s, s->x_resolution) + 0.5);
}                               /* ighmm_scanner_get_length_x */

/*============================================================================*/
int ighmm_scanner_get_length_y (scanner_t * s)
{
  return (s->y_scale * scanner_get_length (s, s->y_resolution) + 0.5);
}                               /* ighmm_scanner_get_length_y */


#if defined( TEST )
/*============================================================================*/
int scanner_tst (void)
{
# define CUR_PROC "scanner_tst"
  scanner_t *s = ighmm_scanner_alloc ("scanner.cfg");
  char *char_arr = NULL;
  int char_len = 0;
  int *int_arr = NULL;
  int int_len = 0;
  double *double_arr = NULL;
  int double_len = 0;
  char **string_arr = NULL;
  int string_len = 0;
  int res = -1;
  int i;

  if (!s) {
    GHMM_LOG_QUEUED(LCONVERTED);
    goto STOP;
  }

  while (!s->err && !s->eof) {
    if (ighmm_scanner_get_name (s))
      break;
    if (ighmm_scanner_consume (s, '='))
      break;
    else if (!strcmp (s->id, "char")) {
      m_free (char_arr);
      char_arr = scanner_get_char_array (s, &char_len);
    }
    else if (!strcmp (s->id, "int")) {
      m_free (int_arr);
      int_arr = scanner_get_int_array (s, &int_len);
    }
    else if (!strcmp (s->id, "string")) {
      m_free (string_arr);
      string_arr = scanner_get_cstring_array (s, &string_len);
    }
    else if (!strcmp (s->id, "double")) {
      m_free (double_arr);
      double_arr = scanner_get_double_array (s, &double_len);
    }
    else
      ighmm_scanner_error (s, "unknown identifyer");
    if (ighmm_scanner_consume (s, ';'))
      break;
  }

  if (char_arr) {
    mes_win ("\nchar:\n");
    for (i = 0; i < char_len; i++)
      ighmm_mes (MES_WIN, "  '%c'\n", char_arr[i]);
  }
  if (int_arr) {
    mes_win ("\nint:\n");
    for (i = 0; i < int_len; i++)
      ighmm_mes (MES_WIN, "  %d\n", int_arr[i]);
  }
  if (double_arr) {
    mes_win ("\ndouble:\n");
    for (i = 0; i < double_len; i++)
      ighmm_mes (MES_WIN, "  %f\n", double_arr[i]);
  }
  if (string_arr) {
    mes_win ("\nstring:\n");
    for (i = 0; i < string_len; i++)
      ighmm_mes (MES_WIN, "  \"%s\"\n", string_arr[i]);
  }

  res = 0;
STOP:
  ighmm_scanner_free (&s);
  m_free (char_arr);
  m_free (int_arr);
  m_free (double_arr);
  if (string_arr)
    for (i = 0; i < string_len; i++)
      m_free (string_arr[i]);
  m_free (string_arr);
  return (res);
# undef CUR_PROC
}                               /* scanner_tst */
#endif /* defined( TEST ) */

/*----------------------------------------------------------------------------*/
static int scanner_free_d_matrix (double ***matrix, long rows)
{
# define CUR_PROC "scanner_free_d_matrix"
  long i;
  mes_check_ptr (matrix, return (-1));
  if (!*matrix)
    return (0);
  for (i = 0; i < rows; i++)
    m_free ((*matrix)[i]);
  m_free (*matrix);
  return (0);
# undef CUR_PROC
}                               /* scanner_free_d_matrix */

/*============================================================================*/
double **ighmm_scanner_get_d_matrix (scanner_t * s, int *rows, int *cols)
{
#define CUR_PROC "ighmm_scanner_get_d_matrix"
  double **matrix = NULL;
  int local_cols = 0;
  *rows = *cols = 0;
  while (!s->eof && !s->err && s->c - '}') {
    (*rows)++;
    ARRAY_REALLOC (matrix, *rows);
    matrix[*rows - 1] = scanner_get_double_array (s, &local_cols);
    ighmm_scanner_consume (s, ';');
    if (s->err)
      goto STOP;
    if (*rows > 1)
      if (local_cols != *cols) {
        ighmm_scanner_error (s, "rows of variing length in matrix");
        goto STOP;
      }
    *cols = local_cols;
  }                             /* while ... */
  return matrix;
STOP:     /* Label STOP from ARRAY_[CM]ALLOC */
  scanner_free_d_matrix (&matrix, *rows);
  return NULL;
#undef CUR_PROC
}                               /* ighmm_scanner_get_d_matrix */

#endif /* GHMM_OBSOLETE */
