TINCL
TINCL, The Idiotically Named CGI Language, is a template-and-C preprocessor written in 1998 by Ben Olmstead - the creator of Malbolge - for writing CGI programs at the Colorado School of Mines. A TINCL source file is divided into named sections, mixes literal HTML with escaped blocks of C, and is compiled by a flex-based translator into a C program; the language was never taken past beta, and its distribution archive is lost
Created by Ben Olmstead, then a student at the Colorado School of Mines in Golden, Colorado, writing from the account bolmstea on the school's student web server. He is far better known for Malbolge, the deliberately unusable esoteric language he released the same month, and for maintaining the Random Programming Languages List; TINCL is the practical, unfunny half of the same personal web site
TINCL - The Idiotically Named CGI Language - is a template language for writing web programs, written in April 1998 by Ben Olmstead while he was a student at the Colorado School of Mines. A TINCL file is mostly HTML; where it is not HTML, it is C, wrapped in percent-brace escapes. A flex-based translator turns the whole thing into a C source file, and a C compiler turns that into a CGI executable.
The interesting thing about TINCL is who wrote it and when. In the same weeks of the same spring, on the same student account, Olmstead released Malbolge, the language built so that programming in it would be as close to the infernal as possible and which resisted being used at all for two years. TINCL is what the author of the world’s most hostile programming language wrote when he wanted to get a form processed. It is sensible, unglamorous, thoroughly commented and, by his own classification, serious - which is precisely why it disappeared while Malbolge became famous.
What actually survives
Everything on this page comes from four files, and it is worth being exact about them:
| Source | Date | What it gives |
|---|---|---|
tincl/ project page | written 20 Apr 1998, captured 2000-2004 | The expansion of the name, the build requirements, the beta warning, the link to the lost tincl.zip |
beer.html demo page | written 18 Apr 1998, captured from Oct 1999 | The description “based on C and generating C code (it was heavily influenced by Lex)”, and a live form pointing at a compiled TINCL program |
tincl/templ.tin | captured 2002-2004, byte-identical | 306 lines: the complete language reference, written as commentary inside a working TINCL program |
99bob.tin | captured Jan 2000 | The one deployed application: thirty lines, of which twenty-three are program |
What does not survive is the implementation. tincl.zip was linked from the
project page for six years and was never crawled; when the student account went
away in 2004 the compiler went with it. There is no mirror, no source
repository, no packaged copy and no reimplementation. TINCL is a language for
which the specification is intact and the compiler is gone - the opposite of the
usual situation with lost languages, and arguably the more frustrating one.
The name
The project page states it plainly:
TINCL (The Idiotically Named CGI Language) is a language designed for CGI programming. Like Lex and yacc, it is essentially just a C wrapper (at least for now). It is currently in Beta/flux, so backwards compatibility, documentation, and working implementations are not guaranteed.
The recursive self-deprecation is of its period and of its author - the same person whose “Ego Gratification Page” opens “About me: I’m a human, not a computer or a cucumber or something” and whose esoteric-language list opens by asking whether you have ever wondered what life would be like without our nifty tools. It also has a practical consequence: a language whose name is a joke about its own name is almost impossible to search for, and in 2026 the phrase “The Idiotically Named CGI Language” appears, so far as could be determined, nowhere on the live web outside archived copies of Olmstead’s own pages.
How a TINCL program is built
A source file is divided into up to five sections, each introduced by a name
between %. and .%. Any section may be omitted:
| Section | Purpose |
|---|---|
%.config.% | Declarations about the program: which HTTP methods supply input, whether to emit the default header, plus C #includes and globals that go to the top of the generated file |
%.fragments.% | Named blocks of output text, compiled into zero-argument C functions |
%.headers.% | Literal HTTP headers, with leading whitespace stripped and blank lines ignored |
%.html.% | The body of the program: HTML by default, C where escaped |
%.c.% | Straight C for the end of the generated file - function definitions and anything else |
Skipping %.config.% accepts all defaults; skipping %.headers.% emits the
default Content-type: text/html unless no-default-headers is set in
%.config.%; skipping %.html.% produces an empty
document. The config section is a small vocabulary of English words rather than
a syntax - get-input, post-input, no-post-input, command-line-input,
no-default-headers - and commas between them are ignored, “and may be used as
desired to make the place look nicer.”
The escapes
Inside %.html.%, anything that is not a recognised escape is text to be echoed.
The escapes are:
| Escape | Meaning |
|---|---|
%{ ... }% | A block of C, emitted verbatim into the generated program |
%' name '% | Declare a fragment; everything up to the next declaration is its text |
%( name )% | Call a fragment; exactly synonymous with %{ name(); }% |
%[ name ]% | Print the form field name; inside C it becomes get_value( "name" ) with no semicolon |
%! NAME !% | Print the environment variable at run time; inside C, getenv( "NAME" ) |
%# expr #% | Print a C integer expression as a signed base-10 number |
%: ... :% | A TINCL comment, non-recursive, stripped before the C file is written |
| `%? c % | a :: b |
%" ... "% | Synonym for }% ... %{, for writing readable interleaved conditionals |
Hyphens inside fragment names are mapped to underscores, “merely a convenience
the author likes and nothing more” - which is how a fragment written
%'html-header'% becomes the C function html_header().
Control flow by unbalanced brace
The design decision that gives TINCL its character is that it has no control structures. It has C, and C’s braces are allowed to be left open across stretches of HTML. The reference file says so outright: it is “completely permissible to leave unbalanced {} in a C block”. So a conditional plural is written like this, from the surviving beer program:
%#beer#% bottle%{ if ( beer != 1 ) { }%s%{ } }% of beer on the wall,<br>
and a loop over a fragment like this:
%{ while( beer > 0 ) { %(fragment)% } }%
Because that quickly becomes unreadable, the language supplies %" and "% as
aliases so the same conditional can be written as
%{ if ( bool ) { %"Some HTML"% } }%, and %?, %|, ::, |% as an even
terser form. The aliases can be mixed freely with the raw braces - “a feature
which can be either used or abused as you see fit.”
The one surviving application
99bob.tin is the complete deployed program, minus its comment header:
%.config.%
get-input, post-input
%{
#include <stdlib.h>
int beer;
}%
%.fragments.%
<p>
%#beer#% bottle%{ if ( beer != 1 ) { }%s%{ } }% of beer on the wall,<br>
%#beer#% bottle%{ if ( beer != 1 ) { }%s%{ } }% of beer,<br>
Take one down and pass it around,<br>
%{ if ( !--beer ) { }%No more%{ } else { }%%#beer#%%{ } }% bottle%{ if ( beer != 1 ) { }%s%{ } }% of beer on the wall.
</p>
%.html.%
%{ set_var( &beer, 0, 1000, 99, get_value( "beer" ) ); }%
<html><head><title>%#beer#% Bottles of Beer on the Wall</title></head>
<body>
%{ while( beer > 0 ) { %(fragment)% } }%
</body></html>
Three things are worth noticing. The config section declares that the program
accepts both GET and POST, and that is the whole of its request handling. The
unnamed leading text in %.fragments.% becomes a fragment called fragment,
which is why the loop can call %(fragment)% without anything having been
named. And the single line of real logic is the set_var call, which is the
language’s answer to hostile input.
Taking untrusted input seriously in 1998
set_var has the signature
| |
and the documentation explains the arguments in terms of what a stranger might
do to you: min and max are the bounds, because “if you’re using it for a
loop, you don’t want someone taking up all your processor time, for example”,
and def is what to use when str is null or is not a number. A form field is
never an integer until it has been through a function that takes a floor, a
ceiling and a fallback. In the beer program the bounds are 0 and 1000 - though
the public demo page advertises 0 to 200, so the page and the program had
already drifted apart by the time both were archived.
The reference file is similarly blunt about the two things it will not protect
you from. Printing a form field directly “can lead to strange happenings,
although no security breeches: just, if someone types in some HTML code it will
be interpreted as HTML code”, with <img src="wherever"> given as the example -
a plain description of what would later be called cross-site scripting, written
before the term existed and dismissed as a cosmetic problem. And printing
environment variables you should not, such as PATH, “is not a security hole,
just a window, but windows let crackers see the holes.”
There is also a debugging feature that is more thoughtful than the beta status
suggests. Passing -t to the compiler turns on command-line-input and turns
off GET, POST and default headers “no matter what the config section says”, so
that a program can be driven from a shell with name=value arguments - the
stated reason being “so you don’t have to post potential security holes before
they’re ready.”
Where it sits in 1998
TINCL was written into a specific gap. CGI in 1998 usually meant Perl, or C with
a library. The alternative approach - HTML as the outer layer with code embedded
in it - was arriving at exactly that moment: PHP/FI had become PHP 3 in June
1998, Microsoft’s Active Server Pages had shipped in 1996, and Perl’s HTML
templating modules were in circulation. TINCL is a member of that family that
chose C as its embedded language and compilation as its execution model. Its
own comparison is not to any of them but to lex and yacc: like them it is a
translator that eats an annotated source file and produces C, and like them its
generated output is meant to be handed straight to cc.
That choice has one obvious payoff and one obvious cost. The payoff is that a TINCL page is a compiled binary with no interpreter startup, at a time when CGI meant forking a new process for every request - though no benchmark of TINCL against anything was ever published, so this is an argument about design and not a measured result. The cost is that the whole edifice needs a C toolchain plus flex on the server, that a typo in an escape surfaces as a C syntax error in generated code, and that the audience for “CGI, but you must know C” was never large.
Running TINCL
It cannot be done. The compiler was distributed only as tincl.zip from
www.mines.edu/students/b/bolmstea/tincl/; that page stopped answering in 2004
and the Internet Archive holds captures of the page but never of the archive.
There is no Docker image, no package, no mirror and no reimplementation.
Rebuilding it is not a hopeless project: templ.tin documents the sections, the
escapes, the aliases, the runtime helpers (get_value, set_var and
affirmative) and the config vocabulary in
enough detail that a flex scanner emitting C could plausibly be written from it in
a weekend. How long the original took its author is not recorded anywhere. But
that would be a reconstruction from the manual, not the language as it shipped.
Why it matters
TINCL matters for three reasons, none of which is technical merit.
First, as a counterweight. Ben Olmstead is remembered for one artefact, a language engineered so that its first working program had to be found by a search algorithm rather than written. TINCL shows the same person, in the same month, on the same web server, doing careful, defensive, well-commented work on a tool for real use - bounds-checking form input, providing an offline test mode, warning the reader about echoing environment variables. Esoteric programming languages are usually made by people who understand ordinary ones very well, and here is the proof in the same directory listing.
Second, as an illustration of what survives. TINCL had a documentation file, a working demo, a public download and six years of continuous availability. What made it into 2026 is the documentation and the demo - text files a crawler could save - while the download, the only part that could not be regenerated, evaporated. The language’s presence in modern encyclopedia lists rests entirely on a stranger’s anonymous 2005 copy-paste of a beer song into a novelty catalogue, whose author and URL fields were left as “Anonymous” and “n/a” - the only attribution to survive the trip being the six lines of comment Olmstead had put at the top of the file himself.
Third, as a marker in the history of web templating. The idea that a page should be HTML on the outside and code on the inside was not obvious in 1998; it had to be arrived at repeatedly, by different people, in different languages, most of whom were not aware of each other. TINCL is one of those independent arrivals - smaller and shorter-lived than PHP or ASP, but recognisably the same idea, worked out by one student in one spring, and documented well enough that a quarter of a century later you can still read exactly what he meant.
Timeline
Notable Uses & Legacy
99 Bottles of Beer CGI at the Colorado School of Mines
The only TINCL program known to have been deployed. A thirty-line source file, 99bob.tin - twenty-three lines of program under a six-line comment header - compiled to a CGI executable served through cgiwrap on the school's student web server, which read a form field named beer and printed that many verses. Its own demo page advertises bounds of 0 to 200 verses while the source passes 0 and 1000 to set_var - a discrepancy preserved for twenty-eight years because both files were captured
templ.tin, the language's documentation
TINCL's reference manual is a TINCL program. The 306-line templ.tin walks through every section and escape in the language inside %: ... :% comments, while simultaneously being a compilable page that greets the reader, prints a scaled number, echoes a form field and dumps PATH_INFO. It is both the specification and the largest surviving example
99-bottles-of-beer.net entry 452
Not a use so much as the reason anyone still has the name. The anonymous 2005 submission appears to be the only copy of a TINCL program to have lived outside the Internet Archive, and is the source of the language's appearance in modern encyclopedia lists. Its author, e-mail and URL fields read Anonymous, Anonymous and n/a - though the pasted source retains Olmstead's own comment header, which is where the name and the 1998 date can still be read