#!/usr/bin/perl
eval 'exec perl -S $0 "$@"'
if $runnning_under_some_shell;
# $Id: jmake.SH,v 3.0.1.6 1995/09/25 09:08:01 ram Exp $
#
# Copyright (c) 1991-1993, Raphael Manfredi
#
# You may redistribute only under the terms of the Artistic Licence,
# as specified in the README file that comes with the distribution.
# You may reuse parts of this distribution only within the terms of
# that same Artistic Licence; a copy of which may be found at the root
# of the source tree for dist 3.0.
#
# $Log: jmake.SH,v $
# Revision 3.0.1.6 1995/09/25 09:08:01 ram
# patch59: will now force macro definitions to the left
#
# Revision 3.0.1.5 1995/07/25 13:34:47 ram
# patch56: all error messages are now prefixed with the program name
#
# Revision 3.0.1.4 1995/03/21 08:45:27 ram
# patch52: now invokes cpp through new fixcpp script
# patch52: first pass now skips cpp comments alltogether
#
# Revision 3.0.1.3 1994/10/29 15:47:01 ram
# patch36: added various escapes in strings for perl5 support
#
# Revision 3.0.1.2 1993/08/24 12:12:50 ram
# patch3: privlib dir was ~name expanded in the wrong place
#
# Revision 3.0.1.1 1993/08/19 06:42:13 ram
# patch1: leading config.sh searching was not aborting properly
#
# Revision 3.0 1993/08/18 12:04:17 ram
# Baseline for dist 3.0 netwide release.
#
$dir = '/u/vieraat/vieraat/jhi/Perl/lib/dist/files';
$cpp = '/usr/bin/cpp';
$version = '3.0';
$patchlevel = '70';
($me = $0) =~ s|.*/(.*)|$1|;
$dir = &tilda_expand($dir); # ~name expansion
$file = $dir . '/Jmake.tmpl';
$cpp_opt = "-I. "; # For Jmakefile, which is local
while ($ARGV[0] =~ /^-/) {
$_ = shift;
last if /--/;
$cpp_opt .= "$_ ";
}
$cpp_opt .= "-I$dir";
# Thank you HP-UX for having a cpp that blindly strips trailing backslashes
# in the text. Run through cpp by using the fixcpp script...
open(CPP, "$dir/fixcpp $cpp_opt $file |");
while (<CPP>) {
# Record defined symbols in Jmakefile. We won't catch symbols
# in conditional commands, but that's ok, I hope.
if ($in_symbol) {
$val = $_;
$in_symbol = 0 if !($val =~ s/\\\s*$//); # Last line
if ($val = /^\|expand/) { # Found an expand command
$in_symbol = 0; # Stop gathering value
$val .= "void::x"; # Stop any incomplete escape sequence
}
chop($val);
$Makesym{$current_symbol} .= $val;
} elsif (/^\s*(\w+)\s*=(.*)/ && !$in_symbol) {
# Found a makefile's macro declaration
$val = $2;
$current_symbol = $1;
if ($val =~ s/\\\s*$//) { # Remove final '\'
$in_symbol = 1; # This is a continuation line
}
$Makesym{$current_symbol} = $val;
push(@Order, $current_symbol); # Keep track of order
}
# Protect RCS keyword Id or Header from normal substitution
s/\$(Id|Header|Log)/\$X-$1/;
# Restore possibly escaped C comments
s|/#\*|/*|g;
s|\*#/|*/|g;
# Remove all ^^ (null space character)
s|\^\^||g;
# Restore escaped ^^ sequence
s|\^\\\^|^^|g;
next if /^#\s+\d+/; # Skip cpp commments
s/^;#/#/;
s/@#\s?/\n/g; # Kept for backward compatibility
s/@!\s?/\n/g;
s/@@\s?/\n\t/g;
$* = 1;
# A '\r' is added to all lines, in order to let 'split' keep them
# As lines ending with '\' won't fit in the next regular
# expression (why ?), we have to treat that special case separately
s/\n$/\r\n/g;
s/\\\s*$/\\\r/g; # Remove spaces after final '\' and add '\r'
$* = 0;
@macro = split(/\n/);
for ($i = 0; $i <= $#macro; $i++) {
chop($_ = $macro[$i]); # Remove final '\r'
s/\s+$//g; # Remove possible useless spaces
if (/^TOP\s*=\s*(\S+)/) { # Get the top from generated file
$top = $1;
}
if (s/^\s*>//) { # '>' means "symbol wanted"
$symbol{$_} = 1;
} elsif (s/^\s*\+//) { # '+' means "initialization section"
if (s/^\+(\w+)//) { # '++' means add to variable list
$added{$1} .= $_;
} else { # A single '+' means "add as is".
push(@init, $_);
}
} elsif (s/^\|//) { # Command for us
if (/suffix\s+(\S+)/) { # Add suffix
push(@suffix, $1) unless $seen{$1};
$seen{$1} = 1;
} elsif (s/^rule://) { # Add building rule
s/^\s(\s*\S+)/\t$1/; # Make sure leading tab is there
push(@rule, $_);
} elsif (/^skip/) { # Unconditional skip... funny!
push(@makefile, "|$_"); # Skip handled in pass 2
} elsif (/^expand/) {
push(@makefile, "|$_"); # Expand handled in pass 2
} elsif (/^once\s+(\S+)/) { # Once handled in pass 1
if ($Once{$1}++) { # Symbol already seen -- skip
for (; $i <= $#macro; $i++) {
last if $macro[$i] =~/^-once/;
}
warn("$me: -once not found for $1")
unless $macro[$i] =~/^-once/;
}
} else {
print "$me: Warning: unknown command $_\n";
}
} else {
next if /^-once/; # Control statement removed
push(@makefile, $_);
}
}
}
close CPP;
@key = keys(%added);
$last_was_blank = 1; # To avoid blank line at the top of the file
$symbol{'INIT'} = 1 if ($#init >= 0 || $#key >=0); # Initializations
$symbol{'SUFFIX'} = 1 if ($#suffix >= 0 || $#rule >=0); # Rules or suffixes
$symbol{'TOP'} = 1 if $top eq '.'; # If imake invoked for the top
open(MAKEFILE, ">Makefile.SH");
# We have to use for instead of foreach to handle 'skip' easily
line: for ($i = 0; $i <= $#makefile; $i++) {
$_ = $makefile[$i];
next if /^-skip|-expand/; # They might have made a mistake
s/<TAG>/[jmake $version PL$patchlevel]/;
if (/^\s*$/) {
next if ($last_was_blank);
$last_was_blank = 1;
} else {
$last_was_blank = 0;
}
# Lines starting with ?SYMBOL: (resp. %SYMBOL:) are to be processed
# only if SYMBOL is defined (resp. undefined).
# Apply in sequence
while (/^\s*\?|\s*%/) {
if (s/^\s*\?(\w+)://) { # Wanted symbol ?
next line unless $symbol{$1};
} elsif (s/^\s*%(\w+)://) { # Unwanted symbol ?
next line if $symbol{$1};
} else {
print "$me: Warning: missing ':' in $_\n";
last;
}
}
# We wish to make sure there is a leading tab if the line starts with
# a space to prevent problems later on. However, variable definitions
# might want to be aligned on the '=' (imake style). Not all make
# may be able to cope with those though, so they are left justified
# again.
s/^\s/\t/ unless /^\s+\w+\s+=/; # Make sure leading tab is there
s/^\s+(\w+\s+=)/$1/; # Left justify variable definition
s/^;#/#/; # Comments in Jmakefile
if (s/^\|//) { # Command for us
if (/^skip/) { # Skip until -skip
for (; $i <= $#makefile; $i++) {
last if $makefile[$i] =~ /^-skip/;
}
} elsif (s/^expand//) {
do init_expand($_); # Initializes data structures
$i++; # Skip expand line
undef @Expand; # Storage for expanded lines
$pattern = ''; # Assume no pattern
for (; $i <= $#makefile; $i++) {
$_ = $makefile[$i];
if (s/^-expand//) { # Reached end of expansion
if (s/^\s*(.*)/$1/) { # Expand followed by a pattern
$pattern = $_; # Get pattern to be removed
}
last;
}
s/^\s/\t/; # Make sure leading tab is there
push(@Expand, $_); # Line to be expanded
}
do expand($pattern); # Expand all lines in buffer
} else {
print "$me: Warning: unknown command $_\n";
}
} elsif (/^INIT/) { # Initialization section
# All the initializations are put in the variable substitution
# section of the Makefile.SH. Therefore, we have to protect all
# the '$' signs that are not followed by an alphanumeric character.
foreach (@init) {
# Dumps core sometimes with perl 4.0 PL10
# do protect_dollars(*_);
$_ = do protect_dollars($_);
do print_makefile($_);
}
foreach (@key) { # @key set earlier to keys(%added)
$_ .= " = " . $added{$_};
# Dumps core sometimes with perl 4.0 PL10
# do protect_dollars(*_);
$_ = do protect_dollars($_);
do print_makefile($_);
}
} elsif (/^SUFFIX/) { # Suffixes/Rules section
# Rules and suffixes are put in the variable substitution
# section of the Makefile.SH. Therefore, we have to protect all
# the '$' signs that are not followed by an alphanumeric character.
if ($#suffix >= 0) {
print MAKEFILE ".SUFFIXES:";
foreach (@suffix) {
# Dumps core sometimes with perl 4.0 PL10
# do protect_dollars(*_);
$_ = do protect_dollars($_);
print MAKEFILE " $_";
}
print MAKEFILE "\n\n";
}
foreach (@rule) {
# Dumps core sometimes with perl 4.0 PL10
# do protect_dollars(*_);
$_ = do protect_dollars($_);
print MAKEFILE "$_\n";
}
} else {
do print_makefile($_);
}
}
close MAKEFILE;
sub protect_dollars {
# Dumps core sometimes with perl 4.0 PL10
# local(*_) = shift(@_);
s/\\\$/\\=/g; # Protect already escaped '$'
s/(\$\W)/\\$1/g; # Escape unprotected '$'
s/\\=/\\\$/g; # Restore escaped '$'
$_; # Because perl dumps core... :-(
}
# Initializes data structures for expansion. If we detect Makefile
# macro in the 'expand' line (the argument), then we write a small
# makefile that will do the substitution for us -- I'm lazy today :-)
sub init_expand {
local($_) = shift(@_);
undef %Vars; # Reset array of variables
$Vars_len = 0; # Number of "symbols" in first expanded
if (/\$\(\w+\)/) { # If at least one macro
local($make) = "/tmp/mkjm$$";
open(MAKE, ">$make") || die "$me: can't create $make: $!\n";
do gen_variables(); # Generates already computed variables
foreach $var (@Order) { # Print each in order we found them
print MAKE "$var = $Makesym{$var}\n" if !$Gvars{$var};
}
print MAKE "all:\n\t\@echo '$_'\n";
close MAKE;
chop($_ = `make -f $make all`);
unlink($make);
}
while (s/^\s*(\w+)!([^!]*)!//) {
$Vars{$1} = $2;
# Record only length for _first_ expanded symbol
$Vars_len = split(/\s\s*/, $2) unless $Vars_len;
}
}
# Expand lines in the @Expand array. The argument is a pattern which is to
# be removed from the last chunk of expanded lines.
# For each symbol s, !s is replaced by the next item, and !s:p=q does the
# same after having replaced the pattern 'p' by pattern 'q' in the item.
# Spaces are NOT allowed in 'p' or 'q'. Substitution is done once (no /g).
sub expand {
local($pattern) = shift; # To-be-removed pattern for last chunk
local($_);
local($sub);
local($i);
local(@expands);
for ($i = 0; $i < $Vars_len; $i++) {
foreach $line (@Expand) {
$_ = $line; # Don't modify elements in array
foreach $sym (keys %Vars) {
@expands = split(/\s\s*/, $Vars{$sym});
$sub = $expands[$i];
$sub =~ s/\/\///g; # // is a void value
while (s/!${sym}:([^\s]*)=([^\s]*)/,x##x,/) {
# Replacing item is altered by some pattern
local($p) = $1;
local($q) = $2;
local($subq) = $sub;
eval "\$subq =~ s=${p}=${q}=";
s/,x##x,/${subq}/;
}
s/!${sym}/${sub}/g;
}
# Protect substitution in an 'eval' in case of error
eval "s/${pattern}\$//" if $pattern && $i == ($Vars_len - 1);
do print_makefile($_);
}
}
}
# Prints its argument in MAKEFILE and records it also in Generated
sub print_makefile {
local($_) = shift(@_); # Line to be printed
print MAKEFILE "$_\n";
push(@Generated, "$_\n");
}
# Generates in MAKE file all the generated variable we have so far for
# final Makefile. This is mainly intended to allow expansion of variables
# which are already defined with an expand.
sub gen_variables {
undef %Gvars; # Reset already generated variables
local ($in_symbol) = 0; # True when in variable (Makefile's macro)
foreach (@Generated) {
if ($in_symbol) {
if (/^\s*(\w+)\s*=(.*)/) { # Missed the end of previous macro
$in_symbol = 0;
$Gvars{$1} = 1; # Definition of variable seen
$in_symbol = 1 if (/\\\s*$/); # There is a final '\'
print MAKE "void::\n"; # Cut incomplete esc sequence
} else {
$in_symbol = 0 if !(/\\\s*$/); # Last line
}
print MAKE;
} elsif (/^\s*(\w+)\s*=(.*)/ && !$in_symbol) {
# Found a makefile's macro declaration
$Gvars{$1} = 1; # Definition of variable seen
$in_symbol = 1 if (/\\\s*$/); # There is a final '\'
print MAKE;
}
}
print MAKE "void::\n"; # Cut incomplete escape sequence
}
# Perform ~name expansion ala ksh...
# (banish csh from your vocabulary ;-)
sub tilda_expand {
local($path) = @_;
return $path unless $path =~ /^~/;
$path =~ s:^~([^/]+):(getpwnam($1))[$[+7]:e; # ~name
$path =~ s:^~:$ENV{'HOME'} || (getpwuid($<))[$[+7]:e; # ~
$path;
}