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