void
st_close (st_parameter_close *clp)
{
  close_status status;
  gfc_unit *u;
#if !HAVE_UNLINK_OPEN_FILE
  char * path;

  path = NULL;
#endif

  library_start (&clp->common);

  status = !(clp->common.flags & IOPARM_CLOSE_HAS_STATUS) ? CLOSE_UNSPECIFIED :
    find_option (&clp->common, clp->status, clp->status_len,
		 status_opt, "Bad STATUS parameter in CLOSE statement");

  if ((clp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
  {
    library_end ();
    return;
  }

  u = find_unit (clp->common.unit);
  if (u != NULL)
    {
      if (u->flags.status == STATUS_SCRATCH)
	{
	  if (status == CLOSE_KEEP)
	    generate_error (&clp->common, LIBERROR_BAD_OPTION,
			    "Can't KEEP a scratch file on CLOSE");
#if !HAVE_UNLINK_OPEN_FILE
	  path = (char *) gfc_alloca (u->file_len + 1);
          unpack_filename (path, u->file, u->file_len);
#endif
	}
      else
	{
	  if (status == CLOSE_DELETE)
            {
#if HAVE_UNLINK_OPEN_FILE
	      delete_file (u);
#else
	      path = (char *) gfc_alloca (u->file_len + 1);
              unpack_filename (path, u->file, u->file_len);
#endif
            }
	}

      close_unit (u);

#if !HAVE_UNLINK_OPEN_FILE
      if (path != NULL)
        unlink (path);
#endif
    }

  /* CLOSE on unconnected unit is legal and a no-op: F95 std., 9.3.5. */ 
  library_end ();
}
Exemplo n.º 2
0
Arquivo: link.c Projeto: ChaosJohn/gcc
void
link_i8_sub (char *path1, char *path2, GFC_INTEGER_8 *status,
             gfc_charlen_type path1_len, gfc_charlen_type path2_len)
{
  int val;
  char *str1, *str2;

  /* Trim trailing spaces from paths.  */
  while (path1_len > 0 && path1[path1_len - 1] == ' ')
    path1_len--;
  while (path2_len > 0 && path2[path2_len - 1] == ' ')
    path2_len--;

  /* Make a null terminated copy of the strings.  */
  str1 = gfc_alloca (path1_len + 1);
  memcpy (str1, path1, path1_len);
  str1[path1_len] = '\0';

  str2 = gfc_alloca (path2_len + 1);
  memcpy (str2, path2, path2_len);
  str2[path2_len] = '\0';

  val = link (str1, str2);

  if (status != NULL)
    *status = (val == 0) ? 0 : errno;
}
Exemplo n.º 3
0
static void
read_default_char4 (st_parameter_dt *dtp, char *p, int len, size_t width)
{
  char *s;
  gfc_char4_t *dest;
  int m, n, status;

  s = gfc_alloca (width);

  status = read_block_form (dtp, s, &width);
  
  if (status == FAILURE)
    return;
  if (width > (size_t) len)
     s += (width - len);

  m = ((int) width > len) ? len : (int) width;
  
  dest = (gfc_char4_t *) p;
  
  for (n = 0; n < m; n++, dest++, s++)
    *dest = (unsigned char ) *s;

  for (n = 0; n < len - (int) width; n++, dest++)
    *dest = (unsigned char) ' ';
}
Exemplo n.º 4
0
int
chmod_func (char *name, char *mode, gfc_charlen_type name_len,
	    gfc_charlen_type mode_len)
{
  char * file, * m;
  pid_t pid;
  int status;

  /* Trim trailing spaces.  */
  while (name_len > 0 && name[name_len - 1] == ' ')
    name_len--;
  while (mode_len > 0 && mode[mode_len - 1] == ' ')
    mode_len--;

  /* Make a null terminated copy of the strings.  */
  file = gfc_alloca (name_len + 1);
  memcpy (file, name, name_len);
  file[name_len] = '\0';

  m = gfc_alloca (mode_len + 1);
  memcpy (m, mode, mode_len);
  m[mode_len]= '\0';

  /* Execute /bin/chmod.  */
  if ((pid = fork()) < 0)
    return errno;
  if (pid == 0)
    {
      /* Child process.  */
      execl ("/bin/chmod", "chmod", m, file, (char *) NULL);
      return errno;
    }
  else
    wait (&status);

  if (WIFEXITED(status))
    return WEXITSTATUS(status);
  else
    return -1;
}
Exemplo n.º 5
0
static void
already_open (st_parameter_open *opp, gfc_unit * u, unit_flags * flags)
{
  if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
    {
      edit_modes (opp, u, flags);
      return;
    }

  /* If the file is connected to something else, close it and open a
     new unit.  */

  if (!compare_file_filename (u, opp->file, opp->file_len))
    {
#if !HAVE_UNLINK_OPEN_FILE
      char *path = NULL;
      if (u->file && u->flags.status == STATUS_SCRATCH)
	{
	  path = (char *) gfc_alloca (u->file_len + 1);
	  unpack_filename (path, u->file, u->file_len);
	}
#endif

      if (sclose (u->s) == FAILURE)
	{
	  unlock_unit (u);
	  generate_error (&opp->common, LIBERROR_OS,
			  "Error closing file in OPEN statement");
	  return;
	}

      u->s = NULL;
      if (u->file)
	free_mem (u->file);
      u->file = NULL;
      u->file_len = 0;

#if !HAVE_UNLINK_OPEN_FILE
      if (path != NULL)
	unlink (path);
#endif

      u = new_unit (opp, u, flags);
      if (u != NULL)
	unlock_unit (u);
      return;
    }

  edit_modes (opp, u, flags);
}
Exemplo n.º 6
0
void
perror_sub (char *string, gfc_charlen_type string_len)
{
    char * str;

    /* Trim trailing spaces from paths.  */
    while (string_len > 0 && string[string_len - 1] == ' ')
        string_len--;

    /* Make a null terminated copy of the strings.  */
    str = gfc_alloca (string_len + 1);
    memcpy (str, string, string_len);
    str[string_len] = '\0';

    perror (str);
}
Exemplo n.º 7
0
void
read_l (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
{
  char *p;
  size_t w;

  w = f->u.w;

  p = gfc_alloca (w);

  if (read_block_form (dtp, p, &w) == FAILURE)
    return;

  while (*p == ' ')
    {
      if (--w == 0)
	goto bad;
      p++;
    }

  if (*p == '.')
    {
      if (--w == 0)
	goto bad;
      p++;
    }

  switch (*p)
    {
    case 't':
    case 'T':
      set_integer (dest, (GFC_INTEGER_LARGEST) 1, length);
      break;
    case 'f':
    case 'F':
      set_integer (dest, (GFC_INTEGER_LARGEST) 0, length);
      break;
    default:
    bad:
      generate_error (&dtp->common, LIBERROR_READ_VALUE,
		      "Bad value on logical read");
      next_record (dtp, 1);
      break;
    }
}
Exemplo n.º 8
0
void
chdir_i8_sub (char *dir, GFC_INTEGER_8 *status, gfc_charlen_type dir_len)
{
  int val;
  char *str;

  /* Trim trailing spaces from paths.  */
  while (dir_len > 0 && dir[dir_len - 1] == ' ')
    dir_len--;

  /* Make a null terminated copy of the strings.  */
  str = gfc_alloca (dir_len + 1);
  memcpy (str, dir, dir_len);
  str[dir_len] = '\0';

  val = chdir (str);

  if (status != NULL)
    *status = (val == 0) ? 0 : errno;
}
Exemplo n.º 9
0
void
unlink_i4_sub (char *name, GFC_INTEGER_4 *status, gfc_charlen_type name_len)
{
  char *str;
  GFC_INTEGER_4 stat;

  /* Trim trailing spaces from name.  */
  while (name_len > 0 && name[name_len - 1] == ' ')
    name_len--;

  /* Make a null terminated copy of the string.  */
  str = gfc_alloca (name_len + 1);
  memcpy (str, name, name_len);
  str[name_len] = '\0'; 

  stat = unlink (str);

  if (status != NULL) 
    *status = (stat == 0) ? stat : errno;
}
Exemplo n.º 10
0
static void
read_default_char1 (st_parameter_dt *dtp, char *p, int len, size_t width)
{
  char *s;
  int m, n, status;

  s = gfc_alloca (width);

  status = read_block_form (dtp, s, &width);
  
  if (status == FAILURE)
    return;
  if (width > (size_t) len)
     s += (width - len);

  m = ((int) width > len) ? len : (int) width;
  memcpy (p, s, m);

  n = len - width;
  if (n > 0)
    memset (p + m, ' ', n);
}
Exemplo n.º 11
0
Arquivo: env.c Projeto: Alexpux/GCC
void 
PREFIX(getenv) (char * name, char * value, gfc_charlen_type name_len, 
		gfc_charlen_type value_len)
{
  char *name_nt;
  char *res = NULL;
  int res_len;

  if (name == NULL || value == NULL)
    runtime_error ("Both arguments to getenv are mandatory.");

  if (value_len < 1 || name_len < 1)
    runtime_error ("Zero length string(s) passed to getenv.");
  else
    memset (value, ' ', value_len); /* Blank the string.  */

  /* Trim trailing spaces from name.  */
  while (name_len > 0 && name[name_len - 1] == ' ')
    name_len--;

  /* Make a null terminated copy of the string.  */
  name_nt = gfc_alloca (name_len + 1);
  memcpy (name_nt, name, name_len);
  name_nt[name_len] = '\0'; 

  res = getenv(name_nt);

  /* If res is NULL, it means that the environment variable didn't 
     exist, so just return.  */
  if (res == NULL)
    return;

  res_len = strlen(res);
  if (value_len < res_len)
    memcpy (value, res, value_len);
  else
    memcpy (value, res, res_len);
}
Exemplo n.º 12
0
void
read_radix (st_parameter_dt *dtp, const fnode *f, char *dest, int length,
	    int radix)
{
  GFC_UINTEGER_LARGEST value, maxv, maxv_r;
  GFC_INTEGER_LARGEST v;
  int w, negative;
  char c, *p;
  size_t wu;

  wu = f->u.w;

  p = gfc_alloca (wu);

  if (read_block_form (dtp, p, &wu) == FAILURE)
    return;

  w = wu;

  p = eat_leading_spaces (&w, p);
  if (w == 0)
    {
      set_integer (dest, (GFC_INTEGER_LARGEST) 0, length);
      return;
    }

  maxv = max_value (length, 0);
  maxv_r = maxv / radix;

  negative = 0;
  value = 0;

  switch (*p)
    {
    case '-':
      negative = 1;
      /* Fall through */

    case '+':
      p++;
      if (--w == 0)
	goto bad;
      /* Fall through */

    default:
      break;
    }

  /* At this point we have a digit-string */
  value = 0;

  for (;;)
    {
      c = next_char (dtp, &p, &w);
      if (c == '\0')
	break;
      if (c == ' ')
        {
	  if (dtp->u.p.blank_status == BLANK_NULL) continue;
	  if (dtp->u.p.blank_status == BLANK_ZERO) c = '0';
        }

      switch (radix)
	{
	case 2:
	  if (c < '0' || c > '1')
	    goto bad;
	  break;

	case 8:
	  if (c < '0' || c > '7')
	    goto bad;
	  break;

	case 16:
	  switch (c)
	    {
	    case '0':
	    case '1':
	    case '2':
	    case '3':
	    case '4':
	    case '5':
	    case '6':
	    case '7':
	    case '8':
	    case '9':
	      break;

	    case 'a':
	    case 'b':
	    case 'c':
	    case 'd':
	    case 'e':
	    case 'f':
	      c = c - 'a' + '9' + 1;
	      break;

	    case 'A':
	    case 'B':
	    case 'C':
	    case 'D':
	    case 'E':
	    case 'F':
	      c = c - 'A' + '9' + 1;
	      break;

	    default:
	      goto bad;
	    }

	  break;
	}

      if (value > maxv_r)
	goto overflow;

      c -= '0';
      value = radix * value;

      if (maxv - c < value)
	goto overflow;
      value += c;
    }

  v = value;
  if (negative)
    v = -v;

  set_integer (dest, v, length);
  return;

 bad:
  generate_error (&dtp->common, LIBERROR_READ_VALUE,
		  "Bad value during integer read");
  next_record (dtp, 1);
  return;

 overflow:
  generate_error (&dtp->common, LIBERROR_READ_OVERFLOW,
		  "Value overflowed during integer read");
  next_record (dtp, 1);

}
Exemplo n.º 13
0
int
chmod_func (char *name, char *mode, gfc_charlen_type name_len,
	    gfc_charlen_type mode_len)
{
  char * file;
  int i;
  bool ugo[3];
  bool rwxXstugo[9];
  int set_mode, part;
  bool honor_umask, continue_clause = false;
#ifndef __MINGW32__
  bool is_dir;
#endif
  mode_t mode_mask, file_mode, new_mode;
  struct stat stat_buf;

  /* Trim trailing spaces of the file name.  */
  while (name_len > 0 && name[name_len - 1] == ' ')
    name_len--;

  /* Make a null terminated copy of the file name.  */
  file = gfc_alloca (name_len + 1);
  memcpy (file, name, name_len);
  file[name_len] = '\0';

  if (mode_len == 0)
    return 1;

  if (mode[0] >= '0' && mode[0] <= '9')
    {
#ifdef __MINGW32__
      unsigned fmode;
      if (sscanf (mode, "%o", &fmode) != 1)
	return 1;
      file_mode = (mode_t) fmode;
#else
      if (sscanf (mode, "%o", &file_mode) != 1)
	return 1;
#endif
      return chmod (file, file_mode);
    }

  /* Read the current file mode. */
  if (stat (file, &stat_buf))
    return 1;

  file_mode = stat_buf.st_mode & ~S_IFMT;
#ifndef __MINGW32__
  is_dir = stat_buf.st_mode & S_IFDIR;
#endif

#ifdef HAVE_UMASK
  /* Obtain the umask without distroying the setting.  */
  mode_mask = 0;
  mode_mask = umask (mode_mask);
  (void) umask (mode_mask);
#else
  honor_umask = false;
#endif

  for (i = 0; i < mode_len; i++)
    {
      if (!continue_clause)
	{
	  ugo[0] = false;
	  ugo[1] = false;
	  ugo[2] = false;
#ifdef HAVE_UMASK
	  honor_umask = true;
#endif
	}
      continue_clause = false; 
      rwxXstugo[0] = false;
      rwxXstugo[1] = false;
      rwxXstugo[2] = false;
      rwxXstugo[3] = false;
      rwxXstugo[4] = false;
      rwxXstugo[5] = false;
      rwxXstugo[6] = false;
      rwxXstugo[7] = false;
      rwxXstugo[8] = false;
      part = 0;
      set_mode = -1;
      for (; i < mode_len; i++)
	{
	  switch (mode[i])
	    {
	    /* User setting: a[ll]/u[ser]/g[roup]/o[ther].  */
	    case 'a':
	      if (part > 1)
		return 1;
	      ugo[0] = true;
	      ugo[1] = true;
	      ugo[2] = true;
	      part = 1;
#ifdef HAVE_UMASK
	      honor_umask = false;
#endif
	      break;
	    case 'u':
	      if (part == 2)
		{
		  rwxXstugo[6] = true; 
		  part = 4;
		  break; 
		}
	      if (part > 1)
		return 1;
	      ugo[0] = true;
	      part = 1;
#ifdef HAVE_UMASK
	      honor_umask = false;
#endif
	      break;
	    case 'g':
	      if (part == 2)
		{
		  rwxXstugo[7] = true; 
		  part = 4;
		  break; 
		}
	      if (part > 1)
		return 1;
       	      ugo[1] = true;
	      part = 1;
#ifdef HAVE_UMASK
	      honor_umask = false;
#endif
	      break;
	    case 'o':
	      if (part == 2)
		{
		  rwxXstugo[8] = true; 
		  part = 4;
		  break; 
		}
	      if (part > 1)
		return 1;
	      ugo[2] = true;
	      part = 1;
#ifdef HAVE_UMASK
	      honor_umask = false;
#endif
	      break;

	    /* Mode setting: =+-.  */
	    case '=':
	      if (part > 2)
		{
		  continue_clause = true;
		  i--;
		  part = 2;
		  goto clause_done;
		}
	      set_mode = 1;
	      part = 2;
	      break;

	    case '-':
	      if (part > 2)
		{
		  continue_clause = true;
		  i--;
		  part = 2;
		  goto clause_done;
		}
	      set_mode = 2;
	      part = 2;
	      break;

	    case '+':
	      if (part > 2)
		{
		  continue_clause = true;
		  i--;
		  part = 2;
		  goto clause_done;
		}
	      set_mode = 3;
	      part = 2;
	      break;

	    /* Permissions: rwxXst - for ugo see above.  */
	    case 'r':
	      if (part != 2 && part != 3)
		return 1;
	      rwxXstugo[0] = true;
	      part = 3;
	      break;

	    case 'w':
	      if (part != 2 && part != 3)
		return 1;
	      rwxXstugo[1] = true;
	      part = 3;
	      break;

	    case 'x':
	      if (part != 2 && part != 3)
		return 1;
	      rwxXstugo[2] = true;
	      part = 3;
	      break;

	    case 'X':
	      if (part != 2 && part != 3)
		return 1;
	      rwxXstugo[3] = true;
	      part = 3;
	      break;

	    case 's':
	      if (part != 2 && part != 3)
		return 1;
	      rwxXstugo[4] = true;
	      part = 3;
	      break;

	    case 't':
	      if (part != 2 && part != 3)
		return 1;
	      rwxXstugo[5] = true;
	      part = 3;
	      break;

	    /* Tailing blanks are valid in Fortran.  */
	    case ' ':
	      for (i++; i < mode_len; i++)
		if (mode[i] != ' ')
		  break;
	      if (i != mode_len)
		return 1;
	      goto clause_done;

	    case ',':
	      goto clause_done;

	    default:
	      return 1;
	    }
	}

clause_done:
      if (part < 2)
	return 1;

      new_mode = 0;

#ifdef __MINGW32__

      /* Read. */
      if (rwxXstugo[0] && (ugo[0] || honor_umask))
	new_mode |= _S_IREAD;

      /* Write. */
      if (rwxXstugo[1] && (ugo[0] || honor_umask))
	new_mode |= _S_IWRITE;

#else

      /* Read. */
      if (rwxXstugo[0])
	{
	  if (ugo[0] || honor_umask)
	    new_mode |= S_IRUSR;
	  if (ugo[1] || honor_umask)
	    new_mode |= S_IRGRP;
	  if (ugo[2] || honor_umask)
	    new_mode |= S_IROTH;
	}

      /* Write.  */
      if (rwxXstugo[1])
	{
	  if (ugo[0] || honor_umask)
	    new_mode |= S_IWUSR;
	  if (ugo[1] || honor_umask)
	    new_mode |= S_IWGRP;
	  if (ugo[2] || honor_umask)
	    new_mode |= S_IWOTH;
	}

      /* Execute. */
      if (rwxXstugo[2])
	{
	  if (ugo[0] || honor_umask)
	    new_mode |= S_IXUSR;
	  if (ugo[1] || honor_umask)
	    new_mode |= S_IXGRP;
	  if (ugo[2] || honor_umask)
	    new_mode |= S_IXOTH;
	}

      /* 'X' execute.  */
      if (rwxXstugo[3]
	  && (is_dir || (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
	new_mode |= (S_IXUSR | S_IXGRP | S_IXOTH);

      /* 's'.  */
      if (rwxXstugo[4])
	{
	  if (ugo[0] || honor_umask)
	    new_mode |= S_ISUID;
	  if (ugo[1] || honor_umask)
	    new_mode |= S_ISGID;
	}

      /* As original 'u'.  */
      if (rwxXstugo[6])
	{
	  if (ugo[1] || honor_umask)
	    {
	      if (file_mode & S_IRUSR)
		new_mode |= S_IRGRP;
	      if (file_mode & S_IWUSR)
		new_mode |= S_IWGRP;
	      if (file_mode & S_IXUSR)
		new_mode |= S_IXGRP;
	    }
	  if (ugo[2] || honor_umask)
	    {
	      if (file_mode & S_IRUSR)
		new_mode |= S_IROTH;
	      if (file_mode & S_IWUSR)
		new_mode |= S_IWOTH;
	      if (file_mode & S_IXUSR)
		new_mode |= S_IXOTH;
	    }
	}

      /* As original 'g'.  */
      if (rwxXstugo[7])
	{
	  if (ugo[0] || honor_umask)
	    {
	      if (file_mode & S_IRGRP)
		new_mode |= S_IRUSR;
	      if (file_mode & S_IWGRP)
		new_mode |= S_IWUSR;
	      if (file_mode & S_IXGRP)
		new_mode |= S_IXUSR;
	    }
	  if (ugo[2] || honor_umask)
	    {
	      if (file_mode & S_IRGRP)
		new_mode |= S_IROTH;
	      if (file_mode & S_IWGRP)
		new_mode |= S_IWOTH;
	      if (file_mode & S_IXGRP)
		new_mode |= S_IXOTH;
	    }
	}

      /* As original 'o'.  */
      if (rwxXstugo[8])
	{
	  if (ugo[0] || honor_umask)
	    {
	      if (file_mode & S_IROTH)
		new_mode |= S_IRUSR;
	      if (file_mode & S_IWOTH)
		new_mode |= S_IWUSR;
	      if (file_mode & S_IXOTH)
		new_mode |= S_IXUSR;
	    }
	  if (ugo[1] || honor_umask)
	    {
	      if (file_mode & S_IROTH)
		new_mode |= S_IRGRP;
	      if (file_mode & S_IWOTH)
		new_mode |= S_IWGRP;
	      if (file_mode & S_IXOTH)
		new_mode |= S_IXGRP;
	    }
	}
#endif  /* __MINGW32__ */

#ifdef HAVE_UMASK
    if (honor_umask)
      new_mode &= ~mode_mask;
#endif

    if (set_mode == 1)
      {
#ifdef __MINGW32__
	if (ugo[0] || honor_umask)
	  file_mode = (file_mode & ~(_S_IWRITE | _S_IREAD))
		      | (new_mode & (_S_IWRITE | _S_IREAD));
#else
	/* Set '='.  */
	if ((ugo[0] || honor_umask) && !rwxXstugo[6])
	  file_mode = (file_mode & ~(S_ISUID | S_IRUSR | S_IWUSR | S_IXUSR))
		      | (new_mode & (S_ISUID | S_IRUSR | S_IWUSR | S_IXUSR));
	if ((ugo[1] || honor_umask) && !rwxXstugo[7])
	  file_mode = (file_mode & ~(S_ISGID | S_IRGRP | S_IWGRP | S_IXGRP))
		      | (new_mode & (S_ISGID | S_IRGRP | S_IWGRP | S_IXGRP));
	if ((ugo[2] || honor_umask) && !rwxXstugo[8])
	  file_mode = (file_mode & ~(S_IROTH | S_IWOTH | S_IXOTH))
		      | (new_mode & (S_IROTH | S_IWOTH | S_IXOTH));
#ifndef __VXWORKS__
	if (is_dir && rwxXstugo[5])
	  file_mode |= S_ISVTX;
	else if (!is_dir)
	  file_mode &= ~S_ISVTX;
#endif
#endif
      }
    else if (set_mode == 2)
      {
	/* Clear '-'.  */
	file_mode &= ~new_mode;
#if !defined( __MINGW32__) && !defined (__VXWORKS__)
	if (rwxXstugo[5] || !is_dir)
	  file_mode &= ~S_ISVTX;
#endif
      }
    else if (set_mode == 3)
      {
	file_mode |= new_mode;
#if !defined (__MINGW32__) && !defined (__VXWORKS__)
	if (rwxXstugo[5] && is_dir)
	  file_mode |= S_ISVTX;
	else if (!is_dir)
	  file_mode &= ~S_ISVTX;
#endif
      }
  }

  return chmod (file, file_mode);
}
Exemplo n.º 14
0
void
read_f (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
{
  int w, seen_dp, exponent;
  int exponent_sign;
  const char *p;
  char *buffer;
  char *out;
  int seen_int_digit; /* Seen a digit before the decimal point?  */
  int seen_dec_digit; /* Seen a digit after the decimal point?  */

  seen_dp = 0;
  seen_int_digit = 0;
  seen_dec_digit = 0;
  exponent_sign = 1;
  exponent = 0;
  w = f->u.w;

  /* Read in the next block.  */
  p = read_block_form (dtp, &w);
  if (p == NULL)
    return;
  p = eat_leading_spaces (&w, (char*) p);
  if (w == 0)
    goto zero;

  /* In this buffer we're going to re-format the number cleanly to be parsed
     by convert_real in the end; this assures we're using strtod from the
     C library for parsing and thus probably get the best accuracy possible.
     This process may add a '+0.0' in front of the number as well as change the
     exponent because of an implicit decimal point or the like.  Thus allocating
     strlen ("+0.0e-1000") == 10 characters plus one for NUL more than the
     original buffer had should be enough.  */
  buffer = gfc_alloca (w + 11);
  out = buffer;

  /* Optional sign */
  if (*p == '-' || *p == '+')
    {
      if (*p == '-')
	*(out++) = '-';
      ++p;
      --w;
    }

  p = eat_leading_spaces (&w, (char*) p);
  if (w == 0)
    goto zero;

  /* Process the mantissa string.  */
  while (w > 0)
    {
      switch (*p)
	{
	case ',':
	  if (dtp->u.p.current_unit->decimal_status != DECIMAL_COMMA)
	    goto bad_float;
	  /* Fall through.  */
	case '.':
	  if (seen_dp)
	    goto bad_float;
	  if (!seen_int_digit)
	    *(out++) = '0';
	  *(out++) = '.';
	  seen_dp = 1;
	  break;

	case ' ':
	  if (dtp->u.p.blank_status == BLANK_ZERO)
	    {
	      *(out++) = '0';
	      goto found_digit;
	    }
	  else if (dtp->u.p.blank_status == BLANK_NULL)
	    break;
	  else
	    /* TODO: Should we check instead that there are only trailing
	       blanks here, as is done below for exponents?  */
	    goto done;
	  /* Fall through.  */
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
	  *(out++) = *p;
found_digit:
	  if (!seen_dp)
	    seen_int_digit = 1;
	  else
	    seen_dec_digit = 1;
	  break;

	case '-':
	case '+':
	  goto exponent;

	case 'e':
	case 'E':
	case 'd':
	case 'D':
	  ++p;
	  --w;
	  goto exponent;

	default:
	  goto bad_float;
	}

      ++p;
      --w;
    }
  
  /* No exponent has been seen, so we use the current scale factor.  */
  exponent = - dtp->u.p.scale_factor;
  goto done;

  /* At this point the start of an exponent has been found.  */
exponent:
  p = eat_leading_spaces (&w, (char*) p);
  if (*p == '-' || *p == '+')
    {
      if (*p == '-')
	exponent_sign = -1;
      ++p;
      --w;
    }

  /* At this point a digit string is required.  We calculate the value
     of the exponent in order to take account of the scale factor and
     the d parameter before explict conversion takes place.  */

  if (w == 0)
    goto bad_float;

  if (dtp->u.p.blank_status == BLANK_UNSPECIFIED)
    {
      while (w > 0 && isdigit (*p))
	{
	  exponent *= 10;
	  exponent += *p - '0';
	  ++p;
	  --w;
	}
	
      /* Only allow trailing blanks.  */
      while (w > 0)
	{
	  if (*p != ' ')
	    goto bad_float;
	  ++p;
	  --w;
	}
    }    
  else  /* BZ or BN status is enabled.  */
    {
      while (w > 0)
	{
	  if (*p == ' ')
	    {
	      if (dtp->u.p.blank_status == BLANK_ZERO)
		exponent *= 10;
	      else
		assert (dtp->u.p.blank_status == BLANK_NULL);
	    }
	  else if (!isdigit (*p))
	    goto bad_float;
	  else
	    {
	      exponent *= 10;
	      exponent += *p - '0';
	    }

	  ++p;
	  --w;
	}
    }

  exponent *= exponent_sign;

done:
  /* Use the precision specified in the format if no decimal point has been
     seen.  */
  if (!seen_dp)
    exponent -= f->u.real.d;

  /* Output a trailing '0' after decimal point if not yet found.  */
  if (seen_dp && !seen_dec_digit)
    *(out++) = '0';

  /* Print out the exponent to finish the reformatted number.  Maximum 4
     digits for the exponent.  */
  if (exponent != 0)
    {
      int dig;

      *(out++) = 'e';
      if (exponent < 0)
	{
	  *(out++) = '-';
	  exponent = - exponent;
	}

      assert (exponent < 10000);
      for (dig = 3; dig >= 0; --dig)
	{
	  out[dig] = (char) ('0' + exponent % 10);
	  exponent /= 10;
	}
      out += 4;
    }
  *(out++) = '\0';

  /* Do the actual conversion.  */
  convert_real (dtp, dest, buffer, length);

  return;

  /* The value read is zero.  */
zero:
  switch (length)
    {
      case 4:
	*((GFC_REAL_4 *) dest) = 0.0;
	break;

      case 8:
	*((GFC_REAL_8 *) dest) = 0.0;
	break;

#ifdef HAVE_GFC_REAL_10
      case 10:
	*((GFC_REAL_10 *) dest) = 0.0;
	break;
#endif

#ifdef HAVE_GFC_REAL_16
      case 16:
	*((GFC_REAL_16 *) dest) = 0.0;
	break;
#endif

      default:
	internal_error (&dtp->common, "Unsupported real kind during IO");
    }
  return;

bad_float:
  generate_error (&dtp->common, LIBERROR_READ_VALUE,
		  "Bad value during floating point read");
  next_record (dtp, 1);
  return;
}
Exemplo n.º 15
0
void
read_decimal (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
{
  GFC_UINTEGER_LARGEST value, maxv, maxv_10;
  GFC_INTEGER_LARGEST v;
  int w, negative; 
  size_t wu;
  char c, *p;

  wu = f->u.w;

  p = gfc_alloca (wu);

  if (read_block_form (dtp, p, &wu) == FAILURE)
    return;

  w = wu;

  p = eat_leading_spaces (&w, p);
  if (w == 0)
    {
      set_integer (dest, (GFC_INTEGER_LARGEST) 0, length);
      return;
    }

  maxv = max_value (length, 1);
  maxv_10 = maxv / 10;

  negative = 0;
  value = 0;

  switch (*p)
    {
    case '-':
      negative = 1;
      /* Fall through */

    case '+':
      p++;
      if (--w == 0)
	goto bad;
      /* Fall through */

    default:
      break;
    }

  /* At this point we have a digit-string */
  value = 0;

  for (;;)
    {
      c = next_char (dtp, &p, &w);
      if (c == '\0')
	break;
	
      if (c == ' ')
        {
	  if (dtp->u.p.blank_status == BLANK_NULL) continue;
	  if (dtp->u.p.blank_status == BLANK_ZERO) c = '0';
        }
        
      if (c < '0' || c > '9')
	goto bad;

      if (value > maxv_10 && compile_options.range_check == 1)
	goto overflow;

      c -= '0';
      value = 10 * value;

      if (value > maxv - c && compile_options.range_check == 1)
	goto overflow;
      value += c;
    }

  v = value;
  if (negative)
    v = -v;

  set_integer (dest, v, length);
  return;

 bad:
  generate_error (&dtp->common, LIBERROR_READ_VALUE,
		  "Bad value during integer read");
  next_record (dtp, 1);
  return;

 overflow:
  generate_error (&dtp->common, LIBERROR_READ_OVERFLOW,
		  "Value overflowed during integer read");
  next_record (dtp, 1);

}
Exemplo n.º 16
0
Arquivo: open.c Projeto: delkon/gcc
gfc_unit *
new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags * flags)
{
  gfc_unit *u2;
  stream *s;
  char tmpname[5 /* fort. */ + 10 /* digits of unit number */ + 1 /* 0 */];

  /* Change unspecifieds to defaults.  Leave (flags->action ==
     ACTION_UNSPECIFIED) alone so open_external() can set it based on
     what type of open actually works.  */

  if (flags->access == ACCESS_UNSPECIFIED)
    flags->access = ACCESS_SEQUENTIAL;

  if (flags->form == FORM_UNSPECIFIED)
    flags->form = (flags->access == ACCESS_SEQUENTIAL)
      ? FORM_FORMATTED : FORM_UNFORMATTED;

  if (flags->async == ASYNC_UNSPECIFIED)
    flags->async = ASYNC_NO;

  if (flags->status == STATUS_UNSPECIFIED)
    flags->status = STATUS_UNKNOWN;

  /* Checks.  */

  if (flags->delim == DELIM_UNSPECIFIED)
    flags->delim = DELIM_NONE;
  else
    {
      if (flags->form == FORM_UNFORMATTED)
	{
	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
			  "DELIM parameter conflicts with UNFORMATTED form in "
			  "OPEN statement");
	  goto fail;
	}
    }

  if (flags->blank == BLANK_UNSPECIFIED)
    flags->blank = BLANK_NULL;
  else
    {
      if (flags->form == FORM_UNFORMATTED)
	{
	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
			  "BLANK parameter conflicts with UNFORMATTED form in "
			  "OPEN statement");
	  goto fail;
	}
    }

  if (flags->pad == PAD_UNSPECIFIED)
    flags->pad = PAD_YES;
  else
    {
      if (flags->form == FORM_UNFORMATTED)
	{
	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
			  "PAD parameter conflicts with UNFORMATTED form in "
			  "OPEN statement");
	  goto fail;
	}
    }

  if (flags->decimal == DECIMAL_UNSPECIFIED)
    flags->decimal = DECIMAL_POINT;
  else
    {
      if (flags->form == FORM_UNFORMATTED)
	{
	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
			  "DECIMAL parameter conflicts with UNFORMATTED form "
			  "in OPEN statement");
	  goto fail;
	}
    }

  if (flags->encoding == ENCODING_UNSPECIFIED)
    flags->encoding = ENCODING_DEFAULT;
  else
    {
      if (flags->form == FORM_UNFORMATTED)
	{
	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
			  "ENCODING parameter conflicts with UNFORMATTED form in "
			  "OPEN statement");
	  goto fail;
	}
    }

  /* NB: the value for ROUND when it's not specified by the user does not
         have to be PROCESSOR_DEFINED; the standard says that it is
	 processor dependent, and requires that it is one of the
	 possible value (see F2003, 9.4.5.13).  */
  if (flags->round == ROUND_UNSPECIFIED)
    flags->round = ROUND_PROCDEFINED;
  else
    {
      if (flags->form == FORM_UNFORMATTED)
	{
	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
			  "ROUND parameter conflicts with UNFORMATTED form in "
			  "OPEN statement");
	  goto fail;
	}
    }

  if (flags->sign == SIGN_UNSPECIFIED)
    flags->sign = SIGN_PROCDEFINED;
  else
    {
      if (flags->form == FORM_UNFORMATTED)
	{
	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
			  "SIGN parameter conflicts with UNFORMATTED form in "
			  "OPEN statement");
	  goto fail;
	}
    }

  if (flags->position != POSITION_ASIS && flags->access == ACCESS_DIRECT)
   {
     generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
                     "ACCESS parameter conflicts with SEQUENTIAL access in "
                     "OPEN statement");
     goto fail;
   }
  else
   if (flags->position == POSITION_UNSPECIFIED)
     flags->position = POSITION_ASIS;

  if (flags->access == ACCESS_DIRECT
      && (opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) == 0)
    {
      generate_error (&opp->common, LIBERROR_MISSING_OPTION,
		      "Missing RECL parameter in OPEN statement");
      goto fail;
    }

  if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) && opp->recl_in <= 0)
    {
      generate_error (&opp->common, LIBERROR_BAD_OPTION,
		      "RECL parameter is non-positive in OPEN statement");
      goto fail;
    }

  switch (flags->status)
    {
    case STATUS_SCRATCH:
      if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
	{
	  opp->file = NULL;
	  break;
	}

      generate_error (&opp->common, LIBERROR_BAD_OPTION,
		      "FILE parameter must not be present in OPEN statement");
      goto fail;

    case STATUS_OLD:
    case STATUS_NEW:
    case STATUS_REPLACE:
    case STATUS_UNKNOWN:
      if ((opp->common.flags & IOPARM_OPEN_HAS_FILE))
	break;

      opp->file = tmpname;
      opp->file_len = snprintf(opp->file, sizeof (tmpname), "fort.%d", 
			       (int) opp->common.unit);
      break;

    default:
      internal_error (&opp->common, "new_unit(): Bad status");
    }

  /* Make sure the file isn't already open someplace else.
     Do not error if opening file preconnected to stdin, stdout, stderr.  */

  u2 = NULL;
  if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) != 0)
    u2 = find_file (opp->file, opp->file_len);
  if (u2 != NULL
      && (options.stdin_unit < 0 || u2->unit_number != options.stdin_unit)
      && (options.stdout_unit < 0 || u2->unit_number != options.stdout_unit)
      && (options.stderr_unit < 0 || u2->unit_number != options.stderr_unit))
    {
      unlock_unit (u2);
      generate_error (&opp->common, LIBERROR_ALREADY_OPEN, NULL);
      goto cleanup;
    }

  if (u2 != NULL)
    unlock_unit (u2);

  /* Open file.  */

  s = open_external (opp, flags);
  if (s == NULL)
    {
      char *path, *msg;
      size_t msglen;
      path = (char *) gfc_alloca (opp->file_len + 1);
      msglen = opp->file_len + 51;
      msg = (char *) gfc_alloca (msglen);
      unpack_filename (path, opp->file, opp->file_len);

      switch (errno)
	{
	case ENOENT: 
	  snprintf (msg, msglen, "File '%s' does not exist", path);
	  break;

	case EEXIST:
	  snprintf (msg, msglen, "File '%s' already exists", path);
	  break;

	case EACCES:
	  snprintf (msg, msglen, 
		    "Permission denied trying to open file '%s'", path);
	  break;

	case EISDIR:
	  snprintf (msg, msglen, "'%s' is a directory", path);
	  break;

	default:
	  msg = NULL;
	}

      generate_error (&opp->common, LIBERROR_OS, msg);
      goto cleanup;
    }

  if (flags->status == STATUS_NEW || flags->status == STATUS_REPLACE)
    flags->status = STATUS_OLD;

  /* Create the unit structure.  */

  u->file = xmalloc (opp->file_len);
  if (u->unit_number != opp->common.unit)
    internal_error (&opp->common, "Unit number changed");
  u->s = s;
  u->flags = *flags;
  u->read_bad = 0;
  u->endfile = NO_ENDFILE;
  u->last_record = 0;
  u->current_record = 0;
  u->mode = READING;
  u->maxrec = 0;
  u->bytes_left = 0;
  u->saved_pos = 0;

  if (flags->position == POSITION_APPEND)
    {
      if (sseek (u->s, 0, SEEK_END) < 0)
	generate_error (&opp->common, LIBERROR_OS, NULL);
      u->endfile = AT_ENDFILE;
    }

  /* Unspecified recl ends up with a processor dependent value.  */

  if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
    {
      u->flags.has_recl = 1;
      u->recl = opp->recl_in;
      u->recl_subrecord = u->recl;
      u->bytes_left = u->recl;
    }
  else
    {
      u->flags.has_recl = 0;
      u->recl = max_offset;
      if (compile_options.max_subrecord_length)
	{
	  u->recl_subrecord = compile_options.max_subrecord_length;
	}
      else
	{
	  switch (compile_options.record_marker)
	    {
	    case 0:
	      /* Fall through */
	    case sizeof (GFC_INTEGER_4):
	      u->recl_subrecord = GFC_MAX_SUBRECORD_LENGTH;
	      break;

	    case sizeof (GFC_INTEGER_8):
	      u->recl_subrecord = max_offset - 16;
	      break;

	    default:
	      runtime_error ("Illegal value for record marker");
	      break;
	    }
	}
    }

  /* If the file is direct access, calculate the maximum record number
     via a division now instead of letting the multiplication overflow
     later.  */

  if (flags->access == ACCESS_DIRECT)
    u->maxrec = max_offset / u->recl;
  
  if (flags->access == ACCESS_STREAM)
    {
      u->maxrec = max_offset;
      u->recl = 1;
      u->bytes_left = 1;
      u->strm_pos = stell (u->s) + 1;
    }

  memmove (u->file, opp->file, opp->file_len);
  u->file_len = opp->file_len;

  /* Curiously, the standard requires that the
     position specifier be ignored for new files so a newly connected
     file starts out at the initial point.  We still need to figure
     out if the file is at the end or not.  */

  test_endfile (u);

  if (flags->status == STATUS_SCRATCH && opp->file != NULL)
    free (opp->file);
    
  if (flags->form == FORM_FORMATTED)
    {
      if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
        fbuf_init (u, u->recl);
      else
        fbuf_init (u, 0);
    }
  else
    u->fbuf = NULL;

    
    
  return u;

 cleanup:

  /* Free memory associated with a temporary filename.  */

  if (flags->status == STATUS_SCRATCH && opp->file != NULL)
    free (opp->file);

 fail:

  close_unit (u);
  return NULL;
}
Exemplo n.º 17
0
static void
stat_i4_sub_0 (char *name, gfc_array_i4 *sarray, GFC_INTEGER_4 *status,
	       gfc_charlen_type name_len, int is_lstat __attribute__ ((unused)))
{
  int val;
  char *str;
  struct stat sb;

  /* If the rank of the array is not 1, abort.  */
  if (GFC_DESCRIPTOR_RANK (sarray) != 1)
    runtime_error ("Array rank of SARRAY is not 1.");

  /* If the array is too small, abort.  */
  if (sarray->dim[0].ubound + 1 - sarray->dim[0].lbound < 13)
    runtime_error ("Array size of SARRAY is too small.");

  /* Trim trailing spaces from name.  */
  while (name_len > 0 && name[name_len - 1] == ' ')
    name_len--;

  /* Make a null terminated copy of the string.  */
  str = gfc_alloca (name_len + 1);
  memcpy (str, name, name_len);
  str[name_len] = '\0';

  /* On platforms that don't provide lstat(), we use stat() instead.  */
#ifdef HAVE_LSTAT
  if (is_lstat)
    val = lstat(str, &sb);
  else
#endif
    val = stat(str, &sb);

  if (val == 0)
    {
      /* Device ID  */
      sarray->data[0 * sarray->dim[0].stride] = sb.st_dev;

      /* Inode number  */
      sarray->data[1 * sarray->dim[0].stride] = sb.st_ino;

      /* File mode  */
      sarray->data[2 * sarray->dim[0].stride] = sb.st_mode;

      /* Number of (hard) links  */
      sarray->data[3 * sarray->dim[0].stride] = sb.st_nlink;

      /* Owner's uid  */
      sarray->data[4 * sarray->dim[0].stride] = sb.st_uid;

      /* Owner's gid  */
      sarray->data[5 * sarray->dim[0].stride] = sb.st_gid;

      /* ID of device containing directory entry for file (0 if not available) */
#if HAVE_STRUCT_STAT_ST_RDEV
      sarray->data[6 * sarray->dim[0].stride] = sb.st_rdev;
#else
      sarray->data[6 * sarray->dim[0].stride] = 0;
#endif

      /* File size (bytes)  */
      sarray->data[7 * sarray->dim[0].stride] = sb.st_size;

      /* Last access time  */
      sarray->data[8 * sarray->dim[0].stride] = sb.st_atime;

      /* Last modification time  */
      sarray->data[9 * sarray->dim[0].stride] = sb.st_mtime;

      /* Last file status change time  */
      sarray->data[10 * sarray->dim[0].stride] = sb.st_ctime;

      /* Preferred I/O block size (-1 if not available)  */
#if HAVE_STRUCT_STAT_ST_BLKSIZE
      sarray->data[11 * sarray->dim[0].stride] = sb.st_blksize;
#else
      sarray->data[11 * sarray->dim[0].stride] = -1;
#endif

      /* Number of blocks allocated (-1 if not available)  */
#if HAVE_STRUCT_STAT_ST_BLOCKS
      sarray->data[12 * sarray->dim[0].stride] = sb.st_blocks;
#else
      sarray->data[12 * sarray->dim[0].stride] = -1;
#endif
    }

  if (status != NULL)
    *status = (val == 0) ? 0 : errno;
}
Exemplo n.º 18
0
Arquivo: env.c Projeto: Alexpux/GCC
void
get_environment_variable_i4 (char *name, char *value, GFC_INTEGER_4 *length,
			     GFC_INTEGER_4 *status, GFC_LOGICAL_4 *trim_name,
			     gfc_charlen_type name_len,
			     gfc_charlen_type value_len)
{
  int stat = GFC_SUCCESS, res_len = 0;
  char *name_nt;
  char *res;

  if (name == NULL)
    runtime_error ("Name is required for get_environment_variable.");

  if (value == NULL && length == NULL && status == NULL && trim_name == NULL)
    return;

  if (name_len < 1)
    runtime_error ("Zero-length string passed as name to "
		   "get_environment_variable.");

  if (value != NULL)
    { 
      if (value_len < 1)
	runtime_error ("Zero-length string passed as value to "
		       "get_environment_variable.");
      else
	memset (value, ' ', value_len); /* Blank the string.  */
    }

  if ((!trim_name) || *trim_name)
    {
      /* Trim trailing spaces from name.  */
      while (name_len > 0 && name[name_len - 1] == ' ')
	name_len--;
    }
  /* Make a null terminated copy of the name.  */
  name_nt = gfc_alloca (name_len + 1);
  memcpy (name_nt, name, name_len);
  name_nt[name_len] = '\0'; 
  
  res = getenv(name_nt);

  if (res == NULL)
    stat = GFC_NAME_DOES_NOT_EXIST;
  else
    {
      res_len = strlen(res);
      if (value != NULL)
	{
	  if (value_len < res_len)
	    {
	      memcpy (value, res, value_len);
	      stat = GFC_VALUE_TOO_SHORT;
	    }
	  else
	    memcpy (value, res, res_len);
	}
    }

  if (status != NULL)
    *status = stat;

  if (length != NULL)
    *length = res_len;
}
Exemplo n.º 19
0
void
read_f (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
{
  size_t wu;
  int w, seen_dp, exponent;
  int exponent_sign, val_sign;
  int ndigits;
  int edigits;
  int i;
  char *p, *buffer;
  char *digits;
  char scratch[SCRATCH_SIZE];

  val_sign = 1;
  seen_dp = 0;
  wu = f->u.w;

  p = gfc_alloca (wu);

  if (read_block_form (dtp, p, &wu) == FAILURE)
    return;

  w = wu;

  p = eat_leading_spaces (&w, p);
  if (w == 0)
    goto zero;

  /* Optional sign */

  if (*p == '-' || *p == '+')
    {
      if (*p == '-')
        val_sign = -1;
      p++;
      w--;
    }

  exponent_sign = 1;
  p = eat_leading_spaces (&w, p);
  if (w == 0)
    goto zero;

  /* A digit, a '.' or a exponent character ('e', 'E', 'd' or 'D')
     is required at this point */

  if (!isdigit (*p) && *p != '.' && *p != ',' && *p != 'd' && *p != 'D'
      && *p != 'e' && *p != 'E')
    goto bad_float;

  /* Remember the position of the first digit.  */
  digits = p;
  ndigits = 0;

  /* Scan through the string to find the exponent.  */
  while (w > 0)
    {
      switch (*p)
	{
	case ',':
	  if (dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA
               && *p == ',')
	    *p = '.';
	  else
	    goto bad_float;
	  /* Fall through */
	case '.':
	  if (seen_dp)
	    goto bad_float;
	  seen_dp = 1;
	  /* Fall through */

	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
	case ' ':
	  ndigits++;
	  p++;
	  w--;
	  break;

	case '-':
	  exponent_sign = -1;
	  /* Fall through */

	case '+':
	  p++;
	  w--;
	  goto exp2;

	case 'd':
	case 'e':
	case 'D':
	case 'E':
	  p++;
	  w--;
	  goto exp1;

	default:
	  goto bad_float;
	}
    }

  /* No exponent has been seen, so we use the current scale factor */
  exponent = -dtp->u.p.scale_factor;
  goto done;

 bad_float:
  generate_error (&dtp->common, LIBERROR_READ_VALUE,
		  "Bad value during floating point read");
  next_record (dtp, 1);
  return;

  /* The value read is zero */
 zero:
  switch (length)
    {
      case 4:
	*((GFC_REAL_4 *) dest) = 0;
	break;

      case 8:
	*((GFC_REAL_8 *) dest) = 0;
	break;

#ifdef HAVE_GFC_REAL_10
      case 10:
	*((GFC_REAL_10 *) dest) = 0;
	break;
#endif

#ifdef HAVE_GFC_REAL_16
      case 16:
	*((GFC_REAL_16 *) dest) = 0;
	break;
#endif

      default:
	internal_error (&dtp->common, "Unsupported real kind during IO");
    }
  return;

  /* At this point the start of an exponent has been found */
 exp1:
  while (w > 0 && *p == ' ')
    {
      w--;
      p++;
    }

  switch (*p)
    {
    case '-':
      exponent_sign = -1;
      /* Fall through */

    case '+':
      p++;
      w--;
      break;
    }

  if (w == 0)
    goto bad_float;

  /* At this point a digit string is required.  We calculate the value
     of the exponent in order to take account of the scale factor and
     the d parameter before explict conversion takes place. */
 exp2:
  /* Normal processing of exponent */
  exponent = 0;
  if (dtp->u.p.blank_status == BLANK_UNSPECIFIED)
    {
      while (w > 0 && isdigit (*p))
        {
          exponent = 10 * exponent + *p - '0';
          p++;
          w--;
        }
        
      /* Only allow trailing blanks */

      while (w > 0)
        {
          if (*p != ' ')
	    goto bad_float;
          p++;
          w--;
        }
    }    
  else  /* BZ or BN status is enabled */
    {
      while (w > 0)
        {
          if (*p == ' ')
            {
	      if (dtp->u.p.blank_status == BLANK_ZERO) *p = '0';
	      if (dtp->u.p.blank_status == BLANK_NULL)
                {
                  p++;
                  w--;
                  continue;
                }
            }
          else if (!isdigit (*p))
            goto bad_float;

          exponent = 10 * exponent + *p - '0';
          p++;
          w--;
        }
    }

  exponent = exponent * exponent_sign;

 done:
  /* Use the precision specified in the format if no decimal point has been
     seen.  */
  if (!seen_dp)
    exponent -= f->u.real.d;

  if (exponent > 0)
    {
      edigits = 2;
      i = exponent;
    }
  else
    {
      edigits = 3;
      i = -exponent;
    }

  while (i >= 10)
    {
      i /= 10;
      edigits++;
    }

  i = ndigits + edigits + 1;
  if (val_sign < 0)
    i++;

  if (i < SCRATCH_SIZE) 
    buffer = scratch;
  else
    buffer = get_mem (i);

  /* Reformat the string into a temporary buffer.  As we're using atof it's
     easiest to just leave the decimal point in place.  */
  p = buffer;
  if (val_sign < 0)
    *(p++) = '-';
  for (; ndigits > 0; ndigits--)
    {
      if (*digits == ' ')
        {
	  if (dtp->u.p.blank_status == BLANK_ZERO) *digits = '0';
	  if (dtp->u.p.blank_status == BLANK_NULL)
            {
              digits++;
              continue;
            } 
        }
      *p = *digits;
      p++;
      digits++;
    }
  *(p++) = 'e';
  sprintf (p, "%d", exponent);

  /* Do the actual conversion.  */
  convert_real (dtp, dest, buffer, length);

  if (buffer != scratch)
     free_mem (buffer);

}