1 /*-
2  * This code is derived from software copyrighted by the Free Software
3  * Foundation.
4  *
5  * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)input-scrub.c	6.4 (Berkeley) 05/08/91";
10 #endif /* not lint */
11 
12 /* input_scrub.c - layer between app and the rest of the world
13    Copyright (C) 1987 Free Software Foundation, Inc.
14 
15 This file is part of GAS, the GNU Assembler.
16 
17 GAS is free software; you can redistribute it and/or modify
18 it under the terms of the GNU General Public License as published by
19 the Free Software Foundation; either version 1, or (at your option)
20 any later version.
21 
22 GAS is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25 GNU General Public License for more details.
26 
27 You should have received a copy of the GNU General Public License
28 along with GAS; see the file COPYING.  If not, write to
29 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
30 
31 #include "as.h"
32 #include "read.h"
33 #include "input-file.h"
34 
35 /*
36  * O/S independent module to supply buffers of sanitised source code
37  * to rest of assembler. We get raw input data of some length.
38  * Also looks after line numbers, for e.g. error messages.
39  * This module used to do the sanitising, but now a pre-processor program
40  * (app) does that job so this module is degenerate.
41  * Now input is pre-sanitised, so we only worry about finding the
42  * last partial line. A buffer of full lines is returned to caller.
43  * The last partial line begins the next buffer we build and return to caller.
44  * The buffer returned to caller is preceeded by BEFORE_STRING and followed
45  * by AFTER_STRING. The last character before AFTER_STRING is a newline.
46  */
47 
48 /*
49  * We expect the following sanitation has already been done.
50  *
51  * No comments, reduce a comment to a space.
52  * Reduce a tab to a space unless it is 1st char of line.
53  * All multiple tabs and spaces collapsed into 1 char. Tab only
54  *   legal if 1st char of line.
55  * # line file statements converted to .line x;.file y; statements.
56  * Escaped newlines at end of line: remove them but add as many newlines
57  *   to end of statement as you removed in the middle, to synch line numbers.
58  */
59 
60 #define BEFORE_STRING ("\n")
61 #define AFTER_STRING ("\0")	/* bcopy of 0 chars might choke. */
62 #define BEFORE_SIZE (1)
63 #define AFTER_SIZE  (1)
64 
65 static char *	buffer_start;	/* -> 1st char of full buffer area. */
66 static char *	partial_where;	/* -> after last full line in buffer. */
67 static int	partial_size;	/* >=0. Number of chars in partial line in buffer. */
68 static char	save_source [AFTER_SIZE];
69 				/* Because we need AFTER_STRING just after last */
70 				/* full line, it clobbers 1st part of partial */
71 				/* line. So we preserve 1st part of partial */
72 				/* line here. */
73 static int	buffer_length;	/* What is the largest size buffer that */
74 				/* input_file_give_next_buffer() could */
75 				/* return to us? */
76 
77 static void as_1_char ();
78 
79 /*
80 We never have more than one source file open at once.
81 We may, however, read more than 1 source file in an assembly.
82 NULL means we have no file open right now.
83 */
84 
85 
86 /*
87 We must track the physical file and line number for error messages.
88 We also track a "logical" file and line number corresponding to (C?)
89 compiler source line numbers.
90 Whenever we open a file we must fill in physical_input_file. So if it is NULL
91 we have not opened any files yet.
92 */
93 
94 static
95 char *		physical_input_file,
96      *		logical_input_file;
97 
98 
99 
100 typedef unsigned int line_numberT;	/* 1-origin line number in a source file. */
101 				/* A line ends in '\n' or eof. */
102 
103 static
104 line_numberT	physical_input_line,
105 		logical_input_line;
106 
107 void
108 input_scrub_begin ()
109 {
110   know( strlen(BEFORE_STRING) == BEFORE_SIZE );
111   know( strlen( AFTER_STRING) ==  AFTER_SIZE );
112 
113   input_file_begin ();
114 
115   buffer_length = input_file_buffer_size ();
116 
117   buffer_start = xmalloc ((long)(BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE));
118   bcopy (BEFORE_STRING, buffer_start, (int)BEFORE_SIZE);
119 
120   /* Line number things. */
121   logical_input_line = 0;
122   logical_input_file = (char *)NULL;
123   physical_input_file = NULL;	/* No file read yet. */
124   do_scrub_begin();
125 }
126 
127 void
128 input_scrub_end ()
129 {
130   input_file_end ();
131 }
132 
133 char *				/* Return start of caller's part of buffer. */
134 input_scrub_new_file (filename)
135      char *	filename;
136 {
137   input_file_open (filename, !flagseen['f']);
138   physical_input_file = filename[0] ? filename : "{standard input}";
139   physical_input_line = 0;
140 
141   partial_size = 0;
142   return (buffer_start + BEFORE_SIZE);
143 }
144 
145 char *
146 input_scrub_next_buffer (bufp)
147 char **bufp;
148 {
149   register char *	limit;	/* -> just after last char of buffer. */
150 
151 #ifdef DONTDEF
152   if(preprocess) {
153     if(save_buffer) {
154       *bufp = save_buffer;
155       save_buffer = 0;
156     }
157     limit = input_file_give_next_buffer(buffer_start+BEFORE_SIZE);
158     if (!limit) {
159       partial_where = 0;
160       if(partial_size)
161         as_warn("Partial line at end of file ignored");
162       return partial_where;
163     }
164 
165     if(partial_size)
166       bcopy(save_source, partial_where,(int)AFTER_SIZE);
167     do_scrub(partial_where,partial_size,buffer_start+BEFORE_SIZE,limit-(buffer_start+BEFORE_SIZE),&out_string,&out_length);
168     limit=out_string + out_length;
169     for(p=limit;*--p!='\n';)
170       ;
171     p++;
172     if(p<=buffer_start+BEFORE_SIZE)
173       as_fatal("Source line too long.  Please change file '%s' and re-make the assembler.",__FILE__);
174 
175     partial_where = p;
176     partial_size = limit-p;
177     bcopy(partial_where, save_source,(int)AFTER_SIZE);
178     bcopy(AFTER_STRING, partial_where, (int)AFTER_SIZE);
179 
180     save_buffer = *bufp;
181     *bufp = out_string;
182 
183     return partial_where;
184   }
185 
186   /* We're not preprocessing.  Do the right thing */
187 #endif
188   if (partial_size)
189     {
190       bcopy (partial_where, buffer_start + BEFORE_SIZE, (int)partial_size);
191       bcopy (save_source, buffer_start + BEFORE_SIZE, (int)AFTER_SIZE);
192     }
193   limit = input_file_give_next_buffer (buffer_start + BEFORE_SIZE + partial_size);
194   if (limit)
195     {
196       register char *	p;	/* Find last newline. */
197 
198       for (p = limit;   * -- p != '\n';   )
199 	{
200 	}
201       ++ p;
202       if (p <= buffer_start + BEFORE_SIZE)
203 	{
204 	  as_fatal ("Source line too long. Please change file %s then rebuild assembler.", __FILE__);
205 	}
206       partial_where = p;
207       partial_size = limit - p;
208       bcopy (partial_where, save_source,  (int)AFTER_SIZE);
209       bcopy (AFTER_STRING, partial_where, (int)AFTER_SIZE);
210     }
211   else
212     {
213       partial_where = 0;
214       if (partial_size > 0)
215 	{
216 	  as_warn( "Partial line at end of file ignored" );
217 	}
218     }
219   return (partial_where);
220 }
221 
222 /*
223  * The remaining part of this file deals with line numbers, error
224  * messages and so on.
225  */
226 
227 
228 int
229 seen_at_least_1_file ()		/* TRUE if we opened any file. */
230 {
231   return (physical_input_file != NULL);
232 }
233 
234 void
235 bump_line_counters ()
236 {
237   ++ physical_input_line;
238   ++ logical_input_line;
239 }
240 
241 /*
242  *			new_logical_line()
243  *
244  * Tells us what the new logical line number and file are.
245  * If the line_number is <0, we don't change the current logical line number.
246  * If the fname is NULL, we don't change the current logical file name.
247  */
248 void
249 new_logical_line (fname, line_number)
250      char *	fname;		/* DON'T destroy it! We point to it! */
251      int	line_number;
252 {
253   if ( fname )
254     {
255       logical_input_file = fname;
256     }
257   if ( line_number >= 0 )
258     {
259       logical_input_line = line_number;
260     }
261 }
262 
263 /*
264  *			a s _ w h e r e ( )
265  *
266  * Write a line to stderr locating where we are in reading
267  * input source files.
268  * As a sop to the debugger of AS, pretty-print the offending line.
269  */
270 void
271 as_where()
272 {
273   char *p;
274   line_numberT line;
275 
276   if (physical_input_file)
277     {				/* we tried to read SOME source */
278       if (input_file_is_open())
279 	{			/* we can still read lines from source */
280 #ifdef DONTDEF
281 	  fprintf (stderr," @ physical line %ld., file \"%s\"",
282 		   (long) physical_input_line, physical_input_file);
283 	  fprintf (stderr," @ logical line %ld., file \"%s\"\n",
284 		   (long) logical_input_line, logical_input_file);
285 	  (void)putc(' ', stderr);
286 	  as_howmuch (stderr);
287 	  (void)putc('\n', stderr);
288 #else
289 		p = logical_input_file ? logical_input_file : physical_input_file;
290 		line = logical_input_line ? logical_input_line : physical_input_line;
291 		fprintf(stderr,"%s:%u:", p, line);
292 #endif
293 	}
294       else
295 	{
296 #ifdef DONTDEF
297 	  fprintf (stderr," After reading source.\n");
298 #else
299 	p = logical_input_file ? logical_input_file : physical_input_file;
300 	line = logical_input_line ? logical_input_line : physical_input_line;
301 	fprintf (stderr,"%s:unknown:", p);
302 #endif
303 	}
304     }
305   else
306     {
307 #ifdef DONTDEF
308       fprintf (stderr," Before reading source.\n");
309 #else
310 #endif
311     }
312 }
313 
314 /*
315  * Support for source file debugging.  These functions handle
316  * logical lines and logical files.
317  */
318 static char *saved_file;
319 static int saved_len;
320 static line_numberT saved_line;
321 
322 void
323 filestab()
324 {
325   char *file;
326   int len;
327 
328   if (!physical_input_file ||
329       !input_file_is_open())
330     return;
331 
332   file = logical_input_file ? logical_input_file : physical_input_file;
333 
334   if (saved_file == 0 || strcmp(file, saved_file) != 0)
335     {
336       stabs(file);
337       len = strlen(file) + 1;
338       if (len > saved_len)
339 	{
340 	  if (saved_file == 0)
341 	    saved_file = xmalloc(len);
342 	  else
343 	    saved_file = xrealloc(saved_file, len);
344 	  memcpy(saved_file, file, len);
345 	  saved_len = len;
346 	}
347       else
348 	strcpy(saved_file, file);
349       saved_line = 0;
350     }
351 }
352 
353 void
354 funcstab(func)
355      char *func;
356 {
357   if (now_seg != SEG_TEXT)
358     return;
359 
360   filestab();
361   stabf(func);
362 }
363 
364 void
365 linestab()
366 {
367   line_numberT line;
368 
369   if (now_seg != SEG_TEXT)
370     return;
371 
372   filestab();
373 
374   line = logical_input_line ? logical_input_line : physical_input_line;
375 
376   if (saved_line == 0 || line != saved_line)
377     {
378       stabd(line);
379       saved_line = line;
380     }
381 }
382 
383 /*
384  *			a s _ h o w m u c h ( )
385  *
386  * Output to given stream how much of line we have scanned so far.
387  * Assumes we have scanned up to and including input_line_pointer.
388  * No free '\n' at end of line.
389  */
390 void
391 as_howmuch (stream)
392      FILE * stream;		/* Opened for write please. */
393 {
394   register	char *	p;	/* Scan input line. */
395   /* register	char	c; JF unused */
396 
397   for (p = input_line_pointer - 1;   * p != '\n';   --p)
398     {
399     }
400   ++ p;				/* p -> 1st char of line. */
401   for (;  p <= input_line_pointer;  p++)
402     {
403       /* Assume ASCII. EBCDIC & other micro-computer char sets ignored. */
404       /* c = *p & 0xFF; JF unused */
405       as_1_char (*p, stream);
406     }
407 }
408 
409 static void
410 as_1_char (c,stream)
411      unsigned char c;
412      FILE *	stream;
413 {
414   if ( c > 127 )
415     {
416       (void)putc( '%', stream);
417       c -= 128;
418     }
419   if ( c < 32 )
420     {
421       (void)putc( '^', stream);
422       c += '@';
423     }
424   (void)putc( c, stream);
425 }
426 
427 /* end: input_scrub.c */
428