00001 /* 00002 * OpenBIOS - free your system! 00003 * ( FCode tokenizer ) 00004 * 00005 * stream.c - source program streaming from file. 00006 * 00007 * This program is part of a free implementation of the IEEE 1275-1994 00008 * Standard for Boot (Initialization Configuration) Firmware. 00009 * 00010 * Copyright (C) 2001-2005 by Stefan Reinauer <stepan@openbios.org> 00011 * 00012 * This program is free software; you can redistribute it and/or modify 00013 * it under the terms of the GNU General Public License as published by 00014 * the Free Software Foundation; version 2 of the License. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software 00023 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA 00024 * 00025 */ 00026 00027 /* ************************************************************************** 00028 * Modifications made in 2005 by IBM Corporation 00029 * (C) Copyright 2005 IBM Corporation. All Rights Reserved. 00030 * Modifications Author: David L. Paktor dlpaktor@us.ibm.com 00031 **************************************************************************** */ 00032 00033 #include <stdio.h> 00034 #include <stdlib.h> 00035 #ifdef __GLIBC__ 00036 #define __USE_XOPEN_EXTENDED 00037 #endif 00038 #include <string.h> 00039 #include <sys/stat.h> 00040 00041 #include "emit.h" 00042 #include "stream.h" 00043 #include "errhandler.h" 00044 #include "toke.h" 00045 00046 /* ************************************************************************** 00047 * 00048 * Revision History: 00049 * Updated Tue, 31 Jan 2006 by David L. Paktor 00050 * Add support for embedded Environment-Variables in path name 00051 * Updated Thu, 16 Feb 2006 David L. Paktor 00052 * Collect missing (inaccessible) filenames 00053 * Updated Thu, 16 Mar 2006 David L. Paktor 00054 * Add support for Include-Lists 00055 * 00056 **************************************************************************** */ 00057 00058 /* ************************************************************************** 00059 * 00060 * Global Variables Exported 00061 * start Start of input-source buffer 00062 * end End of input-source buffer 00063 * pc Input-source Scanning pointer 00064 * iname Current Input File name 00065 * lineno Current Line Number in Input File 00066 * ostart Start of Output Buffer 00067 * opc FCode Output Buffer Position Counter 00068 * oname Output File name 00069 * 00070 **************************************************************************** */ 00071 00072 00073 /* Input pointers, Position Counters and Length counters */ 00074 u8 *start = NULL; 00075 u8 *pc; 00076 u8 *end; 00077 char *iname = NULL; 00078 unsigned int lineno = 0; 00079 unsigned int abs_token_no = 0; /* Absolute Token Number in all Source Input 00080 * Will be used to identify position 00081 * where colon-definition begins and 00082 * to limit clearing of control-structs. 00083 */ 00084 static unsigned int ilen; /* Length of Input Buffer */ 00085 00086 /* output pointers */ 00087 u8 *ostart; 00088 char *oname = NULL; 00089 unsigned int opc; /* Output Position Counter */ 00090 00091 /* We want to limit exposure of this v'ble, so don't put it in .h file */ 00092 unsigned int olen; /* Length of Output Buffer */ 00093 /* We want to limit exposure of this Imported Function, likewise. */ 00094 void init_emit( void); 00095 00096 /* ************************************************************************** 00097 * 00098 * Internal Static Variables 00099 * load_list_name Name of the Load List File 00100 * load_list_file (Pointer to) File-Structure for the Load List File 00101 * depncy_list_name Name of the Dependency List File 00102 * depncy_file (Pointer to) File-Structure for the Dependency List File 00103 * missing_list_name Name of the Missing-Files-List File 00104 * missing_list_file (Pointer to) File-Structure for Missing-List File 00105 * no_files_missing TRUE if able to load all files 00106 * 00107 **************************************************************************** */ 00108 00109 static char *load_list_name; 00110 static FILE *load_list_file; 00111 static char *depncy_list_name; 00112 static FILE *depncy_file; 00113 static char *missing_list_name; 00114 static FILE *missing_list_file; 00115 static bool no_files_missing = TRUE; 00116 00117 /* ************************************************************************** 00118 * 00119 * Private data-structure for Include-List support 00120 * 00121 * Components are simply a string-pointer and a link pointer 00122 * 00123 **************************************************************************** */ 00124 00125 typedef struct incl_list 00126 { 00127 char *dir_path; 00128 struct incl_list *next; 00129 } incl_list_t; 00130 00131 /* ************************************************************************** 00132 * 00133 * Internal Static Variables associated with Include-List support 00134 * include_list_start Start of the Include-List 00135 * include_list_next Next entry in Include-List to add or read 00136 * max_dir_path_len Size of longest entry in the Include-List 00137 * include_list_full_path Full-Path (i.e., expanded File-name with 00138 * Include-List Entry) that was last opened. 00139 * 00140 **************************************************************************** */ 00141 static incl_list_t *include_list_start = NULL; 00142 static incl_list_t *include_list_next = NULL; 00143 static unsigned int max_dir_path_len = 0; 00144 static char *include_list_full_path = NULL; 00145 00146 00147 /* ************************************************************************** 00148 * 00149 * Function name: add_to_include_list 00150 * Synopsis: Add an entry to the Include-List 00151 * 00152 * Inputs: 00153 * Parameters: 00154 * dir_compt Directory Component to add to Inc-List 00155 * Local Static Variables: 00156 * include_list_start First entry in the Include-List 00157 * include_list_next Next entry in Include-List to add 00158 * max_dir_path_len Previous max Dir-Component Length 00159 * 00160 * Outputs: 00161 * Returned Value: NONE 00162 * Local Static Variables: 00163 * include_list_start Assigned a value, first time through 00164 * include_list_next "Next" field updated with new entry, 00165 * then pointer updated to new entry. 00166 * max_dir_path_len Maximum Length 00167 * Memory Allocated 00168 * For the list-entry, and for the directory/path name to be added 00169 * When Freed? 00170 * Remains in effect through the life of the program. 00171 * 00172 * Process Explanation: 00173 * Unlike most of our linked-lists, this one will be linked forward, 00174 * i.e., in the order elements are added, and will be searched 00175 * in a forward order. 00176 * This means extra code to handle the first entry. 00177 * Allocate and initialize the New Include-List Entry. 00178 * If this is the first entry, point the List-Starter at it. 00179 * Otherwise, the Last-Entry-on-the-List pointer is already valid; 00180 * point its "next" field at the New Entry. 00181 * Point the Last-Entry-on-the-List pointer at the New Entry. 00182 * 00183 **************************************************************************** */ 00184 00185 void add_to_include_list( char *dir_compt) 00186 { 00187 unsigned int new_path_len = strlen( dir_compt); 00188 incl_list_t *new_i_l_e = safe_malloc( sizeof( incl_list_t), 00189 "adding to include-list" ); 00190 00191 new_i_l_e->dir_path = strdup( dir_compt); 00192 new_i_l_e->next = NULL; 00193 00194 if ( include_list_start == NULL ) 00195 { 00196 include_list_start = new_i_l_e; 00197 }else{ 00198 include_list_next->next = new_i_l_e; 00199 } 00200 00201 include_list_next = new_i_l_e; 00202 if ( new_path_len > max_dir_path_len ) max_dir_path_len = new_path_len; 00203 } 00204 00205 #define DISPLAY_WIDTH 80 00206 /* ************************************************************************** 00207 * 00208 * Function name: display_include_list 00209 * Synopsis: Display the Include-List, once it's completed, 00210 * if "verbose" mode is in effect. 00211 * 00212 * Inputs: 00213 * Parameters: NONE 00214 * Local Static Variables: 00215 * include_list_start First entry in the Include-List 00216 * include_list_next Next entry, as we step through. 00217 * Macro: 00218 * DISPLAY_WIDTH Width limit of the display 00219 * 00220 * Outputs: 00221 * Returned Value: NONE 00222 * Local Static Variables: 00223 * include_list_next NULL, when reaches end of Incl-List 00224 * Printout: 00225 * The elements of the Include-List, separated by a space, on 00226 * a line up to the DISPLAY_WIDTH, or on a line by itself 00227 * if the element is wider. 00228 * 00229 * Process Explanation: 00230 * The calling routine will check for the verbose flag. 00231 * Nothing to be done here if Include-List is NULL. 00232 * Print a header, then the list. 00233 * 00234 **************************************************************************** */ 00235 00236 void display_include_list( void) 00237 { 00238 if ( include_list_start != NULL ) 00239 { 00240 int curr_wid = DISPLAY_WIDTH; /* Current width; force new line */ 00241 printf("\nInclude-List:"); 00242 include_list_next = include_list_start ; 00243 while ( include_list_next != NULL ) 00244 { 00245 int this_wid = strlen( include_list_next->dir_path) + 1; 00246 char *separator = " "; 00247 if ( curr_wid + this_wid > DISPLAY_WIDTH ) 00248 { 00249 separator = "\n\t"; 00250 curr_wid = 7; /* Allow 1 for the theoretical space */ 00251 } 00252 printf("%s%s", separator, include_list_next->dir_path); 00253 curr_wid += this_wid; 00254 include_list_next = include_list_next->next ; 00255 } 00256 printf("\n"); 00257 } 00258 } 00259 00260 00261 00262 /* ************************************************************************** 00263 * 00264 * We cannot accommodate the structures of the different 00265 * routines that open files with a single function, so 00266 * we will have to divide the action up into pieces: 00267 * one routine to initialize the include-list search, a 00268 * second to return successive candidates. The calling 00269 * routine will do the operation (stat or fopen) until 00270 * it succeeds or the list is exhausted. Then it will 00271 * call a final routine to clean up and display messages. 00272 * 00273 * I'm sure I don't need to mention that, when no include-list 00274 * is defined, these functions will still support correct 00275 * operation... 00276 * 00277 **************************************************************************** */ 00278 00279 /* ************************************************************************** 00280 * 00281 * Function name: init_incl_list_scan 00282 * Synopsis: Initialize the search through the Include-List 00283 * 00284 * Inputs: 00285 * Parameters: 00286 * base_name Expanded user-supplied file-name 00287 * Local Static Variables: 00288 * include_list_start First entry in the Include-List 00289 * max_dir_path_len Maximum Directory Component Length 00290 * 00291 * Outputs: 00292 * Returned Value: NONE 00293 * Local Static Variables: 00294 * include_list_next Next entry in Include-List to read 00295 * include_list_full_path Full-Path Buffer pointer 00296 * Memory Allocated 00297 * Full-Path Buffer (If Include-List was defined) 00298 * When Freed? 00299 * In finish_incl_list_scan() 00300 * 00301 * Process Explanation: 00302 * The base_name passed to the routine is expected to have 00303 * any embedded Environment-Variables already expanded. 00304 * The Full-Path Buffer is presumed to be unallocated, and 00305 * its pointer to be NULL. 00306 * The Next-Entry-to-read pointer is also presumed to be NULL. 00307 * If an Include-List has been defined, we will allocate memory 00308 * for the Full-Path Buffer and point the Next-Entry pointer 00309 * at the Start of the List. If not, no need to do anything. 00310 * 00311 **************************************************************************** */ 00312 00313 static void init_incl_list_scan( char *base_name) 00314 { 00315 if ( include_list_start != NULL ) 00316 { 00317 /* Allocate memory for the file-name buffer. 00318 * maximum path-element length plus base-name length 00319 * plus one for the slash plus one for the ending NULL 00320 */ 00321 unsigned int new_path_len = max_dir_path_len + strlen( base_name) + 2; 00322 include_list_full_path = safe_malloc( new_path_len, 00323 "scanning include-list" ); 00324 include_list_next = include_list_start; 00325 } 00326 } 00327 00328 /* ************************************************************************** 00329 * 00330 * Function name: scan_incl_list 00331 * Synopsis: Prepare the next candidate in the include-list search 00332 * Indicate when the end has been reached. 00333 * 00334 * Inputs: 00335 * Parameters: 00336 * base_name Expanded user-supplied file-name 00337 * Local Static Variables: 00338 * include_list_full_path Full-Path Buffer pointer 00339 * include_list_next Next entry in Include-List to read 00340 * 00341 * Outputs: 00342 * Returned Value: TRUE if valid candidate; FALSE when done 00343 * Local Static Variables: 00344 * include_list_full_path Next Full file-name Path to use 00345 * include_list_next Updated to next entry in the List 00346 * 00347 * Process Explanation: 00348 * Include-List Components are presumed not to require any expansion; 00349 * the Shell is expected to resolve any Environment-Variables 00350 * supplied in command-line arguments before they are passed 00351 * to the (this) application-program. 00352 * We will, therefore, not attempt to expand any Components of 00353 * the Include-List. 00354 * If the Full-Path Buffer pointer is NULL, it indicates that no 00355 * entries have been made to the Include-List and this is our 00356 * first time through this routine in this search; we will 00357 * use the base-name as supplied, presumably relative to the 00358 * current directory. Point the buffer-pointer at the base- 00359 * -name and return "Not Done". 00360 * Otherwise, we will look at the Next-Entry pointer: 00361 * If it is NULL, we have come to the end of the Include-List; 00362 * whether because no Include-List was defined or because 00363 * we have reached the end, we will return "Done". 00364 * Otherwise, we will load the Full-Path Buffer with the entry 00365 * currently indicated by the Next-Entry pointer, advance 00366 * it to the next entry in the List and return "Not Done". 00367 * We will supply a slash as the directory-element separator in 00368 * between the Include-List entry and the base_name 00369 * 00370 * Extraneous Remarks: 00371 * The slash as directory-element separator works in UNIX-related 00372 * environments, but is not guaranteed in others. I would 00373 * have preferred to specify that Include-List Components are 00374 * required to end with the appropriate separator, but that 00375 * was neither acceptable nor compatible with existing practice 00376 * in other utilities, and the effort to programmatically 00377 * determine the separator used by the Host O/S was too much 00378 * for such a small return. And besides, we already have so 00379 * many other UNIX-centric assumptions hard-coded into the 00380 * routines in this file (dollar-sign to signify Environment 00381 * Variables, period for file-name-extension separator, etc.) 00382 * that it's just too much of an uphill battle anymore... 00383 * 00384 **************************************************************************** */ 00385 00386 static bool scan_incl_list( char *base_name) 00387 { 00388 bool retval = FALSE; /* default to "Done" */ 00389 00390 if ( include_list_full_path == NULL ) 00391 { 00392 include_list_full_path = base_name; 00393 retval = TRUE; 00394 }else{ 00395 if ( include_list_next != NULL ) 00396 { 00397 00398 /* Special case: If the next Directory Component is 00399 * an empty string, do not prepend a slash; that 00400 * would either become a root-based absolute path, 00401 * or, if the base-name is itself an absolute path, 00402 * it would be a path that begins with two slashes, 00403 * and *some* Host Operating Systems ***REALLY*** 00404 * DO NOT LIKE that! 00405 */ 00406 if ( strlen( include_list_next->dir_path) == 0 ) 00407 { 00408 sprintf( include_list_full_path, "%s", base_name); 00409 }else{ 00410 sprintf( include_list_full_path, "%s/%s", 00411 include_list_next->dir_path, base_name); 00412 } 00413 include_list_next = include_list_next->next; 00414 retval = TRUE; 00415 } 00416 } 00417 00418 return( retval); 00419 } 00420 00421 /* ************************************************************************** 00422 * 00423 * Function name: finish_incl_list_scan 00424 * Synopsis: Clean up after a search through the Include-List 00425 * Display appropriate messages. 00426 * 00427 * Inputs: 00428 * Parameters: 00429 * op_succeeded TRUE if intended operation was ok. 00430 * 00431 * Local Static Variables: 00432 * include_list_start Non-NULL if Include-List was defined 00433 * 00434 * Outputs: 00435 * Returned Value: NONE 00436 * Local Static Variables: 00437 * include_list_full_path Reset to NULL 00438 * include_list_next Reset to NULL 00439 * Memory Freed 00440 * Full-Path Buffer (If Include-List was defined) 00441 * Printout: 00442 * If file was found in Include-List, Advisory showing where. 00443 * 00444 **************************************************************************** */ 00445 00446 static void finish_incl_list_scan( bool op_succeeded) 00447 { 00448 if ( include_list_start != NULL ) 00449 { 00450 if ( op_succeeded ) 00451 { 00452 tokenization_error( INFO, 00453 "File was found in %s\n" ,include_list_full_path ); 00454 } 00455 free( include_list_full_path); 00456 } 00457 include_list_full_path = NULL; 00458 include_list_next = NULL; 00459 } 00460 00461 /* ************************************************************************** 00462 * 00463 * Function name: open_incl_list_file 00464 * Synopsis: Look in the Include-List, if one is defined, for 00465 * the file whose name is given and open it. 00466 * 00467 * Inputs: 00468 * Parameters: 00469 * base_name Expanded user-supplied file-name 00470 * mode Mode-string to use; usually "r" or "rb" 00471 * Local Static Variables: 00472 * include_list_full_path Full Path to use in fopen atttempt 00473 * 00474 * Outputs: 00475 * Returned Value: File structure pointer; NULL if failed 00476 * Local Static Variables: 00477 * include_list_full_path Full Path used, if succeeded 00478 * 00479 * Error Detection: 00480 * Calling routine will detect and report Errors. 00481 * 00482 * Process Explanation: 00483 * This routine will initialize and step through Include-List. 00484 * Calling routine will be responsible for "finishing" the 00485 * Include-List search, as well as any Advisory messages. 00486 * 00487 **************************************************************************** */ 00488 00489 static FILE *open_incl_list_file( char *base_name, char *mode) 00490 { 00491 FILE *retval = NULL; 00492 00493 init_incl_list_scan( base_name); 00494 while ( scan_incl_list( base_name) ) 00495 { 00496 retval = fopen( include_list_full_path, mode); 00497 if ( retval != NULL ) 00498 { 00499 break; 00500 } 00501 } 00502 00503 return (retval); 00504 } 00505 00506 /* ************************************************************************** 00507 * 00508 * Function name: stat_incl_list_file 00509 * Synopsis: Look in the Include-List, if defined, for given file, 00510 * and collect its statistics. 00511 * 00512 * 00513 * Inputs: 00514 * Parameters: 00515 * base_name Expanded user-supplied file-name 00516 * file_info Pointer to STAT structure 00517 * Local Static Variables: 00518 * include_list_full_path Full Path to use in file-status atttempt 00519 * 00520 * Outputs: 00521 * Returned Value: TRUE if succeeded. 00522 * Local Static Variables: 00523 * include_list_full_path Full Path used, if succeeded 00524 * Supplied Pointers: 00525 * *file_info File-statistics structure from STAT call 00526 * 00527 * Error Detection: 00528 * Calling routine will detect and report Errors. 00529 * 00530 * Process Explanation: 00531 * This routine will initialize and step through Include-List. 00532 * Calling routine will be responsible for "finishing" the 00533 * Include-List search, as well as any Advisory messages. 00534 * 00535 **************************************************************************** */ 00536 00537 static bool stat_incl_list_file( char *base_name, struct stat *file_info) 00538 { 00539 bool retval = FALSE; 00540 int stat_reslt = -1; /* Success = 0 */ 00541 00542 init_incl_list_scan( base_name); 00543 while ( scan_incl_list( base_name) ) 00544 { 00545 stat_reslt = stat( include_list_full_path, file_info); 00546 if ( stat_reslt == 0 ) 00547 { 00548 retval = TRUE; 00549 break; 00550 } 00551 } 00552 00553 return (retval); 00554 } 00555 00556 /* ************************************************************************** 00557 * 00558 * Function name: init_inbuf 00559 * Synopsis: Set the given buffer as the current input source 00560 * 00561 * Inputs: 00562 * Parameters: 00563 * inbuf Pointer to start of new input buffer 00564 * buflen Length of new input buffer 00565 * 00566 * Outputs: 00567 * Returned Value: NONE 00568 * Global Variables: 00569 * start Points to given buffer 00570 * end Points to end of new input buffer 00571 * pc Re-initialized 00572 * 00573 **************************************************************************** */ 00574 00575 void init_inbuf(char *inbuf, unsigned int buflen) 00576 { 00577 start = inbuf; 00578 pc = start; 00579 end = pc + buflen; 00580 } 00581 00582 /* ************************************************************************** 00583 * 00584 * Function name: could_not_open 00585 * Synopsis: Report the "Could not open" Message for various Files. 00586 * 00587 * Inputs: 00588 * Parameters: 00589 * severity Severity of message, WARNING or ERROR 00590 * fle_nam Name of file 00591 * for_what Phrase after "... for " 00592 * 00593 * Outputs: 00594 * Returned Value: NONE 00595 * Printout: 00596 * Message of indicated severity. 00597 * 00598 * Error Detection: 00599 * Error already detected; reported here. 00600 * 00601 **************************************************************************** */ 00602 00603 static void could_not_open(int severity, char *fle_nam, char *for_what) 00604 { 00605 tokenization_error( severity, "Could not open file %s for %s.\n", 00606 fle_nam, for_what); 00607 00608 } 00609 00610 /* ************************************************************************** 00611 * 00612 * Function name: file_is_missing 00613 * Synopsis: Add the given File to the Missing-Files-List. 00614 * 00615 * Inputs: 00616 * Parameters: 00617 * fle_nam Name of file 00618 * Local Static Variables: 00619 * missing_list_file Missing-Files-List File Structure 00620 * May be NULL if none was opened 00621 * 00622 * Outputs: 00623 * Returned Value: NONE 00624 * Local Static Variables: 00625 * no_files_missing Set FALSE 00626 * File Output: 00627 * Write File name to Missing-Files-List (if one was opened) 00628 * 00629 * Error Detection: 00630 * Error already detected; reported here. 00631 * 00632 **************************************************************************** */ 00633 00634 static void file_is_missing( char *fle_nam) 00635 { 00636 if ( missing_list_file != NULL ) 00637 { 00638 fprintf( missing_list_file, "%s\n", fle_nam); 00639 no_files_missing = FALSE; 00640 } 00641 } 00642 00643 /* ************************************************************************** 00644 * 00645 * Function name: add_to_load_lists 00646 * Synopsis: Add the given input file-name to the Load-List File, 00647 * and the Full File path to the Dependency-List File. 00648 * 00649 * Inputs: 00650 * Parameters: 00651 * in_name Name of given input Source File 00652 * Local Static Variables: 00653 * load_list_file Load List File Structure pointer 00654 * depncy_file Dependency-List File Structure ptr 00655 * Either may be NULL if the file was not opened. 00656 * include_list_full_path Full Path to where the file was found. 00657 * 00658 * Outputs: 00659 * Returned Value: NONE 00660 * File Output: 00661 * Write given file-name to Load-List file (if one was opened) 00662 * Write File Path to Dependency-List file (if one was opened) 00663 * 00664 * Process Explanation: 00665 * Write into the Load-List file the input Source Filename in the 00666 * same form -- i.e., unexpanded -- as was supplied by the User. 00667 * Write into the Dependency-List file the full expanded path, as 00668 * supplied by the program to the Host Operating System. 00669 * 00670 **************************************************************************** */ 00671 00672 static void add_to_load_lists( const char *in_name) 00673 { 00674 if ( load_list_file != NULL ) 00675 { 00676 fprintf( load_list_file, "%s\n", in_name); 00677 } 00678 if ( depncy_file != NULL ) 00679 { 00680 fprintf( depncy_file, "%s\n", include_list_full_path); 00681 } 00682 } 00683 00684 00685 /* ************************************************************************** 00686 * 00687 * In the functions that support accessing files whose path-names 00688 * contain embedded Environment-Variables, the commentaries 00689 * will refer to this process, or to inputs that require it, 00690 * using variants of the term "expand". 00691 * 00692 * We will also keep some of the relevant information as Local 00693 * Static Variables. 00694 * 00695 **************************************************************************** */ 00696 00697 static char expansion_buffer[ 2*GET_BUF_MAX]; 00698 static bool was_expanded; 00699 static int expansion_msg_severity = INFO; 00700 00701 /* ************************************************************************** 00702 * 00703 * Function name: expanded_name 00704 * Synopsis: Advisory message to display filename expansion. 00705 * 00706 * Inputs: 00707 * Parameters: 00708 * Local Static Variables: 00709 * was_expanded TRUE if expansion happened 00710 * expansion_buffer Buffer with result of expansion 00711 * expansion_msg_severity Whether it's an ordinary Advisory 00712 * or we force a message. 00713 * 00714 * Outputs: 00715 * Returned Value: NONE 00716 * 00717 * Printout: 00718 * Advisory message showing expansion, if expansion happened 00719 * Otherwise, nothing. 00720 * 00721 **************************************************************************** */ 00722 00723 static void expanded_name( void ) 00724 { 00725 if ( was_expanded ) 00726 { 00727 tokenization_error( expansion_msg_severity, 00728 "File name expanded to: %s\n", expansion_buffer); 00729 } 00730 } 00731 00732 00733 /* ************************************************************************** 00734 * 00735 * Function name: expansion_error 00736 * Synopsis: Supplemental message to display filename expansion. 00737 * Called after an expanded-filename failure was reported. 00738 * 00739 * Inputs: 00740 * Parameters: 00741 * Global Variables: 00742 * verbose Set by "-v" switch 00743 * 00744 * Outputs: 00745 * Returned Value: NONE 00746 * Printout: 00747 * Advisory message showing expansion, if applicable 00748 * and if wasn't already shown. 00749 * 00750 * Error Detection: 00751 * Called after Error was reported. 00752 * 00753 * Process Explanation: 00754 * Presumptions are that: 00755 * An Error message, showing the user-supplied form of the 00756 * pathname is also being displayed 00757 * An advisory message showing the pathname expansion may 00758 * have been displayed during the expansion process, 00759 * if verbose was TRUE. 00760 * The purpose of this routine is to display the expansion if 00761 * it had not already just been displayed, i.e., if verbose 00762 * is not set to TRUE: Temporarily force the display of an 00763 * Advisory message. 00764 * 00765 * Extraneous Remarks: 00766 * If this routine is called before the Error message is displayed, 00767 * the verbose and non-verbose versions of the Log-File will 00768 * match up nicely... 00769 * 00770 **************************************************************************** */ 00771 00772 static void expansion_error( void ) 00773 { 00774 if ( INVERSE( verbose) ) 00775 { 00776 expansion_msg_severity |= FORCE_MSG; 00777 expanded_name(); 00778 expansion_msg_severity ^= FORCE_MSG; 00779 } 00780 } 00781 00782 00783 /* ************************************************************************** 00784 * 00785 * Function name: expand_pathname 00786 * Synopsis: Perform the expansion of a path-name that may contain 00787 * embedded Environment-Variables 00788 * 00789 * Inputs: 00790 * Parameters: 00791 * input_pathname The user-supplied filename 00792 * Global/Static MACRO: 00793 * GET_BUF_MAX Size of expansion buffer is twice this. 00794 * 00795 * Outputs: 00796 * Returned Value: Pointer to expanded name, or to 00797 * input if no expansion needed. 00798 * NULL if error. 00799 * Local Static Variables: 00800 * was_expanded TRUE if expansion needed and succeeded 00801 * expansion_buffer Result of expansion 00802 * Printout: 00803 * Advisory message showing expansion 00804 * Presumption is that an Advisory giving the user-supplied 00805 * pathname was already printed. 00806 * 00807 * Error Detection: 00808 * Syntax error. System might print something; it might not be 00809 * captured, even to a log-file. System failure return might 00810 * be the only program-detectable indication. Display ERROR 00811 * message and return NULL pointer. Calling routine will 00812 * display the user-supplied pathname in its Error message 00813 * indicating failure to open the file. 00814 * 00815 * Process Explanation: 00816 * Generally speaking, we will let the Shell expand the Environment 00817 * Variables embedded in the user-supplied pathname. 00818 * First, though, we will see if the expansion is necessary: Look 00819 * for the telltale character, '$', in the input string. If 00820 * it's not there, there are no Env't-V'bles, and no expansion 00821 * is necessary. Return the pointer to the input string and 00822 * we're done. Otherwise..... 00823 * Acquire a temporary file-name. Construct a string of the form: 00824 * echo input_string > temp_file_name 00825 * and then issue that string as a command to the Shell. 00826 * If that string generates a system-call failure, report an ERROR. 00827 * Open the temporary file and read its contents. That will be 00828 * the expansion of the input string. If its length exceeds 00829 * the capacity of the expansion buffer, it's another ERROR. 00830 * (Of course, don't forget to delete the temporary file.) 00831 * Place the null-byte marker at the end of the expanded name, 00832 * trimming off the terminating new-line. 00833 * Success. Display the expanded name (as an Advisory message) 00834 * Return the pointer to the expansion buffer and set the flag. 00835 * (Did I mention don't forget to delete the temporary file?) 00836 * 00837 * Extraneous Remarks: 00838 * This implementation approach turned out to be the simplest and 00839 * cleanest way to accomplish our purpose. It also boasts the 00840 * HUGE advantage of not requiring re-invention of a well-used 00841 * (proverbial) wheel. Plus, any variations allowed by the 00842 * shell (e.g.,: $PWD:h ) are automatically converted, too, 00843 * depending on the System shell (e.g., not for Bourne shell). 00844 * In order to spare you, the maintenance programmer, unnecessary 00845 * agony, I will list a few other approaches I tested, with a 00846 * brief note about the results of each: 00847 * (1) 00848 * I actually tried parsing the input line and passing each component 00849 * V'ble to the getenv() function, accumulating the results into 00850 * a conversion buffer. I needed to check for every possible 00851 * delimiter, and handle curly-brace enclosures. The resultant 00852 * code was *UGLY* ... you'd be appalled! The only good spot was 00853 * that I was able to compensate for an open-curly-brace without 00854 * a corresponding close-curly-brace (if close-c-b wasn't found, 00855 * resume the search for other delimiters...) which, apparently, 00856 * the System does not or will not do. It was, however, too 00857 * small a compensation for all the awfulness entailed overall. 00858 * 00859 * I tried various approaches to using the Environment-Variables to 00860 * convert and retrieve the input string: 00861 * (2) 00862 * Create a command-string that would set an Env't V'ble to the 00863 * input-string, and pass the command-string to the system() call, 00864 * then retrieve the Env't V'ble thus set via getenv(). No dice; 00865 * the system() call operated in a separate sub-shell and could 00866 * not export its Env't upwards. 00867 * (3) 00868 * Use the setenv() command to set an Env't V'ble to the input-string 00869 * and retrieve it via getenv(). The returned string matched the 00870 * input-string without converting it. 00871 * (4) 00872 * Use the setenv() command to set an Env't V'ble to a string like: 00873 * `echo input_string` 00874 * Again, the string retrieved via getenv() exactly matched the 00875 * unconverted command-string, back-quotes and all. 00876 * 00877 * Of course, the equivalents of (2), (3) and (4) worked as desired 00878 * when tested as direct commands to the Shell. UNIX can be 00879 * funny that way... 00880 * 00881 * Oh! Also: we will slightly stretch the rules of well-structured 00882 * code. 00883 * 00884 **************************************************************************** */ 00885 00886 static char *expand_pathname( const char *input_pathname) 00887 { 00888 static const int buffer_max = GET_BUF_MAX * 2; 00889 00890 char *retval = (char *)input_pathname; 00891 was_expanded = FALSE; 00892 00893 /* If no '$' is found, expansion is unnecessary. */ 00894 if ( strchr( input_pathname, '$') != NULL ) 00895 { 00896 FILE *temp_file; 00897 int syst_stat; 00898 const char *temp_file_name = tmpnam( NULL); 00899 00900 /* Use the expansion buffer for our temporary command string */ 00901 sprintf( expansion_buffer, 00902 "echo %s>%s\n", input_pathname, temp_file_name); 00903 syst_stat = system( expansion_buffer); 00904 if ( syst_stat != 0 ) 00905 { 00906 tokenization_error( TKERROR, 00907 "Expansion Syntax.\n"); 00908 /* The "File-Opening" error message will show the input string */ 00909 return( NULL); 00910 } 00911 00912 temp_file = fopen( temp_file_name, "r"); /* Cannot fail. */ 00913 syst_stat = fread( expansion_buffer, 1, buffer_max, temp_file); 00914 /* Error test. Length of what we read is not a good indicator; 00915 * it's limited anyway by buffer_max. 00916 * Valid test is if last character read was the new-line. 00917 */ 00918 if ( expansion_buffer[syst_stat-1] != '\n' ) 00919 { 00920 tokenization_error( TKERROR, 00921 "Expansion buffer overflow. Max length is %d.\n", 00922 buffer_max); 00923 retval = NULL; 00924 }else{ 00925 expansion_buffer[syst_stat-1] =0; 00926 was_expanded = TRUE; 00927 retval = expansion_buffer; 00928 expanded_name(); 00929 } 00930 00931 fclose( temp_file); 00932 remove( temp_file_name); 00933 } 00934 00935 return( retval); 00936 } 00937 00938 /* ************************************************************************** 00939 * 00940 * Function name: open_expanded_file 00941 * Synopsis: Open a file, expanding Environment-Variables that 00942 * may be embedded in the given path-name. 00943 * 00944 * Inputs: 00945 * Parameters: 00946 * path_name The user-supplied path-name 00947 * mode Mode-string to use; usually "r" or "rb" 00948 * for_what Phrase to use in Messages 00949 * 00950 * Outputs: 00951 * Returned Value: Pointer to FILE structure; NULL if failed 00952 * Local Static Variables: 00953 * was_expanded TRUE if expansion happened 00954 * expansion_buffer Result of expansion 00955 * Printout: 00956 * Advisory message showing expansion 00957 * 00958 * Error Detection: 00959 * If expansion or system-call for file-open failed, 00960 * report Error and return NULL. 00961 * 00962 **************************************************************************** */ 00963 00964 FILE *open_expanded_file( const char *path_name, char *mode, char *for_what) 00965 { 00966 00967 FILE *retval = NULL; 00968 00969 char *infile_name = expand_pathname( path_name); 00970 if ( infile_name != NULL ) 00971 { 00972 retval = open_incl_list_file( infile_name, mode); 00973 } 00974 00975 if ( retval == NULL ) 00976 { 00977 expansion_error(); 00978 tokenization_error ( TKERROR, 00979 "Failed to open file %s for %s\n", path_name, for_what ); 00980 } 00981 00982 finish_incl_list_scan( BOOLVAL( retval != NULL) ); 00983 00984 return( retval); 00985 } 00986 00987 /* ************************************************************************** 00988 * 00989 * Function name: init_stream 00990 * Synopsis: Open a file and make it the current source. 00991 * This is called, not only at the start of tokenization, 00992 * but also when a subsidiary file is FLOADed. 00993 * 00994 * Inputs: 00995 * Parameters: 00996 * name Name of the new Input File to open 00997 * May be path-name containing 00998 * embedded Environment-Variables. 00999 * Global Variables: 01000 * oname NULL if opening Primary Input File 01001 * Local Static Variables: 01002 * include_list_full_path Full Path to where the file was found 01003 * 01004 * Outputs: 01005 * Returned Value: TRUE = opened and read file successfully 01006 * Global Variables (Only changed if successful): 01007 * iname Set to new Input File name 01008 * lineno Re-initialized to 1 01009 * Local Static Variables: 01010 * no_files_missing Set FALSE if couldn't read input file 01011 * include_list_full_path Retains full-path if file opened was 01012 * the Primary Input File (as contrasted with an FLoaded 01013 * Source file), in which case a call to init_output() 01014 * is expected; the Full-Path Buffer will be freed there. 01015 * Memory Allocated 01016 * Duplicate of Input File name (becomes iname ) 01017 * A fresh input buffer; input file is copied to it. 01018 * Becomes start by action of call to init_inbuf(). 01019 * When Freed? 01020 * By close_stream() 01021 * File Output: 01022 * Write new Input File name to Load-List file. 01023 * Writing to Missing-Files-List File if failure, 01024 * or Full File path to Dependency-List File, 01025 * is handled by called routine. 01026 * Other Exotic Effects: 01027 * Force a flush of stdout before printing ERROR messages 01028 * 01029 * Error Detection: 01030 * Failure to open or read Input file: ERROR; suppress output; 01031 * write Input File name to Missing-Files-List File. 01032 * 01033 * Process Explanation: 01034 * Free local buffer on failure. 01035 * Caller should only invoke close_stream() if this call succeeded. 01036 * Some filesystems use zeros for new-line; we need to convert 01037 * those zeros to line-feeds. 01038 * Similarly for files that have carr-ret/line-feed; the carr-ret 01039 * will cause havoc; replace it w/ a space. 01040 * 01041 * Revision History: 01042 * Updated Thu, 07 Apr 2005 by David L. Paktor 01043 * Restructured. If opened file, close it, even if can't read it. 01044 * Return TRUE on success. 01045 * Caller examines return value. 01046 * Updated Wed, 13 Jul 2005 by David L. Paktor 01047 * Replace carr-rets with spaces. 01048 * Updated Sun, 27 Nov 2005 by David L. Paktor 01049 * Write new Input File name to Load-List file. 01050 * Updated Tue, 31 Jan 2006 by David L. Paktor 01051 * Add support for embedded Environment-Variables in path name 01052 * Updated Thu, 16 Feb 2006 David L. Paktor 01053 * Collect missing (inaccessible) filenames 01054 * Updated Fri, 17 Mar 2006 David L. O'Paktor 01055 * Add support for Include-List search 01056 * 01057 * Still to be done: 01058 * Set a flag when carr-ret has been replaced by space; 01059 * when a string crosses a line, if this flag is set, 01060 * issue a warning that an extra space has been inserted. 01061 * 01062 **************************************************************************** */ 01063 01064 bool init_stream( const char *name) 01065 { 01066 FILE *infile; 01067 u8 *newbuf; 01068 struct stat finfo; 01069 bool stat_succ = FALSE; 01070 bool tried_stat = FALSE; 01071 bool retval = FALSE; 01072 bool inp_fil_acc_err = FALSE; 01073 bool inp_fil_open_err = FALSE; 01074 bool inp_fil_read_err = FALSE; 01075 01076 char *infile_name = expand_pathname( name); 01077 01078 if ( (infile_name != NULL) ) 01079 { 01080 tried_stat = TRUE; 01081 stat_succ = stat_incl_list_file( infile_name, &finfo); 01082 } 01083 01084 if ( INVERSE( stat_succ) ) 01085 { 01086 inp_fil_acc_err = TRUE; 01087 }else{ 01088 01089 infile = fopen( include_list_full_path, "r"); 01090 if ( infile == NULL ) 01091 { 01092 inp_fil_open_err = TRUE; 01093 }else{ 01094 01095 ilen=finfo.st_size; 01096 newbuf = safe_malloc(ilen+1, "initting stream"); 01097 01098 if ( fread( newbuf, ilen, 1, infile) != 1 ) 01099 { 01100 inp_fil_read_err = TRUE; 01101 free( newbuf ); 01102 } else { 01103 unsigned int i; 01104 01105 retval = TRUE ; 01106 /* Replace zeroes in the file with LineFeeds. */ 01107 /* Replace carr-rets with spaces. */ 01108 for (i=0; i<ilen; i++) 01109 { 01110 char test_c = newbuf[i]; 01111 if ( test_c == 0 ) newbuf[i] = 0x0a; 01112 if ( test_c == 0x0d ) newbuf[i] = ' '; 01113 } 01114 newbuf[ilen]=0; 01115 01116 init_inbuf(newbuf, ilen); 01117 01118 /* If the -l option was specified, write the name of the 01119 * new input-file to the Load-List file... UNLESS 01120 * this is the first time through and we haven't yet 01121 * opened the Load-List file, in which case we'll 01122 * just open it here and wait until we create the 01123 * output-file name (since the Load-List file name 01124 * depends on the output-file name anyway) before 01125 * we write the initial input-file name to it. 01126 */ 01127 /* Looking for the option-flag _and_ for a non-NULL value 01128 * of the file-structure pointer is redundandundant: 01129 * The non-NULL pointer is sufficient, once the List 01130 * File has been created... 01131 */ 01132 /* Same thing applies if the -P option was specified, 01133 * for the Dependency-List file, except there we'll 01134 * write the full path to where the file was found. 01135 */ 01136 /* We have a routine to do both of those. */ 01137 add_to_load_lists( name); 01138 /* 01139 * And... there's one slight complication: If this is 01140 * the first time through, (i.e., we're opening the 01141 * Primary Input File) then we haven't yet opened the 01142 * Dependency-List file, and we need to preserve the 01143 * Full file-name Buffer until the call to init_output() 01144 * where the include-list scan will be "finish"ed. 01145 * Actually, we want to postpone "finish"ing the inc-l scan 01146 * for several reasons beyond the Dependency-List file, 01147 * such as completing the File Name Announcement first. 01148 * A NULL output-name buffer is our indicator. 01149 */ 01150 if ( oname == NULL ) 01151 { 01152 /* Quick way to suppress "finish"ing the i-l scan */ 01153 tried_stat = FALSE; 01154 } 01155 } 01156 fclose(infile); 01157 } 01158 } 01159 01160 FFLUSH_STDOUT /* Do this first */ 01161 /* Now we can deliver our postponed error and advisory messages */ 01162 if ( INVERSE( retval) ) 01163 { 01164 file_is_missing( (char *)name); 01165 if ( inp_fil_acc_err ) 01166 { 01167 expansion_error(); 01168 tokenization_error( TKERROR, 01169 "Could not access input file %s\n", name); 01170 }else{ 01171 if ( inp_fil_open_err ) 01172 { 01173 expansion_error(); 01174 could_not_open( TKERROR, (char *)name, "input"); 01175 }else{ 01176 if ( inp_fil_read_err ) 01177 { 01178 expansion_error(); 01179 tokenization_error( TKERROR, 01180 "Could not read input file %s\n", name); 01181 } 01182 } 01183 } 01184 } 01185 01186 if ( tried_stat ) 01187 { 01188 finish_incl_list_scan( stat_succ); 01189 } 01190 01191 /* Don't change the input file name and line-number until after 01192 * the Advisory showing where the file was found. 01193 */ 01194 if ( retval ) 01195 { 01196 iname=strdup(name); 01197 lineno=1; 01198 } 01199 01200 return ( retval ); 01201 01202 } 01203 01204 /* ************************************************************************** 01205 * 01206 * Function name: extend_filename 01207 * Synopsis: Change the filename to the given extension 01208 * 01209 * Inputs: 01210 * Parameters: 01211 * base_name Name of the Input Base File 01212 * new_ext New ext'n (with leading period) 01213 * 01214 * Outputs: 01215 * Returned Value: Result filename 01216 * Memory Allocated 01217 * Buffer for result filename 01218 * When Freed? 01219 * At end of Tokenization, by close_output(). 01220 * 01221 * Process Explanation: 01222 * If the Input Base File Name has an extension, it will be replaced 01223 * with the given new extension. If not, the new extension will 01224 * simply be appended. 01225 * If the Input Base File Name has an extension that matches the 01226 * new extension, a duplicate of the extension will be appended. 01227 * 01228 * Extraneous Remarks: 01229 * I only recently added protection against the situation where the 01230 * Input Base File Name has no extension, but the Directory Path 01231 * leading to it has a period in one of the directory names. 01232 * Granted, this is a rare case, but not altogether impossible; 01233 * I would have done it earlier except for the fact that the 01234 * separator between directories may vary with different Host 01235 * Operating Systems. 01236 * However, at this point we have UNIX-centric assumptions hard- 01237 * -coded in to so many other places that we might as well 01238 * go with the slash here too. 01239 * 01240 **************************************************************************** */ 01241 01242 static char *extend_filename( const char *base_name, const char *new_ext) 01243 { 01244 char *retval; 01245 char *ext; 01246 unsigned int len; /* should this be size_t? */ 01247 const char *root; 01248 01249 root = strrchr(base_name, '/'); 01250 if ( root == NULL ) root = base_name; 01251 01252 ext = strrchr(root, '.'); 01253 if ( ext != NULL ) 01254 { 01255 if ( strcasecmp(ext, new_ext) == 0 ) 01256 { 01257 ext = NULL; 01258 } 01259 } 01260 01261 len = ext ? (ext - base_name) : (unsigned int)strlen(base_name) ; 01262 retval = safe_malloc(len+strlen(new_ext)+1, "extending file-name"); 01263 memcpy( retval, base_name, len); 01264 retval[len] = 0; 01265 strcat(retval, new_ext); 01266 01267 return( retval); 01268 } 01269 01270 /* ************************************************************************** 01271 * 01272 * Function name: init_output 01273 * Synopsis: After the Input Source File has been opened, assign 01274 * the name for the Binary Output File; initialize 01275 * the FCode Output Buffer; assign names for the 01276 * FLoad List, Dependency-List, and Missing-Files 01277 * List files; open them and write their first 01278 * entries to them. 01279 * Announce the Input and various output file names. 01280 * 01281 * Inputs: 01282 * Parameters: 01283 * in_name Name of the Input Source File 01284 * out_name Name of the Binary Output File, if 01285 * specified on the Command Line, 01286 * or NULL if not. 01287 * Global Variables: 01288 * fload_list Whether to create an FLoad-List file 01289 * dependency_list Whether to create a Dependency-List file 01290 * Local Static Variables: 01291 * include_list_full_path Full Path to the Input Source File; 01292 * should still be valid from opening 01293 * of Primary Source Input file, for 01294 * first entry to Dependency-List file. 01295 * 01296 * Outputs: 01297 * Returned Value: NONE 01298 * Global Variables: 01299 * oname Binary Output File Name 01300 * ostart Start of FCode Output Buffer 01301 * opc FCode Output Buffer Position Counter 01302 * abs_token_no Initialized to 1 01303 * Local Static Variables: 01304 * load_list_name Name of the Load List File 01305 * load_list_file FLoad List File Structure pointer 01306 * depncy_list_name Name of the Dependency List File ptr 01307 * depncy_file Dependency List File Structure 01308 * missing_list_name Name of the Missing-Files-List File 01309 * missing_list_file Missing-Files-List File Structure 01310 * no_files_missing Initialized to TRUE 01311 * Memory Allocated 01312 * Binary Output File Name Buffer 01313 * FCode Output Buffer 01314 * FLoad List File Name Buffer 01315 * Dependency List File Name Buffer 01316 * 01317 * When Freed? 01318 * In close_output() 01319 * File Output: 01320 * FLoad List or Dependency List files are opened (if specified). 01321 * Primary Source Input file name and path, respectively, 01322 * are written as the first entry to each. 01323 * Printout: 01324 * (Announcement of input file name has already been made) 01325 * Announce binary output, fload- and dependency- -list file names 01326 * 01327 * Error Detection: 01328 * Failure to open FLoad List or Dependency List file: ERROR; 01329 * suppress binary output. Further attempts to write to 01330 * FLoad List or Dependency List files are prevented by 01331 * the respective FILE_structure pointers being NULL. 01332 * Failure to open Missing-Files-List file: WARNING 01333 * 01334 * Process Explanation: 01335 * If no Output File Name was specified on the Command Line, the 01336 * name of the Binary (FCode) Output File will be derived 01337 * from the name of the Input File by replacing its extension 01338 * with .fc , or, if the Input File had no extension, by 01339 * merely appending the extension .fc 01340 * In the odd case where the Input File name has an extension 01341 * of .fc, we will merely append another .fc extension. 01342 * If fload_list is TRUE (i.e., the "-l" option was specified on 01343 * the command-line, the FLoad List File name will be derived 01344 * from the name of the Output File by the same rules, only with 01345 * an extension of .fl Open the FLoad List File. Write the 01346 * name of the initial input file to the FLoad List File. 01347 * Similarly if the "-P" command-line option was specified, the name 01348 * of the Dependency List File will be derived with an extension 01349 * of .P Open it and write the Full Path for the initial input 01350 * file to it. NOTE: To do that, we need to have preserved the 01351 * Full Path-name Buffer from the call to init_stream() We 01352 * will "finish" it here, after we've used it. 01353 * The Missing-Files-List File will be created if either option was 01354 * specified. Its name will be derived similarly, with an 01355 * extension of .fl.missing 01356 * 01357 **************************************************************************** */ 01358 01359 void init_output( const char *in_name, const char *out_name ) 01360 { 01361 /* preparing output */ 01362 01363 if( out_name != NULL ) 01364 { 01365 oname = strdup( out_name ); 01366 }else{ 01367 oname = extend_filename( in_name, ".fc"); 01368 } 01369 01370 /* output buffer size. this is 128k per default now, but we 01371 * could reallocate if we run out. KISS for now. 01372 */ 01373 olen = OUTPUT_SIZE; 01374 ostart=safe_malloc(olen, "initting output buffer"); 01375 01376 opc = 0; 01377 init_emit(); /* Init'l'zns needed by our companion file, emit.c */ 01378 01379 printf("Binary output to %s ", oname); 01380 if ( fload_list ) 01381 { 01382 load_list_name = extend_filename( oname, ".fl"); 01383 load_list_file = fopen( load_list_name,"w"); 01384 printf(" FLoad-list to %s ", load_list_name); 01385 } 01386 if ( dependency_list ) 01387 { 01388 depncy_list_name = extend_filename( oname, ".P"); 01389 depncy_file = fopen( depncy_list_name,"w"); 01390 printf(" Dependency-list to %s ", depncy_list_name); 01391 } 01392 printf("\n"); 01393 01394 add_to_load_lists( in_name); 01395 01396 /* Let's avoid collisions between stdout and stderr */ 01397 FFLUSH_STDOUT 01398 01399 /* Now we can deliver our advisory and error messages */ 01400 01401 { 01402 /* Suspend showing filename in advisory and error messages. */ 01403 char *temp_iname = iname; 01404 iname = NULL; 01405 01406 finish_incl_list_scan( TRUE); 01407 01408 if ( fload_list && (load_list_file == NULL) ) 01409 { 01410 could_not_open( TKERROR, load_list_name, "Load-List"); 01411 free( load_list_name); 01412 } 01413 if ( dependency_list && (depncy_file == NULL) ) 01414 { 01415 could_not_open( TKERROR, depncy_list_name, 01416 "Dependency-List"); 01417 free( depncy_list_name); 01418 } 01419 01420 if ( fload_list || dependency_list ) 01421 { 01422 missing_list_name = extend_filename( oname, ".fl.missing"); 01423 missing_list_file = fopen( missing_list_name,"w"); 01424 no_files_missing = TRUE; 01425 01426 if ( missing_list_file == NULL ) 01427 { 01428 could_not_open( WARNING, missing_list_name, 01429 "Missing-Files List" ); 01430 free( missing_list_name); 01431 } 01432 } 01433 iname = temp_iname; 01434 } 01435 abs_token_no = 1; 01436 } 01437 01438 /* ************************************************************************** 01439 * 01440 * Function name: increase_output_buffer 01441 * Synopsis: Reallocate the Output Buffer to double its prior size 01442 * 01443 * Inputs: 01444 * Parameters: NONE 01445 * Global Variables: 01446 * ostart Start-address of current Output Buffer 01447 * olen Current size of the Output Buffer 01448 * Local Static Variables: 01449 * 01450 * Outputs: 01451 * Returned Value: NONE 01452 * Local Static Variables: 01453 * olen Doubled from value at input 01454 * ostart Start-address of new Output Buffer 01455 * Memory Allocated 01456 * A new FCode Output Buffer, using the realloc() facility. 01457 * When Freed? 01458 * In close_output() 01459 * Memory Freed 01460 * Former FCode Output Buffer, also by means of realloc() 01461 * 01462 * Printout: 01463 * Advisory message that this is taking place. 01464 * 01465 * Error Detection: 01466 * FATAL if realloc() fails. 01467 * FATAL if output buffer has been expanded to a size beyond 01468 * what an INT can express. Unlikely? maybe; impossible? no... 01469 * 01470 * Process Explanation: 01471 * Because we are allowing the Output Buffer to be relocated, we 01472 * must take care to limit the exposure to external routines 01473 * of its actual address. All references to locations within 01474 * the Output Buffer should be made in terms of an _offset_. 01475 * 01476 * Extraneous Remarks: 01477 * Unfortunately, it is not feasible to completely isolate the 01478 * actual address of the Output Buffer, but we will keep the 01479 * exposure limited to the routines in emit.c 01480 * Similarly, it wasn't feasible to keep this routine isolated, 01481 * nor the variable olen , but we will limit their exposure. 01482 * 01483 **************************************************************************** */ 01484 void increase_output_buffer( void ); /* Keep the prototype local */ 01485 void increase_output_buffer( void ) 01486 { 01487 u8 *newout; 01488 01489 if ( olen == 0 ) 01490 { 01491 tokenization_error( FATAL, 01492 "Output Buffer reallocation overflow."); 01493 }else{ 01494 unsigned int rea_len; 01495 olen = olen * 2; 01496 rea_len = olen; 01497 if ( rea_len == 0 ) rea_len = (unsigned int)-1; 01498 tokenization_error( INFO, 01499 "Output Buffer overflow. " 01500 "Relocating and increasing to %d bytes.\n", rea_len); 01501 01502 newout = realloc(ostart, rea_len); 01503 if ( newout == NULL) 01504 { 01505 tokenization_error( FATAL, 01506 "Could not reallocate %d bytes for Output Buffer", rea_len); 01507 } 01508 01509 ostart = newout; 01510 } 01511 } 01512 01513 01514 /* ************************************************************************** 01515 * 01516 * Function name: close_stream 01517 * Synopsis: Free-up the memory used for the current input file 01518 * whenever it is closed. Reset pointers and 01519 * line-counter. Close files as necessary. 01520 * 01521 * The dummy parameter is there to accommodate Macro-recursion protection. 01522 * It's a long story; don't get me started... 01523 * 01524 **************************************************************************** */ 01525 01526 void close_stream( _PTR dummy) 01527 { 01528 free(start); 01529 free(iname); 01530 start = NULL; 01531 iname = NULL; 01532 lineno = 0; 01533 } 01534 01535 /* ************************************************************************** 01536 * 01537 * Function name: close_output 01538 * Synopsis: Write the Binary Output file, if appropriate. 01539 * Return a "Failure" flag. 01540 * 01541 **************************************************************************** */ 01542 01543 01544 bool close_output(void) 01545 { 01546 bool retval = TRUE; /* "Failure" */ 01547 if ( error_summary() ) 01548 { 01549 if ( opc == 0 ) 01550 { 01551 retval = FALSE; /* "Not a problem" */ 01552 }else{ 01553 FILE *outfile; 01554 01555 outfile=fopen( oname,"w"); 01556 if (!outfile) 01557 { 01558 /* Don't do this as a tokenization_error( TKERROR 01559 * because those are all counted, among other reasons... 01560 */ 01561 printf( "Could not open file %s for output.\n", oname); 01562 }else{ 01563 01564 if ( fwrite(ostart, opc, 1, outfile) != 1 ) 01565 { 01566 tokenization_error( FATAL, "While writing output."); 01567 } 01568 01569 fclose(outfile); 01570 01571 printf("toke: wrote %d bytes to bytecode file '%s'\n", 01572 opc, oname); 01573 retval = FALSE; /* "No problem" */ 01574 } 01575 } 01576 } 01577 01578 free(oname); 01579 free(ostart); 01580 oname = NULL; 01581 ostart = NULL; 01582 opc = 0; 01583 olen = OUTPUT_SIZE; 01584 01585 if ( load_list_file != NULL ) 01586 { 01587 fclose(load_list_file); 01588 free(load_list_name); 01589 } 01590 if ( depncy_file != NULL ) 01591 { 01592 fclose(depncy_file); 01593 free(depncy_list_name); 01594 } 01595 if ( missing_list_file != NULL ) 01596 { 01597 fclose( missing_list_file); 01598 if ( no_files_missing ) 01599 { 01600 remove( missing_list_name); 01601 } 01602 free( missing_list_name); 01603 } 01604 01605 load_list_file = NULL; 01606 load_list_name = NULL; 01607 missing_list_file = NULL; 01608 missing_list_name = NULL; 01609 depncy_file = NULL; 01610 depncy_list_name = NULL; 01611 01612 return ( retval ); 01613 } 01614