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