Home | History | Annotate | Download | only in gas
      1 /* input_file.c - Deal with Input Files -
      2    Copyright (C) 1987-2016 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 = (FILE *) 0;
     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 (c == '#')
    170     {
    171       /* Begins with comment, may not want to preprocess.  */
    172       c = getc (f_in);
    173       if (c == 'N')
    174 	{
    175 	  if (fgets (buf, sizeof (buf), f_in)
    176 	      && !strncmp (buf, "O_APP", 5) && ISSPACE (buf[5]))
    177 	    preprocess = 0;
    178 	  if (!strchr (buf, '\n'))
    179 	    ungetc ('#', f_in);	/* It was longer.  */
    180 	  else
    181 	    ungetc ('\n', f_in);
    182 	}
    183       else if (c == 'A')
    184 	{
    185 	  if (fgets (buf, sizeof (buf), f_in)
    186 	      && !strncmp (buf, "PP", 2) && ISSPACE (buf[2]))
    187 	    preprocess = 1;
    188 	  if (!strchr (buf, '\n'))
    189 	    ungetc ('#', f_in);
    190 	  else
    191 	    ungetc ('\n', f_in);
    192 	}
    193       else if (c == '\n')
    194 	ungetc ('\n', f_in);
    195       else
    196 	ungetc ('#', f_in);
    197     }
    198   else
    199     ungetc (c, f_in);
    200 }
    201 
    202 /* Close input file.  */
    203 
    204 void
    205 input_file_close (void)
    206 {
    207   /* Don't close a null file pointer.  */
    208   if (f_in != NULL)
    209     fclose (f_in);
    210 
    211   f_in = 0;
    212 }
    213 
    214 /* This function is passed to do_scrub_chars.  */
    215 
    216 static size_t
    217 input_file_get (char *buf, size_t buflen)
    218 {
    219   size_t size;
    220 
    221   if (feof (f_in))
    222     return 0;
    223 
    224   size = fread (buf, sizeof (char), buflen, f_in);
    225   if (ferror (f_in))
    226     as_bad (_("can't read from %s: %s"), file_name, xstrerror (errno));
    227   return size;
    228 }
    229 
    230 /* Read a buffer from the input file.  */
    231 
    232 char *
    233 input_file_give_next_buffer (char *where /* Where to place 1st character of new buffer.  */)
    234 {
    235   char *return_value;		/* -> Last char of what we read, + 1.  */
    236   size_t size;
    237 
    238   if (f_in == (FILE *) 0)
    239     return 0;
    240   /* fflush (stdin); could be done here if you want to synchronise
    241      stdin and stdout, for the case where our input file is stdin.
    242      Since the assembler shouldn't do any output to stdout, we
    243      don't bother to synch output and input.  */
    244   if (preprocess)
    245     size = do_scrub_chars (input_file_get, where, BUFFER_SIZE);
    246   else
    247     size = input_file_get (where, BUFFER_SIZE);
    248 
    249   if (size)
    250     return_value = where + size;
    251   else
    252     {
    253       if (fclose (f_in))
    254 	as_warn (_("can't close %s: %s"), file_name, xstrerror (errno));
    255 
    256       f_in = (FILE *) 0;
    257       return_value = 0;
    258     }
    259 
    260   return return_value;
    261 }
    262