/*
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 */
}