File Coverage

blib/lib/Language/Dashrep.pm
Criterion Covered Total %
statement 706 1167 60.5
branch 268 534 50.1
condition 43 120 35.8
subroutine 20 22 90.9
pod 17 17 100.0
total 1054 1860 56.6


line stmt bran cond sub pod time code
1             package Language::Dashrep;
2              
3 2     2   82830 use 5.010;
  2         8  
  2         198  
4 2     2   14 use warnings;
  2         7  
  2         80  
5 2     2   12 use strict;
  2         12  
  2         85  
6 2     2   12 use Carp;
  2         3  
  2         874  
7             require Exporter;
8              
9              
10             =head1 NAME
11              
12             Language::Dashrep - Dashrep language translator/interpreter
13              
14             =cut
15              
16              
17             =head1 VERSION
18              
19             Version 2.33
20              
21             =cut
22              
23             our $VERSION = '2.33';
24              
25              
26             =head1 SYNOPSIS
27              
28             The following sample code executes the Dashrep-language actions specified in the standard input file.
29              
30             use Language::Dashrep;
31             &Dashrep::dashrep_linewise_translate( );
32              
33             The module also supports direct access to functions that define Dashrep phrases, expand text that contains Dashrep phrases, and more.
34              
35             =cut
36              
37              
38             =head1 ABOUT
39              
40             Dashrep (TM) is a versatile descriptive programming language that recognizes hyphenated phrases, such as B, and recursively expands the phrases to generate an HTML web page, an XML file, a JavaScript program, a boilerplate-based document, a template-based email message, or any other text-based content.
41              
42             See www.Dashrep.org for details about the Dashrep language.
43              
44             Although Dashrep code is not directly executable, it can generate executable code. Although it does not directly define loops, it generates lists in which any delimited (using commas and/or spaces) list of text strings (including integers) specifies the unique values for the list items. Although the Dashrep language does not directly implement a branching structure, the translated code can be completely changed at any level (including within lists) based on parameterized hyphenated phrases such as B<[-template-for-move-proposal-link-for-action-[-output-requested-action-]-]>.
45              
46             The Dashrep language has been used to convert text files into MML- and XML-format files (for two books, I and I
47              
48             The design goals for the Dashrep language were:
49              
50             =over
51              
52             =item * Provide a convenient way to move descriptive code out of executable code.
53              
54             =item * Keep it simple, and keep it flexible.
55              
56             =item * Make the language speakable. (This characteristic is useful for various purposes, including circumventing keyboard-induced repetitive-stress injury, and using microphone-equipped mobile devices.)
57              
58             Note about Version 2 and later: These versions, if they are from GitHub instead of CPAN, can be used without the CPAN envioronment. The GitHub version only needs the Perl interpreter, which means that on the Windows operating system only the I and I and I files (or their more-recent equivalents) are needed.
59              
60             =back
61              
62             =cut
63              
64              
65             =head1 EXPORT
66              
67             The following subroutines are exported.
68              
69             =head2 dashrep_define
70              
71             =head2 dashrep_import_replacements
72              
73             =head2 dashrep_get_replacement
74              
75             =head2 dashrep_get_list_of_phrases
76              
77             =head2 dashrep_delete
78              
79             =head2 dashrep_delete_all
80              
81             =head2 dashrep_expand_parameters
82              
83             =head2 dashrep_expand_phrases
84              
85             =head2 dashrep_expand_phrases_except_special
86              
87             =head2 dashrep_expand_special_phrases
88              
89             =head2 dashrep_xml_tags_to_dashrep
90              
91             =head2 dashrep_top_level_action
92              
93             =head2 dashrep_linewise_translate
94              
95             =cut
96              
97              
98             our @ISA = qw(Exporter);
99             our @EXPORT = qw(
100             dashrep_define
101             dashrep_import_replacements
102             dashrep_get_replacement
103             dashrep_get_list_of_phrases
104             dashrep_delete
105             dashrep_delete_all
106             dashrep_expand_parameters
107             dashrep_expand_phrases
108             dashrep_expand_phrases_except_special
109             dashrep_expand_special_phrases
110             dashrep_xml_tags_to_dashrep
111             dashrep_top_level_action
112             dashrep_linewise_translate
113             );
114              
115              
116             #-----------------------------------------------
117             # This Perl code is intentionally written
118             # in a subset of Perl and uses a C-like
119             # syntax so that it can be ported more
120             # easily to other languages, especially
121             # the C language for faster execution.
122             #
123             # If you offer improvements to this code,
124             # please follow this convention so that
125             # the code continues to be easily converted
126             # into other languages.
127             #-----------------------------------------------
128              
129              
130             #-----------------------------------------------
131             # Declare package variables.
132              
133             my $global_true ;
134             my $global_false ;
135             my $global_endless_loop_counter ;
136             my $global_endless_loop_counter_limit ;
137             my $global_nesting_level_of_file_actions ;
138             my $global_xml_level_number ;
139             my $global_xml_accumulated_sequence_of_tag_names ;
140             my $global_spaces ;
141             my $global_ignore_level ;
142             my $global_capture_level ;
143             my $global_phrase_to_insert_after_next_top_level_line ;
144             my $global_top_line_count_for_insert_phrase ;
145             my %global_dashrep_replacement ;
146             my %global_replacement_count_for_item_name ;
147             my %global_exists_xml_hyphenated_phrase ;
148             my @global_list_of_lists_to_generate ;
149             my @global_xml_tag_at_level_number ;
150              
151              
152             #-----------------------------------------------
153             # Define package constants, and initialize
154             # special phrases.
155              
156             BEGIN {
157 2     2   5 $global_true = 1 ;
158 2         4 $global_false = 0 ;
159 2         3 $global_endless_loop_counter = 0 ;
160 2         3 $global_endless_loop_counter_limit = 70000 ;
161 2         4 $global_xml_accumulated_sequence_of_tag_names = "" ;
162 2         4 $global_spaces = " " ;
163 2         4 $global_nesting_level_of_file_actions = 0 ;
164 2         4 $global_ignore_level = 0 ;
165 2         3 $global_capture_level = 0 ;
166 2         3 $global_xml_level_number = 0 ;
167 2         4 %global_replacement_count_for_item_name = ( ) ;
168 2         4 @global_list_of_lists_to_generate = ( ) ;
169 2         2 @global_xml_tag_at_level_number = ( ) ;
170              
171 2         15 %global_dashrep_replacement = ( ) ;
172 2         5 $global_dashrep_replacement{ "dashrep-comments-ignored" } = "" ;
173 2         13 $global_dashrep_replacement{ "dashrep-endless-loop-counter-limit" } = "" ;
174 2         6 $global_dashrep_replacement{ "dashrep-debug-trace-on-or-off" } = "" ;
175 2         6 $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } = "" ;
176 2         2 $global_dashrep_replacement{ "dashrep-linewise-trace-on-or-off" } = "" ;
177 2         4 $global_dashrep_replacement{ "dashrep-ignore-trace-on-or-off" } = "" ;
178 2         4 $global_dashrep_replacement{ "dashrep-ignore-level" } = "" ;
179 2         4 $global_dashrep_replacement{ "dashrep-capture-trace-on-or-off" } = "" ;
180 2         3 $global_dashrep_replacement{ "dashrep-capture-level" } = "" ;
181 2         4 $global_dashrep_replacement{ "dashrep-xml-trace-on-or-off" } = "" ;
182 2         12 $global_dashrep_replacement{ "dashrep-first-xml-tag-name" } = "" ;
183 2         4 $global_dashrep_replacement{ "dashrep-xml-yes-handle-open-close-tag-" } = "" ;
184 2         4 $global_dashrep_replacement{ "dashrep-xml-yes-handle-open-close-tag-" } = "" ;
185 2         37000 $global_dashrep_replacement{ "dashrep-yes-or-no-export-delimited-definitions" } = "" ;
186             }
187              
188              
189             =head1 FUNCTIONS
190              
191              
192             =head2 initialize_special_phrases
193              
194             Initialize the phrases with special "dashrep_..."
195             names.
196              
197             =cut
198              
199             #-----------------------------------------------
200             #-----------------------------------------------
201             # initialize_special_phrases
202             #-----------------------------------------------
203             #-----------------------------------------------
204              
205             sub initialize_special_phrases
206             {
207 1     1 1 2 $global_dashrep_replacement{ "dashrep-comments-ignored" } = "" ;
208 1         2 $global_dashrep_replacement{ "dashrep-endless-loop-counter-limit" } = "" ;
209 1         1 $global_dashrep_replacement{ "dashrep-debug-trace-on-or-off" } = "" ;
210 1         2 $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } = "" ;
211 1         2 $global_dashrep_replacement{ "dashrep-linewise-trace-on-or-off" } = "" ;
212 1         1 $global_dashrep_replacement{ "dashrep-ignore-trace-on-or-off" } = "" ;
213 1         2 $global_dashrep_replacement{ "dashrep-ignore-level" } = "" ;
214 1         2 $global_dashrep_replacement{ "dashrep-capture-trace-on-or-off" } = "" ;
215 1         2 $global_dashrep_replacement{ "dashrep-capture-level" } = "" ;
216 1         1 $global_dashrep_replacement{ "dashrep-xml-trace-on-or-off" } = "" ;
217 1         2 $global_dashrep_replacement{ "dashrep-first-xml-tag-name" } = "" ;
218 1         2 $global_dashrep_replacement{ "dashrep-xml-yes-handle-open-close-tag-" } = "" ;
219 1         1 $global_dashrep_replacement{ "dashrep-xml-yes-handle-open-close-tag-" } = "" ;
220 1         5 $global_dashrep_replacement{ "dashrep-yes-or-no-export-delimited-definitions" } = "" ;
221             }
222              
223              
224             =head2 dashrep_define
225              
226             Associates a replacement text string with
227             the specified hyphenated phrase.
228              
229             First parameter is the hyphenated phrase.
230             Second parameter is its replacement text
231             string.
232              
233             Return value is 1 if the definition is
234             successful. Return value is zero if there
235             are not exactly two parameters.
236              
237             =cut
238              
239             #-----------------------------------------------
240             #-----------------------------------------------
241             # dashrep_define
242             #-----------------------------------------------
243             #-----------------------------------------------
244              
245             sub dashrep_define
246             {
247              
248 12     12 1 4542 my $phrase_name ;
249             my $expanded_text ;
250              
251              
252             #-----------------------------------------------
253             # Do the assignment.
254              
255 12 50       39 if ( scalar( @_ ) == 2 )
256             {
257 12         19 $phrase_name = $_[ 0 ] ;
258 12         20 $expanded_text = $_[ 1 ] ;
259 12         25 $phrase_name =~ s/^ +// ;
260 12         19 $phrase_name =~ s/ +$// ;
261 12         37 $global_dashrep_replacement{ $phrase_name } = $expanded_text ;
262             } else
263             {
264 0         0 carp "Warning: Call to dashrep_define subroutine does not have exactly two parameters." ;
265 0         0 return 0 ;
266             }
267              
268              
269             #-----------------------------------------------
270             # End of subroutine.
271              
272 12         34 return 1 ;
273              
274             }
275              
276              
277             =head2 dashrep_import_replacements
278              
279             Parses text that associates Dashrep phrases
280             with the definitions for those phrases.
281              
282             First, and only, parameter is the text
283             string that uses the Dashrep language.
284              
285             Return value is the count for how many
286             hyphenated phrases were defined (or
287             redefined). Return value is zero if
288             there is not exactly one parameter.
289              
290             =cut
291              
292             #-----------------------------------------------
293             #-----------------------------------------------
294             # dashrep_import_replacements
295             #-----------------------------------------------
296             #-----------------------------------------------
297              
298             sub dashrep_import_replacements
299             {
300              
301 2     2 1 20 my $definition_name ;
302             my $definition_value ;
303 0         0 my $input_string ;
304 0         0 my $replacements_text_to_import ;
305 0         0 my $text_before ;
306 0         0 my $text_including_comment_end ;
307 0         0 my $text_after ;
308 0         0 my $do_nothing ;
309 0         0 my @list_of_replacement_names ;
310 0         0 my @list_of_replacement_strings ;
311              
312              
313             #-----------------------------------------------
314             # Get the text that contains replacement
315             # definitions.
316              
317 2 50       9 if ( scalar( @_ ) == 1 )
318             {
319 2         25 $replacements_text_to_import = $_[ 0 ] ;
320             } else
321             {
322 0         0 carp "Warning: Call to dashrep_import_replacements subroutine does not have exactly one parameter." ;
323 0         0 return 0 ;
324             }
325 2 50       13 if ( not( defined( $replacements_text_to_import ) ) )
326             {
327 0         0 $replacements_text_to_import = "" ;
328 0 0       0 if ( $global_dashrep_replacement{ "dashrep-debug-trace-on-or-off" } eq "on" )
329             {
330 0         0 print "{{trace; imported zero definitions from empty text}}\n" ;
331             }
332             }
333              
334              
335             #-----------------------------------------------
336             # If the supplied text is empty, indicate this
337             # case and return.
338              
339 2 50       12 if ( $replacements_text_to_import !~ /[^ ]/ )
340             {
341 0 0       0 if ( $global_dashrep_replacement{ "dashrep-debug-trace-on-or-off" } eq "on" )
342             {
343 0         0 print "{{trace; imported zero definitions from empty text}}\n" ;
344             }
345 0         0 return 0 ;
346             }
347              
348              
349             #-----------------------------------------------
350             # Reset the "ignore" and "capture" levels.
351              
352 2         4 $global_ignore_level = 0 ;
353 2         4 $global_capture_level = 0 ;
354              
355              
356             #-----------------------------------------------
357             # Initialization.
358              
359 2         7 @list_of_replacement_names = ( ) ;
360              
361              
362             #-----------------------------------------------
363             # Replace line breaks, and tabs, with spaces.
364              
365 2         147 $replacements_text_to_import =~ s/[\n\r\t]+/ /sg ;
366 2         60 $replacements_text_to_import =~ s/[\n\r\t]+/ /sg ;
367 2         62 $replacements_text_to_import =~ s/ +/ /sg ;
368              
369              
370             #-----------------------------------------------
371             # Ignore comments that consist of, or are embedded
372             # in, strings of the following types:
373             # *------ -------*
374             # /------ -------/
375              
376 2         41 $replacements_text_to_import =~ s/\*\-\-\-+\*/ /g ;
377 2         35 $replacements_text_to_import =~ s/\/\-\-\-+\// /g ;
378 2         51 while ( $replacements_text_to_import =~ /^(.*?)([\*\/]\-\-+)(.*)$/ )
379             {
380 6         28 $text_before = $1 ;
381 6         65 $global_dashrep_replacement{ "dashrep-comments-ignored" } .= " " . $2 ;
382 6         74 $text_including_comment_end = $3 ;
383 6         11 $text_after = "" ;
384 6 50       87 if ( $text_including_comment_end =~ /^(.*?\-\-+[\*\/])(.*)$/ )
385             {
386 6         36 $global_dashrep_replacement{ "dashrep-comments-ignored" } .= $1 . " " ;
387 6         59 $text_after = $2 ;
388             }
389 6         947 $replacements_text_to_import = $text_before . " " . $text_after ;
390             }
391              
392              
393             #-----------------------------------------------
394             # Split the replacement text at spaces,
395             # and put the strings into an array.
396              
397 2         47 $replacements_text_to_import =~ s/ +/ /g ;
398 2         301 @list_of_replacement_strings = split( / / , $replacements_text_to_import ) ;
399              
400              
401             #-----------------------------------------------
402             # Read and handle each item in the array.
403              
404 2         24 $definition_name = "" ;
405 2         7 foreach $input_string ( @list_of_replacement_strings )
406             {
407 872 100 100     8404 if ( $input_string =~ /^ *$/ )
    50 66        
    100          
    100          
    100          
    50          
408             {
409 1         3 $do_nothing ++ ;
410              
411              
412             #-----------------------------------------------
413             # Ignore the "define-begin" directive.
414              
415             } elsif ( $input_string eq 'define-begin' )
416             {
417 0         0 $do_nothing ++ ;
418              
419              
420             #-----------------------------------------------
421             # Ignore the "dashrep-definitions-begin" and
422             # "dashrep-definitions-end" directives.
423              
424             } elsif ( ( $input_string eq 'dashrep-definitions-begin' ) || ( $input_string eq 'dashrep-definitions-end' ) )
425             {
426 2         9 $do_nothing ++ ;
427              
428              
429             #-----------------------------------------------
430             # When the "define-end" directive, or a series
431             # of at least 3 dashes ("--------"), is encountered,
432             # clear the definition name.
433             # Also remove trailing spaces from the previous
434             # replacement.
435              
436             } elsif ( ( $input_string eq 'define-end' ) || ( $input_string =~ /^---+$/ ) )
437             {
438 127         265 $definition_value = $global_dashrep_replacement{ $definition_name } ;
439 127         316 $definition_value =~ s/ +$// ;
440 127 100       330 if ( $definition_value =~ /[^ \n\r]/ )
441             {
442 113         207 $global_dashrep_replacement{ $definition_name } = $definition_value ;
443             } else
444             {
445 14         27 $global_dashrep_replacement{ $definition_name } = "" ;
446             }
447 127         270 $definition_name = "" ;
448              
449              
450             #-----------------------------------------------
451             # Get a definition name.
452             # Allow a colon after the hyphenated name.
453             # If this definition name has already been defined,
454             # ignore the earlier definition.
455             # If the name does not contain a hyphen,
456             # prefix the name with "invalid-phrase-name-".
457              
458             } elsif ( $definition_name eq "" )
459             {
460 127         188 $definition_name = $input_string ;
461 127         404 $definition_name =~ s/\:$// ;
462 127 50       347 if ( $definition_name !~ /\-/ )
463             {
464 0         0 $definition_name = "invalid-phrase-name-" . $definition_name ;
465             }
466 127         318 $global_dashrep_replacement{ $definition_name } = "" ;
467 127         302 push( @list_of_replacement_names , $definition_name ) ;
468              
469              
470             #-----------------------------------------------
471             # Collect any text that is part of a definition.
472             # But do not allow the definition to include
473             # the name of the phrase being defined (because
474             # that would cause an endless loop when the
475             # phrase is replaced).
476              
477             } elsif ( $input_string ne "" )
478             {
479 615 50       1087 if ( $input_string eq $definition_name )
480             {
481 0         0 $global_dashrep_replacement{ $definition_name } = "ERROR: Replacement for the hyphenated phrase:\n " . $definition_name . "\n" . "includes itself, which would cause an endless replacement loop." . "\n" ;
482 0         0 carp "Warning: Replacement for the hyphenated phrase:\n " . $definition_name . "\n" . "includes itself, which would cause an endless replacement loop.". "\n" . "Error occurred " ;
483             } else
484             {
485 615 100       1631 if ( $global_dashrep_replacement{ $definition_name } ne "" )
486             {
487 502         912 $global_dashrep_replacement{ $definition_name } .= " " ;
488             }
489 615         1868 $global_dashrep_replacement{ $definition_name } = $global_dashrep_replacement{ $definition_name } . $input_string ;
490             }
491             }
492              
493              
494             #-----------------------------------------------
495             # Repeat the loop for the next string.
496              
497             }
498              
499              
500             #-----------------------------------------------
501             # End of subroutine.
502              
503 2         114 return $#list_of_replacement_names + 1 ;
504              
505             }
506              
507              
508             =head2 dashrep_get_replacement
509              
510             Gets/returns the replacement text string that
511             is associated with the specified hyphenated
512             phrase.
513              
514             First, and only, parameter is the hyphenated
515             phrase.
516              
517             Return value is the replacement string that
518             is associated with the specified hyphenated
519             phrase. Return value is an empty string if
520             there is not exactly one parameter.
521              
522             =cut
523              
524             #-----------------------------------------------
525             #-----------------------------------------------
526             # dashrep_get_replacement
527             #-----------------------------------------------
528             #-----------------------------------------------
529              
530             sub dashrep_get_replacement
531             {
532              
533 39     39 1 412 my $phrase_name ;
534             my $expanded_text ;
535              
536              
537             #-----------------------------------------------
538             # Get the name of the hyphenated phrase.
539              
540 39 50       95 if ( scalar( @_ ) == 1 )
541             {
542 39         68 $phrase_name = $_[ 0 ] ;
543             } else
544             {
545 0         0 $expanded_text = "" ;
546 0         0 return $expanded_text ;
547             }
548              
549              
550             #-----------------------------------------------
551             # Get the replacement text that is associated
552             # with the hyphenated phrase.
553              
554 39 100 66     250 if ( ( exists( $global_dashrep_replacement{ $phrase_name } ) ) && ( $global_dashrep_replacement{ $phrase_name } =~ /[^ ]/ ) )
555             {
556 36         70 $expanded_text = $global_dashrep_replacement{ $phrase_name } ;
557             } else
558             {
559 3         5 $expanded_text = "" ;
560             }
561              
562              
563             #-----------------------------------------------
564             # End of subroutine.
565              
566 39         110 return $expanded_text ;
567              
568             }
569              
570              
571             =head2 dashrep_get_list_of_phrases
572              
573             Returns an array that lists all the
574             hyphenated phrases that have been defined
575             so far.
576              
577             There are no parameters.
578              
579             Return value is an array that lists all the
580             hyphenated phrases that have been defined.
581             Return value is an empty array if there is
582             not exactly zero parameters.
583              
584             =cut
585              
586             #-----------------------------------------------
587             #-----------------------------------------------
588             # dashrep_get_list_of_phrases
589             #-----------------------------------------------
590             #-----------------------------------------------
591              
592             sub dashrep_get_list_of_phrases
593             {
594              
595 3     3 1 25 my @list_of_phrases ;
596              
597 3 50       10 if ( scalar( @_ ) != 0 )
598             {
599 0         0 carp "Warning: Call to dashrep_define subroutine does not have exactly zero parameters." ;
600 0         0 @list_of_phrases = ( ) ;
601 0         0 return @list_of_phrases ;
602             }
603              
604 3         107 @list_of_phrases = keys( %global_dashrep_replacement ) ;
605 3         40 return @list_of_phrases ;
606              
607             }
608              
609              
610             =head2 dashrep_delete
611              
612             Deletes the specified hyphenated phrase.
613              
614             First parameter is the hyphenated phrase.
615              
616             Return value is 1 if the deletion is
617             successful. Return value is zero if there
618             is not exactly one parameter.
619              
620             =cut
621              
622             #-----------------------------------------------
623             #-----------------------------------------------
624             # dashrep_delete
625             #-----------------------------------------------
626             #-----------------------------------------------
627              
628             sub dashrep_delete
629             {
630              
631 1     1 1 6 my $phrase_name ;
632              
633              
634             #-----------------------------------------------
635             # Delete the indicated phrase.
636              
637 1 50       4 if ( scalar( @_ ) == 1 )
638             {
639 1         3 $phrase_name = $_[ 0 ] ;
640 1         3 $phrase_name =~ s/^ +// ;
641 1         4 $phrase_name =~ s/ +$// ;
642 1         3 delete( $global_dashrep_replacement{ $phrase_name } );
643             } else
644             {
645 0         0 carp "Warning: Call to dashrep_delete subroutine does not have exactly one parameter." ;
646 0         0 return 0 ;
647             }
648              
649              
650             #-----------------------------------------------
651             # End of subroutine.
652              
653 1         4 return 1 ;
654              
655             }
656              
657              
658             =head2 dashrep_delete_all
659              
660             Deletes all the hyphenated phrases.
661              
662             There are no parameters.
663              
664             Return value is 1 if the deletion is
665             successful. Return value is zero if there
666             is not exactly zero parameters.
667              
668             =cut
669              
670             #-----------------------------------------------
671             #-----------------------------------------------
672             # dashrep_delete_all
673             #-----------------------------------------------
674             #-----------------------------------------------
675              
676             sub dashrep_delete_all
677             {
678              
679              
680             #-----------------------------------------------
681             # Reset the "ignore" and "capture" levels.
682              
683 1     1 1 2 $global_ignore_level = 0 ;
684 1         1 $global_capture_level = 0 ;
685              
686              
687             #-----------------------------------------------
688             # Reset the xml-parsing state.
689              
690 1         2 $global_xml_level_number = 0 ;
691 1         1 @global_xml_tag_at_level_number = ( ) ;
692              
693              
694             #-----------------------------------------------
695             # Delete all the phrases.
696              
697 1 50       3 if ( scalar( @_ ) == 0 )
698             {
699 1         17 %global_dashrep_replacement = ( );
700 1         4 &initialize_special_phrases( ) ;
701             } else
702             {
703 0         0 carp "Warning: Call to dashrep_delete_all subroutine does not have exactly zero parameters." ;
704 0         0 return 0 ;
705             }
706              
707              
708             #-----------------------------------------------
709             # End of subroutine.
710              
711 1         2 return 1 ;
712              
713             }
714              
715              
716             =head2 dashrep_expand_parameters
717              
718             Parses a text string that is written in the
719             Dashrep language and handles parameter
720             replacements and special operations. The
721             special operations must be within
722             "[- ... -]" text strings.
723             If the supplied text string is just a
724             hyphenated phrase, it is expanded to its
725             replacement string. Otherwise, any
726             hyphenated phrase that does not appear
727             within the square-bracket pattern is
728             not replaced. (Those hyphenated phrases
729             must be replaced using either the
730             dashrep_expand_phrases,
731             dashrep_expand_phrases_except_special,
732             or dashrep_expand_special_phrases subroutines.)
733              
734             First, and only, parameter is the text -- or
735             hyphenated phrase -- that is to be expanded.
736              
737             Return value is the text after expanding
738             any parameters. Return value is an empty
739             string if there is not exactly one parameter.
740              
741             =cut
742              
743             #-----------------------------------------------
744             #-----------------------------------------------
745             # dashrep_expand_parameters
746             #-----------------------------------------------
747             #-----------------------------------------------
748              
749             sub dashrep_expand_parameters
750             {
751              
752 99     99 1 250 my $supplied_text ;
753             my $replacement_text ;
754 0         0 my $loop_status_done ;
755 0         0 my $text_begin ;
756 0         0 my $text_parameter_name ;
757 0         0 my $text_parameter_value ;
758 0         0 my $text_end ;
759 0         0 my $action_name ;
760 0         0 my $object_of_action ;
761 0         0 my $count ;
762 0         0 my $zero_one_multiple ;
763 0         0 my $empty_or_nonempty ;
764 0         0 my $full_length ;
765 0         0 my $length_half ;
766 0         0 my $string_beginning ;
767 0         0 my $string_end ;
768 0         0 my $same_or_not_same ;
769 0         0 my $sorted_numbers ;
770 0         0 my $text_parameter_placeholder ;
771 0         0 my $text_parameter ;
772 0         0 my $name_for_count ;
773 0         0 my $text_for_value ;
774 0         0 my $possible_new_limit ;
775 0         0 my $text_parameter_content ;
776 0         0 my $source_phrase ;
777 0         0 my $target_phrase ;
778 0         0 my $comparison_type ;
779 0         0 my $first_number_text ;
780 0         0 my $second_number_text ;
781 0         0 my $first_number ;
782 0         0 my $second_number ;
783 0         0 my $yes_or_no ;
784 0         0 my $first_object_of_action ;
785 0         0 my $second_object_of_action ;
786 0         0 my @list ;
787 0         0 my @list_of_sorted_numbers ;
788 0         0 my @list_of_replacements_to_auto_increment ;
789              
790              
791             #-----------------------------------------------
792             # Get the hyphenated phrase or supplied string.
793              
794 99 50       196 if ( scalar( @_ ) == 1 )
795             {
796 99         153 $supplied_text = $_[ 0 ] ;
797             } else
798             {
799 0         0 $replacement_text = "" ;
800 0         0 return $replacement_text ;
801             }
802              
803              
804             #-----------------------------------------------
805             # Use the supplied text as the default result,
806             # without leading or trailing spaces.
807              
808 99         135 $replacement_text = $supplied_text ;
809 99         138 $replacement_text =~ s/^ +//sg;
810 99         166 $replacement_text =~ s/ +$//sg;
811              
812              
813             #-----------------------------------------------
814             # If just a hyphenated phrase was supplied,
815             # expand it into its replacement text.
816              
817 99 100       499 if ( $supplied_text =~ /^ *([^\- ]+-[^ ]*[^\- ]) *$/ )
818             {
819 98         196 $supplied_text = $1 ;
820 98 100 66     563 if ( ( exists( $global_dashrep_replacement{ $supplied_text } ) ) && ( $global_dashrep_replacement{ $supplied_text } =~ /[^ ]/ ) )
821             {
822 68         140 $replacement_text = $global_dashrep_replacement{ $supplied_text } ;
823             }
824             }
825              
826              
827             #-----------------------------------------------
828             # Initialize the list of replacement names
829             # encountered that need to be auto-incremented.
830              
831 99         160 @list_of_replacements_to_auto_increment = ( ) ;
832              
833              
834             #-----------------------------------------------
835             # Update the endless loop count limit in case
836             # it has changed.
837              
838 99 50       241 if ( $global_dashrep_replacement{ "dashrep-endless-loop-counter-limit" } =~ /^[0-9]+$/ )
839             {
840 0         0 $possible_new_limit = $global_dashrep_replacement{ "dashrep-endless-loop-counter-limit" } + 0 ;
841 0 0 0     0 if ( ( $possible_new_limit != $global_endless_loop_counter_limit ) && ( $possible_new_limit > 1000 ) )
842             {
843 0         0 $global_endless_loop_counter_limit = $possible_new_limit ;
844 0 0 0     0 if ( ( $global_dashrep_replacement{ "dashrep-debug-trace-on-or-off" } eq "on" ) && ( $replacement_text =~ /[^ ]/ ) )
845             {
846 0         0 print "{{trace; updated endless loop counter limit: " . $possible_new_limit . "}}\n";
847             }
848             }
849             }
850              
851              
852             #-----------------------------------------------
853             # Begin a loop that repeats until there have
854             # been no more replacements.
855              
856 99         131 $loop_status_done = $global_false ;
857 99         245 while ( $loop_status_done == $global_false )
858             {
859 247         296 $loop_status_done = $global_true ;
860              
861 247 50 33     668 if ( ( $global_dashrep_replacement{ "dashrep-debug-trace-on-or-off" } eq "on" ) && ( $replacement_text =~ /[^ ]/ ) )
862             {
863 0         0 print "{{trace; replacement string: " . $replacement_text . "}}\n";
864             }
865              
866              
867             #-----------------------------------------------
868             # Get the next inner-most parameter syntax --
869             # with "[-" at the beginning and "-]" at the end.
870             # (It must not contain a nested parameter syntax.)
871              
872 247 100       1351 if ( $replacement_text =~ /^(.*?)\[\-([^\[\]]*)\-\](.*)$/ )
873             {
874 148         265 $text_begin = $1 ;
875 148         260 $text_parameter_content = $2 ;
876 148         247 $text_end = $3 ;
877 148         218 $text_parameter_content =~ s/^ +// ;
878 148         259 $text_parameter_content =~ s/ +$// ;
879 148         177 $loop_status_done = $global_false ;
880              
881 148 50 33     398 if ( ( $global_dashrep_replacement{ "dashrep-debug-trace-on-or-off" } eq "on" ) && ( $text_parameter_content =~ /[^ ]/ ) )
882             {
883 0         0 print "{{trace; innermost parameter: " . $text_parameter_content . "}}\n";
884             }
885              
886              
887             #-----------------------------------------------
888             # If the parameter is a defined phrase, do the
889             # replacement.
890              
891 148 100 100     1010 if ( ( $text_parameter_content !~ / / ) && ( exists( $global_dashrep_replacement{ $text_parameter_content } ) ) )
    100          
    50          
    100          
    100          
892             {
893 86         154 $text_parameter = $global_dashrep_replacement{ $text_parameter_content } ;
894 86 50       256 if ( $text_parameter =~ /[^ ]/ )
895             {
896 86         199 $replacement_text = $text_begin . $text_parameter . $text_end ;
897 86         135 $global_replacement_count_for_item_name{ $text_parameter_content } ++ ;
898 86         111 $loop_status_done = $global_false ;
899 86 50       261 if ( $text_parameter_content =~ /^auto-increment-/ )
900             {
901 0         0 push( @list_of_replacements_to_auto_increment , $text_parameter_content ) ;
902             }
903             } else
904             {
905 0         0 $replacement_text = $text_begin . " " . $text_end ;
906 0         0 $loop_status_done = $global_false ;
907             }
908              
909              
910             #-----------------------------------------------
911             # If there is a parameter value assigned -- as
912             # indicated by an equal sign -- then assign
913             # the value.
914             #
915             # Problems will arise if the parameter value
916             # contains a space, bracket, colon, or equal
917             # sign, but in those cases just specify a
918             # replacement name instead of the value of
919             # that replacement.
920              
921             } elsif ( $text_parameter_content =~ /^ *([^ \n\:=]+) *= *([^ \n\:=]+) *$/ )
922             {
923 28         55 $text_parameter_name = $1 ;
924 28         47 $text_parameter_value = $2 ;
925 28         45 $text_parameter_value =~ s/[\- ]+$// ;
926 28 50       70 if ( length( $text_parameter_name ) > 0 )
927             {
928 28         92 $global_dashrep_replacement{ $text_parameter_name } = $text_parameter_value ;
929 28         57 $global_replacement_count_for_item_name{ $text_parameter_name } ++ ;
930             }
931 28         96 $replacement_text = $text_begin . " " . $text_end ;
932 28         55 $global_replacement_count_for_item_name{ $text_parameter_value } ++ ;
933 28 50 33     119 if ( ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" ) && ( $text_parameter_name =~ /[^ ]/ ) )
934             {
935 0         0 print "{{trace; assignment: " . $text_parameter_name . " = " . $text_parameter_value . "}}\n";
936             }
937              
938              
939             #-----------------------------------------------
940             # Handle the two-operand action:
941             # append-from-phrase-to-phrase
942              
943             } elsif ( $text_parameter_content =~ /^append-from-phrase-to-phrase *: *([^\n\:=]*) +([^\n\:=]*)$/ )
944             {
945 0         0 $source_phrase = $1 ;
946 0         0 $target_phrase = $2 ;
947 0         0 $global_dashrep_replacement{ $target_phrase } .= " " . $global_dashrep_replacement{ $source_phrase } ;
948 0 0       0 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
949             {
950 0         0 print "{{trace; appended from phrase " . $source_phrase . " to phrase " . $target_phrase . "}}\n" ;
951             }
952 0         0 $replacement_text = $text_begin . " " . $text_end ;
953              
954              
955             #-----------------------------------------------
956             # Handle these two-operand actions:
957             # yes-or-no-first-number-equals-second-number
958             # yes-or-no-first-number-greater-than-second-number
959             # yes-or-no-first-number-less-than-second-number
960              
961             } elsif ( $text_parameter_content =~ /^(yes-or-no-first-number-((equals)|(greater-than)|(less-than))-second-number) *: *([0-9\,]+) +([0-9\,]+)$/ )
962             {
963 6         20 $comparison_type = $2 ;
964 6         10 $first_number_text = $6 ;
965 6         9 $second_number_text = $7 ;
966 6         11 $first_number = $first_number_text + 0 ;
967 6         7 $second_number = $second_number_text + 0 ;
968 6 100 100     60 if ( ( $comparison_type eq "equals" ) && ( $first_number == $second_number ) )
    100 100        
    100 100        
969             {
970 1         3 $yes_or_no = "yes" ;
971             } elsif ( ( $comparison_type eq "greater-than" ) && ( $first_number > $second_number ) )
972             {
973 1         3 $yes_or_no = "yes" ;
974             } elsif ( ( $comparison_type eq "less-than" ) && ( $first_number < $second_number ) )
975             {
976 1         2 $yes_or_no = "yes" ;
977             } else
978             {
979 3         12 $yes_or_no = "no" ;
980             }
981 6 50       23 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
982             {
983 0         0 print "{{trace; comparison of type " . $comparison_type . " for numbers " . $first_number_text . " and " . $second_number_text . "}}\n" ;
984             }
985 6         16 $replacement_text = $text_begin . $yes_or_no . $text_end ;
986              
987              
988             #-----------------------------------------------
989             # If there is an action requested (which
990             # may include a colon between the action and
991             # its operand(s), handle it.
992              
993             } elsif ( $text_parameter_content =~ /^([^ \n\:=]+-[^ \n\:=]+) *[: ] *([^\n\:=]*)$/ )
994             {
995 25         46 $action_name = $1 ;
996 25         43 $object_of_action = $2 ;
997 25         46 $object_of_action =~ s/\-+$// ;
998 25         35 $object_of_action =~ s/^ +// ;
999 25         34 $object_of_action =~ s/ +$// ;
1000 25 50       62 if ( $object_of_action =~ /^([^ ]+) +(.+)$/ )
1001             {
1002 0         0 $first_object_of_action = $1 ;
1003 0         0 $second_object_of_action = $2 ;
1004             }
1005              
1006 25 50 33     78 if ( ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" ) && ( $action_name =~ /[^ ]/ ) )
1007             {
1008 0         0 print "{{trace; action and object: " . $action_name . " : " . $object_of_action . "}}\n";
1009             }
1010              
1011              
1012             #-----------------------------------------------
1013             # Handle the action:
1014             # first-item-in-list
1015              
1016 25 100       171 if ( $action_name eq "first-item-in-list" )
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
    100          
    100          
    50          
    0          
1017             {
1018 1         4 @list = &dashrep_internal_split_delimited_items( $object_of_action ) ;
1019 1         3 $count = $#list + 1 ;
1020 1         4 $text_for_value = " " ;
1021 1 50       5 if ( $count > 0 )
1022             {
1023 1         3 $text_for_value = $list[ 0 ] ;
1024             }
1025 1         4 $replacement_text = $text_begin . $text_for_value . $text_end ;
1026              
1027              
1028             #-----------------------------------------------
1029             # Handle the action:
1030             # last-item-in-list
1031              
1032             } elsif ( $action_name eq "last-item-in-list" )
1033             {
1034 1         14 @list = &dashrep_internal_split_delimited_items( $object_of_action ) ;
1035 1         4 $count = $#list + 1 ;
1036 1         3 $text_for_value = " " ;
1037 1 50       4 if ( $count > 0 )
1038             {
1039 1         4 $text_for_value = $list[ $#list ] ;
1040             }
1041 1         6 $replacement_text = $text_begin . $text_for_value . $text_end ;
1042              
1043              
1044             #-----------------------------------------------
1045             # Handle the action:
1046             # count-of-list
1047              
1048             } elsif ( $action_name eq "count-of-list" )
1049             {
1050 3 100       11 if ( $object_of_action =~ /[^ ]/ )
1051             {
1052 2         7 @list = &dashrep_internal_split_delimited_items( $object_of_action ) ;
1053 2         5 $count = $#list + 1 ;
1054 2 50       9 if ( $count > 0 )
1055             {
1056 2         4 $text_for_value = $count ;
1057             } else
1058             {
1059 0         0 $text_for_value = "0" ;
1060             }
1061             } else
1062             {
1063 1         2 $text_for_value = "0" ;
1064             }
1065 3         19 $replacement_text = $text_begin . $text_for_value . $text_end ;
1066              
1067              
1068             #-----------------------------------------------
1069             # Handle the action:
1070             # zero-one-multiple-count-of-list
1071              
1072             } elsif ( $action_name eq "zero-one-multiple-count-of-list" )
1073             {
1074 3 100       14 if ( $object_of_action =~ /[^ ]/ )
1075             {
1076 2         7 @list = &dashrep_internal_split_delimited_items( $object_of_action ) ;
1077 2         6 $count = $#list + 1 ;
1078 2 50       13 if ( $count == 0 )
    100          
    50          
1079             {
1080 0         0 $name_for_count = "zero" ;
1081             } elsif ( $count == 1 )
1082             {
1083 1         3 $name_for_count = "one" ;
1084             } elsif ( $count > 1 )
1085             {
1086 1         4 $name_for_count = "multiple" ;
1087             }
1088             } else
1089             {
1090 1         3 $name_for_count = "zero" ;
1091             }
1092 3         26 $replacement_text = $text_begin . $name_for_count . $text_end ;
1093              
1094              
1095             #-----------------------------------------------
1096             # Handle the action:
1097             # zero-one-multiple
1098              
1099             } elsif ( $action_name eq "zero-one-multiple" )
1100             {
1101 3 100       16 if ( $object_of_action + 0 <= 0 )
    100          
1102             {
1103 1         2 $zero_one_multiple = "zero" ;
1104             } elsif ( $object_of_action + 0 == 1 )
1105             {
1106 1         3 $zero_one_multiple = "one" ;
1107             } else
1108             {
1109 1         2 $zero_one_multiple = "multiple" ;
1110             }
1111 3         19 $replacement_text = $text_begin . $zero_one_multiple . $text_end ;
1112              
1113              
1114             #-----------------------------------------------
1115             # Handle the action:
1116             # empty-or-nonempty
1117              
1118             } elsif ( $action_name eq "empty-or-nonempty" )
1119             {
1120 2 100       9 if ( $object_of_action =~ /[^ \n\t]/ )
1121             {
1122 1         3 $empty_or_nonempty = "nonempty" ;
1123             } else
1124             {
1125 1         38 $empty_or_nonempty = "empty" ;
1126             }
1127 2         10 $replacement_text = $text_begin . $empty_or_nonempty . $text_end ;
1128              
1129              
1130             #-----------------------------------------------
1131             # Handle the action:
1132             # empty-or-nonempty-phrase
1133              
1134             } elsif ( $action_name eq "empty-or-nonempty-phrase" )
1135             {
1136 0         0 $empty_or_nonempty = "empty" ;
1137 0 0       0 if ( $object_of_action =~ /[^ \n\t]/ )
1138             {
1139 0 0       0 if ( exists( $global_dashrep_replacement{ $object_of_action } ) )
1140             {
1141 0 0       0 if ( $global_dashrep_replacement{ $object_of_action } =~ /[^ \n\t]/ )
1142             {
1143 0         0 $empty_or_nonempty = "nonempty" ;
1144             }
1145             }
1146             }
1147 0         0 $replacement_text = $text_begin . $empty_or_nonempty . $text_end ;
1148              
1149              
1150             #-----------------------------------------------
1151             # Handle the action:
1152             # same-or-not-same
1153              
1154             } elsif ( $action_name eq "same-or-not-same" )
1155             {
1156 3         5 $full_length = length( $object_of_action ) ;
1157 3         8 $length_half = int( $full_length / 2 ) ;
1158 3         10 $string_beginning = substr( $object_of_action , 0 , $length_half ) ;
1159 3         7 $string_end = substr( $object_of_action , $full_length - $length_half , $length_half ) ;
1160 3 100       9 if ( $string_beginning eq $string_end )
1161             {
1162 1         3 $same_or_not_same = "same" ;
1163             } else
1164             {
1165 2         4 $same_or_not_same = "not-same" ;
1166             }
1167 3         12 $replacement_text = $text_begin . $same_or_not_same . $text_end ;
1168              
1169              
1170             #-----------------------------------------------
1171             # Handle the action:
1172             # sort-numbers
1173              
1174             } elsif ( $action_name eq "sort-numbers" )
1175             {
1176 1 50       5 if ( $object_of_action =~ /[1-9]/ )
1177             {
1178 1         2 $object_of_action =~ s/ +/,/gs ;
1179 1         2 $object_of_action =~ s/^,// ;
1180 1         2 $object_of_action =~ s/,$// ;
1181 1         19 @list = split( /,+/ , $object_of_action ) ;
1182 1         7 @list_of_sorted_numbers = sort { $a <=> $b } @list ;
  7         14  
1183 1         4 $sorted_numbers = join( "," , @list_of_sorted_numbers ) ;
1184             } else
1185             {
1186 0         0 $sorted_numbers = " " ;
1187             }
1188 1         4 $replacement_text = $text_begin . $sorted_numbers . $text_end ;
1189              
1190              
1191             #-----------------------------------------------
1192             # Handle the action:
1193             # unique-value
1194             #
1195             # Currently this action is equivalent to the
1196             # auto-increment action.
1197             # It can be changed to accomodate a
1198             # parallel-processing environment where the
1199             # code here would assign values from separate
1200             # blocks of numbers assigned to each
1201             # processor/process.
1202              
1203             } elsif ( $action_name eq "unique-value" )
1204             {
1205 3 100       12 if ( exists( $global_dashrep_replacement{ $object_of_action } ) )
1206             {
1207 2         7 $global_dashrep_replacement{ $object_of_action } = $global_dashrep_replacement{ $object_of_action } + 1 ;
1208             } else
1209             {
1210 1         2 $global_dashrep_replacement{ $object_of_action } = 1 ;
1211             }
1212 3         20 $replacement_text = $text_begin . " " . $text_end ;
1213              
1214              
1215             #-----------------------------------------------
1216             # Handle the action:
1217             # auto-increment
1218              
1219             } elsif ( $action_name eq "auto-increment" )
1220             {
1221 3 100       12 if ( exists( $global_dashrep_replacement{ $object_of_action } ) )
1222             {
1223 2         8 $global_dashrep_replacement{ $object_of_action } = $global_dashrep_replacement{ $object_of_action } + 1 ;
1224             } else
1225             {
1226 1         4 $global_dashrep_replacement{ $object_of_action } = 1 ;
1227             }
1228 3         11 $replacement_text = $text_begin . " " . $text_end ;
1229              
1230              
1231             #-----------------------------------------------
1232             # Handle the action:
1233             # create-list-named
1234              
1235             } elsif ( $action_name eq "create-list-named" )
1236             {
1237 2         5 push ( @global_list_of_lists_to_generate , $object_of_action ) ;
1238 2         8 $replacement_text = $text_begin . " " . $text_end ;
1239              
1240              
1241             #-----------------------------------------------
1242             # Handle the action:
1243             # insert-phrase-with-brackets-after-next-top-line
1244             # For now, just get the phrase name.
1245              
1246             } elsif ( $action_name eq "insert-phrase-with-brackets-after-next-top-line" )
1247             {
1248 0         0 $global_phrase_to_insert_after_next_top_level_line = $object_of_action ;
1249 0         0 $global_top_line_count_for_insert_phrase = 1 ;
1250 0         0 $replacement_text = $text_begin . " " . $text_end ;
1251 0 0       0 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
1252             {
1253 0         0 print "{{trace; got phrase to insert after next line: " . $global_phrase_to_insert_after_next_top_level_line . "}}\n" ;
1254             }
1255              
1256              
1257             #-----------------------------------------------
1258             # Terminate the branching that handles a
1259             # parameter that looks like it might begin with
1260             # an action name, but doesn't. Just leave the
1261             # text unchanged, but remove the "[-" and "-]"
1262             # strings.
1263              
1264             } else
1265             {
1266 0 0 0     0 if ( ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" ) && ( $action_name =~ /[^ ]/ ) )
1267             {
1268 0         0 print "{{trace; action not recognized: " . $action_name . "}}\n";
1269             }
1270 0         0 $replacement_text = $text_begin . " " . $text_parameter_content . " " . $text_end ;
1271             }
1272              
1273              
1274             #-----------------------------------------------
1275             # If the parameter content has not been
1276             # recognized, simply remove the "[-" and "-]"
1277             # strings.
1278              
1279             } else
1280             {
1281 3         13 $replacement_text = $text_begin . $text_parameter_content . $text_end ;
1282             }
1283              
1284              
1285             #-----------------------------------------------
1286             # Avoid an endless loop (caused by a replacement
1287             # containing, at some level, itself).
1288              
1289 148         190 $global_endless_loop_counter ++ ;
1290 148 50       592 if ( $global_endless_loop_counter > $global_endless_loop_counter_limit )
1291             {
1292 0         0 &dashrep_internal_endless_loop_info( ) ;
1293 0         0 die "Error: The dashrep_expand_parameters subroutine encountered an endless loop." . "\n" . "Stopped" ;
1294             }
1295              
1296              
1297             #-----------------------------------------------
1298             # Repeat the loop that gets the next inner-most
1299             # parameter syntax.
1300              
1301             }
1302              
1303              
1304             #-----------------------------------------------
1305             # Repeat the loop that repeats until no
1306             # replacement was done.
1307              
1308             }
1309              
1310              
1311             #-----------------------------------------------
1312             # For each encountered replacement that begins
1313             # with "auto-increment-", increment its value.
1314              
1315 99         216 foreach $text_parameter_placeholder ( @list_of_replacements_to_auto_increment )
1316             {
1317 0         0 $global_dashrep_replacement{ $text_parameter_placeholder } ++ ;
1318             }
1319 99         152 @list_of_replacements_to_auto_increment = ( ) ;
1320              
1321              
1322             #-----------------------------------------------
1323             # Return the revised text.
1324              
1325 99         371 return $replacement_text ;
1326              
1327              
1328             #-----------------------------------------------
1329             # End of subroutine.
1330              
1331             }
1332              
1333              
1334             =head2 dashrep_generate_lists
1335              
1336             Internal subroutine, not exported.
1337             It is only needed within the Dashrep module.
1338              
1339             =cut
1340              
1341              
1342             #-----------------------------------------------
1343             #-----------------------------------------------
1344             # Non-exported subroutine:
1345             #
1346             # dashrep_generate_lists
1347             #-----------------------------------------------
1348             #-----------------------------------------------
1349             # Generates one or more lists, and the elements
1350             # in them, and puts each list and each element
1351             # into a named replacement.
1352             # Allows new list names to be specified
1353             # while generating the initial lists.
1354              
1355             # This subroutine is not exported because it
1356             # is only needed within this Dashrep module.
1357              
1358             sub dashrep_generate_lists
1359             {
1360              
1361 10     10 1 14 my $list_name ;
1362             my $generated_list_name ;
1363 0         0 my $parameter_name ;
1364 0         0 my $do_nothing ;
1365 0         0 my $list_prefix ;
1366 0         0 my $list_separator ;
1367 0         0 my $list_suffix ;
1368 0         0 my $replacement_name ;
1369 0         0 my $delimited_list_of_parameters ;
1370 0         0 my $pointer ;
1371 0         0 my $parameter ;
1372 0         0 my $item_name ;
1373 0         0 my @list_of_parameters ;
1374 0         0 my %already_generated_list_named ;
1375              
1376              
1377             #-----------------------------------------------
1378             # Begin a loop that handles each list to
1379             # be generated.
1380              
1381 10         23 foreach $list_name ( @global_list_of_lists_to_generate )
1382             {
1383              
1384              
1385             #-----------------------------------------------
1386             # Don't generate the same list more than once.
1387              
1388 13 100       42 if ( exists( $already_generated_list_named{ $list_name } ) )
1389             {
1390 3 50       14 if ( $already_generated_list_named{ $list_name } == $global_true )
1391             {
1392 3         12 next ;
1393             }
1394             }
1395 10         26 $already_generated_list_named{ $list_name } = $global_true ;
1396              
1397              
1398             #-----------------------------------------------
1399             # Get information about the list being generated.
1400              
1401 10         19 $generated_list_name = "generated-list-named-" . $list_name ;
1402 10 50       69 if ( exists( $global_dashrep_replacement{ "parameter-name-for-list-named-" . $list_name } ) )
1403             {
1404 10         24 $parameter_name = $global_dashrep_replacement{ "parameter-name-for-list-named-" . $list_name } ;
1405             } else
1406             {
1407 0         0 $parameter_name = "unspecified-parameter-name-for-list-named-" . $list_name ;
1408 0 0       0 if ( $global_dashrep_replacement{ "dashrep-debug-trace-on-or-off" } eq "on" )
1409             {
1410 0         0 print "{{trace; WARNING: phrase parameter-name-for-list-named-" . $list_name . " is not defined}}\n";
1411             }
1412             }
1413              
1414              
1415             #-----------------------------------------------
1416             # If the list prefix, separator, or suffix is
1417             # not defined, set it to empty (the default
1418             # value).
1419              
1420 10 100       33 if ( not( exists( $global_dashrep_replacement{ "prefix-for-list-named-" . $list_name } ) ) )
1421             {
1422 1         5 $global_dashrep_replacement{ "prefix-for-list-named-" . $list_name } = "" ;
1423             }
1424 10         30 $list_prefix = &dashrep_expand_parameters( "prefix-for-list-named-" . $list_name ) . "\n" ;
1425              
1426 10 100       40 if ( not( exists( $global_dashrep_replacement{ "separator-for-list-named-" . $list_name } ) ) )
1427             {
1428 1         5 $global_dashrep_replacement{ "separator-for-list-named-" . $list_name } = "" ;
1429             }
1430 10         24 $list_separator = &dashrep_expand_parameters( "separator-for-list-named-" . $list_name ) . "\n" ;
1431              
1432 10 100       36 if ( not( exists( $global_dashrep_replacement{ "suffix-for-list-named-" . $list_name } ) ) )
1433             {
1434 1         4 $global_dashrep_replacement{ "suffix-for-list-named-" . $list_name } = "" ;
1435             }
1436 10         29 $list_suffix = &dashrep_expand_parameters( "suffix-for-list-named-" . $list_name ) . "\n" ;
1437              
1438              
1439             #-----------------------------------------------
1440             # Get the list of parameters that define the list.
1441              
1442 10         21 $replacement_name = "list-of-parameter-values-for-list-named-" . $list_name ;
1443 10         26 $delimited_list_of_parameters = &dashrep_expand_parameters( "list-of-parameter-values-for-list-named-" . $list_name ) ;
1444 10         29 @list_of_parameters = &dashrep_internal_split_delimited_items( $delimited_list_of_parameters ) ;
1445 10         39 $global_dashrep_replacement{ "logged-list-of-parameter-values-for-list-named-" . $list_name } = join( "," , @list_of_parameters ) ;
1446              
1447              
1448             #-----------------------------------------------
1449             # Insert a prefix at the beginning of the list.
1450              
1451 10         25 $global_dashrep_replacement{ $generated_list_name } = $list_prefix . "\n" ;
1452              
1453              
1454             #-----------------------------------------------
1455             # If the list of values is empty, skip over
1456             # the upcoming loop.
1457              
1458 10 50       29 if ( $#list_of_parameters < 0 )
1459             {
1460 0 0       0 if ( $global_dashrep_replacement{ "dashrep-debug-trace-on-or-off" } eq "on" )
1461             {
1462 0         0 print "{{trace; list named " . $list_name . " is empty}}\n";
1463             }
1464             } else
1465             {
1466              
1467              
1468             #-----------------------------------------------
1469             # Begin a loop that handles each list item.
1470             # Do not change the order of the parameters.
1471              
1472 10         31 for ( $pointer = 0 ; $pointer <= $#list_of_parameters ; $pointer ++ )
1473             {
1474 50         67 $parameter = $list_of_parameters[ $pointer ] ;
1475 50         85 $global_dashrep_replacement{ $parameter_name } = $parameter ;
1476              
1477              
1478             #-----------------------------------------------
1479             # Add the next item to the list.
1480              
1481 50         87 $item_name = "item-for-list-" . $list_name . "-and-parameter-" . $parameter ;
1482 50         96 $global_dashrep_replacement{ $generated_list_name } .= $item_name . "\n" ;
1483              
1484              
1485             #-----------------------------------------------
1486             # Using a template, generate each item in the list.
1487              
1488 50         122 $global_dashrep_replacement{ $item_name } = &dashrep_expand_parameters( "template-for-list-named-" . $list_name ) ;
1489              
1490              
1491             #-----------------------------------------------
1492             # Insert separators between items.
1493              
1494 50 100       146 if ( $pointer < $#list_of_parameters )
1495             {
1496 40         97 $global_dashrep_replacement{ $generated_list_name } .= $list_separator . "\n" ;
1497             }
1498              
1499              
1500             #-----------------------------------------------
1501             # Protect against an endless loop.
1502              
1503 50         64 $global_endless_loop_counter ++ ;
1504 50 50       180 if ( $global_endless_loop_counter > $global_endless_loop_counter_limit )
1505             {
1506 0         0 die "Error: The dashrep_generate_lists subroutine encountered an endless loop. Stopped" ;
1507             }
1508              
1509              
1510             #-----------------------------------------------
1511             # Repeat the loop for the next list item.
1512              
1513             }
1514              
1515              
1516             #-----------------------------------------------
1517             # Finish skipping over the above sections when
1518             # the list is empty.
1519              
1520             }
1521              
1522              
1523             #-----------------------------------------------
1524             # Terminate the generated list.
1525              
1526 10         38 $global_dashrep_replacement{ $generated_list_name } .= $list_suffix . "\n" ;
1527              
1528              
1529             #-----------------------------------------------
1530             # Repeat the loop for the next list to be
1531             # generated.
1532              
1533             }
1534              
1535              
1536             #-----------------------------------------------
1537             # End of subroutine.
1538              
1539 10         39 return 1 ;
1540              
1541             }
1542              
1543              
1544             =head2 dashrep_expand_phrases_except_special
1545              
1546             Expands the hyphenated phrases in a text
1547             string that is written in the Dashrep
1548             language -- except the special
1549             (built-in) hyphenated phrases that handle
1550             spaces, hyphens, tabs, and line breaks,
1551             and except the parameterized phrases.
1552              
1553             First, and only, parameter is the text
1554             string that uses the Dashrep language.
1555              
1556             Return value is the expanded text string.
1557             Return value is an empty string if there
1558             is not exactly one parameter.
1559              
1560             =cut
1561              
1562             #-----------------------------------------------
1563             #-----------------------------------------------
1564             # dashrep_expand_phrases_except_special
1565             #-----------------------------------------------
1566             #-----------------------------------------------
1567              
1568             sub dashrep_expand_phrases_except_special
1569             {
1570              
1571 10     10 1 35 my $current_item ;
1572             my $hyphenated_phrase_to_expand ;
1573 0         0 my $expanded_output_string ;
1574 0         0 my $first_item ;
1575 0         0 my $remainder ;
1576 0         0 my $replacement_item ;
1577 0         0 my @item_stack ;
1578 0         0 my @items_to_add ;
1579              
1580              
1581             #-----------------------------------------------
1582             # Initialization.
1583              
1584 10         13 $expanded_output_string = "" ;
1585              
1586              
1587             #-----------------------------------------------
1588             # Internally define the "hyphen-here" phrase.
1589              
1590 10         22 $global_dashrep_replacement{ "hyphen-here" } = "no-space - no-space" ;
1591              
1592              
1593             #-----------------------------------------------
1594             # Get the starting replacement name.
1595              
1596 10 50       26 if ( scalar( @_ ) == 1 )
1597             {
1598 10         16 $hyphenated_phrase_to_expand = $_[ 0 ] ;
1599             } else
1600             {
1601 0         0 $expanded_output_string = "" ;
1602 0         0 return $expanded_output_string ;
1603             }
1604              
1605              
1606             #-----------------------------------------------
1607             # Generate any needed lists.
1608              
1609 10         20 &dashrep_generate_lists ;
1610              
1611              
1612             #-----------------------------------------------
1613             # Start with a single phrase on a stack.
1614              
1615 10         16 @item_stack = ( ) ;
1616 10         21 push( @item_stack , $hyphenated_phrase_to_expand ) ;
1617              
1618              
1619             #-----------------------------------------------
1620             # Begin a loop that does all the replacements.
1621              
1622 10         28 while( $#item_stack >= 0 )
1623             {
1624              
1625              
1626             #-----------------------------------------------
1627             # If an endless loop occurs, handle that situation.
1628              
1629 297         379 $global_endless_loop_counter ++ ;
1630 297 50       554 if ( $global_endless_loop_counter > $global_endless_loop_counter_limit )
1631             {
1632 0         0 &dashrep_internal_endless_loop_info( ) ;
1633 0         0 die "Error: The dashrep_expand_phrases_except_special subroutine encountered an endless loop." . "\n" . "Stopped" ;
1634             }
1635              
1636              
1637             #-----------------------------------------------
1638             # Get the first/next item from the stack.
1639             # If it is empty (after removing spaces),
1640             # repeat the loop.
1641              
1642 297         418 $current_item = pop( @item_stack ) ;
1643 297         439 $current_item =~ s/^ +// ;
1644 297         441 $current_item =~ s/ +$// ;
1645 297 100       591 if ( $current_item eq "" )
1646             {
1647 1         5 next ;
1648             }
1649              
1650              
1651             #-----------------------------------------------
1652             # If the item contains a space or line break,
1653             # split the string at the first space or
1654             # line break, and push those strings onto the
1655             # stack, and then repeat the loop.
1656              
1657 296 100       1161 if ( $current_item =~ /^ *([^ ]+)[ \n\r]+(.*)$/ )
1658             {
1659 25         49 $first_item = $1 ;
1660 25         51 $remainder = $2 ;
1661 25 50       81 if ( $remainder =~ /[^ ]/ )
1662             {
1663 25         43 push( @item_stack , $remainder ) ;
1664             }
1665 25         41 push( @item_stack , $first_item ) ;
1666 25         64 next ;
1667             }
1668              
1669              
1670             #-----------------------------------------------
1671             # If the item is a hyphenated phrase that has
1672             # been defined, expand the phrase into its
1673             # associated text (its definition), split the
1674             # text at any spaces or line breaks, put those
1675             # delimited items on the stack, and repeat
1676             # the loop.
1677              
1678 271 100       619 if ( exists( $global_dashrep_replacement{ $current_item } ) )
1679             {
1680 75         137 $replacement_item = $global_dashrep_replacement{ $current_item } ;
1681 75 100       215 if ( $replacement_item =~ /[^ ]/ )
1682             {
1683 69         355 @items_to_add = split( /[ \n\r]+/ , $replacement_item ) ;
1684 69         166 push( @item_stack , reverse( @items_to_add ) ) ;
1685 69         138 $global_replacement_count_for_item_name{ $current_item } ++ ;
1686 69         2097 next ;
1687             }
1688 6         18 next ;
1689             }
1690              
1691              
1692             #-----------------------------------------------
1693             # If the item cannot be expanded, append it to
1694             # the output string.
1695              
1696 196         567 $expanded_output_string .= $current_item . " " ;
1697              
1698              
1699             #-----------------------------------------------
1700             # Repeat the loop for the next replacement.
1701              
1702             }
1703              
1704              
1705             #-----------------------------------------------
1706             # End of subroutine.
1707              
1708 10         42 return $expanded_output_string ;
1709              
1710             }
1711              
1712              
1713             =head2 dashrep_expand_special_phrases
1714              
1715             Expands only the the special (built-in)
1716             hyphenated phrases that handle hyphens,
1717             tabs, spaces and line breaks,
1718              
1719             First, and only, parameter is the
1720             text string that contains the special
1721             hyphenated phrases.
1722              
1723             Return value is the expanded text string.
1724             Return value is an empty string if there
1725             is not exactly one parameter.
1726              
1727             =cut
1728              
1729             #-----------------------------------------------
1730             #-----------------------------------------------
1731             # dashrep_expand_special_phrases
1732             #-----------------------------------------------
1733             #-----------------------------------------------
1734              
1735             sub dashrep_expand_special_phrases
1736             {
1737              
1738 26     26 1 179 my $expanded_string ;
1739             my $phrase_name ;
1740 0         0 my $code_for_non_breaking_space ;
1741 0         0 my $code_with_spaces ;
1742 0         0 my $code_begin ;
1743 0         0 my $code_end ;
1744 0         0 my $remaining_string ;
1745 0         0 my $ignore_directive ;
1746 0         0 my $capture_directive ;
1747              
1748              
1749             #-----------------------------------------------
1750             # Get the starting hyphenated-phrase.
1751              
1752 26 50       81 if ( scalar( @_ ) == 1 )
1753             {
1754 26         46 $expanded_string = $_[ 0 ] ;
1755             } else
1756             {
1757 0         0 $expanded_string = "" ;
1758 0         0 return $expanded_string ;
1759             }
1760 26 100       97 if ( $expanded_string !~ /[^ ]/ )
1761             {
1762 1         6 return "";
1763             }
1764              
1765              
1766             #-----------------------------------------------
1767             # If a single hyphenated phrase is supplied and
1768             # is defined, expand it. Otherwise, assume
1769             # it's a text string that contains the special
1770             # phrases.
1771              
1772 25 100       102 if ( $expanded_string =~ /^ *([^ \[\]]+-[^ \[\]]+) *$/ )
1773             {
1774 10         24 $phrase_name = $1 ;
1775 10 100       28 if ( exists( $global_dashrep_replacement{ $phrase_name } ) )
1776             {
1777 1         4 $expanded_string = $global_dashrep_replacement{ $phrase_name } ;
1778             }
1779             }
1780              
1781              
1782             #-----------------------------------------------
1783             # Get the ignore level. It can be accessed
1784             # from outside this subroutine in case multiple
1785             # streams of Dashrep code are being processed
1786             # in turn.
1787              
1788 25 100       86 if ( $global_dashrep_replacement{ "dashrep-ignore-level" } =~ /^[0-9]+$/ )
1789             {
1790 13         29 $global_ignore_level = $global_dashrep_replacement{ "dashrep-ignore-level" } + 0 ;
1791             }
1792              
1793              
1794             #-----------------------------------------------
1795             # Get the capture level. It can be accessed
1796             # from outside this subroutine in case multiple
1797             # streams of Dashrep code are being processed
1798             # in turn.
1799              
1800 25 100       65 if ( $global_dashrep_replacement{ "dashrep-capture-level" } =~ /^[0-9]+$/ )
1801             {
1802 7         16 $global_capture_level = $global_dashrep_replacement{ "dashrep-capture-level" } + 0 ;
1803             }
1804              
1805              
1806             #-----------------------------------------------
1807             # If the ignore level and capture level are both
1808             # non-zero, indicate an error (because they
1809             # overlap).
1810              
1811 25 50 66     86 if ( ( $global_ignore_level > 0 ) && ( $global_capture_level > 0 ) )
1812             {
1813 0         0 $expanded_string .= " [warning: ignore and capture directives overlap, both directives reset] " ;
1814 0         0 $global_ignore_level = 0 ;
1815 0         0 $global_capture_level = 0 ;
1816             }
1817              
1818              
1819             #-----------------------------------------------
1820             # Handle the directives:
1821             # "ignore-begin-here" and
1822             # "ignore-end-here"
1823              
1824 25         36 $remaining_string = $expanded_string ;
1825 25         35 $expanded_string = "" ;
1826              
1827 25 100 100     76 if ( ( $global_ignore_level > 0 ) && ( $remaining_string !~ /((ignore-begin-here)|(ignore-end-here))/si ) )
1828             {
1829 1 50       5 if ( $global_dashrep_replacement{ "dashrep-ignore-trace-on-or-off" } eq "on" )
1830             {
1831 0         0 print "{{trace; ignore level: " . $global_ignore_level . "}}\n" ;
1832 0 0       0 if ( $remaining_string =~ /[^ ]/ )
1833             {
1834 0         0 print "{{trace; ignored: " . $remaining_string . "}}\n" ;
1835             }
1836             }
1837 1         3 $remaining_string = "" ;
1838             }
1839              
1840 25         180 while ( $remaining_string =~ /^((.*? +)?)((ignore-begin-here)|(ignore-end-here))(( +.*)?)$/si )
1841             {
1842 4         8 $code_begin = $1 ;
1843 4         8 $ignore_directive = $3 ;
1844 4         9 $remaining_string = $6 ;
1845              
1846 4 100       10 if ( $global_ignore_level > 0 )
1847             {
1848 2 50       9 if ( $global_dashrep_replacement{ "dashrep-ignore-trace-on-or-off" } eq "on" )
1849             {
1850 0         0 print "{{trace; ignore level: " . $global_ignore_level . "}}\n" ;
1851 0 0       0 if ( $remaining_string =~ /[^ ]/ )
1852             {
1853 0         0 print "{{trace; ignored: " . $code_begin . "}}\n" ;
1854             }
1855             }
1856             } else
1857             {
1858 2         19 $expanded_string .= $code_begin . " " ;
1859             }
1860              
1861 4 100       15 if ( $ignore_directive eq "ignore-begin-here" )
    50          
1862             {
1863 2 50       7 if ( $global_dashrep_replacement{ "dashrep-ignore-trace-on-or-off" } eq "on" )
1864             {
1865 0         0 print "{{trace; ignore directive: " . $ignore_directive . "}}\n" ;
1866             }
1867 2         3 $global_ignore_level ++ ;
1868 2         77 $global_dashrep_replacement{ "dashrep-ignore-level" } = sprintf( "%d" , $global_ignore_level ) ;
1869             } elsif ( $ignore_directive eq "ignore-end-here" )
1870             {
1871 2 50       8 if ( $global_dashrep_replacement{ "dashrep-ignore-trace-on-or-off" } eq "on" )
1872             {
1873 0         0 print "{{trace; ignore directive: " . $ignore_directive . "}}\n" ;
1874             }
1875 2         3 $global_ignore_level -- ;
1876 2         11 $global_dashrep_replacement{ "dashrep-ignore-level" } = sprintf( "%d" , $global_ignore_level ) ;
1877             }
1878             }
1879 25         48 $expanded_string .= $remaining_string ;
1880              
1881              
1882             #-----------------------------------------------
1883             # Handle the directives:
1884             # "capture-begin-here" and
1885             # "capture-end-here"
1886              
1887 25         33 $remaining_string = $expanded_string ;
1888 25         32 $expanded_string = "" ;
1889              
1890 25 100 100     74 if ( ( $global_capture_level > 0 ) && ( $remaining_string !~ /((capture-begin-here)|(capture-end-here))/si ) )
1891             {
1892 1         4 $global_dashrep_replacement{ "captured-text" } .= " " . $remaining_string ;
1893 1 50       6 if ( $global_dashrep_replacement{ "dashrep-capture-trace-on-or-off" } eq "on" )
1894             {
1895 0         0 print "{{trace; capture level: " . $global_capture_level . "}}\n" ;
1896 0 0       0 if ( $remaining_string =~ /[^ ]/ )
1897             {
1898 0         0 print "{{trace; captured: " . $remaining_string . "}}\n" ;
1899             }
1900             }
1901 1         2 $remaining_string = "" ;
1902             }
1903              
1904 25         155 while ( $remaining_string =~ /^((.*? +)?)((capture-begin-here)|(capture-end-here))(( +.*)?)$/si )
1905             {
1906 4         10 $code_begin = $1 ;
1907 4         25 $capture_directive = $3 ;
1908 4         28 $remaining_string = $6 ;
1909              
1910 4 100       12 if ( $global_capture_level > 0 )
1911             {
1912 2         5 $global_dashrep_replacement{ "captured-text" } .= " " . $code_begin ;
1913 2 50       8 if ( $global_dashrep_replacement{ "dashrep-capture-trace-on-or-off" } eq "on" )
1914             {
1915 0         0 print "{{trace; capture level: " . $global_capture_level . "}}\n" ;
1916 0 0       0 if ( $remaining_string =~ /[^ ]/ )
1917             {
1918 0         0 print "{{trace; captured: " . $code_begin . "}}\n" ;
1919             }
1920             }
1921             } else
1922             {
1923 2         6 $expanded_string .= $code_begin . " " ;
1924             }
1925              
1926 4 100       14 if ( $capture_directive eq "capture-begin-here" )
    50          
1927             {
1928 2         5 $global_dashrep_replacement{ "captured-text" } = "" ;
1929 2 50       8 if ( $global_dashrep_replacement{ "dashrep-capture-trace-on-or-off" } eq "on" )
1930             {
1931 0         0 print "{{trace; capture directive: " . $capture_directive . "}}\n" ;
1932             }
1933 2         3 $global_capture_level ++ ;
1934 2         18 $global_dashrep_replacement{ "dashrep-capture-level" } = sprintf( "%d" , $global_capture_level ) ;
1935             } elsif ( $capture_directive eq "capture-end-here" )
1936             {
1937 2 50       7 if ( $global_dashrep_replacement{ "dashrep-capture-trace-on-or-off" } eq "on" )
1938             {
1939 0         0 print "{{trace; capture directive: " . $capture_directive . "}}\n" ;
1940             }
1941 2         3 $global_capture_level -- ;
1942 2         10 $global_dashrep_replacement{ "dashrep-capture-level" } = sprintf( "%d" , $global_capture_level ) ;
1943             }
1944             }
1945 25         39 $expanded_string .= $remaining_string ;
1946              
1947              
1948             #-----------------------------------------------
1949             # Handle the directive:
1950             # "non-breaking-space"
1951              
1952 25         44 $code_for_non_breaking_space = $global_dashrep_replacement{ "non-breaking-space" } ;
1953 25         118 while ( $expanded_string =~ /^(.* +)?non-breaking-space( +.*)?$/sgi )
1954             {
1955 1         3 $code_begin = $1 ;
1956 1         2 $code_end = $2 ;
1957 1         21 $code_begin =~ s/ +$//si ;
1958 1         4 $code_end =~ s/^ +//si ;
1959 1         4 $expanded_string = $code_begin . $code_for_non_breaking_space . $code_end ;
1960             }
1961              
1962              
1963             #-----------------------------------------------
1964             # Handle the directives:
1965             # "span-non-breaking-spaces-begin" and
1966             # "span-non-breaking-spaces-end"
1967              
1968 25         40 $code_for_non_breaking_space = $global_dashrep_replacement{ "non-breaking-space" } ;
1969 25         118 while ( $expanded_string =~ /^(.*)\bspan-non-breaking-spaces-begin\b *(.*?) *\bspan-non-breaking-spaces-end\b(.*)$/sgi )
1970             {
1971 1         3 $code_begin = $1 ;
1972 1         2 $code_with_spaces = $2 ;
1973 1         2 $code_end = $3 ;
1974 1         8 $code_with_spaces =~ s/ +/ ${code_for_non_breaking_space} /sgi ;
1975 1         6 $code_with_spaces =~ s/ +//sgi ;
1976 1         4 $expanded_string = $code_begin . $code_with_spaces . $code_end ;
1977             }
1978              
1979              
1980             #-----------------------------------------------
1981             # Replace multiple spaces and tabs with single spaces.
1982              
1983 25         81 $expanded_string =~ s/[ \n][ \t]+/ /sg ;
1984              
1985              
1986             #-----------------------------------------------
1987             # Handle the directive:
1988             # "tab-here"
1989              
1990 25         47 $expanded_string =~ s/ *\btab-here\b */\t/sg ;
1991              
1992              
1993             #-----------------------------------------------
1994             # Handle the directives:
1995             # "empty-line" and "new-line"
1996              
1997 25         46 $expanded_string =~ s/ *\bempty-line\b */\n\n/sg ;
1998 25         63 $expanded_string =~ s/ *\bnew-line\b */\n/sg ;
1999              
2000              
2001             #-----------------------------------------------
2002             # Concatenate lines and spaces as indicated by
2003             # the "no-space" and "one-space" directives.
2004              
2005 25         90 $expanded_string =~ s/\bone-space\b//sgi ;
2006              
2007 25         118 $expanded_string =~ s/\bno-space\b//sgi ;
2008              
2009 25         92 $expanded_string =~ s/[ \t]+[ \t]*//sgi ;
2010 25         70 $expanded_string =~ s/[ \t]*[ \t]+//sgi ;
2011 25         73 $expanded_string =~ s///sgi ;
2012 25         36 $expanded_string =~ s///sgi ;
2013              
2014 25         45 $expanded_string =~ s/[ \t]+[ \t]*//sgi ;
2015 25         46 $expanded_string =~ s/[ \t]*[ \t]+//sgi ;
2016 25         44 $expanded_string =~ s// /sgi ;
2017 25         70 $expanded_string =~ s// /sgi ;
2018              
2019              
2020             #-----------------------------------------------
2021             # End of subroutine.
2022              
2023 25         85 return $expanded_string ;
2024              
2025             }
2026              
2027              
2028             =head2 dashrep_expand_phrases
2029              
2030             Expands all the hyphenated phrases
2031             in a text string that is written in the
2032             Dashrep language. This includes expanding
2033             the special (built-in) hyphenated phrases
2034             that handle spaces, hyphens, and line breaks.
2035              
2036             First, and only, parameter is the text string
2037             that may contain hyphenated phrases to be
2038             expanded.
2039              
2040             Return value is the expanded text string.
2041             Return value is an empty string if there is not
2042             exactly one parameter.
2043              
2044             =cut
2045              
2046             #-----------------------------------------------
2047             #-----------------------------------------------
2048             # dashrep_expand_phrases
2049             #-----------------------------------------------
2050             #-----------------------------------------------
2051              
2052             sub dashrep_expand_phrases
2053             {
2054              
2055 9     9 1 115 my $text_string_to_expand ;
2056             my $partly_expanded_string ;
2057 0         0 my $expanded_string ;
2058              
2059              
2060             #-----------------------------------------------
2061             # Get the starting hyphenated-phrase.
2062              
2063 9 50       28 if ( scalar( @_ ) == 1 )
2064             {
2065 9         15 $text_string_to_expand = $_[ 0 ] ;
2066             } else
2067             {
2068 0         0 $expanded_string = "" ;
2069 0         0 return $expanded_string ;
2070             }
2071              
2072              
2073             #-----------------------------------------------
2074             # Expand the phrase except for special phrases.
2075              
2076 9         21 $partly_expanded_string = &dashrep_expand_phrases_except_special( $text_string_to_expand ) ;
2077 9 50       29 if ( $global_dashrep_replacement{ "dashrep-linewise-trace-on-or-off" } eq "on" )
2078             {
2079 0         0 print "{{trace; after non-special phrases expanded: " . $partly_expanded_string . "}}\n" ;
2080             }
2081              
2082              
2083             #-----------------------------------------------
2084             # Handle special directives:
2085             # "empty-line" and "new-line" and
2086             # "no-space" and "one-space" and others
2087              
2088 9         25 $expanded_string = &dashrep_expand_special_phrases( $partly_expanded_string ) ;
2089              
2090              
2091             #-----------------------------------------------
2092             # End of subroutine.
2093              
2094 9         42 return $expanded_string ;
2095              
2096             }
2097              
2098              
2099             =head2 dashrep_xml_tags_to_dashrep
2100              
2101             Converts a single line of XML code into Dashrep
2102             code in which XML tags are replaced by Dashrep
2103             phrases.
2104             Tags are replaced by hyphenated phrases that
2105             are named according to the accumulated XML
2106             tag names, with "begin-" and "end-" to indicate
2107             the beginning and ending tags. The prefix
2108             "begin-and-end-" indicates a self-terminating
2109             XML tag (e.g. "
").
2110             If the resulting phrase has a Dashrep definition,
2111             that definition (which is assumed to be a single
2112             phrase) is used instead.
2113             If the non-tag content contains any hyphens,
2114             they are replaced with the phrase "hyphen-here".
2115             If a tag's opening bracket (<) and closing
2116             bracket (>) are not both on the same line, the
2117             tag will not be recognized.
2118              
2119             =cut
2120              
2121              
2122             #-----------------------------------------------
2123             #-----------------------------------------------
2124             # dashrep_xml_tags_to_dashrep
2125             #-----------------------------------------------
2126             #-----------------------------------------------
2127              
2128             sub dashrep_xml_tags_to_dashrep
2129             {
2130              
2131 3     3 1 10 my $input_text ;
2132             my $first_tag_name ;
2133 0         0 my $output_text ;
2134 0         0 my $open_brackets ;
2135 0         0 my $close_brackets ;
2136 0         0 my $remaining_string ;
2137 0         0 my $prefix_text ;
2138 0         0 my $tag_full ;
2139 0         0 my $suffix_text ;
2140 0         0 my $tag_name ;
2141 0         0 my $previous_input_text ;
2142 0         0 my $text_before_tag ;
2143 0         0 my $tag_and_possible_parameters ;
2144 0         0 my $parameter_name ;
2145 0         0 my $parameter_value ;
2146 0         0 my $text_after_tag ;
2147 0         0 my $revised_tags ;
2148 0         0 my $possible_slash ;
2149 0         0 my $may_include_closing_slash ;
2150 0         0 my $previous_tag_name ;
2151 0         0 my $sequence_without_hyphen_prefix ;
2152 0         0 my $starting_position_of_last_tag_name ;
2153 0         0 my $full_phrase ;
2154              
2155              
2156             #-----------------------------------------------
2157             # Get the input text.
2158              
2159 3 50       10 if ( scalar( @_ ) == 1 )
2160             {
2161 3         8 $input_text = $_[ 0 ] ;
2162             } else
2163             {
2164 0         0 carp "Warning: Call to xml_tags_to_dashrep subroutine does not have exactly one parameter." ;
2165 0         0 return 0 ;
2166             }
2167              
2168              
2169             #-----------------------------------------------
2170             # Trim spaces from the input line, and clear
2171             # the output text.
2172              
2173 3         6 $input_text =~ s/^ +// ;
2174 3         16 $input_text =~ s/ +$// ;
2175 3         6 $output_text = "" ;
2176              
2177              
2178             #-----------------------------------------------
2179             # Get the tag name that is regarded as at
2180             # the highest level of interest. Tags at
2181             # higher levels are ignored.
2182              
2183 3         5 $first_tag_name = $global_dashrep_replacement{ "dashrep-first-xml-tag-name" } ;
2184              
2185              
2186             #-----------------------------------------------
2187             # If a line does not contain the same number
2188             # of open angle brackets (<) as close angle
2189             # brackets (>), and tracing is on, issue a
2190             # warning.
2191              
2192 3         6 $open_brackets = $input_text ;
2193 3         143 $open_brackets =~ s/[^<]//g ;
2194 3         7 $close_brackets = $input_text ;
2195 3         151 $close_brackets =~ s/[^>]//g ;
2196 3 50       15 if ( length( $open_brackets ) != length( $close_brackets ) )
2197             {
2198 0 0       0 if ( $global_dashrep_replacement{ "dashrep-xml-trace-on-or-off" } eq "on" )
2199             {
2200 0         0 print "{{trace; non-matching angle brackets: " . $input_text . "}}\n" ;
2201             }
2202             }
2203              
2204              
2205             #-----------------------------------------------
2206             # If a tag is identified -- through use of
2207             # special hyphenated phrases -- as of the
2208             # open-and-close type that may not include a
2209             # closing slash (such as "
"), then insert
2210             # a closing tag.
2211             # Note that the match is case-sensitive.
2212              
2213 3         6 $remaining_string = $input_text ;
2214 3         5 $input_text = "" ;
2215 3         22 while ( $remaining_string =~ /^(.*?)(<[^ <>\/][^>]*[^>\/]>)(.*)$/ )
2216             {
2217 14         25 $prefix_text = $1 ;
2218 14         24 $tag_full = $2 ;
2219 14         24 $suffix_text = $3 ;
2220 14         22 $tag_name = $tag_full ;
2221 14         56 $tag_name =~ s/^<([^ >\/]+).*>$/$1/ ;
2222 14 50       31 if ( $tag_name ne "" )
2223             {
2224 14 50       44 if ( exists( $global_dashrep_replacement{ "dashrep-xml-yes-handle-open-close-tag-" . $tag_name } ) )
2225             {
2226 0         0 $tag_full .= '" ;
2227 0 0       0 if ( $global_dashrep_replacement{ "dashrep-xml-trace-on-or-off" } eq "on" )
2228             {
2229 0         0 print "{{trace; open-and-close type xml tag: " . $tag_name . " , modified to include closing tag: " . $tag_full . "}}\n" ;
2230             }
2231             }
2232             }
2233 14         30 $input_text .= $prefix_text . $tag_full ;
2234 14         75 $remaining_string = $suffix_text ;
2235             }
2236 3         6 $input_text .= $remaining_string ;
2237              
2238              
2239             #-----------------------------------------------
2240             # If one of the parameters within a tag is a
2241             # "style" tag that has multiple CSS
2242             # parameters with their own parameter values
2243             # (with a colon (:) separating each
2244             # sub-parameter name from its sub-parameter
2245             # value, and with semicolons (;) separating
2246             # those name & value pairs within the XML
2247             # parameter), split up those sub-parameters
2248             # into separate parameters (with combined
2249             # names).
2250              
2251 3         6 $previous_input_text = "" ;
2252 3         8 while ( $input_text ne $previous_input_text )
2253             {
2254 3         4 $previous_input_text = $input_text ;
2255 3         6 $input_text =~ s/(<[^>]+ style) *= *\"([^\"\:\;>]+) *: *([^\"\:\;>]*) *; *([^\">]+)\"([^>]*>)/$1_$2=\"$3\" style=\"$4\"$5/sgi ;
2256 3         6 $input_text =~ s/(<[^>]+ style) *= *\"([^\"\:\;>]+) *: *([^\"\:\;>]*)\"([^>]*>)/$1_$2=\"$3\"$4/sgi ;
2257 3 50       14 if ( $global_dashrep_replacement{ "dashrep-xml-trace-on-or-off" } eq "on" )
2258             {
2259 0 0       0 if ( $previous_input_text ne $input_text )
2260             {
2261 0         0 print "{{trace; after xml sub-parameters extracted: " . $input_text . "}}\n" ;
2262             }
2263             }
2264             }
2265              
2266              
2267             #-----------------------------------------------
2268             # Expand parameters within a tag into separate
2269             # XML tags.
2270             # TODO: Insert "begin-xml-tag-parameters" and
2271             # "end-xml-tag-parameters" around parameters.
2272              
2273 3         20 while ( $input_text =~ /^(.*)(<[^ >\!\?\/][^>]*) ([^ >\=]+)=((\"([^>\"]*)\")|([^ >\"\']+)) *>(.*)$/ )
2274             {
2275 0         0 $text_before_tag = $1 ;
2276 0         0 $tag_and_possible_parameters = $2 ;
2277 0         0 $parameter_name = $3 ;
2278 0         0 $parameter_value = $4 ;
2279 0         0 $text_after_tag = $8 ;
2280 0         0 $parameter_value =~ s/^\"(.*)\"$/$1/ ;
2281 0         0 $parameter_name =~ s/\-/_/g ;
2282 0         0 $revised_tags = $tag_and_possible_parameters . "><" . $parameter_name . ">" . $parameter_value . '" ;
2283 0         0 $input_text = $text_before_tag . $revised_tags . $text_after_tag ;
2284 0 0       0 if ( $global_dashrep_replacement{ "dashrep-xml-trace-on-or-off" } eq "on" )
2285             {
2286 0         0 print "{{trace; after xml parameter extracted: " . $revised_tags . "}}\n" ;
2287             }
2288             }
2289              
2290              
2291             #-----------------------------------------------
2292             # Begin a loop that repeats for each XML tag.
2293             #
2294             # Get the name within a (single) tag, and
2295             # ignore any other content within the tag.
2296             # Ignore the opening XML-standard-required
2297             # declaration.
2298              
2299 3         55 while ( $input_text =~ /^ *([^<>]*)<(\/?)([^ >\?\/]+[^ >\/]*)([^>]*)>(.*)$/ )
2300             {
2301 27         47 $text_before_tag = $1 ;
2302 27         45 $possible_slash = $2 ;
2303 27         38 $tag_name = $3 ;
2304 27         46 $may_include_closing_slash = $4 ;
2305 27         48 $suffix_text = $5 ;
2306 27 50       69 if ( $global_dashrep_replacement{ "dashrep-xml-trace-on-or-off" } eq "on" )
2307             {
2308 0         0 print "{{trace; input line: " . $input_text . "}}\n" ;
2309             }
2310 27         45 $input_text = $suffix_text ;
2311 27 50       60 if ( $global_dashrep_replacement{ "dashrep-xml-trace-on-or-off" } eq "on" )
2312             {
2313 0         0 print "{{trace; tag: <" . $possible_slash . $tag_name . ">}}\n" ;
2314             }
2315              
2316              
2317             #-----------------------------------------------
2318             # If the non-tag content text contains any
2319             # hyphens, replace them with the phrase
2320             # "hypen-here".
2321              
2322 27         41 $text_before_tag =~ s/\-/dashrep_internal_hyphen_here/sg ;
2323 27         29 $text_before_tag =~ s/dashrep_internal_hyphen_here/ hyphen-here /sg ;
2324              
2325              
2326             #-----------------------------------------------
2327             # If any text precedes the tag, write it on a
2328             # separate line.
2329              
2330 27 100       66 if ( $text_before_tag =~ /[^ ]/ )
2331             {
2332 8 50       24 if ( $global_ignore_level <= 0 )
2333             {
2334 8         20 $output_text .= $text_before_tag . "\n" ;
2335             }
2336             }
2337              
2338              
2339             #-----------------------------------------------
2340             # If a specially named Dashrep phrase indicates
2341             # that the tag should be ignored, ignore it.
2342              
2343 27 50       66 if ( exists( $global_dashrep_replacement{ "dashrep-xml-yes-ignore-tag-named-" . $tag_name } ) )
2344             {
2345 0 0       0 if ( $global_dashrep_replacement{ "dashrep-xml-yes-ignore-tag-named-" . $tag_name } eq "yes" )
2346             {
2347 0 0       0 if ( $global_dashrep_replacement{ "dashrep-xml-trace-on-or-off" } eq "on" )
2348             {
2349 0         0 print "{{trace; ignoring tag: " . $tag_name . "}}\n" ;
2350             }
2351 0         0 next ;
2352             }
2353             }
2354              
2355              
2356             #-----------------------------------------------
2357             # If a specially named Dashrep phrase indicates
2358             # that the XML tag should be renamed, rename it as
2359             # requested.
2360              
2361 27 50       66 if ( exists( $global_dashrep_replacement{ "dashrep-xml-replacement-name-for-tag-named-" . $tag_name } ) )
2362             {
2363 0         0 $previous_tag_name = $tag_name ;
2364 0         0 $tag_name = $global_dashrep_replacement{ "dashrep-xml-replacement-name-for-tag-named-" . $previous_tag_name } ;
2365 0 0       0 if ( $global_dashrep_replacement{ "dashrep-xml-trace-on-or-off" } eq "on" )
2366             {
2367 0         0 print "{{trace; changing tag name " . $previous_tag_name . " into tag name " . $tag_name . "}}\n" ;
2368             }
2369             }
2370              
2371              
2372             #-----------------------------------------------
2373             # If the tag is of the "close" type, write the
2374             # appropriate dashrep phrase (and indent it to
2375             # indicate the nesting level). Then remove the
2376             # lowest-level tag name from the phrase that
2377             # contains all the tag names.
2378              
2379 27 100       66 if ( $possible_slash eq '/' )
    100          
2380             {
2381 13 50       28 if ( length( $global_xml_accumulated_sequence_of_tag_names ) > 0 )
2382             {
2383 13 50       27 if ( $global_xml_tag_at_level_number[ $global_xml_level_number ] eq $tag_name )
2384             {
2385 13         18 $full_phrase = "end" . $global_xml_accumulated_sequence_of_tag_names ;
2386 13 50       29 if ( exists( $global_dashrep_replacement{ $full_phrase } ) )
2387             {
2388 0         0 $global_ignore_level = 0 ;
2389             }
2390 13 50       24 if ( $global_ignore_level <= 0 )
2391             {
2392 13         23 $output_text .= substr( $global_spaces , 0 , ( 2 * $global_xml_level_number ) ) ;
2393 13         19 $output_text .= "[-" ;
2394 13 50       28 if ( exists( $global_dashrep_replacement{ $full_phrase } ) )
2395             {
2396 0         0 $output_text .= $global_dashrep_replacement{ $full_phrase } ;
2397             } else
2398             {
2399 13         18 $output_text .= $full_phrase ;
2400             }
2401 13         17 $output_text .= "-]" ;
2402 13         18 $output_text .= "\n" ;
2403             } else
2404             {
2405 0         0 $global_ignore_level -- ;
2406             }
2407 13         17 $sequence_without_hyphen_prefix = $global_xml_accumulated_sequence_of_tag_names ;
2408 13         40 $sequence_without_hyphen_prefix =~ s/^\-// ;
2409 13         25 $global_exists_xml_hyphenated_phrase{ $sequence_without_hyphen_prefix } = "exists" ;
2410 13         23 $starting_position_of_last_tag_name = length( $global_xml_accumulated_sequence_of_tag_names ) - length( $global_xml_tag_at_level_number[ $global_xml_level_number ] ) - 1 ;
2411 13 100       24 if ( $starting_position_of_last_tag_name > 0 )
2412             {
2413 11         21 $global_xml_accumulated_sequence_of_tag_names = substr( $global_xml_accumulated_sequence_of_tag_names , 0 , $starting_position_of_last_tag_name ) ;
2414             } else
2415             {
2416 2         4 $global_xml_accumulated_sequence_of_tag_names = "" ;
2417             }
2418 13         68 $global_xml_level_number -- ;
2419             } else
2420             {
2421 0 0       0 if ( $global_dashrep_replacement{ "dashrep-xml-trace-on-or-off" } eq "on" )
2422             {
2423 0         0 print "{{trace; close tag " . $tag_name . " ignored because it does not match expected close tag name " . $global_xml_tag_at_level_number[ $global_xml_level_number ] . "}}\n" ;
2424             }
2425             }
2426             }
2427              
2428              
2429             #-----------------------------------------------
2430             # If the tag is of the singular (open and close)
2431             # type, write the appropriate dashrep phrase.
2432              
2433             } elsif ( $may_include_closing_slash =~ /\// )
2434             {
2435 1 50       9 if ( length( $global_xml_accumulated_sequence_of_tag_names ) > 0 )
2436             {
2437 0         0 $full_phrase = "begin-and-end" . $global_xml_accumulated_sequence_of_tag_names . "-" . $tag_name ;
2438 0 0 0     0 if ( ( exists( $global_dashrep_replacement{ "dashrep-xml-yes-ignore-if-no-tag-replacement" } ) ) && ( $global_dashrep_replacement{ "dashrep-xml-yes-ignore-if-no-tag-replacement" } eq "yes" ) && ( not( exists( $global_dashrep_replacement{ $full_phrase } ) ) ) )
      0        
2439             {
2440 0         0 $global_ignore_level ++ ;
2441             }
2442 0 0       0 if ( exists( $global_dashrep_replacement{ $full_phrase } ) )
2443             {
2444 0         0 $global_ignore_level = 0 ;
2445             }
2446 0 0       0 if ( $global_ignore_level <= 0 )
2447             {
2448 0         0 $output_text .= substr( $global_spaces , 0 , ( 2 * ( $global_xml_level_number + 1 ) ) ) ;
2449 0         0 $output_text .= "[-" ;
2450 0 0       0 if ( exists( $global_dashrep_replacement{ $full_phrase } ) )
2451             {
2452 0         0 $output_text .= $global_dashrep_replacement{ $full_phrase } ;
2453             } else
2454             {
2455 0         0 $output_text .= $full_phrase ;
2456             }
2457 0         0 $output_text .= "-]" ;
2458 0         0 $output_text .= "\n" ;
2459             } else
2460             {
2461 0         0 $global_ignore_level -- ;
2462             }
2463             }
2464              
2465              
2466             #-----------------------------------------------
2467             # If the tag is of the "open" type, append the
2468             # new tag name to the accumulated hyphenated
2469             # phrase, and then write the appropriate Dashrep
2470             # phrase. However, do not use tag names that
2471             # occur before the specified first tag name
2472             # (of interest) -- unless the first tag name
2473             # is empty.
2474              
2475             } else
2476             {
2477 13 100       24 if ( length( $global_xml_accumulated_sequence_of_tag_names ) <= 0 )
2478             {
2479 2 50       7 if ( $tag_name eq $first_tag_name )
    0          
2480             {
2481 2         4 $global_xml_level_number ++ ;
2482 2         5 $global_xml_tag_at_level_number[ $global_xml_level_number ] = $tag_name ;
2483 2         4 $global_xml_accumulated_sequence_of_tag_names = "-" . $tag_name ;
2484 2 50       7 if ( $global_dashrep_replacement{ "dashrep-xml-trace-on-or-off" } eq "on" )
2485             {
2486 0         0 print "{{trace; specified top-level tag name: " . $first_tag_name . "}}\n" ;
2487             }
2488             } elsif ( $first_tag_name =~ /^ *$/ )
2489             {
2490 0         0 $global_xml_level_number ++ ;
2491 0         0 $global_xml_tag_at_level_number[ $global_xml_level_number ] = $tag_name ;
2492 0         0 $first_tag_name = $tag_name ;
2493 0         0 $global_dashrep_replacement{ "dashrep-first-xml-tag-name" } = $first_tag_name ;
2494 0         0 $global_xml_accumulated_sequence_of_tag_names = "-" . $tag_name ;
2495 0 0       0 if ( $global_dashrep_replacement{ "dashrep-xml-trace-on-or-off" } eq "on" )
2496             {
2497 0         0 print "{{trace; default top-level tag name: " . $tag_name . "}}\n" ;
2498             }
2499             } else
2500             {
2501 0 0       0 if ( $global_dashrep_replacement{ "dashrep-xml-trace-on-or-off" } eq "on" )
2502             {
2503 0         0 print "{{trace; ignored tag: " . $tag_name . "}}\n" ;
2504             }
2505             }
2506             } else
2507             {
2508 11         15 $global_xml_level_number ++ ;
2509 11         20 $global_xml_tag_at_level_number[ $global_xml_level_number ] = $tag_name ;
2510 11         21 $global_xml_accumulated_sequence_of_tag_names .= "-" . $tag_name ;
2511             }
2512 13 50       34 if ( length( $global_xml_accumulated_sequence_of_tag_names ) > 0 )
2513             {
2514 13         17 $full_phrase = "begin" . $global_xml_accumulated_sequence_of_tag_names ;
2515 13 0 33     37 if ( ( exists( $global_dashrep_replacement{ "dashrep-xml-yes-ignore-if-no-tag-replacement" } ) ) && ( $global_dashrep_replacement{ "dashrep-xml-yes-ignore-if-no-tag-replacement" } eq "yes" ) && ( not( exists( $global_dashrep_replacement{ $full_phrase } ) ) ) )
      33        
2516             {
2517 0         0 $global_ignore_level ++ ;
2518             }
2519 13 50       32 if ( exists( $global_dashrep_replacement{ $full_phrase } ) )
2520             {
2521 0         0 $global_ignore_level = 0 ;
2522             }
2523 13 50       26 if ( $global_ignore_level <= 0 )
2524             {
2525 13         32 $output_text .= substr( $global_spaces , 0 , ( 2 * ( $global_xml_level_number - 1 ) ) ) ;
2526 13         19 $output_text .= "[-" ;
2527 13 50       27 if ( exists( $global_dashrep_replacement{ $full_phrase } ) )
2528             {
2529 0         0 $output_text .= $global_dashrep_replacement{ $full_phrase } ;
2530             } else
2531             {
2532 13         22 $output_text .= $full_phrase ;
2533             }
2534 13         20 $output_text .= "-]" ;
2535 13         14 $output_text .= "\n" ;
2536             }
2537 13         22 $sequence_without_hyphen_prefix = $global_xml_accumulated_sequence_of_tag_names ;
2538 13         44 $sequence_without_hyphen_prefix =~ s/^\-// ;
2539 13         105 $global_exists_xml_hyphenated_phrase{ $sequence_without_hyphen_prefix } = "exists" ;
2540             }
2541             }
2542              
2543              
2544             #-----------------------------------------------
2545             # Repeat the loop for the next tag in the
2546             # input line.
2547              
2548             }
2549              
2550              
2551             #-----------------------------------------------
2552             # If the non-tag content text contains any
2553             # hyphens, replace them with the phrase
2554             # "hypen-here".
2555              
2556 3         5 $input_text =~ s/\-/dashrep_internal_hyphen_here/sg ;
2557 3         4 $input_text =~ s/dashrep_internal_hyphen_here/ hyphen-here /sg ;
2558              
2559              
2560             #-----------------------------------------------
2561             # If any text follows the last tag, write it on a
2562             # separate line.
2563              
2564 3 50       8 if ( $input_text =~ /^ *([^ ].*)$/ )
2565             {
2566 0         0 $input_text = $1 ;
2567 0         0 $output_text .= "\n" . $input_text ;
2568 0         0 $input_text = "" ;
2569             }
2570              
2571              
2572             #-----------------------------------------------
2573             # End of subroutine.
2574              
2575 3         13 return $output_text ;
2576              
2577             }
2578              
2579              
2580             =head2 dashrep_top_level_action
2581              
2582             Handles a top-level action such as a transfer
2583             to and from files.
2584              
2585             First, and only, parameter is the
2586             text string that contains any text, which
2587             may include one top-level action (which is
2588             a hyphenated phrase).
2589              
2590             Return value is the text string after removing
2591             the executed action, or the original text
2592             string if there was no action phrase.
2593             Return value is an empty string if there
2594             is not exactly one parameter.
2595              
2596             =cut
2597              
2598              
2599             #-----------------------------------------------
2600             #-----------------------------------------------
2601             # dashrep_top_level_action
2602             #-----------------------------------------------
2603             #-----------------------------------------------
2604              
2605             sub dashrep_top_level_action
2606             {
2607              
2608 21     21 1 188 my $source_definitions ;
2609             my $input_text ;
2610 0         0 my $translation ;
2611 0         0 my $partial_translation ;
2612 0         0 my $source_filename ;
2613 0         0 my $target_filename ;
2614 0         0 my $source_phrase ;
2615 0         0 my $target_phrase ;
2616 0         0 my $lines_to_translate ;
2617 0         0 my $line_count ;
2618 0         0 my $text_list_of_phrases ;
2619 0         0 my $possible_error_message ;
2620 0         0 my $all_defs_begin ;
2621 0         0 my $all_defs_end ;
2622 0         0 my $phrase_begin ;
2623 0         0 my $phrase_end ;
2624 0         0 my $def_begin ;
2625 0         0 my $def_end ;
2626 0         0 my $all_lines ;
2627 0         0 my $input_line ;
2628 0         0 my $phrase_name ;
2629 0         0 my $tracking_on_or_off ;
2630 0         0 my $qualifier ;
2631 0         0 my $numeric_return_value ;
2632 0         0 my $full_line ;
2633 0         0 my $multi_line_limit ;
2634 0         0 my $open_brackets ;
2635 0         0 my $close_brackets ;
2636 0         0 my $multi_line_count ;
2637 0         0 my $xml_hyphenated_phrase ;
2638 0         0 my $counter ;
2639 0         0 my @list_of_phrases ;
2640              
2641              
2642             #-----------------------------------------------
2643             # Reset the xml-parsing state.
2644              
2645 21         28 $global_xml_level_number = 0 ;
2646 21         40 @global_xml_tag_at_level_number = ( ) ;
2647              
2648              
2649             #-----------------------------------------------
2650             # Get the input text.
2651              
2652 21 50       49 if ( scalar( @_ ) == 1 )
2653             {
2654 21         40 $input_text = $_[ 0 ] ;
2655             } else
2656             {
2657 0         0 carp "Warning: Call to dashrep_top_level_action subroutine does not have exactly one parameter." ;
2658 0         0 return 0 ;
2659             }
2660              
2661              
2662             #-----------------------------------------------
2663             # Clear the error message.
2664              
2665 21         30 $possible_error_message = "" ;
2666              
2667              
2668             #-----------------------------------------------
2669             # Ensure this function is not called recursively.
2670              
2671 21         23 $global_nesting_level_of_file_actions ++ ;
2672 21 50       53 if ( $global_nesting_level_of_file_actions > 1 )
2673             {
2674 0         0 carp "Warning: Call to dashrep_top_level_action subroutine called recursivley, which is not allowed." ;
2675 0         0 return 0 ;
2676             }
2677              
2678              
2679             #-----------------------------------------------
2680             # In case definitions are exported, specify
2681             # which delimiters to use -- based on the "yes"
2682             # or "no" definition of the phrase
2683             # "dashrep-yes-or-no-export-delimited-definitions".
2684              
2685 21 50       53 if ( $global_dashrep_replacement{ "dashrep-yes-or-no-export-delimited-definitions" } eq "yes" )
2686             {
2687 0         0 $all_defs_begin = "export-defs-all-begin\n\n" ;
2688 0         0 $all_defs_end = "export-defs-all-end\n\n" ;
2689 0         0 $phrase_begin = "export-defs-phrase-begin " ;
2690 0         0 $phrase_end = " export-defs-phrase-end\n\n" ;
2691 0         0 $def_begin = "export-defs-def-begin " ;
2692 0         0 $def_end = " export-defs-def-end\n\n" ;
2693             } else
2694             {
2695 21         28 $all_defs_begin = "dashrep-definitions-begin\n\n" ;
2696 21         24 $all_defs_end = "dashrep-definitions-end\n\n" ;
2697 21         32 $phrase_begin = "" ;
2698 21         30 $phrase_end = ":\n" ;
2699 21         25 $def_begin = "" ;
2700 21         35 $def_end = "\n-----\n\n" ;
2701             }
2702              
2703              
2704             #-----------------------------------------------
2705             # Handle the action:
2706             # append-from-phrase-to-phrase
2707              
2708 21 100       273 if ( $input_text =~ /^ *append-from-phrase-to-phrase +([^ \[\]]+) +([^ \[\]]+) *$/ )
    100          
    50          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
    100          
    50          
2709             {
2710 1         3 $source_phrase = $1 ;
2711 1         2 $target_phrase = $2 ;
2712 1         4 $global_dashrep_replacement{ $target_phrase } .= " " . $global_dashrep_replacement{ $source_phrase } ;
2713 1 50       5 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
2714             {
2715 0         0 print "{{trace; appended from phrase " . $source_phrase . " to phrase " . $target_phrase . "}}\n" ;
2716             }
2717 1         2 $input_text = "" ;
2718              
2719              
2720             #-----------------------------------------------
2721             # Handle the action:
2722             # copy-from-phrase-append-to-file
2723             #
2724             # The filename is edited to remove any path
2725             # specifications, so that only local files
2726             # are affected.
2727              
2728             } elsif ( $input_text =~ /^ *copy-from-phrase-append-to-file +([^ \[\]]+) +([^ \[\]]+) *$/ )
2729             {
2730 2         6 $source_phrase = $1 ;
2731 2         5 $target_filename = $2 ;
2732 2         8 $target_filename =~ s/^.*[\\\/]// ;
2733 2         6 $target_filename =~ s/^\.+// ;
2734 2 50       71 if ( open ( OUTFILE , ">>" . $target_filename ) )
2735             {
2736 2         6 $possible_error_message .= "" ;
2737             } else
2738             {
2739 0         0 $possible_error_message .= " [file named " . $target_filename . " could not be opened for writing]" ;
2740             }
2741 2 50       8 if ( $possible_error_message eq "" )
2742             {
2743 2         49 print OUTFILE "\n" . $global_dashrep_replacement{ $source_phrase } . "\n" ;
2744 2 50       10 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
2745             {
2746 0         0 print "{{trace; copied from phrase " . $source_phrase . " to end of file " . $target_filename . "}}\n" ;
2747             }
2748             } else
2749             {
2750 0 0       0 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
2751             {
2752 0         0 print "{{trace; error: " . $possible_error_message . "}}\n" ;
2753             }
2754             }
2755 2         111 close( OUTFILE ) ;
2756 2         6 $input_text = "" ;
2757              
2758              
2759             #-----------------------------------------------
2760             # Handle the action:
2761             # expand-phrase-to-file
2762             #
2763             # The filename is edited to remove any path
2764             # specifications, so that only local files
2765             # are affected.
2766              
2767             } elsif ( $input_text =~ /^ *expand-phrase-to-file +([^ \[\]]+) +([^ \[\]]+) *$/ )
2768             {
2769 0         0 $source_phrase = $1 ;
2770 0         0 $target_filename = $2 ;
2771 0         0 $target_filename =~ s/^.*[\\\/]// ;
2772 0         0 $target_filename =~ s/^\.+// ;
2773 0 0       0 if ( open ( OUTFILE , ">" . $target_filename ) )
2774             {
2775 0         0 $possible_error_message .= "" ;
2776             } else
2777             {
2778 0         0 $possible_error_message .= " [file named " . $target_filename . " could not be opened for writing]" ;
2779             }
2780 0 0       0 if ( $possible_error_message eq "" )
2781             {
2782 0         0 $partial_translation = &dashrep_expand_parameters( $source_phrase );
2783 0 0       0 if ( $global_dashrep_replacement{ "dashrep-debug-trace-on-or-off" } eq "on" )
2784             {
2785 0         0 print "{{trace; after parameters expanded: " . $partial_translation . "}}\n" ;
2786             }
2787 0         0 $translation = &dashrep_expand_phrases( $partial_translation );
2788 0         0 print OUTFILE $translation . "\n" ;
2789 0 0       0 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
2790             {
2791 0         0 print "{{trace; expanded phrase " . $source_phrase . " to file " . $target_filename . "}}\n" ;
2792             }
2793             } else
2794             {
2795 0 0       0 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
2796             {
2797 0         0 print "{{trace; error: " . $possible_error_message . "}}\n" ;
2798             }
2799             }
2800 0         0 close( OUTFILE ) ;
2801 0         0 $input_text = "" ;
2802              
2803              
2804             #-----------------------------------------------
2805             # Handle the action:
2806             # copy-from-file-to-phrase
2807              
2808             } elsif ( $input_text =~ /^ *copy-from-file-to-phrase +([^ \[\]]+) +([^ \[\]]+) *$/ )
2809             {
2810 3         9 $source_filename = $1 ;
2811 3         9 $target_phrase = $2 ;
2812 3 50       114 if ( open ( INFILE , "<" . $source_filename ) )
2813             {
2814 3         8 $possible_error_message .= "" ;
2815             } else
2816             {
2817 0         0 $possible_error_message .= " [file named " . $source_filename . " not found, or could not be opened]" ;
2818             }
2819 3 50       493 if ( $possible_error_message eq "" )
2820             {
2821 3         10 $possible_error_message .= " [file named " . $source_filename . " found, and opened]" ;
2822 3         5 $all_lines = "" ;
2823 3         97 while( $input_line = )
2824             {
2825 34         58 chomp( $input_line ) ;
2826 34         64 $input_line =~ s/[\n\r\f\t]+/ /g ;
2827 34         170 $all_lines .= $input_line . "\n" ;
2828             }
2829 3         13 $global_dashrep_replacement{ $target_phrase } = $all_lines ;
2830 3 50       13 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
2831             {
2832 0         0 print "{{trace; copied from file " . $source_filename . " to phrase " . $target_phrase . "}}\n" ;
2833             }
2834             } else
2835             {
2836 0 0       0 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
2837             {
2838 0         0 print "{{trace; error: " . $possible_error_message . "}}\n" ;
2839             }
2840             }
2841 3         33 close( INFILE ) ;
2842 3         8 $input_text = "" ;
2843              
2844              
2845             #-----------------------------------------------
2846             # Handle the action:
2847             # create-empty-file
2848             #
2849             # The filename is edited to remove any path
2850             # specifications, so that only local files
2851             # are affected.
2852              
2853             } elsif ( $input_text =~ /^ *create-empty-file +([^ \[\]]+) *$/ )
2854             {
2855 3         10 $target_filename = $1 ;
2856 3         12 $target_filename =~ s/^.*[\\\/]// ;
2857 3         7 $target_filename =~ s/^\.+// ;
2858 3 50       327 if ( open ( OUTFILE , ">" . $target_filename ) )
2859             {
2860 3         9 $possible_error_message .= "" ;
2861             } else
2862             {
2863 0         0 $possible_error_message .= " [file named " . $target_filename . " could not be created]" ;
2864             }
2865 3 50       11 if ( $possible_error_message eq "" )
2866             {
2867 3         8 print OUTFILE "" ;
2868 3 50       13 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
2869             {
2870 0         0 print "{{trace; created empty file: " . $target_filename . "}}\n" ;
2871             }
2872             } else
2873             {
2874 0 0       0 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
2875             {
2876 0         0 print "{{trace; error: " . $possible_error_message . "}}\n" ;
2877             }
2878             }
2879 3         31 close( OUTFILE ) ;
2880 3         9 $input_text = "" ;
2881              
2882              
2883             #-----------------------------------------------
2884             # Handle the action:
2885             # delete-file
2886             #
2887             # The filename is edited to remove any path
2888             # specifications, so that only local files
2889             # are affected.
2890              
2891             } elsif ( $input_text =~ /^ *delete-file +([^ \[\]]+) *$/ )
2892             {
2893 7         22 $target_filename = $1 ;
2894 7         27 $target_filename =~ s/^.*[\\\/]// ;
2895 7         13 $target_filename =~ s/^\.+// ;
2896 7         426 unlink $target_filename ;
2897 7 50       29 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
2898             {
2899 0         0 print "{{trace; deleted file: " . $target_filename . "}}\n" ;
2900             }
2901 7         16 $input_text = "" ;
2902              
2903              
2904             #-----------------------------------------------
2905             # Handle the action:
2906             # write-all-dashrep-definitions-to-file
2907             #
2908             # The filename is edited to remove any path
2909             # specifications, so that only local files
2910             # are affected.
2911              
2912             } elsif ( $input_text =~ /^ *write-all-dashrep-definitions-to-file +([^ \[\]]+) *$/ )
2913             {
2914 1         3 $target_filename = $1 ;
2915 1         4 $target_filename =~ s/^.*[\\\/]// ;
2916 1         3 $target_filename =~ s/^\.+// ;
2917 1         3 @list_of_phrases = &dashrep_get_list_of_phrases( ) ;
2918 1 50       9 if ( $#list_of_phrases < 0 )
2919             {
2920 0 0       0 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
2921             {
2922 0         0 print "{{trace; warning: no phrases to write (to file)}}\n" ;
2923             }
2924             } else
2925             {
2926 1 50       84 if ( open ( OUTFILE , ">" . $target_filename ) )
2927             {
2928 1         3 $possible_error_message .= "" ;
2929             } else
2930             {
2931 0         0 $possible_error_message .= " [file named " . $target_filename . " could not be opened for writing]" ;
2932             }
2933 1 50       11 if ( $possible_error_message eq "" )
2934             {
2935 1         3 $counter = 0 ;
2936 1         5 print OUTFILE $all_defs_begin ;
2937 1         44 foreach $phrase_name ( sort( @list_of_phrases ) )
2938             {
2939 93 50 33     563 if ( ( defined( $phrase_name ) ) &&( $phrase_name =~ /[^ ]/ ) && ( exists( $global_dashrep_replacement{ $phrase_name } ) ) )
      33        
2940             {
2941 93         262 print OUTFILE $phrase_begin . $phrase_name . $phrase_end . $def_begin . $global_dashrep_replacement{ $phrase_name } . $def_end ;
2942 93         160 $counter ++ ;
2943             }
2944             }
2945 1         3 print OUTFILE $all_defs_end ;
2946 1 50       5 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
2947             {
2948 0         0 print "{{trace; wrote " . $counter . " definitions to file: " . $target_filename . "}}\n" ;
2949             }
2950             } else
2951             {
2952 0 0       0 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
2953             {
2954 0         0 print "{{trace; error: " . $possible_error_message . "}}\n" ;
2955             }
2956             }
2957             }
2958 1         51 close( OUTFILE ) ;
2959 1         3 $input_text = "" ;
2960              
2961              
2962             #-----------------------------------------------
2963             # Handle the action:
2964             # write-dashrep-definitions-listed-in-phrase-to-file
2965             #
2966             # The filename is edited to remove any path
2967             # specifications, so that only local files
2968             # are affected.
2969              
2970             } elsif ( $input_text =~ /^ *write-dashrep-definitions-listed-in-phrase-to-file +([^ \[\]]+) +([^ \[\]]+) *$/ )
2971             {
2972 0         0 $source_phrase = $1 ;
2973 0         0 $target_filename = $2 ;
2974 0         0 $target_filename =~ s/^.*[\\\/]// ;
2975 0         0 $target_filename =~ s/^\.+// ;
2976 0         0 $text_list_of_phrases = $global_dashrep_replacement{ $source_phrase } ;
2977 0 0       0 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
2978             {
2979 0         0 print "{{trace; phrase that contains list of phrases to export: " . $source_phrase . "}}\n" ;
2980 0         0 print "{{trace; list of phrases for exporting definitions to file: " . $text_list_of_phrases . "}}\n" ;
2981             }
2982 0         0 @list_of_phrases = &dashrep_internal_split_delimited_items( $text_list_of_phrases ) ;
2983 0 0       0 if ( open ( OUTFILE , ">" . $target_filename ) )
2984             {
2985 0         0 $possible_error_message .= "" ;
2986             } else
2987             {
2988 0         0 $possible_error_message .= " [file named " . $target_filename . " could not be opened for writing]" ;
2989             }
2990 0 0       0 if ( $possible_error_message eq "" )
2991             {
2992 0         0 $counter = 0 ;
2993 0         0 print OUTFILE $all_defs_begin ;
2994 0         0 foreach $phrase_name ( sort( @list_of_phrases ) )
2995             {
2996 0 0 0     0 if ( ( defined( $phrase_name ) ) && ( $phrase_name =~ /[^ ]/ ) && ( exists( $global_dashrep_replacement{ $phrase_name } ) ) )
      0        
2997             {
2998 0         0 print OUTFILE $phrase_begin . $phrase_name . $phrase_end . $def_begin . $global_dashrep_replacement{ $phrase_name } . $def_end ;
2999 0         0 $counter ++ ;
3000             }
3001             }
3002 0         0 print OUTFILE $all_defs_end ;
3003 0 0       0 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
3004             {
3005 0         0 print "{{trace; wrote " . $counter . " definitions to file: " . $target_filename . "}}\n" ;
3006             }
3007             } else
3008             {
3009 0 0       0 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
3010             {
3011 0         0 print "{{trace; error: " . $possible_error_message . "}}\n" ;
3012             }
3013             }
3014 0         0 close( OUTFILE ) ;
3015 0         0 $input_text = "" ;
3016              
3017              
3018             #-----------------------------------------------
3019             # Handle the action:
3020             # get-definitions-from-file
3021              
3022             } elsif ( $input_text =~ /^ *get-definitions-from-file +([^ \[\]]+) *$/ )
3023             {
3024 1         7 $source_filename = $1 ;
3025 1         7 $source_filename =~ s/[ \t]+//g ;
3026 1 50       77 if ( open ( INFILE , "<" . $source_filename ) )
3027             {
3028 1         3 $possible_error_message = "" ;
3029             } else
3030             {
3031 0 0       0 if ( -e $source_filename )
3032             {
3033 0         0 $possible_error_message .= " [file named " . $source_filename . " found, but could not be opened]" ;
3034             } else
3035             {
3036 0         0 $possible_error_message .= " [file named " . $source_filename . " not found]" ;
3037             }
3038             }
3039 1 50       4 if ( $possible_error_message eq "" )
3040             {
3041 1         4 $possible_error_message .= " [file named " . $source_filename . " found, and opened]" ;
3042 1         3 $source_definitions = "" ;
3043 1         41 while( $input_line = )
3044             {
3045 395         623 chomp( $input_line ) ;
3046 395         701 $input_line =~ s/[\n\r\f\t]+/ /g ;
3047 395 100 66     2731 if ( ( defined( $input_line ) ) && ( $input_line =~ /[^ ]/ ) )
3048             {
3049 278         1550 $source_definitions .= $input_line . " " ;
3050             }
3051             }
3052 1         7 $numeric_return_value = &dashrep_import_replacements( $source_definitions ) ;
3053 1 50       10 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
3054             {
3055 0         0 print "{{trace; imported " . $numeric_return_value . " definitions from file: " . $source_filename . "}}\n" ;
3056             }
3057             } else
3058             {
3059 0 0       0 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
3060             {
3061 0         0 print "{{trace; error: " . $possible_error_message . "}}\n" ;
3062             }
3063             }
3064 1         37 close( INFILE ) ;
3065 1         5 $input_text = "" ;
3066              
3067              
3068             #-----------------------------------------------
3069             # Handle the action:
3070             # clear-all-dashrep-phrases
3071              
3072             } elsif ( $input_text =~ /^ *clear-all-dashrep-phrases *$/ )
3073             {
3074 1         2 $tracking_on_or_off = $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } ;
3075 1         3 &dashrep_delete_all( );
3076 1 50       4 if ( $tracking_on_or_off eq "on" )
3077             {
3078 0         0 print "{{trace; cleared all definitions}}\n" ;
3079             }
3080 1         2 $global_endless_loop_counter = 0 ;
3081 1         3 $input_text = "" ;
3082              
3083              
3084             #-----------------------------------------------
3085             # Handle the actions:
3086             # linewise-translate-from-file-to-file and
3087             # linewise-translate-parameters-only-from-file-to-file
3088             # linewise-translate-phrases-only-from-file-to-file
3089             # linewise-translate-special-phrases-only-from-file-to-file
3090             #
3091             # The output filename is edited to remove any path
3092             # specifications, so that only local files
3093             # are affected.
3094             #
3095             # If there are Dashrep definitions, get them.
3096              
3097             } elsif ( $input_text =~ /^ *linewise-translate(()|(-parameters-only)|(-phrases-only)|(-special-phrases-only))-from-file-to-file +([^ \[\]]+) +([^ \[\]]+) *$/ )
3098             {
3099 1         4 $qualifier = $1 ;
3100 1         5 $source_filename = $6 ;
3101 1         4 $target_filename = $7 ;
3102 1         4 $source_filename =~ s/[ \t]+//g ;
3103 1         6 $target_filename =~ s/^.*[\\\/]// ;
3104 1         18 $target_filename =~ s/^\.+// ;
3105 1 50       55 if ( open ( INFILE , "<" . $source_filename ) )
3106             {
3107 1         3 $possible_error_message .= "" ;
3108             } else
3109             {
3110 0 0       0 if ( -e $source_filename )
3111             {
3112 0         0 $possible_error_message .= " [file named " . $source_filename . " exists, but could not be opened]" ;
3113             } else
3114             {
3115 0         0 $possible_error_message .= " [file named " . $source_filename . " not found]" ;
3116             }
3117             }
3118 1 50       88 if ( open ( OUTFILE , ">" . $target_filename ) )
3119             {
3120 1         3 $possible_error_message .= "" ;
3121             } else
3122             {
3123 0         0 $possible_error_message .= " [file named " . $target_filename . " could not be opened for writing]" ;
3124             }
3125 1 50       7 if ( $possible_error_message eq "" )
3126             {
3127 1         4 $global_ignore_level = 0 ;
3128 1         3 $global_capture_level = 0 ;
3129 1         2 $global_top_line_count_for_insert_phrase = 0 ;
3130 1         21 while( $input_line = )
3131             {
3132 2         7 chomp( $input_line ) ;
3133 2         10 $input_line =~ s/[\n\r\f\t]+/ /g ;
3134 2         3 $global_endless_loop_counter = 0 ;
3135 2         29 %global_replacement_count_for_item_name = ( ) ;
3136 2         4 $lines_to_translate = 1 ;
3137 2         7 while ( $lines_to_translate > 0 )
3138             {
3139 2 50       7 if ( $input_line =~ /^ *dashrep-definitions-begin *$/ )
3140             {
3141 0         0 $all_lines = "" ;
3142 0         0 $line_count = 0 ;
3143 0         0 while( $input_line = )
3144             {
3145 0         0 chomp( $input_line );
3146 0         0 $input_line =~ s/[\n\r\f\t]+/ /g ;
3147 0 0       0 if ( $input_line =~ /^ *dashrep-definitions-end *$/ )
3148             {
3149 0         0 last;
3150             }
3151 0 0 0     0 if ( ( $input_line =~ /[^ ]/ ) && ( defined( $input_line ) ) )
3152             {
3153 0         0 $all_lines .= $input_line . " " ;
3154             }
3155 0         0 $line_count ++ ;
3156             }
3157 0 0       0 if ( $all_lines =~ /[^ ]/ )
3158             {
3159 0         0 $numeric_return_value = &dashrep_import_replacements( $all_lines );
3160 0 0 0     0 if ( ( $global_dashrep_replacement{ "dashrep-linewise-trace-on-or-off" } eq "on" ) && ( $input_line =~ /[^ ]/ ) )
3161             {
3162 0         0 print "{{trace; definitions found, imported " . $numeric_return_value . " definitions from " . $line_count . " lines}}\n" ;
3163             }
3164             }
3165 0         0 $lines_to_translate = 0 ;
3166             } else
3167             {
3168 2         4 $lines_to_translate = 0 ;
3169 2 50       12 if ( $qualifier eq "-parameters-only" )
    50          
    50          
3170             {
3171 0         0 $translation = &dashrep_expand_parameters( $input_line );
3172             } elsif ( $qualifier eq "-phrases-only" )
3173             {
3174 0         0 $translation = &dashrep_expand_phrases( $input_line );
3175             } elsif ( $qualifier eq "-special-phrases-only" )
3176             {
3177 0         0 $translation = &dashrep_expand_special_phrases( $input_line );
3178             } else
3179             {
3180 2         7 $partial_translation = &dashrep_expand_parameters( $input_line );
3181 2         11 $translation = &dashrep_expand_phrases( $partial_translation );
3182             }
3183 2 50 33     20 if ( ( $translation =~ /[^ ]/ ) && ( ( $global_ignore_level < 1 ) || ( $global_capture_level < 1 ) ) )
      66        
3184             {
3185 1         9 print OUTFILE $translation . "\n" ;
3186             }
3187 2 50       33 if ( $global_top_line_count_for_insert_phrase == 1 )
    50          
3188             {
3189 0         0 $global_top_line_count_for_insert_phrase = 2 ;
3190             } elsif ( $global_top_line_count_for_insert_phrase == 2 )
3191             {
3192 0         0 $global_top_line_count_for_insert_phrase = 0 ;
3193 0 0       0 if ( $global_phrase_to_insert_after_next_top_level_line ne "" )
3194             {
3195 0         0 $input_line = "[-" . $global_phrase_to_insert_after_next_top_level_line . "-]" ;
3196 0         0 $lines_to_translate = 1 ;
3197             }
3198             }
3199             }
3200             }
3201             }
3202 1 50       7 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
3203             {
3204 0         0 print "{{trace; linewise translated from file " . $source_filename . " to file " . $target_filename . "}}\n" ;
3205             }
3206             } else
3207             {
3208 0 0       0 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
3209             {
3210 0         0 print "{{trace; failed to linewise translate from file " . $source_filename . " to file " . $target_filename . "}}\n" ;
3211             }
3212             }
3213 1         16 close( INFILE ) ;
3214 1         49 close( OUTFILE ) ;
3215 1         4 $input_text = "" ;
3216              
3217              
3218             #-----------------------------------------------
3219             # Handle the action:
3220             # linewise-translate-xml-tags-in-file-to-dashrep-phrases-in-file
3221             #
3222             # The output filename is edited to remove any path
3223             # specifications, so that only local files
3224             # are affected.
3225             # If a tag does not end on the same line as it
3226             # starts, more lines are read in an attempt
3227             # to reach the end of the tag, but this
3228             # capability is not robust. This is done to
3229             # accomodate XHTML generated by the "Tidy"
3230             # utility.
3231              
3232             } elsif ( $input_text =~ /^ *linewise-translate-xml-tags-in-file-to-dashrep-phrases-in-file +([^ \[\]]+) +([^ \[\]]+) *$/ )
3233             {
3234 1         4 $source_filename = $1 ;
3235 1         2 $target_filename = $2 ;
3236 1         5 $target_filename =~ s/^.*[\\\/]// ;
3237 1         2 $target_filename =~ s/^\.+// ;
3238 1 50       38 if ( open ( INFILE , "<" . $source_filename ) )
3239             {
3240 1         2 $possible_error_message .= "" ;
3241             } else
3242             {
3243 0         0 $possible_error_message .= " [file named " . $source_filename . " not found, or could not be opened]" ;
3244             }
3245 1 50       123 if ( open ( OUTFILE , ">" . $target_filename ) )
3246             {
3247 1         3 $possible_error_message .= "" ;
3248             } else
3249             {
3250 0         0 $possible_error_message .= " [file named " . $target_filename . " could not be opened for writing]" ;
3251             }
3252 1 50       5 if ( $possible_error_message eq "" )
3253             {
3254 1         2 $full_line = "" ;
3255 1         3 $multi_line_limit = 10 ;
3256 1         17 while( $input_line = )
3257             {
3258 2         8 chomp( $input_line ) ;
3259 2         8 $input_line =~ s/[\n\r\f\t]+/ /g ;
3260 2 50       7 if ( $full_line ne "" )
3261             {
3262 0         0 $full_line = $full_line . " " . $input_line ;
3263             } else
3264             {
3265 2         8 $full_line = $input_line ;
3266             }
3267 2         5 $open_brackets = $full_line ;
3268 2         4 $close_brackets = $full_line ;
3269 2         138 $open_brackets =~ s/[^<]//g ;
3270 2         118 $close_brackets =~ s/[^>]//g ;
3271 2 50 33     15 if ( ( length( $open_brackets ) != length( $close_brackets ) ) && ( $multi_line_count < $multi_line_limit ) )
3272             {
3273 0         0 next ;
3274             }
3275 2 50       8 if ( $global_dashrep_replacement{ "dashrep-xml-trace-on-or-off" } eq "on" )
3276             {
3277 0         0 print "{{trace; accumulated text to convert: " . $full_line . "}}\n" ;
3278             }
3279 2         3 $global_endless_loop_counter = 0 ;
3280 2         7 %global_replacement_count_for_item_name = ( ) ;
3281 2         7 $translation = &dashrep_xml_tags_to_dashrep( $full_line );
3282 2         27 print OUTFILE $translation . "\n" ;
3283 2         20 $full_line = "" ;
3284             }
3285 1 50       4 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
3286             {
3287 0         0 print "{{trace; source xml file named " . $source_filename . " expanded into dashrep phrases in file named " . $target_filename . "}}\n" ;
3288             }
3289 1         3 $global_dashrep_replacement{ "dashrep-list-of-xml-phrases" } = "" ;
3290 1         12 foreach $xml_hyphenated_phrase ( sort( keys ( %global_exists_xml_hyphenated_phrase ) ) )
3291             {
3292 9         16 $global_dashrep_replacement{ "dashrep-list-of-xml-phrases" } .= $xml_hyphenated_phrase . " " ;
3293             }
3294             } else
3295             {
3296 0 0       0 if ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" )
3297             {
3298 0         0 print "{{trace; failed to expand source xml file named " . $source_filename . " into dashrep phrases in file named " . $target_filename . "}}\n" ;
3299             }
3300             }
3301 1         15 close( INFILE ) ;
3302 1         55 close( OUTFILE ) ;
3303 1         7 $input_text = "" ;
3304              
3305              
3306             #-----------------------------------------------
3307             # Handle text that was not recognized as an
3308             # action.
3309              
3310             } else
3311             {
3312 0 0 0     0 if ( ( $global_dashrep_replacement{ "dashrep-action-trace-on-or-off" } eq "on" ) && ( $input_text =~ /[^ ]/ ) )
3313             {
3314 0         0 print "{{trace; not recognized as top-level action: " . $input_text . "}}\n" ;
3315             }
3316             }
3317              
3318              
3319             #-----------------------------------------------
3320             # If there was an error message, put it
3321             # into the text that is returned (and remove
3322             # the action that caused the error).
3323              
3324 21         54 $possible_error_message =~ s/^ +// ;
3325 21         42 $possible_error_message =~ s/ +$// ;
3326 21 100       63 if ( $possible_error_message =~ /[^ ]/ )
3327             {
3328 4         9 $input_text = $possible_error_message ;
3329             }
3330              
3331              
3332             #-----------------------------------------------
3333             # Track the nesting level.
3334              
3335 21         27 $global_nesting_level_of_file_actions -- ;
3336              
3337              
3338             #-----------------------------------------------
3339             # Return, possibly with an error message.
3340              
3341 21         120 return $input_text ;
3342              
3343              
3344             #-----------------------------------------------
3345             # End of subroutine.
3346              
3347             }
3348              
3349              
3350             =head2 dashrep_linewise_translate
3351              
3352             Reads from the standard input file,
3353             does the specified Dashrep translations,
3354             and writes any requested translations
3355             into the standard output file.
3356              
3357             There are no parameters.
3358              
3359             Return value is a text string that is either
3360             empty -- if there is no error -- or else
3361             contains an error message (although currently
3362             no errors are defined).
3363              
3364             =cut
3365              
3366              
3367             #-----------------------------------------------
3368             #-----------------------------------------------
3369             # dashrep_linewise_translate
3370             #-----------------------------------------------
3371             #-----------------------------------------------
3372              
3373             sub dashrep_linewise_translate
3374             {
3375              
3376 0     0 1 0 my $input_line ;
3377             my $all_lines ;
3378 0         0 my $line_count ;
3379 0         0 my $numeric_return_value ;
3380 0         0 my $revised_text ;
3381 0         0 my $after_possible_action ;
3382 0         0 my $error_message ;
3383              
3384              
3385             #-----------------------------------------------
3386             # Ensure there is no input text.
3387              
3388 0 0       0 if ( scalar( @_ ) != 0 )
3389             {
3390 0         0 carp "Warning: Call to dashrep_top_level_action subroutine does not have exactly zero parameters." ;
3391 0         0 return 0 ;
3392             }
3393              
3394              
3395             #-----------------------------------------------
3396             # Read each line from the input file.
3397              
3398 0         0 while( $input_line = )
3399             {
3400 0         0 chomp( $input_line );
3401 0         0 $input_line =~ s/[\n\r\f\t]+/ /g ;
3402 0 0 0     0 if ( ( $global_dashrep_replacement{ "dashrep-linewise-trace-on-or-off" } eq "on" ) && ( $input_line =~ /[^ ]/ ) )
3403             {
3404 0         0 print "{{trace; linewise input line: " . $input_line . "}}\n" ;
3405             }
3406              
3407              
3408             #-----------------------------------------------
3409             # If there are Dashrep definitions, get them.
3410              
3411 0 0       0 if ( $input_line =~ /^ *dashrep-definitions-begin *$/ )
3412             {
3413 0         0 $all_lines = "" ;
3414 0         0 $line_count = 0 ;
3415 0         0 while( $input_line = )
3416             {
3417 0         0 chomp( $input_line );
3418 0         0 $input_line =~ s/[\n\r\f\t]+/ /g ;
3419 0 0       0 if ( $input_line =~ /^ *dashrep-definitions-end *$/ )
3420             {
3421 0         0 last;
3422             }
3423 0 0 0     0 if ( ( $input_line =~ /[^ ]/ ) && ( defined( $input_line ) ) )
3424             {
3425 0         0 $all_lines .= $input_line . " " ;
3426             }
3427 0         0 $line_count ++ ;
3428             }
3429 0 0       0 if ( $all_lines =~ /[^ ]/ )
3430             {
3431 0         0 $numeric_return_value = &dashrep_import_replacements( $all_lines );
3432 0 0 0     0 if ( ( $global_dashrep_replacement{ "dashrep-linewise-trace-on-or-off" } eq "on" ) && ( $input_line =~ /[^ ]/ ) )
3433             {
3434 0         0 print "{{trace; definition line: " . $input_line . " ; imported " . $numeric_return_value . " definitions from " . $line_count . " lines}}\n" ;
3435             }
3436             }
3437              
3438              
3439             #-----------------------------------------------
3440             # Otherwise, translate this line by itself.
3441              
3442             } else
3443             {
3444 0         0 $global_endless_loop_counter = 0 ;
3445 0         0 %global_replacement_count_for_item_name = ( ) ;
3446 0         0 $revised_text = &dashrep_expand_parameters( $input_line );
3447 0 0 0     0 if ( ( $global_dashrep_replacement{ "dashrep-linewise-trace-on-or-off" } eq "on" ) && ( $revised_text =~ /[^ ]/ ) )
3448             {
3449 0         0 print "{{trace; line after parameters expanded: " . $revised_text . "}}\n" ;
3450             }
3451 0         0 $after_possible_action = &dashrep_top_level_action( $revised_text );
3452 0 0 0     0 if ( ( $global_dashrep_replacement{ "dashrep-linewise-trace-on-or-off" } eq "on" ) && ( $after_possible_action =~ /^ *$/ ) && ( $revised_text =~ /[^ ]/ ) )
      0        
3453             {
3454 0         0 print "{{trace; line after action executed: " . $after_possible_action . "}}\n" ;
3455             }
3456 0         0 $revised_text = &dashrep_expand_phrases( $after_possible_action );
3457 0 0 0     0 if ( ( $global_dashrep_replacement{ "dashrep-linewise-trace-on-or-off" } eq "on" ) && ( $revised_text =~ /[^ ]/ ) )
3458             {
3459 0         0 print "{{trace; line after phrases expanded: " . $revised_text . "}}\n" ;
3460             }
3461 0         0 print $revised_text . "\n" ;
3462             }
3463              
3464              
3465             #-----------------------------------------------
3466             # Repeat the loop for the next line.
3467              
3468             }
3469              
3470              
3471             #-----------------------------------------------
3472             # End of subroutine.
3473              
3474 0         0 return $error_message ;
3475              
3476             }
3477              
3478              
3479             =head2 dashrep_internal_endless_loop_info
3480              
3481             Internal subroutine, not exported.
3482             It is only needed within the Dashrep module.
3483              
3484             =cut
3485              
3486             #-----------------------------------------------
3487             #-----------------------------------------------
3488             # Non-exported subroutine:
3489             #
3490             # dashrep_internal_endless_loop_info
3491             #-----------------------------------------------
3492             #-----------------------------------------------
3493             # This subroutine displays the name of the
3494             # most-replaced hyphenated phrase, which is
3495             # usually the one that caused the endless loop.
3496              
3497             # This subroutine is not exported because it
3498             # is only needed within this Dashrep module.
3499              
3500             # The collected information is displayed in a
3501             # warning message.
3502              
3503             sub dashrep_internal_endless_loop_info
3504             {
3505              
3506 0     0 1 0 my $item_name ;
3507             my $highest_usage_counter ;
3508 0         0 my $highest_usage_item_name ;
3509              
3510 0         0 $highest_usage_counter = - 1 ;
3511 0         0 foreach $item_name ( keys( %global_replacement_count_for_item_name ) )
3512             {
3513 0 0       0 if ( $global_replacement_count_for_item_name{ $item_name } > $highest_usage_counter )
3514             {
3515 0         0 $highest_usage_counter = $global_replacement_count_for_item_name{ $item_name } ;
3516 0         0 $highest_usage_item_name = $item_name ;
3517             }
3518             }
3519 0         0 carp "Too many cycles of replacement (" . $global_endless_loop_counter . ").\n" . "Hyphenated phrase with highest replacement count (" . $highest_usage_counter . ") is:\n" . " " . $highest_usage_item_name . "\n" ;
3520              
3521              
3522             #-----------------------------------------------
3523             # End of subroutine.
3524              
3525 0         0 return 1 ;
3526              
3527             }
3528              
3529              
3530             =head2 dashrep_internal_split_delimited_items
3531              
3532             Internal subroutine, not exported.
3533             It is only needed within the Dashrep module.
3534              
3535             =cut
3536              
3537              
3538             #-----------------------------------------------
3539             #-----------------------------------------------
3540             # Non-exported subroutine:
3541             #
3542             # dashrep_internal_split_delimited_items
3543             #-----------------------------------------------
3544             #-----------------------------------------------
3545             # This subroutine converts a text-format list
3546             # of text items separated by commas, spaces, or
3547             # line breaks into an array of separate
3548             # text strings. It does not expand any
3549             # hyphenated phrases.
3550              
3551             # This subroutine is not exported because it
3552             # is only needed within this Dashrep module.
3553              
3554             sub dashrep_internal_split_delimited_items
3555             {
3556 16     16 1 23 my $text_string ;
3557             my @array ;
3558              
3559 16         28 $text_string = $_[ 0 ] ;
3560              
3561              
3562             #-----------------------------------------------
3563             # Convert all delimiters to single commas.
3564              
3565 16 50       52 if ( $text_string =~ /[\n\r]/ )
3566             {
3567 0         0 $text_string =~ s/[\n\r][\n\r]+/,/gs ;
3568 0         0 $text_string =~ s/[\n\r][\n\r]+/,/gs ;
3569             }
3570              
3571 16         24 $text_string =~ s/ +/,/gs ;
3572 16         25 $text_string =~ s/,,+/,/gs ;
3573              
3574              
3575             #-----------------------------------------------
3576             # Remove leading and trailing commas.
3577              
3578 16         22 $text_string =~ s/^,// ;
3579 16         23 $text_string =~ s/,$// ;
3580              
3581              
3582             #-----------------------------------------------
3583             # If there are only commas and spaces, or
3584             # the string is empty, return an empty list.
3585              
3586 16 50       52 if ( $text_string =~ /^[ ,]*$/ )
3587             {
3588 0         0 @array = ( ) ;
3589              
3590              
3591             #-----------------------------------------------
3592             # Split the strings into an array.
3593              
3594             } else
3595             {
3596 16         115 @array = split( /,+/ , $text_string ) ;
3597             }
3598              
3599              
3600             #-----------------------------------------------
3601             # Return the resulting array.
3602              
3603 16         89 return @array ;
3604              
3605             }
3606              
3607              
3608              
3609              
3610             =head1 AUTHOR
3611              
3612             Richard Fobes, "CPSolver" at GitHub.com
3613              
3614              
3615             =head1 DOCUMENTATION
3616              
3617             See www.Dashrep.org for details about the Dashrep language.
3618              
3619              
3620             =head1 BUGS
3621              
3622             Please report any bugs or feature requests to "CPSolver" at GitHub.com.
3623              
3624              
3625             =head1 TO DO
3626              
3627             See www.Dashrep.org for descriptions of possible future developments.
3628              
3629              
3630             =head1 ACKNOWLEDGEMENTS
3631              
3632             Richard Fobes designed the Dashrep (TM) language and
3633             developed the original version of this code over a
3634             period of many years. Richard Fobes is the author
3635             of the book titled The Creative Problem Solver's Toolbox.
3636              
3637              
3638             =head1 COPYRIGHT & LICENSE
3639              
3640             Copyright 2009 through 2011 Richard Fobes at www.Dashrep.org, all rights reserved.
3641              
3642             You can redistribute and/or modify this library module
3643             under the Perl Artistic License 2.0, a copy
3644             of which is included in the LICENSE file.
3645              
3646             Conversions of this code into other languages are also
3647             covered by the above license terms.
3648              
3649             The Dashrep (TM) name is trademarked by Richard Fobes at
3650             www.Dashrep.org to prevent the name from being co-opted.
3651              
3652             The Dashrep (TM) language is in the public domain.
3653              
3654             =cut
3655              
3656             1; # End of package