* changed Description of the Softphone Module
[mnemosyne.git] / mnemosyne.pl
blob84dc6a926d21f86862bc406035b1af7745474b8a
1 #!/usr/bin/perl
2 # --- T2-COPYRIGHT-NOTE-BEGIN ---
3 # This copyright note is auto-generated by ./scripts/Create-CopyPatch.
4 #
5 # T2 SDE: target/mnemosyne/mnemosyne.pl
6 # Copyright (C) 2004 - 2006 The T2 SDE Project
7 #
8 # More information can be found in the files COPYING and README.
9 #
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; version 2 of the License. A copy of the
13 # GNU General Public License can be found in the file COPYING.
14 # --- T2-COPYRIGHT-NOTE-END ---
16 use warnings;
17 use strict;
18 use IPC::Open2;
20 use constant {ALL => 0, ASK => 1, CHOICE => 2 };
21 %::FOLDER=();
22 %::MODULE=();
24 sub scandir {
25 my ($pkgseldir,$prefix) = @_;
26 my %current=('location', $pkgseldir, 'var', "CFGTEMP_$prefix");
28 # $current{desc,var} for sub-pkgsel dirs
29 if ($pkgseldir ne $::ROOT) {
30 my ($relative,$dirvar,$dirname);
31 $_ = $pkgseldir;
32 $relative = (m/^$::ROOT\/(.*)/i)[0];
34 $dirvar = "CFGTEMP_$prefix\_$relative";
35 $dirvar =~ tr,a-z\/ ,A-Z__,;
37 $dirname=$relative;
38 $dirname=~ s/.*\///g;
40 $current{desc} = $dirname;
41 $current{var} = $dirvar;
44 # make this folder global
45 $::FOLDER{$current{var}} = \%current;
48 # make scandir recursive
49 my @children;
50 opendir(my $DIR, $pkgseldir);
51 foreach( grep { ! /^\./ } sort readdir($DIR) ) {
52 $_ = "$pkgseldir/$_";
53 if ( -d $_ ) {
54 my $subdir = scandir($_,$prefix);
55 push @children,$subdir;
56 } else {
57 my $module=scanmodule($_,$prefix,$current{var});
58 if ($module) {
59 push @children,$module unless grep(/^$module$/,@children);
63 closedir $DIR;
64 $current{children} = \@children;
65 return $current{var};
70 sub scanmodule {
71 my ($file,$prefix,$folder)=@_;
72 my (%current,$FILE);
74 # this defines dir,key,option and kind acording to the following format.
75 # $dir/[$prio-]$var[$option].$kind
76 do {
77 my ($dir,$key,$option,$kind);
78 m/^(.*)\/(\d+-)?([^\.]*).?([^\.]*)?\.([^\/\.]*)/i;
79 ($dir,$key,$option,$kind) = ($1,$3,$4,$5);
81 if ($kind eq 'choice') { $current{kind} = CHOICE; $current{option} = $option; }
82 elsif ($kind eq 'all') { $current{kind} = ALL; }
83 elsif ($kind eq 'ask') { $current{kind} = ASK; }
84 else { return; }
86 $current{location} = $dir;
87 $current{key} = $key;
88 $current{file} = $file;
90 } for $file;
92 open($FILE,'<',$file);
93 while(<$FILE>) {
94 if (/^#[^#: ]+: /) {
95 my ($field,$value) = m/^#([^#: ]+): (.*)$/i;
96 if ($field eq 'Description') {
97 $current{desc} = $value;
98 } elsif ($field eq 'Variable') {
99 $current{var} = $value;
100 } elsif ($field eq 'Default') {
101 $current{default} = $value;
102 } elsif ($field eq 'Forced') {
103 $current{forced} = $value;
104 } elsif ($field eq 'Imply') {
105 $current{imply} = $value;
106 } elsif ($field eq 'Dependencies') {
107 $current{deps} = $value;
108 # } else {
109 # print "$file:$field:$value.\n";
113 close($FILE);
115 # var name
116 $current{var} = uc $current{key}
117 unless exists $current{var};
118 $current{var} = "SDECFG_$prefix\_" . $current{var}
119 unless $current{var} =~ /^SDECFG_$prefix\_/;
121 # for choices, we use $option instead of $key as description
122 ($current{desc} = $current{option}) =~ s/_/ /g
123 if exists $current{option} && ! exists $current{desc};
124 ($current{desc} = $current{key}) =~ s/_/ /g
125 unless exists $current{desc};
127 # dependencies
128 # NOTE: don't use spaces on the pkgsel file, only to delimite different dependencies
129 if (exists $current{deps}) {
130 my @deps;
131 for ( split (/\s+/,$current{deps}) ) {
132 $_="SDECFG_$prefix\_$_" unless /^SDECFG/;
134 if (/=/) {
135 m/(.*?)(==|!=|=)(.*)/i;
136 $_="\"\$$1\" $2 $3";
137 } else {
138 $_="\"\$$_\" == 1";
141 push @deps,$_;
143 $current{deps} = \@deps;
146 # forced modules
147 if (exists $current{forced}) {
148 my @forced;
149 for ( split (/\s+/,$current{forced}) ) {
150 $_="SDECFG_$prefix\_$_" unless /^SDECFG/;
152 $_="$_=1" unless /=/;
153 push @forced,$_;
155 $current{forced} = \@forced;
158 # implied options
159 if (exists $current{imply}) {
160 my @imply = split (/\s+/,$current{imply});
161 $current{imply} = \@imply;
164 # make this module global
165 if ( $current{kind} == CHOICE ) {
167 # prepare the option for this choice
168 my %option;
169 for ('desc','forced','imply','deps','option','file') {
170 $option{$_}=$current{$_} if exists $current{$_};
173 if ( exists $::MODULE{$current{var}} ) {
174 push @{ $::MODULE{$current{var}}{options} },\%option;
175 } else {
176 # prepare and add this choice module
177 my @options = (\%option);
179 $::MODULE{$current{var}} = {
180 'kind', CHOICE,
181 'options', \@options,
184 for ('key','location','var') {
185 $::MODULE{$current{var}}{$_}=$current{$_}
186 if exists $current{$_};
190 } else {
191 $::MODULE{$current{var}} = {};
192 for ('key','location','var','desc','forced','deps','file','kind') {
193 $::MODULE{$current{var}}{$_}=$current{$_}
194 if exists $current{$_};
198 # default value
199 $::MODULE{$current{var}}{folder} = $folder;
200 $::MODULE{$current{var}}{default} = $current{default}
201 if exists $current{default};
203 return $current{var};
206 sub process_modules {
207 my ($READ,$WRITE,$pid);
208 my $i=0;
210 $pid = open2($READ, $WRITE, 'tsort');
211 # prepare topographic modules map
212 for my $module (values %::MODULE) {
213 my $related;
215 if ($module->{kind} == CHOICE) {
216 for (@{ $module->{options} }) {
217 my $option = $_;
218 for (@{exists $option->{deps} ? $option->{deps} : []} ) {
219 my $dep = (m/"\$([^"]+)"/i)[0];
220 print $WRITE "$dep $module->{var}\n";
221 $related=1;
223 for (@{exists $option->{forced} ? $option->{forced} : []} ) {
224 my $forced = (m/([^"]+)=/i)[0];
225 print $WRITE "$module->{var} $forced\n";
226 $related=1;
229 } else {
230 for (@{exists $module->{deps} ? $module->{deps} : []} ) {
231 my $dep = (m/"\$([^"]+)"/i)[0];
232 print $WRITE "$dep $module->{var}\n";
233 $related=1;
235 for (@{exists $module->{forced} ? $module->{forced} : []} ) {
236 my $forced = (m/([^"]+)=/i)[0];
237 print $WRITE "$module->{var} $forced\n";
238 $related=1;
242 if (! $related) {
243 print $WRITE "$module->{var} $module->{var}\n";
247 close($WRITE);
249 # and populate the sorted list
250 my @sorted;
251 while(<$READ>) {
252 if (/(.*)\n/) { push @sorted, $1; }
255 waitpid $pid,0;
256 die if $?;
258 # and remember the sorted list
259 $::MODULES=\@sorted;
262 sub process_folders {
263 my ($READ,$WRITE,$pid);
265 $pid = open2($READ, $WRITE, 'tsort | tac');
266 # prepare topographic modules map
267 for my $folder (values %::FOLDER) {
268 for ( exists $folder->{children} ? grep(!/^SDECFG/, @{$folder->{children}}) : [] ) {
269 print $WRITE "$folder->{var} $_\n";
272 close($WRITE);
274 # and populate the sorted list
275 my @sorted;
276 while(<$READ>) {
277 if (/(.*)\n/) { push @sorted, $1; }
280 waitpid $pid,0;
281 die if $?;
283 # and remember the sorted list
284 $::FOLDERS=\@sorted;
287 sub render_widgets_folder {
288 my ($folder,$offset) = @_;
289 for (@{$folder->{children}}) {
290 if (/^CFGTEMP/) {
291 my $subfolder=$::FOLDER{$_};
292 print "\n${offset}# $_\n${offset}#\n";
294 # opening
295 print "${offset}if [ \"\$$subfolder->{var}\" == 1 ]; then\n";
296 print "${offset}\tcomment '-- $subfolder->{desc}'\n";
297 print "${offset}\tblock_begin 2\n";
298 print "${offset}fi\n";
300 render_widgets_folder($::FOLDER{$_},"$offset\t");
302 # closing
303 print "${offset}if [ \"\$$subfolder->{var}\" == 1 ]; then\n";
304 print "${offset}\tblock_end\n";
305 print "${offset}fi\n";
306 } else {
307 my $module=$::MODULE{$_};
308 my $var=$module->{var};
309 my $conffile="$module->{location}/$module->{key}.conf"
310 if -f "$module->{location}/$module->{key}.conf";
312 print "${offset}# $var\n";
314 if ($module->{kind} == CHOICE) {
315 # CHOICE
316 my $tmpvar = "CFGTEMP_$1" if $var =~ m/^SDECFG_(.*)/i;
317 my $listvar = "$tmpvar\_LIST";
318 my $defaultvar = "$tmpvar\_DEFAULT";
320 print "${offset}if \[ -n \"\$$var\" \]; then\n";
321 print "${offset}\tchoice $var \$$defaultvar \$$listvar\n";
322 print "${offset}\t. $conffile\n" if $conffile;
323 print "${offset}fi\n";
325 } elsif ($module->{kind} == ASK) {
326 # ASK
327 my $default=0;
328 $default = $module->{default} if exists $module->{default};
330 print "${offset}if \[ -n \"\$$var\" \]; then\n";
331 print "${offset}\tbool '$module->{desc}' $module->{var} $default\n";
332 print "${offset}\t\[ \"\$$var\" == 1 \] && . $conffile\n" if $conffile;
333 print "${offset}fi\n";
334 } elsif ($conffile) {
335 # ALL, only if $conffile
336 print "${offset}if \[ -n \"\$$var\" \]; then\n";
337 print "${offset}\t. $conffile\n" if $conffile;
338 print "${offset}fi\n";
343 sub render_widgets {
344 open(my $FILE,'>',$_[0]);
345 my $root="CFGTEMP_$_[1]";
347 select $FILE;
348 render_widgets_folder($::FOLDER{$root},'');
349 select STDOUT;
350 close($FILE);
353 sub pkgsel_parse {
354 my ($action,$patternlist) = @_;
355 if ($action eq 'X' or $action eq 'x' ) {
356 $action = '$1="X"';
357 } elsif ($action eq 'O' or $action eq 'o') {
358 $action = '$1="O"';
359 } elsif ($action eq '-') {
360 $action = 'next';
361 } else {
362 $action = '{ exit; }';
365 my ($address,$first,$others)= ('','( ','&& ');
367 for (split(/\s+/,$patternlist)) {
368 if (! $address and $_ eq '!') {
369 $address = '! ';
370 $others = '|| $4"/"$5 ~';
371 } else {
372 $_="\*/$_" unless /\//;
373 s,[^a-zA-Z0-9_/\*+\.-],,g;
374 s,([/\.\+]),\\$1,g;
375 s,\*,[^/]*,g;
376 next unless $_;
377 $address = "$address$first";
378 $address = "$address / $_ /";
379 $first = "$others";
382 =for nobody
383 [ "$pattern" ] || continue
384 address="$address$first"
385 address="$address / $pattern /"
386 first=" $others"
388 =cut
391 print "\techo '$address ) { $action; }'\n";
392 return 1;
395 sub render_awkgen {
396 open(my $OUTPUT,'>',$_[0]);
397 my $root="CFGTEMP_$_[1]";
399 select $OUTPUT;
401 # initially change packages $4 and $5 to be able to correctly match repo based.
402 print "echo '{'\n";
403 print "echo '\trepo=\$4 ;'\n";
404 print "echo '\tpkg=\$5 ;'\n";
405 print "echo '\t\$5 = \$4 \"/\" \$5 ;'\n";
406 print "echo '\t\$4 = \"placeholder\" ;'\n";
407 print "echo '}'\n";
409 render_awkgen_folder($::FOLDER{$root});
411 # ... restore $4 and $5, and print the resulting line
412 print "echo '\n{'\n";
413 print "echo '\t\$4=repo ;'\n";
414 print "echo '\t\$5=pkg ;'\n";
415 print "echo '\tprint ;'\n";
416 print "echo '}'\n";
418 select STDOUT;
419 close($OUTPUT);
422 sub render_awkgen_folder {
423 my ($folder) = @_;
424 for (@{$folder->{children}}) {
425 if (/^CFGTEMP/) {
426 render_awkgen_folder($::FOLDER{$_});
427 } else {
428 my $module=$::MODULE{$_};
429 if ($module->{kind} == CHOICE) {
430 my %options;
432 # the list of options
433 for (@{ $module->{options} }) {
434 my $option = $_;
435 my @array=("\"\$$module->{var}\" == $_->{option}");
436 $options{$_->{option}} = \@array;
438 # and their implyed options
439 for (@{ $module->{options} }) {
440 my $option = $_;
441 for (@{exists $option->{imply}? $option->{imply} : [] }) {
442 push @{$options{$_}},
443 "\"\$$module->{var}\" == $option->{option}";
447 print "\n";
448 # and finally, render.
449 for (@{ $module->{options} }) {
450 print "if [ " . join(' -o ',@{ $options{ $_->{option} }}). " ]; then\n";
452 open(my $FILE,'<',$_->{file});
453 my $hasrules=0;
454 while(<$FILE>) {
455 next if /^#/;
456 next if /^\s*$/;
457 pkgsel_parse($1,$2) if m/^([^\s]+)\s+(.*)\s*\n?$/i;
458 $hasrules=1;
460 close($FILE);
461 print "\ttrue\n" unless $hasrules;
463 print "fi\n";
465 } else {
466 print "\nif [ \"\$$module->{var}\" == 1 ]; then\n";
467 open(my $FILE,'<',$module->{file});
468 my $hasrules=0;
469 while(<$FILE>) {
470 next if /^#/;
471 next if /^\s*$/;
472 pkgsel_parse($1,$2) if m/^([^\s]+)\s+(.*)\s*\n?$/i;
473 $hasrules=1;
475 close($FILE);
476 print "\ttrue\n" unless $hasrules;
477 print "fi\n";
483 sub render_rules_module {
484 my ($module,$offset) = @_;
485 my $var = $module->{var};
487 if ($module->{kind} == CHOICE) {
488 my $tmpvar = "CFGTEMP_$1" if $var =~ m/^SDECFG_(.*)/i;
489 my $listvar = "$tmpvar\_LIST";
490 my $defaultvar = "$tmpvar\_DEFAULT";
491 my $default = "undefined";
492 my $forcer;
494 $default = $module->{default} if exists $module->{default};
496 # initialize the list
497 print "${offset}$listvar=\n";
499 print "${offset}$defaultvar=$default\n";
500 print "${offset}\[ -n \"\$$var\" \] || $var=$default\n\n";
502 for ( @{ $module->{options} } ) {
503 my $option = $_;
504 (my $desc = $option->{desc}) =~ s/ /_/g;
506 # has something to force?
507 if (exists $option->{forced}) { $forcer = 1; }
509 if (exists $option->{deps}) {
510 print "${offset}if [ " .
511 join(' -a ', @{ $option->{deps} } ) .
512 " ]; then\n";
513 print "${offset}\t$listvar=\"\$$listvar $option->{option} $desc\"\n";
514 print "${offset}fi\n";
515 } else {
516 print "${offset}$listvar=\"\$$listvar $option->{option} $desc\"\n";
520 # enable the folder display
521 print "${offset}if \[ -n \"\$$listvar\" \]; then\n";
522 print "${offset}\t$module->{folder}=1\n";
523 print "${offset}else\n";
524 print "${offset}\tunset $module->{var}\n";
525 print "${offset}fi\n";
527 # has something to force?
528 if ($forcer) {
529 print "\n${offset}case \"\$$var\" in\n";
530 for ( @{ $module->{options} } ) {
531 my $option = $_;
532 if (exists $option->{forced}) {
533 print "${offset}\t$option->{option})\n";
534 for ( @{ $option->{forced} } ) {
535 print "$offset\t\t$_\n";
536 print "$offset\t\tSDECFGSET_$1\n" if $_ =~ m/^SDECFG_(.*)/i;
538 print "${offset}\t\t;;\n";
541 print "${offset}esac\n";
544 # printref($var,$module,$offset);
545 } elsif ($module->{kind} == ASK) {
546 my $default=0;
547 $default = $module->{default} if exists $module->{default};
549 #enable the folder display
550 print "$offset$module->{folder}=1\n";
552 # and set the default value if none is set.
553 print "$offset\[ -n \"\$$var\" \] || $var=$default\n";
555 # if enabled, append pkgsel and force the forced
557 if (exists $module->{forced}) {
558 print "\n${offset}if [ \"\$$var\" == 1 ]; then\n";
559 for ( @{ $module->{forced} } ) {
560 print "$offset\t$_\n";
561 print "$offset\tSDECFGSET_$1\n" if $_ =~ m/^SDECFG_(.*)/i;
563 print $offset."fi\n";
565 } else {
566 # just enable the feature
567 print "$offset$var=1\n";
569 # forced list doesn't make sense for {kind} == ALL
573 sub render_rules_nomodule {
574 my ($module,$offset) = @_;
575 my $var = $module->{var};
577 # unset the choice list, and the var
578 if ($module->{kind} == CHOICE) {
579 my $listvar = "CFGTEMP_$1_LIST" if $var =~ m/^SDECFG_(.*)/i;
580 print "${offset}unset $listvar\n";
582 print "${offset}unset SDECFGSET_$1\n" if $var =~ m/^SDECFG_(.*)/i;
583 print "${offset}unset $var\n";
586 sub render_rules {
587 open(my $FILE,'>',$_[0]);
588 my $root="CFGTEMP_$_[1]";
589 select $FILE;
591 # clean folder enablers
592 print "#\n# folder enablers\n#\n\n";
593 for (@$::FOLDERS) { print "$_=\n" unless /^$root$/; }
595 # pkgsel list
596 for (@$::MODULES) {
597 my $module = $::MODULE{$_};
598 print "\n#\n# $module->{var} ("
599 . ($module->{kind} == ALL ? "ALL" : ($module->{kind} == ASK ? "ASK" : "CHOICE" ) )
600 . ")\n#\n";
603 if (exists $module->{deps}) {
604 print "if [ " . join(' -a ', @{ $module->{deps} } ) . " ]; then\n";
605 render_rules_module($module,"\t");
606 print "else\n";
607 render_rules_nomodule($module,"\t");
608 print "fi\n";
609 } else {
610 render_rules_module($module,"");
614 print "\n#\n# enable folder with enabled subfolders\n#\n";
615 for (@$::FOLDERS) {
616 my $folder = $::FOLDER{$_};
617 my @subdirs = grep(/^CFGTEMP/,@{$folder->{children}});
618 if ( @subdirs ) {
619 print "if [ -n \"\$".join('$', @subdirs )."\" ]; then\n";
620 print "\t$folder->{var}=1\n";
621 print "fi\n";
625 select STDOUT;
626 close($FILE);
629 # print the content of a hash
630 sub printref {
631 my ($name,$ref,$offset) = @_;
632 my $typeof = ref($ref);
634 print "$offset$name:";
635 if ($typeof eq '') {
636 print " '$ref'\n";
637 } elsif ($typeof eq 'HASH') {
638 print "\n";
639 for (sort keys %{ $ref }) {
640 printref($_,$ref->{$_},"$offset\t");
642 } elsif ($typeof eq 'ARRAY') {
643 my $i=0;
644 print "\n";
645 for (@{ $ref }) {
646 printref("[$i]",$_,"$offset\t");
647 $i++;
649 } else {
650 print " -> $typeof\n";
654 if ($#ARGV != 4) {
655 print "Usage mnemosyne.pl: <pkgseldir> <prefix> <configfile> <rulesfile> <awkgenerator>\n";
656 exit (1);
659 $| = 1;
661 $::ROOT=$ARGV[0];
662 scandir($ARGV[0],$ARGV[1]);
663 process_modules();
664 process_folders();
665 render_rules($ARGV[3],$ARGV[1]);
666 render_widgets($ARGV[2],$ARGV[1]);
667 render_awkgen($ARGV[4],$ARGV[1]);