IOCCC image by Matt Zucker

The International Obfuscated C Code Contest

2025/yang1 - Compound prize

slash/head/tail/chop/prime tool

Author:

Award: Compound prize

To build:

    make all

To use:

    ./prog number < in > out

Try:

    ./try.sh

Judges’ remarks:

What’s better than winning entry that does something useful? An entry that does multiple useful things! Then when you consider that the code is a A polyglot, we think you will be even more impressed.

As an added bonus, there are some real Perls and Ruby gems in the code.

And while you are at it, open making.html in your favorite browser to watch how the author created this excellent winning entry. To watch obfuscation in action, we recommend that you:

A fun challenge

Create an alternative form of prog.c (i.e., prog.alt.c) that also allows for integers, somewhat larger than 9999, to be tested for primality.

The above fun challenge is still open. See the “Fun challenge Info” section for details.

Author’s remarks:

Synopsis

    ./prog {line_number} < {input.txt} > {output.txt}

    ./prog 1 < prog.c > prog_head.c && gcc prog_head.c -o prog_head
    ./prog -1 < prog.c > prog_tail.c && gcc prog_tail.c -o prog_tail

    ./prog_head {line_count} < {input.txt} > {output.txt}
    ./prog_tail {line_count} < {input.txt} > {output.txt}

    ruby prog.c {line_count} < {input.txt} > {output.txt}

    ./prog_head 40 < prog.c | ./prog_tail 12 > prog_generate.c
    gcc prog_generate.c -o prog_generate && ./prog_generate > prog_classify.c

    ./prog {integer_between_1_and_9999} < prog_classify.c > output.c
    gcc output.c -o output && ./output
    cpp output.c | grep main

    perl prog.c

Details

This entry contains a collection of line-based file cutting tools.

Slash

The main program removes a single line from stdin and writes the result to stdout.

    ./prog {line_number} < {input.txt} > {output.txt}

This program accepts a single command line argument, which specifies the line number of the line to remove.

The code will still compile when a single line is removed, but the program behavior will change, see the next sections.

Removing a single line from lines 1..41 (i.e., the “head” portion of the code) will produce a tool that behaves similar to head(1):

    ./prog 1 < prog.c > prog_head.c && gcc prog_head.c -o prog_head

    ./prog_head {line_count} < {input.txt} > {output.txt}

This program accepts a single command line argument, which specifies number of lines to keep.

Tail

Removing a single line from lines 42..62 or -1..-21 (i.e., the “tail” portion of the code, or the tip of the ponytail hair) will produce a tool that behaves similar to tail(1):

    ./prog -1 < prog.c > prog_tail.c && gcc prog_tail.c -o prog_tail

    ./prog_tail {line_count} < {input.txt} > {output.txt}

This program accepts a single command line argument, which specifies number of lines to keep.

Chop

Sometimes the complement behavior of head/tail is more convenient, i.e., specify how much to drop instead of how much to keep. This can be achieved by running the code with Ruby:

    ruby prog.c {line_count} < {input.txt} > {output.txt}

This program accepts a single command line argument, which specifies number of lines to drop.

Prime classifier

After having built all the tools for cutting files, naturally you might be looking for something to cut. You might have noticed that there is a complete C program embedded within prog.c, which can be extracted in at least three ways:

    ./prog_head 40 < prog.c | ./prog_tail 12 > prog_generate.c
    ./prog_tail 34 < prog.c | ./prog_head 12 > prog_generate.c
    ruby prog.c 28 < prog.c | ruby prog.c -22 > prog_generate.c

This program generates another C program on stdout:

    gcc prog_generate.c -o prog_generate && ./prog_generate > prog_classify.c

This output code is a number classifier with 9999 lines. It will compile as is (and outputs ? to stdout), but it will also compile when a single line is removed. The output will tell you whether the line number of the removed line was prime, composite, or one.

    ./prog 1 < prog_classify.c > output_one.c
    ./prog 2 < prog_classify.c > output_prime.c
    ./prog 1234 < prog_classify.c > output_composite.c
    ./prog 9973 < prog_classify.c > output_prime.c
    ./prog 9999 < prog_classify.c > output_composite.c

You can compile and run the output code to get the classification printed to stdout. But since classification is done entirely at compile time, you can just run the C preprocessor and search for main, which is usually the last line:

    cpp output_one.c | ./prog_tail -1
    cpp output_prime.c | ./prog_tail -1
    cpp output_composite.c | ./prog_tail -1

Miscellaneous features

Layout of the code is based on Ubel from “Sousou no Frieren” (Frieren: Beyond Journey’s End), for her ability to cut just about everything.

The main feature is being able to compile even with one line removed, and detect which region contained the removed line. It costs a lot of preprocessor lines to write code that can survive and detect cuts, and those extra lines worked against making the layout work. This resulted in a slightly large ASCII art, and I tried to fill in as many features as possible in the extra space. Besides the collection of tools listed above, there are a few bonus features to fill in the remaining bytes:

Compatibility

Ubel requires compiler supporting C99 and above, or C++98 and above. The main C program and the generated C code from cutting the main program have been verified to work under these environments:

It would have been trivial to write a cut-detecting program using C23’s #embed feature, but that requires C23. Instead, this program targeted the more widely available C99 standard. C99 is needed to support this pattern:

    original_line();  /*
    backup_line();    //*/

If I had gone with C90, the equivalent pattern would have been /* /* */, but there we would trip over -Wcomment warnings when compiling with -Wall -Wextra -pedantic. By making use of C99’s //, the main C code and the embedded/generated C code all compile without warnings.

The extra embedded scripts have been verified to work under these environments (runs free of warnings with ruby -w and perl -w):

Everyone has probably written their own brainf.ck interpreters a few times, but I packaged another one here just in case.

Inventory for 2025/yang1

Primary files

Secondary files


 Jump to: top