Subversion Repositories gelsvn

Rev

Rev 198 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
107 bj 1
package ProjectCreator;
2
 
3
# ************************************************************
4
# Description   : Base class for all project creators
5
# Author        : Chad Elliott
6
# Create Date   : 3/13/2002
7
# ************************************************************
8
 
9
# ************************************************************
10
# Pragmas
11
# ************************************************************
12
 
13
use strict;
14
use FileHandle;
15
use File::Path;
16
use File::Compare;
17
 
18
use Creator;
19
use TemplateInputReader;
20
use TemplateParser;
21
use FeatureParser;
22
 
23
use vars qw(@ISA);
24
@ISA = qw(Creator);
25
 
26
# ************************************************************
27
# Data Section
28
# ************************************************************
29
 
30
my($BaseClassExtension)      = 'mpb';
31
my($ProjectCreatorExtension) = 'mpc';
32
my($TemplateExtension)       = 'mpd';
33
my($TemplateInputExtension)  = 'mpt';
34
 
35
## Valid names for assignments within a project
36
## Bit Meaning
37
## 0   Preserve the order for additions (1) or invert it (0)
38
## 1   Add this value to template input value (if there is one)
217 bj 39
## 2   Preserve <% %> settings for evaluation within the template
107 bj 40
my(%validNames) = ('exename'         => 1,
41
                   'sharedname'      => 1,
42
                   'staticname'      => 1,
43
                   'libpaths'        => 3,
44
                   'install'         => 1,
45
                   'includes'        => 3,
46
                   'after'           => 1,
47
                   'custom_only'     => 1,
48
                   'libs'            => 2,
49
                   'lit_libs'        => 2,
50
                   'pure_libs'       => 2,
51
                   'pch_header'      => 1,
52
                   'pch_source'      => 1,
217 bj 53
                   'prebuild'        => 5,
54
                   'postbuild'       => 5,
107 bj 55
                   'dllout'          => 1,
56
                   'libout'          => 1,
57
                   'dynamicflags'    => 3,
58
                   'staticflags'     => 3,
59
                   'version'         => 1,
60
                   'recurse'         => 1,
61
                   'requires'        => 3,
62
                   'avoids'          => 3,
63
                   'tagname'         => 1,
64
                   'tagchecks'       => 1,
65
                   'macros'          => 3,
66
                  );
67
 
68
## Custom definitions only
69
## Bit  Meaning
70
## 0    Value is always an array
71
## 1    Value is an array and name gets 'outputext' converted to 'files'
72
## 2    Value is always scalar
73
## 3    Name can also be used in an 'optional' clause
74
## 4    Needs <%...%> conversion
75
my(%customDefined) = ('automatic'                   => 0x04,
76
                      'dependent'                   => 0x14,
77
                      'command'                     => 0x14,
78
                      'commandflags'                => 0x14,
79
                      'precommand'                  => 0x14,
80
                      'postcommand'                 => 0x14,
81
                      'inputext'                    => 0x01,
82
                      'libpath'                     => 0x04,
83
                      'output_option'               => 0x14,
84
                      'pch_postrule'                => 0x04,
85
                      'pre_extension'               => 0x08,
86
                      'source_pre_extension'        => 0x08,
87
                      'template_pre_extension'      => 0x08,
88
                      'header_pre_extension'        => 0x08,
89
                      'inline_pre_extension'        => 0x08,
90
                      'documentation_pre_extension' => 0x08,
91
                      'resource_pre_extension'      => 0x08,
198 bj 92
                      'generic_pre_extension'       => 0x08,
107 bj 93
                      'pre_filename'                => 0x08,
94
                      'source_pre_filename'         => 0x08,
95
                      'template_pre_filename'       => 0x08,
96
                      'header_pre_filename'         => 0x08,
97
                      'inline_pre_filename'         => 0x08,
98
                      'documentation_pre_filename'  => 0x08,
99
                      'resource_pre_filename'       => 0x08,
198 bj 100
                      'generic_pre_filename'        => 0x08,
107 bj 101
                      'source_outputext'            => 0x0a,
102
                      'template_outputext'          => 0x0a,
103
                      'header_outputext'            => 0x0a,
104
                      'inline_outputext'            => 0x0a,
105
                      'documentation_outputext'     => 0x0a,
106
                      'resource_outputext'          => 0x0a,
107
                      'generic_outputext'           => 0x0a,
108
                     );
109
 
110
## Custom sections as well as definitions
111
## Value  Meaning
112
## 0    No modifications
113
## 1    Needs <%...%> conversion
114
my(%custom) = ('command'       => 1,
115
               'commandflags'  => 1,
116
               'dependent'     => 1,
117
               'gendir'        => 0,
118
               'precommand'    => 1,
119
               'postcommand'   => 1,
120
              );
121
 
122
## All matching assignment arrays will get these keywords
123
my(@default_matching_assignments) = ('recurse',
124
                                    );
125
 
217 bj 126
## These matching assingment arrays will get added, but only to the
127
## specific project component types.
128
my(%default_matching_assignments) = ('source_files' => ['buildflags'],
129
                                    );
130
 
107 bj 131
## Deal with these components in a special way
132
my(%specialComponents) = ('header_files'   => 1,
133
                          'inline_files'   => 1,
134
                          'template_files' => 1,
135
                         );
136
my(%sourceComponents)  = ('source_files'   => 1,
137
                          'template_files' => 1,
138
                         );
139
 
140
my($defgroup)    = 'default_group';
141
my($grouped_key) = 'grouped_';
142
 
143
## Matches with generic_outputext
144
my($generic_key) = 'generic_files';
145
 
146
# ************************************************************
147
# C++ Specific Component Settings
148
# ************************************************************
149
 
150
## Valid component names within a project along with the valid file extensions
151
my(%cppvc) = ('source_files'        => [ "\\.cpp", "\\.cxx", "\\.cc", "\\.c", "\\.C", ],
152
              'template_files'      => [ "_T\\.cpp", "_T\\.cxx", "_T\\.cc", "_T\\.c", "_T\\.C", ],
153
              'header_files'        => [ "\\.h", "\\.hpp", "\\.hxx", "\\.hh", ],
217 bj 154
              'inline_files'        => [ "\\.i", "\\.ipp", "\\.inl", ],
107 bj 155
              'documentation_files' => [ "README", "readme", "\\.doc", "\\.txt", "\\.html" ],
156
              'resource_files'      => [ "\\.rc", ],
157
             );
158
 
159
## Exclude these extensions when auto generating the component values
160
my(%cppec) = ('source_files' => $cppvc{'template_files'},
161
             );
162
 
163
# ************************************************************
164
# C# Specific Component Settings
165
# ************************************************************
166
 
167
## Valid component names within a project along with the valid file extensions
168
my(%csvc) = ('source_files'        => [ "\\.cs" ],
169
             'config_files'        => [ "\\.config" ],
170
             'resx_files'          => [ "\\.resx" ],
171
             'ico_files'           => [ "\\.ico" ],
172
             'documentation_files' => [ "README", "readme", "\\.doc", "\\.txt", "\\.html" ],
173
            );
174
 
175
my(%csma) = ('source_files' => [ 'subtype' ],
176
            );
177
 
178
# ************************************************************
179
# Java Specific Component Settings
180
# ************************************************************
181
 
182
## Valid component names within a project along with the valid file extensions
183
my(%jvc) = ('source_files'        => [ "\\.java" ],
184
            'documentation_files' => [ "README", "readme", "\\.doc", "\\.txt", "\\.html" ],
185
           );
186
 
187
# ************************************************************
188
# Visual Basic Specific Component Settings
189
# ************************************************************
190
 
191
## Valid component names within a project along with the valid file extensions
192
my(%vbvc) = ('source_files'        => [ "\\.vb" ],
193
             'config_files'        => [ "\\.config" ],
194
             'resx_files'          => [ "\\.resx" ],
195
             'ico_files'           => [ "\\.ico" ],
196
             'documentation_files' => [ "README", "readme", "\\.doc", "\\.txt", "\\.html" ],
197
            );
198
 
199
my(%vbma) = ('source_files' => [ 'subtype' ],
200
            );
201
 
202
# ************************************************************
203
# Language Specific Component Settings
204
# ************************************************************
205
 
206
# Index Description
207
# ----- -----------
208
# 0     File types
209
# 1     Files automatically excluded from source_files
210
# 2     Assignments available in standard file types
211
# 3     The entry point for executables
212
# 4     The language uses a C preprocessor
213
my(%language) = ('cplusplus' => [ \%cppvc, \%cppec, {}    , 'main', 1 ],
214
                 'csharp'    => [ \%csvc,  {},      \%csma, 'Main', 0 ],
217 bj 215
                 'java'      => [ \%jvc,   {},      {}    , 'main', 0 ],
107 bj 216
                 'vb'        => [ \%vbvc,  {},      \%vbma, 'Main', 0 ],
217
                );
218
 
219
# ************************************************************
220
# Subroutine Section
221
# ************************************************************
222
 
223
sub new {
224
  my($class)      = shift;
225
  my($global)     = shift;
226
  my($inc)        = shift;
227
  my($template)   = shift;
228
  my($ti)         = shift;
229
  my($dynamic)    = shift;
230
  my($static)     = shift;
231
  my($relative)   = shift;
232
  my($addtemp)    = shift;
233
  my($addproj)    = shift;
234
  my($progress)   = shift;
235
  my($toplevel)   = shift;
236
  my($baseprojs)  = shift;
237
  my($gfeature)   = shift;
238
  my($feature)    = shift;
239
  my($features)   = shift;
240
  my($hierarchy)  = shift;
241
  my($exclude)    = shift;
242
  my($makeco)     = shift;
243
  my($nmod)       = shift;
244
  my($applypj)    = shift;
245
  my($genins)     = shift;
246
  my($into)       = shift;
247
  my($language)   = shift;
248
  my($use_env)    = shift;
249
  my($expandvars) = shift;
250
  my($self)       = $class->SUPER::new($global, $inc,
251
                                       $template, $ti, $dynamic, $static,
252
                                       $relative, $addtemp, $addproj,
253
                                       $progress, $toplevel, $baseprojs,
254
                                       $feature, $features,
255
                                       $hierarchy, $nmod, $applypj,
256
                                       $into, $language, $use_env,
257
                                       $expandvars,
258
                                       'project');
259
 
260
  $self->{$self->{'type_check'}}   = 0;
261
  $self->{'feature_defined'}       = 0;
262
  $self->{'project_info'}          = [];
263
  $self->{'lib_locations'}         = {};
264
  $self->{'reading_parent'}        = [];
265
  $self->{'dexe_template_input'}   = undef;
266
  $self->{'lexe_template_input'}   = undef;
267
  $self->{'lib_template_input'}    = undef;
268
  $self->{'dll_template_input'}    = undef;
269
  $self->{'flag_overrides'}        = {};
270
  $self->{'custom_special_output'} = {};
271
  $self->{'custom_special_depend'} = {};
272
  $self->{'special_supplied'}      = {};
273
  $self->{'pctype'}                = $self->extractType("$self");
274
  $self->{'verbatim'}              = {};
275
  $self->{'verbatim_accessed'}     = {$self->{'pctype'} => {}};
276
  $self->{'defaulted'}             = {};
277
  $self->{'custom_types'}          = {};
278
  $self->{'parents_read'}          = {};
279
  $self->{'inheritance_tree'}      = {};
280
  $self->{'remove_files'}          = {};
198 bj 281
  $self->{'expanded'}              = {};
107 bj 282
 
198 bj 283
  my($typefeaturef) = $self->mpc_dirname($gfeature) . '/' .
107 bj 284
                      $self->{'pctype'} . '.features';
285
  $typefeaturef = undef if (! -r $typefeaturef);
286
  $self->{'feature_parser'}        = new FeatureParser($features,
287
                                                       $gfeature,
288
                                                       $typefeaturef,
289
                                                       $feature);
290
  $self->{'sort_files'}            = $self->sort_files();
291
  $self->{'source_callback'}       = undef;
292
  $self->{'dollar_special'}        = $self->dollar_special();
293
  $self->{'generate_ins'}          = $genins;
294
  $self->{'addtemp_state'}         = undef;
295
  $self->{'command_subs'}          = $self->get_command_subs();
296
  $self->{'escape_spaces'}         = $self->escape_spaces();
217 bj 297
  $self->{'case_insensitive'}      = $self->case_insensitive();
107 bj 298
 
299
  $self->add_default_matching_assignments();
300
  $self->reset_generating_types();
301
 
302
  return $self;
303
}
304
 
305
 
217 bj 306
sub is_keyword {
307
  my($self) = shift;
308
  my($name) = shift;
309
  return $self->{'valid_names'}->{$name};
310
}
311
 
312
 
107 bj 313
sub read_global_configuration {
314
  my($self)   = shift;
315
  my($input)  = $self->get_global_cfg();
316
  my($status) = 1;
317
 
318
  if (defined $input) {
319
    ## If it doesn't contain a path, search the include path
320
    if ($input !~ /[\/\\]/) {
321
      $input = $self->search_include_path($input);
322
      if (!defined $input) {
323
        $input = $self->get_global_cfg();
324
      }
325
    }
326
 
327
    ## Read and parse the global project file
328
    $self->{'reading_global'} = 1;
329
    $status = $self->parse_file($input);
330
    $self->{'reading_global'} = 0;
331
  }
332
 
333
  return $status;
334
}
335
 
336
 
337
sub process_assignment {
338
  my($self)   = shift;
339
  my($name)   = shift;
340
  my($value)  = shift;
341
  my($assign) = shift;
342
 
343
  ## Support the '*' mechanism as in the project name, to allow
344
  ## the user to correctly depend on another project within the same
345
  ## directory.
217 bj 346
  if (defined $value) {
347
    if ($name eq 'after' && index($value, '*') >= 0) {
348
      $value = $self->fill_type_name($value,
349
                                     $self->get_default_project_name());
350
    }
351
    if (!$self->{'dollar_special'} && index($value, '$$') >= 0) {
352
      $value =~ s/\$\$/\$/g;
353
    }
354
    if (defined $self->{'valid_names'}->{$name} &&
355
        ($self->{'valid_names'}->{$name} & 0x04) == 0 &&
356
        index($value, '<%') >= 0) {
357
      $value = $self->replace_parameters($value, $self->{'command_subs'});
358
    }
107 bj 359
  }
360
  $self->SUPER::process_assignment($name, $value, $assign);
361
 
362
  ## Support keyword mapping here only at the project level scope. The
363
  ## scoped keyword mapping is done through the parse_scoped_assignment()
364
  ## method.
365
  if (!defined $assign || $assign == $self->get_assignment_hash()) {
366
    my($mapped) = $self->{'valid_names'}->{$name};
367
    if (defined $mapped && UNIVERSAL::isa($mapped, 'ARRAY')) {
217 bj 368
      $self->parse_scoped_assignment($$mapped[0], '=',
107 bj 369
                                     $$mapped[1], $value,
370
                                     $self->{'generated_exts'}->{$$mapped[0]});
371
    }
372
  }
373
}
374
 
375
 
376
sub get_assignment_for_modification {
377
  my($self)        = shift;
378
  my($name)        = shift;
379
  my($assign)      = shift;
380
  my($subtraction) = shift;
381
 
382
  ## If we weren't passed an assignment hash, then we need to
383
  ## look one up that may possibly correctly deal with keyword mappings
384
  if (!defined $assign) {
385
    my($mapped) = $self->{'valid_names'}->{$name};
386
 
387
    if (defined $mapped && UNIVERSAL::isa($mapped, 'ARRAY')) {
388
      $name   = $$mapped[1];
389
      $assign = $self->{'generated_exts'}->{$$mapped[0]};
390
    }
391
  }
392
 
393
  ## Get the assignment value
394
  my($value) = $self->get_assignment($name, $assign);
395
 
396
  ## If we are involved in a subtraction, we get back a value and
397
  ## it's a scoped or mapped assignment, then we need to possibly
398
  ## expand any template variables.  Otherwise, the subtractions
399
  ## may not work correctly.
400
  if ($subtraction && defined $value && defined $assign) {
401
    $value = $self->relative($value, 1);
402
  }
403
 
404
  return $value;
405
}
406
 
407
 
408
sub begin_project {
409
  my($self)    = shift;
410
  my($parents) = shift;
411
  my($status)  = 1;
412
  my($error)   = undef;
413
 
414
  ## Deal with the inheritance hierarchy first
415
  ## Add in the base projects from the command line
416
  if (!$self->{'reading_global'} &&
417
      !defined $self->{'reading_parent'}->[0]) {
418
    my($baseprojs) = $self->get_baseprojs();
419
 
420
    if (defined $parents) {
421
      foreach my $base (@$baseprojs) {
422
        my($found) = 0;
423
        foreach my $parent (@$parents) {
424
          if ($base eq $parent) {
425
            $found = 1;
426
            last;
427
          }
428
        }
429
        if (!$found) {
430
          push(@$parents, $base);
431
        }
432
      }
433
    }
434
    else {
435
      $parents = $baseprojs;
436
    }
437
  }
438
 
439
  if (defined $parents) {
440
    foreach my $parent (@$parents) {
441
      ## Read in the parent onto ourself
442
      my($file) = $self->search_include_path(
443
                           "$parent.$BaseClassExtension");
444
      if (!defined $file) {
445
        $file = $self->search_include_path(
446
                             "$parent.$ProjectCreatorExtension");
447
      }
448
 
449
      if (defined $file) {
450
        if (defined $self->{'reading_parent'}->[0]) {
451
          foreach my $currently (@{$self->{'reading_parent'}}) {
452
            if ($currently eq $file) {
453
              $status = 0;
454
              $error = 'Cyclic inheritance detected: ' . $parent;
455
            }
456
          }
457
        }
458
 
459
        if ($status) {
460
          if (!defined $self->{'parents_read'}->{$file}) {
461
            $self->{'parents_read'}->{$file} = 1;
462
 
463
            ## Push the base project file onto the parent stack
464
            push(@{$self->{'reading_parent'}}, $file);
465
 
466
            ## Collect up some information about the inheritance tree
467
            my($tree) = $self->{'current_input'};
468
            if (!defined $self->{'inheritance_tree'}->{$tree}) {
469
              $self->{'inheritance_tree'}->{$tree} = {};
470
            }
471
            my($hash) = $self->{'inheritance_tree'}->{$tree};
472
            foreach my $p (@{$self->{'reading_parent'}}) {
473
              if (!defined $$hash{$p}) {
474
                $$hash{$p} = {};
475
              }
476
              $hash = $$hash{$p};
477
            }
478
 
479
            ## Begin reading the parent
480
            $status = $self->parse_file($file);
481
 
482
            ## Take the base project file off of the parent stack
483
            pop(@{$self->{'reading_parent'}});
484
 
485
            if (!$status) {
486
              $error = "Invalid parent: $parent";
487
            }
488
          }
489
          else {
490
            ## The base project has already been read.  So, if
491
            ## we are reading the original project (not a parent base
492
            ## project), then the current base project is redundant.
493
            if (!defined $self->{'reading_parent'}->[0]) {
494
              $file =~ s/\.[^\.]+$//;
217 bj 495
              $self->information('Inheriting from \'' .
496
                                 $self->mpc_basename($file) .
107 bj 497
                                 '\' in ' . $self->{'current_input'} .
498
                                 ' is redundant at line ' .
499
                                 $self->get_line_number() . '.');
500
            }
501
          }
502
        }
503
      }
504
      else {
505
        $status = 0;
506
        $error = "Unable to locate parent: $parent";
507
      }
508
    }
509
  }
510
 
511
  ## Copy each value from global_assign into assign
512
  if (!$self->{'reading_global'}) {
513
    foreach my $key (keys %{$self->{'global_assign'}}) {
514
      if (!defined $self->{'assign'}->{$key}) {
515
        $self->{'assign'}->{$key} = $self->{'global_assign'}->{$key};
516
      }
517
    }
518
  }
519
 
520
  return $status, $error;
521
}
522
 
523
 
