diff --git a/src/add-ons/kernel/debugger/Jamfile b/src/add-ons/kernel/debugger/Jamfile new file mode 100644 index 0000000000..615631fe0f --- /dev/null +++ b/src/add-ons/kernel/debugger/Jamfile @@ -0,0 +1,11 @@ +SubDir HAIKU_TOP src add-ons kernel debugger ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +# UsePrivateHeaders drivers ; +# UsePrivateHeaders kernel ; + + +KernelAddon hangman : kernel debugger : + hangman.c + ; diff --git a/src/add-ons/kernel/debugger/hangman.c b/src/add-ons/kernel/debugger/hangman.c new file mode 100644 index 0000000000..95d7c11990 --- /dev/null +++ b/src/add-ons/kernel/debugger/hangman.c @@ -0,0 +1,401 @@ +#ifdef _KERNEL_MODE +#include +#include +#endif +#include +#include +#include +#include +#include + +/* do we reboot on loose ? */ +//#define FAIL_IN_BSOD_CAUSE_REBOOT + +/* shortcut to be able to exit (and take a screenshot) */ +#define CAN_EXIT_ON_HYPHEN + +#define MAX_FAILS_BEFORE_BSOD 0 + +#define FORTUNE_FILE "/etc/fortunes/default" + +#define DEV_ENTRY "misc/hangman" + +#define KERNEL_IMAGE_ID 1 + +#define MIN_LETTERS 3 +#define MAX_LETTERS 10 + +#define MAX_CACHED_WORDS 5 + +char words[MAX_CACHED_WORDS][MAX_LETTERS+1]; + +/* design ripped off from http://www.latms.berkeley.k12.ca.us/perl/node30.html :) */ +static char hungman[] = \ +" ____ \n" \ +" | | \n" \ +" | %c \n" \ +" | %c%c%c \n" \ +" | %c %c \n" \ +" | \n"; +/* some colors */ +static char hungman_ansi[] = \ +" ____ \n" \ +" | | \n" \ +" | \033[36m%c\033[0m \n" \ +" | \033[35m%c%c%c\033[0m \n" \ +" | \033[35m%c %c\033[0m \n" \ +" | \n"; + +// for gets, +#define BIGBUFFSZ 128 +char bigbuffer[BIGBUFFSZ]; + +#define BIT_FROM_LETTER(l) (0x1 << (l - 'a')) + +status_t init_words(char *from); + +#ifdef _KERNEL_MODE + +# ifdef __HAIKU__ +extern int kgets(char *buf, int len); +# define PRINTF kprintf +# define GETS(a) ({kprintf("hangman> "); kgets(a, sizeof(a));}) +# define HIDDEN_LETTER '_' +# define HUNGMAN hungman_ansi +# else +/* BeOS R5 version, needs some R5 kernel privates... */ +/* the kernel pointer to the bsod_gets */ +static char *(*bsod_gets)(char *, char *, int); +extern char *(*bsod_kgets)(char *, char *, int); +//extern char *bsod_gets(char *); +/* saved here before panic()ing */ +char *(*bsod_saved_kgets)(char *, char *, int); +# define PRINTF kprintf +# define GETS(a) ((*bsod_kgets)?(*bsod_kgets):(*bsod_gets))("hangman> ", a, sizeof(a)) +# define HIDDEN_LETTER '_' +# define HUNGMAN hungman +# endif +#else +/* userland version */ +# define PRINTF printf +# define GETS(a) gets(a) +# define dprintf printf +# define HIDDEN_LETTER '.' +# define HUNGMAN hungman_ansi +#endif /* !_KERNEL_MODE */ + +status_t init_words(char *from) +{ + int fd; + size_t sz, got; + int current, beg, end, i; + struct stat st; + + memset((void *)words, 0, sizeof(words)); + fd = open(from, O_RDONLY); + if (fd < B_OK) + return fd; + /* lseek() seems to always return 0 from the kernel ??? */ + if (fstat(fd, &st)) + return B_ERROR; + sz = (size_t)st.st_size; +// sz = (size_t)lseek(fd, 0, SEEK_END); +// dprintf("khangman: lseek(): %ld\n", sz); + if (sz < 30) { + dprintf("khangman: fortune file too small\n"); + return B_ERROR; + } +// lseek(fd, 0, SEEK_SET); + //srand((unsigned int)(system_time() + (system_time() >> 32) + find_thread(NULL))); + srand((unsigned int)(system_time() & 0x0ffffffff)); + for (current = 0; current < MAX_CACHED_WORDS; current++) { + off_t offset = (rand() % (sz - MAX_LETTERS)); + // dprintf("current %d, offset %ld\n", current, (long)offset); + lseek(fd, offset, SEEK_SET); + got = read(fd, bigbuffer, BIGBUFFSZ - 2); + // dprintf("--------------buff(%d):\n%20s\n", current, bigbuffer); + for (beg = 0; beg < got && isalpha(bigbuffer[beg]); beg++); + for (; beg < got && !isalpha(bigbuffer[beg]); beg++); + if (beg + 1 < got && isalpha(bigbuffer[beg])) { + for (end = beg; end < got && isalpha(bigbuffer[end]); end++); + if (end < got && !isalpha(bigbuffer[end]) && beg + MIN_LETTERS < end) { + /* got one */ + /* tolower */ + for (i = beg; i < end; i++) + bigbuffer[i] = tolower(bigbuffer[i]); + strncpy(&(words[current][0]), &(bigbuffer[beg]), end - beg); + } else + current--; + } else + current--; + } + close(fd); +/* + for (current = 0; current < MAX_CACHED_WORDS; current++) + dprintf("%s\n", words[current]); +*/ + return B_OK; +} + +void print_hangman(int fails) +{ + PRINTF(HUNGMAN, + (fails > 0)?'O':' ', + (fails > 2)?'/':' ', + (fails > 1)?'|':' ', + (fails > 3)?'\\':' ', + (fails > 4)?'/':' ', + (fails > 5)?'\\':' '); +} + +void display_word(int current, uint32 tried_letters) +{ + int i = 0; + PRINTF("word> "); + while (words[current][i]) { + PRINTF("%c", (BIT_FROM_LETTER(words[current][i]) & tried_letters)?(words[current][i]):HIDDEN_LETTER); + i++; + } + PRINTF("\n"); +} + +int play_hangman(void) +{ + int current; + int score = 0; + int bad_guesses; + uint32 tried_letters; + char *str; + char try; + int gotit, gotone; + + for (current = 0; current < MAX_CACHED_WORDS; current++) { + tried_letters = 0; + gotit = 0; + for (bad_guesses = 0; bad_guesses < 6; bad_guesses++) { + do { + gotit = 0; + gotone = 1; + display_word(current, tried_letters); + str = GETS(bigbuffer); + if (!str) { + str = bigbuffer; + PRINTF("buffer:%s\n", str); + } +#ifdef CAN_EXIT_ON_HYPHEN + if (str[0] == '-') /* emergency exit */ + return 0; +#endif + if (!isalpha(str[0])) { + PRINTF("not a letter\n"); + } else { + try = tolower(str[0]); + if (BIT_FROM_LETTER(try) & tried_letters) { + PRINTF("%c already tried\n", try); + } else { + // REUSE + str = words[current]; + gotit = 1; + gotone = 0; + tried_letters |= BIT_FROM_LETTER(try); + while (*str) { + if (!(BIT_FROM_LETTER(*str) & tried_letters)) + gotit=0; + if (*str == try) { + gotone = 1; + } + str++; + } + } + } + //PRINTF("gotone:%d, gotit:%d, tried_letters:%08lx\n", gotone, gotit, tried_letters); + } while(tried_letters != 0x03ffffff && !gotit && gotone); + if (gotit) + break; + print_hangman(bad_guesses+1); + } + if (bad_guesses < 6) { + display_word(current, 0x03ffffff); + if (strlen(words[current]) < 5) + PRINTF("That was easy :-P\n"); + else if (strlen(words[current]) < 7) + PRINTF("Good one !\n"); + else + PRINTF("You got this hard one ! :-)\n"); + score ++; + } +/**/ + else return score; +/**/ + } + return score; +} + +#ifdef _KERNEL_MODE /* driver parts */ + +typedef struct { + int dummy; +} cookie_t; + +#ifndef __HAIKU__ /* BeOS intimacy revealed */ +//char *bsod_wrapper_gets(char *p, int len) +//char *bsod_wrapper_gets(int len, char *p) +char *bsod_wrapper_gets(char *prompt, char *p, int len) +{ + /* fall back to the normal gets() */ + bsod_kgets = bsod_saved_kgets; +// if (!bsod_kgets) +// bsod_kgets = bsod_gets; + /* and fake some typing */ + strcpy(p, fake_typed); + return p; +} +#else + +#endif + +int kdlhangman(int argc, char **argv) +{ + int score; + score = play_hangman(); +PRINTF("score %d\n", score); + if (score > (MAX_CACHED_WORDS - MAX_FAILS_BEFORE_BSOD)) { + PRINTF("Congrats !\n"); + } + if (score < (MAX_CACHED_WORDS - MAX_FAILS_BEFORE_BSOD)) { +#ifdef FAIL_IN_BSOD_CAUSE_REBOOT + PRINTF("Hmmm, sorry, need to trash your hdd... Ok, just a reboot then\n"); + fake_typed = "reboot"; + bsod_kgets = bsod_wrapper_gets; + return 1; +#else + PRINTF("Hmmm, sorry, need to trash your hdd... Well, I'll be nice this time\n"); +#endif + } + //return B_KDEBUG_CONT; + return B_KDEBUG_QUIT; +} + +const char * device_names[]={DEV_ENTRY, NULL}; + +status_t init_hardware(void) { + return B_OK; +} + +status_t init_driver(void) { + + if (init_words(FORTUNE_FILE) < B_OK) { + dprintf("error reading fortune file\n"); + return B_ERROR; + } + get_image_symbol(KERNEL_IMAGE_ID, "bsod_gets", B_SYMBOL_TYPE_ANY, (void **)&bsod_gets); + add_debugger_command("kdlhangman", kdlhangman, "A funny KDL hangman game :-)"); + return B_OK; +} + +void uninit_driver(void) { + remove_debugger_command("kdlhangman", kdlhangman); +} + +const char **publish_devices() { + return device_names; +} + +status_t khangman_open(const char *name, uint32 flags, cookie_t **cookie) { + (void)name; (void)flags; + *cookie = (void*)malloc(sizeof(cookie_t)); + if (*cookie == NULL) { + dprintf("khangman_open : error allocating cookie\n"); + goto err0; + } + memset(*cookie, 0, sizeof(cookie_t)); + return B_OK; +err0: + return B_ERROR; +} + +status_t khangman_close(void *cookie) { + (void)cookie; + return B_OK; +} + +status_t khangman_free(cookie_t *cookie) { + free(cookie); + return B_OK; +} + +status_t khangman_read(cookie_t *cookie, off_t position, void *data, size_t *numbytes) { + *numbytes = 0; + return B_NOT_ALLOWED; +} + +status_t khangman_write(void *cookie, off_t position, const void *data, size_t *numbytes) { + (void)cookie; (void)position; (void)data; (void)numbytes; + //*numbytes = 0; + /* here we get to kdlhangman */ + fake_typed = "kdlhangman"; + bsod_saved_kgets = bsod_kgets; + bsod_kgets = bsod_wrapper_gets; + kernel_debugger("So much more fun in KDL..."); + + return B_OK; +} + +device_hooks khangman_hooks={ + (device_open_hook)khangman_open, + khangman_close, + (device_free_hook)khangman_free, + NULL, + (device_read_hook)khangman_read, + khangman_write, + NULL, + NULL, + NULL, + NULL +}; + +device_hooks *find_device(const char *name) { + (void)name; + return &khangman_hooks; +} + + + +#else + +void kdl_trip(void) +{ + int fd; + fd = open("/dev/misc/hangman", O_WRONLY); + if (fd < B_OK) { + puts("hey, you're pissing me off, no /dev/"DEV_ENTRY" !!!"); + system("/bin/alert --stop 'It would work better with the hangman driver enabled...\nyou really deserves a forced reboot :P'"); + return; + } + write(fd, "hangme!", 7); + close(fd); +} + +int main(int argc, char *argv) +{ + int score; /* how many correct guesses ? */ + /* init */ + if (init_words(FORTUNE_FILE) < B_OK) { + fprintf(stderr, "error reading fortune file\n"); + return 1; + } + score = play_hangman(); +PRINTF("score %d\n", score); + if (score > (MAX_CACHED_WORDS - MAX_FAILS_BEFORE_BSOD)) { + PRINTF("Congrats !\n"); + } + if (score < (MAX_CACHED_WORDS - MAX_FAILS_BEFORE_BSOD)) { + /* too many fails... gonna kick :p */ + kdl_trip(); + } + return 0; +} + + + +#endif