in reply to Re: Format quine (slightly obfu)
in thread Format quine (slightly obfu)

Thank you! You're correct in that it prints out itself. It's not strictly a true quine, since it reads in its own file, but fun nonetheless. Read on for a breakdown of how it works:

First, check it out with syntax highlighting: http://pastebin.com/m4ae94ecb. You can see that part of line 7 is a comment, just there to throw you off, and to fill up the columns. Line 6 doesn't have a comment, but pastebin's syntax highlighting doesn't understand what's going on. It's important to note that there's some significant trailing whitespace on lines 8 and 11, and that all whitespace is important because of the way it's read in. More on this later.

use strict; my @f; use warnings;

The first line invokes the strict and warnings pragmas, and declares an array, @f

open 0; $/= \11;

This next part makes use of the open 0 trick mentioned in japhy's Obfuscation Review to open the script on the filehandle 0. Then, the input record separator ($/) is set to a reference to the integer 11, meaning "read 11 bytes at a time." This is why each line is made of 10-character chunks separated by spaces (or newlines).

my $i = 0; while (<0>) { chop;

Next, we create a loop to read in the file (filehandle 0, remember), and chop off the last character of each 11 bytes, which ought to be a space or a newline. I'm not sure if this would work on Windows, since newlines are "\r\n", two bytes, but on Linux, the single byte newline gets chopped off.

push @{ $f[$i] }, $_; $i = ( $i + 1 ) % 3 } close 0;

The next statement treats the $ith element of @f as an array ref, dereferences it, and pushes the current 10-byte value of $_ onto it. Then $i is incremented modulo 3, because of the three columns of the original file. This ends the input loop.

$~ = "it";

$~ is the name of the current format for output, so we set it to "it", defined later.

my ($l, $m, $r) = map { $f[$_] }(0 .. 2);

This map assigns the three columns of the @f array of arrays to variables for the left, middle, and right columns of output.

for ( 0 .. $#{ $l } ) {

Here, we loop over the values from 0 to the length of the array referred to by $l.

$m->[$_] ||= ''; $r->[$_] ||= '';

These statements make sure that the values in the $_th row of the middle and right columns are not undef, to avoid pesky warnings. The rest of line 7 is a comment

format it= @<<<<<<<<< @<<<<<<<<< @<<<<<<<<< $l->[$_], $m->[$_], $r->[$_], .

Here we define the format "it" to contain left-justified values of the left, middle, and right columns for this line of the output. I would have put more comments on lines 8 and 11, but Perl doesn't allow anything after a format declaration, and won't end it unless the "." is the only thing on the last line. Of course, whitespace is insignificant to the interpreter, but it does matter for this program.

write; }

Finally, we use write to print the values out according to the format.

Hope that helps!


@_=qw; Just another Perl hacker,; ;$_=q=print "@_"= and eval;