1*47447Sdonn /*	@(#)input-scrub.c	6.3 (Berkeley) 03/15/91
247443Sdonn 
347443Sdonn Modified for Berkeley Unix by Donn Seeley, donn@okeeffe.berkeley.edu  */
447443Sdonn 
547405Sdonn /* input_scrub.c - layer between app and the rest of the world
647405Sdonn    Copyright (C) 1987 Free Software Foundation, Inc.
747405Sdonn 
847405Sdonn This file is part of GAS, the GNU Assembler.
947405Sdonn 
1047405Sdonn GAS is free software; you can redistribute it and/or modify
1147405Sdonn it under the terms of the GNU General Public License as published by
1247405Sdonn the Free Software Foundation; either version 1, or (at your option)
1347405Sdonn any later version.
1447405Sdonn 
1547405Sdonn GAS is distributed in the hope that it will be useful,
1647405Sdonn but WITHOUT ANY WARRANTY; without even the implied warranty of
1747405Sdonn MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1847405Sdonn GNU General Public License for more details.
1947405Sdonn 
2047405Sdonn You should have received a copy of the GNU General Public License
2147405Sdonn along with GAS; see the file COPYING.  If not, write to
2247405Sdonn the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
2347405Sdonn 
2447405Sdonn #include "as.h"
2547405Sdonn #include "read.h"
2647405Sdonn #include "input-file.h"
2747405Sdonn 
2847405Sdonn /*
2947405Sdonn  * O/S independent module to supply buffers of sanitised source code
3047405Sdonn  * to rest of assembler. We get raw input data of some length.
3147405Sdonn  * Also looks after line numbers, for e.g. error messages.
3247405Sdonn  * This module used to do the sanitising, but now a pre-processor program
3347405Sdonn  * (app) does that job so this module is degenerate.
3447405Sdonn  * Now input is pre-sanitised, so we only worry about finding the
3547405Sdonn  * last partial line. A buffer of full lines is returned to caller.
3647405Sdonn  * The last partial line begins the next buffer we build and return to caller.
3747405Sdonn  * The buffer returned to caller is preceeded by BEFORE_STRING and followed
3847405Sdonn  * by AFTER_STRING. The last character before AFTER_STRING is a newline.
3947405Sdonn  */
4047405Sdonn 
4147405Sdonn /*
4247405Sdonn  * We expect the following sanitation has already been done.
4347405Sdonn  *
4447405Sdonn  * No comments, reduce a comment to a space.
4547405Sdonn  * Reduce a tab to a space unless it is 1st char of line.
4647405Sdonn  * All multiple tabs and spaces collapsed into 1 char. Tab only
4747405Sdonn  *   legal if 1st char of line.
4847405Sdonn  * # line file statements converted to .line x;.file y; statements.
4947405Sdonn  * Escaped newlines at end of line: remove them but add as many newlines
5047405Sdonn  *   to end of statement as you removed in the middle, to synch line numbers.
5147405Sdonn  */
5247405Sdonn 
5347405Sdonn #define BEFORE_STRING ("\n")
5447405Sdonn #define AFTER_STRING ("\0")	/* bcopy of 0 chars might choke. */
5547405Sdonn #define BEFORE_SIZE (1)
5647405Sdonn #define AFTER_SIZE  (1)
5747405Sdonn 
5847405Sdonn static char *	buffer_start;	/* -> 1st char of full buffer area. */
5947405Sdonn static char *	partial_where;	/* -> after last full line in buffer. */
6047405Sdonn static int	partial_size;	/* >=0. Number of chars in partial line in buffer. */
6147405Sdonn static char	save_source [AFTER_SIZE];
6247405Sdonn 				/* Because we need AFTER_STRING just after last */
6347405Sdonn 				/* full line, it clobbers 1st part of partial */
6447405Sdonn 				/* line. So we preserve 1st part of partial */
6547405Sdonn 				/* line here. */
6647405Sdonn static int	buffer_length;	/* What is the largest size buffer that */
6747405Sdonn 				/* input_file_give_next_buffer() could */
6847405Sdonn 				/* return to us? */
6947405Sdonn 
7047405Sdonn static void as_1_char ();
7147405Sdonn 
7247405Sdonn /*
7347405Sdonn We never have more than one source file open at once.
7447405Sdonn We may, however, read more than 1 source file in an assembly.
7547405Sdonn NULL means we have no file open right now.
7647405Sdonn */
7747405Sdonn 
7847405Sdonn 
7947405Sdonn /*
8047405Sdonn We must track the physical file and line number for error messages.
8147405Sdonn We also track a "logical" file and line number corresponding to (C?)
8247405Sdonn compiler source line numbers.
8347405Sdonn Whenever we open a file we must fill in physical_input_file. So if it is NULL
8447405Sdonn we have not opened any files yet.
8547405Sdonn */
8647405Sdonn 
8747405Sdonn static
8847405Sdonn char *		physical_input_file,
8947405Sdonn      *		logical_input_file;
9047405Sdonn 
9147405Sdonn 
9247405Sdonn 
9347405Sdonn typedef unsigned int line_numberT;	/* 1-origin line number in a source file. */
9447405Sdonn 				/* A line ends in '\n' or eof. */
9547405Sdonn 
9647405Sdonn static
9747405Sdonn line_numberT	physical_input_line,
9847405Sdonn 		logical_input_line;
9947405Sdonn 
10047405Sdonn void
10147405Sdonn input_scrub_begin ()
10247405Sdonn {
10347405Sdonn   know( strlen(BEFORE_STRING) == BEFORE_SIZE );
10447405Sdonn   know( strlen( AFTER_STRING) ==  AFTER_SIZE );
10547405Sdonn 
10647405Sdonn   input_file_begin ();
10747405Sdonn 
10847405Sdonn   buffer_length = input_file_buffer_size ();
10947405Sdonn 
11047405Sdonn   buffer_start = xmalloc ((long)(BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE));
11147405Sdonn   bcopy (BEFORE_STRING, buffer_start, (int)BEFORE_SIZE);
11247405Sdonn 
11347405Sdonn   /* Line number things. */
11447405Sdonn   logical_input_line = 0;
11547405Sdonn   logical_input_file = (char *)NULL;
11647405Sdonn   physical_input_file = NULL;	/* No file read yet. */
11747405Sdonn   do_scrub_begin();
11847405Sdonn }
11947405Sdonn 
12047405Sdonn void
12147405Sdonn input_scrub_end ()
12247405Sdonn {
12347405Sdonn   input_file_end ();
12447405Sdonn }
12547405Sdonn 
12647405Sdonn char *				/* Return start of caller's part of buffer. */
12747405Sdonn input_scrub_new_file (filename)
12847405Sdonn      char *	filename;
12947405Sdonn {
13047405Sdonn   input_file_open (filename, !flagseen['f']);
13147405Sdonn   physical_input_file = filename[0] ? filename : "{standard input}";
13247405Sdonn   physical_input_line = 0;
13347405Sdonn 
13447405Sdonn   partial_size = 0;
13547405Sdonn   return (buffer_start + BEFORE_SIZE);
13647405Sdonn }
13747405Sdonn 
13847405Sdonn char *
13947405Sdonn input_scrub_next_buffer (bufp)
14047405Sdonn char **bufp;
14147405Sdonn {
14247405Sdonn   register char *	limit;	/* -> just after last char of buffer. */
14347405Sdonn 
14447405Sdonn #ifdef DONTDEF
14547405Sdonn   if(preprocess) {
14647405Sdonn     if(save_buffer) {
14747405Sdonn       *bufp = save_buffer;
14847405Sdonn       save_buffer = 0;
14947405Sdonn     }
15047405Sdonn     limit = input_file_give_next_buffer(buffer_start+BEFORE_SIZE);
15147405Sdonn     if (!limit) {
15247405Sdonn       partial_where = 0;
15347405Sdonn       if(partial_size)
15447405Sdonn         as_warn("Partial line at end of file ignored");
15547405Sdonn       return partial_where;
15647405Sdonn     }
15747405Sdonn 
15847405Sdonn     if(partial_size)
15947405Sdonn       bcopy(save_source, partial_where,(int)AFTER_SIZE);
16047405Sdonn     do_scrub(partial_where,partial_size,buffer_start+BEFORE_SIZE,limit-(buffer_start+BEFORE_SIZE),&out_string,&out_length);
16147405Sdonn     limit=out_string + out_length;
16247405Sdonn     for(p=limit;*--p!='\n';)
16347405Sdonn       ;
16447405Sdonn     p++;
16547405Sdonn     if(p<=buffer_start+BEFORE_SIZE)
16647405Sdonn       as_fatal("Source line too long.  Please change file '%s' and re-make the assembler.",__FILE__);
16747405Sdonn 
16847405Sdonn     partial_where = p;
16947405Sdonn     partial_size = limit-p;
17047405Sdonn     bcopy(partial_where, save_source,(int)AFTER_SIZE);
17147405Sdonn     bcopy(AFTER_STRING, partial_where, (int)AFTER_SIZE);
17247405Sdonn 
17347405Sdonn     save_buffer = *bufp;
17447405Sdonn     *bufp = out_string;
17547405Sdonn 
17647405Sdonn     return partial_where;
17747405Sdonn   }
17847405Sdonn 
17947405Sdonn   /* We're not preprocessing.  Do the right thing */
18047405Sdonn #endif
18147405Sdonn   if (partial_size)
18247405Sdonn     {
18347405Sdonn       bcopy (partial_where, buffer_start + BEFORE_SIZE, (int)partial_size);
18447405Sdonn       bcopy (save_source, buffer_start + BEFORE_SIZE, (int)AFTER_SIZE);
18547405Sdonn     }
18647405Sdonn   limit = input_file_give_next_buffer (buffer_start + BEFORE_SIZE + partial_size);
18747405Sdonn   if (limit)
18847405Sdonn     {
18947405Sdonn       register char *	p;	/* Find last newline. */
19047405Sdonn 
19147405Sdonn       for (p = limit;   * -- p != '\n';   )
19247405Sdonn 	{
19347405Sdonn 	}
19447405Sdonn       ++ p;
19547405Sdonn       if (p <= buffer_start + BEFORE_SIZE)
19647405Sdonn 	{
19747405Sdonn 	  as_fatal ("Source line too long. Please change file %s then rebuild assembler.", __FILE__);
19847405Sdonn 	}
19947405Sdonn       partial_where = p;
20047405Sdonn       partial_size = limit - p;
20147405Sdonn       bcopy (partial_where, save_source,  (int)AFTER_SIZE);
20247405Sdonn       bcopy (AFTER_STRING, partial_where, (int)AFTER_SIZE);
20347405Sdonn     }
20447405Sdonn   else
20547405Sdonn     {
20647405Sdonn       partial_where = 0;
20747405Sdonn       if (partial_size > 0)
20847405Sdonn 	{
20947405Sdonn 	  as_warn( "Partial line at end of file ignored" );
21047405Sdonn 	}
21147405Sdonn     }
21247405Sdonn   return (partial_where);
21347405Sdonn }
21447405Sdonn 
21547405Sdonn /*
21647405Sdonn  * The remaining part of this file deals with line numbers, error
21747405Sdonn  * messages and so on.
21847405Sdonn  */
21947405Sdonn 
22047405Sdonn 
22147405Sdonn int
22247405Sdonn seen_at_least_1_file ()		/* TRUE if we opened any file. */
22347405Sdonn {
22447405Sdonn   return (physical_input_file != NULL);
22547405Sdonn }
22647405Sdonn 
22747405Sdonn void
22847405Sdonn bump_line_counters ()
22947405Sdonn {
23047405Sdonn   ++ physical_input_line;
23147405Sdonn   ++ logical_input_line;
23247405Sdonn }
23347405Sdonn 
23447405Sdonn /*
23547405Sdonn  *			new_logical_line()
23647405Sdonn  *
23747405Sdonn  * Tells us what the new logical line number and file are.
23847405Sdonn  * If the line_number is <0, we don't change the current logical line number.
23947405Sdonn  * If the fname is NULL, we don't change the current logical file name.
24047405Sdonn  */
24147405Sdonn void
24247405Sdonn new_logical_line (fname, line_number)
24347405Sdonn      char *	fname;		/* DON'T destroy it! We point to it! */
24447405Sdonn      int	line_number;
24547405Sdonn {
24647405Sdonn   if ( fname )
24747405Sdonn     {
24847405Sdonn       logical_input_file = fname;
24947405Sdonn     }
25047405Sdonn   if ( line_number >= 0 )
25147405Sdonn     {
25247405Sdonn       logical_input_line = line_number;
25347405Sdonn     }
25447405Sdonn }
25547405Sdonn 
25647405Sdonn /*
25747405Sdonn  *			a s _ w h e r e ( )
25847405Sdonn  *
25947405Sdonn  * Write a line to stderr locating where we are in reading
26047405Sdonn  * input source files.
26147405Sdonn  * As a sop to the debugger of AS, pretty-print the offending line.
26247405Sdonn  */
26347405Sdonn void
26447405Sdonn as_where()
26547405Sdonn {
26647405Sdonn   char *p;
26747405Sdonn   line_numberT line;
26847405Sdonn 
26947405Sdonn   if (physical_input_file)
27047405Sdonn     {				/* we tried to read SOME source */
27147405Sdonn       if (input_file_is_open())
27247405Sdonn 	{			/* we can still read lines from source */
27347405Sdonn #ifdef DONTDEF
27447405Sdonn 	  fprintf (stderr," @ physical line %ld., file \"%s\"",
27547405Sdonn 		   (long) physical_input_line, physical_input_file);
27647405Sdonn 	  fprintf (stderr," @ logical line %ld., file \"%s\"\n",
27747405Sdonn 		   (long) logical_input_line, logical_input_file);
27847405Sdonn 	  (void)putc(' ', stderr);
27947405Sdonn 	  as_howmuch (stderr);
28047405Sdonn 	  (void)putc('\n', stderr);
28147405Sdonn #else
28247405Sdonn 		p = logical_input_file ? logical_input_file : physical_input_file;
28347405Sdonn 		line = logical_input_line ? logical_input_line : physical_input_line;
28447405Sdonn 		fprintf(stderr,"%s:%u:", p, line);
28547405Sdonn #endif
28647405Sdonn 	}
28747405Sdonn       else
28847405Sdonn 	{
28947405Sdonn #ifdef DONTDEF
29047405Sdonn 	  fprintf (stderr," After reading source.\n");
29147405Sdonn #else
29247405Sdonn 	p = logical_input_file ? logical_input_file : physical_input_file;
29347405Sdonn 	line = logical_input_line ? logical_input_line : physical_input_line;
29447405Sdonn 	fprintf (stderr,"%s:unknown:", p);
29547405Sdonn #endif
29647405Sdonn 	}
29747405Sdonn     }
29847405Sdonn   else
29947405Sdonn     {
30047405Sdonn #ifdef DONTDEF
30147405Sdonn       fprintf (stderr," Before reading source.\n");
30247405Sdonn #else
30347405Sdonn #endif
30447405Sdonn     }
30547405Sdonn }
30647443Sdonn 
30747443Sdonn /*
308*47447Sdonn  * Support for source file debugging.  These functions handle
309*47447Sdonn  * logical lines and logical files.
31047443Sdonn  */
311*47447Sdonn static char *saved_file;
312*47447Sdonn static int saved_len;
313*47447Sdonn static line_numberT saved_line;
314*47447Sdonn 
31547443Sdonn void
316*47447Sdonn filestab()
31747443Sdonn {
31847443Sdonn   char *file;
31947443Sdonn   int len;
32047405Sdonn 
321*47447Sdonn   if (!physical_input_file ||
322*47447Sdonn       !input_file_is_open())
32347443Sdonn     return;
32447405Sdonn 
32547443Sdonn   file = logical_input_file ? logical_input_file : physical_input_file;
32647405Sdonn 
32747443Sdonn   if (saved_file == 0 || strcmp(file, saved_file) != 0)
32847443Sdonn     {
32947443Sdonn       stabs(file);
33047443Sdonn       len = strlen(file) + 1;
33147443Sdonn       if (len > saved_len)
33247443Sdonn 	{
33347443Sdonn 	  if (saved_file == 0)
33447443Sdonn 	    saved_file = xmalloc(len);
33547443Sdonn 	  else
33647443Sdonn 	    saved_file = xrealloc(saved_file, len);
33747443Sdonn 	  memcpy(saved_file, file, len);
33847443Sdonn 	  saved_len = len;
33947443Sdonn 	}
34047443Sdonn       else
34147443Sdonn 	strcpy(saved_file, file);
34247443Sdonn       saved_line = 0;
34347443Sdonn     }
344*47447Sdonn }
34547443Sdonn 
346*47447Sdonn void
347*47447Sdonn funcstab(func)
348*47447Sdonn      char *func;
349*47447Sdonn {
350*47447Sdonn   if (now_seg != SEG_TEXT)
351*47447Sdonn     return;
352*47447Sdonn 
353*47447Sdonn   filestab();
354*47447Sdonn   stabf(func);
355*47447Sdonn }
356*47447Sdonn 
357*47447Sdonn void
358*47447Sdonn linestab()
359*47447Sdonn {
360*47447Sdonn   line_numberT line;
361*47447Sdonn 
362*47447Sdonn   if (now_seg != SEG_TEXT)
363*47447Sdonn     return;
364*47447Sdonn 
365*47447Sdonn   filestab();
366*47447Sdonn 
367*47447Sdonn   line = logical_input_line ? logical_input_line : physical_input_line;
368*47447Sdonn 
36947443Sdonn   if (saved_line == 0 || line != saved_line)
37047443Sdonn     {
37147443Sdonn       stabd(line);
37247443Sdonn       saved_line = line;
37347443Sdonn     }
37447443Sdonn }
37547405Sdonn 
37647405Sdonn /*
37747405Sdonn  *			a s _ h o w m u c h ( )
37847405Sdonn  *
37947405Sdonn  * Output to given stream how much of line we have scanned so far.
38047405Sdonn  * Assumes we have scanned up to and including input_line_pointer.
38147405Sdonn  * No free '\n' at end of line.
38247405Sdonn  */
38347405Sdonn void
38447405Sdonn as_howmuch (stream)
38547405Sdonn      FILE * stream;		/* Opened for write please. */
38647405Sdonn {
38747405Sdonn   register	char *	p;	/* Scan input line. */
38847405Sdonn   /* register	char	c; JF unused */
38947405Sdonn 
39047405Sdonn   for (p = input_line_pointer - 1;   * p != '\n';   --p)
39147405Sdonn     {
39247405Sdonn     }
39347405Sdonn   ++ p;				/* p -> 1st char of line. */
39447405Sdonn   for (;  p <= input_line_pointer;  p++)
39547405Sdonn     {
39647405Sdonn       /* Assume ASCII. EBCDIC & other micro-computer char sets ignored. */
39747405Sdonn       /* c = *p & 0xFF; JF unused */
39847405Sdonn       as_1_char (*p, stream);
39947405Sdonn     }
40047405Sdonn }
40147405Sdonn 
40247405Sdonn static void
40347405Sdonn as_1_char (c,stream)
40447405Sdonn      unsigned char c;
40547405Sdonn      FILE *	stream;
40647405Sdonn {
40747405Sdonn   if ( c > 127 )
40847405Sdonn     {
40947405Sdonn       (void)putc( '%', stream);
41047405Sdonn       c -= 128;
41147405Sdonn     }
41247405Sdonn   if ( c < 32 )
41347405Sdonn     {
41447405Sdonn       (void)putc( '^', stream);
41547405Sdonn       c += '@';
41647405Sdonn     }
41747405Sdonn   (void)putc( c, stream);
41847405Sdonn }
41947405Sdonn 
42047405Sdonn /* end: input_scrub.c */
421