Home | History | Annotate | Download | only in gas
      1 /* input_file.c - Deal with Input Files -
      2    Copyright (C) 1987-2014 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 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     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 = (struct saved_file *) xmalloc (sizeof *saved);
     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 void
    117 input_file_open (char *filename, /* "" means use stdin. Must not be 0.  */
    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 	  if (fgets (buf, sizeof (buf), f_in)
    174 	      && !strncmp (buf, "O_APP", 5) && ISSPACE (buf[5]))
    175 	    preprocess = 0;
    176 	  if (!strchr (buf, '\n'))
    177 	    ungetc ('#', f_in);	/* It was longer.  */
    178 	  else
    179 	    ungetc ('\n', f_in);
    180 	}
    181       else if (c == 'A')
    182 	{
    183 	  if (fgets (buf, sizeof (buf), f_in)
    184 	      && !strncmp (buf, "PP", 2) && ISSPACE (buf[2]))
    185 	    preprocess = 1;
    186 	  if (!strchr (buf, '\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 }
    260