/*
No conditional branches! What that applies:
1. any loops forbidden,
2. printf() forbidden for it has to lookup placeholders in the pattern,
3. NUL-terminated strings are useless, due to testing for '\0' is forbidden;
4. (!!!) do not use libc, due to many conditional statements in every function
Usage:
gcc -Wall -Wextra -Wl,-s -nostdlib 99-bottles-of-beer.c
... or ...
gcc -nostdlib 99-bottles-of-beer.c
Dependencies:
x86 arch with Linux
Idea:
http://www.99-bottles-of-beer.net/
*/
const char wall[12] = " on the wall";
const char take[65] =
"Go to the store and buy some moreTake one down and pass it around";
/* quit() - syscall exit() */
static void quit(int a) {
(void) a;
asm volatile ("int $0x80" : : "a" (1), "b" (0));
}
/* write() - syscall write() with fd = 1 */
static void write(const char *buf, long size) {
asm volatile ("int $0x80" : : "a" (4), "b" (1), "c" (buf), "d" (size));
}
/* p() - return 1 for any positive integer and 0 otherwise */
static unsigned char p(char n) { return ( (unsigned char) -n ) >> 7 ; }
/* putTail() - print "" for 1 and "s" otherwise */
static void putTail(char n) { write("s", p((n - 1) & 0x7F)) ; }
/* putNum() - print out number of bottles
n - number of bottles
cap - if the first letter should be capitalized
*/
static void putNum(char n, char cap) {
int length = 1 + p(n / 10) + 6 * (1 - p(n));
static char a[9] = "..no more";
a[0] = '0' + (n / 10);
a[1] = '0' + (n % 10);
a[2] = 'N' * p(cap) + 'n' * (1 - p(cap));
write(a + 1 - p(n / 10) + 1 * (1 - p(n)), length);
}
/* putPhrase() - print out phrase counting bottles
n - number of bottles
cap - if the 1st letter should be capital
*/
static void putPhrase(char n, char cap) {
putNum(n, cap);
write(" bottle", 7);
putTail(n);
write(" of beer", 8);
}
/* putLine() - print out the 2nd line of the verse */
static void putLine(char n) {
write(take + 33 * p(n), 33 - p(n));
write(", ", 2);
putPhrase(n - 1 + 100 * (1 - p(n)), 0);
write(wall, 12);
write(".\n\n", 3);
}
/* putVerse() - print out the verse */
static void putVerse(int num) {
putPhrase(num, 1);
write(wall, 12);
write(", ", 2);
putPhrase(num, 0);
write(".\n", 2);
putLine(num);
}
int _start() {
void *funcs[] = { &quit, &putVerse };
void (*foo) (int);
char cx = 99;
again:
foo = funcs[p(cx + 1)];
foo(cx--);
goto again;
quit(0);
return 0; /* convenience */
}