File Coverage

blib/lib/Text/EP3.pm
Criterion Covered Total %
statement 459 582 78.8
branch 169 334 50.6
condition 24 33 72.7
subroutine 35 38 92.1
pod 23 25 92.0
total 710 1012 70.1


line stmt bran cond sub pod time code
1             package Text::EP3;
2              
3             =head1 NAME
4              
5             EP3 - The Extensible Perl PreProcessor
6              
7             =head1 SYNOPSIS
8              
9             # Use options and files from command-line
10             use Text::EP3;
11             [use Text::EP3::{Extension}] # Language Specific Modules
12             # create the PreProcessor object
13             my $preprocessor = new Text::EP3 file;
14             # do the preprocessing, using command-line options from @ARGV
15             $preprocessor->ep3_execute;
16            
17             # Set options and files from the Perl script
18             use Text::EP3;
19             [use Text::EP3::{Extension}] # Language Specific Modules
20             # create the PreProcessor object
21             my $preprocessor = new Text::EP3 file;
22             # configure the PreProcessor object (optional)
23             $preprocessor->ep3_output_file([$filename]);
24             $preprocessor->ep3_modules([@modules]);
25             $preprocessor->ep3_includes([@include_directories]);
26             $preprocessor->ep3_reset;
27             $preprocessor->ep3_start_comment([$string]);
28             $preprocessor->ep3_end_comment([$string]);
29             $preprocessor->ep3_line_comment([$string]);
30             $preprocessor->ep3_delimiter([$string]);
31             $preprocessor->ep3_gen_depend_list([$value]);
32             $preprocessor->ep3_keep_comments([$value]);
33             $preprocessor->ep3_protect_comments([$value]);
34             $preprocessor->ep3_defines($string1=$string2);
35             # do the preprocessing
36             $preprocessor->ep3_process([$filename, [$condition]]);
37              
38             =head1 DESCRIPTION
39              
40             EP3 is a Perl5 program that preprocesses STDIN or some set
41             of input files and produces an output file.
42             EP3 only works on input files and produces output files. It seems to me that
43             if you want to preprocess arrays or somesuch, you should be using perl.
44             EP3 was first developed to provide
45             a flexible preprocessor for the Verilog hardware
46             description language. Verilog presents some problems that
47             were not easily solved by using cpp or m4. I wanted to be
48             able to use a normal preprocessor, but extend its functionality.
49             So I wrote EP3 - the Extensible Perl PreProcessor. The main
50             difference between EP3 and other preprocessors is its built-in
51             extensibility. Every directive in EP3 is really a method defined
52             in EP3, one of its submodules, or embedded in the file that is
53             being processed. By linking the directive name
54             to the associated methods, other methods could
55             be added, thus extending the preprocessor.
56              
57             Many of the features of EP3 can be modified via command line switches. For
58             every command line switch, there is an also accessor method.
59              
60             =over 4
61              
62             =item Directives and Method Invocation
63              
64             Directives are preceded with the a user
65             defined delimeter. The default delimeter is `@'. This
66             delimeter was chosen to avoid conflicts with other
67             preprocessor delimeters (`#' and the Verilog backtick),
68             as well as Verilog syntax that might be found a the
69             beginning of a line (`$', `&', etc.). A directive is
70             defined in Perl as
71             the beginning of the line, any amount of whitespace,
72             and the delimeter immediately followed by Perl word
73             characters (0-9A-Za-z_).
74              
75             EP3 looks for directives, strips off the delimeter, and then
76             invokes a method of the same name. The standard
77             directives are defined within the EP3 program. Library
78             or user defined directives may be loaded as perl
79             modules either via the use command or from a command
80             line switch for inclusion at the
81             beginning of the EP3 run. Using the "include" directive
82             coupled with the "perl_begin/end" directives
83             perl subroutines (and hence
84             EP3 directives) may be dynamically included during
85             the EP3 run.
86              
87             =item Directive Extension Method 1: The use command.
88              
89             A module may be included with the use statement provided that it pushes its
90             package name onto EP3's @ISA array (thus telling EP3 to inherit its methods).
91             For a Verilog module whose filename is Verilog.pm and has the package name
92             Text::EP3::Verilog, the following line must be included ...
93              
94             push (@Text::EP3::ISA, qw(Text::EP3::Verilog));
95              
96             This package can then be simply included in whatever script you are using to
97             call EP3 with the line:
98              
99             use Text::EP3::Verilog;
100              
101             All methods within the module are now available to EP3 as directives.
102              
103             =item Directive Extension Method 2: The command line switch.
104              
105             A module can be included at run time with the -module modulename switch on the
106             command line (assuming the ep3_parse_command_line method is invoked). The
107             modulename is assumed to have a .pm extension and exist somewhere in the
108             directories specified in @INC.
109             All methods within the module are now available to EP3 as directives.
110              
111             =item Directive Extension Method 3: The ep3_modules accessor method.
112              
113             Modules can be added by using the accessor method ep3_modules.
114              
115             $preprocessor->ep3_modules("module1","module2", ....);
116              
117             All methods within the module are now available to EP3 as directives.
118              
119             =item Directive Extension Method 4: Embedded in the source code or included files.
120              
121             Using the perl_begin and perl_end directives to delineate perl sections,
122             subroutines can be declared (as methods) anywhere in a processed file or in a
123             file that the process file includes. In this way, runtime methods are made
124             available to EP3. For example ...
125              
126             1 Text to be printed ...
127             @perl_begin
128             sub hello {
129             my $self = shift;
130             print "Hello there\n";
131             }
132             @perl_end
133             2 Text to be printed ...
134             @hello
135             3 Text to be printed ...
136            
137             would result in
138             1 Text to be printed ...
139             2 Text to be printed ...
140             Hello there
141             3 Text to be printed ...
142              
143             Using this method, libraries of directives can be built and included with the
144             include directive (but it is recommended that they be moved into a module when
145             they become static).
146              
147              
148             =item Input Files and Processing
149              
150             Input files are processed one line at a time. The
151             EP3 engine attempts to perform substitutions with
152             elements stored in macro/define/replace lists. All directive
153             lines are preprocessed before being evaluated (the only
154             exception being the key portions of the if[n]def and
155             define directives). Directive lines can be extended
156             across multiple lines by placing the `\' character at the
157             end of each line. Comments are normally protected
158             from the preprocessor, but protection can be
159             dynamically turned off and then back on. From a
160             command line switch, comments can also be deleted
161             from the output.
162              
163              
164             =item Output Files
165              
166             EP3 typically writes output to Perl's STDOUT, but
167             can be assigned to any output file. EP3 can also be run
168             in "dependency check" mode via a command line
169             switch. In this mode, normal output is suppressed, and
170             all dependent files are output in the order accessed.
171             NOTE! EP3 uses the select call to change the default output
172             file for included perl blocks. However, if you are using
173             a method invocation of ep3, note that the default output
174             for the rest of your script will be changed as well.
175             (This can be easily worked with, but should be known beforehand).
176              
177             Most parameters can be modified before invoking EP3 including
178             directive string, comment delimeters, comment protection
179             and inclusion, include path, and startup defines.
180              
181             =back
182              
183             =head1 Standard Directives
184              
185             EP3 defines a standard set of preprocessor
186             directives with a few special additions that integrate the
187             power of Perl into the coded language.
188              
189             =over 4
190              
191             =item The define directive
192              
193             @define key definition
194             The define directive assigns the definition to the
195             key. The definition can contain any character including
196             whitespace. The key is searched for as an individual
197             word (i.e the input to be searched is tokenized on Perl
198             word boundaries). The definition contains everything
199             from the whitespace following the key until the end of
200             the line.
201              
202             =item The replace directive
203              
204             @replace key definition
205             The replace directive is identical to the define
206             directive except that the substitution is performed if the
207             key exists anywhere, not just on word boundaries.
208              
209             =item The macro directive
210              
211             @macro key(value[,value]*) definition
212             The macro directive tokenizes as the define
213             directive, replacing the key(value,...) text with the
214             definition and saving the value list. The definition is
215             then parsed and the original macro values are replaced
216             with the saved values.
217              
218             =item The eval directive
219              
220             @eval key expr
221             The eval directive first evaluates the expr using
222             Perl. Any valid Perl expr is accepted. This key is then
223             defined with the result of the evaluation.
224              
225             =item The include directive
226              
227             @include or "file" [condition]
228             The include directive looks for the "file" in the
229             present directory, and anywhere in the include
230             path (definable via command line switch). Included
231             files are recursively evaluated by the preprocessor. If
232             the optional condition is specified, only those lines in
233             between the text strings "@mark condition_BEGIN"
234             and "@mark condition_END" will be included. The
235             condition can be any string. For example if the file "file.V" contains the
236             following lines:
237              
238             1 Stuff before
239             @mark PORT_BEGIN
240             2 Stuff middle
241             @mark PORT_END
242             3 Stuff after
243              
244             Then any file with the following line:
245              
246             @include "file.V" PORT
247              
248             will include the following line from file.V
249              
250             2 Stuff middle
251              
252             This is useful for partial inclusion of files (like port list specifications
253             in Verilog).
254              
255             =item The enum directive
256              
257             @enum a,b,c,d,...
258             enum generates multiple define's with each
259             sequential element receiving a 1 up count from the
260             previous element. Default starts at 0. If any element is a
261             number, the enum value will be set to that value.
262              
263             =item The ifdef and ifndef directives
264              
265             @ifdef and @ifndef key
266             Conditional compilation directives. The key is
267             defined if it was placed in the define/replace list by
268             define, replace, or any command that generates a define
269             or replace.
270              
271             =item The if directive
272              
273             @if expr
274             The expression is evaluated using Perl. The
275             expression can be any valid Perl expression. This
276             allows for a wide range of conditional compilation.
277              
278             =item The elif [elsif] directive
279              
280             @[elif|elsif] key | expr
281             The else if directive. Used for either "if[n]def" or
282             "if".
283              
284             =item The else directive
285              
286             @else
287             The else directive. Used for either "if[n]def" or
288             "if".
289              
290             =item The endif directive
291              
292             @endif
293             The conclusion of any "if[n]def" or "if" block.
294              
295             =item The comment directive
296              
297             @comment on|off|default|previous
298             The comment switch can be one of "on", "off",
299             "default", or "previous". This is used to turn comments
300             on or off in the resultant file. This directive is very
301             useful when including other files with commented
302             header descriptions. By using "comment off" and
303             "comment previous" surrounding a header the output
304             will not see the included files comments. Using
305             "comment on" with "comment previous" insures that
306             comments are included (as in an attached synthesis
307             directive file). The default comment setting is on. This
308             can be altered by a command line switch. The
309             "comment default" directive will restore the comment
310             setting to the EP3 invocation default.
311            
312             =item The protect directive
313              
314             @protect on|off|default|previous
315            
316             The protect switch can be one of "on", "off",
317             "default", or "previous". This is used to turn protection
318             of comments from macro substitution on or off in the resultant file.
319            
320             By using "protect off" and "protect previous" surrounding
321             a section of code, any comments in the section will be subject to
322             macro substitution. The default comment setting is on. This
323             can be altered by a command line switch. The
324             "protect default" directive will restore the protect
325             setting to the EP3 invocation default.
326              
327             =item The ep3 directive
328              
329             @ep3 on|off
330             The "ep3 off" directive turns off preprocessing
331             until the "ep3 on" directive is encountered. This can
332             greatly speed up processing of large files where
333             postprocessing is only necessary in small chunks.
334              
335             =item The perl_begin and perl_end directives
336              
337             @perl_begin
338             perl code here ....
339             (Single line and multi-line output mechanisms are available)
340              
341             @> text to be output after variable interpolation
342             or
343              
344             @>> text to be output
345              
346             after variable interpolation
347              
348             @<<
349              
350             @perl_end
351              
352             The "perl" directives provide the underlying
353             language with all of the power of
354             perl, embedded in the preprocessed code. Anything
355             enclosed within the "perl_begin" and "perl_end"
356             directives will be evaluated as a Perl script. This can be
357             used to include a subroutine that can later be called as a
358             directive. Using this type of extension, directive
359             libraries can be developed and included to perform a
360             variety of powerful source code development features.
361             This construct can also be used to mimic and expand
362             the VHDL generate capabilities. The "@>" and "@>> @<<" directives
363             from within a perl_[begin|end] block directs ep3 to
364             perform variable interpolation on the given line and
365             then print it to the output.
366              
367             =item The debug directive
368              
369             @debug on|off|value
370             The debug directive enables debug statements to go to the output file. The
371             debug statements are preceded by the Line Comment string. Currently the debug
372             values that will enable printouts are the following:
373              
374             0x01 1 - Primary messages (Entering Subroutines)
375             0x02 2 - ep3_process Engine
376             0x04 4 - define (replace, macro, eval, enum)
377             0x08 8 - include
378             0x10 16 - if (else, ifdef, etc.)
379             0x20 32 - perl_begin/end
380              
381             =back
382              
383             =head1 EP3 Constructor
384              
385             =over 8
386              
387             =item Text::EP3->new
388              
389             Returns an EP3 preprocessor object, on which you can call the methods listed below.
390             Takes no arguments.
391              
392             =back
393              
394             =head1 EP3 Methods
395              
396             EP3 defines several methods that can be invoked by the user.
397              
398             =over 8
399              
400             =item ep3_execute
401              
402             Execute sets up EP3 to act like a perl script. It parses the command line,
403             includes any modules specified on the command line, loads in any specified
404             modules, does any preexisting defines, sets up the output files,
405             and then processes the input. Sort of the whole shebang.
406              
407             =item ep3_parse_command_line
408              
409             ep3_parse_command_line does just that - parses the command line looking for EP3
410             options. It uses the GetOpt::Long module.
411              
412             =item ep3_modules
413              
414             This method will find and include any modules specified as arguments. It
415             expects just the name and will append .pm to it before doing a require.
416             The module returns the methods specified in the objects methods array.
417              
418             =item ep3_output_file
419              
420             ep3_output_file determines what the output should be (either the processed
421             text or a list of dependencies) and where it should go. It then proceeds to
422             open the required output files.
423             NOTE! - this module uses select to change the default output file.
424             The module returns the output filename.
425              
426             =item ep3_reset
427              
428             ep3_reset resets all of the internal EP3 lists (defines, replaces, keycounts,
429             etc.) so that a user can do multiple files independently from within one
430             script.
431              
432             =item ep3_process([$filename [, $condition]])
433              
434             ep3_process is the guts of the whole thing. It takes a filename as input and
435             produces the specified output. This is the method that is iteratively called
436             by the include directive. A null filename will cause ep3_process to look for
437             filenames in ARGV.
438              
439             =item ep3_includes([@include_directories])
440              
441             This method will add the specified directories to the ep3 include path.
442              
443             =item ep3_defines($string1=$string2);
444              
445             This method will initialize defines with string1 defined as string 2. It
446             initializes all of the defines in the objects Defines array.
447              
448             =item ep3_end_comment([$string]);
449              
450             This method sets the end_comment string to the value specifed.
451             If null, the method returns the current value.
452              
453             =item ep3_start_comment([$string]);
454              
455             This method sets the start_comment string to the value specifed.
456             If null, the method returns the current value.
457              
458             =item ep3_line_comment([$string]);
459              
460             This method sets the end_commenline string to the value specifed.
461             If null, the method returns the current value.
462              
463             =item ep3_delimiter([$string]);
464              
465             This method sets the directive delimiter string to the value specifed.
466             If null, the method returns the current value.
467              
468             =item ep3_delimeter([$string]);
469            
470             A synonym for ep3_delimiter, for backwards compatibility.
471              
472             =item ep3_gen_depend_list([$value]);
473              
474             This method enables/disables dependency list generation. When
475             gen_depend_list is 1, a dependency list is generated. When it is 0,
476             normal operation occurs.
477             If null, the method returns the current value.
478            
479             =item ep3_sync_lines([$value]);
480              
481             This method enables/disables output of synchronisation lines, as generated by cpp and m4.
482             These lines start with the current delimiter string, and contain the line number and
483             filename of the following output line.
484              
485             =item ep3_keep_comments([$value]);
486              
487             This method sets the keep_comments variable to the value specifed.
488             If null, the method returns the current value.
489              
490             =item ep3_protect_comments([$value]);
491              
492             This method sets the protect_comments variable to the value specifed.
493             If null, the method returns the current value.
494              
495             =back
496              
497             =head1 EP3 Options
498              
499             EP3 Options can be set from the command line (if ep3_execute or ep3_parse_command_line is invoked) or the internal variables can be explicitly set.
500              
501             =over 8
502              
503             =item [-no]protect
504              
505             Should comments be protected from substution?
506             Default: 1
507              
508             =item [-no]comment
509              
510             Should comments be passed to the output?
511             Default: 1
512              
513             =item [-no]depend
514              
515             Are we generating a dependency list or simply processing?
516             Default: 0
517              
518             =item -delimeter string
519              
520             The directive delimeter - can be a string
521             Default: @
522              
523             =item -define string1=string2
524              
525             Defines from the command line.
526             Multiple -define options can be specified
527             Default: ()
528              
529             =item -includes directory
530              
531             Where to look for include files.
532             Multiple -include options can be specified
533             Default: ()
534              
535             =item -output_filename filename
536              
537             Where to place the output.
538             Default: STDOUT
539              
540             =item -modules filename
541              
542             Modules to load (just the module name, expecting to find module.pm somewhere in @INC.
543             Multiple -modules options can be specified
544             Default: ()
545              
546             =item -line_comment string
547              
548             The Line Comment string.
549             Default: //
550              
551             =item -start_comment string
552              
553             The Start Comment string.
554             Default: /*
555              
556             =item -end_comment string
557              
558             The End Comment string.
559             Default: */
560              
561             =back
562              
563             =head1 AUTHOR
564              
565             Module created by Gary Spivey, spivey@ieee.org
566            
567             Version 1.10 changes by Michael Attenborough, michael doht attenborough aht physics doht org
568              
569             Many thanks to Steve Bresson for his help, ideas, and code ...
570              
571             =head1 SEE ALSO
572              
573             perl(1).
574              
575             =cut
576              
577 3     3   39890 use strict;
  3         7  
  3         146  
578 3     3   16 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
  3         7  
  3         239  
579              
580 3     3   16 use Exporter;
  3         10  
  3         112  
581 3     3   3274 use FileHandle;
  3         45126  
  3         21  
582 3     3   6073 use Getopt::Long;
  3         57660  
  3         19  
583 3     3   592 use Cwd;
  3         7  
  3         195  
584 3     3   16 use Carp;
  3         6  
  3         175  
585 3     3   4282 use AutoLoader;
  3         5188  
  3         25  
586 3     3   4900 use Env; # Make environment variables available
  3         10151  
  3         46  
587              
588             @ISA = qw(Exporter AutoLoader);
589             @EXPORT = qw();
590             @EXPORT_OK = qw(
591             );
592              
593             $VERSION = '1.10';
594              
595             # Set an unused default here just to avoid warnings
596             $Text::EP3::Dependfile_Handle = *STDOUT;
597              
598             sub new {
599              
600 2     2 1 415 my $package = shift;
601 2         6 my $self = {};
602              
603             # Set up Defaults
604 2         6 $self->{Protect_Default} = 1; # Should comments be protected from
605             # substitutions?
606 2         5 $self->{Keep_Default} = 1; # Should comments be passed to the
607             # output?
608 2         4 $self->{Gen_Depend_List} = 0; # Are we generating a dependency list or
609             # simply processing
610 2         5 $self->{Delimeter} = '@'; # The directive delimeter
611 2         5 $self->{Defines} = []; # Defines from the command line
612 2         6 $self->{Include_Directory} =[]; # Where to look for include files
613 2         4 $self->{Output_Filename} = 'STDOUT'; # Where to place the output
614 2         8 $self->{Modules}=[]; # Modules to load
615 2         4 $self->{Line_Comment} = '//'; # The Line Comment string
616 2         6 $self->{Start_Comment} = '/*'; # The Start Comment string
617 2         4 $self->{End_Comment} = '*/'; # The End Comment string
618 2         4 $self->{In_Perl_Begin} = 0; # The Perl_Begin marker
619 2         4 $self->{Debug} = 0; # The Debug value
620 2         4 $self->{Keycount} = 0; # The Initial count of keys
621 2         4 $self->{Sync_Lines} = 0; # Should we generate C-preprocessor-style
622             # source file name and line number information?
623 2         8 $self->{Keep_Comments} = $self->{Keep_Default};
624 2         54 $self->{Protect_Comments} = $self->{Protect_Default};
625 2         9 $self->{DPAT} = quotemeta $self->{Delimeter};
626              
627 2         8 bless $self, $package ;
628             }
629              
630             sub ep3_execute {
631             # The ep3_execute method is used to invoke EP3 as though it were a perl script.
632             # The calling perl script would look like this:
633             #
634             # require 5;
635             # use Text::EP3;
636             # use Text::EP3::Verilog; #(or any other optional modules)
637             # $self->ep3_execute;
638             #
639             #
640 0     0 1 0 my $self = shift;
641 0         0 $self->ep3_parse_command_line;
642             # Determine what the output file should be (can be set on the command line)
643 0         0 $self->ep3_output_file;
644             # Modules to be loaded can be passed in from the command line
645 0         0 $self->ep3_modules;
646             # Process the defines
647 0         0 $self->ep3_defines;
648             # Process the input file
649 0         0 $self->ep3_process;
650             }
651              
652             sub ep3_parse_command_line {
653             # Parse the command line using the Getopt::Long module
654             #
655 0     0 1 0 my $self = shift;
656 0         0 my $usage = "Usage:\t$0\n\t[-include dir]\n\t[-define key [value]]\n\t[-delimeter string]\n\t[-module modulename]\n\t[-[no]comments]\n\t[-[no]protect]\n\t[-[no]depend]\n\tfile1 [file2 .. filen]\n";
657 0 0       0 die $usage if (! (&GetOptions (
658             "comments!" => \$self->{Keep_Default}, # Pass comments to output?
659             "sync_lines!" => \$self->{Sync_Lines}, # Output sync lines?
660             "protect!" => \$self->{Protect_Default}, # Protect comments from
661             # substitution?
662             "depend!" => \$self->{Gen_Depend_List}, # Are we generating dependency
663             # list or simply processing?
664             "delimeter=s" => \$self->{Delimeter}, # The directive delimiter
665             "delimiter=s" => \$self->{Delimeter}, # The directive delimiter
666             "define=s@" => $self->{Defines}, # Defines from command line
667             "include=s@" => $self->{Include_Directory}, # Where to find include files
668             "output_filename=s" => \$self->{Output_Filename},
669             # Where to place the output
670             "modules=s@" => $self->{Modules}, # Modules to load
671             "line_comment=s" => \$self->{Line_Comment}, # The Line Comment string
672             "start_comment=s" => \$self->{Start_Comment}, # The Start Comment string
673             "end_comment=s" => \$self->{End_Comment}, # The End Comment string
674             )));
675             # Set the current comment markers to the defaults (i.e. command line
676             # specifies defaults.
677 0         0 $self->{Keep_Comments} = $self->{Keep_Default};
678 0         0 $self->{Protect_Comments} = $self->{Protect_Default};
679 0         0 $self->{DPAT} = quotemeta $self->{Delimeter};
680             }
681              
682             sub ep3_reset {
683             # Reset the preprocessor variables (typically called in between
684             # multiple distinct files to be preprocessed)
685             # Note, this does not reset any EP3 of the values set by new,
686             # if they have been altered by the user, they will not be changed by ep3_reset.
687 0     0 1 0 my $self = shift;
688 0         0 undef $self->{Keyline};
689 0         0 undef $self->{Keyfile};
690 0         0 undef $self->{Define_List};
691 0         0 undef $self->{Replace_List};
692 0         0 undef $self->{Keyfind};
693 0         0 undef $self->{Macro_Value};
694 0         0 undef $self->{Macro_Vars};
695 0         0 $self->{Keycount} = 0;
696             }
697              
698              
699              
700             sub ep3_process {
701             # This is the EP3 engine (along with the _ep3_do_subs routine) ...
702             # Process takes a filename as input (the file to be preprocessed).
703 15     15 1 95 my $self = shift;
704 15         42 local $Text::EP3::filehandle; # The Input_Filehandle
705 15         28 local $Text::EP3::filename;
706 15 50       63 $Text::EP3::filename = shift if @_;
707 15         20 my $condition; # Are there any conditions on this file?
708 15         32 $condition = '';
709 15 100       59 $condition = shift if @_ ;
710             #$condition = shift @_ ;
711             #@_ ? $condition = shift : $condition = '';
712 15         25 my $condition_satisfied;
713             my $condition_start;
714 0         0 my $condition_end;
715 0         0 my $in_comment;
716 0         0 my $original;
717 0         0 my $text_portion;
718 15         35 my $new_comment_portion = '';
719 15         48 my $old_comment_portion = '';
720 15         24 my @pieces;
721             my $x;
722 0         0 my $method;
723 0         0 my $chomped;
724 0         0 my @string;
725 15         54 my $start_pattern = quotemeta $self->{Start_Comment};
726 15         38 my $end_pattern = quotemeta $self->{End_Comment};
727 15         40 my $line_pattern = quotemeta $self->{Line_Comment};
728 15         19 my $result;
729 15         24 my $sync_start_sent = 0;
730            
731 15 50       53 print "$self->{Line_Comment}EP3->ep3_process: Entered ep3_process. Line $Text::EP3::line of $Text::EP3::filename: process file:$Text::EP3::filename condition:$condition\n" if $self->{Debug} & 1;
732              
733 15         184 $Text::EP3::filehandle = new FileHandle;
734             # See which kind of file we are processing
735 15 50       740 if (! defined $Text::EP3::filename) {
736             # If there is no Input_Filename,
737 0 0       0 if ($#ARGV >= 0) {
738             # Set the filename and open the input files ...
739             # Is there a better way to do this??
740 0 0       0 $Text::EP3::filename = $ARGV[0] if ($#ARGV == 0);
741 0 0       0 $Text::EP3::filename = "<" . join (',',@ARGV) . ">" if ($#ARGV >= 1);
742 0         0 my $filelist = join(' ',@ARGV);
743 0         0 $result = open($Text::EP3::filehandle,"perl -e 'while (<>) {print;}' $filelist |");
744             }
745             else {
746             # Else just use stdin
747 0         0 $Text::EP3::filehandle = *STDIN;
748 0         0 $Text::EP3::filename = 'STDIN';
749 0         0 $result = 1;
750             }
751             }
752             else {
753 15         663 $result = open($Text::EP3::filehandle, $Text::EP3::filename);
754             }
755              
756 15 50       55 die "Could not open $Text::EP3::filename" if (!$result );
757            
758              
759             # Check for a condition
760             # Conditions are used to include files segments, instead of the whole file.
761             # If there is a condition, see if it has been satisfied
762 15 100       44 if ($condition ne '') {
763 12         21 $condition_satisfied = 0;
764             }
765             else {
766 3         8 $condition_satisfied = 1;
767             }
768             # Set up the flags on which to look for a condition ...
769             # Conditions segments are marked using the mark directive ...
770             # If the condition is PORT, the start would be $self->{Delimeter}mark PORT_BEGIN
771             # and the end would be $self->{Delimeter}mark PORT_END
772             # @mark PORT_BEGIN
773             # .. lines to include ..
774             # @mark PORT_END
775 15         30 $condition_start = $condition . "_BEGIN";
776 15         28 $condition_end = $condition . "_END";
777            
778 15         20 $in_comment = 0;
779              
780 15         493 while (<$Text::EP3::filehandle>) {
781 1010         1361 $Text::EP3::line = $.;
782 1010 100 100     7073 if ($self->{Sync_Lines} && $condition_satisfied && !$sync_start_sent) {
      100        
783 4         8 $sync_start_sent = 1;
784 4         49 print "\n$self->{Delimeter} $Text::EP3::line \"$Text::EP3::filename\" 1\n"
785             }
786             #print "$self->{Line_Comment}EP3->ep3_process:$Text::EP3::line of $Text::EP3::filename: $_" if $self->{Debug} & 2;
787             # First, resolve multiline directives into single line
788             # i.e. make a line that ends in a backslash and whitespace join with
789             # the next line
790 1010         4311 while (/^\s*$self->{DPAT}\w.*\\\n$/) {
791             #print "Got a splitter\n" if $self->{Debug} & 2;
792 0         0 s/\\\s*\n$//;
793 0         0 $_ .= <$Text::EP3::filehandle>;
794 0         0 $Text::EP3::line = $.;
795             }
796            
797             # $original is saved so that we can tell if a blank line was there
798             # before comment deletion
799 1010         1393 $original = $_;
800            
801             #Check if this is a conditional include
802 1010 100       1888 if ($condition ne '') {
803             # If we have found a condition start ....
804 1005 100       3846 if (/^\s*$self->{DPAT}mark\s+$condition_start/) {
805 12 50       42 print "$self->{Line_Comment}EP3->ep3_process: Found $condition_start. Looking for $condition_end\n" if 2 & $self->{Debug};
806 12         25 $condition_satisfied = 1; # Turn on preprocessing
807             }
808             # continue reading (skip this line) if the condition is not satisfied
809 1005 100       3949 next if ( ! $condition_satisfied);
810 62 100       613 if (/^\s*$self->{DPAT}mark\s+$condition_end/) {
811 12 50       58 print "$self->{Line_Comment}EP3->ep3_process: Matching $condition_end\n" if 2 & $self->{Debug};
812 12         27 $condition_satisfied = 0; # Turn off preprocessing
813             }
814             }
815            
816            
817             # Do something with comments
818 67 100 66     241 if ( ($self->{Protect_Comments}) || (! $self->{Keep_Comments}) ) {
819 62         129 $text_portion = $new_comment_portion = $old_comment_portion = '';
820 62         824 (@pieces) = split /($start_pattern|$end_pattern|$line_pattern)/;
821 62         184 while ($#pieces >= 0) {
822 65         105 $x = shift (@pieces);
823             #start comment
824 65 50       303 if ($x eq $self->{Start_Comment}) {
    50          
    100          
825             #print "$self->{Line_Comment}EP3->ep3_process: Got comment start\n" if $self->{Debug} & 2;
826 0 0       0 if ($in_comment) {
827 0         0 $new_comment_portion .= $x;
828             }
829             else {
830 0         0 $new_comment_portion .= $x;
831 0         0 $in_comment = 1;
832             }
833             }
834             #end comment
835             elsif ($x eq $self->{End_Comment}) {
836             #print "$self->{Line_Comment}EP3->ep3_process: Got comment end\n" if $self->{Debug} & 2;
837 0 0       0 if ($in_comment) {
838 0         0 $in_comment = 0;
839             # end a comment from a previous line
840 0 0       0 if ($new_comment_portion eq '') {
841 0         0 $old_comment_portion .= $x;
842             }
843             # end a comment from a current line
844             else {
845 0         0 $new_comment_portion .= $x;
846             }
847             }
848             else {
849 0         0 carp "end of comment without prior start of comment on line $Text::EP3::line of file $Text::EP3::filename:";
850 0         0 $text_portion .= $x;
851             }
852             }
853             #line comment
854             elsif ($x eq $self->{Line_Comment}) {
855             #print "$self->{Line_Comment}EP3->ep3_process: Got comment line\n" if $self->{Debug} & 2;
856 3 50       7 if ($in_comment) {
857 0         0 $new_comment_portion .= $x;
858             }
859             else {
860 3         4 $new_comment_portion .= $x;
861             #flush the line
862 3         8 while ($#pieces >= 0) {
863 3         10 $new_comment_portion .= shift(@pieces);
864             }
865             }
866             }
867             #text
868             else {
869 62 50       122 if ($in_comment) {
870             #print "$self->{Line_Comment}EP3->ep3_process: Got comment text\n" if $self->{Debug} & 2;
871 0 0       0 if ($new_comment_portion eq '') {
872 0         0 $old_comment_portion .= $x;
873             }
874             # a comment from a current line
875             else {
876 0         0 $new_comment_portion .= $x;
877             }
878             }
879             else {
880 62         189 $text_portion .= $x;
881             }
882             }
883             }
884 62         125 $_ = $text_portion;
885             }
886            
887             # Now do the substitutions
888 67         216 $self->_ep3_do_subs() ;
889            
890             # If this was a directive line ... then lets invoke the directive method
891 67 100       2463 if (/^(\s*)$self->{DPAT}\w+/) {
892             # get rid of any leading spaces and save them in case any
893             # directive wants to use them
894 50         123 $self->{Indent} = $1;
895             # get the method token
896 50         228 @string = split(' ',$_);
897 50         163 $method = substr($string[0],1,length($string[0])-1);
898             #print "$self->{Line_Comment}EP3->ep3_process: attempting to call method ->$method<-\n" if $self->{Debug} & 2;
899              
900             # call method if it is available -
901             # I feel that it is pretty important to be able to cover
902             # text cases that look like directives and aren't - this is a pretty
903             # good check.
904 50 50       268 if ( ! $self->can($method)) {
905 0 0       0 if ( $self->{In_Perl_Begin} <= 0) { # Normal Case
906 0         0 carp "Unknown Directive $self->{Delimeter}$method, Line $Text::EP3::line of file $Text::EP3::filename, Passing to output:";
907             }
908             }
909             else {
910             # Get rid of the strict so that user's routines are a little more
911             # flexible ... They can always put strict in their routines if
912             # they want them ...
913 3     3   6413 no strict;
  3         5  
  3         138  
914 50         1208 $self->$method($_);
915 3     3   14 use strict;
  3         5  
  3         3758  
916             # Clear the line so that nothing prints
917 50         136 $_ = '';
918             }
919             }
920 67 100       305 if (! $self->{Keep_Comments}) {
921             # delete the blank lines which are a result of comment deletion
922 2 50 33     14 if ( ($original ne $_) && (/^\s*$/) ) {
923 2         3 $_ = '';
924             }
925             else {
926             # put the newline back if it was inside a comment
927 0 0       0 $_ .= "\n" if ($_ !~ /\n$/);
928             }
929             }
930 67 100 100     339 if (($self->{Protect_Comments}) && ($self->{Keep_Comments}) ) {
931             # move the trailing \n in the text portion to the end of the line
932             # e.g. the line
933             # hello /* barney */
934             # should not result in ...
935             # hello
936             # /* barney */
937             # Which it would if the newline part of the text portion gets placed
938             # before the comment at the end of the text portion.
939 60         111 $chomped = chomp;
940 60         122 $_ = $old_comment_portion . $_ . $new_comment_portion;
941 60 100       133 $_ .= "\n" if $chomped;
942             #print "$self->{Line_Comment}EP3->ep3_process: comment portion = ->$new_comment_portion<-\n" if $self->{Debug} & 2;
943             }
944            
945 67 50       141 if ( $self->{In_Perl_Begin} <= 0) { # Normal Case
946 67         659 print "$_";
947             }
948             else { # Oh! We're in a perl_begin diversion. Stash it away.
949 0         0 push(@{$self->{Perl_Lines}}, $_);
  0         0  
950             }
951             }
952             }
953            
954             sub _ep3_save_directive {
955             # This subroutine splits off the portion of a directive line to be preotected
956             # from substitution and saves it in the save_directive variable
957 71     71   84 my $self = shift;
958 71         96 my $line = shift;
959 71         192 my $save_directive;
960             my @ret;
961 71 100 66     696 if (defined $self->{DPAT} && $line =~ /^(\s*$self->{DPAT}\w+)/) {
962 51 50       133 print "$self->{Line_Comment}EP3->_ep3_save_directive: Saving the directives on a delimeter line\n" if $self->{Debug} & 2;
963             # Save the directive ..
964 51         121 $save_directive = $1;
965             # What to do for substitutions inside of directive lines?
966             # perform substitutions unless requesting not to?
967 51 100 100     1437 if ( $line =~ (/^(\s*$self->{DPAT}if[n]*def\s+\w+)/) ||
      100        
      66        
968             (/^(\s*$self->{DPAT}define\s+\w+)/) ||
969             (/^(\s*$self->{DPAT}macro\s+\w+)/) ||
970             (/^(\s*$self->{DPAT}replace\s+\w+)/) ) {
971             #For these directives, save the directive and the key so that
972             #substititions are not performed on them.
973 6         13 $save_directive = $1;
974 6         88 $line =~ s/$save_directive//;
975             }
976             else {
977             #Here, just protect the directive itself
978 45         490 $line =~ s/$save_directive//;
979             }
980             }
981             else {
982             #If not a directive, then clear the save directive marker
983 20         40 $save_directive = '';
984             }
985              
986 71         194 @ret = ($save_directive,$line);
987             #print "$self->{Line_Comment}EP3->_ep3_save_directive: Returning directive ->$save_directive<-\n" if $self->{Debug} & 2;
988             #print "$self->{Line_Comment}EP3->_ep3_save_directive: Returning \$_ ->$_<-\n" if $self->{Debug} & 2;
989 71         297 return (@ret);
990            
991             }
992              
993             sub _ep3_do_subs
994             {
995             # This is the actual guts of the module - where the substitutions take place
996 71     71   93 my $self = shift;
997 71         98 my($key) = @_;
998 71         70 my (@macvars, $newmacro, @newvars, $newvar, $var, $save_directive);
999              
1000             # Should we do substitutions on this line?
1001 71         172 ($save_directive,$_) = $self->_ep3_save_directive($_);
1002              
1003             # We have to pull the keys out in the order that we received them
1004 71         109 foreach $key (@{$self->{Keylist}}) {
  71         189  
1005             # First see if this key is in the line... this is simply a timesaver
1006             # Tried other types of timesavers (study, building search databases and
1007             # functions, but the simple approach proved fastest for most every
1008             # application.
1009 279 100       656 if (index($_, $key) >= 0) {
1010             # Check for defined macros first
1011 9 100       42 if (defined $self->{Macro_Value}{$key} ) {
    50          
    0          
1012 1 50       36 if( /(^|\W)$key\((.*)\)(\W|$)/ ) {
1013 1         4 @newvars = split(',',$2);
1014 1         4 @macvars = split (',',$self->{Macro_Vars}{$key});
1015 1 50       3 die "Macro and definition have different number of variables" if ($#newvars != $#macvars);
1016 1         3 $newmacro = $self->{Macro_Value}{$key};
1017 1         2 foreach $var (@macvars) {
1018 2         3 $newvar = shift (@newvars);
1019 2         50 $newmacro =~ s/(^|\W)\Q$var\E(\W|$)/$1$newvar$2/g;
1020             }
1021 1         29 s/(^|\W)$key\(.*\)(\W|$)/$1$newmacro$2/g;
1022             #print "/*<$1$key(.*)$2> replaced by macro definition <$1$newmacro$2>\n*/" if $self->{Debug} & 2;
1023             }
1024             }
1025             # Then check for defines
1026             elsif (defined $self->{Define_List}{$key} ) {
1027 8 50       618 if( s/(^|\W)$key(\W|$)/$1$self->{Define_List}{$key}$2/g ){
1028             #print "/*<$1$key$2> defined with <$1$self->{Define_List}{$key}$2>\n*/" if $self->{Debug} & 2;
1029             }
1030             }
1031             # And finally replaces
1032             elsif (defined $self->{Replace_List}{$key} ) {
1033 0 0       0 if( s/$key/$self->{Replace_List}{$key}/g){
1034             #print "/*<$key> replaced with <$self->{Replace_List{$key}>\n*/" if $self->{Debug} & 2;
1035             }
1036             }
1037             }
1038             }
1039             # Put the protected directive portion back on the line
1040 71         302 $_ = $save_directive . $_;
1041             }
1042              
1043             sub replace;
1044             sub define;
1045             sub macro;
1046             sub undef;
1047             sub include;
1048             sub elif;
1049             sub elsif;
1050             sub else;
1051             sub ifndef;
1052             sub ifdef;
1053             sub endif;
1054             sub if;
1055             sub enum;
1056             sub eval;
1057             sub perl_begin;
1058             sub perl_end;
1059             sub _ep3_output_code;
1060             sub mark;
1061             sub ep3;
1062             sub protect;
1063             sub comment;
1064             sub debug;
1065              
1066             sub ep3_end_comment ;
1067             sub ep3_start_comment ;
1068             sub ep3_line_comment ;
1069             sub ep3_delimiter ;
1070             sub ep3_delimeter ;
1071             sub ep3_gen_depend_list ;
1072             sub ep3_keep_comments ;
1073             sub ep3_sync_lines ;
1074             sub ep3_protect_comments ;
1075             sub ep3_modules ;
1076             sub ep3_includes ;
1077             sub ep3_defines ;
1078             sub ep3_require_modules ;
1079             sub ep3_output_file ;
1080              
1081             1;
1082              
1083             __END__