|
|
1.1 root 1: /* input_scrub.c - layer between app and the rest of the world
2: Copyright (C) 1987 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: #include <stdlib.h>
21: #include <string.h>
22: #include <errno.h>
23: #include <libc.h>
24: #ifdef NeXT /* .include feature */
25: #include <sys/file.h>
26: #include <sys/param.h>
27: #endif /* NeXT .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"
35:
36: /*
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.
47: */
48:
49: /*
50: * We expect the following sanitation has already been done.
51: *
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.
59: */
60:
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 */
65:
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? */
77:
78: /*
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.
82: */
83:
84:
85: /*
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.
91: */
92:
93: int doing_include = FALSE; /* TRUE when we are processing a .include */
94:
95: char *physical_input_file = NULL;
96: char *logical_input_file = NULL;
97:
98: line_numberT physical_input_line = 0;
99: line_numberT logical_input_line = 0;
100:
101:
102: void
103: input_scrub_begin(
104: void)
105: {
106: know( strlen(BEFORE_STRING) == BEFORE_SIZE );
107: know( strlen(AFTER_STRING) + 1 == AFTER_SIZE );
108:
109: input_file_begin ();
110:
111: buffer_length = input_file_buffer_size ();
112:
113: buffer_start = xmalloc ((long)(BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE));
114: memcpy(buffer_start, BEFORE_STRING, (int)BEFORE_SIZE);
115:
116: /* Line number things. */
117: logical_input_line = 0;
118: logical_input_file = (char *)NULL;
119: physical_input_file = NULL; /* No file read yet. */
120: do_scrub_begin();
121: }
122:
123: void
124: input_scrub_end(
125: void)
126: {
127: input_file_end ();
128: }
129:
130: char * /* Return start of caller's part of buffer. */
131: input_scrub_new_file(
132: char *filename)
133: {
134: input_file_open (filename, !flagseen['f']);
135: physical_input_file = filename[0] ? filename : "{standard input}";
136: physical_input_line = 0;
137:
138: partial_size = 0;
139: return (buffer_start + BEFORE_SIZE);
140: }
141:
142: char *
143: input_scrub_next_buffer(
144: char **bufp)
145: {
146: register char * limit; /* -> just after last char of buffer. */
147:
148: if (partial_size)
149: {
150: memcpy(buffer_start + BEFORE_SIZE, partial_where, (int)partial_size);
151: memcpy(buffer_start + BEFORE_SIZE, save_source, (int)AFTER_SIZE);
152: }
153: limit = input_file_give_next_buffer (buffer_start + BEFORE_SIZE + partial_size);
154: if (limit)
155: {
156: register char * p; /* Find last newline. */
157:
158: for (p = limit; * -- p != '\n'; )
159: {
160: }
161: ++ p;
162: if (p <= buffer_start + BEFORE_SIZE)
163: {
164: as_fatal ("Source line too long. Please change file %s then rebuild assembler.", __FILE__);
165: }
166: partial_where = p;
167: partial_size = limit - p;
168: memcpy(save_source, partial_where, (int)AFTER_SIZE);
169: memcpy(partial_where, AFTER_STRING, (int)AFTER_SIZE);
170: }
171: else
172: {
173: partial_where = 0;
174: if (partial_size > 0)
175: {
176: as_warn( "Partial line at end of file ignored" );
177: }
178: }
179: return (partial_where);
180: }
181:
182: /*
183: * The remaining part of this file deals with line numbers, error
184: * messages and so on.
185: */
186:
187:
188: /*
189: * seen_at_least_1_file() returns TRUE if we opened any file.
190: */
191: int
192: seen_at_least_1_file(
193: void)
194: {
195: return (physical_input_file != NULL);
196: }
197:
198: void
199: bump_line_counters(
200: void)
201: {
202: ++ physical_input_line;
203: ++ logical_input_line;
204: }
205:
206: /*
207: * new_logical_line()
208: *
209: * Tells us what the new logical line number and file are.
210: * If the line_number is <0, we don't change the current logical line number.
211: * If the fname is NULL, we don't change the current logical file name.
212: */
213: void
214: new_logical_line(
215: char *fname, /* DON'T destroy it! We point to it! */
216: int line_number)
217: {
218: if ( fname )
219: {
220: logical_input_file = fname;
221: }
222: if ( line_number >= 0 )
223: {
224: logical_input_line = line_number;
225: }
226: }
227:
228: /*
229: * a s _ w h e r e ( )
230: *
231: * Write a line to stderr locating where we are in reading
232: * input source files.
233: * As a sop to the debugger of AS, pretty-print the offending line.
234: */
235: void
236: as_where(
237: void)
238: {
239: char *p;
240: line_numberT line;
241:
242: if (physical_input_file)
243: { /* we tried to read SOME source */
244: if (input_file_is_open())
245: { /* we can still read lines from source */
246: p = logical_input_file ? logical_input_file : physical_input_file;
247: line = logical_input_line ? logical_input_line : physical_input_line;
248: fprintf(stderr,"%s:%u:", p, line);
249: }
250: else
251: {
252: p = logical_input_file ? logical_input_file : physical_input_file;
253: line = logical_input_line ? logical_input_line : physical_input_line;
254: fprintf (stderr,"%s:unknown:", p);
255: }
256: }
257: else
258: {
259: }
260: }
261:
262: /*
263: * as_where_ProjectBuilder() returns the fileName, directory, and line number
264: * to be used to tell ProjectBuilder where the error is. Note that the '/'
265: * between fileName and directory does not appear in what is returned.
266: */
267: void
268: as_where_ProjectBuilder(
269: char **fileName,
270: char **directory,
271: int *line)
272: {
273: char *p, *q;
274: static char directory_buf[MAXPATHLEN];
275:
276: getwd(directory_buf);
277: *fileName = NULL;
278: *directory = directory_buf;
279: *line = 0;
280:
281: if(physical_input_file){
282: p = logical_input_file ?
283: logical_input_file : physical_input_file;
284: if(input_file_is_open()){
285: *line = logical_input_line ?
286: logical_input_line : physical_input_line;
287: }
288: *fileName = p;
289: q = strrchr(p, '/');
290: if(q == NULL)
291: return;
292: *fileName = p + 1;
293: strncat(directory_buf, p, q - p);
294: }
295: }
296:
297: /*
298: * a s _ p e r r o r
299: *
300: * Like perror(3), but with more info.
301: */
302: void
303: as_perror(
304: char *gripe, /* Unpunctuated error theme. */
305: char *filename)
306: {
307: fprintf (stderr,"as:file(%s) %s! ",
308: filename, gripe
309: );
310: if (errno > sys_nerr)
311: {
312: fprintf (stderr, "Unknown error #%d.", errno);
313: }
314: else
315: {
316: fprintf (stderr, "%s.", sys_errlist [errno]);
317: }
318: (void)putc('\n', stderr);
319: errno = 0; /* After reporting, clear it. */
320: if (input_file_is_open()) /* RMS says don't mention line # if not needed. */
321: {
322: as_where();
323: }
324: }
325:
326:
327: #ifdef NeXT /* .include feature */
328: /* DJA -- added for .include pseudo op support */
329: void
330: read_an_include_file(
331: char *no_path_name)
332: {
333: char * buffer;
334: char * last_buffer_limit;
335: char * last_buffer_start;
336: int last_doing_include;
337: FILE * last_f_in;
338: char * last_file_name;
339: char * last_input_line_pointer;
340: char * last_logical_input_file;
341: line_numberT last_logical_input_line;
342: int last_partial_size;
343: char * last_partial_where;
344: char * last_physical_input_file;
345: line_numberT last_physical_input_line;
346: char last_save_source [AFTER_SIZE];
347: #if 0
348: char * last_save_buffer;
349: #endif
350: char name_buffer [MAXPATHLEN];
351: scrub_context_data scrub_context;
352: register struct directory_stack * the_path_pointer;
353: register char * whole_file_name;
354:
355: /*
356: * figure out what directory the file name is in.
357: */
358: whole_file_name = no_path_name;
359: if (access(whole_file_name, R_OK))
360: {
361: whole_file_name = name_buffer;
362: the_path_pointer = include;
363: while (the_path_pointer)
364: {
365: if (strlen (the_path_pointer->fname) + (strlen (no_path_name)) >= MAXPATHLEN)
366: as_warn ("include file name too long: \"%s%s\"", the_path_pointer->fname, no_path_name);
367: else
368: {
369: *whole_file_name = '\0';
370: strcpy (whole_file_name, the_path_pointer->fname);
371: strcat (whole_file_name, "/");
372: strcat (whole_file_name, no_path_name);
373: if (!access(whole_file_name, R_OK))
374: goto found;
375: }
376: the_path_pointer = the_path_pointer->next;
377: }
378: the_path_pointer = include_defaults;
379: while (the_path_pointer->fname != NULL)
380: {
381: if (strlen (the_path_pointer->fname) + (strlen (no_path_name)) >= MAXPATHLEN)
382: as_warn ("include file name too long: \"%s%s\"", the_path_pointer->fname, no_path_name);
383: else
384: {
385: *whole_file_name = '\0';
386: strcpy (whole_file_name, the_path_pointer->fname);
387: strcat (whole_file_name, "/");
388: strcat (whole_file_name, no_path_name);
389: if (!access(whole_file_name, R_OK))
390: goto found;
391: }
392: the_path_pointer++;
393: }
394: as_fatal ("Couldn't find the include file: \"%s\"", no_path_name);
395: return;
396: }
397: found:
398: /*
399: * save a copy of the file state for a recursive call to read a file
400: */
401: last_buffer_limit = buffer_limit;
402: last_buffer_start = buffer_start;
403: last_doing_include = doing_include;
404: last_f_in = f_in;
405: last_file_name = file_name;
406: last_input_line_pointer = input_line_pointer;
407: last_logical_input_file = logical_input_file;
408: last_logical_input_line = logical_input_line;
409: last_partial_size = partial_size;
410: last_partial_where = partial_where;
411: last_physical_input_file = physical_input_file;
412: last_physical_input_line = physical_input_line;
413: memcpy(last_save_source, save_source, sizeof (save_source));
414: save_scrub_context (&scrub_context);
415: /*
416: * set up for another file
417: */
418: partial_size = 0;
419: doing_include = TRUE;
420: input_scrub_begin ();
421: buffer = input_scrub_new_file (whole_file_name);
422: if (f_in != (FILE *)0)
423: read_a_source_file(buffer);
424:
425: xfree (buffer_start);
426: /*
427: * restore the file state
428: */
429: buffer_limit = last_buffer_limit;
430: buffer_start = last_buffer_start;
431: doing_include = last_doing_include;
432: f_in = last_f_in;
433: file_name = last_file_name;
434: input_line_pointer = last_input_line_pointer;
435: logical_input_file = last_logical_input_file;
436: logical_input_line = last_logical_input_line;
437: partial_size = last_partial_size;
438: partial_where = last_partial_where;
439: physical_input_file = last_physical_input_file;
440: physical_input_line = last_physical_input_line;
441: memcpy(save_source, last_save_source, sizeof (save_source));
442: restore_scrub_context (&scrub_context);
443: } /* read_an_include_file */
444: #endif /* NeXT .include feature */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.