Quines
As most programmers – or anyone who read the first heading on this page – will already know, a quine is a program which writes its own source code as its output. There are a number of rules to write them properly and to avoid repeating information that is already out there myself, Ray Toal’s post on the subject is fairly comprehensive.
In this short post, I will summarize the topic using C as an example, have a crack at writing my own quine in Awk and discuss the problems I had when I tried to write one using DTrace.
A tutorial in C
The key to writing a quine is to find an alternative way to use a quote character than the literal character itself. This is because the quote character would prematurely end the string and therefore requires escaping with a backslash. However, the backslash character also needs to be escaped so you end up in a loop of escaping from which there is no escape!
The C example I am showing below is from this stackoverflow post and is designed to work with “modern C”. It works because the string interpolates itself when it is passed as both the first and fourth arguments to printf
. The first argument to printf
is a format string containing an arbitrary number of placeholders which are populated by its subsequent arguments.
In C the printf
function can use a char
placeholder (%c
) in a format string and then, because a char
is just an int
, interpreted as an ASCII character, the integer value of an ASCII quote (34) can be passed as an argument. Newlines can be passed as decimal 10 to avoid the backslash escape hell there as well.
#include <stdio.h> char*s="#include <stdio.h>%cchar*s=%c%s%c;%cint main(void){printf(s,10,34,s,34,10,10);}%c"; int main(void){printf(s,10,34,s,34,10,10);}
Awk quine
The Awk quine is fairly trivial. We make use of the special BEGIN
pattern to cause our code to be executed at the start of the program. The rest of the program is very easy to understand.
BEGIN{s="BEGIN{s=%c%s%c;printf(s,34,s,34,10)}%c";printf(s,34,s,34,10)}
This can be run by issuing the command: awk -f quine.awk
assuming that the above code is saved to a file named quine.awk
.
Okay, so the DTrace quine should look the exact same then, right? Well, not exactly.
DTrace quine
The problem is that DTrace’s printf
statement takes a string constant
as its first argument. A string constant
, in DTrace, is a string surrounded by quotes (not assigned to a variable). It seems possible to create a constant by using a global inline string but I couldn’t get it to work because DTrace still recognizes it as an ordinary string. DTrace also has a char
type so I also tried assigning a char
a quote using its ASCII representation but when passed to the trace
function, the integer value is output, rather than the character.
After a fair bit of faffery, I have to put the DTrace quine on hold until I have any other new ideas. And before my supervisor at university has a stroke when he finds out how I spent the time I should have been conducting experiments for my project.