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