524
sub get_process_project_type {
525
  my($self)    = shift;
526
  my($types)   = shift;
527
  my($type)    = '';
528
  my($defcomp) = $self->get_default_component_name();
529
 
530
  foreach my $t (split(/\s*,\s*/, $types)) {
531
    my($not) = ($t =~ s/^!\s*//);
532
    if ($not) {
533
      if ($t eq $self->{'pctype'}) {
534
        $type = '';
535
        last;
536
      }
537
      else {
538
        $type = $self->{'pctype'};
539
      }
540
    }
541
    elsif ($t eq $self->{'pctype'} || $t eq $defcomp) {
542
      $type = $t;
543
      last;
544
    }
545
  }
546
 
547
  return $type;
548
}
549
 
550
 
551
sub parse_line {
552
  my($self)   = shift;
553
  my($ih)     = shift;
554
  my($line)   = shift;
555
  my($status,
556
     $errorString,
557
     @values) = $self->parse_known($line);
558
 
559
  ## parse_known() passes back an array of values
560
  ## that make up the contents of the line parsed.
561
  ## The array can have 0 to 3 items.  The first,
562
  ## if defined, is always an identifier of some
563
  ## sort.
564
 
565
  if ($status && defined $values[0]) {
566
    if ($values[0] eq $self->{'grammar_type'}) {
567
      my($name)      = $values[1];
568
      my($typecheck) = $self->{'type_check'};
569
      if (defined $name && $name eq '}') {
570
        ## Project Ending
571
        my($rp) = $self->{'reading_parent'};
572
        if (!defined $$rp[0] && !$self->{'reading_global'}) {
573
          ## Fill in all the default values
574
          $self->generate_defaults();
575
 
576
          ## Perform any additions, subtractions
577
          ## or overrides for the project values.
578
          my($addproj) = $self->get_addproj();
579
          foreach my $ap (keys %$addproj) {
580
            if (defined $self->{'valid_names'}->{$ap}) {
581
              my($val) = $$addproj{$ap};
582
              if ($$val[0] > 0) {
583
                $self->process_assignment_add($ap, $$val[1]);
584
              }
585
              elsif ($$val[0] < 0) {
586
                $self->process_assignment_sub($ap, $$val[1]);
587
              }
588
              else {
589
                $self->process_assignment($ap, $$val[1]);
590
              }
591
            }
592
            else {
593
              $errorString = 'Invalid ' .
594
                             "assignment modification name: $ap";
595
              $status = 0;
596
            }
597
          }
598
 
599
          if ($status) {
217 bj 600
            ## Generate default target names after all source files are added
601
            ## and after we've added in all of the options from the
602
            ## command line.  If the user set exename on the command line
603
            ## and no "main" is found, sharedname will be set too and
604
            ## most templates do not handle that well.
605
            $self->generate_default_target_names();
606
 
107 bj 607
            ## End of project; Write out the file.
608
            ($status, $errorString) = $self->write_project();
609
 
610
            ## write_project() can return 0 for error, 1 for project
611
            ## was written and 2 for project was skipped
612
            if ($status == 1) {
613
              ## Save the library name and location
614
              foreach my $name ('sharedname', 'staticname') {
615
                my($val) = $self->get_assignment($name);
616
                if (defined $val) {
617
                  my($cwd)   = $self->getcwd();
618
                  my($start) = $self->getstartdir();
619
                  my($amount) = 0;
620
                  if ($cwd eq $start) {
621
                    $amount = length($start);
622
                  }
623
                  elsif (index($cwd, $start) == 0) {
624
                    $amount = length($start) + 1;
625
                  }
626
                  $self->{'lib_locations'}->{$val} =
627
                      substr($cwd, $amount);
628
                  last;
629
                }
630
              }
631
 
632
              ## Check for unused verbatim markers
633
              foreach my $key (keys %{$self->{'verbatim'}}) {
634
                if (defined $self->{'verbatim_accessed'}->{$key}) {
635
                  foreach my $ikey (keys %{$self->{'verbatim'}->{$key}}) {
636
                    if (!defined $self->{'verbatim_accessed'}->{$key}->{$ikey}) {
637
                      $self->warning("Marker $ikey does not exist.");
638
                    }
639
                  }
640
                }
641
              }
642
            }
643
 
644
            ## Reset all of the project specific data
645
            foreach my $key (keys %{$self->{'valid_components'}}) {
646
              delete $self->{$key};
647
              $self->{'defaulted'}->{$key} = 0;
648
            }
649
            if (defined $self->{'addtemp_state'}) {
650
              $self->restore_state($self->{'addtemp_state'}, 'addtemp');
651
              $self->{'addtemp_state'} = undef;
652
            }
653
            $self->{'assign'}                = {};
654
            $self->{'verbatim'}              = {};
655
            $self->{'verbatim_accessed'}     = {$self->{'pctype'} => {}};
656
            $self->{'special_supplied'}      = {};
657
            $self->{'flag_overrides'}        = {};
658
            $self->{'parents_read'}          = {};
659
            $self->{'inheritance_tree'}      = {};
660
            $self->{'remove_files'}          = {};
661
            $self->{'custom_special_output'} = {};
662
            $self->{'custom_special_depend'} = {};
198 bj 663
            $self->{'expanded'}              = {};
107 bj 664
            $self->reset_generating_types();
665
          }
666
        }
667
        $self->{$typecheck} = 0;
668
      }
669
      else {
670
        ## Project Beginning
671
        ($status, $errorString) = $self->begin_project($values[2]);
672
 
673
        ## Set up the default project name
674
        if ($status) {
675
          if (defined $name) {
676
            if ($name =~ /[\/\\]/) {
677
              $status = 0;
678
              $errorString = 'Projects can not have a slash ' .
679
                             'or a back slash in the name';
680
            }
681
            else {
682
              ## We should only set the project name if we are not
683
              ## reading in a parent project.
684
              if (!defined $self->{'reading_parent'}->[0]) {
685
                $name =~ s/^\(\s*//;
686
                $name =~ s/\s*\)$//;
687
                $name = $self->transform_file_name($name);
688
 
689
                ## Replace any *'s with the default name
217 bj 690
                if (index($name, '*') >= 0) {
107 bj 691
                  $name = $self->fill_type_name(
692
                                    $name,
693
                                    $self->get_default_project_name());
694
                }
695
 
696
                $self->set_project_name($name);
697
              }
698
              else {
699
                $self->warning("Ignoring project name in a base project.");
700
              }
701
            }
702
          }
703
        }
704
 
705
        if ($status) {
706
          ## Signify that we have a valid project
707
          $self->{$typecheck} = 1;
708
        }
709
      }
710
    }
217 bj 711
    elsif ($values[0] eq '=') {
107 bj 712
      my($name)  = $values[1];
713
      my($value) = $values[2];
714
      if (defined $self->{'valid_names'}->{$name}) {
715
        $self->process_assignment($name, $value);
716
      }
717
      else {
718
        $errorString = "Invalid assignment name: $name";
719
        $status = 0;
720
      }
721
    }
217 bj 722
    elsif ($values[0] eq '+=') {
107 bj 723
      my($name)  = $values[1];
724
      my($value) = $values[2];
725
      if (defined $self->{'valid_names'}->{$name}) {
726
        $self->process_assignment_add($name, $value);
727
      }
728
      else {
729
        $errorString = "Invalid addition name: $name";
730
        $status = 0;
731
      }
732
    }
217 bj 733
    elsif ($values[0] eq '-=') {
107 bj 734
      my($name)  = $values[1];
735
      my($value) = $values[2];
736
      if (defined $self->{'valid_names'}->{$name}) {
737
        $self->process_assignment_sub($name, $value);
738
      }
739
      else {
740
        $errorString = "Invalid subtraction name: $name";
741
        $status = 0;
742
      }
743
    }
744
    elsif ($values[0] eq 'component') {
745
      my($comp) = $values[1];
746
      my($name) = $values[2];
747
      if (defined $name) {
748
        $name =~ s/^\(\s*//;
749
        $name =~ s/\s*\)$//;
750
      }
751
      else {
752
        $name = $self->get_default_component_name();
753
      }
754
 
755
      my($vc) = $self->{'valid_components'};
756
      if (defined $$vc{$comp}) {
757
        ($status, $errorString) = $self->parse_components($ih, $comp, $name);
758
      }
759
      else {
760
        if ($comp eq 'verbatim') {
761
          my($type, $loc) = split(/\s*,\s*/, $name);
762
          ($status, $errorString) = $self->parse_verbatim($ih, $type, $loc);
763
        }
764
        elsif ($comp eq 'specific') {
765
          my($type) = $self->get_process_project_type($name);
766
          if ($type eq $self->{'pctype'} ||
767
              $type eq $self->get_default_component_name()) {
768
            ($status, $errorString) = $self->parse_scope(
198 bj 769
                                        $ih, $comp, $type,
107 bj 770
                                        $self->{'valid_names'},
771
                                        $self->get_assignment_hash(),
772
                                        {});
773
          }
774
          else {
775
            ## We still need to parse the scope, but we will be
776
            ## throwing away whatever is processed.  However, it
777
            ## could still be invalid code that will cause an error.
778
            ($status, $errorString) = $self->parse_scope(
198 bj 779
                                        $ih, $comp, undef,
107 bj 780
                                        $self->{'valid_names'},
781
                                        undef,
782
                                        $self->get_assignment_hash());
783
          }
784
        }
785
        elsif ($comp eq 'define_custom') {
786
          ($status, $errorString) = $self->parse_define_custom($ih, $name);
787
        }
198 bj 788
        elsif ($comp eq 'expand') {
789
          ($status, $errorString) = $self->parse_scope($ih, $comp, $name);
790
        }
107 bj 791
        else {
792
          $errorString = "Invalid component name: $comp";
793
          $status = 0;
794
        }
795
      }
796
    }
797
    elsif ($values[0] eq 'feature') {
798
      $self->{'feature_defined'} = 1;
799
      $self->process_feature($ih, $values[1], $values[2]);
800
      if ($self->{'feature_defined'}) {
801
        $errorString = "Did not find the end of the feature";
802
        $status = 0;
803
      }
804
    }
805
    else {
806
      $errorString = "Unrecognized line: $line";
807
      $status = 0;
808
    }
809
  }
810
  elsif ($status == -1) {
811
    $status = 0;
812
  }
813
 
814
  return $status, $errorString;
815
}
816
 
817
 
818
sub parse_scoped_assignment {
819
  my($self)   = shift;
820
  my($tag)    = shift;
821
  my($type)   = shift;
822
  my($name)   = shift;
823
  my($value)  = shift;
824
  my($flags)  = shift;
825
  my($over)   = {};
826
  my($status) = 0;
827
 
828
  ## Map the assignment name on a scoped assignment
829
  my($mapped) = $self->{'valid_names'}->{$name};
830
  if (defined $mapped && UNIVERSAL::isa($mapped, 'ARRAY')) {
831
    $name = $$mapped[1];
832
  }
833
 
834
  if (defined $self->{'matching_assignments'}->{$tag}) {
835
    foreach my $possible (@{$self->{'matching_assignments'}->{$tag}}) {
836
      if ($possible eq $name) {
837
        $status = 1;
838
        last;
839
      }
840
    }
841
  }
842
 
843
  if ($status) {
844
    if (defined $self->{'flag_overrides'}->{$tag}) {
845
      $over = $self->{'flag_overrides'}->{$tag};
846
    }
847
    else {
848
      $self->{'flag_overrides'}->{$tag} = $over;
849
    }
850
 
217 bj 851
    if ($type eq '=') {
107 bj 852
      $self->process_assignment($name, $value, $flags);
853
    }
217 bj 854
    elsif ($type eq '+=') {
107 bj 855
      ## If there is no value in $$flags, then we need to get
856
      ## the outer scope value and put it in there.
857
      if (!defined $self->get_assignment($name, $flags)) {
858
        my($outer) = $self->get_assignment($name);
859
        $self->process_assignment($name, $outer, $flags);
860
      }
861
      $self->process_assignment_add($name, $value, $flags);
862
    }
217 bj 863
    elsif ($type eq '-=') {
107 bj 864
      ## If there is no value in $$flags, then we need to get
865
      ## the outer scope value and put it in there.
866
      if (!defined $self->get_assignment($name, $flags)) {
867
        my($outer) = $self->get_assignment($name);
868
        $self->process_assignment($name, $outer, $flags);
869
      }
870
      $self->process_assignment_sub($name, $value, $flags);
871
    }
872
  }
873
  return $status;
874
}
875
 
876
 
877
sub handle_unknown_assignment {
878
  my($self)   = shift;
879
  my($type)   = shift;
880
  my(@values) = @_;
881
 
882
  ## Unknown assignments within a 'specific' section are handled as
883
  ## template value modifications.  These are handled exactly as the
884
  ## -value_template option in Options.pm.
885
 
886
  ## If $type is not defined, then we are skipping this section
887
  if (defined $type) {
888
    ## Save the addtemp state if we haven't done so before
889
    if (!defined $self->{'addtemp_state'}) {
890
      my(%state) = $self->save_state('addtemp');
891
      $self->{'addtemp_state'} = \%state;
892
    }
893
 
894
    ## Now modify the addtemp values
895
    $self->information("'$values[1]' was used as a template modifier.");
217 bj 896
    if ($values[0] eq '+=') {
107 bj 897
      $values[0] = 1;
898
    }
217 bj 899
    elsif ($values[0] eq '-=') {
107 bj 900
      $values[0] = -1;
901
    }
902
    else {
903
      $values[0] = 0;
904
    }
905
 
906
    if (!defined $self->get_addtemp()->{$values[1]}) {
907
      $self->get_addtemp()->{$values[1]} = [];
908
    }
909
    push(@{$self->get_addtemp()->{$values[1]}}, [$values[0], $values[2]]);
910
  }
911
 
912
  return 1, undef;
913
}
914
 
915
 
198 bj 916
sub handle_scoped_unknown {
917
  my($self)  = shift;
918
  my($fh)    = shift;
919
  my($type)  = shift;
920
  my($flags) = shift;
921
  my($line)  = shift;
922
 
923
  if (defined $type) {
924
    if ($type eq $self->get_default_component_name()) {
925
      return 0, 'Can not set expansion in this context';
926
    }
927
    else {
928
      if (!defined $self->{'expanded'}->{$type}) {
929
        my($ok) = 1;
930
        while($line =~ /\$(\w+)/) {
931
          my($name) = $1;
932
          my($val)  = '';
933
          if ($name eq 'PWD') {
934
            $val = $self->getcwd();
935
          }
936
          elsif (defined $ENV{$name}) {
937
            $val = $ENV{$name};
938
          }
939
          else {
940
            $ok = undef;
941
            last;
942
          }
943
          $line =~ s/\$\w+/$val/;
944
        }
945
        $self->{'expanded'}->{$type} = $line if ($ok);
946
      }
947
      return 1, undef;
948
    }
949
  }
950
 
951
  ## If the type is not defined, then this is something other than an
952
  ## assignment in a 'specific' section and should be flagged as an error
953
  return 0, "Unrecognized line: $line";
954
}
955
 
107 bj 956
sub process_component_line {
957
  my($self)    = shift;
958
  my($tag)     = shift;
959
  my($line)    = shift;
960
  my($flags)   = shift;
961
  my($grname)  = shift;
962
  my($current) = shift;
963
  my($excarr)  = shift;
964
  my($comps)   = shift;
965
  my($count)   = shift;
966
  my($status)  = 1;
967
  my($error)   = undef;
968
  my(%exclude) = ();
217 bj 969
  my(@values)  = ();
107 bj 970
 
971
  ## If this returns true, then we've found an assignment
972
  if ($self->parse_assignment($line, \@values)) {
973
    $status = $self->parse_scoped_assignment($tag, @values, $flags);
974
    if (!$status) {
975
      $error = 'Unknown keyword: ' . $values[1];
976
    }
977
  }
978
  else {
979
    ## If we successfully remove a '!' from the front, then
980
    ## the file(s) listed are to be excluded
981
    my($rem) = ($line =~ s/^\^\s*//);
982
    my($exc) = $rem || ($line =~ s/^!\s*//);
983
 
984
    ## Convert any $(...) in this line before we process any
985
    ## wild card characters.  If we do not, scoped assignments will
986
    ## not work nor will we get the correct wild carded file list.
987
    ## We also need to make sure that any back slashes are converted to
988
    ## slashes to ensure that later flag_overrides checks will happen
989
    ## correctly.
990
    $line = $self->relative($line);
217 bj 991
    $line =~ s/\\/\//g if ($self->{'convert_slashes'});
107 bj 992
 
993
    ## Now look for specially listed files
217 bj 994
    if ((index($line, '>>') >= 0 || index($line, '<<') >= 0) &&
995
        $line =~ /(.*)\s+(>>|<<)\s+(.*)/) {
107 bj 996
      $line    = $1;
997
      my($oop) = $2;
217 bj 998
      my($iop) = ($oop eq '>>' ? '<<' : '>>');
107 bj 999
      my($out) = ($oop eq '>>' ? $3 : undef);
1000
      my($dep) = ($oop eq '<<' ? $3 : undef);
1001
 
1002
      $line =~ s/\s+$//;
217 bj 1003
      if (index($line, $iop) >= 0 && $line =~ /(.*)\s+$iop\s+(.*)/) {
107 bj 1004
        $line = $1;
217 bj 1005
        $out  = ($iop eq '>>' ? $2 : $out);
1006
        $dep  = ($iop eq '<<' ? $2 : $dep);
107 bj 1007
        $line =~ s/\s+$//;
1008
      }
1009
 
217 bj 1010
      ## Check for both possible error conditions
1011
      if (index($line, $oop) >= 0) {
1012
        $status = 0;
1013
        $error  = "Duplicate $oop used";
1014
      }
1015
      elsif (index($line, $iop) >= 0) {
1016
        $status = 0;
1017
        $error  = "Duplicate $iop used";
1018
      }
1019
 
1020
      ## Keys used internally to MPC need to be in forward slash format.
107 bj 1021
      my($key) = $line;
217 bj 1022
      $key =~ s/\\/\//g if ($self->{'convert_slashes'});
107 bj 1023
      if (defined $out) {
1024
        if (!defined $self->{'custom_special_output'}->{$tag}) {
1025
          $self->{'custom_special_output'}->{$tag} = {};
1026
        }
1027
        $self->{'custom_special_output'}->{$tag}->{$key} = $self->create_array($out);
1028
      }
1029
      if (defined $dep) {
1030
        $self->{'custom_special_depend'}->{$key} = $self->create_array($dep);
1031
      }
1032
    }
1033
 
1034
    ## Set up the files array.  If the line contains a wild card
1035
    ## character use CORE::glob() to get the files specified.
1036
    my(@files) = ();
1037
    if ($line =~ /^"([^"]+)"$/) {
1038
      push(@files, $1);
1039
    }
1040
    elsif ($line =~ /[\?\*\[\]]/) {
198 bj 1041
      @files = $self->mpc_glob($line);
107 bj 1042
    }
1043
    else {
1044
      push(@files, $line);
1045
    }
1046
 
1047
    ## If we want to remove these files at the end too, then
1048
    ## add them to our remove_files hash array.
1049
    if ($rem) {
1050
      if (!defined $self->{'remove_files'}->{$tag}) {
1051
        $self->{'remove_files'}->{$tag} = {};
1052
      }
1053
      foreach my $file (@files) {
1054
        $self->{'remove_files'}->{$tag}->{$file} = 1;
1055
      }
1056
    }
1057
 
1058
    ## If we're excluding these files, then put them in the hash
1059
    if ($exc) {
1060
      $$grname = $current;
1061
      @exclude{@files} = (@files);
1062
      @$excarr = @files;
1063
    }
1064
    else {
1065
      ## Set the flag overrides for each file
1066
      my($over) = $self->{'flag_overrides'}->{$tag};
1067
      if (defined $over) {
1068
        foreach my $file (@files) {
1069
          $$over{$file} = $flags;
1070
        }
1071
      }
1072
 
1073
      foreach my $file (@files) {
1074
        ## Add the file if we're not excluding it
1075
        if (!defined $exclude{$file}) {
1076
          push(@{$$comps{$current}}, $file);
1077
        }
1078
 
1079
        ## The user listed a file explicitly, whether we
1080
        ## excluded it or not.
1081
        ++$$count;
1082
      }
1083
    }
1084
  }
1085
 
1086
  return $status, $error;
1087
}
1088
 
1089
 
1090
sub parse_conditional {
1091
  my($self)    = shift;
1092
  my($fh)      = shift;
1093
  my($types)   = shift;
1094
  my($tag)     = shift;
1095
  my($flags)   = shift;
1096
  my($grname)  = shift;
1097
  my($current) = shift;
1098
  my($exclude) = shift;
1099
  my($comps)   = shift;
1100
  my($count)   = shift;
1101
  my($status)  = 1;
1102
  my($error)   = undef;
1103
  my($add)     = 0;
1104
  my($type)    = $self->get_process_project_type($types);
1105
 
1106
  if ($type eq $self->{'pctype'}) {
1107
    $add = 1;
1108
  }
1109
 
1110
  while(<$fh>) {
1111
    my($line) = $self->preprocess_line($fh, $_);
1112
 
1113
    if ($line eq '') {
1114
    }
1115
    elsif ($line =~ /^}\s*else\s*{$/) {
1116
      $add ^= 1;
1117
    }
1118
    elsif ($line =~ /^}$/) {
1119
      last;
1120
    }
1121
    elsif ($add) {
1122
      ($status, $error) = $self->process_component_line(
1123
                                              $tag, $line, $flags,
1124
                                              $grname, $current,
1125
                                              $exclude, $comps, $count);
1126
      if (!$status) {
1127
        last;
1128
      }
1129
    }
1130
  }
1131
 
1132
  return $status, $error;
1133
}
1134
 
