This commit was manufactured by cvs2svn to create branch 'binutils'.
[external/binutils.git] / gas / input-file.c
1 /* input_file.c - Deal with Input Files -
2    Copyright (C) 1987, 1990, 1991 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 1, 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
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 /* static const char rcsid[] = "$Id$"; */
21
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
29 #ifdef USG
30 #define setbuffer(stream, buf, size) setvbuf((stream), (buf), _IOFBF, (size))
31 #endif
32
33 #include <stdio.h>
34 #include <assert.h>
35 #include <string.h>
36
37 #include "as.h"
38 #include "input-file.h"
39
40 /* This variable is non-zero if the file currently being read should be
41    preprocessed by app.  It is zero if the file can be read straight in.
42  */
43 int preprocess = 0;
44
45 /*
46  * This code opens a file, then delivers BUFFER_SIZE character
47  * chunks of the file on demand.
48  * BUFFER_SIZE is supposed to be a number chosen for speed.
49  * The caller only asks once what BUFFER_SIZE is, and asks before
50  * the nature of the input files (if any) is known.
51  */
52
53 #define BUFFER_SIZE (32 * 1024)
54
55 /*
56  * We use static data: the data area is not sharable.
57  */
58
59 FILE *f_in;
60 /* static JF remove static so app.c can use file_name */
61 char *  file_name;
62
63 /* Struct for saving the state of this module for file includes.  */
64 struct saved_file {
65   FILE *f_in;
66   char *file_name;
67   int   preprocess;
68   char *app_save;
69 };
70 \f
71 /* These hooks accomodate most operating systems. */
72
73 void input_file_begin() {
74   f_in = (FILE *)0;
75 }
76
77 void input_file_end () { }
78
79  /* Return BUFFER_SIZE. */
80 int input_file_buffer_size() {
81   return (BUFFER_SIZE);
82 }
83
84 int input_file_is_open() {
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 char *input_file_push () {
91   register struct saved_file *saved;
92
93   saved = (struct saved_file *)xmalloc (sizeof *saved);
94
95   saved->f_in           = f_in;
96   saved->file_name      = file_name;
97   saved->preprocess     = preprocess;
98   if (preprocess)
99     saved->app_save     = app_push ();
100
101   input_file_begin ();  /* Initialize for new file */
102
103   return (char *)saved;
104 }
105
106 void
107 input_file_pop (arg)
108      char *arg;
109 {
110   register struct saved_file *saved = (struct saved_file *)arg;
111
112   input_file_end ();    /* Close out old file */
113
114   f_in                  = saved->f_in;
115   file_name             = saved->file_name;
116   preprocess            = saved->preprocess;
117   if (preprocess)
118     app_pop              (saved->app_save);
119
120   free(arg);
121 }
122 \f
123 #ifdef DONTDEF          /* JF save old version in case we need it */
124 void
125 input_file_open (filename, preprocess, debugging)
126      char *     filename;       /* "" means use stdin. Must not be 0. */
127      int        preprocess;     /* TRUE if needs app. */
128      int        debugging;      /* TRUE if we are debugging assembler. */
129 {
130   assert( filename != 0 );      /* Filename may not be NULL. */
131   if (filename [0])
132     {                           /* We have a file name. Suck it and see. */
133       file_handle = open (filename, O_RDONLY, 0);
134       file_name = filename;
135     }
136   else
137     {                           /* use stdin for the input file. */
138       file_handle = fileno (stdin);
139       file_name = "{standard input}"; /* For error messages. */
140     }
141   if (file_handle < 0)
142       as_perror ("Can't open %s for reading", file_name);
143   if ( preprocess )
144     {
145 /*
146  * This code was written in haste for a frobbed BSD 4.2.
147  * I have a flight to catch: will someone please do proper
148  * error checks? - Dean.
149  */
150       int       pid;
151       char temporary_file_name [12];
152       int       fd;
153       union wait        status;
154
155       (void)strcpy (temporary_file_name, "#appXXXXXX");
156       (void)mktemp (temporary_file_name);
157       pid = vfork ();
158       if (pid == -1)
159         {
160           as_perror ("Vfork failed", file_name);
161           _exit (144);
162         }
163       if (pid == 0)
164         {
165           (void)dup2 (file_handle, fileno(stdin));
166           fd = open (temporary_file_name, O_WRONLY + O_TRUNC + O_CREAT, 0666);
167           if (fd == -1)
168             {
169               (void)write(2,"Can't open temporary\n",21);
170               _exit (99);
171             }
172           (void)dup2 (fd, fileno(stdout));
173 /* JF for testing #define PREPROCESSOR "/lib/app" */
174 #define PREPROCESSOR "./app"
175           execl (PREPROCESSOR, PREPROCESSOR, 0);
176           execl ("app","app",0);
177           (void)write(2,"Exec of app failed.  Get help.\n",31);
178           (void)unlink(temporary_file_name);
179           _exit (11);
180         }
181       (void)wait (& status);
182       if (status.w_status & 0xFF00)             /* JF was 0xF000, was wrong */
183         {
184           file_handle = -1;
185           as_bad( "Can't preprocess file \"%s\", status = %xx", file_name, status.w_status );
186         }
187       else
188         {
189           file_handle = open (temporary_file_name, O_RDONLY, 0);
190           if ( ! debugging && unlink(temporary_file_name))
191             as_perror ("Can't delete temp file %s", temporary_file_name);
192         }
193       if (file_handle == -1)
194           as_perror ("Can't retrieve temp file %s", temporary_file_name);
195     }
196 }
197 #else
198
199 void
200 input_file_open (filename,pre)
201      char *     filename;       /* "" means use stdin. Must not be 0. */
202      int pre;
203 {
204         int     c;
205         char    buf[80];
206
207         preprocess = pre;
208
209         assert( filename != 0 );        /* Filename may not be NULL. */
210         if (filename [0]) {     /* We have a file name. Suck it and see. */
211                 f_in=fopen(filename,"r");
212                 file_name=filename;
213         } else {                        /* use stdin for the input file. */
214                 f_in = stdin;
215                 file_name = "{standard input}"; /* For error messages. */
216         }
217         if (f_in==(FILE *)0) {
218                 as_perror ("Can't open %s for reading", file_name);
219                 return;
220         }
221
222 #ifndef VMS
223         /* Ask stdio to buffer our input at BUFFER_SIZE, with a dynamically
224            allocated buffer.  */
225         setvbuf(f_in, (char *)NULL, _IOFBF, BUFFER_SIZE);
226 #endif /* VMS */
227
228         c = getc(f_in);
229         if (c == '#') { /* Begins with comment, may not want to preprocess */
230                 c = getc(f_in);
231                 if (c == 'N') {
232                         fgets(buf,80,f_in);
233                         if (!strcmp(buf,"O_APP\n"))
234                                 preprocess=0;
235                         if (!strchr(buf,'\n'))
236                                 ungetc('#',f_in);       /* It was longer */
237                         else
238                                 ungetc('\n',f_in);
239                 } else if(c=='\n')
240                         ungetc('\n',f_in);
241                 else
242                         ungetc('#',f_in);
243         } else
244                 ungetc(c,f_in);
245
246 #ifdef DONTDEF
247         if ( preprocess ) {
248                 char temporary_file_name [17];
249                 FILE    *f_out;
250
251                 (void)strcpy (temporary_file_name, "/tmp/#appXXXXXX");
252                 (void)mktemp (temporary_file_name);
253                 f_out=fopen(temporary_file_name,"w+");
254                 if(f_out==(FILE *)0)
255                         as_perror("Can't open temp file %s",temporary_file_name);
256
257                         /* JF this will have to be moved on any system that
258                            does not support removal of open files.  */
259                 (void)unlink(temporary_file_name);/* JF do it NOW */
260                 do_scrub(f_in,f_out);
261                 (void)fclose(f_in);     /* All done with it */
262                 (void)rewind(f_out);
263                 f_in=f_out;
264         }
265 #endif
266 }
267 #endif
268
269 /* Close input file.  */
270 void input_file_close() {
271   fclose (f_in);
272   f_in = 0;
273 }
274
275 char *
276 input_file_give_next_buffer (where)
277      char *             where;  /* Where to place 1st character of new buffer. */
278 {
279   char *        return_value;   /* -> Last char of what we read, + 1. */
280   register int  size;
281
282   if (f_in == (FILE *)0)
283       return 0;
284       /*
285        * fflush (stdin); could be done here if you want to synchronise
286        * stdin and stdout, for the case where our input file is stdin.
287        * Since the assembler shouldn't do any output to stdout, we
288        * don't bother to synch output and input.
289        */
290   if(preprocess) {
291         char *p;
292         int n;
293         int ch;
294         extern FILE *scrub_file;
295
296         scrub_file=f_in;
297         for (p = where, n = BUFFER_SIZE; n; --n) {
298
299                 ch = do_scrub_next_char(scrub_from_file, scrub_to_file);
300                 if (ch == EOF)
301                         break;
302                 *p++=ch;
303         }
304         size=BUFFER_SIZE-n;
305   } else
306         size= fread(where,sizeof(char),BUFFER_SIZE,f_in);
307   if (size < 0)
308     {
309       as_perror ("Can't read from %s", file_name);
310       size = 0;
311     }
312   if (size)
313     return_value = where + size;
314   else
315     {
316       if (fclose (f_in))
317         as_perror ("Can't close %s", file_name);
318       f_in = (FILE *)0;
319       return_value = 0;
320     }
321   return (return_value);
322 }