| /* input_file.c - Deal with Input Files - |
| Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1999, 2000, 2001, 2003 |
| Free Software Foundation, Inc. |
| |
| This file is part of GAS, the GNU Assembler. |
| |
| GAS is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GAS is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GAS; see the file COPYING. If not, write to the Free |
| Software Foundation, 59 Temple Place - Suite 330, Boston, MA |
| 02111-1307, USA. */ |
| |
| /* Confines all details of reading source bytes to this module. |
| All O/S specific crocks should live here. |
| What we lose in "efficiency" we gain in modularity. |
| Note we don't need to #include the "as.h" file. No common coupling! */ |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <errno.h> |
| #include "as.h" |
| #include "input-file.h" |
| #include "safe-ctype.h" |
| |
| static int input_file_get (char *, int); |
| |
| /* This variable is non-zero if the file currently being read should be |
| preprocessed by app. It is zero if the file can be read straight in. */ |
| int preprocess = 0; |
| |
| /* This code opens a file, then delivers BUFFER_SIZE character |
| chunks of the file on demand. |
| BUFFER_SIZE is supposed to be a number chosen for speed. |
| The caller only asks once what BUFFER_SIZE is, and asks before |
| the nature of the input files (if any) is known. */ |
| |
| #define BUFFER_SIZE (32 * 1024) |
| |
| /* We use static data: the data area is not sharable. */ |
| |
| static FILE *f_in; |
| static char *file_name; |
| |
| /* Struct for saving the state of this module for file includes. */ |
| struct saved_file |
| { |
| FILE * f_in; |
| char * file_name; |
| int preprocess; |
| char * app_save; |
| }; |
| |
| /* These hooks accommodate most operating systems. */ |
| |
| void |
| input_file_begin (void) |
| { |
| f_in = (FILE *) 0; |
| } |
| |
| void |
| input_file_end (void) |
| { |
| } |
| |
| /* Return BUFFER_SIZE. */ |
| unsigned int |
| input_file_buffer_size (void) |
| { |
| return (BUFFER_SIZE); |
| } |
| |
| int |
| input_file_is_open (void) |
| { |
| return f_in != (FILE *) 0; |
| } |
| |
| /* Push the state of our input, returning a pointer to saved info that |
| can be restored with input_file_pop (). */ |
| |
| char * |
| input_file_push (void) |
| { |
| register struct saved_file *saved; |
| |
| saved = (struct saved_file *) xmalloc (sizeof *saved); |
| |
| saved->f_in = f_in; |
| saved->file_name = file_name; |
| saved->preprocess = preprocess; |
| if (preprocess) |
| saved->app_save = app_push (); |
| |
| /* Initialize for new file. */ |
| input_file_begin (); |
| |
| return (char *) saved; |
| } |
| |
| void |
| input_file_pop (char *arg) |
| { |
| register struct saved_file *saved = (struct saved_file *) arg; |
| |
| input_file_end (); /* Close out old file. */ |
| |
| f_in = saved->f_in; |
| file_name = saved->file_name; |
| preprocess = saved->preprocess; |
| if (preprocess) |
| app_pop (saved->app_save); |
| |
| free (arg); |
| } |
| |
| void |
| input_file_open (char *filename, /* "" means use stdin. Must not be 0. */ |
| int pre) |
| { |
| int c; |
| char buf[80]; |
| |
| preprocess = pre; |
| |
| assert (filename != 0); /* Filename may not be NULL. */ |
| if (filename[0]) |
| { |
| f_in = fopen (filename, FOPEN_RT); |
| file_name = filename; |
| } |
| else |
| { |
| /* Use stdin for the input file. */ |
| f_in = stdin; |
| /* For error messages. */ |
| file_name = _("{standard input}"); |
| } |
| |
| if (f_in) |
| c = getc (f_in); |
| |
| if (f_in == NULL || ferror (f_in)) |
| { |
| #ifdef BFD_ASSEMBLER |
| bfd_set_error (bfd_error_system_call); |
| #endif |
| as_perror (_("Can't open %s for reading"), file_name); |
| |
| if (f_in) |
| { |
| fclose (f_in); |
| f_in = NULL; |
| } |
| return; |
| } |
| |
| if (c == '#') |
| { |
| /* Begins with comment, may not want to preprocess. */ |
| c = getc (f_in); |
| if (c == 'N') |
| { |
| fgets (buf, 80, f_in); |
| if (!strncmp (buf, "O_APP", 5) && ISSPACE (buf[5])) |
| preprocess = 0; |
| if (!strchr (buf, '\n')) |
| ungetc ('#', f_in); /* It was longer. */ |
| else |
| ungetc ('\n', f_in); |
| } |
| else if (c == 'A') |
| { |
| fgets (buf, 80, f_in); |
| if (!strncmp (buf, "PP", 2) && ISSPACE (buf[2])) |
| preprocess = 1; |
| if (!strchr (buf, '\n')) |
| ungetc ('#', f_in); |
| else |
| ungetc ('\n', f_in); |
| } |
| else if (c == '\n') |
| ungetc ('\n', f_in); |
| else |
| ungetc ('#', f_in); |
| } |
| else |
| ungetc (c, f_in); |
| } |
| |
| /* Close input file. */ |
| |
| void |
| input_file_close (void) |
| { |
| /* Don't close a null file pointer. */ |
| if (f_in != NULL) |
| fclose (f_in); |
| |
| f_in = 0; |
| } |
| |
| /* This function is passed to do_scrub_chars. */ |
| |
| static int |
| input_file_get (char *buf, int buflen) |
| { |
| int size; |
| |
| size = fread (buf, sizeof (char), buflen, f_in); |
| if (size < 0) |
| { |
| #ifdef BFD_ASSEMBLER |
| bfd_set_error (bfd_error_system_call); |
| #endif |
| as_perror (_("Can't read from %s"), file_name); |
| size = 0; |
| } |
| return size; |
| } |
| |
| /* Read a buffer from the input file. */ |
| |
| char * |
| input_file_give_next_buffer (char *where /* Where to place 1st character of new buffer. */) |
| { |
| char *return_value; /* -> Last char of what we read, + 1. */ |
| register int size; |
| |
| if (f_in == (FILE *) 0) |
| return 0; |
| /* fflush (stdin); could be done here if you want to synchronise |
| stdin and stdout, for the case where our input file is stdin. |
| Since the assembler shouldn't do any output to stdout, we |
| don't bother to synch output and input. */ |
| if (preprocess) |
| size = do_scrub_chars (input_file_get, where, BUFFER_SIZE); |
| else |
| size = fread (where, sizeof (char), BUFFER_SIZE, f_in); |
| if (size < 0) |
| { |
| #ifdef BFD_ASSEMBLER |
| bfd_set_error (bfd_error_system_call); |
| #endif |
| as_perror (_("Can't read from %s"), file_name); |
| size = 0; |
| } |
| if (size) |
| return_value = where + size; |
| else |
| { |
| if (fclose (f_in)) |
| { |
| #ifdef BFD_ASSEMBLER |
| bfd_set_error (bfd_error_system_call); |
| #endif |
| as_perror (_("Can't close %s"), file_name); |
| } |
| f_in = (FILE *) 0; |
| return_value = 0; |
| } |
| |
| return return_value; |
| } |