1135
sub parse_components {
1136
  my($self)    = shift;
1137
  my($fh)      = shift;
1138
  my($tag)     = shift;
1139
  my($name)    = shift;
1140
  my($current) = $defgroup;
1141
  my($status)  = 1;
1142
  my($error)   = undef;
1143
  my($names)   = {};
1144
  my($comps)   = {};
1145
  my($set)     = undef;
1146
  my(%flags)   = ();
1147
  my(@exclude) = ();
1148
  my($custom)  = defined $self->{'generated_exts'}->{$tag};
1149
  my($grtag)   = $grouped_key . $tag;
1150
  my($grname)  = undef;
1151
 
1152
  if ($custom) {
1153
    ## For the custom scoped assignments, we want to put a copy of
1154
    ## the original custom defined values in our flags associative array.
1155
    foreach my $key (keys %custom) {
1156
      if (defined $self->{'generated_exts'}->{$tag}->{$key}) {
1157
        $flags{$key} = $self->{'generated_exts'}->{$tag}->{$key};
1158
      }
1159
    }
1160
  }
1161
 
1162
  if (defined $self->{$tag}) {
1163
    $names = $self->{$tag};
1164
  }
1165
  else {
1166
    $self->{$tag} = $names;
1167
  }
1168
  if (defined $$names{$name}) {
1169
    $comps = $$names{$name};
1170
  }
1171
  else {
1172
    $$names{$name} = $comps;
1173
  }
1174
  if (!defined $$comps{$current}) {
1175
    $$comps{$current} = [];
1176
  }
1177
 
1178
  my($count) = 0;
1179
  if (defined $specialComponents{$tag}) {
1180
    $self->{'special_supplied'}->{$tag} = 1;
1181
  }
1182
 
1183
  while(<$fh>) {
1184
    my($line) = $self->preprocess_line($fh, $_);
1185
 
1186
    if ($line eq '') {
1187
    }
1188
    elsif ($line =~ /^(\w+)\s*{$/) {
217 bj 1189
      if (!$set) {
107 bj 1190
        $current = $1;
1191
        $set = 1;
1192
        if (!defined $$comps{$current}) {
1193
          $$comps{$current} = [];
1194
        }
1195
      }
1196
      else {
1197
        $status = 0;
1198
        $error  = 'Can not nest groups';
1199
        last;
1200
      }
1201
    }
1202
    elsif ($line =~ /^conditional\s*(\(([^\)]+)\))\s*{$/) {
1203
      ($status, $error) = $self->parse_conditional(
1204
                                         $fh, $2, $tag, \%flags, \$grname,
1205
                                         $current, \@exclude, $comps,
1206
                                         \$count);
1207
      if (!$status) {
1208
        last;
1209
      }
1210
    }
1211
    elsif ($line =~ /^}$/) {
217 bj 1212
      if (!defined $$comps{$current}->[0] && !defined $exclude[0]) {
1213
        ## The default components name was never used
1214
        ## so we remove it from the components
1215
        delete $$comps{$current};
107 bj 1216
      }
217 bj 1217
      else {
1218
        ## It was used, so we need to add that name to
1219
        ## the set of group names unless it's already been added.
1220
        $self->process_assignment_add($grtag, $current);
1221
      }
1222
      if ($set) {
107 bj 1223
        $current = $defgroup;
1224
        $set = undef;
1225
      }
1226
      else {
1227
        ## We are at the end of a component.  If the only group
1228
        ## we added was the default group, then we need to remove
1229
        ## the group setting altogether.
1230
        my($groups) = $self->get_assignment($grtag);
1231
        if (defined $groups) {
217 bj 1232
          my($grarray) = $self->create_array($groups);
1233
          if (scalar(@$grarray) == 1 && $$grarray[0] eq $defgroup) {
107 bj 1234
            $self->process_assignment($grtag, undef);
1235
          }
1236
        }
1237
 
1238
        ## This is not an error,
1239
        ## this is the end of the components
1240
        last;
1241
      }
1242
    }
217 bj 1243
    else {
107 bj 1244
      ($status, $error) = $self->process_component_line($tag, $line, \%flags,
1245
                                                        \$grname, $current,
1246
                                                        \@exclude, $comps,
1247
                                                        \$count);
1248
      if (!$status) {
1249
        last;
1250
      }
1251
    }
1252
  }
1253
 
1254
  ## If we didn't encounter an error, didn't have any files explicitly
1255
  ## listed and we attempted to exclude files, then we need to find the
1256
  ## set of files that don't match the excluded files and add them.
217 bj 1257
  if ($status && defined $exclude[0] && defined $grname) {
107 bj 1258
    my($alldir)  = $self->get_assignment('recurse') || $flags{'recurse'};
1259
    my(%checked) = ();
1260
    my(@files)   = ();
1261
    foreach my $exc (@exclude) {
198 bj 1262
      my($dname) = $self->mpc_dirname($exc);
107 bj 1263
      if (!defined $checked{$dname}) {
1264
        $checked{$dname} = 1;
1265
        push(@files, $self->generate_default_file_list($dname,
217 bj 1266
                                                       \@exclude,
1267
                                                       undef, $alldir));
107 bj 1268
      }
1269
    }
1270
 
1271
    $self->sift_files(\@files,
1272
                      $self->{'valid_components'}->{$tag},
1273
                      $self->get_assignment('pch_header'),
1274
                      $self->get_assignment('pch_source'),
1275
                      $tag,
1276
                      $$comps{$grname});
1277
  }
1278
 
1279
  return $status, $error;
1280
}
1281
 
1282
 
1283
sub parse_verbatim {
1284
  my($self) = shift;
1285
  my($fh)   = shift;
1286
  my($type) = shift;
1287
  my($loc)  = shift;
1288
 
1289
  if (!defined $loc) {
1290
    return 0, 'You must provide a location parameter to verbatim';
1291
  }
1292
 
1293
  ## All types are lower case
1294
  $type = lc($type);
1295
 
1296
  if (!defined $self->{'verbatim'}->{$type}) {
1297
    $self->{'verbatim'}->{$type} = {};
1298
  }
1299
  $self->{'verbatim'}->{$type}->{$loc} = [];
1300
  my($array) = $self->{'verbatim'}->{$type}->{$loc};
1301
 
1302
  while(<$fh>) {
1303
    my($line) = $self->preprocess_line($fh, $_);
1304
 
1305
    if ($line =~ /^}$/) {
1306
      ## This is not an error,
1307
      ## this is the end of the verbatim
1308
      last;
1309
    }
1310
    else {
1311
      push(@$array, $line);
1312
    }
1313
  }
1314
 
1315
  return 1, undef;
1316
}
1317
 
1318
 
1319
sub process_feature {
1320
  my($self)    = shift;
1321
  my($fh)      = shift;
1322
  my($names)   = shift;
1323
  my($parents) = shift;
1324
  my($status)  = 1;
1325
  my($error)   = undef;
1326
 
1327
  my($requires) = '';
1328
  my($avoids)   = '';
1329
  foreach my $name (@$names) {
1330
    if ($name =~ /^!\s*(.*)$/) {
1331
      if ($avoids ne '') {
1332
        $avoids .= ' ';
1333
      }
1334
      $avoids .= $1;
1335
    }
1336
    else {
1337
      if ($requires ne '') {
1338
        $requires .= ' ';
1339
      }
1340
      $requires .= $name;
1341
    }
1342
  }
1343
 
1344
  if ($self->check_features($requires, $avoids)) {
1345
    ## The required features are enabled, so we say that
1346
    ## a project has been defined and we allow the parser to
1347
    ## find the data held within the feature.
1348
    ($status, $error) = $self->begin_project($parents);
1349
    if ($status) {
1350
      $self->{'feature_defined'} = 0;
1351
      $self->{$self->{'type_check'}} = 1;
1352
    }
1353
  }
1354
  else {
1355
    ## Otherwise, we read in all the lines until we find the
1356
    ## closing brace for the feature and it appears to the parser
1357
    ## that nothing was defined.
1358
    my($curly) = 1;
1359
    while(<$fh>) {
1360
      my($line) = $self->preprocess_line($fh, $_);
1361
 
1362
      ## This is a very simplistic way of finding the end of
1363
      ## the feature definition.  It will work as long as no spurious
1364
      ## open curly braces are counted.
1365
      if ($line =~ /{$/) {
1366
        ++$curly;
1367
      }
1368
      if ($line =~ /^}/) {
1369
        --$curly;
1370
      }
1371
      if ($curly == 0) {
1372
        $self->{'feature_defined'} = 0;
1373
        last;
1374
      }
1375
    }
1376
  }
1377
 
1378
  return $status, $error;
1379
}
1380
 
1381
 
1382
sub process_array_assignment {
1383
  my($self)  = shift;
1384
  my($aref)  = shift;
1385
  my($type)  = shift;
1386
  my($array) = shift;
1387
 
217 bj 1388
  if (!defined $$aref || $type eq '=') {
1389
    if ($type ne '-=') {
107 bj 1390
      $$aref = $array;
1391
    }
1392
  }
1393
  else {
217 bj 1394
    if ($type eq '+=') {
107 bj 1395
      push(@{$$aref}, @$array);
1396
    }
217 bj 1397
    elsif ($type eq '-=') {
107 bj 1398
      my($count) = scalar(@{$$aref});
1399
      for(my $i = 0; $i < $count; ++$i) {
1400
        foreach my $val (@$array) {
1401
          if ($$aref->[$i] eq $val) {
1402
            splice(@{$$aref}, $i, 1);
1403
            --$i;
1404
            --$count;
1405
            last;
1406
          }
1407
        }
1408
      }
1409
    }
1410
  }
1411
}
1412
 
1413
 
1414
sub parse_define_custom {
1415
  my($self)        = shift;
1416
  my($fh)          = shift;
1417
  my($tag)         = shift;
1418
  my($status)      = 0;
1419
  my($errorString) = "Unable to process $tag";
1420
 
1421
  ## Make the tag something _files
1422
  $tag = lc($tag) . '_files';
1423
 
1424
  if ($tag eq $generic_key) {
1425
    $errorString = "$tag is reserved";
1426
  }
1427
  elsif (defined $self->{'valid_components'}->{$tag}) {
1428
    $errorString = "$tag has already been defined";
1429
  }
1430
  else {
1431
    ## Update the custom_types assignment
1432
    $self->process_assignment_add('custom_types', $tag);
1433
 
1434
    if (!defined $self->{'matching_assignments'}->{$tag}) {
1435
      my(@keys) = keys %custom;
1436
      push(@keys, @default_matching_assignments);
1437
      $self->{'matching_assignments'}->{$tag} = \@keys;
1438
    }
1439
 
1440
    ## Set up the 'optional' hash table
1441
    $self->{'generated_exts'}->{$tag}->{'optional'} = {};
1442
 
1443
    my($optname) = undef;
1444
    my($inscope) = 0;
1445
    while(<$fh>) {
1446
      my($line) = $self->preprocess_line($fh, $_);
1447
 
1448
      if ($line eq '') {
1449
      }
1450
      elsif ($line =~ /optional\s*\(([^\)]+)\)\s*{/) {
1451
        $optname = $1;
1452
        $optname =~ s/^\s+//;
1453
        $optname =~ s/\s+$//;
1454
        if (defined $customDefined{$optname} &&
1455
            ($customDefined{$optname} & 0x08) != 0) {
1456
          ++$inscope;
1457
          if ($inscope != 1) {
1458
            $status = 0;
1459
            $errorString = 'Can not nest \'optional\' sections';
1460
            last;
1461
          }
1462
        }
1463
        else {
1464
          $status = 0;
1465
          $errorString = "Invalid optional name: $optname";
1466
          last;
1467
        }
1468
      }
1469
      elsif ($inscope) {
1470
        if ($line =~ /^}$/) {
1471
          $optname = undef;
1472
          --$inscope;
1473
        }
1474
        else {
1475
          if ($line =~ /(\w+)\s*\(([^\)]+)\)\s*\+=\s*(.*)/) {
1476
            my($name) = lc($1);
1477
            my($opt)  = $2;
1478
            my(@val)  = split(/\s*,\s*/, $3);
1479
 
1480
            ## Fix $opt spacing
1481
            $opt =~ s/(\&\&|\|\|)/ $1 /g;
1482
            $opt =~ s/!\s+/!/g;
1483
 
1484
            if (!defined $self->{'generated_exts'}->{$tag}->
1485
                                {'optional'}->{$optname}) {
1486
              $self->{'generated_exts'}->{$tag}->
1487
                     {'optional'}->{$optname} = {};
1488
            }
1489
            if (!defined $self->{'generated_exts'}->{$tag}->
1490
                                {'optional'}->{$optname}->{$name}) {
1491
              $self->{'generated_exts'}->{$tag}->
1492
                     {'optional'}->{$optname}->{$name} = {};
1493
            }
1494
            if (!defined $self->{'generated_exts'}->{$tag}->
1495
                                {'optional'}->{$optname}->{$name}->{$opt}) {
1496
              $self->{'generated_exts'}->{$tag}->
1497
                     {'optional'}->{$optname}->{$name}->{$opt} = [];
1498
            }
1499
            push(@{$self->{'generated_exts'}->{$tag}->{'optional'}->
1500
                    {$optname}->{$name}->{$opt}}, @val);
1501
          }
1502
        }
1503
      }
1504
      elsif ($line =~ /^}$/) {
1505
        $status = 1;
1506
        $errorString = undef;
1507
 
1508
        ## Propagate the custom defined values into the mapped values
1509
        foreach my $key (keys %{$self->{'valid_names'}}) {
1510
          if (UNIVERSAL::isa($self->{'valid_names'}->{$key}, 'ARRAY')) {
1511
            my($value) = $self->{'generated_exts'}->{$tag}->{
1512
                                   $self->{'valid_names'}->{$key}->[1]};
1513
            if (defined $value) {
1514
              ## Bypass the process_assignment() defined in this class
1515
              ## to avoid unwanted keyword mapping.
1516
              $self->SUPER::process_assignment($key, $value);
1517
            }
1518
          }
1519
        }
1520
 
1521
        ## Set some defaults (if they haven't already been set)
1522
        if (!defined $self->{'generated_exts'}->{$tag}->{'pre_filename'}) {
1523
          $self->{'generated_exts'}->{$tag}->{'pre_filename'} = [ '' ];
1524
        }
1525
        if (!defined $self->{'generated_exts'}->{$tag}->{'pre_extension'}) {
1526
          $self->{'generated_exts'}->{$tag}->{'pre_extension'} = [ '' ];
1527
        }
1528
        if (!defined $self->{'generated_exts'}->{$tag}->{'automatic'}) {
1529
          $self->{'generated_exts'}->{$tag}->{'automatic'} = 1;
1530
        }
1531
        if (!defined $self->{'valid_components'}->{$tag}) {
1532
          $self->{'valid_components'}->{$tag} = [];
1533
        }
1534
        last;
1535
      }
1536
      else {
1537
        my(@values) = ();
1538
        ## If this returns true, then we've found an assignment
1539
        if ($self->parse_assignment($line, \@values)) {
1540
          my($type)  = $values[0];
1541
          my($name)  = $values[1];
1542
          my($value) = $values[2];
1543
          if (defined $customDefined{$name}) {
1544
            if (($customDefined{$name} & 0x01) != 0) {
1545
              $value = $self->escape_regex_special($value);
1546
              my(@array) = split(/\s*,\s*/, $value);
1547
              $self->process_array_assignment(
1548
                        \$self->{'valid_components'}->{$tag}, $type, \@array);
1549
            }
1550
            else {
1551
              if (!defined $self->{'generated_exts'}->{$tag}) {
1552
                $self->{'generated_exts'}->{$tag} = {};
1553
              }
1554
              ## Try to convert the value into a relative path
1555
              $value = $self->relative($value);
1556
 
1557
              if (($customDefined{$name} & 0x04) != 0) {
217 bj 1558
                if ($type eq '=') {
107 bj 1559
                  $self->process_assignment(
1560
                                     $name, $value,
1561
                                     $self->{'generated_exts'}->{$tag});
1562
                }
217 bj 1563
                elsif ($type eq '+=') {
107 bj 1564
                  $self->process_assignment_add(
1565
                                     $name, $value,
1566
                                     $self->{'generated_exts'}->{$tag});
1567
                }
217 bj 1568
                elsif ($type eq '-=') {
107 bj 1569
                  $self->process_assignment_sub(
1570
                                     $name, $value,
1571
                                     $self->{'generated_exts'}->{$tag});
1572
                }
1573
              }
1574
              else {
1575
                if (($customDefined{$name} & 0x02) != 0) {
1576
                  ## Transform the name from something outputext to
1577
                  ## something files.  We expect this to match the
1578
                  ## names of valid_assignments.
1579
                  $name =~ s/outputext/files/g;
1580
                }
1581
 
1582
                ## Get it ready for regular expressions
1583
                $value = $self->escape_regex_special($value);
1584
 
1585
                ## Process the array assignment
1586
                my(@array) = split(/\s*,\s*/, $value);
1587
                $self->process_array_assignment(
1588
                            \$self->{'generated_exts'}->{$tag}->{$name},
1589
                            $type, \@array);
1590
              }
1591
            }
1592
          }
1593
          else {
1594
            $status = 0;
1595
            $errorString = "Invalid assignment name: $name";
1596
            last;
1597
          }
1598
        }
1599
        elsif ($line =~ /^(\w+)\s+(\w+)(\s*=\s*(\w+)?)?/) {
1600
          ## Check for keyword mapping here
1601
          my($keyword) = $1;
1602
          my($newkey)  = $2;
1603
          my($mapkey)  = $4;
1604
          if ($keyword eq 'keyword') {
1605
            if (defined $self->{'valid_names'}->{$newkey}) {
1606
              $status = 0;
1607
              $errorString = "Cannot map $newkey onto an " .
1608
                             "existing keyword";
1609
              last;
1610
            }
1611
            elsif (!defined $mapkey) {
1612
              $self->{'valid_names'}->{$newkey} = 1;
1613
            }
1614
            elsif ($newkey ne $mapkey) {
1615
              if (defined $customDefined{$mapkey}) {
1616
                $self->{'valid_names'}->{$newkey} = [ $tag, $mapkey ];
1617
              }
1618
              else {
1619
                $status = 0;
1620
                $errorString = "Cannot map $newkey to an " .
1621
                               "undefined custom keyword: $mapkey";
1622
                last;
1623
              }
1624
            }
1625
            else {
1626
              $status = 0;
1627
              $errorString = "Cannot map $newkey to $mapkey";
1628
              last;
1629
            }
1630
          }
1631
          else {
1632
            $status = 0;
1633
            $errorString = "Unrecognized line: $line";
1634
            last;
1635
          }
1636
        }
1637
        else {
1638
          $status = 0;
1639
          $errorString = "Unrecognized line: $line";
1640
          last;
1641
        }
1642
      }
1643
    }
1644
  }
1645
 
1646
  return $status, $errorString;
1647
}
1648
 
1649
 
1650
sub remove_duplicate_addition {
217 bj 1651
  my($self)  = shift;
1652
  my($name)  = shift;
1653
  my($value) = shift;
1654
  my($nval)  = shift;
107 bj 1655
 
217 bj 1656
  if (defined $nval) {
1657
    ## If we are modifying the libs, libpaths, macros or includes
1658
    ## assignment with either addition or subtraction, we are going to
1659
    ## perform a little fix on the value to avoid multiple
1660
    ## libraries and to try to insure the correct linking order
1661
    if ($name eq 'macros' || $name eq 'libpaths' ||
1662
        $name eq 'includes' || $name =~ /libs$/ ||
1663
        index($name, $grouped_key) == 0) {
107 bj 1664
      my($allowed) = '';
1665
      my(%parts)   = ();
1666
 
1667
      ## Convert the array into keys for a hash table
1668
      @parts{@{$self->create_array($nval)}} = ();
1669
 
1670
      ## In order to ensure that duplicates are correctly removed, we
1671
      ## need to get the modified assignment value before we attempt to
1672
      ## do so.
1673
      $value = $self->modify_assignment_value($name, $value);
1674
      foreach my $val (@{$self->create_array($value)}) {
1675
        if (!exists $parts{$val}) {
198 bj 1676
          my($qt) = ($val =~ /\s/ ? '"' : '');
1677
          $allowed .= $qt . $val . $qt . ' ';
107 bj 1678
        }
1679
      }
1680
      $allowed =~ s/\s+$//;
1681
      return $allowed;
1682
    }
1683
  }
1684
 
1685
  return $value;
1686
}
1687
 
1688
 
1689
sub read_template_input {
1690
  my($self)        = shift;
1691
  my($status)      = 1;
1692
  my($errorString) = undef;
1693
  my($file)        = undef;
1694
  my($tag)         = undef;
1695
  my($ti)          = $self->get_ti_override();
1696
  my($override)    = undef;
1697
 
1698
  if ($self->exe_target()) {
1699
    if ($self->get_static() == 1) {
1700
      $tag = 'lexe_template_input';
1701
      if (!defined $self->{$tag}) {
1702
        if (defined $$ti{'lib_exe'}) {
1703
          $file = $$ti{'lib_exe'};
1704
          $override = 1;
1705
        }
1706
        else {
1707
          $file = $self->get_lib_exe_template_input_file();
1708
        }
1709
      }
1710
    }
1711
    else {
1712
      $tag = 'dexe_template_input';
1713
      if (!defined $self->{$tag}) {
1714
        if (defined $$ti{'dll_exe'}) {
1715
          $file = $$ti{'dll_exe'};
1716
          $override = 1;
1717
        }
1718
        else {
1719
          $file = $self->get_dll_exe_template_input_file();
1720
        }
1721
      }
1722
    }
1723
  }
1724
  else {
1725
    if ($self->get_static() == 1) {
1726
      $tag = 'lib_template_input';
1727
      if (!defined $self->{$tag}) {
1728
        if (defined $$ti{'lib'}) {
1729
          $file = $$ti{'lib'};
1730
          $override = 1;
1731
        }
1732
        else {
1733
          $file = $self->get_lib_template_input_file();
1734
        }
1735
      }
1736
    }
1737
    else {
1738
      $tag = 'dll_template_input';
1739
      if (!defined $self->{$tag}) {
1740
        if (defined $$ti{'dll'}) {
1741
          $file = $$ti{'dll'};
1742
          $override = 1;
1743
        }
1744
        else {
1745
          $file = $self->get_dll_template_input_file();
1746
        }
1747
      }
1748
    }
1749
  }
1750
 
1751
  if (defined $file) {
1752
    my($file) = $self->search_include_path("$file.$TemplateInputExtension");
1753
    if (defined $file) {
1754
      $self->{$tag} = new TemplateInputReader($self->get_include_path());
1755
      ($status, $errorString) = $self->{$tag}->cached_file_read($file);
1756
    }
1757
    else {
1758
      if ($override) {
1759
        $status = 0;
1760
        $errorString = 'Unable to locate template input file.';
1761
      }
1762
    }
1763
  }
1764
 
217 bj 1765
  if ($status && defined $self->{$tag}) {
1766
    ## Put the features into the template input set
1767
    my($features) = $self->{'feature_parser'}->get_names();
1768
    $self->{$tag}->parse_line(undef, "features = @$features");
1769
  }
1770
 
107 bj 1771
  return $status, $errorString;
1772
}
1773
 
