(root)/
binutils-2.41/
gas/
input-file.c
       1  /* input_file.c - Deal with Input Files -
       2     Copyright (C) 1987-2023 Free Software Foundation, Inc.
       3  
       4     This file is part of GAS, the GNU Assembler.
       5  
       6     GAS is free software; you can redistribute it and/or modify
       7     it under the terms of the GNU General Public License as published by
       8     the Free Software Foundation; either version 3, or (at your option)
       9     any later version.
      10  
      11     GAS is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14     GNU General Public License for more details.
      15  
      16     You should have received a copy of the GNU General Public License
      17     along with GAS; see the file COPYING.  If not, write to the Free
      18     Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
      19     02110-1301, USA.  */
      20  
      21  /* Confines all details of reading source bytes to this module.
      22     All O/S specific crocks should live here.
      23     What we lose in "efficiency" we gain in modularity.
      24     Note we don't need to #include the "as.h" file. No common coupling!  */
      25  
      26  #include "as.h"
      27  #include "input-file.h"
      28  #include "safe-ctype.h"
      29  
      30  /* This variable is non-zero if the file currently being read should be
      31     preprocessed by app.  It is zero if the file can be read straight in.  */
      32  int preprocess = 0;
      33  
      34  /* This code opens a file, then delivers BUFFER_SIZE character
      35     chunks of the file on demand.
      36     BUFFER_SIZE is supposed to be a number chosen for speed.
      37     The caller only asks once what BUFFER_SIZE is, and asks before
      38     the nature of the input files (if any) is known.  */
      39  
      40  #define BUFFER_SIZE (32 * 1024)
      41  
      42  /* We use static data: the data area is not sharable.  */
      43  
      44  static FILE *f_in;
      45  static const char *file_name;
      46  
      47  /* Struct for saving the state of this module for file includes.  */
      48  struct saved_file
      49    {
      50      FILE * f_in;
      51      const char * file_name;
      52      int    preprocess;
      53      char * app_save;
      54    };
      55  
      56  /* These hooks accommodate most operating systems.  */
      57  
      58  void
      59  input_file_begin (void)
      60  {
      61    f_in = (FILE *) 0;
      62  }
      63  
      64  void
      65  input_file_end (void)
      66  {
      67  }
      68  
      69  /* Return BUFFER_SIZE.  */
      70  size_t
      71  input_file_buffer_size (void)
      72  {
      73    return (BUFFER_SIZE);
      74  }
      75  
      76  /* Push the state of our input, returning a pointer to saved info that
      77     can be restored with input_file_pop ().  */
      78  
      79  char *
      80  input_file_push (void)
      81  {
      82    struct saved_file *saved;
      83  
      84    saved = XNEW (struct saved_file);
      85  
      86    saved->f_in = f_in;
      87    saved->file_name = file_name;
      88    saved->preprocess = preprocess;
      89    if (preprocess)
      90      saved->app_save = app_push ();
      91  
      92    /* Initialize for new file.  */
      93    input_file_begin ();
      94  
      95    return (char *) saved;
      96  }
      97  
      98  void
      99  input_file_pop (char *arg)
     100  {
     101    struct saved_file *saved = (struct saved_file *) arg;
     102  
     103    input_file_end ();		/* Close out old file.  */
     104  
     105    f_in = saved->f_in;
     106    file_name = saved->file_name;
     107    preprocess = saved->preprocess;
     108    if (preprocess)
     109      app_pop (saved->app_save);
     110  
     111    free (arg);
     112  }
     113  
     114  /* Open the specified file, "" means stdin.  Filename must not be null.  */
     115  
     116  void
     117  input_file_open (const char *filename,
     118  		 int pre)
     119  {
     120    int c;
     121    char buf[80];
     122  
     123    preprocess = pre;
     124  
     125    gas_assert (filename != 0);	/* Filename may not be NULL.  */
     126    if (filename[0])
     127      {
     128        f_in = fopen (filename, FOPEN_RT);
     129        file_name = filename;
     130      }
     131    else
     132      {
     133        /* Use stdin for the input file.  */
     134        f_in = stdin;
     135        /* For error messages.  */
     136        file_name = _("{standard input}");
     137      }
     138  
     139    if (f_in == NULL)
     140      {
     141        as_bad (_("can't open %s for reading: %s"),
     142  	      file_name, xstrerror (errno));
     143        return;
     144      }
     145  
     146    c = getc (f_in);
     147  
     148    if (ferror (f_in))
     149      {
     150        as_bad (_("can't read from %s: %s"),
     151  	      file_name, xstrerror (errno));
     152  
     153        fclose (f_in);
     154        f_in = NULL;
     155        return;
     156      }
     157  
     158    /* Check for an empty input file.  */
     159    if (feof (f_in))
     160      {
     161        fclose (f_in);
     162        f_in = NULL;
     163        return;
     164      }
     165    gas_assert (c != EOF);
     166  
     167    if (c == '#')
     168      {
     169        /* Begins with comment, may not want to preprocess.  */
     170        c = getc (f_in);
     171        if (c == 'N')
     172  	{
     173  	  char *p = fgets (buf, sizeof (buf), f_in);
     174  	  if (p && startswith (p, "O_APP") && ISSPACE (p[5]))
     175  	    preprocess = 0;
     176  	  if (!p || !strchr (p, '\n'))
     177  	    ungetc ('#', f_in);
     178  	  else
     179  	    ungetc ('\n', f_in);
     180  	}
     181        else if (c == 'A')
     182  	{
     183  	  char *p = fgets (buf, sizeof (buf), f_in);
     184  	  if (p && startswith (p, "PP") && ISSPACE (p[2]))
     185  	    preprocess = 1;
     186  	  if (!p || !strchr (p, '\n'))
     187  	    ungetc ('#', f_in);
     188  	  else
     189  	    ungetc ('\n', f_in);
     190  	}
     191        else if (c == '\n')
     192  	ungetc ('\n', f_in);
     193        else
     194  	ungetc ('#', f_in);
     195      }
     196    else
     197      ungetc (c, f_in);
     198  }
     199  
     200  /* Close input file.  */
     201  
     202  void
     203  input_file_close (void)
     204  {
     205    /* Don't close a null file pointer.  */
     206    if (f_in != NULL)
     207      fclose (f_in);
     208  
     209    f_in = 0;
     210  }
     211  
     212  /* This function is passed to do_scrub_chars.  */
     213  
     214  static size_t
     215  input_file_get (char *buf, size_t buflen)
     216  {
     217    size_t size;
     218  
     219    if (feof (f_in))
     220      return 0;
     221  
     222    size = fread (buf, sizeof (char), buflen, f_in);
     223    if (ferror (f_in))
     224      as_bad (_("can't read from %s: %s"), file_name, xstrerror (errno));
     225    return size;
     226  }
     227  
     228  /* Read a buffer from the input file.  */
     229  
     230  char *
     231  input_file_give_next_buffer (char *where /* Where to place 1st character of new buffer.  */)
     232  {
     233    char *return_value;		/* -> Last char of what we read, + 1.  */
     234    size_t size;
     235  
     236    if (f_in == (FILE *) 0)
     237      return 0;
     238    /* fflush (stdin); could be done here if you want to synchronise
     239       stdin and stdout, for the case where our input file is stdin.
     240       Since the assembler shouldn't do any output to stdout, we
     241       don't bother to synch output and input.  */
     242    if (preprocess)
     243      size = do_scrub_chars (input_file_get, where, BUFFER_SIZE);
     244    else
     245      size = input_file_get (where, BUFFER_SIZE);
     246  
     247    if (size)
     248      return_value = where + size;
     249    else
     250      {
     251        if (fclose (f_in))
     252  	as_warn (_("can't close %s: %s"), file_name, xstrerror (errno));
     253  
     254        f_in = (FILE *) 0;
     255        return_value = 0;
     256      }
     257  
     258    return return_value;
     259  }