as - Fix a case where a pointer to stack memeory could be returned.
[darwin-xtools.git] / cctools / as / input-scrub.c
blob5a6e41ae6e0ce66df2abc5d0185f58d3b4c30268
1 /* input_scrub.c - layer between app and the rest of the world
2 Copyright (C) 1987 Free Software Foundation, Inc.
4 This file is part of GAS, the GNU Assembler.
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.
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.
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. */
20 #include <stdlib.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <libc.h>
24 #ifdef NeXT_MOD /* .include feature */
25 #include <sys/file.h>
26 #include <sys/param.h>
27 #endif /* NeXT_MOD .include feature */
28 #include "as.h"
29 #include "read.h"
30 #include "input-file.h"
31 #include "input-scrub.h"
32 #include "app.h"
33 #include "xmalloc.h"
34 #include "messages.h"
37 * O/S independent module to supply buffers of sanitised source code
38 * to rest of assembler. We get raw input data of some length.
39 * Also looks after line numbers, for e.g. error messages.
40 * This module used to do the sanitising, but now a pre-processor program
41 * (app) does that job so this module is degenerate.
42 * Now input is pre-sanitised, so we only worry about finding the
43 * last partial line. A buffer of full lines is returned to caller.
44 * The last partial line begins the next buffer we build and return to caller.
45 * The buffer returned to caller is preceeded by BEFORE_STRING and followed
46 * by AFTER_STRING. The last character before AFTER_STRING is a newline.
50 * We expect the following sanitation has already been done.
52 * No comments, reduce a comment to a space.
53 * Reduce a tab to a space unless it is 1st char of line.
54 * All multiple tabs and spaces collapsed into 1 char. Tab only
55 * legal if 1st char of line.
56 * # line file statements converted to .line x;.file y; statements.
57 * Escaped newlines at end of line: remove them but add as many newlines
58 * to end of statement as you removed in the middle, to synch line numbers.
61 #define BEFORE_STRING ("\n")
62 #define AFTER_STRING ("\0") /* memcpy of 0 chars might choke. */
63 #define BEFORE_SIZE (1)
64 #define AFTER_SIZE (1) /* includes the \0 */
66 static char * buffer_start; /* -> 1st char of full buffer area. */
67 static char * partial_where; /* -> after last full line in buffer. */
68 static int partial_size; /* >=0. Number of chars in partial line in buffer. */
69 static char save_source [AFTER_SIZE];
70 /* Because we need AFTER_STRING just after last */
71 /* full line, it clobbers 1st part of partial */
72 /* line. So we preserve 1st part of partial */
73 /* line here. */
74 static int buffer_length; /* What is the largest size buffer that */
75 /* input_file_give_next_buffer() could */
76 /* return to us? */
79 We never have more than one source file open at once.
80 We may, however, read more than 1 source file in an assembly.
81 NULL means we have no file open right now.
86 We must track the physical file and line number for error messages.
87 We also track a "logical" file and line number corresponding to (C?)
88 compiler source line numbers.
89 Whenever we open a file we must fill in physical_input_file. So if it is NULL
90 we have not opened any files yet.
93 int doing_include = FALSE; /* TRUE when we are processing a .include */
95 char *physical_input_file = NULL;
96 char *logical_input_file = NULL;
97 char *layout_file = NULL;
98 char *input_dir = NULL;
100 line_numberT physical_input_line = 0;
101 line_numberT logical_input_line = 0;
102 line_numberT layout_line = 0;
105 void
106 input_scrub_begin(
107 void)
109 know( strlen(BEFORE_STRING) == BEFORE_SIZE );
110 know( strlen(AFTER_STRING) + 1 == AFTER_SIZE );
112 input_file_begin ();
114 buffer_length = input_file_buffer_size ();
116 buffer_start = xmalloc ((size_t)(BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE));
117 memcpy(buffer_start, BEFORE_STRING, (int)BEFORE_SIZE);
119 /* Line number things. */
120 logical_input_line = 0;
121 logical_input_file = (char *)NULL;
122 physical_input_file = NULL; /* No file read yet. */
123 do_scrub_begin();
126 void
127 input_scrub_end(
128 void)
130 input_file_end ();
133 char * /* Return start of caller's part of buffer. */
134 input_scrub_new_file(
135 char *filename)
137 input_file_open (filename, !flagseen['f']);
138 physical_input_file = filename[0] ? filename : "{standard input}";
139 physical_input_line = 0;
141 if (filename[0])
143 char *p;
144 int len;
146 p = strrchr(filename, '/');
147 if (p != NULL && p[1] != '\0')
149 len = p - filename + 1;
150 input_dir = xmalloc(len + 1);
151 strncpy(input_dir, filename, len);
155 partial_size = 0;
156 return (buffer_start + BEFORE_SIZE);
160 * input_scrub_next_buffer()
162 * The input parameter **bufp is used to return the address of a new or the
163 * previous buffer containing the characters to parse.
165 * This uses the static variables declared in this file (previouly set up by
166 * input_scrub_begin() and previous calls to itself). The buffer is created
167 * with twice the buffer_length plus the "BEFORE" and "AFTER" bytes.
168 * So there maybe some characters from a partial line following the last
169 * newline in the buffer.
171 * It returns a pointer into the buffer as the buffer_limit to the last
172 * character of the last line in the buffer (before the last newline, where the
173 * parsing stops).
175 char *
176 input_scrub_next_buffer(
177 char **bufp)
179 register char * limit; /* -> just after last char of buffer. */
180 int give_next_size;
182 if (partial_size)
184 memcpy(buffer_start + BEFORE_SIZE, partial_where, (int)partial_size);
185 memcpy(buffer_start + BEFORE_SIZE, save_source, (int)AFTER_SIZE);
187 get_more:
188 limit = input_file_give_next_buffer(
189 buffer_start + BEFORE_SIZE + partial_size,
190 &give_next_size);
191 if (limit)
193 register char * p; /* Find last newline. */
194 for (p = limit; * -- p != '\n'; )
197 ++ p;
198 if (p <= buffer_start + BEFORE_SIZE)
200 int new;
202 new = limit - (buffer_start + BEFORE_SIZE + partial_size);
203 partial_size += new;
206 * If there is enough room left in this buffer for what
207 * input_file_give_next_buffer() will need don't reallocate as we
208 * could run out of memory needlessly.
210 if((BEFORE_SIZE + buffer_length * 2) - (limit - buffer_start) >
211 give_next_size)
212 goto get_more;
214 buffer_length = buffer_length * 2;
215 buffer_start = xrealloc (buffer_start,
216 (size_t)(BEFORE_SIZE + buffer_length +
217 buffer_length + AFTER_SIZE));
218 *bufp = buffer_start + BEFORE_SIZE;
219 goto get_more;
221 partial_where = p;
222 partial_size = limit - p;
223 memcpy(save_source, partial_where, (int)AFTER_SIZE);
224 memcpy(partial_where, AFTER_STRING, (int)AFTER_SIZE);
226 else
228 partial_where = 0;
229 if (partial_size > 0)
231 as_warn( "Partial line at end of file ignored" );
234 return (partial_where);
238 * The remaining part of this file deals with line numbers, error
239 * messages and so on.
244 * seen_at_least_1_file() returns TRUE if we opened any file.
247 seen_at_least_1_file(
248 void)
250 return (physical_input_file != NULL);
253 void
254 bump_line_counters(
255 void)
257 ++ physical_input_line;
258 ++ logical_input_line;
262 * new_logical_line()
264 * Tells us what the new logical line number and file are.
265 * If the line_number is <0, we don't change the current logical line number.
266 * If the fname is NULL, we don't change the current logical file name.
268 void
269 new_logical_line(
270 char *fname, /* DON'T destroy it! We point to it! */
271 int line_number)
273 if ( fname )
275 logical_input_file = fname;
277 if ( line_number >= 0 )
279 logical_input_line = line_number;
284 * a s _ w h e r e ( )
286 * Write a line to stderr locating where we are in reading
287 * input source files.
288 * As a sop to the debugger of AS, pretty-print the offending line.
290 void
291 as_where(
292 void)
294 char *p;
295 line_numberT line;
297 if (physical_input_file)
298 { /* we tried to read SOME source */
299 if (input_file_is_open())
300 { /* we can still read lines from source */
301 p = logical_input_file ? logical_input_file : physical_input_file;
302 line = logical_input_line ? logical_input_line : physical_input_line;
303 fprintf(stderr,"%s:%u:", p, line);
305 else
307 p = logical_input_file ? logical_input_file : physical_input_file;
308 line = logical_input_line ? logical_input_line : physical_input_line;
309 if(layout_line != 0)
310 fprintf (stderr,"%s:%u:", layout_file, layout_line);
311 else
312 fprintf (stderr,"%s:unknown:", p);
315 else
320 void
321 as_file_and_line(
322 char **file_ret,
323 unsigned int *line_ret)
325 *file_ret = NULL;
326 *line_ret = 0;
327 if (physical_input_file)
328 { /* we tried to read SOME source */
329 *file_ret = logical_input_file ?
330 logical_input_file : physical_input_file;
331 if (input_file_is_open())
332 { /* we can still read lines from source */
333 *line_ret = logical_input_line ?
334 logical_input_line : physical_input_line;
340 * as_where_ProjectBuilder() returns the fileName, directory, and line number
341 * to be used to tell ProjectBuilder where the error is. Note that the '/'
342 * between fileName and directory does not appear in what is returned.
344 void
345 as_where_ProjectBuilder(
346 char **fileName,
347 char **directory,
348 int *line)
350 char *p, *q;
351 static char directory_buf[MAXPATHLEN];
353 getwd(directory_buf);
354 *fileName = NULL;
355 *directory = directory_buf;
356 *line = 0;
358 if(physical_input_file){
359 p = logical_input_file ?
360 logical_input_file : physical_input_file;
361 if(input_file_is_open()){
362 *line = logical_input_line ?
363 logical_input_line : physical_input_line;
365 *fileName = p;
366 q = strrchr(p, '/');
367 if(q == NULL)
368 return;
369 *fileName = p + 1;
370 strncat(directory_buf, p, q - p);
375 * a s _ p e r r o r
377 * Like perror(3), but with more info.
379 void
380 as_perror(
381 char *gripe, /* Unpunctuated error theme. */
382 char *filename)
384 fprintf (stderr,"as:file(%s) %s! ",
385 filename, gripe
387 if (errno > sys_nerr)
389 fprintf (stderr, "Unknown error #%d.", errno);
391 else
393 fprintf (stderr, "%s.", sys_errlist [errno]);
395 (void)putc('\n', stderr);
396 errno = 0; /* After reporting, clear it. */
397 if (input_file_is_open()) /* RMS says don't mention line # if not needed. */
399 as_where();
401 bad_error = 1;
405 #ifdef NeXT_MOD /* .include feature */
406 /* DJA -- added for .include pseudo op support */
407 char *
408 find_an_include_file(
409 char *no_path_name)
411 char name_buffer [MAXPATHLEN];
412 register struct directory_stack * the_path_pointer;
413 register char * whole_file_name;
416 * figure out what directory the file name is in.
418 whole_file_name = no_path_name;
419 if (access(whole_file_name, R_OK))
421 whole_file_name = name_buffer;
422 if (no_path_name[0] != '/' && input_dir != NULL)
424 if (strlen (input_dir) + strlen (no_path_name) >= MAXPATHLEN)
425 as_fatal ("include file name too long: \"%s%s\"", input_dir, no_path_name);
426 else
428 strcpy (whole_file_name, input_dir);
429 strcat (whole_file_name, no_path_name);
430 if (!access(whole_file_name, R_OK))
431 goto found;
434 the_path_pointer = include;
435 while (the_path_pointer)
437 if (strlen (the_path_pointer->fname) + (strlen (no_path_name)) >= MAXPATHLEN)
438 as_fatal ("include file name too long: \"%s%s\"", the_path_pointer->fname, no_path_name);
439 else
441 *whole_file_name = '\0';
442 strcpy (whole_file_name, the_path_pointer->fname);
443 strcat (whole_file_name, "/");
444 strcat (whole_file_name, no_path_name);
445 if (!access(whole_file_name, R_OK))
446 goto found;
448 the_path_pointer = the_path_pointer->next;
450 the_path_pointer = include_defaults;
451 while (the_path_pointer->fname != NULL)
453 if (strlen (the_path_pointer->fname) + (strlen (no_path_name)) >= MAXPATHLEN)
454 as_fatal ("include file name too long: \"%s%s\"", the_path_pointer->fname, no_path_name);
455 else
457 *whole_file_name = '\0';
458 strcpy (whole_file_name, the_path_pointer->fname);
459 strcat (whole_file_name, "/");
460 strcat (whole_file_name, no_path_name);
461 if (!access(whole_file_name, R_OK))
462 goto found;
464 the_path_pointer++;
466 as_fatal ("Couldn't find the include file: \"%s\"", no_path_name);
467 return (NULL);
469 found:
470 return (strndup(whole_file_name, MAXPATHLEN+1));
473 void
474 read_an_include_file(
475 char *no_path_name)
477 char * buffer;
478 char * last_buffer_limit;
479 char * last_buffer_start;
480 int last_doing_include;
481 FILE * last_f_in;
482 char * last_file_name;
483 char * last_input_line_pointer;
484 char * last_logical_input_file;
485 line_numberT last_logical_input_line;
486 int last_partial_size;
487 char * last_partial_where;
488 char * last_physical_input_file;
489 line_numberT last_physical_input_line;
490 char last_save_source [AFTER_SIZE];
491 int last_buffer_length;
492 #if 0
493 char * last_save_buffer;
494 #endif
495 scrub_context_data scrub_context;
496 register char * whole_file_name;
499 * figure out what directory the file name is in.
501 whole_file_name = find_an_include_file (no_path_name);
504 * save a copy of the file state for a recursive call to read a file
506 last_buffer_limit = buffer_limit;
507 last_buffer_start = buffer_start;
508 last_doing_include = doing_include;
509 last_f_in = f_in;
510 last_file_name = file_name;
511 last_input_line_pointer = input_line_pointer;
512 last_logical_input_file = logical_input_file;
513 last_logical_input_line = logical_input_line;
514 last_partial_size = partial_size;
515 last_partial_where = partial_where;
516 last_physical_input_file = physical_input_file;
517 last_physical_input_line = physical_input_line;
518 memcpy(last_save_source, save_source, sizeof (save_source));
519 last_buffer_length = buffer_length;
520 save_scrub_context (&scrub_context);
522 * set up for another file
524 partial_size = 0;
525 doing_include = TRUE;
526 input_scrub_begin ();
527 buffer = input_scrub_new_file (whole_file_name);
528 if (f_in != (FILE *)0)
529 read_a_source_file(buffer);
531 xfree (buffer_start);
533 * restore the file state
535 buffer_limit = last_buffer_limit;
536 buffer_start = last_buffer_start;
537 doing_include = last_doing_include;
538 f_in = last_f_in;
539 file_name = last_file_name;
540 input_line_pointer = last_input_line_pointer;
541 logical_input_file = last_logical_input_file;
542 logical_input_line = last_logical_input_line;
543 partial_size = last_partial_size;
544 partial_where = last_partial_where;
545 physical_input_file = last_physical_input_file;
546 physical_input_line = last_physical_input_line;
547 memcpy(save_source, last_save_source, sizeof (save_source));
548 buffer_length = last_buffer_length;
549 restore_scrub_context (&scrub_context);
550 } /* read_an_include_file */
551 #endif /* NeXT_MOD .include feature */