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