File Coverage

blib/lib/App/sh2p/Utils.pm
Criterion Covered Total %
statement 6 200 3.0
branch 0 90 0.0
condition 0 21 0.0
subroutine 2 50 4.0
pod 0 48 0.0
total 8 409 1.9


line stmt bran cond sub pod time code
1             package App::sh2p::Utils;
2              
3 1     1   9 use warnings;
  1         3  
  1         43  
4 1     1   6 use strict;
  1         2  
  1         3734  
5              
6             our $VERSION = '0.06';
7              
8             require Exporter;
9             our (@ISA, @EXPORT);
10             @ISA = ('Exporter');
11             @EXPORT = qw (Register_variable Register_env_variable
12             Delete_variable get_variable_type
13             print_types_tokens reset_globals
14             iout out pre_out error_out flush_out
15             rd_iout rd_remove
16             get_special_var set_special_var can_var_interpolate
17             mark_function unmark_function ina_function
18             mark_subshell unmark_subshell ina_subshell
19             inc_block_level dec_block_level get_block_level
20             is_user_function set_user_function unset_user_function
21             dec_indent inc_indent
22             rem_empty_string fix_print_arg
23             no_semi_colon reset_semi_colon query_semi_colon
24             set_in_quotes unset_in_quotes query_in_quotes
25             out_to_buffer off_out_to_buffer
26             set_shell which_shell
27             open_out_file close_out_file
28             set_break is_break);
29              
30             ############################################################################
31              
32             my $g_indent_spacing = 4;
33              
34             my %g_special_vars = (
35             'IFS' => '" \t\n"',
36             'ERRNO' => '$!',
37             'HOME' => '$ENV{HOME}',
38             'PATH' => '$ENV{PATH}',
39             'FUNCNAME' => '(caller(0))[3]', # Corrected 0.04
40             '?' => '($? >> 8)',
41             '#' => 'scalar(@ARGV)',
42             '@' => '"@ARGV"',
43             '*' => '"@ARGV"',
44             '-' => 'not supported',
45             '$' => '$$',
46             '!' => 'not supported'
47             );
48            
49             # This hash keeps a key for each variable declared
50             # so we know if to put a 'my' prefix
51             my %g_variables;
52              
53             # This hash keeps track of environment variables
54             my %g_env_variables;
55              
56             my %g_user_functions;
57             my $g_new_line = 1;
58             my $g_use_semi_colon = 1;
59             my $g_ina_function = 0;
60             my $g_ina_subshell = 0;
61             my $g_block_level = 0;
62             my $g_indent = 0;
63             my $g_errors = 0;
64             my $g_is_in_quotes = 0;
65             my $g_shell_in_use = "ksh";
66              
67             my $g_outh;
68             my $g_filename;
69             my $g_out_buffer; # Main output buffer
70             my $g_err_buffer; # INSPECT messages, for output before the statement
71             my $g_pre_buffer; # For preamble, like declaring 'my' variables
72             my $g_ref_redirect; # Redirect output to buffer instead of script file
73             my $g_break = \do{my $some_scalar}; # We have to define a 'break' somehow
74              
75             # Remember position and length for later deletion
76             my $g_rd_pos = 0;
77             my $g_rd_len = 0;
78              
79             # For use by App::sh2p only
80             ############################################################################
81             # Called by Handlers::interpolate
82             sub can_var_interpolate {
83              
84 0     0 0   my ($name) = @_;
85 0           my $retn;
86            
87 0           $retn = get_special_var ($name, 1);
88            
89 0 0 0       if (defined $retn && $retn !~ /^[\$\@]/) {
90 0           return 0
91             }
92             else {
93 0           return 1
94             }
95             }
96             ########################################################
97             # This is primarily for [@] and [*]. Also to prevent globbing inside ""
98             sub query_in_quotes {
99 0     0 0   return $g_is_in_quotes;
100             }
101              
102             sub set_in_quotes {
103 0     0 0   $g_is_in_quotes = 1;
104             }
105              
106             sub unset_in_quotes {
107 0     0 0   $g_is_in_quotes = 0;
108             }
109              
110             ############################################################################
111              
112             sub set_break {
113              
114 0     0 0   return $g_break
115             }
116              
117             sub is_break {
118 0     0 0   my $ref = shift;
119            
120 0 0 0       if (defined $ref && ref($ref) && $ref eq $g_break) {
      0        
121 0           return 1
122             }
123             else {
124 0           return 0
125             }
126             }
127              
128             ############################################################################
129              
130             sub get_special_var {
131 0     0 0   my ($name, $no_errors) = @_;
132 0           my $retn;
133            
134 0 0         return undef if ! defined $name;
135              
136 0 0         $no_errors = 0 if ! defined $no_errors;
137              
138             # Remove dollar prefix and quotes
139 0           $name =~ s/^([\'\"]?)\$(.*?)\1/$2/;
140              
141 0 0 0       if ($name eq '0') {
    0          
    0          
    0          
142 0           $retn = '$0';
143             }
144             elsif ($name =~ /^(\d+)$/) {
145 0           my $offset = $1 - 1;
146 0           $retn = "\$ARGV[$offset]";
147             }
148             elsif ($name eq 'PWD') {
149            
150 0 0         if (!$no_errors) {
151 0           error_out ("Using \$PWD is unsafe: use Cwd::getcwd");
152             }
153 0           $retn = '$ENV{PWD}';
154             }
155             elsif ($name eq '*' && query_in_quotes()) {
156            
157 0           my $glue = $g_special_vars{'IFS'};
158 0           $glue =~ s/^([\"\'])(.*)\1$/$2/;
159 0           $glue = substr($glue,0,1);
160 0           $retn = "join(\"$glue\",\@ARGV)";
161             }
162             else {
163 0           $retn = $g_special_vars{$name};
164             }
165              
166             # In a subroutine we use @_
167 0 0 0       if (defined $retn && $g_ina_function) {
168 0           $retn =~ s/ARGV/_/;
169             }
170            
171 0           return $retn;
172             }
173              
174             ############################################################################
175              
176             sub set_special_var {
177 0     0 0   my ($name, $value) = @_;
178             #print STDERR "set_special_var: <$name> <$value>\n";
179            
180             # Do not set environment variables through here - January 2009
181 0 0         if (substr($g_special_vars{$name},0,4) ne '$ENV') {
182 0           $g_special_vars{$name} = $value;
183             }
184            
185 0           return $value;
186             }
187              
188             ############################################################################
189              
190             sub no_semi_colon() {
191 0     0 0   $g_use_semi_colon = 0;
192             }
193              
194             sub reset_semi_colon() {
195 0     0 0   $g_use_semi_colon = 1;
196             }
197              
198             sub query_semi_colon() {
199 0     0 0   return $g_use_semi_colon;
200             }
201              
202             ############################################################################
203              
204             sub set_shell {
205 0     0 0   my $shell = shift;
206 0           $g_shell_in_use = $shell;
207             #print STDERR "Shell set to <$shell>\n";
208             }
209              
210             sub which_shell {
211 0     0 0   return $g_shell_in_use;
212             }
213              
214             #################################################################################
215              
216             sub mark_function {
217 0     0 0   $g_ina_function++;
218             }
219              
220             sub unmark_function {
221 0     0 0   $g_ina_function--;
222            
223 0 0         if ($g_ina_function < 0) {
224 0           print STDERR "++++ Internal Error, function count = $g_ina_function\n";
225             }
226             }
227              
228             sub ina_function {
229 0     0 0   return $g_ina_function;
230             }
231              
232             #################################################################################
233              
234             sub mark_subshell {
235 0     0 0   $g_ina_subshell++;
236             }
237              
238             sub unmark_subshell {
239              
240             # Delete all the variables for this subshell
241            
242 0     0 0   while (my($key, $value) = each %g_variables) {
243 0 0         if ($value->[2] == $g_ina_subshell) {
244 0           delete $g_variables{$key};
245             }
246             }
247              
248 0           $g_ina_subshell--;
249            
250 0 0         if ($g_ina_subshell < 0) {
251 0           print STDERR "++++ Internal Error, subshell count = $g_ina_subshell\n";
252             }
253             }
254              
255             sub ina_subshell {
256 0     0 0   return $g_ina_subshell;
257             }
258              
259             ############################################################################
260             # Return TRUE if NOT already registered
261             sub Register_variable {
262            
263 0     0 0   my ($name, $type) = @_;
264 0           my $level = get_block_level();
265            
266 0 0         if (! defined $type) {
267 0           $type = '$'
268             }
269            
270             # Remove '$' if it exists
271 0           $name =~ s/^\$//;
272            
273             # January 2009
274 0 0 0       if (exists $g_special_vars{$name} && $name ne 'IFS') {
275 0           return 0;
276             }
277            
278 0 0         if (exists $g_variables{$name}) {
    0          
279            
280 0 0 0       if ($g_variables{$name}->[0] <= $level &&
281             $g_variables{$name}->[2] == $g_ina_subshell) {
282             #print STDERR "Register_variable: <$name> <$g_variables{$name}->[1]> returning 0\n";
283 0           return 0
284             }
285             else {
286             # Create the variable with the block level and type
287 0           $g_variables{$name} = [$level, $type, $g_ina_subshell];
288 0           return 1
289             }
290             }
291             elsif (exists $g_env_variables{$name}) {
292            
293 0           $g_env_variables{$name} = undef;
294 0           return 0;
295             }
296             else {
297             # Create the variable with a block level and type
298            
299 0           $g_variables{$name} = [$level, $type, $g_ina_subshell];
300 0           return 1
301             }
302             }
303              
304             ############################################################################
305              
306             sub Register_env_variable {
307 0     0 0   my ($name) = @_;
308            
309             # Does not matter if it already exists, or its type
310 0           $g_env_variables{$name} = undef;
311             }
312              
313             ############################################################################
314              
315             sub get_variable_type {
316              
317 0     0 0   my ($name) = @_;
318 0           my $level = get_block_level();
319              
320             # Remove '$' if it exists - 0.06
321 0           $name =~ s/^\$//;
322              
323 0 0         if (exists $g_variables{$name}) {
324            
325 0 0         if ($g_variables{$name}->[0] <= $level) {
326 0           return $g_variables{$name}->[1]
327             }
328             }
329            
330 0           return '$'; # default
331             }
332              
333             ############################################################################
334             # Called by unset and export
335             sub Delete_variable {
336 0     0 0   my ($name) = @_;
337 0           my $level = get_block_level();
338            
339 0 0         if (exists $g_variables{$name}) {
340 0 0         if ($g_variables{$name}->[0] <= $level) { # ->[0] 0.05
341 0           delete $g_variables{$name}
342             }
343             }
344            
345             }
346              
347             #################################################################################
348              
349             sub inc_block_level {
350 0     0 0   $g_block_level++;
351             }
352              
353             sub dec_block_level {
354            
355             # Remove registered variables of current block level ->[0] added 0.05
356 0     0 0   while (my($key, $value) = each (%g_variables)) {
357 0 0         delete $g_variables{$key} if $value->[0] == $g_block_level;
358             }
359            
360 0           $g_block_level--;
361            
362 0 0         if ($g_block_level < 0) {
363 0           print STDERR "++++ Internal Error, block level = $g_block_level\n";
364 0           my @caller = caller;
365 0           die "@caller\n";
366             }
367             }
368              
369             sub get_block_level {
370 0     0 0   return $g_block_level;
371             }
372              
373             #################################################################################
374              
375             sub is_user_function {
376 0     0 0   my ($name) = @_;
377              
378 0           return (exists $g_user_functions{$name})
379             }
380              
381             sub set_user_function {
382 0     0 0   my ($name) = @_;
383              
384 0           $g_user_functions{$name} = undef;
385            
386 0           return 1; # true
387             }
388              
389             sub unset_user_function {
390 0     0 0   my ($name) = @_;
391            
392 0 0         delete $g_user_functions{$name} if exists $g_user_functions{$name};
393            
394 0           return 1; # true
395             }
396              
397             #################################################################################
398              
399             sub mark_new_line {
400 0     0 0   $g_new_line = 1;
401             }
402              
403             sub new_line {
404 0     0 0   return $g_new_line;
405             }
406              
407             #################################################################################
408              
409 0 0   0 0   sub inc_indent { $g_indent++ if $g_indent < 80 }
410 0 0   0 0   sub dec_indent { $g_indent-- if $g_indent > 0 }
411              
412             #################################################################################
413              
414             sub open_out_file {
415 0     0 0   my ($g_filename, $perms) = @_;
416            
417 0 0         if ($g_filename eq '-') {
418 0           $g_outh = *STDOUT;
419             }
420             else {
421 0 0         open ($g_outh, '>', $g_filename) || die "$g_filename: $!\n";
422            
423             # fchmod is not implemented on all platforms
424 0 0         chmod ($perms, $g_filename) if defined $perms;
425 0           print STDERR "Processing $g_filename:\n";
426             }
427            
428 0           $g_out_buffer = '';
429 0           $g_err_buffer = '';
430 0           $g_pre_buffer = '';
431             }
432              
433             sub close_out_file {
434            
435 0     0 0   flush_out ();
436            
437 0           close ($g_outh);
438 0           print STDERR "\n";
439 0           $g_filename = undef;
440             }
441              
442             #################################################################################
443             # Out to remember redirection position
444             sub rd_iout {
445              
446 0     0 0   $g_rd_pos = length ($g_out_buffer);
447 0           iout (@_);
448 0           $g_rd_len = length ($g_out_buffer) - $g_rd_pos;
449             }
450              
451             sub rd_remove {
452              
453 0 0   0 0   if ($g_rd_len) {
454 0           $g_out_buffer = substr ($g_out_buffer, 0, $g_rd_pos) .
455             substr ($g_out_buffer, $g_rd_pos + $g_rd_len);
456             }
457             }
458              
459             #################################################################################
460              
461             sub out_to_buffer {
462 0     0 0   flush_out();
463 0           ($g_ref_redirect) = @_;
464             }
465              
466             sub off_out_to_buffer {
467 0     0 0   flush_out();
468 0           $g_ref_redirect = undef;
469             }
470              
471             #################################################################################
472             # Indented out
473             sub iout {
474              
475             #print $g_outh ' ' x ($g_indent * $g_indent_spacing);
476            
477 0     0 0   my (@args) = @_;
478            
479 0 0         if (query_semi_colon()) {
480 0           unshift @args, (' ' x ($g_indent * $g_indent_spacing));
481             }
482            
483 0           out (@args);
484             }
485              
486             #################################################################################
487              
488             sub out {
489            
490 0     0 0   local $" = '';
491             #my @caller = caller();
492             #print STDERR "out: <@_> @caller\n";
493            
494 0           $g_out_buffer .= "@_";
495            
496 0           $g_new_line = 0;
497            
498             }
499              
500             ################################################################################
501             # I don't like these hacks, but any other way is convoluted
502             sub fix_print_arg {
503             # This avoids 'print (...) interpreted as function'
504             #print STDERR "fix_print_arg: <$g_out_buffer>\n";
505            
506 0 0   0 0   if ($g_out_buffer =~ /print/) {
507 0           $g_out_buffer =~ s/(^|[^\'\"]+)(print\s+)\(/$2\"\",(/;
508             }
509             }
510              
511             sub rem_empty_string {
512            
513 0 0   0 0   return if $g_out_buffer =~ /print/; # Often required
514              
515             # Remove "". at start of calls
516 0           $g_out_buffer =~ s/\(\"\"\./(/;
517            
518             # Remove "". in assignments
519 0           $g_out_buffer =~ s/= \"\"\./= /;
520            
521             }
522              
523             ################################################################################
524              
525             sub error_out {
526 0     0 0   my $msg = shift;
527            
528             # 0.06
529 0 0         if (defined $msg) {
530 0           $g_err_buffer .= "# **** INSPECT: $msg\n";
531             }
532             else {
533 0           $g_err_buffer .= "\n";
534             }
535            
536 0           $g_errors++;
537             }
538              
539             ################################################################################
540              
541             sub pre_out {
542 0     0 0   my $msg = shift;
543            
544 0 0         if (!defined $msg) {
545 0           $msg = "\n";
546             }
547            
548 0 0         if (query_semi_colon()) {
549 0           $g_pre_buffer .= (' ' x ($g_indent * $g_indent_spacing)).$msg;
550             }
551             else {
552 0           $g_pre_buffer .= $msg;
553             }
554            
555             }
556              
557             #################################################################################
558              
559             sub flush_out {
560              
561 0 0   0 0   if (defined $g_ref_redirect) {
562 0 0         $$g_ref_redirect .= $g_err_buffer if $g_err_buffer;
563 0 0         $$g_ref_redirect .= $g_pre_buffer if $g_pre_buffer;
564 0           $$g_ref_redirect .= $g_out_buffer;
565            
566 0           $g_ref_redirect = undef;
567             }
568             else {
569 0 0         print $g_outh $g_err_buffer if $g_err_buffer;
570 0 0         print $g_outh $g_pre_buffer if $g_pre_buffer;
571 0           print $g_outh $g_out_buffer;
572             }
573            
574             # Leading space for readability with multiple files
575 0           $g_err_buffer =~ s/\#/ \#/g;
576 0           print STDERR $g_err_buffer;
577            
578 0           $g_out_buffer = '';
579 0           $g_err_buffer = '';
580 0           $g_pre_buffer = '';
581 0           $g_rd_len = 0;
582            
583             }
584              
585             #################################################################################
586              
587             sub reset_globals {
588              
589 0     0 0   %g_variables = ();
590 0           %g_env_variables = ();
591 0           %g_user_functions = ();
592            
593 0           $g_out_buffer = '';
594 0           $g_err_buffer = '';
595 0           $g_pre_buffer = '';
596            
597 0           $g_new_line = 1;
598 0           $g_use_semi_colon = 1;
599 0           $g_ina_function = 0;
600 0           $g_ina_subshell = 0;
601 0           $g_block_level = 0;
602 0           $g_indent = 0;
603 0           $g_errors = 0;
604 0           $g_is_in_quotes = 0;
605 0           $g_shell_in_use = "ksh";
606            
607 0           $g_rd_pos = 0;
608 0           $g_rd_len = 0;
609            
610             }
611              
612             #################################################################################
613             # Debug purposes only
614             sub print_types_tokens {
615            
616 0     0 0   my ($types, $tokens) = @_;
617 0           my $caller = (caller(1))[3];
618            
619 0           for (my $i = 0; $i < @$types; $i++) {
620            
621 0 0         if (defined $types->[$i][0]) {
622 0           print STDERR "$caller Type: ".$types->[$i][0].", ";
623 0           print STDERR "Token: ".$tokens->[$i]."\n";
624             }
625             else {
626 0           print STDERR "**** Type undefined for Token: <".$tokens->[$i].">\n";
627             }
628             }
629            
630 0 0         if (@$types != @$tokens) {
631 0           print STDERR "Types array: ".@$types.", Token array: ".@$tokens."\n";
632             }
633 0           print STDERR "\n";
634             }
635              
636             #################################################################################
637              
638             # Module end
639             1;