Main Page | Data Structures | File List | Data Fields | Globals

stream.c

Go to the documentation of this file.
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 

Generated on Fri Aug 18 14:03:39 2006 for Toke1.0 by  doxygen 1.4.4