+my $arglen = 200;
+
+sub get_command_and_cmdline($)
+{
+ my ($file, $args) = split /\s+/, $_[0], 2;
+
+ my $full = $file;
+ $full .= " $args" if defined $args;
+ $full =~ s/"/\\"/g;
+
+ if (length($full) > $arglen) {
+ print "$.: \"$full\" too long...\n";
+ exit 1;
+ }
+
+ ($file, $full);
+}
+
+sub error($)
+{
+ print STDERR shift;
+ exit(1);
+}
+
+sub handle_line($)
+{
+ my $r = shift;
+
+ if ($r =~ /^((perl|glob|shell):\s+)/)
+ {
+ substr $r, 0, length($1), "";
+
+ if ($2 eq 'perl')
+ {
+ my @m = eval $r;
+ die "perl: ".$@ if $@;
+ return @m;
+ }
+ elsif ($2 eq 'shell')
+ {
+ my @m = split /\n/, `$r`;
+ error "$mod_file:$.: Shell command failed\n" if $?;
+ return @m;
+ }
+ elsif ($2 eq 'glob')
+ {
+ return ( glob $r );
+ }
+ else
+ {
+ die "should not happen";
+ }
+ }
+
+ return ( $r );
+}
+
+sub handle_line_first($)
+{
+ return (handle_line(shift))[0];
+}
+
+sub readin_config($)
+{
+ my ($mod_file) = @_;
+
+ my @fs_fds;
+ my @fs_filenames;
+ my @mod_files_for_include;
+ my $fd;
+ my @contents;
+ my %file_to_id;
+ my %id_to_file;
+ my $file_id_cur = 0;
+
+ push @mod_files_for_include, $mod_file;
+
+ while (1)
+ {
+ if (@mod_files_for_include)
+ {
+ my $f = shift @mod_files_for_include;
+
+ if (grep { /^$f$/ } @fs_filenames)
+ {
+ print STDERR "$mod_file:$.: Warning: $f already included, skipping.\n";
+ next;
+ }
+
+ push @fs_filenames, $mod_file;
+ push @fs_fds, $fd;
+
+ undef $fd;
+ $mod_file = $f;
+ open($fd, $f) || error "Cannot open '$f': $!\n";
+
+ $id_to_file{$file_id_cur} = $f;
+ $file_to_id{$f} = $file_id_cur++;
+ }
+
+ while (<$fd>)
+ {
+ chomp;
+ s/#.*$//;
+ s/^\s*//;
+ next if /^$/;
+
+ my ($cmd, $remaining) = split /\s+/, $_, 2;
+ $cmd = lc($cmd);
+
+ if ($cmd eq 'include')
+ {
+ my @f = handle_line($remaining);
+ foreach my $f (@f)
+ {
+ my $abs;
+ if ($f =~ /^\//)
+ {
+ $abs = $f;
+ }
+ else
+ {
+ my @tmp = split /\/+/, $mod_file;
+ $tmp[@tmp - 1] = $f;
+ $abs = join('/', @tmp);
+ }
+ unshift @mod_files_for_include, glob $abs;
+ }
+
+ last;
+ }
+
+ push @contents, [ $file_to_id{$mod_file}, $., $_ ];
+ }
+
+ unless (defined $_)
+ {
+ close $fd;
+
+ $fd = pop @fs_fds;
+ $mod_file = pop @fs_filenames;
+
+ last unless defined $fd;
+ }
+ }
+
+
+ if (0)
+ {
+ print "$id_to_file{$$_[0]}($$_[0]):$$_[1]: $$_[2]\n" foreach (@contents);
+ }
+
+ return (
+ contents => [ @contents ],
+ file_to_id => { %file_to_id },
+ id_to_file => { %id_to_file },
+ );
+}
+