Acme-EyeDrops

 view release on metacpan or  search on metacpan

lib/Acme/EyeDrops.pm  view on Meta::CPAN

package Acme::EyeDrops;
require 5.006;
use strict;
use warnings;
use vars qw($VERSION @ISA @EXPORT_OK);
require Exporter; @ISA = qw(Exporter);
@EXPORT_OK = qw(ascii_to_sightly sightly_to_ascii
   regex_print_sightly regex_eval_sightly clean_print_sightly
   clean_eval_sightly regex_binmode_print_sightly
   clean_binmode_print_sightly
   get_eye_dir get_eye_shapes get_eye_string get_builtin_shapes
   get_eye_properties get_eye_keywords find_eye_shapes
   make_triangle make_siertri make_banner
   border_shape invert_shape reflect_shape rotate_shape
   reduce_shape expand_shape hjoin_shapes
   pour_text pour_sightly sightly);
$VERSION = '1.62';
{  # This table was generated by demo/gentable.pl.
   my @C = (
      q Z('!'^'!')Z,q Z('('^')')Z,q Z('<'^'>')Z,q Z('>'^'=')Z,
      q Z('>'^':')Z,q Z('>'^';')Z,q Z('+'^'-')Z,q Z('*'^'-')Z,
      q Z('+'^'#')Z,q Z('*'^'#')Z,q Z('!'^'+')Z,q Z('!'^'*')Z,
      q Z('!'^'-')Z,q Z('!'^',')Z,q Z('!'^'/')Z,q Z('!'^'.')Z,
      q Z('?'^'/')Z,q Z('<'^'-')Z,q Z('-'^'?')Z,q Z('.'^'=')Z,
      q Z('+'^'?')Z,q Z('*'^'?')Z,q Z('?'^')')Z,q Z('<'^'+')Z,
      q Z('%'^'=')Z,q Z('&'^'?')Z,q Z('?'^'%')Z,q Z('>'^'%')Z,
      q Z('&'^':')Z,q Z('<'^'!')Z,q Z('?'^'!')Z,q Z('%'^':')Z,
      q Z('{'^'[')Z,q Z'!'Z,q Z'\\\\'.'"'Z,q Z'#'Z,
      q Z'\\\\'.'$'Z,q Z'%'Z,q Z'&'Z,q Z"'"Z,q Z'('Z,q Z')'Z,
      q Z'*'Z,q Z'+'Z,q Z','Z,q Z'-'Z,q Z'.'Z,q Z'/'Z,
      q Z('^'^('`'|'.'))Z,q Z('^'^('`'|'/'))Z,q Z('^'^('`'|','))Z,
      q Z('^'^('`'|'-'))Z,q Z('^'^('`'|'*'))Z,q Z('^'^('`'|'+'))Z,
      q Z('^'^('`'|'('))Z,q Z('^'^('`'|')'))Z,q Z(':'&'=')Z,
      q Z(';'&'=')Z,q Z':'Z,q Z';'Z,q Z'<'Z,q Z'='Z,q Z'>'Z,q Z'?'Z,
      q Z'\\\\'.'@'Z,q Z('`'^'!')Z,q Z('`'^'"')Z,q Z('`'^'#')Z,
      q Z('`'^'$')Z,q Z('`'^'%')Z,q Z('`'^'&')Z,q Z('`'^"'")Z,
      q Z('`'^'(')Z,q Z('`'^')')Z,q Z('`'^'*')Z,q Z('`'^'+')Z,
      q Z('`'^',')Z,q Z('`'^'-')Z,q Z('`'^'.')Z,q Z('`'^'/')Z,
      q Z('{'^'+')Z,q Z('{'^'*')Z,q Z('{'^')')Z,q Z('{'^'(')Z,
      q Z('{'^'/')Z,q Z('{'^'.')Z,q Z('{'^'-')Z,q Z('{'^',')Z,
      q Z('{'^'#')Z,q Z('{'^'"')Z,q Z('{'^'!')Z,q Z'['Z,
      q Z'\\\\'.'\\\\'Z,q Z']'Z,q Z'^'Z,q Z'_'Z,
      q Z'`'Z,q Z('`'|'!')Z,q Z('`'|'"')Z,q Z('`'|'#')Z,
      q Z('`'|'$')Z,q Z('`'|'%')Z,q Z('`'|'&')Z,q Z('`'|"'")Z,
      q Z('`'|'(')Z,q Z('`'|')')Z,q Z('`'|'*')Z,q Z('`'|'+')Z,
      q Z('`'|',')Z,q Z('`'|'-')Z,q Z('`'|'.')Z,q Z('`'|'/')Z,
      q Z('['^'+')Z,q Z('['^'*')Z,q Z('['^')')Z,q Z('['^'(')Z,
      q Z('['^'/')Z,q Z('['^'.')Z,q Z('['^'-')Z,q Z('['^',')Z,
      q Z('['^'#')Z,q Z('['^'"')Z,q Z('['^'!')Z,q Z'\\\\'.'{'Z,
      q Z'|'Z,q Z'\\\\'.'}'Z,q Z'~'Z,q Z('!'^'^')Z
   );
   push @C, map(join('.', q#'\\\\'#, $C[120],
      map($C[$_], unpack('C*', sprintf('%x', $_)))), 128..255);
   sub ascii_to_sightly { join '.', map($C[$_], unpack('C*', $_[0])) }
}
sub sightly_to_ascii { eval eval q#'"'.# . $_[0] . q#.'"'# }

sub regex_print_sightly {
   q#''=~('('.'?'.'{'.# . ascii_to_sightly('print') . q#.'"'.# .
   &ascii_to_sightly . q#.'"'.'}'.')')#;
}

sub regex_binmode_print_sightly {
   q#''=~('('.'?'.'{'.# . ascii_to_sightly('binmode(STDOUT);print')
   . q#.'"'.# .  &ascii_to_sightly . q#.'"'.'}'.')')#;
}

sub regex_eval_sightly {
   q#''=~('('.'?'.'{'.# . ascii_to_sightly('eval') . q#.'"'.# .
   &ascii_to_sightly . q#.'"'.'}'.')')#;
}

sub clean_print_sightly {
   qq#print eval '"'.\n\n\n# . &ascii_to_sightly . q#.'"'#;
}

sub clean_binmode_print_sightly {
   qq#binmode(STDOUT);print eval '"'.\n\n\n# .
   &ascii_to_sightly . q#.'"'#;
}

sub clean_eval_sightly {
   qq#eval eval '"'.\n\n\n# . &ascii_to_sightly . q#.'"'#;
}

# -----------------------------------------------------------------

sub _slurp_tfile {
   my $f = shift;
   my $b = shift;
   open my $fh, '<', $f or die "open '$f': $!";
   $b and binmode($fh);
   local $/; my $s = <$fh>; close($fh); $s;
}

# Poor man's properties (see also YAML, java.util.Properties).
# Return ref to property hash.
sub _get_properties {
   my $f = shift;
   open my $fh, '<', $f or die "open '$f': $!";
   my $l; my %h;
   while (defined($l = <$fh>)) {
      chomp($l);
      if ($l =~ s/\\$//) {
         my $n = <$fh>; $n =~ s/^\s+//; $l .= $n;
         redo unless eof($fh);
      }
      $l =~ s/^\s+//; $l =~ s/\s+$//;
      next unless length($l);
      next if $l =~ /^#/;
      my ($k, $v) = split(/\s*:\s*/, $l, 2);
      $h{$k} = $v;
   }
   close($fh);
   return \%h;
}

sub _def_ihandler { print STDERR $_[0] }

# Return largest no. of tokens with total length less than $slen ($slen > 0).
sub _guess_ntok {
   my ($rtok, $sidx, $slen, $rexact) = @_; my $tlen = 0;
   for my $i ($sidx .. $sidx + $slen) {
      ($tlen += length($rtok->[$i])) < $slen or
         return $i - $sidx + (${$rexact} = $tlen == $slen);
   }
   # should never get here
}

sub _guess_compact_ntok {
   my ($rtok, $sidx, $slen, $rexact, $fcompact) = @_; my $tlen = 0;
   for my $i ($sidx .. $sidx + $slen + $slen) {
      ($tlen += length($rtok->[$i]) - ($i > $sidx+1 && $rtok->[$i-1] eq '.'
      && substr($rtok->[$i], 0, 1) eq "'" && substr($rtok->[$i-2], 0, 1)
      eq "'" ? (${$fcompact} = 3) : 0)) < $slen or
         return $i - $sidx + ($tlen > $slen ? 0 : (${$rexact} = 1) +
         ($i > $sidx && $rtok->[$i] eq '.' && substr($rtok->[$i-1], 0, 1)
         eq "'" && $rtok->[$i+1] =~ /^'..$/ ? (${$fcompact} = 1) : 0));
   }
   # should never get here
}

sub _compact_join {
   my ($rtok, $sidx, $n) = @_; my $s = "";
   for my $i ($sidx .. $sidx + $n - 1) {
      if ($i > $sidx+1 && $rtok->[$i-1] eq '.' && substr($rtok->[$i], 0, 1)
      eq "'" && substr($rtok->[$i-2], 0, 1) eq "'") {
         substr($s, -2) = substr($rtok->[$i], 1);  # 'a'.'b' to 'ab'
      } else {
         $s .= $rtok->[$i];
      }
   }

lib/Acme/EyeDrops.pm  view on Meta::CPAN

   # Return built-in shape string or undef if invalid shape.
   sub _get_builtin_string {
      my $shape = shift;
      return unless exists($builtin_shapes{$shape});
      $builtin_shapes{$shape}->(shift);
   }
}

sub sightly {
   my $ruarg = shift; my %arg = (
      Shape             => "",    ShapeString       => "",
      SourceFile        => "",    SourceString      => "",
      SourceHandle      => undef, InformHandler     => undef,
      Width             => 0,     BannerString      => "",
      Text              => 0,     TextFiller        => "",
      Regex             => 0,     Compact           => 0,
      Print             => 0,     Binary            => 0,
      Gap               => 0,     Rotate            => 0,
      RotateType        => 0,     RotateFlip        => 0,
      Reflect           => 0,     Reduce            => 0,
      Expand            => 0,     Invert            => 0,
      TrailingSpaces    => 0,     RemoveNewlines    => 0,
      Indent            => 0,     BorderGap         => 0,
      BorderGapLeft     => 0,     BorderGapRight    => 0,
      BorderGapTop      => 0,     BorderGapBottom   => 0,
      BorderWidth       => 0,     BorderWidthLeft   => 0,
      BorderWidthRight  => 0,     BorderWidthTop    => 0,
      BorderWidthBottom => 0,     TrapEvalDie       => 0,
      TrapWarn          => 0,     FillerVar         => [],
      EyeDir            => get_eye_dir()
   );
   for my $k (keys %{$ruarg}) {
      exists($arg{$k}) or die "invalid parameter '$k'";
      $arg{$k} = $ruarg->{$k};
   }
   length($arg{SourceFile}) && $arg{SourceHandle} and
      die "cannot specify both SourceFile and SourceHandle";
   length($arg{SourceFile}) && length($arg{SourceString}) and
      die "cannot specify both SourceFile and SourceString";
   length($arg{SourceString}) && $arg{SourceHandle} and
      die "cannot specify both SourceString and SourceHandle";
   $arg{Shape} && $arg{ShapeString} and
      die "cannot specify both Shape and ShapeString";
   if (length($arg{SourceFile})) {
      $arg{SourceString} = _slurp_tfile($arg{SourceFile}, $arg{Binary});
   } elsif ($arg{SourceHandle}) {
      local $/; $arg{SourceString} = readline($arg{SourceHandle});
   }
   my $fill = $arg{FillerVar};
   if (ref($fill) && !$arg{Text}) {
      # Non-rigourous check for module (package) or END block.
      @{$fill} or $fill = ($arg{SourceString} =~ /^\s*END\b/m or
                           $arg{SourceString} =~ /^\s*package\b/m) ?
         [ '$:', '$~', '$^' ] :
         [ '$:', '$~', '$^', '$/', '$,', '$\\' ];
   }
   $arg{RemoveNewlines} and $arg{SourceString} =~ tr/\n//d;
   my $shape = my $sightly = "";
   length($arg{SourceString}) && !$arg{Text} and $sightly = $arg{Print} ?
      ( $arg{Regex} ? ( $arg{Binary} ?
                        regex_binmode_print_sightly($arg{SourceString}) :
                        regex_print_sightly($arg{SourceString})  ) :
                      ( $arg{Binary} ?
                        clean_binmode_print_sightly($arg{SourceString}) :
                        clean_print_sightly($arg{SourceString})  )  ) :
      ( $arg{Regex} ?   regex_eval_sightly($arg{SourceString}) :
                        clean_eval_sightly($arg{SourceString}) );
   if ($arg{ShapeString}) {
      $shape = $arg{ShapeString};
   } elsif ($arg{Shape}) {
      $shape = join("\n" x $arg{Gap},
               map(_get_builtin_string($_, \%arg) ||
               (m#[./]# ? _slurp_tfile($_) : _get_eye_string($arg{EyeDir}, $_)),
               split(/,/, $arg{Shape})));
   } elsif ($arg{Width}) {
      die "invalid width $arg{Width} (must be > 3)"
         if !$arg{Text} && $arg{Width} < 4;
      $shape = '#' x $arg{Width};
   }
   $shape or return "use re 'eval';\n" x ($arg{Regex} == 3 || ($arg{Regex} == 1 && $] >= 5.017)) . $sightly;
   $arg{Rotate} and $shape = rotate_shape($shape, $arg{Rotate},
                             $arg{RotateType}, $arg{RotateFlip});
   $arg{Reflect} and $shape = reflect_shape($shape);
   $arg{Reduce} and $shape = reduce_shape($shape, $arg{Reduce});
   $arg{Expand} and $shape = expand_shape($shape, $arg{Expand});
   $arg{Invert} and $shape = invert_shape($shape);
   $arg{TrailingSpaces}  ||
   $arg{BorderGap}       || $arg{BorderWidth}       ||
   $arg{BorderGapLeft}   || $arg{BorderWidthLeft}   ||
   $arg{BorderGapRight}  || $arg{BorderWidthRight}  ||
   $arg{BorderGapTop}    || $arg{BorderWidthTop}    ||
   $arg{BorderGapBottom} || $arg{BorderWidthBottom} and
     $shape = border_shape($shape,
        $arg{BorderGapLeft}     || $arg{BorderGap},
        $arg{BorderGapRight}    || $arg{BorderGap},
        $arg{BorderGapTop}      || $arg{BorderGap},
        $arg{BorderGapBottom}   || $arg{BorderGap},
        $arg{BorderWidthLeft}   || $arg{BorderWidth},
        $arg{BorderWidthRight}  || $arg{BorderWidth},
        $arg{BorderWidthTop}    || $arg{BorderWidth},
        $arg{BorderWidthBottom} || $arg{BorderWidth});
   if ($arg{Indent}) { my $s = ' ' x $arg{Indent}; $shape =~ s/^/$s/mg }
   $arg{Text} and return
      pour_text($shape, $arg{SourceString}, $arg{Gap}, $arg{TextFiller});
   "use re 'eval';\n" x ($arg{Regex} == 3 || ($arg{Regex} == 1 && $] >= 5.017)) .
   'local $SIG{__WARN__}=sub{};' x $arg{TrapWarn} .
   pour_sightly($shape, $sightly, $arg{Gap}, $fill, $arg{Compact},
   $arg{InformHandler}) . "\n\n\n;die \$\@ if \$\@\n" x $arg{TrapEvalDie};
}

# -------------------------------------------------------------------------

sub _get_eye_shapes {
   my $d = shift;
   opendir my $dh, $d or die "opendir '$d': $!";
   my @e = sort map(/(.+)\.eye$/, readdir($dh));
   closedir($dh); @e;
}

sub _get_eye_string { _slurp_tfile($_[0] . '/' . $_[1] . '.eye') }

sub _get_eye_properties {
   my $f = $_[0] . '/' . $_[1] . '.eyp';
   -f $f or return;

lib/Acme/EyeDrops.pm  view on Meta::CPAN

          ,map($|--?$"    x(-3    *11+ord):$_,
          /./g)}split+    Z,$~    ),@x);splice
         @;,   -$_,  2,pop@,;@;=(""  ,@;)   ;;;
          ;sleep!                      $%}+2..
            18#                          /-\

