⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 list_read.c

📁 gcc-fortran,linux使用fortran的编译软件。很好用的。
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.   Contributed by Andy Vaught   Namelist input contributed by Paul ThomasThis file is part of the GNU Fortran 95 runtime library (libgfortran).Libgfortran is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.In addition to the permissions in the GNU General Public License, theFree Software Foundation gives you unlimited permission to link thecompiled version of this file into combinations with other programs,and to distribute those combinations without any restriction comingfrom the use of this file.  (The General Public License restrictionsdo apply in other respects; for example, they cover modification ofthe file, and distribution when not linked into a combineexecutable.)Libgfortran is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with Libgfortran; see the file COPYING.  If not, write tothe Free Software Foundation, 51 Franklin Street, Fifth Floor,Boston, MA 02110-1301, USA.  */#include "config.h"#include <string.h>#include <ctype.h>#include "libgfortran.h"#include "io.h"/* List directed input.  Several parsing subroutines are practically   reimplemented from formatted input, the reason being that there are   all kinds of small differences between formatted and list directed   parsing.  *//* Subroutines for reading characters from the input.  Because a   repeat count is ambiguous with an integer, we have to read the   whole digit string before seeing if there is a '*' which signals   the repeat count.  Since we can have a lot of potential leading   zeros, we have to be able to back up by arbitrary amount.  Because   the input might not be seekable, we have to buffer the data   ourselves.  */#define CASE_DIGITS   case '0': case '1': case '2': case '3': case '4': \                      case '5': case '6': case '7': case '8': case '9'#define CASE_SEPARATORS  case ' ': case ',': case '/': case '\n': case '\t': \                         case '\r'/* This macro assumes that we're operating on a variable.  */#define is_separator(c) (c == '/' ||  c == ',' || c == '\n' || c == ' ' \                         || c == '\t' || c == '\r')/* Maximum repeat count.  Less than ten times the maximum signed int32.  */#define MAX_REPEAT 200000000/* Save a character to a string buffer, enlarging it as necessary.  */static voidpush_char (st_parameter_dt *dtp, char c){  char *new;  if (dtp->u.p.saved_string == NULL)    {      if (dtp->u.p.scratch == NULL)	dtp->u.p.scratch = get_mem (SCRATCH_SIZE);      dtp->u.p.saved_string = dtp->u.p.scratch;      memset (dtp->u.p.saved_string, 0, SCRATCH_SIZE);      dtp->u.p.saved_length = SCRATCH_SIZE;      dtp->u.p.saved_used = 0;    }  if (dtp->u.p.saved_used >= dtp->u.p.saved_length)    {      dtp->u.p.saved_length = 2 * dtp->u.p.saved_length;      new = get_mem (2 * dtp->u.p.saved_length);      memset (new, 0, 2 * dtp->u.p.saved_length);      memcpy (new, dtp->u.p.saved_string, dtp->u.p.saved_used);      if (dtp->u.p.saved_string != dtp->u.p.scratch)	free_mem (dtp->u.p.saved_string);      dtp->u.p.saved_string = new;    }  dtp->u.p.saved_string[dtp->u.p.saved_used++] = c;}/* Free the input buffer if necessary.  */static voidfree_saved (st_parameter_dt *dtp){  if (dtp->u.p.saved_string == NULL)    return;  if (dtp->u.p.saved_string != dtp->u.p.scratch)    free_mem (dtp->u.p.saved_string);  dtp->u.p.saved_string = NULL;  dtp->u.p.saved_used = 0;}static charnext_char (st_parameter_dt *dtp){  int length;  gfc_offset record;  char c, *p;  if (dtp->u.p.last_char != '\0')    {      dtp->u.p.at_eol = 0;      c = dtp->u.p.last_char;      dtp->u.p.last_char = '\0';      goto done;    }  length = 1;  /* Handle the end-of-record condition for internal array unit */  if (is_array_io(dtp) && dtp->u.p.current_unit->bytes_left == 0)    {      c = '\n';      record = next_array_record (dtp, dtp->u.p.current_unit->ls);      /* Check for "end-of-file condition */            if (record == 0)        longjmp (*dtp->u.p.eof_jump, 1);      record *= dtp->u.p.current_unit->recl;            if (sseek (dtp->u.p.current_unit->s, record) == FAILURE)	longjmp (*dtp->u.p.eof_jump, 1);      dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;      goto done;    }  /* Get the next character and handle end-of-record conditions */  p = salloc_r (dtp->u.p.current_unit->s, &length);  if (is_internal_unit(dtp))    {      if (is_array_io(dtp))	{	  /* End of record is handled in the next pass through, above.  The	     check for NULL here is cautionary. */	  if (p == NULL)	    {	      generate_error (&dtp->common, ERROR_INTERNAL_UNIT, NULL);	      return '\0';	    }	  dtp->u.p.current_unit->bytes_left--;	  c = *p;	}      else	{	  if (p == NULL)	    longjmp (*dtp->u.p.eof_jump, 1);	  if (length == 0)	    c = '\n';	  else	    c = *p;	}    }  else    {      if (p == NULL)	{	  generate_error (&dtp->common, ERROR_OS, NULL);	  return '\0';	}      if (length == 0)	longjmp (*dtp->u.p.eof_jump, 1);      c = *p;    }done:  dtp->u.p.at_eol = (c == '\n' || c == '\r');  return c;}/* Push a character back onto the input.  */static voidunget_char (st_parameter_dt *dtp, char c){  dtp->u.p.last_char = c;}/* Skip over spaces in the input.  Returns the nonspace character that   terminated the eating and also places it back on the input.  */static chareat_spaces (st_parameter_dt *dtp){  char c;  do    {      c = next_char (dtp);    }  while (c == ' ' || c == '\t');  unget_char (dtp, c);  return c;}/* Skip over a separator.  Technically, we don't always eat the whole   separator.  This is because if we've processed the last input item,   then a separator is unnecessary.  Plus the fact that operating   systems usually deliver console input on a line basis.   The upshot is that if we see a newline as part of reading a   separator, we stop reading.  If there are more input items, we   continue reading the separator with finish_separator() which takes   care of the fact that we may or may not have seen a comma as part   of the separator.  */static voideat_separator (st_parameter_dt *dtp){  char c, n;  eat_spaces (dtp);  dtp->u.p.comma_flag = 0;  c = next_char (dtp);  switch (c)    {    case ',':      dtp->u.p.comma_flag = 1;      eat_spaces (dtp);      break;    case '/':      dtp->u.p.input_complete = 1;      break;    case '\r':      n = next_char(dtp);      if (n == '\n')	dtp->u.p.at_eol = 1;      else        {	  unget_char (dtp, n);	  unget_char (dtp, c);        }       break;    case '\n':      dtp->u.p.at_eol = 1;      break;    case '!':      if (dtp->u.p.namelist_mode)	{			/* Eat a namelist comment.  */	  do	    c = next_char (dtp);	  while (c != '\n');	  break;	}      /* Fall Through...  */    default:      unget_char (dtp, c);      break;    }}/* Finish processing a separator that was interrupted by a newline.   If we're here, then another data item is present, so we finish what   we started on the previous line.  */static voidfinish_separator (st_parameter_dt *dtp){  char c; restart:  eat_spaces (dtp);  c = next_char (dtp);  switch (c)    {    case ',':      if (dtp->u.p.comma_flag)	unget_char (dtp, c);      else	{	  c = eat_spaces (dtp);	  if (c == '\n' || c == '\r')	    goto restart;	}      break;    case '/':      dtp->u.p.input_complete = 1;      if (!dtp->u.p.namelist_mode) next_record (dtp, 0);      break;    case '\n':    case '\r':      goto restart;    case '!':      if (dtp->u.p.namelist_mode)	{	  do	    c = next_char (dtp);	  while (c != '\n');	  goto restart;	}    default:      unget_char (dtp, c);      break;    }}/* This function is needed to catch bad conversions so that namelist can   attempt to see if dtp->u.p.saved_string contains a new object name rather   than a bad value.  */static intnml_bad_return (st_parameter_dt *dtp, char c){  if (dtp->u.p.namelist_mode)    {      dtp->u.p.nml_read_error = 1;      unget_char (dtp, c);      return 1;    }  return 0;}/* Convert an unsigned string to an integer.  The length value is -1   if we are working on a repeat count.  Returns nonzero if we have a   range problem.  As a side effect, frees the dtp->u.p.saved_string.  */static intconvert_integer (st_parameter_dt *dtp, int length, int negative){  char c, *buffer, message[100];  int m;  GFC_INTEGER_LARGEST v, max, max10;  buffer = dtp->u.p.saved_string;  v = 0;  max = (length == -1) ? MAX_REPEAT : max_value (length, 1);  max10 = max / 10;  for (;;)    {      c = *buffer++;      if (c == '\0')	break;      c -= '0';      if (v > max10)	goto overflow;      v = 10 * v;      if (v > max - c)	goto overflow;      v += c;    }  m = 0;  if (length != -1)    {      if (negative)	v = -v;      set_integer (dtp->u.p.value, v, length);    }  else    {      dtp->u.p.repeat_count = v;      if (dtp->u.p.repeat_count == 0)	{	  st_sprintf (message, "Zero repeat count in item %d of list input",		      dtp->u.p.item_count);	  generate_error (&dtp->common, ERROR_READ_VALUE, message);	  m = 1;	}    }  free_saved (dtp);  return m; overflow:  if (length == -1)    st_sprintf (message, "Repeat count overflow in item %d of list input",		dtp->u.p.item_count);  else    st_sprintf (message, "Integer overflow while reading item %d",		dtp->u.p.item_count);  free_saved (dtp);  generate_error (&dtp->common, ERROR_READ_VALUE, message);  return 1;}/* Parse a repeat count for logical and complex values which cannot   begin with a digit.  Returns nonzero if we are done, zero if we   should continue on.  */static intparse_repeat (st_parameter_dt *dtp){  char c, message[100];  int repeat;  c = next_char (dtp);  switch (c)    {    CASE_DIGITS:      repeat = c - '0';      break;    CASE_SEPARATORS:      unget_char (dtp, c);      eat_separator (dtp);      return 1;    default:      unget_char (dtp, c);      return 0;    }  for (;;)    {      c = next_char (dtp);      switch (c)	{	CASE_DIGITS:	  repeat = 10 * repeat + c - '0';	  if (repeat > MAX_REPEAT)	    {	      st_sprintf (message,			  "Repeat count overflow in item %d of list input",			  dtp->u.p.item_count);	      generate_error (&dtp->common, ERROR_READ_VALUE, message);	      return 1;	    }	  break;	case '*':	  if (repeat == 0)	    {	      st_sprintf (message,			  "Zero repeat count in item %d of list input",			  dtp->u.p.item_count);	      generate_error (&dtp->common, ERROR_READ_VALUE, message);	      return 1;	    }	  goto done;	default:	  goto bad_repeat;	}    } done:  dtp->u.p.repeat_count = repeat;  return 0; bad_repeat:  st_sprintf (message, "Bad repeat count in item %d of list input",	      dtp->u.p.item_count);  generate_error (&dtp->common, ERROR_READ_VALUE, message);  return 1;}/* Read a logical character on the input.  */static voidread_logical (st_parameter_dt *dtp, int length){  char c, message[100];  int v;  if (parse_repeat (dtp))    return;  c = next_char (dtp);  switch (c)    {    case 't':    case 'T':      v = 1;      break;    case 'f':    case 'F':      v = 0;      break;    case '.':      c = next_char (dtp);      switch (c)	{	case 't':	case 'T':	  v = 1;	  break;	case 'f':	case 'F':	  v = 0;	  break;	default:	  goto bad_logical;	}      break;    CASE_SEPARATORS:      unget_char (dtp, c);      eat_separator (dtp);      return;			/* Null value.  */    default:      goto bad_logical;    }  dtp->u.p.saved_type = BT_LOGICAL;  dtp->u.p.saved_length = length;  /* Eat trailing garbage.  */  do    {      c = next_char (dtp);    }  while (!is_separator (c));  unget_char (dtp, c);  eat_separator (dtp);  free_saved (dtp);  set_integer ((int *) dtp->u.p.value, v, length);  return; bad_logical:  if (nml_bad_return (dtp, c))    return;  st_sprintf (message, "Bad logical value while reading item %d",	      dtp->u.p.item_count);  generate_error (&dtp->common, ERROR_READ_VALUE, message);}/* Reading integers is tricky because we can actually be reading a   repeat count.  We have to store the characters in a buffer because   we could be reading an integer that is larger than the default int   used for repeat counts.  */static voidread_integer (st_parameter_dt *dtp, int length){  char c, message[100];  int negative;  negative = 0;  c = next_char (dtp);  switch (c)    {    case '-':      negative = 1;      /* Fall through...  */    case '+':      c = next_char (dtp);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -