3 # ************************************************************
4 # Description : Base class for workspace and project creators
5 # Author : Chad Elliott
6 # Create Date : 5/13/2002
7 # ************************************************************
9 # ************************************************************
11 # ************************************************************
22 # ************************************************************
24 # ************************************************************
26 ## Constants for use throughout the project
27 use constant cplusplus
=> 'cplusplus';
28 use constant csharp
=> 'csharp';
29 use constant java
=> 'java';
30 use constant vb
=> 'vb';
31 use constant website
=> 'website';
33 ## The default language for MPC
34 my $deflang = 'cplusplus';
36 ## A map of all of the allowed languages. The 'website' value
37 ## is not here because it isn't really a language. It is used
38 ## as a language internally by some project types though.
39 my %languages = (cplusplus
=> 1,
45 my $assign_key = 'assign';
46 my $gassign_key = 'global_assign';
47 my %non_convert = ('prebuild' => 1,
51 my @statekeys = ('global', 'include', 'template', 'ti',
52 'dynamic', 'static', 'relative', 'addtemp',
53 'addproj', 'progress', 'toplevel', 'baseprojs',
54 'features', 'feature_file', 'hierarchy',
55 'name_modifier', 'apply_project', 'into', 'use_env',
56 'expand_vars', 'language',
60 my $onVMS = DirectoryManager
::onVMS
();
62 # ************************************************************
64 # ************************************************************
67 my($class, $global, $inc, $template, $ti, $dynamic, $static, $relative, $addtemp, $addproj, $progress, $toplevel, $baseprojs, $feature, $features, $hierarchy, $nmodifier, $applypj, $into, $language, $use_env, $expandvars, $type) = @_;
68 my $self = Parser
::new
($class, $inc);
70 $self->{'relative'} = $relative;
71 $self->{'template'} = $template;
73 $self->{'global'} = $global;
74 $self->{'grammar_type'} = $type;
75 $self->{'type_check'} = $type . '_defined';
76 $self->{'global_read'} = 0;
77 $self->{'current_input'} = '';
78 $self->{'progress'} = $progress;
79 $self->{'addtemp'} = $addtemp;
80 $self->{'addproj'} = $addproj;
81 $self->{'toplevel'} = $toplevel;
82 $self->{'files_written'} = {};
83 $self->{'real_fwritten'} = [];
84 $self->{'reading_global'} = 0;
85 $self->{$gassign_key} = {};
86 $self->{$assign_key} = {};
87 $self->{'baseprojs'} = $baseprojs;
88 $self->{'dynamic'} = $dynamic;
89 $self->{'static'} = $static;
90 $self->{'feature_file'} = $feature;
91 $self->{'features'} = $features;
92 $self->{'hierarchy'} = $hierarchy;
93 $self->{'name_modifier'} = $nmodifier;
94 $self->{'apply_project'} = $applypj;
95 $self->{'into'} = $into;
96 $self->{'language'} = defined $language ?
$language : $deflang;
97 $self->{'use_env'} = $use_env;
98 $self->{'expand_vars'} = $expandvars;
99 $self->{'convert_slashes'} = $self->convert_slashes();
100 $self->{'requires_forward_slashes'} = $self->requires_forward_slashes();
101 $self->{'case_tolerant'} = $self->case_insensitive();
107 sub preprocess_line
{
108 my($self, $fh, $line) = @_;
110 $line = $self->strip_line($line);
111 while ($line =~ /\\$/) {
112 $line =~ s/\s*\\$/ /;
113 my $next = $fh->getline();
114 $line .= $self->strip_line($next) if (defined $next);
120 sub generate_default_input
{
123 $error) = $self->parse_line(undef, "$self->{'grammar_type'} {");
125 ## Parse the finish line if there was no error
126 ($status, $error) = $self->parse_line(undef, '}') if ($status);
128 ## Display the error if there was one
129 $self->error($error) if (!$status);
136 my($self, $input) = @_;
138 ## Save the last line number so we can put it back later
139 my $oline = $self->get_line_number();
141 ## Read the input file
142 my($status, $errorString) = $self->read_file($input);
145 $self->error($errorString,
146 "$input: line " . $self->get_line_number() . ':');
148 elsif ($self->{$self->{'type_check'}}) {
149 ## If we are at the end of the file and the type we are looking at
150 ## is still defined, then we have an error
151 $self->error("Did not " .
152 "find the end of the $self->{'grammar_type'}",
153 "$input: line " . $self->get_line_number() . ':');
156 $self->set_line_number($oline);
163 my($self, $input) = @_;
166 ## Reset the files_written hash array between processing each file
167 $self->{'files_written'} = {};
168 $self->{'real_fwritten'} = [];
170 ## Allow subclasses to reset values before
171 ## each call to generate().
172 $self->reset_values();
174 ## Read the global configuration file
175 if (!$self->{'global_read'}) {
176 $status = $self->read_global_configuration();
177 $self->{'global_read'} = 1;
181 $self->{'current_input'} = $input;
183 ## An empty input file name says that we
184 ## should generate a default input file and use that
186 $status = $self->generate_default_input();
189 $status = $self->parse_file($input);
197 # split an inheritance list like ": a,b, c" into components
199 my($parents, $errorStringRef, $statusRef) = @_;
200 if (defined $parents) {
201 $parents =~ s/^:\s*//;
202 $parents =~ s/\s+$//;
203 my @parents = split(/\s*,\s*/, $parents);
204 if (!defined $parents[0]) {
205 ## The : was used, but no parents followed. This
207 $$errorStringRef = 'No parents listed';
217 my($self, $line) = @_;
220 my $type = $self->{'grammar_type'};
224 ## Each regexp that looks for the '{' looks for it at the
225 ## end of the line. It is purposely this way to decrease
226 ## the amount of extra lines in each file. This
227 ## allows for the most compact file as human readably
232 elsif ($line =~ /^$type\s*(\([^\)]+\))?\s*(:.*)?\s*{$/) {
235 if ($self->{$self->{'type_check'}}) {
236 $errorString = "Did not find the end of the $type";
240 $parents = parse_parents
($parents, \
$errorString, \
$status);
241 push(@values, $type, $name, $parents);
244 elsif ($line =~ /^}$/) {
245 if ($self->{$self->{'type_check'}}) {
246 push(@values, $type, $line);
249 $errorString = "Did not find the beginning of the $type";
253 elsif ($line =~ /^(feature)\s*\(([^\)]+)\)\s*(:.*)?\s*{$/) {
257 my @names = split(/\s*,\s*/, $name);
258 $parents = parse_parents
($parents, \
$errorString, \
$status);
259 push(@values, $type, \
@names, $parents);
261 elsif (!$self->{$self->{'type_check'}}) {
262 $errorString = "No $type was defined";
265 elsif ($self->parse_assignment($line, \
@values)) {
266 ## If this returns true, then we've found an assignment
268 elsif ($line =~ /^(\w+)\s*(\([^\)]+\))?\s*(:.*)?\s*{$/) {
278 $name = $self->get_default_component_name();
280 $parents = parse_parents
($parents, \
$errorString, \
$status);
281 push(@values, 'component', $comp, $name, $parents);
284 $errorString = "Unrecognized line: $line";
288 return $status, $errorString, @values;
293 my($self, $fh, $name, $type, $validNames, $flags, $elseflags) = @_;
295 my $errorString = "Unable to process $name";
297 ## Make sure $flags has a hash map reference
298 $flags = {} if (!defined $flags);
301 my $line = $self->preprocess_line($fh, $_);
305 elsif ($line =~ /^}$/) {
306 ($status, $errorString) = $self->handle_scoped_end($type, $flags);
309 elsif ($line =~ /^}\s*else\s*{$/) {
310 if (defined $elseflags) {
311 ## From here on out anything after this goes into the $elseflags
315 ## We need to adjust the type also. If there was a type
316 ## then the first part of the clause was used. If there was
317 ## no type, then the first part was ignored and the second
318 ## part will be used.
323 $type = $self->get_default_component_name();
328 $errorString = 'An else is not allowed in this context';
334 if (defined $validNames && $self->parse_assignment($line, \
@values)) {
335 if (defined $$validNames{$values[1]}) {
336 ## If $type is not defined, we don't even need to bother with
337 ## processing the assignment as we will be throwing the value
340 if ($values[0] == 0) {
341 $self->process_assignment($values[1], $values[2], $flags);
343 elsif ($values[0] == 1) {
344 $self->process_assignment_add($values[1], $values[2], $flags);
346 elsif ($values[0] == -1) {
347 $self->process_assignment_sub($values[1], $values[2], $flags);
353 $errorString) = $self->handle_unknown_assignment($type,
359 ($status, $errorString) = $self->handle_scoped_unknown($fh,
367 return $status, $errorString;
373 return $self->mpc_basename($self->getcwd());
377 sub generate_default_file_list
{
378 my($self, $dir, $exclude, $fileexc, $recurse) = @_;
379 my $dh = new FileHandle
();
382 if (opendir($dh, $dir)) {
383 my $prefix = ($dir ne '.' ?
"$dir/" : '');
384 my $have_exc = (defined $$exclude[0]);
386 foreach my $file (grep(!/^\.\.?$/,
387 ($onVMS ?
map {$_ =~ s/\.dir$//; $_} readdir($dh) :
389 ## Prefix each file name with the directory only if it's not '.'
390 my $full = $prefix . $file;
393 foreach my $exc (@
$exclude) {
403 $$fileexc = 1 if (defined $fileexc);
406 if ($recurse && -d
$full) {
408 $self->generate_default_file_list($full, $exclude,
409 $fileexc, $recurse));
412 # Strip out ^ symbols
413 $full =~ s/\^//g if ($onVMS);
420 if ($self->sort_files()) {
421 @files = sort { $self->file_sorter($a, $b) } @files;
430 sub transform_file_name
{
431 my($self, $name) = @_;
433 $name =~ s/[\s\-]/_/g;
439 my($self, $file) = @_;
440 return (defined $all_written{$self->getcwd() . '/' . $file});
444 sub add_file_written
{
445 my($self, $file) = @_;
448 if (defined $self->{'files_written'}->{$key}) {
449 $self->warning("$self->{'grammar_type'} $file " .
450 ($self->{'case_tolerant'} ?
451 "has been overwritten." :
452 "of differing case has been processed."));
455 $self->{'files_written'}->{$key} = $file;
456 push(@
{$self->{'real_fwritten'}}, $file);
459 $all_written{$self->getcwd() . '/' . $file} = 1;
463 sub extension_recursive_input_list
{
464 my($self, $dir, $exclude, $ext) = @_;
465 my $fh = new FileHandle
();
468 if (opendir($fh, $dir)) {
469 my $prefix = ($dir ne '.' ?
"$dir/" : '');
471 foreach my $file (grep(!/^\.\.?$/,
472 ($onVMS ?
map {$_ =~ s/\.dir$//; $_} readdir($fh) :
474 my $full = $prefix . $file;
476 ## Check for command line exclusions
477 if (defined $$exclude[0]) {
478 foreach my $exc (@
$exclude) {
486 ## If we are not skipping this directory or file, then check it out
492 push(@files, $self->extension_recursive_input_list($full,
496 elsif ($full =~ /$ext$/) {
507 sub recursive_directory_list
{
508 my($self, $dir, $exclude) = @_;
509 my $directories = '';
510 my $fh = new FileHandle
();
512 if (opendir($fh, $dir)) {
513 my $prefix = ($dir ne '.' ?
"$dir/" : '');
515 if (defined $$exclude[0]) {
516 foreach my $exc (@
$exclude) {
527 $directories .= ' ' . $dir;
530 foreach my $file (grep(!/^\.\.?$/,
531 ($onVMS ?
map {$_ =~ s/\.dir$//; $_} readdir($fh) :
533 my $full = $prefix . $file;
535 if ($file eq '.svn' || $file eq 'CVS') {
539 ## Check for command line exclusions
540 if (defined $$exclude[0]) {
541 foreach my $exc (@
$exclude) {
550 ## If we are not skipping this directory or file, then check it out
556 $directories .= $self->recursive_directory_list($full, $exclude);
567 sub modify_assignment_value
{
568 my($self, $name, $value) = @_;
570 if ($self->{'convert_slashes'} &&
571 index($name, 'flags') == -1 && !defined $non_convert{$name}) {
579 sub get_assignment_hash
{
580 ## NOTE: If anything in this block changes, then you must make the
581 ## same change in process_assignment.
583 return $self->{$self->{'reading_global'} ?
$gassign_key : $assign_key};
587 sub process_assignment
{
588 my($self, $name, $value, $assign) = @_;
590 ## If no hash table was passed in
591 if (!defined $assign) {
592 ## NOTE: If anything in this block changes, then you must make the
593 ## same change in get_assignment_hash.
594 $assign = $self->{$self->{'reading_global'} ?
595 $gassign_key : $assign_key};
598 if (defined $value) {
602 ## Modify the assignment value before saving it
603 $$assign{$name} = $self->modify_assignment_value($name, $value);
606 $$assign{$name} = undef;
612 my($self, $name, $value, $nval, $assign) = @_;
615 if ($self->preserve_assignment_order($name)) {
619 $nval = "$value $nval";
625 $self->process_assignment($name, $nval, $assign, 1);
629 sub process_assignment_add
{
630 my($self, $name, $value, $assign) = @_;
631 my $nval = $self->get_assignment_for_modification($name, $assign);
633 ## Remove all duplicate parts from the value to be added.
634 ## Whether anything gets removed or not is up to the implementation
635 ## of the sub classes.
636 $value = $self->remove_duplicate_addition($name, $value, $nval);
638 ## If there is anything to add, then do so
639 $self->addition_core($name, $value, $nval, $assign) if ($value ne '');
643 sub subtraction_core
{
644 my($self, $name, $value, $nval, $assign) = @_;
650 ## Escape any regular expression special characters
651 $value = $self->escape_regex_special($value);
653 ## If necessary, split the value into an array
654 my $elements = ($value =~ /\s/ ?
$self->create_array($value) : [$value]);
655 for(my $i = 0; $i <= $last; $i++) {
657 ## If we did not find the string to subtract in the original
658 ## value, try again after expanding template variables for
660 $nval = $self->get_assignment_for_modification($name, $assign, 1);
662 for(my $j = 0; $j <= $last; $j++) {
663 ## Try to remove each individual element and then set the new
664 ## value if any of the elements were found in the original value
665 foreach my $elem (@
$elements) {
666 ## First try with quotes, then try again without them
667 my $re = ($j == 0 ?
'"' . $elem . '"' : $elem);
669 if ($nval =~ s/\s+$re\s+/ / || $nval =~ s/\s+$re$// ||
670 $nval =~ s/^$re\s+// || $nval =~ s/^$re$//) {
675 $self->process_assignment($name, $nval, $assign, -1);
685 sub process_assignment_sub
{
686 my($self, $name, $value, $assign) = @_;
687 my $nval = $self->get_assignment_for_modification($name, $assign);
689 ## Remove double quotes if there are any
690 $value =~ s/^\"(.*)\"$/$1/;
692 ## Call to the core function to perform the subtraction. We must also
693 ## pass the value through the assignment modifier to ensure that
694 ## slashes are in the project native format.
695 $self->subtraction_core($name,
696 $self->modify_assignment_value($name, $value),
702 my($self, $names, $def) = @_;
703 my $array = ($names =~ /\s/ ?
$self->create_array($names) : [$names]);
706 foreach my $name (@
$array) {
708 my $pre = $def . '_';
709 my $mid = '_' . $def . '_';
710 my $post = '_' . $def;
712 ## Replace the beginning and end first then the middle
713 $name =~ s/^\*/$pre/;
714 $name =~ s/\*$/$post/;
715 $name =~ s/\*/$mid/g;
717 ## Remove any trailing underscore or any underscore that is followed
718 ## by a space. This value could be a space separated list.
723 ## If any one word is capitalized then capitalize each word
724 if ($name =~ /[A-Z][0-9a-z_]+/) {
726 if ($name =~ /^([a-z])([^_]+)/) {
729 $name =~ s/^[a-z][^_]+/$first$rest/;
731 ## Do subsequent words
732 while($name =~ /(_[a-z])([^_]+)/) {
735 $name =~ s/_[a-z][^_]+/$first$rest/;
740 $names .= $name . ' ';
749 my($self, $obj) = @_;
751 ## Check for various types of data. Those that are not found to be
752 ## types that we need to deep copy are just assigned to new values.
753 ## All others are copied by recursively calling this method.
754 if (UNIVERSAL
::isa
($obj, 'HASH')) {
756 foreach my $key (keys %$obj) {
757 $$new{$key} = $self->clone($$obj{$key});
761 elsif (UNIVERSAL
::isa
($obj, 'ARRAY')) {
763 foreach my $o (@
$obj) {
764 push(@
$new, $self->clone($o));
774 my($self, $selected) = @_;
777 ## Make a deep copy of each state value. That way our array
778 ## references and hash references do not get accidentally modified.
779 foreach my $skey (defined $selected ?
$selected : @statekeys) {
780 if (defined $self->{$skey}) {
781 ## It is necessary to clone each value so that nested complex data
782 ## types do not get unknowingly modified.
783 $state{$skey} = $self->clone($self->{$skey});
792 my($self, $state, $selected) = @_;
794 ## Make a deep copy of each state value. That way our array
795 ## references and hash references do not get accidentally modified.
796 ## It's not necessary to do a recursive deep copy (i.e., use the
797 ## clone() method) because the value coming in will now be owned by
798 ## this object and will not be modified unknowingly.
799 foreach my $skey (defined $selected ?
$selected : @statekeys) {
800 my $old = $self->{$skey};
801 if (defined $state->{$skey} &&
802 UNIVERSAL
::isa
($state->{$skey}, 'ARRAY')) {
803 my @arr = @
{$state->{$skey}};
804 $self->{$skey} = \
@arr;
806 elsif (defined $state->{$skey} &&
807 UNIVERSAL
::isa
($state->{$skey}, 'HASH')) {
808 my %hash = %{$state->{$skey}};
809 $self->{$skey} = \
%hash;
812 $self->{$skey} = $state->{$skey};
814 $self->restore_state_helper($skey, $old, $self->{$skey});
820 return $_[0]->{'global'};
824 sub get_template_override
{
825 return $_[0]->{'template'};
829 sub get_ti_override
{
830 return $_[0]->{'ti'};
835 return $_[0]->{'relative'};
839 sub get_progress_callback
{
840 return $_[0]->{'progress'};
845 return $_[0]->{'addtemp'};
850 return $_[0]->{'addproj'};
855 return $_[0]->{'toplevel'};
860 return $_[0]->{'into'};
865 return $_[0]->{'use_env'};
869 sub get_expand_vars
{
870 return $_[0]->{'expand_vars'};
874 sub get_files_written
{
875 return $_[0]->{'real_fwritten'};
881 my $name = $self->resolve_alias(shift);
884 ## If no hash table was passed in
885 if (!defined $assign) {
886 $assign = $self->{$self->{'reading_global'} ?
887 $gassign_key : $assign_key};
890 return $$assign{$name};
894 sub get_assignment_for_modification
{
895 my($self, $name, $assign, $subtraction) = @_;
896 return $self->get_assignment($name, $assign);
901 return $_[0]->{'baseprojs'};
906 return $_[0]->{'dynamic'};
911 return $_[0]->{'static'};
915 sub get_default_component_name
{
922 return $_[0]->{'features'};
927 return $_[0]->{'hierarchy'};
931 sub get_name_modifier
{
932 return $_[0]->{'name_modifier'};
936 sub get_apply_project
{
937 return $_[0]->{'apply_project'};
942 return $_[0]->{'language'};
948 if (defined $self->{'into'}) {
949 my $outdir = $self->getcwd();
950 my $re = $self->escape_regex_special($self->getstartdir());
953 return $self->{'into'} . $outdir;
961 sub expand_variables
{
962 my($self, $value, $rel, $expand_template, $scope, $expand, $warn) = @_;
963 my $cwd = $self->getcwd();
965 my $forward_slashes = $self->{'convert_slashes'} ||
966 $self->{'requires_forward_slashes'};
968 ## Fix up the value for Windows switch the \\'s to /
969 $cwd =~ s/\\/\//g
if ($forward_slashes);
971 while(substr($value, $start) =~ /(\$\(([^)]+)\))/) {
974 if (defined $$rel{$name}) {
975 my $val = $$rel{$name};
977 $val =~ s/\//\\/g
if ($forward_slashes);
978 substr($value, $start) =~ s/\$\([^)]+\)/$val/;
982 ## Fix up the value for Windows switch the \\'s to /
983 $val =~ s/\\/\//g
if ($forward_slashes);
985 my $icwd = ($self->{'case_tolerant'} ?
lc($cwd) : $cwd);
986 my $ival = ($self->{'case_tolerant'} ?
lc($val) : $val);
987 my $iclen = length($icwd);
988 my $ivlen = length($ival);
990 ## If the relative value contains the current working
991 ## directory plus additional subdirectories, we must pull
992 ## off the additional directories into a temporary where
993 ## it can be put back after the relative replacement is done.
995 if (index($ival, $icwd) == 0 && $iclen != $ivlen &&
996 substr($ival, $iclen, 1) eq '/') {
997 my $diff = $ivlen - $iclen;
998 $append = substr($ival, $iclen);
999 substr($ival, $iclen, $diff) = '';
1003 if (index($icwd, $ival) == 0 &&
1004 ($iclen == $ivlen || substr($icwd, $ivlen, 1) eq '/')) {
1005 my $current = $icwd;
1006 substr($current, 0, $ivlen) = '';
1008 my $dircount = ($current =~ tr/\///);
1009 if ($dircount == 0) {
1013 $ival = '../' x
$dircount;
1016 $ival .= $append if (defined $append);
1018 ## We have to remove the leading ./ if there is one.
1019 ## Otherwise, if this value is used as an exclude value it will
1020 ## not match up correctly.
1023 ## Convert the slashes if necessary
1024 $ival =~ s/\//\\/g
if ($self->{'convert_slashes'});
1025 substr($value, $start) =~ s/\$\([^)]+\)/$ival/;
1028 elsif ($self->convert_all_variables() && $warn) {
1029 ## The user did not choose to expand $() variables directly,
1030 ## but we could not convert it into a relative path. So,
1031 ## instead of leaving it we will expand it. But, we will only
1032 ## get into this section if this is the secondary attempt to
1033 ## replace the variable (indicated by the $warn boolean).
1034 $val =~ s/\//\\/g
if ($self->{'convert_slashes'});
1035 substr($value, $start) =~ s/\$\([^)]+\)/$val/;
1039 my $loc = index(substr($value, $start), $whole);
1040 $start += $loc if ($loc > 0);
1044 elsif ($expand_template ||
1045 $self->expand_variables_from_template_values()) {
1046 my $ti = $self->get_template_input();
1047 my $val = (defined $ti ?
$ti->get_value($name) : undef);
1048 my $sname = (defined $scope ?
$scope . "::$name" : undef);
1049 my $arr = $self->adjust_value([$sname, $name],
1050 (defined $val ?
$val : []));
1051 if (UNIVERSAL
::isa
($arr, 'HASH')) {
1052 $self->warning("$name conflicts with a template variable scope");
1054 elsif (UNIVERSAL
::isa
($arr, 'ARRAY') && defined $$arr[0]) {
1055 $val = $self->modify_assignment_value(lc($name), "@$arr");
1056 substr($value, $start) =~ s/\$\([^)]+\)/$val/;
1058 ## We have replaced the template value, but that template
1059 ## value may contain a $() construct that may need to get
1060 ## replaced too. However, if the name of the template variable
1061 ## is the same as the original $() variable name, we need to
1062 ## leave it alone to avoid looping infinitely.
1063 $whole = '' if ($whole ne $val);
1066 $self->warning("Unable to expand $name.") if ($expand && $warn);
1067 my $loc = index(substr($value, $start), $whole);
1068 $start += $loc if ($loc > 0);
1071 elsif ($self->convert_all_variables() && $warn) {
1072 ## We could not find a value to correspond to the variable name.
1073 ## Instead of leaving it we will expand it. But, we will only
1074 ## get into this section if this is the secondary attempt to
1075 ## replace the variable (indicated by the $warn boolean).
1076 substr($value, $start) =~ s/\$\([^)]+\)//;
1080 my $loc = index(substr($value, $start), $whole);
1081 $start += $loc if ($loc > 0);
1083 $start += length($whole);
1086 $value =~ s/\\/\//g
if ($self->{'requires_forward_slashes'});
1092 sub replace_env_vars
{
1093 my($self, $lref) = @_;
1094 my $one_empty = undef;
1096 ## Loop through the string until we find no more environment variables.
1097 while($$lref =~ /\$(\w+)/) {
1101 ## PWD is a special variable. It isn't set on Windows, but in MPC we
1102 ## must guarantee that it is always there.
1103 if ($name eq 'PWD') {
1104 $val = $self->getcwd();
1106 elsif (defined $ENV{$name}) {
1110 ## Keep track of an environment variable not being set.
1113 $$lref =~ s/\$\w+/$val/;
1120 my($self, $value, $expand_template, $scope) = @_;
1122 if (defined $value) {
1123 if (UNIVERSAL
::isa
($value, 'ARRAY')) {
1125 foreach my $val (@
$value) {
1126 my $rel = $self->relative($val, $expand_template, $scope);
1127 if (UNIVERSAL
::isa
($rel, 'ARRAY')) {
1128 push(@built, @
$rel);
1136 elsif (index($value, '$') >= 0) {
1137 ## A form of this code lives in
1138 ## ProjectCreator::create_recursive_settings. If you are changing
1139 ## something in this area, please look at the method in
1140 ## ProjectCreator.pm to see if it needs changing too.
1142 my $ovalue = $value;
1143 my($rel, $how) = $self->get_initial_relative_values();
1144 $value = $self->expand_variables($value, $rel,
1145 $expand_template, $scope, $how);
1147 if ($ovalue eq $value || index($value, '$') >= 0) {
1148 ($rel, $how) = $self->get_secondary_relative_values();
1149 $value = $self->expand_variables($value, $rel,
1150 $expand_template, $scope,
1156 ## Values that have two or more strings enclosed in double quotes are
1157 ## to be interpreted as elements of an array
1158 if (defined $value && $value =~ /^"[^"]+"(\s+"[^"]+")+$/) {
1159 $value = $self->create_array($value);
1166 ## Static function. Returns the default language for MPC.
1167 sub defaultLanguage
{
1172 ## Static function. Returns an array of valid languages.
1173 sub validLanguages
{
1174 return keys %languages;
1178 ## Static function. The one and only argument is the language
1179 ## string to check for validity.
1180 sub isValidLanguage
{
1181 return defined $languages{$_[0]};
1186 #my($self, $language) = @_;
1187 return $_[0]->{'language'} eq $_[1];
1190 # ************************************************************
1191 # Virtual Methods To Be Overridden
1192 # ************************************************************
1194 sub restore_state_helper
{
1202 sub get_initial_relative_values
{
1208 sub get_secondary_relative_values
{
1210 return ($self->{'use_env'} ? \
%ENV :
1211 $self->{'relative'}), $self->{'expand_vars'};
1215 sub convert_all_variables
{
1221 sub expand_variables_from_template_values
{
1227 sub preserve_assignment_order
{
1234 sub compare_output
{
1240 sub files_are_different
{
1241 my($self, $old, $new) = @_;
1242 return !(-r
$old && -s
$new == -s
$old && compare
($new, $old) == 0);
1246 sub handle_scoped_end
{
1253 sub handle_unknown_assignment
{
1257 return 0, "Invalid assignment name: '$values[1]'";
1261 sub handle_scoped_unknown
{
1262 my($self, $fh, $type, $flags, $line) = @_;
1263 return 0, "Unrecognized line: $line";
1267 sub remove_duplicate_addition
{
1268 my($self, $name, $value, $current) = @_;
1273 sub generate_recursive_input_list
{
1276 #my $exclude = shift;
1296 return $_[1] cmp $_[2];
1300 sub read_global_configuration
{
1307 sub set_verbose_ordering
{
1313 sub get_properties
{
1316 ## Create the property hash map with the language property
1317 my %props = ($self->get_language() => 1);
1319 ## Set the 'static' property only if the project is static
1320 $props{'static'} = 1 if ($self->get_static());