=head1 REFERENCE

=head2 Sightly Encoding

There are 32 characters in the sightly character set:

    ! " # $ % & ' ( ) * + , - . /            (33-47)
    : ; < = > ? @                            (58-64)
    [ \ ] ^ _ `                              (91-96)
    { | } ~                                  (123-126)

A I<sightly string> consists only of characters drawn from
this set.

The C<ascii_to_sightly> function converts an ASCII string
(0-255) to a sightly string; the C<sightly_to_ascii> function
does the reverse.

=head2 Function Reference

=over 4

=item ascii_to_sightly STRING

Given an ascii string STRING, returns a sightly string.

=item sightly_to_ascii STRING

Given a sightly string STRING, returns an ascii string.

=item regex_print_sightly STRING

Given an ascii string STRING, returns a sightly-encoded Perl
program with a print statement embedded in a regular expression.
When run, the program will print STRING.

=item regex_eval_sightly STRING

Given a Perl program in ascii string STRING, returns an
equivalent sightly-encoded Perl program using an eval
statement embedded in a regular expression.

=item clean_print_sightly STRING

Given an ascii string STRING, returns a sightly-encoded Perl
program with a print statement executed via eval.
When run, the program will print STRING.

=item clean_eval_sightly STRING

Given a Perl program in ascii string STRING, returns an
equivalent sightly-encoded Perl program using an eval
statement executed via eval.

=item regex_binmode_print_sightly STRING

Given an ascii string STRING, returns a sightly-encoded Perl
program with a binmode(STDOUT) and a print statement embedded
in a regular expression. When run, the program will print STRING.
Note that STRING may contain any character in the range 0-255.
This function is used to sightly-encode binary files.
This function is dodgy because regexs don't seem to like
binary zeros; use C<clean_binmode_print_sightly> instead.

=item clean_binmode_print_sightly STRING

Given an ascii string STRING, returns a sightly-encoded Perl
program with a binmode(STDOUT) and a print statement executed
via eval. When run, the program will print STRING.
Note that STRING may contain any character in the range 0-255.
This function is used to sightly-encode binary files.

=item get_builtin_shapes

Returns a list of the built-in shape names.

=item get_eye_dir

Returns the directory containing the F<.eye> file shapes.
This is the F<EyeDrops> sub-directory underneath
where F<EyeDrops.pm> is located.

=item get_eye_shapes

Returns a list of the I<eye> shapes in ascii-betical order.
An eye shape is just a file with a F<.eye> extension residing
in the F<get_eye_dir> directory.

=item get_eye_keywords

Returns a hash reference keyed by keyword, with the
value being the list of shapes containing the keyword.

=item find_eye_shapes KEYWORDLIST

Returns a list of the I<eye> shapes in ascii-betical order
that contain all keywords in KEYWORDLIST.
The keywords in KEYWORDLIST are implicitly AND'ed together.
Additionally, you may use OR inside any KEYWORDLIST element.
If this is unclear, see the examples in "Shape Properties"
section below.

=item get_eye_string SHAPENAME

Given a .eye SHAPENAME, returns the shape string.

=item get_eye_properties SHAPENAME

Given a .eye SHAPENAME, returns a hash reference of
the shape properties or undef if the shape has no
properties.

=item slurp_yerself

Returns a string containing the contents of F<EyeDrops.pm>.

=item make_triangle WIDTH

Returns a triangle shaped string of WIDTH characters.

=item make_siertri WIDTH

Returns a Sierpinski triangle shaped string containing 2**WIDTH lines.

=item make_banner WIDTH STRING

Linux only. Returns a banner of STRING, using the Linux command
C</usr/games/banner -w WIDTH>.



( run in 2.288 seconds using v1.01-cache-2.11-cpan-cdf2f3d4e48 )