Home | History | Annotate | Line # | Download | only in gas
      1 /* input_file.c - Deal with Input Files -
      2    Copyright (C) 1987-2026 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.  */
     58 
     59 void
     60 input_file_begin (void)
     61 {
     62   f_in = NULL;
     63 }
     64 
     65 void
     66 input_file_end (void)
     67 {
     68 }
     69 
     70 /* Return BUFFER_SIZE.  */
     71 size_t
     72 input_file_buffer_size (void)
     73 {
     74   return (BUFFER_SIZE);
     75 }
     76 
     77 /* Push the state of our input, returning a pointer to saved info that
     78    can be restored with input_file_pop ().  */
     79 
     80 char *
     81 input_file_push (void)
     82 {
     83   struct saved_file *saved;
     84 
     85   saved = XNEW (struct saved_file);
     86 
     87   saved->f_in = f_in;
     88   saved->file_name = file_name;
     89   saved->preprocess = preprocess;
     90   if (preprocess)
     91     saved->app_save = app_push ();
     92 
     93   /* Initialize for new file.  */
     94   input_file_begin ();
     95 
     96   return (char *) saved;
     97 }
     98 
     99 void
    100 input_file_pop (char *arg)
    101 {
    102   struct saved_file *saved = (struct saved_file *) arg;
    103 
    104   input_file_end ();		/* Close out old file.  */
    105 
    106   f_in = saved->f_in;
    107   file_name = saved->file_name;
    108   preprocess = saved->preprocess;
    109   if (preprocess)
    110     app_pop (saved->app_save);
    111 
    112   free (arg);
    113 }
    114 
    115 /* Open the specified file, "" means stdin.  Filename must not be null.  */
    117 
    118 void
    119 input_file_open (const char *filename,
    120 		 int pre)
    121 {
    122   int c;
    123   char buf[80];
    124 
    125   preprocess = pre;
    126 
    127   gas_assert (filename != 0);	/* Filename may not be NULL.  */
    128   if (filename[0])
    129     {
    130       f_in = fopen (filename, FOPEN_RT);
    131       file_name = filename;
    132     }
    133   else
    134     {
    135       /* Use stdin for the input file.  */
    136       f_in = stdin;
    137       /* For error messages.  */
    138       file_name = _("{standard input}");
    139     }
    140 
    141   if (f_in == NULL)
    142     {
    143       as_bad (_("can't open %s for reading: %s"),
    144 	      file_name, xstrerror (errno));
    145       return;
    146     }
    147 
    148   c = getc (f_in);
    149 
    150   if (ferror (f_in))
    151     {
    152       as_bad (_("can't read from %s: %s"),
    153 	      file_name, xstrerror (errno));
    154 
    155       fclose (f_in);
    156       f_in = NULL;
    157       return;
    158     }
    159 
    160   /* Check for an empty input file.  */
    161   if (feof (f_in))
    162     {
    163       fclose (f_in);
    164       f_in = NULL;
    165       return;
    166     }
    167   gas_assert (c != EOF);
    168 
    169   if (strchr (line_comment_chars, '#')
    170       ? c == '#'
    171       : c && strchr (line_comment_chars, c))
    172     {
    173       /* Begins with comment, may not want to preprocess.  */
    174       int lead = c;
    175 
    176       c = getc (f_in);
    177       if (c == 'N')
    178 	{
    179 	  char *p = fgets (buf, sizeof (buf), f_in);
    180 	  if (p && startswith (p, "O_APP") && is_end_of_line (p[5]))
    181 	    preprocess = 0;
    182 	  if (!p || !strchr (p, '\n'))
    183 	    ungetc (lead, f_in);
    184 	  else
    185 	    ungetc ('\n', f_in);
    186 	}
    187       else if (c == 'A')
    188 	{
    189 	  char *p = fgets (buf, sizeof (buf), f_in);
    190 	  if (p && startswith (p, "PP") && is_end_of_line (p[2]))
    191 	    preprocess = 1;
    192 	  if (!p || !strchr (p, '\n'))
    193 	    ungetc (lead, f_in);
    194 	  else
    195 	    ungetc ('\n', f_in);
    196 	}
    197       else if (c == '\n')
    198 	ungetc ('\n', f_in);
    199       else
    200 	ungetc (lead, f_in);
    201     }
    202   else
    203     ungetc (c, f_in);
    204 }
    205 
    206 /* Close input file.  */
    207 
    208 void
    209 input_file_close (void)
    210 {
    211   /* Don't close a null file pointer.  */
    212   if (f_in != NULL)
    213     fclose (f_in);
    214 
    215   f_in = 0;
    216 }
    217 
    218 /* This function is passed to do_scrub_chars.  */
    219 
    220 static size_t
    221 input_file_get (char *buf, size_t buflen)
    222 {
    223   size_t size;
    224 
    225   if (feof (f_in))
    226     return 0;
    227 
    228   size = fread (buf, sizeof (char), buflen, f_in);
    229   if (ferror (f_in))
    230     as_bad (_("can't read from %s: %s"), file_name, xstrerror (errno));
    231   return size;
    232 }
    233 
    234 /* Read a buffer from the input file.  */
    235 
    236 char *
    237 input_file_give_next_buffer (char *where /* Where to place 1st character of new buffer.  */)
    238 {
    239   char *return_value;		/* -> Last char of what we read, + 1.  */
    240   size_t size;
    241 
    242   if (f_in == NULL)
    243     return 0;
    244   /* fflush (stdin); could be done here if you want to synchronise
    245      stdin and stdout, for the case where our input file is stdin.
    246      Since the assembler shouldn't do any output to stdout, we
    247      don't bother to synch output and input.  */
    248   if (preprocess)
    249     size = do_scrub_chars (input_file_get, where, BUFFER_SIZE,
    250                            multibyte_handling == multibyte_warn);
    251   else
    252     {
    253       size = input_file_get (where, BUFFER_SIZE);
    254 
    255       if (multibyte_handling == multibyte_warn)
    256 	{
    257 	  const unsigned char *start = (const unsigned char *) where;
    258 
    259 	  (void) scan_for_multibyte_characters (start, start + size,
    260 						true /* Generate warnings */);
    261 	}
    262     }
    263 
    264   if (size)
    265     return_value = where + size;
    266   else
    267     {
    268       if (fclose (f_in))
    269 	as_warn (_("can't close %s: %s"), file_name, xstrerror (errno));
    270 
    271       f_in = NULL;
    272       return_value = 0;
    273     }
    274 
    275   return return_value;
    276 }
    277