1 : /*
2 : * OpenBIOS - free your system!
3 : * ( FCode tokenizer )
4 : *
5 : * stream.c - source program streaming from file.
6 : *
7 : * This program is part of a free implementation of the IEEE 1275-1994
8 : * Standard for Boot (Initialization Configuration) Firmware.
9 : *
10 : * Copyright (C) 2001-2005 by Stefan Reinauer <stepan@openbios.org>
11 : *
12 : * This program is free software; you can redistribute it and/or modify
13 : * it under the terms of the GNU General Public License as published by
14 : * the Free Software Foundation; version 2 of the License.
15 : *
16 : * This program is distributed in the hope that it will be useful,
17 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : * GNU General Public License for more details.
20 : *
21 : * You should have received a copy of the GNU General Public License
22 : * along with this program; if not, write to the Free Software
23 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
24 : *
25 : */
26 :
27 : /* **************************************************************************
28 : * Modifications made in 2005 by IBM Corporation
29 : * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
30 : * Modifications Author: David L. Paktor dlpaktor@us.ibm.com
31 : **************************************************************************** */
32 :
33 : #include <stdio.h>
34 : #include <stdlib.h>
35 : #ifdef __GLIBC__
36 : #define __USE_XOPEN_EXTENDED
37 : #endif
38 : #include <string.h>
39 : #include <sys/stat.h>
40 :
41 : #include "emit.h"
42 : #include "stream.h"
43 : #include "errhandler.h"
44 : #include "toke.h"
45 :
46 : /* **************************************************************************
47 : *
48 : * Revision History:
49 : * Updated Tue, 31 Jan 2006 by David L. Paktor
50 : * Add support for embedded Environment-Variables in path name
51 : * Updated Thu, 16 Feb 2006 David L. Paktor
52 : * Collect missing (inaccessible) filenames
53 : * Updated Thu, 16 Mar 2006 David L. Paktor
54 : * Add support for Include-Lists
55 : *
56 : **************************************************************************** */
57 :
58 : /* **************************************************************************
59 : *
60 : * Global Variables Exported
61 : * start Start of input-source buffer
62 : * end End of input-source buffer
63 : * pc Input-source Scanning pointer
64 : * iname Current Input File name
65 : * lineno Current Line Number in Input File
66 : * ostart Start of Output Buffer
67 : * opc FCode Output Buffer Position Counter
68 : * oname Output File name
69 : *
70 : **************************************************************************** */
71 :
72 :
73 : /* Input pointers, Position Counters and Length counters */
74 : u8 *start = NULL;
75 : u8 *pc;
76 : u8 *end;
77 : char *iname = NULL;
78 : unsigned int lineno = 0;
79 : unsigned int abs_token_no = 0; /* Absolute Token Number in all Source Input
80 : * Will be used to identify position
81 : * where colon-definition begins and
82 : * to limit clearing of control-structs.
83 : */
84 : static unsigned int ilen; /* Length of Input Buffer */
85 :
86 : /* output pointers */
87 : u8 *ostart;
88 : char *oname = NULL;
89 : unsigned int opc; /* Output Position Counter */
90 :
91 : /* We want to limit exposure of this v'ble, so don't put it in .h file */
92 : unsigned int olen; /* Length of Output Buffer */
93 : /* We want to limit exposure of this Imported Function, likewise. */
94 : void init_emit( void);
95 :
96 : /* **************************************************************************
97 : *
98 : * Internal Static Variables
99 : * load_list_name Name of the Load List File
100 : * load_list_file (Pointer to) File-Structure for the Load List File
101 : * depncy_list_name Name of the Dependency List File
102 : * depncy_file (Pointer to) File-Structure for the Dependency List File
103 : * missing_list_name Name of the Missing-Files-List File
104 : * missing_list_file (Pointer to) File-Structure for Missing-List File
105 : * no_files_missing TRUE if able to load all files
106 : *
107 : **************************************************************************** */
108 :
109 : static char *load_list_name;
110 : static FILE *load_list_file;
111 : static char *depncy_list_name;
112 : static FILE *depncy_file;
113 : static char *missing_list_name;
114 : static FILE *missing_list_file;
115 : static bool no_files_missing = TRUE;
116 :
117 : /* **************************************************************************
118 : *
119 : * Private data-structure for Include-List support
120 : *
121 : * Components are simply a string-pointer and a link pointer
122 : *
123 : **************************************************************************** */
124 :
125 : typedef struct incl_list
126 : {
127 : char *dir_path;
128 : struct incl_list *next;
129 : } incl_list_t;
130 :
131 : /* **************************************************************************
132 : *
133 : * Internal Static Variables associated with Include-List support
134 : * include_list_start Start of the Include-List
135 : * include_list_next Next entry in Include-List to add or read
136 : * max_dir_path_len Size of longest entry in the Include-List
137 : * include_list_full_path Full-Path (i.e., expanded File-name with
138 : * Include-List Entry) that was last opened.
139 : *
140 : **************************************************************************** */
141 : static incl_list_t *include_list_start = NULL;
142 : static incl_list_t *include_list_next = NULL;
143 : static unsigned int max_dir_path_len = 0;
144 : static char *include_list_full_path = NULL;
145 :
146 :
147 : /* **************************************************************************
148 : *
149 : * Function name: add_to_include_list
150 : * Synopsis: Add an entry to the Include-List
151 : *
152 : * Inputs:
153 : * Parameters:
154 : * dir_compt Directory Component to add to Inc-List
155 : * Local Static Variables:
156 : * include_list_start First entry in the Include-List
157 : * include_list_next Next entry in Include-List to add
158 : * max_dir_path_len Previous max Dir-Component Length
159 : *
160 : * Outputs:
161 : * Returned Value: NONE
162 : * Local Static Variables:
163 : * include_list_start Assigned a value, first time through
164 : * include_list_next "Next" field updated with new entry,
165 : * then pointer updated to new entry.
166 : * max_dir_path_len Maximum Length
167 : * Memory Allocated
168 : * For the list-entry, and for the directory/path name to be added
169 : * When Freed?
170 : * Remains in effect through the life of the program.
171 : *
172 : * Process Explanation:
173 : * Unlike most of our linked-lists, this one will be linked forward,
174 : * i.e., in the order elements are added, and will be searched
175 : * in a forward order.
176 : * This means extra code to handle the first entry.
177 : * Allocate and initialize the New Include-List Entry.
178 : * If this is the first entry, point the List-Starter at it.
179 : * Otherwise, the Last-Entry-on-the-List pointer is already valid;
180 : * point its "next" field at the New Entry.
181 : * Point the Last-Entry-on-the-List pointer at the New Entry.
182 : *
183 : **************************************************************************** */
184 :
185 : void add_to_include_list( char *dir_compt)
186 75 : {
187 75 : unsigned int new_path_len = strlen( dir_compt);
188 : incl_list_t *new_i_l_e = safe_malloc( sizeof( incl_list_t),
189 75 : "adding to include-list" );
190 :
191 75 : new_i_l_e->dir_path = strdup( dir_compt);
192 75 : new_i_l_e->next = NULL;
193 :
194 75 : if ( include_list_start == NULL )
195 : {
196 31 : include_list_start = new_i_l_e;
197 : }else{
198 44 : include_list_next->next = new_i_l_e;
199 : }
200 :
201 75 : include_list_next = new_i_l_e;
202 75 : if ( new_path_len > max_dir_path_len ) max_dir_path_len = new_path_len;
203 75 : }
204 :
205 : #define DISPLAY_WIDTH 80
206 : /* **************************************************************************
207 : *
208 : * Function name: display_include_list
209 : * Synopsis: Display the Include-List, once it's completed,
210 : * if "verbose" mode is in effect.
211 : *
212 : * Inputs:
213 : * Parameters: NONE
214 : * Local Static Variables:
215 : * include_list_start First entry in the Include-List
216 : * include_list_next Next entry, as we step through.
217 : * Macro:
218 : * DISPLAY_WIDTH Width limit of the display
219 : *
220 : * Outputs:
221 : * Returned Value: NONE
222 : * Local Static Variables:
223 : * include_list_next NULL, when reaches end of Incl-List
224 : * Printout:
225 : * The elements of the Include-List, separated by a space, on
226 : * a line up to the DISPLAY_WIDTH, or on a line by itself
227 : * if the element is wider.
228 : *
229 : * Process Explanation:
230 : * The calling routine will check for the verbose flag.
231 : * Nothing to be done here if Include-List is NULL.
232 : * Print a header, then the list.
233 : *
234 : **************************************************************************** */
235 :
236 : void display_include_list( void)
237 153 : {
238 153 : if ( include_list_start != NULL )
239 : {
240 29 : int curr_wid = DISPLAY_WIDTH; /* Current width; force new line */
241 29 : printf("\nInclude-List:");
242 29 : include_list_next = include_list_start ;
243 129 : while ( include_list_next != NULL )
244 : {
245 71 : int this_wid = strlen( include_list_next->dir_path) + 1;
246 71 : char *separator = " ";
247 71 : if ( curr_wid + this_wid > DISPLAY_WIDTH )
248 : {
249 33 : separator = "\n\t";
250 33 : curr_wid = 7; /* Allow 1 for the theoretical space */
251 : }
252 71 : printf("%s%s", separator, include_list_next->dir_path);
253 71 : curr_wid += this_wid;
254 71 : include_list_next = include_list_next->next ;
255 : }
256 29 : printf("\n");
257 : }
258 153 : }
259 :
260 :
261 :
262 : /* **************************************************************************
263 : *
264 : * We cannot accommodate the structures of the different
265 : * routines that open files with a single function, so
266 : * we will have to divide the action up into pieces:
267 : * one routine to initialize the include-list search, a
268 : * second to return successive candidates. The calling
269 : * routine will do the operation (stat or fopen) until
270 : * it succeeds or the list is exhausted. Then it will
271 : * call a final routine to clean up and display messages.
272 : *
273 : * I'm sure I don't need to mention that, when no include-list
274 : * is defined, these functions will still support correct
275 : * operation...
276 : *
277 : **************************************************************************** */
278 :
279 : /* **************************************************************************
280 : *
281 : * Function name: init_incl_list_scan
282 : * Synopsis: Initialize the search through the Include-List
283 : *
284 : * Inputs:
285 : * Parameters:
286 : * base_name Expanded user-supplied file-name
287 : * Local Static Variables:
288 : * include_list_start First entry in the Include-List
289 : * max_dir_path_len Maximum Directory Component Length
290 : *
291 : * Outputs:
292 : * Returned Value: NONE
293 : * Local Static Variables:
294 : * include_list_next Next entry in Include-List to read
295 : * include_list_full_path Full-Path Buffer pointer
296 : * Memory Allocated
297 : * Full-Path Buffer (If Include-List was defined)
298 : * When Freed?
299 : * In finish_incl_list_scan()
300 : *
301 : * Process Explanation:
302 : * The base_name passed to the routine is expected to have
303 : * any embedded Environment-Variables already expanded.
304 : * The Full-Path Buffer is presumed to be unallocated, and
305 : * its pointer to be NULL.
306 : * The Next-Entry-to-read pointer is also presumed to be NULL.
307 : * If an Include-List has been defined, we will allocate memory
308 : * for the Full-Path Buffer and point the Next-Entry pointer
309 : * at the Start of the List. If not, no need to do anything.
310 : *
311 : **************************************************************************** */
312 :
313 : static void init_incl_list_scan( char *base_name)
314 438 : {
315 438 : if ( include_list_start != NULL )
316 : {
317 : /* Allocate memory for the file-name buffer.
318 : * maximum path-element length plus base-name length
319 : * plus one for the slash plus one for the ending NULL
320 : */
321 90 : unsigned int new_path_len = max_dir_path_len + strlen( base_name) + 2;
322 90 : include_list_full_path = safe_malloc( new_path_len,
323 : "scanning include-list" );
324 90 : include_list_next = include_list_start;
325 : }
326 438 : }
327 :
328 : /* **************************************************************************
329 : *
330 : * Function name: scan_incl_list
331 : * Synopsis: Prepare the next candidate in the include-list search
332 : * Indicate when the end has been reached.
333 : *
334 : * Inputs:
335 : * Parameters:
336 : * base_name Expanded user-supplied file-name
337 : * Local Static Variables:
338 : * include_list_full_path Full-Path Buffer pointer
339 : * include_list_next Next entry in Include-List to read
340 : *
341 : * Outputs:
342 : * Returned Value: TRUE if valid candidate; FALSE when done
343 : * Local Static Variables:
344 : * include_list_full_path Next Full file-name Path to use
345 : * include_list_next Updated to next entry in the List
346 : *
347 : * Process Explanation:
348 : * Include-List Components are presumed not to require any expansion;
349 : * the Shell is expected to resolve any Environment-Variables
350 : * supplied in command-line arguments before they are passed
351 : * to the (this) application-program.
352 : * We will, therefore, not attempt to expand any Components of
353 : * the Include-List.
354 : * If the Full-Path Buffer pointer is NULL, it indicates that no
355 : * entries have been made to the Include-List and this is our
356 : * first time through this routine in this search; we will
357 : * use the base-name as supplied, presumably relative to the
358 : * current directory. Point the buffer-pointer at the base-
359 : * -name and return "Not Done".
360 : * Otherwise, we will look at the Next-Entry pointer:
361 : * If it is NULL, we have come to the end of the Include-List;
362 : * whether because no Include-List was defined or because
363 : * we have reached the end, we will return "Done".
364 : * Otherwise, we will load the Full-Path Buffer with the entry
365 : * currently indicated by the Next-Entry pointer, advance
366 : * it to the next entry in the List and return "Not Done".
367 : * We will supply a slash as the directory-element separator in
368 : * between the Include-List entry and the base_name
369 : *
370 : * Extraneous Remarks:
371 : * The slash as directory-element separator works in UNIX-related
372 : * environments, but is not guaranteed in others. I would
373 : * have preferred to specify that Include-List Components are
374 : * required to end with the appropriate separator, but that
375 : * was neither acceptable nor compatible with existing practice
376 : * in other utilities, and the effort to programmatically
377 : * determine the separator used by the Host O/S was too much
378 : * for such a small return. And besides, we already have so
379 : * many other UNIX-centric assumptions hard-coded into the
380 : * routines in this file (dollar-sign to signify Environment
381 : * Variables, period for file-name-extension separator, etc.)
382 : * that it's just too much of an uphill battle anymore...
383 : *
384 : **************************************************************************** */
385 :
386 : static bool scan_incl_list( char *base_name)
387 545 : {
388 545 : bool retval = FALSE; /* default to "Done" */
389 :
390 545 : if ( include_list_full_path == NULL )
391 : {
392 348 : include_list_full_path = base_name;
393 348 : retval = TRUE;
394 : }else{
395 197 : if ( include_list_next != NULL )
396 : {
397 :
398 : /* Special case: If the next Directory Component is
399 : * an empty string, do not prepend a slash; that
400 : * would either become a root-based absolute path,
401 : * or, if the base-name is itself an absolute path,
402 : * it would be a path that begins with two slashes,
403 : * and *some* Host Operating Systems ***REALLY***
404 : * DO NOT LIKE that!
405 : */
406 181 : if ( strlen( include_list_next->dir_path) == 0 )
407 : {
408 8 : sprintf( include_list_full_path, "%s", base_name);
409 : }else{
410 173 : sprintf( include_list_full_path, "%s/%s",
411 : include_list_next->dir_path, base_name);
412 : }
413 181 : include_list_next = include_list_next->next;
414 181 : retval = TRUE;
415 : }
416 : }
417 :
418 545 : return( retval);
419 : }
420 :
421 : /* **************************************************************************
422 : *
423 : * Function name: finish_incl_list_scan
424 : * Synopsis: Clean up after a search through the Include-List
425 : * Display appropriate messages.
426 : *
427 : * Inputs:
428 : * Parameters:
429 : * op_succeeded TRUE if intended operation was ok.
430 : *
431 : * Local Static Variables:
432 : * include_list_start Non-NULL if Include-List was defined
433 : *
434 : * Outputs:
435 : * Returned Value: NONE
436 : * Local Static Variables:
437 : * include_list_full_path Reset to NULL
438 : * include_list_next Reset to NULL
439 : * Memory Freed
440 : * Full-Path Buffer (If Include-List was defined)
441 : * Printout:
442 : * If file was found in Include-List, Advisory showing where.
443 : *
444 : **************************************************************************** */
445 :
446 : static void finish_incl_list_scan( bool op_succeeded)
447 441 : {
448 441 : if ( include_list_start != NULL )
449 : {
450 91 : if ( op_succeeded )
451 : {
452 86 : tokenization_error( INFO,
453 : "File was found in %s\n" ,include_list_full_path );
454 : }
455 91 : free( include_list_full_path);
456 : }
457 441 : include_list_full_path = NULL;
458 441 : include_list_next = NULL;
459 441 : }
460 :
461 : /* **************************************************************************
462 : *
463 : * Function name: open_incl_list_file
464 : * Synopsis: Look in the Include-List, if one is defined, for
465 : * the file whose name is given and open it.
466 : *
467 : * Inputs:
468 : * Parameters:
469 : * base_name Expanded user-supplied file-name
470 : * mode Mode-string to use; usually "r" or "rb"
471 : * Local Static Variables:
472 : * include_list_full_path Full Path to use in fopen atttempt
473 : *
474 : * Outputs:
475 : * Returned Value: File structure pointer; NULL if failed
476 : * Local Static Variables:
477 : * include_list_full_path Full Path used, if succeeded
478 : *
479 : * Error Detection:
480 : * Calling routine will detect and report Errors.
481 : *
482 : * Process Explanation:
483 : * This routine will initialize and step through Include-List.
484 : * Calling routine will be responsible for "finishing" the
485 : * Include-List search, as well as any Advisory messages.
486 : *
487 : **************************************************************************** */
488 :
489 : static FILE *open_incl_list_file( char *base_name, char *mode)
490 15 : {
491 15 : FILE *retval = NULL;
492 :
493 15 : init_incl_list_scan( base_name);
494 66 : while ( scan_incl_list( base_name) )
495 : {
496 43 : retval = fopen( include_list_full_path, mode);
497 43 : if ( retval != NULL )
498 : {
499 7 : break;
500 : }
501 : }
502 :
503 15 : return (retval);
504 : }
505 :
506 : /* **************************************************************************
507 : *
508 : * Function name: stat_incl_list_file
509 : * Synopsis: Look in the Include-List, if defined, for given file,
510 : * and collect its statistics.
511 : *
512 : *
513 : * Inputs:
514 : * Parameters:
515 : * base_name Expanded user-supplied file-name
516 : * file_info Pointer to STAT structure
517 : * Local Static Variables:
518 : * include_list_full_path Full Path to use in file-status atttempt
519 : *
520 : * Outputs:
521 : * Returned Value: TRUE if succeeded.
522 : * Local Static Variables:
523 : * include_list_full_path Full Path used, if succeeded
524 : * Supplied Pointers:
525 : * *file_info File-statistics structure from STAT call
526 : *
527 : * Error Detection:
528 : * Calling routine will detect and report Errors.
529 : *
530 : * Process Explanation:
531 : * This routine will initialize and step through Include-List.
532 : * Calling routine will be responsible for "finishing" the
533 : * Include-List search, as well as any Advisory messages.
534 : *
535 : **************************************************************************** */
536 :
537 : static bool stat_incl_list_file( char *base_name, struct stat *file_info)
538 423 : {
539 423 : bool retval = FALSE;
540 423 : int stat_reslt = -1; /* Success = 0 */
541 :
542 423 : init_incl_list_scan( base_name);
543 423 : while ( scan_incl_list( base_name) )
544 : {
545 972 : stat_reslt = stat( include_list_full_path, file_info);
546 486 : if ( stat_reslt == 0 )
547 : {
548 415 : retval = TRUE;
549 415 : break;
550 : }
551 : }
552 :
553 423 : return (retval);
554 : }
555 :
556 : /* **************************************************************************
557 : *
558 : * Function name: init_inbuf
559 : * Synopsis: Set the given buffer as the current input source
560 : *
561 : * Inputs:
562 : * Parameters:
563 : * inbuf Pointer to start of new input buffer
564 : * buflen Length of new input buffer
565 : *
566 : * Outputs:
567 : * Returned Value: NONE
568 : * Global Variables:
569 : * start Points to given buffer
570 : * end Points to end of new input buffer
571 : * pc Re-initialized
572 : *
573 : **************************************************************************** */
574 :
575 : void init_inbuf(char *inbuf, unsigned int buflen)
576 1609 : {
577 1609 : start = inbuf;
578 1609 : pc = start;
579 1609 : end = pc + buflen;
580 1609 : }
581 :
582 : /* **************************************************************************
583 : *
584 : * Function name: could_not_open
585 : * Synopsis: Report the "Could not open" Message for various Files.
586 : *
587 : * Inputs:
588 : * Parameters:
589 : * severity Severity of message, WARNING or ERROR
590 : * fle_nam Name of file
591 : * for_what Phrase after "... for "
592 : *
593 : * Outputs:
594 : * Returned Value: NONE
595 : * Printout:
596 : * Message of indicated severity.
597 : *
598 : * Error Detection:
599 : * Error already detected; reported here.
600 : *
601 : **************************************************************************** */
602 :
603 : static void could_not_open(int severity, char *fle_nam, char *for_what)
604 6 : {
605 6 : tokenization_error( severity, "Could not open file %s for %s.\n",
606 : fle_nam, for_what);
607 :
608 6 : }
609 :
610 : /* **************************************************************************
611 : *
612 : * Function name: file_is_missing
613 : * Synopsis: Add the given File to the Missing-Files-List.
614 : *
615 : * Inputs:
616 : * Parameters:
617 : * fle_nam Name of file
618 : * Local Static Variables:
619 : * missing_list_file Missing-Files-List File Structure
620 : * May be NULL if none was opened
621 : *
622 : * Outputs:
623 : * Returned Value: NONE
624 : * Local Static Variables:
625 : * no_files_missing Set FALSE
626 : * File Output:
627 : * Write File name to Missing-Files-List (if one was opened)
628 : *
629 : * Error Detection:
630 : * Error already detected; reported here.
631 : *
632 : **************************************************************************** */
633 :
634 : static void file_is_missing( char *fle_nam)
635 20 : {
636 20 : if ( missing_list_file != NULL )
637 : {
638 8 : fprintf( missing_list_file, "%s\n", fle_nam);
639 8 : no_files_missing = FALSE;
640 : }
641 20 : }
642 :
643 : /* **************************************************************************
644 : *
645 : * Function name: add_to_load_lists
646 : * Synopsis: Add the given input file-name to the Load-List File,
647 : * and the Full File path to the Dependency-List File.
648 : *
649 : * Inputs:
650 : * Parameters:
651 : * in_name Name of given input Source File
652 : * Local Static Variables:
653 : * load_list_file Load List File Structure pointer
654 : * depncy_file Dependency-List File Structure ptr
655 : * Either may be NULL if the file was not opened.
656 : * include_list_full_path Full Path to where the file was found.
657 : *
658 : * Outputs:
659 : * Returned Value: NONE
660 : * File Output:
661 : * Write given file-name to Load-List file (if one was opened)
662 : * Write File Path to Dependency-List file (if one was opened)
663 : *
664 : * Process Explanation:
665 : * Write into the Load-List file the input Source Filename in the
666 : * same form -- i.e., unexpanded -- as was supplied by the User.
667 : * Write into the Dependency-List file the full expanded path, as
668 : * supplied by the program to the Host Operating System.
669 : *
670 : **************************************************************************** */
671 :
672 : static void add_to_load_lists( const char *in_name)
673 570 : {
674 570 : if ( load_list_file != NULL )
675 : {
676 184 : fprintf( load_list_file, "%s\n", in_name);
677 : }
678 570 : if ( depncy_file != NULL )
679 : {
680 7 : fprintf( depncy_file, "%s\n", include_list_full_path);
681 : }
682 570 : }
683 :
684 :
685 : /* **************************************************************************
686 : *
687 : * In the functions that support accessing files whose path-names
688 : * contain embedded Environment-Variables, the commentaries
689 : * will refer to this process, or to inputs that require it,
690 : * using variants of the term "expand".
691 : *
692 : * We will also keep some of the relevant information as Local
693 : * Static Variables.
694 : *
695 : **************************************************************************** */
696 :
697 : static char expansion_buffer[ 2*GET_BUF_MAX];
698 : static bool was_expanded;
699 : static int expansion_msg_severity = INFO;
700 :
701 : /* **************************************************************************
702 : *
703 : * Function name: expanded_name
704 : * Synopsis: Advisory message to display filename expansion.
705 : *
706 : * Inputs:
707 : * Parameters:
708 : * Local Static Variables:
709 : * was_expanded TRUE if expansion happened
710 : * expansion_buffer Buffer with result of expansion
711 : * expansion_msg_severity Whether it's an ordinary Advisory
712 : * or we force a message.
713 : *
714 : * Outputs:
715 : * Returned Value: NONE
716 : *
717 : * Printout:
718 : * Advisory message showing expansion, if expansion happened
719 : * Otherwise, nothing.
720 : *
721 : **************************************************************************** */
722 :
723 : static void expanded_name( void )
724 29 : {
725 29 : if ( was_expanded )
726 : {
727 27 : tokenization_error( expansion_msg_severity,
728 : "File name expanded to: %s\n", expansion_buffer);
729 : }
730 29 : }
731 :
732 :
733 : /* **************************************************************************
734 : *
735 : * Function name: expansion_error
736 : * Synopsis: Supplemental message to display filename expansion.
737 : * Called after an expanded-filename failure was reported.
738 : *
739 : * Inputs:
740 : * Parameters:
741 : * Global Variables:
742 : * verbose Set by "-v" switch
743 : *
744 : * Outputs:
745 : * Returned Value: NONE
746 : * Printout:
747 : * Advisory message showing expansion, if applicable
748 : * and if wasn't already shown.
749 : *
750 : * Error Detection:
751 : * Called after Error was reported.
752 : *
753 : * Process Explanation:
754 : * Presumptions are that:
755 : * An Error message, showing the user-supplied form of the
756 : * pathname is also being displayed
757 : * An advisory message showing the pathname expansion may
758 : * have been displayed during the expansion process,
759 : * if verbose was TRUE.
760 : * The purpose of this routine is to display the expansion if
761 : * it had not already just been displayed, i.e., if verbose
762 : * is not set to TRUE: Temporarily force the display of an
763 : * Advisory message.
764 : *
765 : * Extraneous Remarks:
766 : * If this routine is called before the Error message is displayed,
767 : * the verbose and non-verbose versions of the Log-File will
768 : * match up nicely...
769 : *
770 : **************************************************************************** */
771 :
772 : static void expansion_error( void )
773 31 : {
774 31 : if ( INVERSE( verbose) )
775 : {
776 9 : expansion_msg_severity |= FORCE_MSG;
777 9 : expanded_name();
778 9 : expansion_msg_severity ^= FORCE_MSG;
779 : }
780 31 : }
781 :
782 :
783 : /* **************************************************************************
784 : *
785 : * Function name: expand_pathname
786 : * Synopsis: Perform the expansion of a path-name that may contain
787 : * embedded Environment-Variables
788 : *
789 : * Inputs:
790 : * Parameters:
791 : * input_pathname The user-supplied filename
792 : * Global/Static MACRO:
793 : * GET_BUF_MAX Size of expansion buffer is twice this.
794 : *
795 : * Outputs:
796 : * Returned Value: Pointer to expanded name, or to
797 : * input if no expansion needed.
798 : * NULL if error.
799 : * Local Static Variables:
800 : * was_expanded TRUE if expansion needed and succeeded
801 : * expansion_buffer Result of expansion
802 : * Printout:
803 : * Advisory message showing expansion
804 : * Presumption is that an Advisory giving the user-supplied
805 : * pathname was already printed.
806 : *
807 : * Error Detection:
808 : * Syntax error. System might print something; it might not be
809 : * captured, even to a log-file. System failure return might
810 : * be the only program-detectable indication. Display ERROR
811 : * message and return NULL pointer. Calling routine will
812 : * display the user-supplied pathname in its Error message
813 : * indicating failure to open the file.
814 : *
815 : * Process Explanation:
816 : * Generally speaking, we will let the Shell expand the Environment
817 : * Variables embedded in the user-supplied pathname.
818 : * First, though, we will see if the expansion is necessary: Look
819 : * for the telltale character, '$', in the input string. If
820 : * it's not there, there are no Env't-V'bles, and no expansion
821 : * is necessary. Return the pointer to the input string and
822 : * we're done. Otherwise.....
823 : * Acquire a temporary file-name. Construct a string of the form:
824 : * echo input_string > temp_file_name
825 : * and then issue that string as a command to the Shell.
826 : * If that string generates a system-call failure, report an ERROR.
827 : * Open the temporary file and read its contents. That will be
828 : * the expansion of the input string. If its length exceeds
829 : * the capacity of the expansion buffer, it's another ERROR.
830 : * (Of course, don't forget to delete the temporary file.)
831 : * Place the null-byte marker at the end of the expanded name,
832 : * trimming off the terminating new-line.
833 : * Success. Display the expanded name (as an Advisory message)
834 : * Return the pointer to the expansion buffer and set the flag.
835 : * (Did I mention don't forget to delete the temporary file?)
836 : *
837 : * Extraneous Remarks:
838 : * This implementation approach turned out to be the simplest and
839 : * cleanest way to accomplish our purpose. It also boasts the
840 : * HUGE advantage of not requiring re-invention of a well-used
841 : * (proverbial) wheel. Plus, any variations allowed by the
842 : * shell (e.g.,: $PWD:h ) are automatically converted, too,
843 : * depending on the System shell (e.g., not for Bourne shell).
844 : * In order to spare you, the maintenance programmer, unnecessary
845 : * agony, I will list a few other approaches I tested, with a
846 : * brief note about the results of each:
847 : * (1)
848 : * I actually tried parsing the input line and passing each component
849 : * V'ble to the getenv() function, accumulating the results into
850 : * a conversion buffer. I needed to check for every possible
851 : * delimiter, and handle curly-brace enclosures. The resultant
852 : * code was *UGLY* ... you'd be appalled! The only good spot was
853 : * that I was able to compensate for an open-curly-brace without
854 : * a corresponding close-curly-brace (if close-c-b wasn't found,
855 : * resume the search for other delimiters...) which, apparently,
856 : * the System does not or will not do. It was, however, too
857 : * small a compensation for all the awfulness entailed overall.
858 : *
859 : * I tried various approaches to using the Environment-Variables to
860 : * convert and retrieve the input string:
861 : * (2)
862 : * Create a command-string that would set an Env't V'ble to the
863 : * input-string, and pass the command-string to the system() call,
864 : * then retrieve the Env't V'ble thus set via getenv(). No dice;
865 : * the system() call operated in a separate sub-shell and could
866 : * not export its Env't upwards.
867 : * (3)
868 : * Use the setenv() command to set an Env't V'ble to the input-string
869 : * and retrieve it via getenv(). The returned string matched the
870 : * input-string without converting it.
871 : * (4)
872 : * Use the setenv() command to set an Env't V'ble to a string like:
873 : * `echo input_string`
874 : * Again, the string retrieved via getenv() exactly matched the
875 : * unconverted command-string, back-quotes and all.
876 : *
877 : * Of course, the equivalents of (2), (3) and (4) worked as desired
878 : * when tested as direct commands to the Shell. UNIX can be
879 : * funny that way...
880 : *
881 : * Oh! Also: we will slightly stretch the rules of well-structured
882 : * code.
883 : *
884 : **************************************************************************** */
885 :
886 : static char *expand_pathname( const char *input_pathname)
887 443 : {
888 : static const int buffer_max = GET_BUF_MAX * 2;
889 :
890 443 : char *retval = (char *)input_pathname;
891 443 : was_expanded = FALSE;
892 :
893 : /* If no '$' is found, expansion is unnecessary. */
894 443 : if ( strchr( input_pathname, '$') != NULL )
895 : {
896 : FILE *temp_file;
897 : int syst_stat;
898 25 : const char *temp_file_name = tmpnam( NULL);
899 :
900 : /* Use the expansion buffer for our temporary command string */
901 25 : sprintf( expansion_buffer,
902 : "echo %s>%s\n", input_pathname, temp_file_name);
903 25 : syst_stat = system( expansion_buffer);
904 25 : if ( syst_stat != 0 )
905 : {
906 5 : tokenization_error( TKERROR,
907 : "Expansion Syntax.\n");
908 : /* The "File-Opening" error message will show the input string */
909 5 : return( NULL);
910 : }
911 :
912 20 : temp_file = fopen( temp_file_name, "r"); /* Cannot fail. */
913 20 : syst_stat = fread( expansion_buffer, 1, buffer_max, temp_file);
914 : /* Error test. Length of what we read is not a good indicator;
915 : * it's limited anyway by buffer_max.
916 : * Valid test is if last character read was the new-line.
917 : */
918 20 : if ( expansion_buffer[syst_stat-1] != '\n' )
919 : {
920 0 : tokenization_error( TKERROR,
921 : "Expansion buffer overflow. Max length is %d.\n",
922 : buffer_max);
923 0 : retval = NULL;
924 : }else{
925 20 : expansion_buffer[syst_stat-1] =0;
926 20 : was_expanded = TRUE;
927 20 : retval = expansion_buffer;
928 20 : expanded_name();
929 : }
930 :
931 20 : fclose( temp_file);
932 20 : remove( temp_file_name);
933 : }
934 :
935 438 : return( retval);
936 : }
937 :
938 : /* **************************************************************************
939 : *
940 : * Function name: open_expanded_file
941 : * Synopsis: Open a file, expanding Environment-Variables that
942 : * may be embedded in the given path-name.
943 : *
944 : * Inputs:
945 : * Parameters:
946 : * path_name The user-supplied path-name
947 : * mode Mode-string to use; usually "r" or "rb"
948 : * for_what Phrase to use in Messages
949 : *
950 : * Outputs:
951 : * Returned Value: Pointer to FILE structure; NULL if failed
952 : * Local Static Variables:
953 : * was_expanded TRUE if expansion happened
954 : * expansion_buffer Result of expansion
955 : * Printout:
956 : * Advisory message showing expansion
957 : *
958 : * Error Detection:
959 : * If expansion or system-call for file-open failed,
960 : * report Error and return NULL.
961 : *
962 : **************************************************************************** */
963 :
964 : FILE *open_expanded_file( const char *path_name, char *mode, char *for_what)
965 18 : {
966 :
967 18 : FILE *retval = NULL;
968 :
969 18 : char *infile_name = expand_pathname( path_name);
970 18 : if ( infile_name != NULL )
971 : {
972 15 : retval = open_incl_list_file( infile_name, mode);
973 : }
974 :
975 18 : if ( retval == NULL )
976 : {
977 11 : expansion_error();
978 11 : tokenization_error ( TKERROR,
979 : "Failed to open file %s for %s\n", path_name, for_what );
980 : }
981 :
982 18 : finish_incl_list_scan( BOOLVAL( retval != NULL) );
983 :
984 18 : return( retval);
985 : }
986 :
987 : /* **************************************************************************
988 : *
989 : * Function name: init_stream
990 : * Synopsis: Open a file and make it the current source.
991 : * This is called, not only at the start of tokenization,
992 : * but also when a subsidiary file is FLOADed.
993 : *
994 : * Inputs:
995 : * Parameters:
996 : * name Name of the new Input File to open
997 : * May be path-name containing
998 : * embedded Environment-Variables.
999 : * Global Variables:
1000 : * oname NULL if opening Primary Input File
1001 : * Local Static Variables:
1002 : * include_list_full_path Full Path to where the file was found
1003 : *
1004 : * Outputs:
1005 : * Returned Value: TRUE = opened and read file successfully
1006 : * Global Variables (Only changed if successful):
1007 : * iname Set to new Input File name
1008 : * lineno Re-initialized to 1
1009 : * Local Static Variables:
1010 : * no_files_missing Set FALSE if couldn't read input file
1011 : * include_list_full_path Retains full-path if file opened was
1012 : * the Primary Input File (as contrasted with an FLoaded
1013 : * Source file), in which case a call to init_output()
1014 : * is expected; the Full-Path Buffer will be freed there.
1015 : * Memory Allocated
1016 : * Duplicate of Input File name (becomes iname )
1017 : * A fresh input buffer; input file is copied to it.
1018 : * Becomes start by action of call to init_inbuf().
1019 : * When Freed?
1020 : * By close_stream()
1021 : * File Output:
1022 : * Write new Input File name to Load-List file.
1023 : * Writing to Missing-Files-List File if failure,
1024 : * or Full File path to Dependency-List File,
1025 : * is handled by called routine.
1026 : * Other Exotic Effects:
1027 : * Force a flush of stdout before printing ERROR messages
1028 : *
1029 : * Error Detection:
1030 : * Failure to open or read Input file: ERROR; suppress output;
1031 : * write Input File name to Missing-Files-List File.
1032 : *
1033 : * Process Explanation:
1034 : * Free local buffer on failure.
1035 : * Caller should only invoke close_stream() if this call succeeded.
1036 : * Some filesystems use zeros for new-line; we need to convert
1037 : * those zeros to line-feeds.
1038 : * Similarly for files that have carr-ret/line-feed; the carr-ret
1039 : * will cause havoc; replace it w/ a space.
1040 : *
1041 : * Revision History:
1042 : * Updated Thu, 07 Apr 2005 by David L. Paktor
1043 : * Restructured. If opened file, close it, even if can't read it.
1044 : * Return TRUE on success.
1045 : * Caller examines return value.
1046 : * Updated Wed, 13 Jul 2005 by David L. Paktor
1047 : * Replace carr-rets with spaces.
1048 : * Updated Sun, 27 Nov 2005 by David L. Paktor
1049 : * Write new Input File name to Load-List file.
1050 : * Updated Tue, 31 Jan 2006 by David L. Paktor
1051 : * Add support for embedded Environment-Variables in path name
1052 : * Updated Thu, 16 Feb 2006 David L. Paktor
1053 : * Collect missing (inaccessible) filenames
1054 : * Updated Fri, 17 Mar 2006 David L. O'Paktor
1055 : * Add support for Include-List search
1056 : *
1057 : * Still to be done:
1058 : * Set a flag when carr-ret has been replaced by space;
1059 : * when a string crosses a line, if this flag is set,
1060 : * issue a warning that an extra space has been inserted.
1061 : *
1062 : **************************************************************************** */
1063 :
1064 : bool init_stream( const char *name)
1065 425 : {
1066 : FILE *infile;
1067 : u8 *newbuf;
1068 : struct stat finfo;
1069 425 : bool stat_succ = FALSE;
1070 425 : bool tried_stat = FALSE;
1071 425 : bool retval = FALSE;
1072 425 : bool inp_fil_acc_err = FALSE;
1073 425 : bool inp_fil_open_err = FALSE;
1074 425 : bool inp_fil_read_err = FALSE;
1075 :
1076 425 : char *infile_name = expand_pathname( name);
1077 :
1078 425 : if ( (infile_name != NULL) )
1079 : {
1080 423 : tried_stat = TRUE;
1081 423 : stat_succ = stat_incl_list_file( infile_name, &finfo);
1082 : }
1083 :
1084 425 : if ( INVERSE( stat_succ) )
1085 : {
1086 10 : inp_fil_acc_err = TRUE;
1087 : }else{
1088 :
1089 415 : infile = fopen( include_list_full_path, "r");
1090 415 : if ( infile == NULL )
1091 : {
1092 3 : inp_fil_open_err = TRUE;
1093 : }else{
1094 :
1095 412 : ilen=finfo.st_size;
1096 412 : newbuf = safe_malloc(ilen+1, "initting stream");
1097 :
1098 412 : if ( fread( newbuf, ilen, 1, infile) != 1 )
1099 : {
1100 7 : inp_fil_read_err = TRUE;
1101 7 : free( newbuf );
1102 : } else {
1103 : unsigned int i;
1104 :
1105 405 : retval = TRUE ;
1106 : /* Replace zeroes in the file with LineFeeds. */
1107 : /* Replace carr-rets with spaces. */
1108 2387462 : for (i=0; i<ilen; i++)
1109 : {
1110 2387057 : char test_c = newbuf[i];
1111 2387057 : if ( test_c == 0 ) newbuf[i] = 0x0a;
1112 2387057 : if ( test_c == 0x0d ) newbuf[i] = ' ';
1113 : }
1114 405 : newbuf[ilen]=0;
1115 :
1116 405 : init_inbuf(newbuf, ilen);
1117 :
1118 : /* If the -l option was specified, write the name of the
1119 : * new input-file to the Load-List file... UNLESS
1120 : * this is the first time through and we haven't yet
1121 : * opened the Load-List file, in which case we'll
1122 : * just open it here and wait until we create the
1123 : * output-file name (since the Load-List file name
1124 : * depends on the output-file name anyway) before
1125 : * we write the initial input-file name to it.
1126 : */
1127 : /* Looking for the option-flag _and_ for a non-NULL value
1128 : * of the file-structure pointer is redundandundant:
1129 : * The non-NULL pointer is sufficient, once the List
1130 : * File has been created...
1131 : */
1132 : /* Same thing applies if the -P option was specified,
1133 : * for the Dependency-List file, except there we'll
1134 : * write the full path to where the file was found.
1135 : */
1136 : /* We have a routine to do both of those. */
1137 405 : add_to_load_lists( name);
1138 : /*
1139 : * And... there's one slight complication: If this is
1140 : * the first time through, (i.e., we're opening the
1141 : * Primary Input File) then we haven't yet opened the
1142 : * Dependency-List file, and we need to preserve the
1143 : * Full file-name Buffer until the call to init_output()
1144 : * where the include-list scan will be "finish"ed.
1145 : * Actually, we want to postpone "finish"ing the inc-l scan
1146 : * for several reasons beyond the Dependency-List file,
1147 : * such as completing the File Name Announcement first.
1148 : * A NULL output-name buffer is our indicator.
1149 : */
1150 405 : if ( oname == NULL )
1151 : {
1152 : /* Quick way to suppress "finish"ing the i-l scan */
1153 165 : tried_stat = FALSE;
1154 : }
1155 : }
1156 412 : fclose(infile);
1157 : }
1158 : }
1159 :
1160 425 : FFLUSH_STDOUT /* Do this first */
1161 : /* Now we can deliver our postponed error and advisory messages */
1162 425 : if ( INVERSE( retval) )
1163 : {
1164 20 : file_is_missing( (char *)name);
1165 20 : if ( inp_fil_acc_err )
1166 : {
1167 10 : expansion_error();
1168 10 : tokenization_error( TKERROR,
1169 : "Could not access input file %s\n", name);
1170 : }else{
1171 10 : if ( inp_fil_open_err )
1172 : {
1173 3 : expansion_error();
1174 3 : could_not_open( TKERROR, (char *)name, "input");
1175 : }else{
1176 7 : if ( inp_fil_read_err )
1177 : {
1178 7 : expansion_error();
1179 7 : tokenization_error( TKERROR,
1180 : "Could not read input file %s\n", name);
1181 : }
1182 : }
1183 : }
1184 : }
1185 :
1186 425 : if ( tried_stat )
1187 : {
1188 258 : finish_incl_list_scan( stat_succ);
1189 : }
1190 :
1191 : /* Don't change the input file name and line-number until after
1192 : * the Advisory showing where the file was found.
1193 : */
1194 425 : if ( retval )
1195 : {
1196 405 : iname=strdup(name);
1197 405 : lineno=1;
1198 : }
1199 :
1200 425 : return ( retval );
1201 :
1202 : }
1203 :
1204 : /* **************************************************************************
1205 : *
1206 : * Function name: extend_filename
1207 : * Synopsis: Change the filename to the given extension
1208 : *
1209 : * Inputs:
1210 : * Parameters:
1211 : * base_name Name of the Input Base File
1212 : * new_ext New ext'n (with leading period)
1213 : *
1214 : * Outputs:
1215 : * Returned Value: Result filename
1216 : * Memory Allocated
1217 : * Buffer for result filename
1218 : * When Freed?
1219 : * At end of Tokenization, by close_output().
1220 : *
1221 : * Process Explanation:
1222 : * If the Input Base File Name has an extension, it will be replaced
1223 : * with the given new extension. If not, the new extension will
1224 : * simply be appended.
1225 : * If the Input Base File Name has an extension that matches the
1226 : * new extension, a duplicate of the extension will be appended.
1227 : *
1228 : * Extraneous Remarks:
1229 : * I only recently added protection against the situation where the
1230 : * Input Base File Name has no extension, but the Directory Path
1231 : * leading to it has a period in one of the directory names.
1232 : * Granted, this is a rare case, but not altogether impossible;
1233 : * I would have done it earlier except for the fact that the
1234 : * separator between directories may vary with different Host
1235 : * Operating Systems.
1236 : * However, at this point we have UNIX-centric assumptions hard-
1237 : * -coded in to so many other places that we might as well
1238 : * go with the slash here too.
1239 : *
1240 : **************************************************************************** */
1241 :
1242 : static char *extend_filename( const char *base_name, const char *new_ext)
1243 247 : {
1244 : char *retval;
1245 : char *ext;
1246 : unsigned int len; /* should this be size_t? */
1247 : const char *root;
1248 :
1249 247 : root = strrchr(base_name, '/');
1250 247 : if ( root == NULL ) root = base_name;
1251 :
1252 247 : ext = strrchr(root, '.');
1253 247 : if ( ext != NULL )
1254 : {
1255 245 : if ( strcasecmp(ext, new_ext) == 0 )
1256 : {
1257 0 : ext = NULL;
1258 : }
1259 : }
1260 :
1261 247 : len = ext ? (ext - base_name) : (unsigned int)strlen(base_name) ;
1262 247 : retval = safe_malloc(len+strlen(new_ext)+1, "extending file-name");
1263 247 : memcpy( retval, base_name, len);
1264 247 : retval[len] = 0;
1265 247 : strcat(retval, new_ext);
1266 :
1267 247 : return( retval);
1268 : }
1269 :
1270 : /* **************************************************************************
1271 : *
1272 : * Function name: init_output
1273 : * Synopsis: After the Input Source File has been opened, assign
1274 : * the name for the Binary Output File; initialize
1275 : * the FCode Output Buffer; assign names for the
1276 : * FLoad List, Dependency-List, and Missing-Files
1277 : * List files; open them and write their first
1278 : * entries to them.
1279 : * Announce the Input and various output file names.
1280 : *
1281 : * Inputs:
1282 : * Parameters:
1283 : * in_name Name of the Input Source File
1284 : * out_name Name of the Binary Output File, if
1285 : * specified on the Command Line,
1286 : * or NULL if not.
1287 : * Global Variables:
1288 : * fload_list Whether to create an FLoad-List file
1289 : * dependency_list Whether to create a Dependency-List file
1290 : * Local Static Variables:
1291 : * include_list_full_path Full Path to the Input Source File;
1292 : * should still be valid from opening
1293 : * of Primary Source Input file, for
1294 : * first entry to Dependency-List file.
1295 : *
1296 : * Outputs:
1297 : * Returned Value: NONE
1298 : * Global Variables:
1299 : * oname Binary Output File Name
1300 : * ostart Start of FCode Output Buffer
1301 : * opc FCode Output Buffer Position Counter
1302 : * abs_token_no Initialized to 1
1303 : * Local Static Variables:
1304 : * load_list_name Name of the Load List File
1305 : * load_list_file FLoad List File Structure pointer
1306 : * depncy_list_name Name of the Dependency List File ptr
1307 : * depncy_file Dependency List File Structure
1308 : * missing_list_name Name of the Missing-Files-List File
1309 : * missing_list_file Missing-Files-List File Structure
1310 : * no_files_missing Initialized to TRUE
1311 : * Memory Allocated
1312 : * Binary Output File Name Buffer
1313 : * FCode Output Buffer
1314 : * FLoad List File Name Buffer
1315 : * Dependency List File Name Buffer
1316 : *
1317 : * When Freed?
1318 : * In close_output()
1319 : * File Output:
1320 : * FLoad List or Dependency List files are opened (if specified).
1321 : * Primary Source Input file name and path, respectively,
1322 : * are written as the first entry to each.
1323 : * Printout:
1324 : * (Announcement of input file name has already been made)
1325 : * Announce binary output, fload- and dependency- -list file names
1326 : *
1327 : * Error Detection:
1328 : * Failure to open FLoad List or Dependency List file: ERROR;
1329 : * suppress binary output. Further attempts to write to
1330 : * FLoad List or Dependency List files are prevented by
1331 : * the respective FILE_structure pointers being NULL.
1332 : * Failure to open Missing-Files-List file: WARNING
1333 : *
1334 : * Process Explanation:
1335 : * If no Output File Name was specified on the Command Line, the
1336 : * name of the Binary (FCode) Output File will be derived
1337 : * from the name of the Input File by replacing its extension
1338 : * with .fc , or, if the Input File had no extension, by
1339 : * merely appending the extension .fc
1340 : * In the odd case where the Input File name has an extension
1341 : * of .fc, we will merely append another .fc extension.
1342 : * If fload_list is TRUE (i.e., the "-l" option was specified on
1343 : * the command-line, the FLoad List File name will be derived
1344 : * from the name of the Output File by the same rules, only with
1345 : * an extension of .fl Open the FLoad List File. Write the
1346 : * name of the initial input file to the FLoad List File.
1347 : * Similarly if the "-P" command-line option was specified, the name
1348 : * of the Dependency List File will be derived with an extension
1349 : * of .P Open it and write the Full Path for the initial input
1350 : * file to it. NOTE: To do that, we need to have preserved the
1351 : * Full Path-name Buffer from the call to init_stream() We
1352 : * will "finish" it here, after we've used it.
1353 : * The Missing-Files-List File will be created if either option was
1354 : * specified. Its name will be derived similarly, with an
1355 : * extension of .fl.missing
1356 : *
1357 : **************************************************************************** */
1358 :
1359 : void init_output( const char *in_name, const char *out_name )
1360 165 : {
1361 : /* preparing output */
1362 :
1363 165 : if( out_name != NULL )
1364 : {
1365 54 : oname = strdup( out_name );
1366 : }else{
1367 111 : oname = extend_filename( in_name, ".fc");
1368 : }
1369 :
1370 : /* output buffer size. this is 128k per default now, but we
1371 : * could reallocate if we run out. KISS for now.
1372 : */
1373 165 : olen = OUTPUT_SIZE;
1374 165 : ostart=safe_malloc(olen, "initting output buffer");
1375 :
1376 165 : opc = 0;
1377 165 : init_emit(); /* Init'l'zns needed by our companion file, emit.c */
1378 :
1379 165 : printf("Binary output to %s ", oname);
1380 165 : if ( fload_list )
1381 : {
1382 65 : load_list_name = extend_filename( oname, ".fl");
1383 65 : load_list_file = fopen( load_list_name,"w");
1384 65 : printf(" FLoad-list to %s ", load_list_name);
1385 : }
1386 165 : if ( dependency_list )
1387 : {
1388 6 : depncy_list_name = extend_filename( oname, ".P");
1389 6 : depncy_file = fopen( depncy_list_name,"w");
1390 6 : printf(" Dependency-list to %s ", depncy_list_name);
1391 : }
1392 165 : printf("\n");
1393 :
1394 165 : add_to_load_lists( in_name);
1395 :
1396 : /* Let's avoid collisions between stdout and stderr */
1397 165 : FFLUSH_STDOUT
1398 :
1399 : /* Now we can deliver our advisory and error messages */
1400 :
1401 : {
1402 : /* Suspend showing filename in advisory and error messages. */
1403 165 : char *temp_iname = iname;
1404 165 : iname = NULL;
1405 :
1406 165 : finish_incl_list_scan( TRUE);
1407 :
1408 165 : if ( fload_list && (load_list_file == NULL) )
1409 : {
1410 2 : could_not_open( TKERROR, load_list_name, "Load-List");
1411 2 : free( load_list_name);
1412 : }
1413 165 : if ( dependency_list && (depncy_file == NULL) )
1414 : {
1415 0 : could_not_open( TKERROR, depncy_list_name,
1416 : "Dependency-List");
1417 0 : free( depncy_list_name);
1418 : }
1419 :
1420 165 : if ( fload_list || dependency_list )
1421 : {
1422 65 : missing_list_name = extend_filename( oname, ".fl.missing");
1423 65 : missing_list_file = fopen( missing_list_name,"w");
1424 65 : no_files_missing = TRUE;
1425 :
1426 65 : if ( missing_list_file == NULL )
1427 : {
1428 1 : could_not_open( WARNING, missing_list_name,
1429 : "Missing-Files List" );
1430 1 : free( missing_list_name);
1431 : }
1432 : }
1433 165 : iname = temp_iname;
1434 : }
1435 165 : abs_token_no = 1;
1436 165 : }
1437 :
1438 : /* **************************************************************************
1439 : *
1440 : * Function name: increase_output_buffer
1441 : * Synopsis: Reallocate the Output Buffer to double its prior size
1442 : *
1443 : * Inputs:
1444 : * Parameters: NONE
1445 : * Global Variables:
1446 : * ostart Start-address of current Output Buffer
1447 : * olen Current size of the Output Buffer
1448 : * Local Static Variables:
1449 : *
1450 : * Outputs:
1451 : * Returned Value: NONE
1452 : * Local Static Variables:
1453 : * olen Doubled from value at input
1454 : * ostart Start-address of new Output Buffer
1455 : * Memory Allocated
1456 : * A new FCode Output Buffer, using the realloc() facility.
1457 : * When Freed?
1458 : * In close_output()
1459 : * Memory Freed
1460 : * Former FCode Output Buffer, also by means of realloc()
1461 : *
1462 : * Printout:
1463 : * Advisory message that this is taking place.
1464 : *
1465 : * Error Detection:
1466 : * FATAL if realloc() fails.
1467 : * FATAL if output buffer has been expanded to a size beyond
1468 : * what an INT can express. Unlikely? maybe; impossible? no...
1469 : *
1470 : * Process Explanation:
1471 : * Because we are allowing the Output Buffer to be relocated, we
1472 : * must take care to limit the exposure to external routines
1473 : * of its actual address. All references to locations within
1474 : * the Output Buffer should be made in terms of an _offset_.
1475 : *
1476 : * Extraneous Remarks:
1477 : * Unfortunately, it is not feasible to completely isolate the
1478 : * actual address of the Output Buffer, but we will keep the
1479 : * exposure limited to the routines in emit.c
1480 : * Similarly, it wasn't feasible to keep this routine isolated,
1481 : * nor the variable olen , but we will limit their exposure.
1482 : *
1483 : **************************************************************************** */
1484 : void increase_output_buffer( void ); /* Keep the prototype local */
1485 : void increase_output_buffer( void )
1486 6 : {
1487 : u8 *newout;
1488 :
1489 6 : if ( olen == 0 )
1490 : {
1491 0 : tokenization_error( FATAL,
1492 : "Output Buffer reallocation overflow.");
1493 : }else{
1494 : unsigned int rea_len;
1495 6 : olen = olen * 2;
1496 6 : rea_len = olen;
1497 6 : if ( rea_len == 0 ) rea_len = (unsigned int)-1;
1498 6 : tokenization_error( INFO,
1499 : "Output Buffer overflow. "
1500 : "Relocating and increasing to %d bytes.\n", rea_len);
1501 :
1502 6 : newout = realloc(ostart, rea_len);
1503 6 : if ( newout == NULL)
1504 : {
1505 0 : tokenization_error( FATAL,
1506 : "Could not reallocate %d bytes for Output Buffer", rea_len);
1507 : }
1508 :
1509 6 : ostart = newout;
1510 : }
1511 6 : }
1512 :
1513 :
1514 : /* **************************************************************************
1515 : *
1516 : * Function name: close_stream
1517 : * Synopsis: Free-up the memory used for the current input file
1518 : * whenever it is closed. Reset pointers and
1519 : * line-counter. Close files as necessary.
1520 : *
1521 : * The dummy parameter is there to accommodate Macro-recursion protection.
1522 : * It's a long story; don't get me started...
1523 : *
1524 : **************************************************************************** */
1525 :
1526 : void close_stream( _PTR dummy)
1527 404 : {
1528 404 : free(start);
1529 404 : free(iname);
1530 404 : start = NULL;
1531 404 : iname = NULL;
1532 404 : lineno = 0;
1533 404 : }
1534 :
1535 : /* **************************************************************************
1536 : *
1537 : * Function name: close_output
1538 : * Synopsis: Write the Binary Output file, if appropriate.
1539 : * Return a "Failure" flag.
1540 : *
1541 : **************************************************************************** */
1542 :
1543 :
1544 : bool close_output(void)
1545 164 : {
1546 164 : bool retval = TRUE; /* "Failure" */
1547 164 : if ( error_summary() )
1548 : {
1549 147 : if ( opc == 0 )
1550 : {
1551 18 : retval = FALSE; /* "Not a problem" */
1552 : }else{
1553 : FILE *outfile;
1554 :
1555 129 : outfile=fopen( oname,"w");
1556 129 : if (!outfile)
1557 : {
1558 : /* Don't do this as a tokenization_error( TKERROR
1559 : * because those are all counted, among other reasons...
1560 : */
1561 2 : printf( "Could not open file %s for output.\n", oname);
1562 : }else{
1563 :
1564 127 : if ( fwrite(ostart, opc, 1, outfile) != 1 )
1565 : {
1566 0 : tokenization_error( FATAL, "While writing output.");
1567 : }
1568 :
1569 127 : fclose(outfile);
1570 :
1571 127 : printf("toke: wrote %d bytes to bytecode file '%s'\n",
1572 : opc, oname);
1573 127 : retval = FALSE; /* "No problem" */
1574 : }
1575 : }
1576 : }
1577 :
1578 164 : free(oname);
1579 164 : free(ostart);
1580 164 : oname = NULL;
1581 164 : ostart = NULL;
1582 164 : opc = 0;
1583 164 : olen = OUTPUT_SIZE;
1584 :
1585 164 : if ( load_list_file != NULL )
1586 : {
1587 63 : fclose(load_list_file);
1588 63 : free(load_list_name);
1589 : }
1590 164 : if ( depncy_file != NULL )
1591 : {
1592 6 : fclose(depncy_file);
1593 6 : free(depncy_list_name);
1594 : }
1595 164 : if ( missing_list_file != NULL )
1596 : {
1597 64 : fclose( missing_list_file);
1598 64 : if ( no_files_missing )
1599 : {
1600 62 : remove( missing_list_name);
1601 : }
1602 64 : free( missing_list_name);
1603 : }
1604 :
1605 164 : load_list_file = NULL;
1606 164 : load_list_name = NULL;
1607 164 : missing_list_file = NULL;
1608 164 : missing_list_name = NULL;
1609 164 : depncy_file = NULL;
1610 164 : depncy_list_name = NULL;
1611 :
1612 164 : return ( retval );
1613 : }
1614 :
|