/src/binutils-gdb/gas/input-file.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* input_file.c - Deal with Input Files - |
2 | | Copyright (C) 1987-2023 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 | 99.6k | #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 const 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 | | const char * file_name; |
52 | | int preprocess; |
53 | | char * app_save; |
54 | | }; |
55 | | |
56 | | /* These hooks accommodate most operating systems. */ |
57 | | |
58 | | void |
59 | | input_file_begin (void) |
60 | 189k | { |
61 | 189k | f_in = (FILE *) 0; |
62 | 189k | } |
63 | | |
64 | | void |
65 | | input_file_end (void) |
66 | 189k | { |
67 | 189k | } |
68 | | |
69 | | /* Return BUFFER_SIZE. */ |
70 | | size_t |
71 | | input_file_buffer_size (void) |
72 | 95.8k | { |
73 | 95.8k | return (BUFFER_SIZE); |
74 | 95.8k | } |
75 | | |
76 | | /* Push the state of our input, returning a pointer to saved info that |
77 | | can be restored with input_file_pop (). */ |
78 | | |
79 | | char * |
80 | | input_file_push (void) |
81 | 94.4k | { |
82 | 94.4k | struct saved_file *saved; |
83 | | |
84 | 94.4k | saved = XNEW (struct saved_file); |
85 | | |
86 | 94.4k | saved->f_in = f_in; |
87 | 94.4k | saved->file_name = file_name; |
88 | 94.4k | saved->preprocess = preprocess; |
89 | 94.4k | if (preprocess) |
90 | 76.1k | saved->app_save = app_push (); |
91 | | |
92 | | /* Initialize for new file. */ |
93 | 94.4k | input_file_begin (); |
94 | | |
95 | 94.4k | return (char *) saved; |
96 | 94.4k | } |
97 | | |
98 | | void |
99 | | input_file_pop (char *arg) |
100 | 94.4k | { |
101 | 94.4k | struct saved_file *saved = (struct saved_file *) arg; |
102 | | |
103 | 94.4k | input_file_end (); /* Close out old file. */ |
104 | | |
105 | 94.4k | f_in = saved->f_in; |
106 | 94.4k | file_name = saved->file_name; |
107 | 94.4k | preprocess = saved->preprocess; |
108 | 94.4k | if (preprocess) |
109 | 76.1k | app_pop (saved->app_save); |
110 | | |
111 | 94.4k | free (arg); |
112 | 94.4k | } |
113 | | |
114 | | /* Open the specified file, "" means stdin. Filename must not be null. */ |
115 | | |
116 | | void |
117 | | input_file_open (const char *filename, |
118 | | int pre) |
119 | 1.15k | { |
120 | 1.15k | int c; |
121 | 1.15k | char buf[80]; |
122 | | |
123 | 1.15k | preprocess = pre; |
124 | | |
125 | 1.15k | gas_assert (filename != 0); /* Filename may not be NULL. */ |
126 | 1.15k | if (filename[0]) |
127 | 1.15k | { |
128 | 1.15k | f_in = fopen (filename, FOPEN_RT); |
129 | 1.15k | file_name = filename; |
130 | 1.15k | } |
131 | 0 | else |
132 | 0 | { |
133 | | /* Use stdin for the input file. */ |
134 | 0 | f_in = stdin; |
135 | | /* For error messages. */ |
136 | 0 | file_name = _("{standard input}"); |
137 | 0 | } |
138 | | |
139 | 1.15k | if (f_in == NULL) |
140 | 0 | { |
141 | 0 | as_bad (_("can't open %s for reading: %s"), |
142 | 0 | file_name, xstrerror (errno)); |
143 | 0 | return; |
144 | 0 | } |
145 | | |
146 | 1.15k | c = getc (f_in); |
147 | | |
148 | 1.15k | if (ferror (f_in)) |
149 | 0 | { |
150 | 0 | as_bad (_("can't read from %s: %s"), |
151 | 0 | file_name, xstrerror (errno)); |
152 | |
|
153 | 0 | fclose (f_in); |
154 | 0 | f_in = NULL; |
155 | 0 | return; |
156 | 0 | } |
157 | | |
158 | | /* Check for an empty input file. */ |
159 | 1.15k | if (feof (f_in)) |
160 | 0 | { |
161 | 0 | fclose (f_in); |
162 | 0 | f_in = NULL; |
163 | 0 | return; |
164 | 0 | } |
165 | 1.15k | gas_assert (c != EOF); |
166 | | |
167 | 1.15k | if (c == '#') |
168 | 148 | { |
169 | | /* Begins with comment, may not want to preprocess. */ |
170 | 148 | c = getc (f_in); |
171 | 148 | if (c == 'N') |
172 | 127 | { |
173 | 127 | char *p = fgets (buf, sizeof (buf), f_in); |
174 | 127 | if (p && startswith (p, "O_APP") && ISSPACE (p[5])) |
175 | 102 | preprocess = 0; |
176 | 127 | if (!p || !strchr (p, '\n')) |
177 | 13 | ungetc ('#', f_in); |
178 | 114 | else |
179 | 114 | ungetc ('\n', f_in); |
180 | 127 | } |
181 | 21 | else if (c == 'A') |
182 | 0 | { |
183 | 0 | char *p = fgets (buf, sizeof (buf), f_in); |
184 | 0 | if (p && startswith (p, "PP") && ISSPACE (p[2])) |
185 | 0 | preprocess = 1; |
186 | 0 | if (!p || !strchr (p, '\n')) |
187 | 0 | ungetc ('#', f_in); |
188 | 0 | else |
189 | 0 | ungetc ('\n', f_in); |
190 | 0 | } |
191 | 21 | else if (c == '\n') |
192 | 0 | ungetc ('\n', f_in); |
193 | 21 | else |
194 | 21 | ungetc ('#', f_in); |
195 | 148 | } |
196 | 1.00k | else |
197 | 1.00k | ungetc (c, f_in); |
198 | 1.15k | } |
199 | | |
200 | | /* Close input file. */ |
201 | | |
202 | | void |
203 | | input_file_close (void) |
204 | 1.15k | { |
205 | | /* Don't close a null file pointer. */ |
206 | 1.15k | if (f_in != NULL) |
207 | 13 | fclose (f_in); |
208 | | |
209 | 1.15k | f_in = 0; |
210 | 1.15k | } |
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 | 5.54k | { |
217 | 5.54k | size_t size; |
218 | | |
219 | 5.54k | if (feof (f_in)) |
220 | 2.66k | return 0; |
221 | | |
222 | 2.88k | size = fread (buf, sizeof (char), buflen, f_in); |
223 | 2.88k | if (ferror (f_in)) |
224 | 0 | as_bad (_("can't read from %s: %s"), file_name, xstrerror (errno)); |
225 | 2.88k | return size; |
226 | 5.54k | } |
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 | 3.90k | { |
233 | 3.90k | char *return_value; /* -> Last char of what we read, + 1. */ |
234 | 3.90k | size_t size; |
235 | | |
236 | 3.90k | if (f_in == (FILE *) 0) |
237 | 196 | 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 | 3.70k | if (preprocess) |
243 | 3.32k | size = do_scrub_chars (input_file_get, where, BUFFER_SIZE); |
244 | 383 | else |
245 | 383 | size = input_file_get (where, BUFFER_SIZE); |
246 | | |
247 | 3.70k | if (size) |
248 | 2.57k | return_value = where + size; |
249 | 1.13k | else |
250 | 1.13k | { |
251 | 1.13k | if (fclose (f_in)) |
252 | 0 | as_warn (_("can't close %s: %s"), file_name, xstrerror (errno)); |
253 | | |
254 | 1.13k | f_in = (FILE *) 0; |
255 | 1.13k | return_value = 0; |
256 | 1.13k | } |
257 | | |
258 | 3.70k | return return_value; |
259 | 3.90k | } |