1774
 
1775
sub already_added {
1776
  my($self)  = shift;
1777
  my($array) = shift;
1778
  my($name)  = shift;
1779
 
217 bj 1780
  ## This method expects that the file name will be unix style
1781
  $name =~ s/\\/\//g if ($self->{'convert_slashes'});
107 bj 1782
 
217 bj 1783
  ## Remove the leading ./
1784
  $name =~ s/^\.\///;
1785
  my($dsname) = "./$name";
1786
 
107 bj 1787
  foreach my $file (@$array) {
217 bj 1788
    return 1 if ($file eq $name || $file eq $dsname);
107 bj 1789
  }
1790
 
1791
  return 0;
1792
}
1793
 
1794
 
1795
sub get_applied_custom_keyword {
1796
  my($self)  = shift;
1797
  my($name)  = shift;
1798
  my($type)  = shift;
1799
  my($file)  = shift;
1800
  my($value) = undef;
1801
 
1802
  if (defined $self->{'flag_overrides'}->{$type}->{$file}->{$name}) {
1803
    $value = $self->{'flag_overrides'}->{$type}->{$file}->{$name};
1804
  }
1805
  else {
1806
    $value = $self->get_assignment($name,
1807
                                   $self->{'generated_exts'}->{$type});
1808
  }
1809
  return $self->relative($value, 1);
1810
}
1811
 
1812
 
1813
sub evaluate_optional_option {
1814
  my($self)  = shift;
1815
  my($opt)   = shift;
1816
  my($value) = shift;
1817
 
1818
  if ($opt =~ /^!\s*(.*)/) {
1819
    return (!exists $$value{$1} ? 1 : 0);
1820
  }
1821
  else {
1822
    return (exists $$value{$opt} ? 1 : 0);
1823
  }
1824
 
1825
  return 0;
1826
}
1827
 
1828
 
1829
sub process_optional_option {
1830
  my($self)   = shift;
1831
  my($opt)    = shift;
1832
  my($value)  = shift;
1833
  my($status) = undef;
1834
  my(@parts)  = grep(!/^$/, split(/\s+/, $opt));
217 bj 1835
  my($pcount) = scalar(@parts);
107 bj 1836
 
217 bj 1837
  for(my $i = 0; $i < $pcount; $i++) {
107 bj 1838
    if ($parts[$i] eq '&&' || $parts[$i] eq '||') {
1839
      if (defined $status) {
1840
        if (defined $parts[$i + 1]) {
1841
          if ($parts[$i] eq '&&') {
1842
            $status &&= $self->evaluate_optional_option($parts[$i + 1],
1843
                                                        $value);
1844
          }
1845
          else {
1846
            $status ||= $self->evaluate_optional_option($parts[$i + 1],
1847
                                                        $value);
1848
          }
1849
        }
1850
        else {
1851
          $self->warning("Expected token in optional after $parts[$i]");
1852
        }
1853
      }
1854
      else {
1855
        $self->warning("Unexpected token in optional: $parts[$i]");
1856
      }
1857
      ++$i;
1858
    }
1859
    else {
1860
      if (!defined $status) {
1861
        $status = $self->evaluate_optional_option($parts[$i], $value);
1862
      }
1863
      else {
1864
        $self->warning("Unexpected token in optional: $parts[$i]");
1865
      }
1866
    }
1867
  }
1868
 
1869
  return $status;
1870
}
1871
 
1872
 
1873
sub add_optional_filename_portion {
1874
  my($self)    = shift;
1875
  my($gentype) = shift;
1876
  my($tag)     = shift;
1877
  my($file)    = shift;
1878
  my($array)   = shift;
1879
 
1880
  foreach my $name (keys %{$self->{'generated_exts'}->{$gentype}->{'optional'}->{$tag}}) {
1881
    foreach my $opt (keys %{$self->{'generated_exts'}->{$gentype}->{'optional'}->{$tag}->{$name}}) {
1882
      ## Get the name value
1883
      my($value) = $self->get_applied_custom_keyword($name,
1884
                                                     $gentype, $file);
1885
 
1886
      ## Convert the value into a hash map for easy lookup
1887
      my(%values) = ();
1888
      if (defined $value) {
1889
        @values{split(/\s+/, $value)} = ();
1890
      }
1891
 
1892
      ## See if the option or options are contained in the value
1893
      if ($self->process_optional_option($opt, \%values)) {
1894
        ## Add the optional portion
1895
        push(@$array, @{$self->{'generated_exts'}->{$gentype}->{'optional'}->{$tag}->{$name}->{$opt}});
1896
      }
1897
    }
1898
  }
1899
}
1900
 
1901
 
1902
sub get_pre_keyword_array {
1903
  my($self)    = shift;
1904
  my($keyword) = shift;
1905
  my($gentype) = shift;
1906
  my($tag)     = shift;
1907
  my($file)    = shift;
1908
 
1909
  ## Get the general pre extension array
1910
  my(@array) = @{$self->{'generated_exts'}->{$gentype}->{$keyword}};
1911
 
1912
  ## Add the component specific pre extension array
1913
  my(@additional) = ();
1914
  $tag =~ s/files$/$keyword/;
1915
  if (defined $self->{'generated_exts'}->{$gentype}->{$tag}) {
1916
    push(@additional, @{$self->{'generated_exts'}->{$gentype}->{$tag}});
1917
  }
1918
 
1919
  ## Add in any optional portion to the array
1920
  foreach my $itag ($keyword, $tag) {
1921
    $self->add_optional_filename_portion($gentype, $itag,
1922
                                         $file, \@additional);
1923
  }
1924
 
1925
  ## If the current array only has the default,
1926
  ## then we need to remove it
217 bj 1927
  if (defined $additional[0]) {
107 bj 1928
    if ($#array == 0 && $array[0] eq '') {
1929
      pop(@array);
1930
    }
1931
    push(@array, @additional);
1932
  }
1933
 
1934
  return @array;
1935
}
1936
 
1937
 
217 bj 1938
sub add_explicit_output {
1939
  my($self)  = shift;
1940
  my($file)  = shift;
1941
  my($type)  = shift;
1942
  my($tag)   = shift;
1943
  my($array) = shift;
1944
 
1945
  if (defined $self->{'valid_components'}->{$tag} &&
1946
      defined $self->{'custom_special_output'}->{$type} &&
1947
      defined $self->{'custom_special_output'}->{$type}->{$file}) {
1948
    my(@files) = ();
1949
    foreach my $check (@{$self->{'custom_special_output'}->{$type}->{$file}}) {
1950
      foreach my $regext (@{$self->{'valid_components'}->{$tag}}) {
1951
        if ($check =~ /$regext$/) {
1952
          my($add) = 1;
1953
          if ($tag eq 'source_files') {
1954
            foreach my $tregext (@{$self->{'valid_components'}->{'template_files'}}) {
1955
              if ($check =~ /$tregext$/) {
1956
                $add = undef;
1957
                last;
1958
              }
1959
            }
1960
          }
1961
          if ($add) {
1962
            ## If gendir was specified, then we need to account for that
1963
            my($dir) = '';
1964
            if (defined $self->{'flag_overrides'}->{$type} &&
1965
                defined $self->{'flag_overrides'}->{$type}->{$file} &&
1966
                defined $self->{'flag_overrides'}->{$type}->{$file}->{'gendir'}) {
1967
              if ($self->{'flag_overrides'}->{$type}->{$file}->{'gendir'} eq '.') {
1968
                $dir = '';
1969
              }
1970
              else {
1971
                $dir = $self->{'flag_overrides'}->{$type}->{$file}->{'gendir'} . '/';
1972
              }
1973
            }
1974
 
1975
            push(@files, "$dir$check");
1976
            last;
1977
          }
1978
        }
1979
      }
1980
    }
1981
    if (defined $files[0]) {
1982
      push(@$array, \@files);
1983
    }
1984
  }
1985
}
1986
 
