#!/usr/bin/perl # --- T2-COPYRIGHT-NOTE-BEGIN --- # This copyright note is auto-generated by ./scripts/Create-CopyPatch. # # T2 SDE: target/mnemosyne2/mnemosyne.pl # Copyright (C) 2004 - 2005 The T2 SDE Project # # More information can be found in the files COPYING and README. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License. A copy of the # GNU General Public License can be found in the file COPYING. # --- T2-COPYRIGHT-NOTE-END --- use warnings; use strict; use IPC::Open2; use constant {ALL => 0, ASK => 1, CHOICE => 2 }; %::FOLDER=(); %::MODULE=(); sub scandir { my ($pkgseldir,$prefix) = @_; my %current=('location', $pkgseldir, 'var', "CFGTEMP_$prefix"); # $current{desc,var} for sub-pkgsel dirs if ($pkgseldir ne $::ROOT) { my ($relative,$dirvar,$dirname); $_ = $pkgseldir; $relative = (m/^$::ROOT\/(.*)/i)[0]; $dirvar = "CFGTEMP_$prefix\_$relative"; $dirvar =~ tr,a-z\/ ,A-Z__,; $dirname=$relative; $dirname=~ s/.*\///g; $current{desc} = $dirname; $current{var} = $dirvar; } # make this folder global $::FOLDER{$current{var}} = \%current; { # make scandir recursive my @children; opendir(my $DIR, $pkgseldir); foreach( grep { ! /^\./ } sort readdir($DIR) ) { $_ = "$pkgseldir/$_"; if ( -d $_ ) { my $subdir = scandir($_,$prefix); push @children,$subdir; } else { my $module=scanmodule($_,$prefix,$current{var}); if ($module) { push @children,$module unless grep(/^$module$/,@children); } } } closedir $DIR; $current{children} = \@children; return $current{var}; } } sub scanmodule { my ($file,$prefix,$folder)=@_; my (%current,$FILE); # this defines dir,key,option and kind acording to the following format. # $dir/[$prio-]$var[$option].$kind do { my ($dir,$key,$option,$kind); m/^(.*)\/(\d+-)?([^\.]*).?([^\.]*)?\.([^\/\.]*)/i; ($dir,$key,$option,$kind) = ($1,$3,$4,$5); if ($kind eq 'choice') { $current{kind} = CHOICE; $current{option} = $option; } elsif ($kind eq 'all') { $current{kind} = ALL; } elsif ($kind eq 'ask') { $current{kind} = ASK; } else { return; } $current{location} = $dir; $current{key} = $key; $current{file} = $file; } for $file; open($FILE,'<',$file); while(<$FILE>) { if (/^#[^#: ]+: /) { my ($field,$value) = m/^#([^#: ]+): (.*)$/i; if ($field eq 'Description') { $current{desc} = $value; } elsif ($field eq 'Variable') { $current{var} = $value; } elsif ($field eq 'Default') { $current{default} = $value; } elsif ($field eq 'Forced') { $current{forced} = $value; } elsif ($field eq 'Imply') { $current{imply} = $value; } elsif ($field eq 'Dependencies') { $current{deps} = $value; # } else { # print "$file:$field:$value.\n"; } } } close($FILE); # var name $current{var} = uc $current{key} unless exists $current{var}; $current{var} = "SDECFG_$prefix\_" . $current{var} unless $current{var} =~ /^SDECFG_$prefix\_/; # for choices, we use $option instead of $key as description ($current{desc} = $current{option}) =~ s/_/ /g if exists $current{option} && ! exists $current{desc}; ($current{desc} = $current{key}) =~ s/_/ /g unless exists $current{desc}; # dependencies # NOTE: don't use spaces on the pkgsel file, only to delimite different dependencies if (exists $current{deps}) { my @deps; for ( split (/\s+/,$current{deps}) ) { $_="SDECFG_$prefix\_$_" unless /^SDECFG/; if (/=/) { m/(.*?)(==|!=|=)(.*)/i; $_="\"\$$1\" $2 $3"; } else { $_="\"\$$_\" == 1"; } push @deps,$_; } $current{deps} = \@deps; } # forced modules if (exists $current{forced}) { my @forced; for ( split (/\s+/,$current{forced}) ) { $_="SDECFG_$prefix\_$_" unless /^SDECFG/; $_="$_=1" unless /=/; push @forced,$_; } $current{forced} = \@forced; } # implied options if (exists $current{imply}) { my @imply = split (/\s+/,$current{imply}); $current{imply} = \@imply; } # make this module global if ( $current{kind} == CHOICE ) { # prepare the option for this choice my %option; for ('desc','forced','imply','deps','option','file') { $option{$_}=$current{$_} if exists $current{$_}; } if ( exists $::MODULE{$current{var}} ) { push @{ $::MODULE{$current{var}}{options} },\%option; } else { # prepare and add this choice module my @options = (\%option); $::MODULE{$current{var}} = { 'kind', CHOICE, 'options', \@options, }; for ('key','location','var') { $::MODULE{$current{var}}{$_}=$current{$_} if exists $current{$_}; } } } else { $::MODULE{$current{var}} = {}; for ('key','location','var','desc','forced','deps','file','kind') { $::MODULE{$current{var}}{$_}=$current{$_} if exists $current{$_}; } } # default value $::MODULE{$current{var}}{folder} = $folder; $::MODULE{$current{var}}{default} = $current{default} if exists $current{default}; return $current{var}; } sub process_modules { my ($READ,$WRITE,$pid); my $i=0; $pid = open2($READ, $WRITE, 'tsort'); # prepare topographic modules map for my $module (values %::MODULE) { my $related; if ($module->{kind} == CHOICE) { for (@{ $module->{options} }) { my $option = $_; for (@{exists $option->{deps} ? $option->{deps} : []} ) { my $dep = (m/"\$([^"]+)"/i)[0]; print $WRITE "$dep $module->{var}\n"; $related=1; } for (@{exists $option->{forced} ? $option->{forced} : []} ) { my $forced = (m/([^"]+)=/i)[0]; print $WRITE "$module->{var} $forced\n"; $related=1; } } } else { for (@{exists $module->{deps} ? $module->{deps} : []} ) { my $dep = (m/"\$([^"]+)"/i)[0]; print $WRITE "$dep $module->{var}\n"; $related=1; } for (@{exists $module->{forced} ? $module->{forced} : []} ) { my $forced = (m/([^"]+)=/i)[0]; print $WRITE "$module->{var} $forced\n"; $related=1; } } if (! $related) { print $WRITE "$module->{var}\n"; $i++; } } print $WRITE "IGNORE_TOKEN\n" unless ( $i % 2 == 0); close($WRITE); # and populate the sorted list my @sorted; while(<$READ>) { if (! /^IGNORE_TOKEN/ && /(.*)\n/) { push @sorted, $1; } } waitpid $pid,0; die if $?; # and remember the sorted list $::MODULES=\@sorted; } sub process_folders { my ($READ,$WRITE,$pid); $pid = open2($READ, $WRITE, 'tsort | tac'); # prepare topographic modules map for my $folder (values %::FOLDER) { for ( exists $folder->{children} ? grep(!/^SDECFG/, @{$folder->{children}}) : [] ) { print $WRITE "$folder->{var} $_\n"; } } close($WRITE); # and populate the sorted list my @sorted; while(<$READ>) { if (/(.*)\n/) { push @sorted, $1; } } waitpid $pid,0; die if $?; # and remember the sorted list $::FOLDERS=\@sorted; } sub render_widgets_folder { my ($folder,$offset) = @_; for (@{$folder->{children}}) { if (/^CFGTEMP/) { my $subfolder=$::FOLDER{$_}; print "\n${offset}# $_\n${offset}#\n"; # opening print "${offset}if [ \"\$$subfolder->{var}\" == 1 ]; then\n"; print "${offset}\tcomment '-- $subfolder->{desc}'\n"; print "${offset}\tblock_begin 2\n"; print "${offset}fi\n"; render_widgets_folder($::FOLDER{$_},"$offset\t"); # closing print "${offset}if [ \"\$$subfolder->{var}\" == 1 ]; then\n"; print "${offset}\tblock_end\n"; print "${offset}fi\n"; } else { my $module=$::MODULE{$_}; my $var=$module->{var}; my $conffile="$module->{location}/$module->{key}.conf" if -f "$module->{location}/$module->{key}.conf"; print "${offset}# $var\n"; if ($module->{kind} == CHOICE) { # CHOICE my $tmpvar = "CFGTEMP_$1" if $var =~ m/^SDECFG_(.*)/i; my $listvar = "$tmpvar\_LIST"; my $defaultvar = "$tmpvar\_DEFAULT"; print "${offset}if \[ -n \"\$$var\" \]; then\n"; print "${offset}\tchoice $var \$$defaultvar \$$listvar\n"; print "${offset}\t. $conffile\n" if $conffile; print "${offset}fi\n"; } elsif ($module->{kind} == ASK) { # ASK my $default=0; $default = $module->{default} if exists $module->{default}; print "${offset}if \[ -n \"\$$var\" \]; then\n"; print "${offset}\tbool '$module->{desc}' $module->{var} $default\n"; print "${offset}\t\[ \"\$$var\" == 1 \] && . $conffile\n" if $conffile; print "${offset}fi\n"; } elsif ($conffile) { # ALL, only if $conffile print "${offset}if \[ -n \"\$$var\" \]; then\n"; print "${offset}\t. $conffile\n" if $conffile; print "${offset}fi\n"; } } } } sub render_widgets { open(my $FILE,'>',$_[0]); my $root="CFGTEMP_$_[1]"; select $FILE; render_widgets_folder($::FOLDER{$root},''); select STDOUT; close($FILE); } sub pkgsel_parse { my ($action,$patternlist) = @_; if ($action eq 'X' or $action eq 'x' ) { $action = '$1="X"'; } elsif ($action eq 'O' or $action eq 'o') { $action = '$1="O"'; } elsif ($action eq '-') { $action = 'next'; } else { $action = '{ exit; }'; } my ($address,$first,$others)= ('','( ','&& '); for (split(/\s+/,$patternlist)) { if (! $address and $_ eq '!') { $address = '! '; $others = '|| $4"/"$5 ~'; } else { $_="\*/$_" unless /\//; s,[^a-zA-Z0-9_/\*+\.-],,g; s,([/\.\+]),\\$1,g; s,\*,[^/]*,g; next unless $_; $address = "$address$first"; $address = "$address / $_ /"; $first = "$others"; } =for nobody [ "$pattern" ] || continue address="$address$first" address="$address / $pattern /" first=" $others" =cut } print "\techo '$address ) { $action; }'\n"; return 1; } sub render_awkgen { open(my $OUTPUT,'>',$_[0]); my $root="CFGTEMP_$_[1]"; select $OUTPUT; # initially change packages $4 and $5 to be able to correctly match repo based. print "echo '{'\n"; print "echo '\trepo=\$4 ;'\n"; print "echo '\tpkg=\$5 ;'\n"; print "echo '\t\$5 = \$4 \"/\" \$5 ;'\n"; print "echo '\t\$4 = \"placeholder\" ;'\n"; print "echo '}'\n"; render_awkgen_folder($::FOLDER{$root}); # ... restore $4 and $5, and print the resulting line print "echo '\n{'\n"; print "echo '\t\$4=repo ;'\n"; print "echo '\t\$5=pkg ;'\n"; print "echo '\tprint ;'\n"; print "echo '}'\n"; select STDOUT; close($OUTPUT); } sub render_awkgen_folder { my ($folder) = @_; for (@{$folder->{children}}) { if (/^CFGTEMP/) { render_awkgen_folder($::FOLDER{$_}); } else { my $module=$::MODULE{$_}; if ($module->{kind} == CHOICE) { my %options; # the list of options for (@{ $module->{options} }) { my $option = $_; my @array=("\"\$$module->{var}\" == $_->{option}"); $options{$_->{option}} = \@array; } # and their implyed options for (@{ $module->{options} }) { my $option = $_; for (@{exists $option->{imply}? $option->{imply} : [] }) { push @{$options{$_}}, "\"\$$module->{var}\" == $option->{option}"; } } print "\n"; # and finally, render. for (@{ $module->{options} }) { print "if [ " . join(' -o ',@{ $options{ $_->{option} }}). " ]; then\n"; open(my $FILE,'<',$_->{file}); my $hasrules=0; while(<$FILE>) { next if /^#/; next if /^\s*$/; pkgsel_parse($1,$2) if m/^([^\s]+)\s+(.*)\s*\n?$/i; $hasrules=1; } close($FILE); print "\ttrue\n" unless $hasrules; print "fi\n"; } } else { print "\nif [ \"\$$module->{var}\" == 1 ]; then\n"; open(my $FILE,'<',$module->{file}); my $hasrules=0; while(<$FILE>) { next if /^#/; next if /^\s*$/; pkgsel_parse($1,$2) if m/^([^\s]+)\s+(.*)\s*\n?$/i; $hasrules=1; } close($FILE); print "\ttrue\n" unless $hasrules; print "fi\n"; } } } } sub render_rules_module { my ($module,$offset) = @_; my $var = $module->{var}; if ($module->{kind} == CHOICE) { my $tmpvar = "CFGTEMP_$1" if $var =~ m/^SDECFG_(.*)/i; my $listvar = "$tmpvar\_LIST"; my $defaultvar = "$tmpvar\_DEFAULT"; my $default = "undefined"; my $forcer; $default = $module->{default} if exists $module->{default}; # initialize the list print "${offset}$listvar=\n"; print "${offset}$defaultvar=$default\n"; print "${offset}\[ -n \"\$$var\" \] || $var=$default\n\n"; for ( @{ $module->{options} } ) { my $option = $_; (my $desc = $option->{desc}) =~ s/ /_/g; # has something to force? if (exists $option->{forced}) { $forcer = 1; } if (exists $option->{deps}) { print "${offset}if [ " . join(' -a ', @{ $option->{deps} } ) . " ]; then\n"; print "${offset}\t$listvar=\"\$$listvar $option->{option} $desc\"\n"; print "${offset}fi\n"; } else { print "${offset}$listvar=\"\$$listvar $option->{option} $desc\"\n"; } } # enable the folder display print "${offset}if \[ -n \"\$$listvar\" \]; then\n"; print "${offset}\t$module->{folder}=1\n"; print "${offset}else\n"; print "${offset}\tunset $module->{var}\n"; print "${offset}fi\n"; # has something to force? if ($forcer) { print "\n${offset}case \"\$$var\" in\n"; for ( @{ $module->{options} } ) { my $option = $_; if (exists $option->{forced}) { print "${offset}\t$option->{option})\n"; for ( @{ $option->{forced} } ) { print "$offset\t\t$_\n"; print "$offset\t\tSDECFGSET_$1\n" if $_ =~ m/^SDECFG_(.*)/i; } print "${offset}\t\t;;\n"; } } print "${offset}esac\n"; } # printref($var,$module,$offset); } elsif ($module->{kind} == ASK) { my $default=0; $default = $module->{default} if exists $module->{default}; #enable the folder display print "$offset$module->{folder}=1\n"; # and set the default value if none is set. print "$offset\[ -n \"\$$var\" \] || $var=$default\n"; # if enabled, append pkgsel and force the forced if (exists $module->{forced}) { print "\n${offset}if [ \"\$$var\" == 1 ]; then\n"; for ( @{ $module->{forced} } ) { print "$offset\t$_\n"; print "$offset\tSDECFGSET_$1\n" if $_ =~ m/^SDECFG_(.*)/i; } print $offset."fi\n"; } } else { # just enable the feature print "$offset$var=1\n"; # forced list doesn't make sense for {kind} == ALL } } sub render_rules_nomodule { my ($module,$offset) = @_; my $var = $module->{var}; # unset the choice list, and the var if ($module->{kind} == CHOICE) { my $listvar = "CFGTEMP_$1_LIST" if $var =~ m/^SDECFG_(.*)/i; print "${offset}unset $listvar\n"; } print "${offset}unset SDECFGSET_$1\n" if $var =~ m/^SDECFG_(.*)/i; print "${offset}unset $var\n"; } sub render_rules { open(my $FILE,'>',$_[0]); my $root="CFGTEMP_$_[1]"; select $FILE; # clean folder enablers print "#\n# folder enablers\n#\n\n"; for (@$::FOLDERS) { print "$_=\n" unless /^$root$/; } # pkgsel list for (@$::MODULES) { my $module = $::MODULE{$_}; print "\n#\n# $module->{var} (" . ($module->{kind} == ALL ? "ALL" : ($module->{kind} == ASK ? "ASK" : "CHOICE" ) ) . ")\n#\n"; if (exists $module->{deps}) { print "if [ " . join(' -a ', @{ $module->{deps} } ) . " ]; then\n"; render_rules_module($module,"\t"); print "else\n"; render_rules_nomodule($module,"\t"); print "fi\n"; } else { render_rules_module($module,""); } } print "\n#\n# enable folder with enabled subfolders\n#\n"; for (@$::FOLDERS) { my $folder = $::FOLDER{$_}; my @subdirs = grep(/^CFGTEMP/,@{$folder->{children}}); if ( @subdirs ) { print "if [ -n \"\$".join('$', @subdirs )."\" ]; then\n"; print "\t$folder->{var}=1\n"; print "fi\n"; } } select STDOUT; close($FILE); } # print the content of a hash sub printref { my ($name,$ref,$offset) = @_; my $typeof = ref($ref); print "$offset$name:"; if ($typeof eq '') { print " '$ref'\n"; } elsif ($typeof eq 'HASH') { print "\n"; for (sort keys %{ $ref }) { printref($_,$ref->{$_},"$offset\t"); } } elsif ($typeof eq 'ARRAY') { my $i=0; print "\n"; for (@{ $ref }) { printref("[$i]",$_,"$offset\t"); $i++; } } else { print " -> $typeof\n"; } } if ($#ARGV != 4) { print "Usage mnemosyne.pl: \n"; exit (1); } $| = 1; $::ROOT=$ARGV[0]; scandir($ARGV[0],$ARGV[1]); process_modules(); process_folders(); render_rules($ARGV[3],$ARGV[1]); render_widgets($ARGV[2],$ARGV[1]); render_awkgen($ARGV[4],$ARGV[1]);