#!/usr/bin/perl #+ # Name: # makeh # Purpose: # Generate the contents of the "ast.h" header file. # Type: # Perl script. # Invocation: # makeh file_list # Description: # This script processes private header files used within the AST library # in order to extract the public information they contain. This information # is produced in a form suitable for use in the public "ast.h" header file, # which defines the public interface to the library. # Parameters: # file_list # A space-separated list of the private AST header files whose public # information is to be extracted. # Result: # The contents of the "ast.h" header file are written to standard output. # Notes: # - This script is specific to the AST library and contains some knowledge # of the input file contents. # History: # 10-JAN-2005 (DSB): # Added second argument (mode) to the mkdir invocation which creates # the temporary directory. # 2-MAR-2006 (DSB): # Check for "config.h" as well as # 6-JAN-2010 (DSB): # Add work-around for GCC 4.4.2 problem - the pre-processor seesm to simply # throw away backslshes that escape newlines in the input header file. Reported # by Bryan Irby at GSFC. # 27-JUL-2011 (DSB): # Include the process ID in the name of the temporary directory and # file, so that simultaneous invocations of this script do not trample # all over each other. #- ( $#ARGV >= 0 ) || Usage(); # Test whether we need to include config.h in the result. $need_config_h = 0; # Location of source files (makefile variable $(srcdir)). # This is most typically '.', but can be different. $srcdir = '.'; while ( $ARGV[0] =~ /^-/ ) { if ( $ARGV[0] eq '-s' ) { shift @ARGV; ( $#ARGV >= 0 ) || Usage(); $srcdir = $ARGV[0]; shift @ARGV; } else { Usage(); } } # Create a scratch directory. $tmpdir="/tmp/makeh-$$.tmp"; unless ( -d $tmpdir && -w $tmpdir ) { if ( -e $tmpdir ) { die "Temp $tmpdir exists, but is unwritable or is not a directory\n"; } mkdir $tmpdir, 0777 || die "Failed to create temporary directory $tmpdir\n"; } # Open each input file. foreach $file ( @ARGV ) { protect_copy_file( $file ); } # Open a pipe to a script (in the current directory) which runs the C # preprocessor and direct its output to a scratch file. open( CC, "| ./ast_cpp >/tmp/ast-$$.h" ) || die "Can't open pipe to C preprocessor (cpp)"; if ( $need_config_h ) { # Include this directory's config.h, unescaped, in the output. We # need to pay attention to the values in this file, but don't want # them unexpanded in the final ast.h. chomp($cwd = `pwd`); print(CC "#include \"$cwd/config.h\"\n"); } # Before including each file, write an underlined heading in the form of # C comments (with comment characters suitably protected so that they will # be passed unchanged by cpp). foreach $file ( @ARGV ) { $comment = $file; $comment =~ s|^.*/||; $comment =~ s|.h$||; print( CC "/_* " . $comment . ". *_/\n" ); $comment =~ s/./=/g; print( CC "/_* " . $comment . "= *_/\n" ); # Write #include "xxx.h" lines to cpp so that it includes (and # preprocesses) each of the temporary files created above in turn. $tmp_file = $file; $tmp_file =~ s|^.*/||; printf(CC "#include \"%s/%s\"\n", $tmpdir, $tmp_file); }; # Close the pipe to cpp. close( CC ) || die "C preprocessor (cpp) error"; # Remove the temporary directory and the files it contains. print( stderr `rm -r $tmpdir` ); # Write the output preamble. print( '#if !defined(AST_INCLUDED) #define AST_INCLUDED /* *+ * Name: * ast.h * Purpose: * Define the public C interface to the AST library. * Language: * ANSI C * Type of Module: * C header file. * Description: * This file defines the public C interface to the AST library. It contains * all the type definitions, function prototypes, macro definitions, etc. * needed to use the library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either * version 3 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General * License along with this program. If not, see * . * Authors: * DSB: D.S. Berry (STARLINK) * RFWS: R.F. Warren-Smith (STARLINK) * {enter_new_authors_here} * History: * ' ); # Add the current date at this point. ( $sec, $min, $hour, $mday, $mon, $year ) = localtime; print( $mday, '-', ( 'JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC' )[ $mon ], '-', ( $year > 95 ? 1900 : 2000 ) + $year ); print( ' (makeh): * Original version, generated automatically from the internal header * files by the "makeh" script. * {enter_changes_here} *- */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif ' ); # Open the scratch file created above and read it. $space = 0; open( TEMP, " ) { # Remove the underscores from the protected lines and macros. s/^_#include(\s)/#include$1/; s/^_#define(\s)/#define$1/; s/___LINE__/__LINE__/g; s/___FILE__/__FILE__/g; # Also un-protect protected comments. s|/_\*|/*|g; s|\*_/|*/|g; # Convert multiple blank lines (cpp creates lots of these) into single blank # lines. if ( /^\s*$/ ) { $space = 1; } else { # Remove additional unwanted lines that cpp creates. if ( ! /^# \d+/ ) { if ( $space ) { print( "\n" ) }; $space = 0; # Output the lines we want to keep. print; } } } # Write closing output lines. print( ' #endif ' ); # Close and remove the scratch file. close( TEMP ); unlink "/tmp/ast-$$.h"; sub protect_copy_file { my $file = shift; open( INCLUDE, "$srcdir/$file" ) || die "Can't open input file " . $srcdir/$file; # Inicate we have no deferred text to write out. $total = ""; # Open an output file with the same name in the temporary directory. $tmp_file = $file; $tmp_file =~ s|^.*/||; open( TEMP, ">$tmpdir/$tmp_file" ); # Read the input file and detect "#include <...>" lines, extracting the name # of the header file being included. line: while ( ) { # Omit any config.h includes, and note that we saw this if (/^\s*\#\s*include\s+/ || /^\s*\#\s*include\s+"config.h"/) { $need_config_h = 1; next line; } if ( ( $header ) = /^\#include\s+<(.+)>/ ) { # If this system header file has already been included, ignore it and go on to # the next input line. next line if $done{ $header }++; # Otherwise, protect the #include with an underscore to prevent the file # actually being included. s/^/_/; } # Also protect "#define ..." lines, to prevent macro substitution being # performed by the C preprocessor. Do not do this to lines of the form # "#define XXX_INCLUDED" because these are still needed to determine which # AST header files get included. if ( /^\#define\s/ ) { if ( ! /^\#define\s+\w*_INCLUDED/ ) { s/^/_/ }; } # Similarly add underscores to protect standard C macros. s/__LINE__/___LINE__/g; s/__FILE__/___FILE__/g; # Some pre-processors (e.g. GCC 4.4.2) seem to simply throw away trailing # backslashes used to concatenate consecutive lines, producing two # independent lines in the output rather than one. This completely fouls # up the resulting header file. To avoid this, we concatenate such lines # explicitly, before writing them out to the temporary output file. # If the current line ends with an escaped newline, remove the escape # character and newline, and concatenate it with any previously deferred # lines. if( /^(.*)\\\s*$/ ) { $total .= $1; # If the current line does not end with an escaped newline, concatenate it # with any previously deferred lines, and write the total string out. Then # reset the total string to indicate we have no deferred text. } else { $total .= $_; print TEMP $total; $total = ""; } } # Close each file when done. close( INCLUDE ); close( TEMP ); } sub Usage { print STDERR "$0 [-s srcdir] file...\n"; exit (1); }