Files
ioccc/1990/tbr
Cody Boone Ferguson 205fa25ced Change references of many terms to new names
This is a HUGE commit and this task is not done. There are still some
changes that might need to be discussed and since so much is done here I
think it's better to let this go through and then make sure everything
is okay. When the remaining references are discussed they can also be
changed.

I did NOT include changes in the tmp/OLD_manifest directory.

Some of the changes in this commit (it might be exhaustive but it might
not be - not sure):

- In the Makefiles the WINNERS was renamed AUTHORS.
- References to winners.html were changed to authors.html.
- The FAQ named anchor 'fix_a_winner' was renamed 'fix_an_entry'.
- The JSON fields (or whatever they're called) 'winner_id' and
'winner_JSON_format_version' were changed so that 'winner' is 'entry'.
- In scripts for entries 'IOCCC winner' was changed to 'IOCCC entry'.
- 'winners_text' is now 'entries_text'. It might be better to be
'entry_text' as it's per entry but this was not noticed at first. Since
this is easy to fix I am holding off on this for the meantime.
- The script tmp/update-manifest.sh now has the commit log messages
changed to the correct terms as well.

The index.html files were updated as well with any of the above
changes.

There are some references that should NOT be updated. Two examples
caught (and maybe more have slipped through that will have to be changed
back): in 1984/anonymous/README.md the author wrote back to Landon after
being told about the famous tattoo and they used the words:

    .. my entry will be the first IOCCC winner ..

but since this comes from the author it should remain so.

The other one is that winners.html should still refer to winners.html as
it informs people that it's been moved to authors.html (it does redirect
too but even so if it was changed it would defeat the purpose of the
message).

With paths like authors.html I tried to copy paste so that hopefully
there are no typos. It is possible that I did not end up doing this with
all but these can be fixed when discovered.
2024-02-13 07:31:36 -08:00
..
2024-02-01 14:35:49 -08:00
2024-01-15 04:29:39 -08:00
2023-10-11 03:09:57 -07:00
2023-10-11 03:09:57 -07:00
2023-07-06 21:49:38 -07:00

To build:

make all

The authors provided another version of this program. See the alternate version section below.

Bugs and (Mis)features:

The current status of this entry is:

STATUS: INABIAF - please **DO NOT** fix

For more detailed information see 1990 tbr in bugs.md.

A note about the fixes of this entry in 2023:

In 2023 it was noticed that in some systems like macOS there was confusing output due to a warning at runtime that was interspersed with the output of the program. For instance it would show:

./tbr
$ warning: this program uses gets(), which is unsafe.

which kind of hid the prompt. Thus the entry was changed to use fgets(3) which is referred to later in this file.

Also exit(3) returns void but the entry was using it in a binary expression so this entry would not compile in modern systems. This fix is also referred to below, in the alternate version section.

To use:

./tbr
$ enter some shell commands

NOTE: globs do not work with this entry. Why?

NOTE: exit does not work and neither does logout. To exit try sending ctrl-d or ctrl-c (or kill it from another terminal :-) ). But why does it not work with just exit or logout? Hint: see the authors' remarks.

Try:

./tbr
$ ls -l tbr tbr.c

# notice how the following does not work:
ls tbr*

# try figuring out how this entry works in an editor:
vi tbr.c

# then figure out how to exit vi :-)

What happens if you try using cd - to return to previous directory? What about cd with no args?

The authors include a section called BUGS that, because they were documented, are not considered bugs as such in the context of the contest.

Alternate code:

The authors supplied us with a slightly smaller unformatted version of the program which we include below:

#define D ,close(
char*c,q[512],m[256],*v[99],**u,*i[3];int f[2],p;main(){for(m[m[60]=m[62]=
32]=m[*m=124[m]=9]=6;e(-8),gets(1+(c=q))||(exit(0),0);r(0,0))for(;*++c;);}
r(t,o){*i=i[2]=0;for(u=v+98;m[*--c]^9;m[*c]&32?i[*c&2]=
*u,u-v^98&&++u:3)if(!m[*c]){for(*++c=0;!m[*--c];);*--u=
++c;}u-v^98?strcmp(*u,"cd")?*c?pipe(f),o=f[1]:1,(p=fork())?e(p),o?
r(o,0)D o)D*f):4,wait(0):(o?dup2(*f,0)D*f)D o):*i?1 D
0),e(open(*i,0)):5,t?dup2(t,1)D t):i[2]?9 D
1),e(creat(i[2],438)):2,e(execvp(*u,u))):e(chdir(u[1])*2):6;}
e(x){x<0?write(2,"?\n$ "-x/4,2),x+1||(exit(1),0):5;}

and in the alternate source. It has the exit() returns void fix as well as the gets() to fgets() fix applied to it to make it functionally equivalent like the authors intended.

Alternate build:

make alt

Alternate use:

./tbr.alt

Judges' remarks:

This program touches on a well known Unix utility, the 6th edition Bourne Shell (/bin/sh), whose original source was considered to be extremely obfuscated by many people (although Steve Bourne might disagree). Did you know that the Bourne Shell source was a major inspiration for the formation of the IOCCC back in 1984?

Authors' remarks:

This program is a rudimentary shell. It does I/O redirection, pipes and cd. It flags errors on failed chdir(), open(), creat(), execvp(), fork() and a few syntax errors.

This program is obfuscated in a few notable ways: apart from the layout (an unformatted (but crunched) version is included for people who want to put this through cb) it makes clever use of a write() statement, so that the same statement can be used to print errors and the prompt. By calling the error function with the value -8, the pointer offset in the expression "?\n$ "-x/4 goes from 0 to 2. Presto! A prompt. For errors with numbers smaller than -4 (i.e., UNIX system calls) a question mark is printed.

The error value of chdir() is doubled so that we don't exit from the parent shell on a chdir() error (since e() exits on -1 errors only). All other system call failures exit since they are from sub-shells.

Recursion is sneakily employed to avoid a second call to fork(), and the line is parsed in a fairly bizarre fashion: backwards. The heart of the program, that is, the part which performs all fork()s, exec()s, open()s, etc. is ONE C STATEMENT.

The meta-values array is initialized in a bizarre fashion, and the subsequent checks for the '<' and '>' are performed in a single statement using a mask, since you know that '>'&2 is 0, whereas '<'&2 is 2. Other such micro-obfuscations abound.

Finally, it is notable that the code was hacked for minimality. If you look at the compressed version, you will be hard-pressed to eliminate more than a few characters (we can't see how to make it any smaller!). 550 characters is pretty lean for a shell that does this much.

BUGS

The syntax of the shell has not been fully explored, but if you try to redirect in the same direction more than once, only one redirection is performed. This is a "feature" of the way the line is parsed; a pointer to the stack of arguments is assigned and an argument is stolen every time a > or < is encountered. The shell flags an error if no arguments are on the stack. Thus, for example:

cat > foo > bar

cats to foo, since it was pushed last, but

cat > > foo bar

cats to bar, since bar was pushed under foo (remember we're parsing right-left).

Depending on your flavor of Unix, cd without an argument will either produce an error or just do nothing.

There is just one error message, the question mark, but hey, that's all ed(1) does too.

This file is Copyright (c) 2023 by Landon Curt Noll. All Rights Reserved. You are free to share and adapt this file under the terms of this license:

Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)

For more information, see: https://creativecommons.org/licenses/by-sa/4.0/