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