107 bj 1987
sub generated_filename_arrays {
1988
  my($self)  = shift;
1989
  my($part)  = shift;
1990
  my($type)  = shift;
1991
  my($tag)   = shift;
1992
  my($file)  = shift;
1993
  my($noext) = shift;
1994
  my(@array) = ();
1995
  my(@pearr) = $self->get_pre_keyword_array('pre_extension',
1996
                                            $type, $tag, $file);
1997
  my(@pfarr) = $self->get_pre_keyword_array('pre_filename',
1998
                                            $type, $tag, $file);
1999
  my(@exts)  = (defined $self->{'generated_exts'}->{$type}->{$tag} ?
2000
                  @{$self->{'generated_exts'}->{$type}->{$tag}} : ());
2001
 
217 bj 2002
  if (!defined $exts[0]) {
107 bj 2003
    my($backtag) = $tag;
2004
    if ($backtag =~ s/files$/outputext/) {
2005
      $self->add_optional_filename_portion($type, $backtag,
2006
                                           $file, \@exts);
2007
    }
2008
  }
2009
 
217 bj 2010
  if (!defined $exts[0] && $#pearr == 0 && $#pfarr == 0 &&
107 bj 2011
      $pearr[0] eq '' && $pfarr[0] eq '') {
2012
    ## If both arrays are defined to be the defaults, then there
2013
    ## is nothing for us to do.
2014
  }
2015
  else {
2016
    my($dir)  = '';
2017
    my($base) = undef;
2018
 
2019
    ## Correctly deal with pre filename and directories
2020
    if ($part =~ /(.*[\/\\])([^\/\\]+)$/) {
2021
      $dir = $1;
2022
      $base = $2;
2023
    }
2024
    else {
2025
      $base = $part;
2026
    }
2027
 
2028
    ## If gendir was specified, then we need to account for that
2029
    if (defined $self->{'flag_overrides'}->{$type} &&
2030
        defined $self->{'flag_overrides'}->{$type}->{$file} &&
2031
        defined $self->{'flag_overrides'}->{$type}->{$file}->{'gendir'}) {
2032
      if ($self->{'flag_overrides'}->{$type}->{$file}->{'gendir'} eq '.') {
2033
        $dir = '';
2034
      }
2035
      else {
2036
        $dir = $self->{'flag_overrides'}->{$type}->{$file}->{'gendir'} . '/';
2037
      }
2038
    }
2039
 
2040
    ## Loop through creating all of the possible file names
2041
    foreach my $pe (@pearr) {
2042
      push(@array, []);
217 bj 2043
      $pe =~ s/\\\././g;
107 bj 2044
      foreach my $pf (@pfarr) {
217 bj 2045
        $pf =~ s/\\\././g;
107 bj 2046
        if ($noext) {
2047
          push(@{$array[$#array]}, "$dir$pf$base$pe");
2048
        }
2049
        else {
2050
          foreach my $ext (@exts) {
217 bj 2051
            $ext =~ s/\\\././g;
107 bj 2052
            push(@{$array[$#array]}, "$dir$pf$base$pe$ext");
2053
          }
2054
        }
2055
      }
2056
    }
2057
  }
2058
 
217 bj 2059
  $self->add_explicit_output($file, $type, $tag, \@array);
107 bj 2060
  return @array;
2061
}
2062
 
2063
 
2064
sub generated_filenames {
2065
  my($self)  = shift;
2066
  my(@files) = ();
2067
 
217 bj 2068
  foreach my $array ($self->generated_filename_arrays(@_)) {
107 bj 2069
    push(@files, @$array);
2070
  }
2071
 
2072
  return @files;
2073
}
2074
 
2075
 
2076
sub add_generated_files {
2077
  my($self)    = shift;
2078
  my($gentype) = shift;
2079
  my($tag)     = shift;
2080
  my($group)   = shift;
2081
  my($arr)     = shift;
2082
 
2083
  ## This method is called by list_default_generated.  It performs the
2084
  ## actual file insertion and grouping.
2085
 
2086
  my($wanted) = $self->{'valid_components'}->{$gentype}->[0];
2087
  if (defined $wanted) {
2088
    ## Remove the escape sequences for the wanted extension.  It doesn't
2089
    ## matter if the first valid extension is not the same as the actual
2090
    ## input file (ex. input = car.y and first ext is .yy).  The extension
2091
    ## is immediately removed in generated_filename_arrays.
2092
    $wanted =~ s/\\//g;
2093
  }
2094
  else {
2095
    $wanted = '';
2096
  }
2097
 
2098
  ## Get the generated filenames
2099
  my(@added) = ();
2100
  foreach my $file (@$arr) {
2101
    foreach my $gen ($self->generated_filenames($file, $gentype, $tag,
217 bj 2102
                                                "$file$wanted", 1)) {
107 bj 2103
      $self->list_generated_file($gentype, $tag, \@added, $gen, $file);
2104
    }
2105
  }
2106
 
217 bj 2107
  if (defined $added[0]) {
107 bj 2108
    my($names) = $self->{$tag};
2109
 
2110
    ## Get all files in one list and save the directory
2111
    ## and component group in a hashed array.
2112
    my(@all) = ();
2113
    my(%dircomp) = ();
2114
    foreach my $name (keys %$names) {
2115
      foreach my $key (keys %{$$names{$name}}) {
2116
        push(@all, @{$$names{$name}->{$key}});
2117
        foreach my $file (@{$$names{$name}->{$key}}) {
2118
          $dircomp{$self->mpc_dirname($file)} = $key;
2119
        }
2120
      }
2121
    }
2122
 
2123
    ## Create a small array of only the files we want to add.
2124
    ## We put them all together so we can keep them in order when
2125
    ## we put them at the front of the main file list.
2126
    my(@oktoadd) = ();
2127
    foreach my $file (@added) {
2128
      if (!$self->already_added(\@all, $file)) {
2129
        push(@oktoadd, $file);
2130
      }
2131
    }
2132
 
2133
    ## If we have files to add, make sure we add them to a group
2134
    ## that has the same directory location as the files we're adding.
217 bj 2135
    if (defined $oktoadd[0]) {
107 bj 2136
      my($key) = (defined $group ? $group :
2137
                          $dircomp{$self->mpc_dirname($oktoadd[0])});
2138
      if (!defined $key) {
2139
        my($check) = $oktoadd[0];
2140
        foreach my $regext (@{$self->{'valid_components'}->{$tag}}) {
2141
          if ($check =~ s/$regext$//) {
2142
            last;
2143
          }
2144
        }
2145
        foreach my $vc (keys %{$self->{'valid_components'}}) {
2146
          if ($vc ne $tag) {
2147
            foreach my $name (keys %{$self->{$vc}}) {
2148
              foreach my $ckey (keys %{$self->{$vc}->{$name}}) {
2149
                if ($ckey ne $defgroup) {
2150
                  foreach my $ofile (@{$self->{$vc}->{$name}->{$ckey}}) {
2151
                    my($file) = $ofile;
2152
                    foreach my $regext (@{$self->{'valid_components'}->{$vc}}) {
2153
                      if ($file =~ s/$regext//) {
2154
                        last;
2155
                      }
2156
                    }
2157
                    if ($file eq $check) {
2158
                      $key = $ckey;
2159
                      last;
2160
                    }
2161
                  }
2162
                }
2163
                last if (defined $key);
2164
              }
2165
            }
2166
            last if (defined $key);
2167
          }
2168
        }
2169
        if (!defined $key) {
2170
          $key = $defgroup;
2171
        }
2172
      }
2173
      foreach my $name (keys %$names) {
2174
        if (!defined $$names{$name}->{$key}) {
2175
          if ($key ne $defgroup &&
2176
              defined $$names{$name}->{$defgroup} &&
2177
              defined $$names{$name}->{$defgroup}->[0]) {
2178
            $self->process_assignment_add($grouped_key . $tag, $defgroup);
2179
          }
2180
          $$names{$name}->{$key} = [];
2181
          $self->process_assignment_add($grouped_key . $tag, $key);
2182
        }
2183
        unshift(@{$$names{$name}->{$key}}, @oktoadd);
2184
      }
2185
    }
2186
  }
2187
}
2188
 
2189
 
2190
sub search_for_entry {
2191
  my($self)    = shift;
2192
  my($file)    = shift;
2193
  my($main)    = shift;
2194
  my($preproc) = shift;
2195
  my($name)    = undef;
2196
  my($fh)      = new FileHandle();
2197
 
2198
  if (open($fh, $file)) {
2199
    my($poundifed) = 0;
2200
    my($commented) = 0;
2201
 
2202
    while(<$fh>) {
217 bj 2203
      if (!$commented) {
107 bj 2204
        ## Remove c++ style comments
2205
        $_ =~ s/\/\/.*//;
2206
      }
2207
 
217 bj 2208
      ## Remove one line c style comments
2209
      $_ =~ s/\/\*.*\*\///g;
107 bj 2210
 
217 bj 2211
      if ($commented) {
2212
        if (/\*\//) {
2213
          ## Found the end of a multi-line c style comment
2214
          --$commented;
107 bj 2215
        }
217 bj 2216
      }
2217
      else {
2218
        if (/\/\*/) {
2219
          ## Found the beginning of a multi-line c style comment
2220
          ++$commented;
2221
        }
2222
        elsif ($preproc) {
2223
          ## If the current language supports a c preprocessor, we
2224
          ## will perform a minimal check for #if 0
2225
          if (/#\s*if\s+0/) {
107 bj 2226
            ## Found the beginning of a #if 0
2227
            ++$poundifed;
2228
          }
2229
          elsif ($poundifed) {
2230
            if (/#\s*if/) {
2231
              ## We need to keep track of any other #if directives
2232
              ## to be sure that when we see an #endif we don't
2233
              ## count the wrong one.
2234
              ++$poundifed;
2235
            }
2236
            elsif (/#\s*endif/) {
2237
              ## Found a #endif, so decrement our count
2238
              --$poundifed;
2239
            }
2240
          }
2241
        }
2242
      }
2243
 
2244
      ## Check for main; Make sure it's not #if 0'ed and not commented out
2245
      if (!$poundifed && !$commented &&
2246
          (/\s+$main\s*\(/ || /^\s*$main\s*\(/)) {
2247
        ## If we've found a main, set the exename to the basename
2248
        ## of the cpp file with the extension removed
217 bj 2249
        $name = $self->mpc_basename($file);
107 bj 2250
        $name =~ s/\.[^\.]+$//;
2251
        last;
2252
      }
2253
    }
2254
    close($fh);
2255
  }
2256
  return $name;
2257
}
2258
 
2259
 
2260
sub generate_default_target_names {
2261
  my($self) = shift;
2262
 
2263
  if (!$self->exe_target()) {
2264
    my($sharedname) = $self->get_assignment('sharedname');
2265
    my($staticname) = $self->get_assignment('staticname');
2266
    my($shared_empty) = undef;
2267
 
2268
    if (defined $sharedname) {
2269
      if ($sharedname eq '') {
2270
        $shared_empty = 1;
2271
        $sharedname = undef;
2272
        $self->process_assignment('sharedname', $sharedname);
2273
      }
2274
      elsif (!defined $staticname) {
2275
        $staticname = $sharedname;
2276
        $self->process_assignment('staticname', $staticname);
2277
      }
2278
    }
2279
    if (defined $staticname && !$shared_empty && !defined $sharedname) {
2280
      $sharedname = $staticname;
2281
      $self->process_assignment('sharedname', $sharedname);
2282
    }
2283
 
2284
    ## If it's neither an exe or library target, we will search
2285
    ## through the source files for a main()
2286
    if (!$self->lib_target()) {
2287
      my($exename) = undef;
2288
      my(@sources) = $self->get_component_list('source_files', 1);
2289
      my($main)    = $language{$self->get_language()}->[3];
2290
      my($preproc) = $language{$self->get_language()}->[4];
2291
 
2292
      foreach my $file (@sources) {
2293
        $exename = $self->search_for_entry($file, $main, $preproc);
2294
 
2295
        ## Set the exename assignment
2296
        if (defined $exename) {
2297
          $self->process_assignment('exename', $exename);
2298
          last;
2299
        }
2300
      }
2301
 
2302
      ## If we still don't have a project type, then we will
2303
      ## default to a library if there are source or resource files
2304
      if (!defined $exename) {
217 bj 2305
        if (!defined $sources[0]) {
107 bj 2306
          @sources = $self->get_component_list('resource_files', 1);
2307
        }
217 bj 2308
        if (defined $sources[0]) {
107 bj 2309
          if (!$shared_empty) {
2310
            $self->process_assignment('sharedname',
2311
                                      $self->{'unmodified_project_name'});
2312
          }
2313
          $self->process_assignment('staticname',
2314
                                    $self->{'unmodified_project_name'});
2315
        }
2316
      }
2317
    }
2318
  }
2319
 
2320
  ## If we are generating only static projects, then we need to
2321
  ## unset the sharedname, so that we can insure that projects of
2322
  ## various types only generate static targets.
2323
  if ($self->get_static() == 1) {
2324
    my($sharedname) = $self->get_assignment('sharedname');
2325
    if (defined $sharedname) {
2326
      $self->process_assignment('sharedname', undef);
2327
    }
2328
  }
2329
 
2330
  ## Check for the use of an asterisk in the name
2331
  foreach my $key ('exename', 'sharedname', 'staticname') {
2332
    my($value) = $self->get_assignment($key);
217 bj 2333
    if (defined $value && index($value, '*') >= 0) {
107 bj 2334
      $value = $self->fill_type_name($value,
2335
                                     $self->{'unmodified_project_name'});
2336
      $self->process_assignment($key, $value);
2337
    }
2338
  }
2339
}
2340
 
2341
 
2342
sub generate_default_pch_filenames {
2343
  my($self)    = shift;
2344
  my($files)   = shift;
2345
  my($pchhdef) = (defined $self->get_assignment('pch_header'));
2346
  my($pchcdef) = (defined $self->get_assignment('pch_source'));
2347
 
2348
  if (!$pchhdef || !$pchcdef) {
217 bj 2349
    my($pname)     = $self->get_assignment('project_name');
107 bj 2350
    my($hcount)    = 0;
2351
    my($ccount)    = 0;
2352
    my($hmatching) = undef;
2353
    my($cmatching) = undef;
2354
    foreach my $file (@$files) {
2355
      ## If the file doesn't even contain _pch, then there's no point
2356
      ## in looping through all of the extensions
217 bj 2357
      if (index($file, '_pch') >= 0) {
107 bj 2358
        if (!$pchhdef) {
2359
          foreach my $ext (@{$self->{'valid_components'}->{'header_files'}}) {
2360
            if ($file =~ /(.*_pch$ext)$/) {
2361
              $self->process_assignment('pch_header', $1);
2362
              ++$hcount;
217 bj 2363
              if (index($file, $pname) >= 0) {
107 bj 2364
                $hmatching = $file;
2365
              }
2366
              last;
2367
            }
2368
          }
2369
        }
2370
        if (!$pchcdef) {
2371
          foreach my $ext (@{$self->{'valid_components'}->{'source_files'}}) {
2372
            if ($file =~ /(.*_pch$ext)$/) {
2373
              $self->process_assignment('pch_source', $1);
2374
              ++$ccount;
217 bj 2375
              if (index($file, $pname) >= 0) {
107 bj 2376
                $cmatching = $file;
2377
              }
2378
              last;
2379
            }
2380
          }
2381
        }
2382
      }
2383
    }
2384
    if (!$pchhdef && $hcount > 1 && defined $hmatching) {
2385
      $self->process_assignment('pch_header', $hmatching);
2386
    }
2387
    if (!$pchcdef && $ccount > 1 && defined $cmatching) {
2388
      $self->process_assignment('pch_source', $cmatching);
2389
    }
2390
  }
2391
}
2392
 
2393
 
2394
sub fix_pch_filenames {
2395
  my($self) = shift;
2396
  foreach my $type ('pch_header', 'pch_source') {
2397
    my($pch) = $self->get_assignment($type);
2398
    if (defined $pch && $pch eq '') {
2399
      $self->process_assignment($type, undef);
2400
    }
2401
  }
2402
}
2403
 
2404
 
2405
sub remove_extra_pch_listings {
2406
  my($self) = shift;
2407
  my(@pchs) = ('pch_header', 'pch_source');
2408
  my(@tags) = ('header_files', 'source_files');
2409
 
217 bj 2410
  for(my $j = 0; $j < 2; ++$j) {
107 bj 2411
    my($pch) = $self->get_assignment($pchs[$j]);
2412
 
2413
    if (defined $pch) {
2414
      ## If we are converting slashes, then we need to
2415
      ## convert the pch file back to forward slashes
217 bj 2416
      $pch =~ s/\\/\//g if ($self->{'convert_slashes'});
107 bj 2417
 
2418
      ## Find out which files are duplicated
2419
      my($names) = $self->{$tags[$j]};
2420
      foreach my $name (keys %$names) {
2421
        my($comps) = $$names{$name};
2422
        foreach my $key (keys %$comps) {
2423
          my($array) = $$comps{$key};
2424
          my($count) = scalar(@$array);
2425
          for(my $i = 0; $i < $count; ++$i) {
2426
            if ($pch eq $$array[$i]) {
2427
              splice(@$array, $i, 1);
2428
              --$count;
2429
            }
2430
          }
2431
        }
2432
      }
2433
    }
2434
  }
2435
}
2436
 
2437
 
2438
sub sift_files {
2439
  my($self)   = shift;
2440
  my($files)  = shift;
2441
  my($exts)   = shift;
2442
  my($pchh)   = shift;
2443
  my($pchc)   = shift;
2444
  my($tag)    = shift;
2445
  my($array)  = shift;
2446
  my($alldir) = shift;
2447
  my(@saved)  = ();
2448
  my($ec)     = $self->{'exclude_components'};
217 bj 2449
  my($havec)  = (defined $$ec{$tag});
107 bj 2450
 
2451
  foreach my $file (@$files) {
2452
    foreach my $ext (@$exts) {
2453
      ## Always exclude the precompiled header and cpp
2454
      if ($file =~ /$ext$/ && (!defined $pchh || $file ne $pchh) &&
2455
                              (!defined $pchc || $file ne $pchc)) {
217 bj 2456
        if ($havec) {
2457
          my($exclude) = 0;
107 bj 2458
          foreach my $exc (@{$$ec{$tag}}) {
2459
            if ($file =~ /$exc$/) {
2460
              $exclude = 1;
2461
              last;
2462
            }
2463
          }
217 bj 2464
          last if ($exclude);
107 bj 2465
        }
2466
        elsif (!$alldir && $tag eq 'resource_files') {
2467
          ## Save these files for later.  There may
2468
          ## be more than one and we want to try and
2469
          ## find the one that corresponds to this project
2470
          push(@saved, $file);
217 bj 2471
          last;
107 bj 2472
        }
2473
 
217 bj 2474
        if (!$self->already_added($array, $file)) {
107 bj 2475
          push(@$array, $file);
2476
        }
2477
        last;
2478
      }
2479
    }
2480
  }
2481
 
2482
  ## Now deal with the saved files
2483
  if (defined $saved[0]) {
217 bj 2484
    if (!defined $saved[1]) {
107 bj 2485
      ## Theres only one rc file, take it
2486
      push(@$array, $saved[0]);
2487
    }
2488
    else {
2489
      my($pjname) = $self->escape_regex_special(
2490
                              $self->transform_file_name(
2491
                                  $self->get_assignment('project_name')));
2492
      ## Use a case insensitive search.
2493
      ## After all, this is a Windows specific file type.
2494
      foreach my $save (@saved) {
2495
        if ($save =~ /$pjname/i) {
2496
          if (!$self->already_added($array, $save)) {
2497
            push(@$array, $save);
2498
          }
2499
        }
2500
      }
2501
    }
2502
  }
2503
}
2504
 
2505
 
2506
sub sift_default_file_list {
2507
  my($self)    = shift;
2508
  my($tag)     = shift;
2509
  my($file)    = shift;
2510
  my($built)   = shift;
2511
  my($exts)    = shift;
2512
  my($recurse) = shift;
2513
  my($pchh)    = shift;
2514
  my($pchc)    = shift;
2515
  my($alldir)  = $recurse ||
2516
                 $self->{'flag_overrides'}->{$tag}->{$file}->{'recurse'};
217 bj 2517
  my(@gen)     = $self->generate_default_file_list($file, [], undef, $alldir);
107 bj 2518
 
2519
  $self->sift_files(\@gen, $exts, $pchh, $pchc, $tag, $built, $alldir);
2520
}
2521
 
2522
 
2523
sub generate_default_components {
2524
  my($self)    = shift;
2525
  my($files)   = shift;
2526
  my($passed)  = shift;
2527
  my($vc)      = $self->{'valid_components'};
2528
  my(@tags)    = (defined $passed ? $passed : keys %$vc);
2529
  my($pchh)    = $self->get_assignment('pch_header');
2530
  my($pchc)    = $self->get_assignment('pch_source');
2531
  my($recurse) = $self->get_assignment('recurse');
2532
 
2533
  ## The order of @tags does make a difference in the way that generated
2534
  ## files get added.  And since the tags are user definable, there may be
2535
  ## a problem with that.
2536
  foreach my $tag (@tags) {
2537
    if (!defined $self->{'generated_exts'}->{$tag} ||
2538
        $self->{'generated_exts'}->{$tag}->{'automatic'}) {
2539
      my($exts) = $$vc{$tag};
2540
      if (defined $$exts[0]) {
2541
        if (defined $self->{$tag}) {
2542
          ## If the tag is defined, then process directories
2543
          my($names) = $self->{$tag};
2544
          foreach my $name (keys %$names) {
2545
            my($comps) = $$names{$name};
2546
            foreach my $comp (keys %$comps) {
2547
              my($array) = $$comps{$comp};
2548
              if (defined $passed) {
2549
                $self->sift_files($files, $exts, $pchh, $pchc, $tag, $array);
2550
              }
2551
              else {
2552
                my(@built) = ();
2553
                foreach my $file (@$array) {
2554
                  if (-d $file) {
2555
                    $self->sift_default_file_list($tag, $file, \@built,
2556
                                                  $exts, $recurse, $pchh, $pchc);
2557
                  }
2558
                  else {
2559
                    if (!$self->already_added(\@built, $file)) {
2560
                      push(@built, $file);
2561
                    }
2562
                  }
2563
                }
2564
                $$comps{$comp} = \@built;
2565
              }
2566
            }
2567
          }
2568
        }
2569
        else {
2570
          ## Generate default values for undefined tags
2571
          my($defcomp) = $self->get_default_component_name();
2572
          $self->{$tag} = {};
2573
          my($comps) = {};
2574
          $self->{$tag}->{$defcomp} = $comps;
2575
          $$comps{$defgroup} = [];
2576
          my($array) = $$comps{$defgroup};
2577
 
2578
          $self->{'defaulted'}->{$tag} = 1;
2579
 
2580
          if (!defined $specialComponents{$tag}) {
2581
            $self->sift_files($files, $exts, $pchh, $pchc, $tag, $array);
2582
            if (defined $sourceComponents{$tag}) {
2583
              my($grtag) = $grouped_key . $tag;
2584
              foreach my $gentype (keys %{$self->{'generated_exts'}}) {
2585
                ## If we are auto-generating the source_files, then
2586
                ## we need to make sure that any generated source
2587
                ## files that are added are put at the front of the list.
2588
                my($newgroup) = undef;
2589
                my(@input) = ();
2590
 
2591
                ## If I call keys %{$self->{$gentype}} using perl 5.6.1
2592
                ## it returns nothing.  I have to put it in an
2593
                ## intermediate variable to ensure that I get the keys.
2594
                my($names) = $self->{$gentype};
2595
                foreach my $name (keys %$names) {
2596
                  foreach my $key (keys %{$$names{$name}}) {
2597
                    push(@input, @{$$names{$name}->{$key}});
2598
                    if ($key ne $defgroup) {
2599
                      $newgroup = $key;
2600
                    }
2601
                  }
2602
                }
2603
 
217 bj 2604
                if (defined $input[0]) {
107 bj 2605
                  my(@front) = ();
2606
                  my(@copy)  = @$array;
2607
 
2608
                  @$array = ();
2609
                  foreach my $input (@input) {
198 bj 2610
                    my($part) = $self->remove_wanted_extension(
2611
                                   $input,
2612
                                   $self->{'valid_components'}->{$gentype});
2613
 
107 bj 2614
                    my(@files) = $self->generated_filenames($part, $gentype,
217 bj 2615
                                                            $tag, $input);
2616
                    if (defined $copy[0]) {
107 bj 2617
                      my($found) = 0;
2618
                      foreach my $file (@files) {
217 bj 2619
                        for(my $i = 0; $i < scalar(@copy); $i++) {
107 bj 2620
                          my($re) = $self->escape_regex_special($copy[$i]);
2621
                          if ($file eq $copy[$i] || $file =~ /[\/\\]$re$/) {
2622
                            ## No need to check for previously added files
2623
                            ## here since there are none.
2624
                            $found = 1;
2625
                            push(@front, $file);
2626
                            splice(@copy, $i, 1);
2627
                            last;
2628
                          }
2629
                        }
2630
                        if ($found) {
2631
                          last;
2632
                        }
2633
                      }
2634
                      if (!$found) {
2635
                        my($ext) = $$exts[0];
2636
                        foreach my $file (@files) {
2637
                          if ($file =~ /$ext$/) {
2638
                            push(@front, $file);
2639
                          }
2640
                        }
2641
                      }
2642
                    }
2643
                    else {
2644
                      my($ext) = $$exts[0];
2645
                      foreach my $file (@files) {
2646
                        if ($file =~ /$ext$/) {
2647
                          push(@front, $file);
2648
                        }
2649
                      }
2650
                    }
2651
                  }
217 bj 2652
                  if (defined $copy[0]) {
107 bj 2653
                    ## No need to check for previously added files
2654
                    ## here since there are none.
2655
                    push(@$array, @copy);
2656
                    if (defined $self->get_assignment($grtag)) {
2657
                      $self->process_assignment_add($grtag, $defgroup);
2658
                    }
2659
                  }
2660
                  if (defined $front[0]) {
2661
                    if (defined $newgroup) {
217 bj 2662
                      if (defined $copy[0]) {
107 bj 2663
                        $self->process_assignment_add($grtag, $defgroup);
2664
                      }
217 bj 2665
                      if (!defined $self->{$tag}->{$defcomp}->{$newgroup}) {
2666
                        $self->{$tag}->{$defcomp}->{$newgroup} = \@front;
2667
                      }
2668
                      else {
2669
                        push(@{$self->{$tag}->{$defcomp}->{$newgroup}}, @front);
2670
                      }
107 bj 2671
                      $self->process_assignment_add($grtag, $newgroup);
2672
                    }
2673
                    else {
2674
                      unshift(@$array, @front);
2675
                    }
2676
                  }
2677
                }
2678
              }
2679
            }
2680
          }
2681
        }
2682
      }
2683
    }
2684
  }
2685
}
2686
 
2687
 
2688
sub remove_duplicated_files {
2689
  my($self)   = shift;
2690
  my($dest)   = shift;
2691
  my($source) = shift;
2692
  my($names)  = $self->{$dest};
2693
  my(@slist)  = $self->get_component_list($source, 1);
2694
  my(%shash)  = ();
2695
 
2696
  ## Convert the array into keys for a hash table
2697
  @shash{@slist} = ();
2698
 
2699
  ## Find out which source files are listed
2700
  foreach my $name (keys %$names) {
2701
    foreach my $key (keys %{$$names{$name}}) {
2702
      my($array) = $$names{$name}->{$key};
2703
      my($count) = scalar(@$array);
2704
      for(my $i = 0; $i < $count; ++$i) {
2705
        ## Is the source file in the component array?
2706
        if (exists $shash{$$array[$i]}) {
2707
          ## Remove the element and fix the index and count
2708
          splice(@$array, $i, 1);
2709
          --$count;
2710
          --$i;
2711
        }
2712
      }
2713
    }
2714
  }
2715
}
2716
 
2717
 
2718
sub generated_source_listed {
2719
  my($self)  = shift;
2720
  my($gent)  = shift;
2721
  my($tag)   = shift;
2722
  my($arr)   = shift;
2723
  my($sext)  = shift;
2724
  my($names) = $self->{$tag};
2725
 
2726
  ## Find out which generated source files are listed
2727
  foreach my $name (keys %$names) {
2728
    my($comps) = $$names{$name};
2729
    foreach my $key (keys %$comps) {
2730
      foreach my $val (@{$$comps{$key}}) {
2731
        foreach my $i (@$arr) {
2732
          foreach my $wanted (@$sext) {
2733
            ## Remove any escape characters from the extension
2734
            my($oext) = $wanted;
2735
            $oext =~ s/\\//g;
217 bj 2736
            foreach my $re ($self->generated_filenames($i, $gent,
2737
                                                       $tag, "$i$oext")) {
2738
              $re = $self->escape_regex_special($re);
107 bj 2739
              if ($val =~ /$re$/) {
2740
                return 1;
2741
              }
2742
            }
2743
          }
2744
        }
2745
      }
2746
    }
2747
  }
2748
 
2749
  return 0;
2750
}
2751
 
2752
 
2753
sub list_default_generated {
2754
  my($self)    = shift;
2755
  my($gentype) = shift;
2756
  my($tags)    = shift;
2757
 
2758
  ## This method is called when the user has custom input files and has
2759
  ## provided source files.  If the user defaults the component (i.e.
2760
  ## source_files, resource_files, etc.) they are filled in by the
2761
  ## generate_default_components method.
2762
 
2763
  if ($self->{'generated_exts'}->{$gentype}->{'automatic'}) {
2764
    ## After all source and headers have been defaulted, see if we
2765
    ## need to add the generated files
2766
    if (defined $self->{$gentype}) {
2767
      ## Build up the list of files
2768
      my(@arr)   = ();
2769
      my($names) = $self->{$gentype};
2770
      my($group) = undef;
2771
      foreach my $name (keys %$names) {
2772
        foreach my $key (keys %{$$names{$name}}) {
2773
          my($array) = $$names{$name}->{$key};
2774
 
2775
          if ($key ne $defgroup) {
2776
            $group = $key;
2777
          }
2778
 
2779
          foreach my $val (@$array) {
198 bj 2780
            my($f) = $self->remove_wanted_extension(
2781
                              $val,
2782
                              $self->{'valid_components'}->{$gentype});
107 bj 2783
            push(@arr, $f);
2784
          }
2785
        }
2786
      }
2787
 
2788
      foreach my $type (@$tags) {
2789
        ## Do not add generated files if they are "special"
2790
        ## unless they haven't been explicitly supplied.
2791
        if (!$specialComponents{$type} ||
2792
            !$self->{'special_supplied'}->{$type}) {
2793
          if (!$self->generated_source_listed(
2794
                                $gentype, $type, \@arr,
2795
                                $self->{'valid_components'}->{$gentype})) {
2796
            $self->add_generated_files($gentype, $type, $group, \@arr);
2797
          }
2798
        }
2799
      }
2800
    }
2801
  }
2802
}
2803
 
2804
 
2805
sub prepend_gendir {
2806
  my($self)    = shift;
2807
  my($created) = shift;
2808
  my($ofile)   = shift;
2809
  my($gentype) = shift;
2810
  my($key)     = undef;
2811
 
2812
  foreach my $ext (@{$self->{'valid_components'}->{$gentype}}) {
2813
    my($e) = $ext;
2814
    $e =~ s/\\//g;
2815
    $key = "$ofile$e";
2816
    if (defined $self->{'flag_overrides'}->{$gentype}->{$key}) {
2817
      last;
2818
    }
2819
    else {
2820
      $key = undef;
2821
    }
2822
  }
2823
 
2824
  if (defined $key) {
2825
    foreach my $ma (@{$self->{'matching_assignments'}->{$gentype}}) {
2826
      if ($ma eq 'gendir') {
217 bj 2827
        my($dir) = $self->{'flag_overrides'}->{$gentype}->{$key}->{$ma};
2828
        if (defined $dir) {
107 bj 2829
          ## Convert the file to unix style for basename
2830
          $created =~ s/\\/\//g;
217 bj 2831
          return "$dir/" . $self->mpc_basename($created);
107 bj 2832
        }
2833
      }
2834
    }
2835
  }
2836
 
2837
  return $created;
2838
}
2839
 
2840
 
2841
sub list_generated_file {
2842
  my($self)    = shift;
2843
  my($gentype) = shift;
2844
  my($tag)     = shift;
2845
  my($array)   = shift;
2846
  my($file)    = shift;
2847
  my($ofile)   = shift;
217 bj 2848
  my($count)   = 0;
107 bj 2849
 
217 bj 2850
  ## Save the length of the basename for later.  We can not convert the
2851
  ## slashes on $file as it needs to keep the back slashes since that's
2852
  ## what comes from generated_filenames() below.  This is, of course, if
2853
  ## we are converting slashes in the first place.
2854
  my($fcopy) = $file;
2855
  $fcopy =~ s/.*[\/\\]//;
2856
  my($blen) = length($fcopy);
2857
 
2858
  ## Turn it into a regular expression
107 bj 2859
  $file = $self->escape_regex_special($file);
2860
 
2861
  foreach my $gen ($self->get_component_list($gentype, 1)) {
2862
    my($input) = $gen;
2863
    foreach my $ext (@{$self->{'valid_components'}->{$gentype}}) {
2864
      ## Remove the extension.
2865
      ## If it works, then we can exit this loop.
2866
      if ($gen =~ s/$ext$//) {
2867
        last;
2868
      }
2869
    }
2870
 
2871
    ## If the user provided file does not match any of the
2872
    ## extensions specified by the custom definition, we need
2873
    ## to remove the extension or else this file will not be
2874
    ## added to the project.
2875
    if ($gen eq $input) {
2876
      $gen =~ s/\.[^\.]+$//;
2877
    }
2878
 
2879
    ## See if we need to add the file.  We only need to bother
2880
    ## if the length of $gen is less than or equal to the length of
2881
    ## $file because they couldn't possibly match if they weren't.
217 bj 2882
    if (length($self->mpc_basename($gen)) <= $blen) {
107 bj 2883
      foreach my $re ($self->generated_filenames($gen, $gentype,
217 bj 2884
                                                 $tag, $input)) {
107 bj 2885
        if ($re =~ /$file(.*)?$/) {
2886
          my($created) = $re;
2887
          if (defined $ofile) {
2888
            $created = $self->prepend_gendir($created, $ofile, $gentype);
2889
          }
2890
          if (!$self->already_added($array, $created)) {
2891
            push(@$array, $created);
217 bj 2892
            ++$count;
107 bj 2893
          }
2894
          last;
2895
        }
2896
      }
2897
    }
2898
  }
217 bj 2899
  return $count;
107 bj 2900
}
2901
 
2902
 
2903
sub add_corresponding_component_files {
217 bj 2904
  my($self)     = shift;
2905
  my($filecomp) = shift;
2906
  my($tag)      = shift;
2907
  my($grname)   = $grouped_key . $tag;
107 bj 2908
 
2909
  ## Create a hash array keyed off of the existing files of the type
2910
  ## that we plan on adding.
2911
  my($fexist)  = 0;
2912
  my(%scfiles) = ();
217 bj 2913
  my($names)   = $self->{$tag};
107 bj 2914
  foreach my $name (keys %$names) {
2915
    ## Check to see if files exist in the default group
2916
    if (defined $$names{$name}->{$defgroup} &&
2917
        defined $$names{$name}->{$defgroup}->[0]) {
2918
      $fexist = 1;
2919
    }
2920
    foreach my $comp (keys %{$$names{$name}}) {
2921
      @scfiles{@{$$names{$name}->{$comp}}} = ();
2922
    }
2923
  }
2924
 
2925
  ## Create an array of extensions for the files we want to add
2926
  my(@exts) = ();
2927
  foreach my $ext (@{$self->{'valid_components'}->{$tag}}) {
2928
    push(@exts, $ext);
2929
    $exts[$#exts] =~ s/\\//g;
2930
  }
2931
 
2932
  ## Check each file against a possible new file addition
2933
  my($adddefaultgroup) = 0;
2934
  my($oktoadddefault)  = 0;
217 bj 2935
  foreach my $sfile (keys %$filecomp) {
107 bj 2936
    my($found) = 0;
2937
    foreach my $ext (@exts) {
2938
      if (exists $scfiles{"$sfile$ext"}) {
2939
        $found = 1;
2940
        last;
2941
      }
2942
    }
2943
 
2944
    if (!$found) {
2945
      ## Get the array of files for the selected component name
2946
      my($array) = [];
217 bj 2947
      my($comp)  = $$filecomp{$sfile};
107 bj 2948
      foreach my $name (keys %$names) {
2949
        if (defined $$names{$name}->{$comp}) {
2950
          $array = $$names{$name}->{$comp};
2951
        }
2952
      }
2953
 
217 bj 2954
      ## First, see if it will be generated so that we can correctly
2955
      ## deal with 'gendir' settings.
2956
      foreach my $gentype (keys %{$self->{'generated_exts'}}) {
2957
        $found += $self->list_generated_file($gentype, $tag, $array, $sfile);
107 bj 2958
      }
2959
 
217 bj 2960
      ## Next check to see if the file exists
107 bj 2961
      if (!$found) {
217 bj 2962
        foreach my $ext (@exts) {
2963
          if (-r "$sfile$ext") {
2964
            my($file) = "$sfile$ext";
2965
            if (!$self->already_added($array, $file)) {
2966
              push(@$array, $file);
2967
              ++$found;
2968
            }
2969
            last;
2970
          }
107 bj 2971
        }
2972
      }
2973
 
2974
      ## If we have any files at all in the component array, check
2975
      ## to see if we need to add a new group name
2976
      if (defined $$array[0]) {
217 bj 2977
        if ($comp eq $defgroup) {
2978
          $adddefaultgroup = 1;
2979
        }
2980
        else {
2981
          my($compexists) = undef;
2982
          my($grval)      = $self->get_assignment($grname);
2983
          if (defined $grval) {
2984
            foreach my $grkey (@{$self->create_array($grval)}) {
2985
              if ($grkey eq $comp) {
2986
                $compexists = 1;
2987
                last;
2988
              }
107 bj 2989
            }
2990
          }
2991
 
217 bj 2992
          if (!$compexists) {
107 bj 2993
            $self->process_assignment_add($grname, $comp);
2994
          }
217 bj 2995
          $oktoadddefault = 1;
2996
          $adddefaultgroup |= $fexist;
107 bj 2997
        }
2998
 
2999
        ## Put the array back into the component list
217 bj 3000
        if ($found) {
3001
          foreach my $name (keys %$names) {
3002
            $$names{$name}->{$comp} = $array;
3003
          }
107 bj 3004
        }
3005
      }
3006
    }
3007
  }
3008
 
3009
  ## We only need to add the default group name if we wanted to
3010
  ## add the default group when adding new files and we added a group
3011
  ## by some other name.  Otherwise, defaulted files would always be
3012
  ## in a group, which is not what we want.
3013
  if ($adddefaultgroup && $oktoadddefault) {
3014
    $self->process_assignment_add($grname, $defgroup);
3015
  }
3016
}
3017
 
3018
 
3019
sub get_default_project_name {
3020
  my($self) = shift;
3021
  my($name) = $self->{'current_input'};
3022
 
3023
  if ($name eq '') {
3024
    $name = $self->transform_file_name($self->base_directory());
3025
  }
3026
  else {
3027
    ## Since files on UNIX can have back slashes, we transform them
3028
    ## into underscores.
3029
    $name =~ s/\\/_/g;
3030
 
3031
    ## Convert the name to a usable name
3032
    $name = $self->transform_file_name($name);
3033
 
3034
    ## Take off the extension
3035
    $name =~ s/\.[^\.]+$//;
3036
  }
3037
 
3038
  return $name;
3039
}
3040
 
3041
 
3042
sub remove_excluded {
3043
  my($self) = shift;
3044
  my(@tags) = @_;
3045
 
3046
  ## Process each file type and remove the excluded files
3047
  foreach my $tag (@tags) {
3048
    my($names) = $self->{$tag};
3049
    foreach my $name (keys %$names) {
3050
      foreach my $comp (keys %{$$names{$name}}) {
3051
        my($count) = scalar(@{$$names{$name}->{$comp}});
3052
        for(my $i = 0; $i < $count; ++$i) {
3053
          my($file) = $$names{$name}->{$comp}->[$i];
3054
          if (defined $self->{'remove_files'}->{$tag}->{$file}) {
3055
            splice(@{$$names{$name}->{$comp}}, $i, 1);
3056
            --$i;
3057
            --$count;
3058
          }
3059
        }
3060
      }
3061
    }
3062
    delete $self->{'remove_files'}->{$tag};
3063
  }
3064
}
3065
 
3066
 
3067
sub generate_defaults {
3068
  my($self) = shift;
3069
 
3070
  ## Generate default project name
3071
  if (!defined $self->get_assignment('project_name')) {
3072
    $self->set_project_name($self->get_default_project_name());
3073
  }
3074
 
3075
  ## Generate the default pch file names (if needed)
3076
  my(@files) = $self->generate_default_file_list(
217 bj 3077
                                 '.', [],
3078
                                 undef, $self->get_assignment('recurse'));
107 bj 3079
  $self->generate_default_pch_filenames(\@files);
3080
 
3081
  ## If the pch file names are empty strings then we need to fix that
3082
  $self->fix_pch_filenames();
3083
 
3084
  ## Generate default components, but %specialComponents
3085
  ## are skipped in the initial default components generation
3086
  $self->generate_default_components(\@files);
3087
 
3088
  ## Remove source files that are also listed in the template files
3089
  ## If we do not do this, then generated projects can be invalid.
3090
  $self->remove_duplicated_files('source_files', 'template_files');
3091
 
3092
  ## If pch files are listed in header_files or source_files more than
3093
  ## once, we need to remove the extras
3094
  $self->remove_extra_pch_listings();
3095
 
3096
  ## Generate the default generated list of files only if we defaulted
3097
  ## the generated file list.  I want to ensure that source_files comes
3098
  ## first in the list to pick up group information (since source_files
3099
  ## are most likely going to be grouped than anything else).
3100
  my(@vc) = reverse sort { return 1 if $a eq 'source_files';
3101
                           return $a cmp $b; } keys %{$self->{'valid_components'}};
3102
  foreach my $gentype (keys %{$self->{'generated_exts'}}) {
3103
    $self->list_default_generated($gentype, \@vc);
3104
  }
3105
 
3106
  ## Now that all of the source files have been added
3107
  ## we need to remove those that have need to be removed
3108
  $self->remove_excluded('source_files');
3109
 
217 bj 3110
  ## Collect up all of the source file that have already been listed
3111
  ## with the extension removed.
3112
  my(%sourcecomp) = ();
3113
  foreach my $sourcetag (keys %sourceComponents) {
3114
    my($names) = $self->{$sourcetag};
3115
    foreach my $name (keys %$names) {
3116
      foreach my $comp (keys %{$$names{$name}}) {
3117
        foreach my $sfile (@{$$names{$name}->{$comp}}) {
3118
          my($mod) = $sfile;
3119
          $mod =~ s/\.[^\.]+$//;
3120
          $sourcecomp{$mod} = $comp;
3121
        }
3122
      }
3123
    }
3124
  }
3125
 
107 bj 3126
  ## Add %specialComponents files based on the
3127
  ## source_components (i.e. .h and .i or .inl based on .cpp)
3128
  foreach my $tag (keys %specialComponents) {
217 bj 3129
    $self->add_corresponding_component_files(\%sourcecomp, $tag);
107 bj 3130
  }
3131
 
3132
  ## Now, if the %specialComponents are still empty
3133
  ## then take any file that matches the components extension
3134
  foreach my $tag (keys %specialComponents) {
3135
    if (!$self->{'special_supplied'}->{$tag}) {
3136
      my($names) = $self->{$tag};
3137
      if (defined $names) {
3138
        ## We only want to generate default components if we have
3139
        ## defaulted the source files or we have no files listed
3140
        ## in the current special component.
3141
        my($ok) = $self->{'defaulted'}->{'source_files'};
3142
        if (!$ok) {
3143
          my(@all) = ();
3144
          foreach my $name (keys %$names) {
3145
            foreach my $key (keys %{$$names{$name}}) {
3146
              push(@all, @{$$names{$name}->{$key}});
3147
            }
3148
          }
217 bj 3149
          $ok = (!defined $all[0]);
107 bj 3150
        }
3151
        if ($ok) {
3152
          $self->generate_default_components(\@files, $tag);
3153
        }
3154
      }
3155
    }
3156
  }
3157
 
3158
  ## Now that all of the other files have been added
3159
  ## we need to remove those that have need to be removed
3160
  my(@rmkeys) = keys %{$self->{'remove_files'}};
217 bj 3161
  if (defined $rmkeys[0]) {
107 bj 3162
    $self->remove_excluded(@rmkeys);
3163
  }
3164
}
3165
 
3166
 
3167
sub set_project_name {
3168
  my($self) = shift;
3169
  my($name) = shift;
3170
 
3171
  ## Save the unmodified project name so that when we
3172
  ## need to determine the default target name, we can use
3173
  ## what is expected by the user.
3174
  $self->{'unmodified_project_name'} = $name;
3175
 
3176
  ## If we are applying the name modifier to the project
3177
  ## then we will modify the project name
3178
  if ($self->get_apply_project()) {
3179
    my($nmod) = $self->get_name_modifier();
3180
 
3181
    if (defined $nmod) {
3182
      $nmod =~ s/\*/$name/g;
3183
      $name = $nmod;
3184
    }
3185
  }
3186
 
3187
  ## Set the project_name assignment so that the TemplateParser
3188
  ## can get the project name.
3189
  $self->process_assignment('project_name', $name);
3190
}
3191
 
3192
 
3193
sub project_name {
3194
  my($self) = shift;
3195
  return $self->get_assignment('project_name');
3196
}
3197
 
3198
 
3199
sub lib_target {
3200
  my($self) = shift;
3201
  return (defined $self->get_assignment('sharedname') ||
3202
          defined $self->get_assignment('staticname'));
3203
}
3204
 
3205
 
3206
sub exe_target {
3207
  my($self) = shift;
3208
  return (defined $self->get_assignment('exename'));
3209
}
3210
 
3211
 
3212
sub get_component_list {
3213
  my($self)      = shift;
3214
  my($tag)       = shift;
3215
  my($noconvert) = shift;
3216
  my($names)     = $self->{$tag};
3217
  my(@list)      = ();
3218
 
3219
  foreach my $name (keys %$names) {
3220
    foreach my $key (keys %{$$names{$name}}) {
3221
      push(@list, @{$$names{$name}->{$key}});
3222
    }
3223
  }
3224
 
3225
  ## By default, if 'convert_slashes' is true, then we convert slashes
3226
  ## to backslashes.  There are cases where we do not want to convert
3227
  ## the slashes, in that case get_component_list() was called with
3228
  ## an additional parameter indicating this.
3229
  if (!$noconvert && $self->{'convert_slashes'}) {
217 bj 3230
    foreach my $item (@list) {
3231
      $item =~ s/\//\\/g;
107 bj 3232
    }
3233
  }
3234
 
3235
  if ($self->{'sort_files'}) {
3236
    @list = sort { $self->file_sorter($a, $b) } @list;
3237
  }
3238
 
3239
  return @list;
3240
}
3241
 
3242
 
3243
sub check_custom_output {
3244
  my($self)    = shift;
3245
  my($based)   = shift;
3246
  my($cinput)  = shift;
3247
  my($ainput)  = shift;
3248
  my($type)    = shift;
3249
  my($comps)   = shift;
3250
  my(@outputs) = ();
3251
 
3252
  foreach my $array ($self->generated_filename_arrays($cinput, $based,
217 bj 3253
                                                      $type, $ainput)) {
107 bj 3254
    foreach my $built (@$array) {
3255
      if (@$comps == 0) {
3256
        push(@outputs, $built);
3257
        last;
3258
      }
3259
      elsif (defined $specialComponents{$type} &&
3260
             !$self->{'special_supplied'}->{$type}) {
3261
        push(@outputs, $built);
3262
        last;
3263
      }
3264
      else {
3265
        my($base) = $built;
217 bj 3266
        $base =~ s/\\/\//g if ($self->{'convert_slashes'});
3267
        my($re) = $self->escape_regex_special($self->mpc_basename($base));
107 bj 3268
        foreach my $c (@$comps) {
3269
          ## We only match if the built file name matches from
3270
          ## beginning to end or from a slash to the end.
3271
          if ($c =~ /^$re$/ || $c =~ /[\/\\]$re$/) {
3272
            push(@outputs, $built);
3273
            last;
3274
          }
3275
        }
3276
      }
3277
    }
3278
  }
3279
 
3280
  return @outputs;
3281
}
3282
 
3283
 
3284
sub get_special_value {
3285
  my($self)   = shift;
3286
  my($type)   = shift;
3287
  my($cmd)    = shift;
3288
  my($based)  = shift;
3289
  my(@params) = @_;
3290
 
217 bj 3291
 
3292
  if ($type eq 'feature') {
3293
    return $self->get_feature_value($cmd, $based);
3294
  }
3295
  elsif (index($type, 'custom_type') == 0) {
107 bj 3296
    return $self->get_custom_value($cmd, $based, @params);
3297
  }
217 bj 3298
  elsif (index($type, $grouped_key) == 0) {
107 bj 3299
    return $self->get_grouped_value($type, $cmd, $based);
3300
  }
3301
 
3302
  return undef;
3303
}
3304
 
3305
 
217 bj 3306
sub get_feature_value {
3307
  my($self)   = shift;
3308
  my($cmd)    = shift;
3309
  my($based)  = shift;
3310
 
3311
  if ($cmd eq 'value') {
3312
    my($val) = $self->{'feature_parser'}->get_value($based);
3313
    if (defined $val && $val != 0) {
3314
      return 1;
3315
    }
3316
  }
3317
 
3318
  return undef;
3319
}
3320
 
3321
 
107 bj 3322
sub get_grouped_value {
3323
  my($self)  = shift;
3324
  my($type)  = shift;
3325
  my($cmd)   = shift;
3326
  my($based) = shift;
3327
  my($value) = undef;
3328
 
3329
  ## Make it all lower case
3330
  $type = lc($type);
3331
 
3332
  ## Remove the grouped_ part
3333
  $type =~ s/^$grouped_key//;
3334
 
3335
  ## Add the s if it isn't there
3336
  if ($type !~ /s$/) {
3337
    $type .= 's';
3338
  }
3339
 
3340
  my($names) = $self->{$type};
3341
  if ($cmd eq 'files') {
3342
    foreach my $name (keys %$names) {
3343
      my($comps) = $$names{$name};
3344
      foreach my $comp (keys %$comps) {
3345
        if ($comp eq $based) {
3346
          if ($self->{'convert_slashes'}) {
3347
            my(@converted) = ();
3348
            foreach my $file (@{$$comps{$comp}}) {
3349
              push(@converted, $self->slash_to_backslash($file));
3350
            }
3351
            $value = \@converted;
3352
          }
3353
          else {
3354
            $value = $$comps{$comp};
3355
          }
3356
          if ($self->{'sort_files'}) {
3357
            my(@sorted) = sort { $self->file_sorter($a, $b) } @$value;
3358
            $value = \@sorted;
3359
          }
3360
          last;
3361
        }
3362
      }
3363
    }
3364
  }
3365
  elsif ($cmd eq 'component_name') {
3366
    ## If there is more than one name, then we will need
3367
    ## to deal with that at a later time.
3368
    foreach my $name (keys %$names) {
3369
      $value = $name;
3370
    }
3371
  }
3372
 
3373
  return $value;
3374
}
3375
 
3376
 
3377
sub get_command_subs {
3378
  my($self)  = shift;
3379
  my(%valid) = ();
3380
 
3381
  ## Add the built-in OS compatibility commands
217 bj 3382
  if (UNIVERSAL::isa($self, 'WinProjectBase')) {
107 bj 3383
    $valid{'cat'}   = 'type';
217 bj 3384
    $valid{'cmp'}   = 'fc';
107 bj 3385
    $valid{'cp'}    = 'copy /y';
3386
    $valid{'mkdir'} = 'mkdir';
3387
    $valid{'mv'}    = 'move /y';
217 bj 3388
    $valid{'os'}    = 'win32';
107 bj 3389
    $valid{'rm'}    = 'del /f/s/q';
3390
    $valid{'nul'}   = 'nul';
3391
  }
3392
  else {
3393
    $valid{'cat'}   = 'cat';
217 bj 3394
    $valid{'cmp'}   = 'cmp';
107 bj 3395
    $valid{'cp'}    = 'cp -f';
3396
    $valid{'mkdir'} = 'mkdir -p';
3397
    $valid{'mv'}    = 'mv -f';
217 bj 3398
    $valid{'os'}    = 'unix';
107 bj 3399
    $valid{'rm'}    = 'rm -rf';
3400
    $valid{'nul'}   = '/dev/null';
3401
  }
3402
 
3403
  ## Add the project specific compatibility commands
3404
  $valid{'gt'}    = $self->get_gt_symbol();
3405
  $valid{'lt'}    = $self->get_lt_symbol();
3406
  $valid{'and'}   = $self->get_and_symbol();
3407
  $valid{'or'}    = $self->get_or_symbol();
3408
  $valid{'quote'} = $self->get_quote_symbol();
3409
 
3410
  return \%valid;
3411
}
3412
 
3413
 
217 bj 3414
sub replace_parameters {
3415
  my($self)   = shift;
3416
  my($str)    = shift;
3417
  my($valid)  = shift;
3418
  my($nowarn) = shift;
3419
  my($input)  = shift;
3420
  my($output) = shift;
3421
 
3422
  while ($str =~ /<%(\w+)(\(\w+\))?%>/) {
3423
    my($name)     = $1;
3424
    my($modifier) = $2;
3425
    if (defined $modifier) {
3426
      my($tmp) = $name;
3427
      $name = $modifier;
3428
      $name =~ s/[\(\)]//g;
3429
      $modifier = $tmp;
3430
    }
3431
 
3432
    if (exists $$valid{$name}) {
3433
      if (defined $$valid{$name}) {
3434
        my($replace) = $$valid{$name};
3435
        if (defined $modifier) {
3436
          if ($modifier eq 'noextension') {
3437
            $replace =~ s/\.[^\.]+$//;
3438
          }
3439
          else {
3440
            $self->warning("Uknown parameter modifier $modifier.");
3441
          }
3442
        }
3443
        $str =~ s/<%\w+(\(\w+\))?%>/$replace/;
3444
      }
3445
      else {
3446
        $str =~ s/<%\w+(\(\w+\))?%>//;
3447
      }
3448
    }
3449
    else {
3450
      $str =~ s/<%\w+(\(\w+\))?%>//;
3451
 
3452
      ## We only want to warn the user that we did not recognize the
3453
      ## pseudo template parameter if there was an input and an output
3454
      ## file passed to this function.  If this variable was used
3455
      ## without the parenthesis (as in an if statement), then we don't
3456
      ## want to warn the user.
3457
      if (defined $input && defined $output) {
3458
        if (!defined $$nowarn{$name}) {
3459
          $self->warning("<%$name%> was not recognized.");
3460
        }
3461
 
3462
        ## If we didn't recognize the pseudo template parameter then
3463
        ## we don't want to return anything back.
3464
        return undef;
3465
      }
3466
    }
3467
  }
3468
 
3469
  return $str;
3470
}
3471
 
3472
 
107 bj 3473
sub convert_command_parameters {
3474
  my($self)   = shift;
3475
  my($str)    = shift;
3476
  my($input)  = shift;
3477
  my($output) = shift;
3478
  my(%nowarn) = ();
3479
  my(%valid)  = %{$self->{'command_subs'}};
3480
 
3481
  ## Add in the values that change for every call to this function
3482
  $valid{'temporary'} = 'temp.$$$$.' . int(rand(0xffffffff));
3483
 
3484
  if (defined $input) {
3485
    $valid{'input'}          = $input;
217 bj 3486
    $valid{'input_basename'} = $self->mpc_basename($input);
107 bj 3487
    $valid{'input_noext'}    = $input;
3488
    $valid{'input_noext'}    =~ s/(\.[^\.]+)$//;
3489
    $valid{'input_ext'}      = $1;
3490
  }
3491
 
3492
  if (defined $output) {
3493
    my($first) = 1;
3494
    $valid{'output'} = "@$output";
3495
    foreach my $out (@$output) {
3496
      my($noext) = $out;
3497
      $noext =~ s/(\.[^\.]+)$//;
3498
 
3499
      $valid{'output_ext'}       = $1;
3500
      $valid{'output_noext'}    .= (!$first ? ' ' : '') . $noext;
217 bj 3501
      $valid{'output_basename'} .= (!$first ? ' ' : '') .
3502
                                   $self->mpc_basename($out);
107 bj 3503
      $first = 0;
3504
    }
3505
  }
3506
 
3507
  ## Add in the specific types of output files
3508
  if (defined $output) {
3509
    foreach my $type (keys %{$self->{'valid_components'}}) {
3510
      my($key) = $type;
3511
      $key =~ s/s$//gi;
3512
      $nowarn{$key} = 1;
3513
      $nowarn{$key . '_noext'} = 1;
3514
      foreach my $ext (@{$self->{'valid_components'}->{$type}}) {
3515
        foreach my $out (@$output) {
3516
          if ($out =~ /$ext$/) {
3517
            $valid{$key} = $out;
3518
            $valid{$key . '_noext'} = $out;
3519
            $valid{$key . '_noext'} =~ s/\.[^\.]+$//;
3520
            last;
3521
          }
3522
        }
3523
      }
3524
    }
3525
  }
3526
 
217 bj 3527
  return $self->replace_parameters($str, \%valid, \%nowarn, $input, $output);
107 bj 3528
}
3529
 
3530
 
3531
sub get_custom_value {
3532
  my($self)   = shift;
3533
  my($cmd)    = shift;
3534
  my($based)  = shift;
3535
  my(@params) = @_;
3536
  my($value)  = undef;
3537
 
3538
  if ($cmd eq 'input_files') {
3539
    ## Get the component list for the component type
3540
    my(@array) = $self->get_component_list($based);
3541
 
3542
    ## Check for directories in the component list.  If the component
3543
    ## type is not automatic, we may have directories here and will need
3544
    ## to get the file list for that type.
3545
    my($once) = undef;
217 bj 3546
    for(my $i = 0; $i < scalar(@array); ++$i) {
107 bj 3547
      if (-d $array[$i]) {
3548
        if (!defined $once) {
3549
          $once = {'recurse' => $self->get_assignment('recurse'),
3550
                   'pchh'    => $self->get_assignment('pch_header'),
3551
                   'pchc'    => $self->get_assignment('pch_source'),
3552
                  };
3553
        }
3554
        my(@built) = ();
3555
        $self->sift_default_file_list($based, $array[$i], \@built,
3556
                                      $self->{'valid_components'}->{$based},
3557
                                      $$once{'recurse'},
3558
                                      $$once{'pchh'}, $$once{'pchc'});
3559
        splice(@array, $i, 1, @built);
3560
        $i += $#built;
3561
      }
3562
    }
3563
 
3564
    $value = \@array;
3565
 
3566
    $self->{'custom_output_files'} = {};
3567
    my(%vcomps) = ();
3568
    foreach my $vc (keys %{$self->{'valid_components'}}) {
3569
      my(@comps) = $self->get_component_list($vc);
3570
      $vcomps{$vc} = \@comps;
3571
    }
3572
    $vcomps{$generic_key} = [];
3573
 
3574
    foreach my $input (@array) {
3575
      my(@outputs) = ();
3576
      my($ainput)  = $input;
3577
      my($cinput)  = $input;
3578
 
3579
      ## Remove the extension
3580
      $cinput =~ s/\.[^\.]+$//;
3581
 
3582
      ## If we are converting slashes,
3583
      ## change them back for this parameter
217 bj 3584
      $ainput =~ s/\\/\//g if ($self->{'convert_slashes'});
107 bj 3585
 
3586
      ## Add all of the output files
3587
      foreach my $vc (keys %{$self->{'valid_components'}}, $generic_key) {
3588
        push(@outputs,
3589
             $self->check_custom_output($based, $cinput,
3590
                                        $ainput, $vc, $vcomps{$vc}));
3591
      }
3592
 
3593
      ## Add specially listed files avoiding duplicates
3594
      if (defined $self->{'custom_special_output'}->{$based} &&
3595
          defined $self->{'custom_special_output'}->{$based}->{$ainput}) {
3596
        foreach my $file (@{$self->{'custom_special_output'}->{$based}->{$ainput}}) {
3597
          my($found) = 0;
3598
          foreach my $output (@outputs) {
3599
            if ($output eq $file) {
3600
              $found = 1;
3601
              last;
3602
            }
3603
          }
3604
          if (!$found) {
3605
            push(@outputs, $file);
3606
          }
3607
        }
3608
      }
3609
 
3610
      if ($self->{'sort_files'}) {
3611
        @outputs = sort { $self->file_sorter($a, $b) } @outputs;
3612
      }
3613
      $self->{'custom_output_files'}->{$input} = \@outputs;
3614
    }
3615
  }
3616
  elsif ($cmd eq 'output_files') {
3617
    # Generate output files based on $based
3618
    if (defined $self->{'custom_output_files'}) {
3619
      $value = $self->{'custom_output_files'}->{$based};
3620
    }
3621
  }
3622
  elsif ($cmd eq 'source_output_files') {
3623
    # Generate source output files based on $based
3624
    if (defined $self->{'custom_output_files'}) {
3625
      $value = [];
3626
      foreach my $file (@{$self->{'custom_output_files'}->{$based}}) {
3627
        foreach my $ext (@{$self->{'valid_components'}->{'source_files'}}) {
3628
          if ($file =~ /$ext$/) {
3629
            ## We've found a file that matches one of the source file
3630
            ## extensions.  Now we have to make sure that it doesn't
3631
            ## match a template file extension.
3632
            my($matched) = 0;
3633
            foreach my $text (@{$self->{'valid_components'}->{'template_files'}}) {
3634
              if ($file =~ /$text$/) {
3635
                $matched = 1;
3636
                last;
3637
              }
3638
            }
3639
            if (!$matched) {
3640
              push(@$value, $file);
3641
            }
3642
            last;
3643
          }
3644
        }
3645
      }
3646
    }
3647
  }
3648
  elsif ($cmd eq 'non_source_output_files') {
3649
    # Generate non source output files based on $based
3650
    if (defined $self->{'custom_output_files'}) {
3651
      $value = [];
3652
      foreach my $file (@{$self->{'custom_output_files'}->{$based}}) {
3653
        my($source) = 0;
3654
        foreach my $ext (@{$self->{'valid_components'}->{'source_files'}}) {
3655
          if ($file =~ /$ext$/) {
3656
            $source = 1;
217 bj 3657
            ## We've found a file that matches one of the source file
3658
            ## extensions.  Now we have to make sure that it doesn't
3659
            ## match a template file extension.
3660
            foreach my $text (@{$self->{'valid_components'}->{'template_files'}}) {
3661
              if ($file =~ /$text$/) {
3662
                $source = 0;
3663
                last;
3664
              }
3665
            }
3666
            last if ($source);
107 bj 3667
          }
3668
        }
3669
        if (!$source) {
3670
          push(@$value, $file);
3671
        }
3672
      }
3673
    }
3674
  }
3675
  elsif ($cmd eq 'inputexts') {
3676
    my(@array) = @{$self->{'valid_components'}->{$based}};
3677
    foreach my $val (@array) {
3678
      $val =~ s/\\\.//g;
3679
    }
3680
    $value = \@array;
3681
  }
3682
  elsif ($cmd eq 'dependencies') {
217 bj 3683
    ## If we are converting slashes, change them back for this parameter
3684
    $based =~ s/\\/\//g if ($self->{'convert_slashes'});
107 bj 3685
    $value = $self->{'custom_special_depend'}->{$based};
3686
  }
3687
  elsif (defined $customDefined{$cmd} &&
3688
         ($customDefined{$cmd} & 0x04) != 0) {
3689
    $value = $self->get_assignment($cmd,
3690
                                   $self->{'generated_exts'}->{$based});
3691
    if (defined $value && ($customDefined{$cmd} & 0x10) != 0) {
3692
      $value = $self->convert_command_parameters($value, @params);
3693
    }
3694
  }
3695
  elsif (defined $custom{$cmd}) {
3696
    $value = $self->get_assignment($cmd,
3697
                                   $self->{'generated_exts'}->{$based});
3698
  }
3699
 
3700
  return $value;
3701
}
3702
 
3703
 
3704
sub check_features {
3705
  my($self)     = shift;
3706
  my($requires) = shift;
3707
  my($avoids)   = shift;
3708
  my($info)     = shift;
3709
  my($status)   = 1;
3710
  my($why)      = undef;
3711
 
3712
  if (defined $requires) {
3713
    foreach my $require (split(/\s+/, $requires)) {
3714
      my($fval) = $self->{'feature_parser'}->get_value($require);
3715
 
3716
      ## By default, if the feature is not listed, then it is enabled.
3717
      if (defined $fval && !$fval) {
3718
        $why = "requires $require";
3719
        $status = 0;
3720
        last;
3721
      }
3722
    }
3723
  }
3724
 
3725
  ## If it passes the requires, then check the avoids
3726
  if ($status) {
3727
    if (defined $avoids) {
3728
      foreach my $avoid (split(/\s+/, $avoids)) {
3729
        my($fval) = $self->{'feature_parser'}->get_value($avoid);
3730
 
3731
        ## By default, if the feature is not listed, then it is enabled.
3732
        if (!defined $fval || $fval) {
3733
          $why = "avoids $avoid";
3734
          $status = 0;
3735
          last;
3736
        }
3737
      }
3738
    }
3739
  }
3740
 
3741
  if ($info && !$status) {
3742
    $self->details("Skipping " . $self->get_assignment('project_name') .
3743
                   " ($self->{'current_input'}), it $why.");
3744
  }
3745
 
3746
  return $status;
3747
}
3748
 
3749
 
3750
sub need_to_write_project {
3751
  my($self) = shift;
3752
 
3753
  foreach my $key ('source_files', 'resource_files',
3754
                   keys %{$self->{'generated_exts'}}) {
3755
    my($names) = $self->{$key};
3756
    foreach my $name (keys %$names) {
3757
      foreach my $key (keys %{$names->{$name}}) {
3758
        if (defined $names->{$name}->{$key}->[0]) {
3759
          return 1;
3760
        }
3761
      }
3762
    }
3763
  }
3764
 
3765
  return 0;
3766
}
3767
 
3768
 
3769
sub write_output_file {
3770
  my($self)     = shift;
3771
  my($name)     = shift;
3772
  my($status)   = 0;
3773
  my($error)    = undef;
3774
  my($tover)    = $self->get_template_override();
3775
  my($template) = (defined $tover ? $tover : $self->get_template());
3776
 
3777
  ## If the template files does not end in the template extension
3778
  ## then we will add it on.
3779
  if ($template !~ /$TemplateExtension$/) {
3780
    $template = $template . ".$TemplateExtension";
3781
  }
3782
 
3783
  ## If the template file does not contain a full path, then we
3784
  ## will search through the include paths for it.
3785
  my($tfile) = undef;
3786
  if ($template =~ /^([a-z]:)?[\/\\]/i) {
3787
    $tfile = $template;
3788
  }
3789
  else {
3790
    $tfile = $self->search_include_path($template);
3791
  }
3792
 
3793
  if (defined $tfile) {
3794
    ## Read in the template values for the
3795
    ## specific target and project type
3796
    ($status, $error) = $self->read_template_input();
3797
 
3798
    if ($status) {
3799
      my($tp) = new TemplateParser($self);
3800
 
3801
      ## Set the project_file assignment for the template parser
3802
      $self->process_assignment('project_file', $name);
3803
 
3804
      ($status, $error) = $tp->parse_file($tfile);
3805
 
3806
      if ($status) {
3807
        if (defined $self->{'source_callback'}) {
3808
          my($cb)     = $self->{'source_callback'};
3809
          my($pjname) = $self->get_assignment('project_name');
3810
          my(@list)   = $self->get_component_list('source_files');
3811
          if (UNIVERSAL::isa($cb, 'ARRAY')) {
3812
            my(@copy) = @$cb;
3813
            my($s) = shift(@copy);
3814
            &$s(@copy, $name, $pjname, @list);
3815
          }
3816
          elsif (UNIVERSAL::isa($cb, 'CODE')) {
3817
            &$cb($name, $pjname, @list);
3818
          }
3819
          else {
3820
            $self->warning("Ignoring callback: $cb.");
3821
          }
3822
        }
3823
 
3824
        if ($self->get_toplevel()) {
3825
          my($outdir) = $self->get_outdir();
3826
          my($oname)  = $name;
3827
 
3828
          $name = "$outdir/$name";
3829
 
3830
          my($fh)  = new FileHandle();
3831
          my($dir) = $self->mpc_dirname($name);
3832
 
3833
          if ($dir ne '.') {
3834
            mkpath($dir, 0, 0777);
3835
          }
3836
 
3837
          if ($self->compare_output()) {
3838
            ## First write the output to a temporary file
3839
            my($tmp) = "$outdir/MPC$>.$$";
3840
            my($different) = 1;
3841
            if (open($fh, ">$tmp")) {
3842
              my($lines) = $tp->get_lines();
3843
              foreach my $line (@$lines) {
3844
                print $fh $line;
3845
              }
3846
              close($fh);
3847
 
3848
              if (-r $name &&
3849
                  -s $tmp == -s $name && compare($tmp, $name) == 0) {
3850
                $different = 0;
3851
              }
3852
            }
3853
            else {
3854
              $error = "Unable to open $tmp for output.";
3855
              $status = 0;
3856
            }
3857
 
3858
            if ($status) {
3859
              ## If they are different, then rename the temporary file
3860
              if ($different) {
3861
                unlink($name);
3862
                if (rename($tmp, $name)) {
217 bj 3863
                  $self->post_file_creation($name);
107 bj 3864
                  $self->add_file_written($oname);
3865
                }
3866
                else {
3867
                  $error = "Unable to open $name for output.";
3868
                  $status = 0;
3869
                }
3870
              }
3871
              else {
3872
                ## We will pretend that we wrote the file
3873
                unlink($tmp);
3874
                $self->add_file_written($oname);
3875
              }
3876
            }
3877
          }
3878
          else {
3879
            if (open($fh, ">$name")) {
3880
              my($lines) = $tp->get_lines();
3881
              foreach my $line (@$lines) {
3882
                print $fh $line;
3883
              }
3884
              close($fh);
3885
              $self->add_file_written($oname);
3886
            }
3887
            else {
3888
              $error = "Unable to open $name for output.";
3889
              $status = 0;
3890
            }
3891
          }
3892
        }
3893
      }
3894
    }
3895
  }
3896
  else {
3897
    $error = "Unable to locate the template file: $template.";
3898
    $status = 0;
3899
  }
3900
 
3901
  return $status, $error;
3902
}
3903
 
3904
 
3905
sub write_install_file {
3906
  my($self)    = shift;
3907
  my($fh)      = new FileHandle();
3908
  my($insfile) = $self->transform_file_name(
3909
                           $self->get_assignment('project_name')) .
3910
                 '.ins';
3911
  my($outdir)  = $self->get_outdir();
3912
 
3913
  $insfile = "$outdir/$insfile";
3914
 
3915
  unlink($insfile);
3916
  if (open($fh, ">$insfile")) {
3917
    foreach my $vc (keys %{$self->{'valid_components'}}) {
3918
      my($names) = $self->{$vc};
3919
      foreach my $name (keys %$names) {
3920
        foreach my $key (keys %{$$names{$name}}) {
3921
          my($array) = $$names{$name}->{$key};
3922
          if (defined $$array[0]) {
3923
            print $fh "$vc:\n";
3924
            foreach my $file (@$array) {
3925
              print $fh "$file\n";
3926
            }
3927
            print $fh "\n";
3928
          }
3929
        }
3930
      }
3931
    }
3932
    if ($self->exe_target()) {
3933
      my($install) = $self->get_assignment('install');
3934
      print $fh "exe_output:\n",
3935
                (defined $install ? $self->relative($install) : ''),
3936
                ' ', $self->get_assignment('exename'), "\n";
3937
    }
3938
    elsif ($self->lib_target()) {
3939
      my($shared) = $self->get_assignment('sharedname');
3940
      my($static) = $self->get_assignment('staticname');
3941
      my($dllout) = $self->relative($self->get_assignment('dllout'));
3942
      my($libout) = $self->relative($self->get_assignment('libout'));
3943
 
3944
      print $fh "lib_output:\n";
3945
 
3946
      if (defined $shared && $shared ne '') {
3947
        print $fh (defined $dllout ? $dllout : $libout), " $shared\n";
3948
      }
3949
      if ((defined $static && $static ne '') &&
3950
          (defined $dllout || !defined $shared ||
3951
               (defined $shared && $shared ne $static))) {
3952
        print $fh "$libout $static\n";
3953
      }
3954
    }
3955
 
3956
    close($fh);
3957
    return 1, undef;
3958
  }
3959
 
3960
  return 0, 'Unable write to ' . $insfile;
3961
}
3962
 
3963
 
3964
sub write_project {
3965
  my($self)      = shift;
3966
  my($status)    = 1;
3967
  my($error)     = undef;
3968
  my($progress)  = $self->get_progress_callback();
3969
 
3970
  if (defined $progress) {
3971
    &$progress();
3972
  }
3973
 
3974
  if ($self->check_features($self->get_assignment('requires'),
3975
                            $self->get_assignment('avoids'),
3976
                            1)) {
3977
    if ($self->need_to_write_project()) {
3978
      if ($self->get_assignment('custom_only')) {
3979
        $self->remove_non_custom_settings();
3980
      }
3981
 
3982
      if ($self->{'escape_spaces'}) {
3983
        foreach my $name ('exename', 'sharedname', 'staticname') {
3984
          my($value) = $self->get_assignment($name);
3985
          if (defined $value && $value =~ s/(\s)/\\$1/g) {
3986
            $self->process_assignment($name, $value);
3987
          }
3988
        }
3989
        foreach my $key (keys %{$self->{'valid_components'}}) {
3990
          my($names) = $self->{$key};
3991
          foreach my $name (keys %$names) {
3992
            foreach my $key (keys %{$$names{$name}}) {
3993
              foreach my $file (@{$$names{$name}->{$key}}) {
3994
                $file =~ s/(\s)/\\$1/g;
3995
              }
3996
            }
3997
          }
3998
        }
3999
      }
4000
 
4001
      ($status, $error) = $self->write_output_file(
4002
                                   $self->transform_file_name(
4003
                                            $self->project_file_name()));
4004
      if ($self->{'generate_ins'} && $status) {
4005
        ($status, $error) = $self->write_install_file();
4006
      }
4007
    }
4008
    else {
4009
      my($msg) = $self->transform_file_name($self->project_file_name()) .
4010
                 " has no useful targets.";
4011
 
4012
      if ($self->{'current_input'} eq '') {
4013
        $self->information($msg);
4014
      }
4015
      else {
4016
        $self->warning($msg);
4017
      }
4018
    }
4019
  }
4020
  else {
4021
    $status = 2;
4022
  }
4023
 
4024
  return $status, $error;
4025
}
4026
 
4027
 
4028
sub get_project_info {
4029
  my($self) = shift;
4030
  return $self->{'project_info'};
4031
}
4032
 
4033
 
4034
sub get_lib_locations {
4035
  my($self) = shift;
4036
  return $self->{'lib_locations'};
4037
}
4038
 
4039
 
4040
sub get_inheritance_tree {
4041
  my($self) = shift;
4042
  return $self->{'inheritance_tree'};
4043
}
4044
 
4045
 
4046
sub set_component_extensions {
4047
  my($self) = shift;
4048
  my($vc)   = $self->{'valid_components'};
4049
  my($ec)   = $self->{'exclude_components'};
4050
 
4051
  foreach my $key (keys %$vc) {
4052
    my($ov) = $self->override_valid_component_extensions($key);
4053
    if (defined $ov) {
4054
      $$vc{$key} = $ov;
4055
    }
4056
  }
4057
 
4058
  foreach my $key (keys %$ec) {
4059
    my($ov) = $self->override_exclude_component_extensions($key);
4060
    if (defined $ov) {
4061
      $$ec{$key} = $ov;
4062
    }
4063
  }
4064
}
4065
 
4066
 
4067
sub set_source_listing_callback {
4068
  my($self) = shift;
4069
  my($cb)   = shift;
4070
  $self->{'source_callback'} = $cb;
4071
}
4072
 
4073
 
4074
sub reset_values {
4075
  my($self) = shift;
4076
 
4077
  ## Only put data structures that need to be cleared
4078
  ## out when the mpc file is done being read, not at the
217 bj 4079
  ## end of each project within the mpc file.  Those go in
4080
  ## the closing curly brace section of parse_line().
107 bj 4081
  $self->{'project_info'}  = [];
4082
  $self->{'lib_locations'} = {};
217 bj 4083
  $self->reset_generating_types();
107 bj 4084
}
4085
 
4086
 
4087
sub add_default_matching_assignments {
4088
  my($self) = shift;
4089
  my($lang) = $self->get_language();
4090
 
4091
  if (defined $lang) {
4092
    foreach my $key (keys %{$language{$lang}->[0]}) {
4093
      if (!defined $language{$lang}->[2]->{$key}) {
217 bj 4094
        $language{$lang}->[2]->{$key} = [];
4095
        if (defined $default_matching_assignments{$key}) {
4096
          push(@{$language{$lang}->[2]->{$key}},
4097
               @{$default_matching_assignments{$key}});
4098
        }
107 bj 4099
        foreach my $keyword (@default_matching_assignments) {
4100
          push(@{$language{$lang}->[2]->{$key}}, $keyword);
4101
        }
4102
      }
4103
    }
4104
  }
4105
}
4106
 
4107
 
4108
sub reset_generating_types {
4109
  my($self)  = shift;
4110
  my($lang)  = $self->get_language();
4111
 
4112
  if (defined $lang) {
4113
    my(%reset) = ('valid_components'     => $language{$lang}->[0],
4114
                  'custom_only_removed'  => $language{$lang}->[0],
4115
                  'exclude_components'   => $language{$lang}->[1],
4116
                  'matching_assignments' => $language{$lang}->[2],
4117
                  'generated_exts'       => {},
4118
                  'valid_names'          => \%validNames,
4119
                 );
4120
 
4121
    foreach my $r (keys %reset) {
4122
      $self->{$r} = {};
4123
      foreach my $key (keys %{$reset{$r}}) {
4124
        $self->{$r}->{$key} = $reset{$r}->{$key};
4125
      }
4126
    }
4127
  }
4128
 
4129
  $self->{'custom_types'} = {};
4130
 
4131
  ## Allow subclasses to override the default extensions
4132
  $self->set_component_extensions();
4133
}
4134
 
4135
 
4136
sub get_template_input {
4137
  my($self) = shift;
4138
 
4139
  ## This follows along the same logic as read_template_input() by
4140
  ## checking for exe target and then defaulting to a lib target
4141
  if ($self->exe_target()) {
4142
    if ($self->get_static() == 1) {
4143
      return $self->{'lexe_template_input'};
4144
    }
4145
    else {
4146
      return $self->{'dexe_template_input'};
4147
    }
4148
  }
4149
 
4150
  if ($self->get_static() == 1) {
4151
    return $self->{'lib_template_input'};
4152
  }
4153
  else {
4154
    return $self->{'dll_template_input'};
4155
  }
4156
}
4157
 
4158
 
4159
sub update_project_info {
4160
  my($self)    = shift;
4161
  my($tparser) = shift;
4162
  my($append)  = shift;
4163
  my($names)   = shift;
217 bj 4164
  my($sep)     = shift || '';
107 bj 4165
  my($pi)      = $self->get_project_info();
4166
  my($value)   = '';
4167
  my($arr)     = ($append && defined $$pi[0] ? pop(@$pi) : []);
4168
 
4169
  ## Set up the hash table when we are starting a new project_info
217 bj 4170
  if (!$append) {
107 bj 4171
    $self->{'project_info_hash_table'} = {};
4172
  }
4173
 
4174
  ## Append the values of all names into one string
217 bj 4175
  my($ncount) = scalar(@$names) - 1;
4176
  for(my $i = 0; $i <= $ncount; $i++) {
4177
    $value .= $self->translate_value(
4178
                               $$names[$i],
4179
                               $tparser->get_value_with_default($$names[$i]));
4180
    $value .= $sep if ($i != $ncount);
107 bj 4181
  }
4182
 
4183
  ## If we haven't seen this value yet, put it on the array
217 bj 4184
  if (!defined $self->{'project_info_hash_table'}->{"@$names $value"}) {
4185
    $self->{'project_info_hash_table'}->{"@$names $value"} = 1;
107 bj 4186
    push(@$arr, $value);
4187
  }
4188
 
4189
  ## Always push the array back onto the project_info
4190
  push(@$pi, $arr);
4191
 
4192
  return $value;
4193
}
4194
 
4195
 
4196
sub adjust_value {
4197
  my($self)  = shift;
4198
  my($names) = shift;
4199
  my($value) = shift;
4200
  my($atemp) = $self->get_addtemp();
4201
 
4202
  ## Perform any additions, subtractions
4203
  ## or overrides for the template values.
4204
  foreach my $name (@$names) {
4205
    if (defined $name && defined $atemp->{lc($name)}) {
217 bj 4206
      my($base) = $name;
4207
      $base =~ s/.*:://;
4208
      my($replace) = (defined $self->{'valid_names'}->{$base} &&
4209
                      ($self->{'valid_names'}->{$base} & 0x04) == 0);
107 bj 4210
      foreach my $val (@{$atemp->{lc($name)}}) {
217 bj 4211
        if ($replace && index($$val[1], '<%') >= 0) {
4212
          $$val[1] = $self->replace_parameters($$val[1],
4213
                                               $self->{'command_subs'});
4214
        }
107 bj 4215
        my($arr) = $self->create_array($$val[1]);
4216
        if ($$val[0] > 0) {
4217
          if (!defined $value) {
4218
            $value = '';
4219
          }
4220
          if (UNIVERSAL::isa($value, 'ARRAY')) {
4221
            ## We need to make $value a new array reference ($arr)
4222
            ## to avoid modifying the array reference pointed to by $value
4223
            unshift(@$arr, @$value);
4224
            $value = $arr;
4225
          }
4226
          else {
4227
            $value .= " $$val[1]";
4228
          }
4229
        }
4230
        elsif ($$val[0] < 0) {
4231
          if (defined $value) {
217 bj 4232
            my($parts) = undef;
107 bj 4233
            if (UNIVERSAL::isa($value, 'ARRAY')) {
4234
              $parts = $value;
4235
            }
4236
            else {
4237
              $parts = $self->create_array($value);
4238
            }
4239
 
4240
            $value = [];
4241
            foreach my $part (@$parts) {
4242
              if ($part ne '') {
4243
                my($found) = 0;
4244
                foreach my $ae (@$arr) {
4245
                  if ($part eq $ae) {
4246
                    $found = 1;
4247
                    last;
4248
                  }
4249
                }
4250
                if (!$found) {
4251
                  push(@$value, $part);
4252
                }
4253
              }
4254
            }
4255
          }
4256
        }
4257
        else {
4258
          ## If the user set the variable to empty, then we need to
4259
          ## set the value to undef
4260
          $value = (defined $$arr[0] ? $arr : undef);
4261
        }
4262
      }
4263
      last;
4264
    }
4265
  }
4266
 
4267
  return $value;
4268
}
4269
 
4270
 
198 bj 4271
sub expand_variables {
107 bj 4272
  my($self)            = shift;
4273
  my($value)           = shift;
198 bj 4274
  my($rel)             = shift;
107 bj 4275
  my($expand_template) = shift;
4276
  my($scope)           = shift;
198 bj 4277
  my($expand)          = shift;
4278
  my($warn)            = shift;
4279
  my($cwd)             = $self->getcwd();
4280
  my($start)           = 0;
107 bj 4281
 
198 bj 4282
  ## Fix up the value for Windows switch the \\'s to /
217 bj 4283
  $cwd =~ s/\\/\//g if ($self->{'convert_slashes'});
107 bj 4284
 
198 bj 4285
  while(substr($value, $start) =~ /(\$\(([^)]+)\))/) {
4286
    my($whole)  = $1;
4287
    my($name)   = $2;
4288
    my($val)    = $$rel{$name};
107 bj 4289
 
198 bj 4290
    if (defined $val) {
4291
      if ($expand) {
217 bj 4292
        $val =~ s/\//\\/g if ($self->{'convert_slashes'});
198 bj 4293
        substr($value, $start) =~ s/\$\([^)]+\)/$val/;
4294
        $whole = $val;
4295
      }
4296
      else {
107 bj 4297
        ## Fix up the value for Windows switch the \\'s to /
217 bj 4298
        $val =~ s/\\/\//g if ($self->{'convert_slashes'});
107 bj 4299
 
217 bj 4300
        my($icwd) = ($self->{'case_insensitive'} ? lc($cwd) : $cwd);
4301
        my($ival) = ($self->{'case_insensitive'} ? lc($val) : $val);
198 bj 4302
        my($iclen) = length($icwd);
4303
        my($ivlen) = length($ival);
107 bj 4304
 
198 bj 4305
        ## If the relative value contains the current working
4306
        ## directory plus additional subdirectories, we must pull
4307
        ## off the additional directories into a temporary where
4308
        ## it can be put back after the relative replacement is done.
4309
        my($append) = undef;
4310
        if (index($ival, $icwd) == 0 && $iclen != $ivlen &&
4311
            substr($ival, $iclen, 1) eq '/') {
4312
          my($diff) = $ivlen - $iclen;
4313
          $append = substr($ival, $iclen);
4314
          substr($ival, $iclen, $diff) = '';
4315
          $ivlen -= $diff;
4316
        }
107 bj 4317
 
198 bj 4318
        if (index($icwd, $ival) == 0 &&
4319
            ($iclen == $ivlen || substr($icwd, $ivlen, 1) eq '/')) {
4320
          my($current) = $icwd;
4321
          substr($current, 0, $ivlen) = '';
107 bj 4322
 
198 bj 4323
          my($dircount) = ($current =~ tr/\///);
4324
          if ($dircount == 0) {
4325
            $ival = '.';
4326
          }
4327
          else {
4328
            $ival = '../' x $dircount;
4329
            $ival =~ s/\/$//;
4330
          }
4331
          if (defined $append) {
4332
            $ival .= $append;
4333
          }
217 bj 4334
          $ival =~ s/\//\\/g if ($self->{'convert_slashes'});
198 bj 4335
          substr($value, $start) =~ s/\$\([^)]+\)/$ival/;
4336
          $whole = $ival;
4337
        }
4338
      }
4339
    }
4340
    elsif ($expand_template ||
4341
           $self->expand_variables_from_template_values()) {
4342
      my($ti) = $self->get_template_input();
4343
      if (defined $ti) {
4344
        $val = $ti->get_value($name);
4345
      }
4346
      my($sname) = (defined $scope ? $scope . "::$name" : undef);
4347
      my($arr) = $self->adjust_value([$sname, $name],
4348
                                     (defined $val ? $val : []));
4349
      if (defined $$arr[0]) {
4350
        $val = "@$arr";
217 bj 4351
        $val =~ s/\//\\/g if ($self->{'convert_slashes'});
198 bj 4352
        substr($value, $start) =~ s/\$\([^)]+\)/$val/;
107 bj 4353
 
198 bj 4354
        ## We have replaced the template value, but that template
4355
        ## value may contain a $() construct that may need to get
4356
        ## replaced too.
4357
        $whole = '';
4358
      }
4359
      else {
4360
        if ($expand && $warn) {
4361
          $self->warning("Unable to expand $name.");
4362
        }
4363
      }
4364
    }
4365
    $start += length($whole);
4366
  }
107 bj 4367
 
198 bj 4368
  return $value;
4369
}
107 bj 4370
 
198 bj 4371
 
4372
sub relative {
4373
  my($self)            = shift;
4374
  my($value)           = shift;
4375
  my($expand_template) = shift;
4376
  my($scope)           = shift;
4377
 
4378
  if (defined $value) {
4379
    if (UNIVERSAL::isa($value, 'ARRAY')) {
4380
      my(@built) = ();
4381
      foreach my $val (@$value) {
4382
        my($rel) = $self->relative($val, $expand_template, $scope);
4383
        if (UNIVERSAL::isa($rel, 'ARRAY')) {
4384
          push(@built, @$rel);
107 bj 4385
        }
198 bj 4386
        else {
4387
          push(@built, $rel);
4388
        }
107 bj 4389
      }
198 bj 4390
      $value = \@built;
107 bj 4391
    }
217 bj 4392
    elsif (index($value, '$') >= 0) {
198 bj 4393
      my($ovalue) = $value;
4394
      my(@keys) = keys %{$self->{'expanded'}};
4395
      if (defined $keys[0]) {
217 bj 4396
        $value = $self->expand_variables($value,
198 bj 4397
                                         $self->{'expanded'},
4398
                                         $expand_template, $scope, 1);
4399
      }
4400
 
4401
      if ($ovalue eq $value) {
4402
        my($rel) = ($self->get_use_env() ? \%ENV : $self->get_relative());
4403
        @keys = keys %$rel;
4404
        if (defined $keys[0]) {
217 bj 4405
          $value = $self->expand_variables($value, $rel,
198 bj 4406
                                           $expand_template, $scope,
4407
                                           $self->get_expand_vars(), 1);
4408
        }
4409
      }
4410
    }
107 bj 4411
  }
4412
 
198 bj 4413
  ## Values that have strings enclosed in double quotes are to
4414
  ## be interpreted as elements of an array
4415
  if (defined $value && $value =~ /^"[^"]+"(\s+"[^"]+")+$/) {
4416
    $value = $self->create_array($value);
4417
  }
4418
 
107 bj 4419
  return $value;
4420
}
4421
 
4422
 
4423
sub get_verbatim {
4424
  my($self)   = shift;
4425
  my($marker) = shift;
4426
  my($str)    = undef;
4427
  my($thash)  = $self->{'verbatim'}->{$self->{'pctype'}};
4428
 
4429
  if (defined $thash) {
4430
    if (defined $thash->{$marker}) {
4431
      my($crlf) = $self->crlf();
4432
      foreach my $line (@{$thash->{$marker}}) {
4433
        if (!defined $str) {
4434
          $str = '';
4435
        }
4436
        $str .= $self->process_special($line) . $crlf;
4437
      }
4438
      if (defined $str) {
4439
        $str .= $crlf;
4440
        $self->{'verbatim_accessed'}->{$self->{'pctype'}}->{$marker} = 1;
4441
      }
4442
    }
4443
  }
4444
 
4445
  return $str;
4446
}
4447
 
4448
 
4449
sub generate_recursive_input_list {
4450
  my($self)    = shift;
4451
  my($dir)     = shift;
4452
  my($exclude) = shift;
4453
  return $self->extension_recursive_input_list($dir,
4454
                                               $exclude,
4455
                                               $ProjectCreatorExtension);
4456
}
4457
 
4458
 
4459
sub get_modified_project_file_name {
4460
  my($self) = shift;
4461
  my($name) = shift;
4462
  my($ext)  = shift;
4463
  my($nmod) = $self->get_name_modifier();
4464
 
4465
  ## We don't apply the name modifier to the project file
4466
  ## name if we have already applied it to the project name
4467
  ## since the project file name comes from the project name.
4468
  if (defined $nmod && !$self->get_apply_project()) {
4469
    $nmod =~ s/\*/$name/g;
4470
    $name = $nmod;
4471
  }
4472
  return "$name$ext";
4473
}
4474
 
4475
 
4476
sub get_valid_names {
4477
  my($self) = shift;
4478
  return $self->{'valid_names'};
4479
}
4480
 
4481
 
4482
sub preserve_assignment_order {
4483
  my($self) = shift;
4484
  my($name) = shift;
4485
  my($mapped) = $self->{'valid_names'}->{$name};
4486
 
4487
  ## Only return the value stored in the valid_names hash map if it's
4488
  ## defined and it's not an array reference.  The array reference is
4489
  ## a keyword mapping and all mapped keywords should have preserved
4490
  ## assignment order.
4491
  if (defined $mapped && !UNIVERSAL::isa($mapped, 'ARRAY')) {
4492
    return ($mapped & 1);
4493
  }
4494
 
4495
  return 1;
4496
}
4497
 
4498
 
4499
sub add_to_template_input_value {
4500
  my($self) = shift;
4501
  my($name) = shift;
4502
  my($mapped) = $self->{'valid_names'}->{$name};
4503
 
4504
  ## Only return the value stored in the valid_names hash map if it's
4505
  ## defined and it's not an array reference.  The array reference is
4506
  ## a keyword mapping and no mapped keywords should be added to
4507
  ## template input variables.
4508
  if (defined $mapped && !UNIVERSAL::isa($mapped, 'ARRAY')) {
4509
    return ($mapped & 2);
4510
  }
4511
 
4512
  return 0;
4513
}
4514
 
4515
 
4516
sub dependency_combined_static_library {
4517
  #my($self) = shift;
4518
  return defined $ENV{MPC_DEPENDENCY_COMBINED_STATIC_LIBRARY};
4519
}
4520
 
4521
 
4522
sub translate_value {
4523
  my($self) = shift;
4524
  my($key)  = shift;
4525
  my($val)  = shift;
4526
 
4527
  if ($key eq 'after' && $val ne '') {
4528
    my($arr) = $self->create_array($val);
4529
    $val = '';
4530
 
4531
    if ($self->require_dependencies()) {
4532
      foreach my $entry (@$arr) {
4533
        if ($self->get_apply_project()) {
4534
          my($nmod) = $self->get_name_modifier();
4535
          if (defined $nmod) {
4536
            $nmod =~ s/\*/$entry/g;
4537
            $entry = $nmod;
4538
          }
4539
        }
4540
        $val .= '"' . ($self->dependency_is_filename() ?
4541
                          $self->project_file_name($entry) : $entry) . '" ';
4542
      }
4543
      $val =~ s/\s+$//;
4544
    }
4545
  }
4546
  return $val;
4547
}
4548
 
4549
 
4550
sub requires_parameters {
4551
  #my($self) = shift;
4552
  #my($name) = shift;
4553
  return $custom{$_[1]};
4554
}
4555
 
4556
 
4557
sub project_file_name {
4558
  my($self) = shift;
4559
  my($name) = shift;
4560
 
4561
  if (!defined $name) {
217 bj 4562
    $name = $self->get_assignment('project_name');
107 bj 4563
  }
4564
 
4565
  return $self->get_modified_project_file_name(
4566
                                     $self->project_file_prefix() . $name,
4567
                                     $self->project_file_extension());
4568
}
4569
 
4570
 
4571
sub remove_non_custom_settings {
4572
  my($self) = shift;
4573
 
4574
  ## Remove any files that may have automatically been added
4575
  ## to this project
4576
  foreach my $key (keys %{$self->{'custom_only_removed'}}) {
4577
    $self->{$key} = {};
4578
  }
4579
 
4580
  ## Unset the exename, sharedname and staticname
4581
  $self->process_assignment('exename',    undef);
4582
  $self->process_assignment('sharedname', undef);
4583
  $self->process_assignment('staticname', undef);
4584
}
4585
 
198 bj 4586
 
4587
sub remove_wanted_extension {
4588
  my($self)  = shift;
4589
  my($name)  = shift;
4590
  my($array) = shift;
4591
  my($orig)  = $name;
4592
 
4593
  foreach my $wanted (@$array) {
4594
    if ($name =~ s/$wanted$//) {
4595
      last;
4596
    }
4597
  }
4598
 
4599
  ## If the user provided file does not match any of the
4600
  ## extensions specified by the custom definition, we need
4601
  ## to remove the extension or else this file will not be
4602
  ## added to the project.
4603
  if ($name eq $orig) {
4604
    $name =~ s/\.[^\.]+$//;
4605
  }
4606
 
4607
  return $name;
4608
}
4609
 
107 bj 4610
# ************************************************************
4611
# Virtual Methods To Be Overridden
4612
# ************************************************************
4613
 
217 bj 4614
sub post_file_creation {
4615
  #my($self) = shift;
4616
  #my($file) = shift;
4617
}
4618
 
4619
 
107 bj 4620
sub escape_spaces {
4621
  #my($self) = shift;
4622
  return 0;
4623
}
4624
 
4625
 
4626
sub validated_directory {
4627
  my($self) = shift;
4628
  my($dir)  = shift;
4629
  return $dir;
4630
}
4631
 
4632
sub get_quote_symbol {
4633
  #my($self) = shift;
217 bj 4634
  return '\\"';
107 bj 4635
}
4636
 
4637
sub get_gt_symbol {
4638
  #my($self) = shift;
4639
  return '>';
4640
}
4641
 
4642
 
4643
sub get_lt_symbol {
4644
  #my($self) = shift;
4645
  return '<';
4646
}
4647
 
4648
 
4649
sub get_and_symbol {
4650
  #my($self) = shift;
4651
  return '&&';
4652
}
4653
 
4654
 
4655
sub get_or_symbol {
4656
  #my($self) = shift;
4657
  return '||';
4658
}
4659
 
4660
 
4661
sub dollar_special {
4662
  #my($self) = shift;
4663
  return 0;
4664
}
4665
 
4666
 
4667
sub expand_variables_from_template_values {
4668
  #my($self) = shift;
4669
  return 1;
4670
}
4671
 
4672
 
4673
sub require_dependencies {
4674
  #my($self) = shift;
4675
  return 1;
4676
}
4677
 
4678
 
4679
sub dependency_is_filename {
4680
  #my($self) = shift;
4681
  return 1;
4682
}
4683
 
4684
 
4685
sub fill_value {
4686
  #my($self) = shift;
4687
  #my($name) = shift;
4688
  return undef;
4689
}
4690
 
4691
 
4692
sub project_file_prefix {
4693
  #my($self) = shift;
4694
  return '';
4695
}
4696
 
4697
 
4698
sub project_file_extension {
4699
  #my($self) = shift;
4700
  return '';
4701
}
4702
 
4703
 
4704
sub override_valid_component_extensions {
4705
  #my($self) = shift;
4706
  #my($comp) = shift;
4707
  return undef;
4708
}
4709
 
4710
 
4711
sub override_exclude_component_extensions {
4712
  #my($self) = shift;
4713
  #my($comp) = shift;
4714
  return undef;
4715
}
4716
 
4717
 
4718
sub get_dll_exe_template_input_file {
4719
  #my($self) = shift;
4720
  return undef;
4721
}
4722
 
4723
 
4724
sub get_lib_exe_template_input_file {
4725
  my($self) = shift;
4726
  return $self->get_dll_exe_template_input_file();
4727
}
4728
 
4729
 
4730
sub get_lib_template_input_file {
4731
  my($self) = shift;
4732
  return $self->get_dll_template_input_file();
4733
}
4734
 
4735
 
4736
sub get_dll_template_input_file {
4737
  #my($self) = shift;
4738
  return undef;
4739
}
4740
 
4741
 
4742
sub get_template {
4743
  my($self) = shift;
4744
  return $self->{'pctype'};
4745
}
4746
 
4747
 
4748
1;