1 #ifdef _KERNEL_MODE 2 # include <Drivers.h> 3 # include <KernelExport.h> 4 # include <module.h> 5 # include <debug.h> 6 #endif 7 8 #include <directories.h> 9 #include <OS.h> 10 #include <image.h> 11 #include <ctype.h> 12 #include <fcntl.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <sys/stat.h> 17 18 /* as driver or module */ 19 //#define AS_DRIVER 1 20 21 /* do we reboot on loose ? */ 22 //#define FAIL_IN_BSOD_CAUSE_REBOOT 1 23 24 /* shortcut to be able to exit (and take a screenshot) */ 25 #define CAN_EXIT_ON_DASH 26 27 #define MAX_FAILS_BEFORE_BSOD 0 28 29 #ifdef __HAIKU__ 30 # define FORTUNE_FILE kSystemDataDirectory "/fortunes/Fortunes" 31 #else 32 # define FORTUNE_FILE "/etc/fortunes/default" 33 #endif 34 35 #define KCMD_HELP "A funny KDL hangman game :-)" 36 37 #define DEV_ENTRY "misc/hangman" 38 39 #define KERNEL_IMAGE_ID 1 40 41 #define MIN_LETTERS 3 42 #define MAX_LETTERS 10 43 44 #define MAX_CACHED_WORDS 5 45 46 char words[MAX_CACHED_WORDS][MAX_LETTERS+1]; 47 48 #ifndef __HAIKU__ 49 50 /* design ripped off from http://www.latms.berkeley.k12.ca.us/perl/node30.html :) */ 51 static char hungman[] = \ 52 " ____ \n" \ 53 " | | \n" \ 54 " | %c \n" \ 55 " | %c%c%c \n" \ 56 " | %c %c \n" \ 57 " | \n"; 58 59 #else 60 61 /* some colors */ 62 static char hungman_ansi[] = \ 63 " ____ \n" \ 64 " | | \n" \ 65 " | \033[36m%c\033[0m \n" \ 66 " | \033[35m%c%c%c\033[0m \n" \ 67 " | \033[35m%c %c\033[0m \n" \ 68 " | \n"; 69 70 #endif 71 72 // for gets, 73 #define BIGBUFFSZ 128 74 char bigbuffer[BIGBUFFSZ]; 75 76 #define BIT_FROM_LETTER(l) (0x1 << (l - 'a')) 77 78 status_t init_words(char *from); 79 status_t init_words_from_threadnames(void); 80 void print_hangman(int fails); 81 void display_word(int current, uint32 tried_letters); 82 int play_hangman(void); 83 int kdlhangman(int argc, char **argv); 84 85 #ifdef _KERNEL_MODE 86 87 # ifdef __HAIKU__ 88 extern int kgets(char *buf, int len); 89 # define PRINTF kprintf 90 # define GETS(a) ({int l; kprintf("hangman> "); l = kgets(a, sizeof(a)); l?a:NULL;}) 91 # define HIDDEN_LETTER '_' 92 # define HUNGMAN hungman_ansi 93 # else 94 /* BeOS R5 version, needs some R5 kernel privates... */ 95 /* the kernel pointer to the bsod_gets */ 96 static char *(*bsod_gets)(char *, char *, int); 97 extern char *(*bsod_kgets)(char *, char *, int); 98 //extern char *bsod_gets(char *); 99 /* saved here before panic()ing */ 100 char *(*bsod_saved_kgets)(char *, char *, int); 101 # define PRINTF kprintf 102 # define GETS(a) ((*bsod_kgets)?(*bsod_kgets):(*bsod_gets))("hangman> ", a, sizeof(a)) 103 # define HIDDEN_LETTER '_' 104 # define HUNGMAN hungman 105 # endif 106 #else 107 /* userland version */ 108 # define PRINTF printf 109 # define GETS(a) gets(a) 110 # define dprintf printf 111 # define HIDDEN_LETTER '.' 112 # define HUNGMAN hungman_ansi 113 #endif /* !_KERNEL_MODE */ 114 115 116 status_t 117 init_words(char *from) 118 { 119 int fd; 120 size_t sz, got, beg, end, i; 121 int current; 122 struct stat st; 123 124 memset((void *)words, 0, sizeof(words)); 125 fd = open(from, O_RDONLY); 126 if (fd < B_OK) 127 return fd; 128 /* lseek() seems to always return 0 from the kernel ??? */ 129 if (fstat(fd, &st)) { 130 close(fd); 131 return B_ERROR; 132 } 133 sz = (size_t)st.st_size; 134 // sz = (size_t)lseek(fd, 0, SEEK_END); 135 // dprintf("khangman: lseek(): %ld\n", sz); 136 if (sz < 30) { 137 dprintf("hangman: fortune file too small\n"); 138 return B_ERROR; 139 } 140 // lseek(fd, 0, SEEK_SET); 141 //srand((unsigned int)(system_time() + (system_time() >> 32) + find_thread(NULL))); 142 srand((unsigned int)(system_time() & 0x0ffffffff)); 143 for (current = 0; current < MAX_CACHED_WORDS; current++) { 144 off_t offset = (rand() % (sz - MAX_LETTERS)); 145 // dprintf("current %d, offset %ld\n", current, (long)offset); 146 lseek(fd, offset, SEEK_SET); 147 got = read(fd, bigbuffer, BIGBUFFSZ - 2); 148 // dprintf("--------------buff(%d):\n%20s\n", current, bigbuffer); 149 for (beg = 0; beg < got && isalpha(bigbuffer[beg]); beg++); 150 for (; beg < got && !isalpha(bigbuffer[beg]); beg++); 151 if (beg + 1 < got && isalpha(bigbuffer[beg])) { 152 for (end = beg; end < got && isalpha(bigbuffer[end]); end++); 153 if (end < got && !isalpha(bigbuffer[end]) && beg + MIN_LETTERS < end) { 154 /* got one */ 155 /* tolower */ 156 for (i = beg; i < end; i++) 157 bigbuffer[i] = tolower(bigbuffer[i]); 158 strncpy(&(words[current][0]), &(bigbuffer[beg]), end - beg); 159 } else 160 current--; 161 } else 162 current--; 163 } 164 close(fd); 165 /* 166 for (current = 0; current < MAX_CACHED_WORDS; current++) 167 dprintf("%s\n", words[current]); 168 */ 169 return B_OK; 170 } 171 172 173 status_t 174 init_words_from_threadnames(void) 175 { 176 size_t sz, got, beg, end, i; 177 int current; 178 thread_info ti; 179 180 memset((void *)words, 0, sizeof(words)); 181 srand((unsigned int)(system_time() & 0x0ffffffff)); 182 for (current = 0; current < MAX_CACHED_WORDS; ) { 183 int offset; 184 char *p; 185 if (get_thread_info(rand() % 200, &ti) != B_OK) 186 continue; 187 sz = strnlen(ti.name, B_OS_NAME_LENGTH); 188 if (sz <= MIN_LETTERS) 189 continue; 190 offset = (rand() % (sz - MIN_LETTERS)); 191 //dprintf("thread '%-.32s' + %d\n", ti.name, offset); 192 p = ti.name + offset; 193 got = sz - offset; 194 for (beg = 0; beg < got && isalpha(p[beg]); beg++); 195 for (; beg < got && !isalpha(p[beg]); beg++); 196 if (beg + 1 < got && isalpha(p[beg])) { 197 for (end = beg; end < got && isalpha(p[end]); end++); 198 if (end < got && !isalpha(p[end]) && beg + MIN_LETTERS < end) { 199 /* got one */ 200 /* tolower */ 201 for (i = beg; i < end; i++) 202 p[i] = tolower(p[i]); 203 strncpy(&(words[current][0]), &(p[beg]), end - beg); 204 } else 205 continue; 206 } else 207 continue; 208 current++; 209 } 210 /* 211 for (current = 0; current < MAX_CACHED_WORDS; current++) 212 dprintf("%s\n", words[current]); 213 */ 214 return B_OK; 215 } 216 217 218 void 219 print_hangman(int fails) 220 { 221 PRINTF(HUNGMAN, 222 (fails > 0)?'O':' ', 223 (fails > 2)?'/':' ', 224 (fails > 1)?'|':' ', 225 (fails > 3)?'\\':' ', 226 (fails > 4)?'/':' ', 227 (fails > 5)?'\\':' '); 228 } 229 230 231 void 232 display_word(int current, uint32 tried_letters) 233 { 234 int i = 0; 235 PRINTF("word> "); 236 while (words[current][i]) { 237 PRINTF("%c", (BIT_FROM_LETTER(words[current][i]) & tried_letters)?(words[current][i]):HIDDEN_LETTER); 238 i++; 239 } 240 PRINTF("\n"); 241 } 242 243 int 244 play_hangman(void) 245 { 246 int current; 247 int score = 0; 248 int bad_guesses; 249 uint32 tried_letters; 250 char *str; 251 char try; 252 int gotit, gotone; 253 254 for (current = 0; current < MAX_CACHED_WORDS; current++) { 255 tried_letters = 0; 256 gotit = 0; 257 for (bad_guesses = 0; bad_guesses < 6; bad_guesses++) { 258 do { 259 gotit = 0; 260 gotone = 1; 261 display_word(current, tried_letters); 262 str = GETS(bigbuffer); 263 if (!str) { 264 str = bigbuffer; 265 PRINTF("buffer:%s\n", str); 266 } 267 #ifdef CAN_EXIT_ON_DASH 268 if (str[0] == '-') /* emergency exit */ 269 return 0; 270 #endif 271 if (!isalpha(str[0])) { 272 PRINTF("not a letter\n"); 273 } else { 274 try = tolower(str[0]); 275 if (BIT_FROM_LETTER(try) & tried_letters) { 276 PRINTF("%c already tried\n", try); 277 } else { 278 // REUSE 279 str = words[current]; 280 gotit = 1; 281 gotone = 0; 282 tried_letters |= BIT_FROM_LETTER(try); 283 while (*str) { 284 if (!(BIT_FROM_LETTER(*str) & tried_letters)) 285 gotit=0; 286 if (try == *str) 287 gotone = 1; 288 str++; 289 } 290 } 291 } 292 //PRINTF("gotone:%d, gotit:%d, tried_letters:%08lx\n", gotone, gotit, tried_letters); 293 } while(tried_letters != 0x03ffffff && !gotit && gotone); 294 if (gotit) 295 break; 296 print_hangman(bad_guesses+1); 297 } 298 if (bad_guesses < 6) { 299 display_word(current, 0x03ffffff); 300 if (strlen(words[current]) < 5) 301 PRINTF("That was easy :-P\n"); 302 else if (strlen(words[current]) < 7) 303 PRINTF("Good one !\n"); 304 else 305 PRINTF("You got this hard one ! :-)\n"); 306 score ++; 307 } 308 /**/ 309 else return score; 310 /**/ 311 } 312 return score; 313 } 314 315 316 #ifdef _KERNEL_MODE /* driver parts */ 317 318 319 #ifndef __HAIKU__ /* BeOS intimacy revealed */ 320 //char *bsod_wrapper_gets(char *p, int len) 321 //char *bsod_wrapper_gets(int len, char *p) 322 char * 323 bsod_wrapper_gets(char *prompt, char *p, int len) 324 { 325 /* fall back to the normal gets() */ 326 bsod_kgets = bsod_saved_kgets; 327 // if (!bsod_kgets) 328 // bsod_kgets = bsod_gets; 329 /* and fake some typing */ 330 strcpy(p, fake_typed); 331 return p; 332 } 333 #else 334 335 #endif 336 337 338 int 339 kdlhangman(int argc, char **argv) 340 { 341 int score; 342 343 if (argc > 1 && strcmp(argv[1], "--help") == 0) { 344 PRINTF("%s\n", KCMD_HELP); 345 return 0; 346 } 347 348 score = play_hangman(); 349 PRINTF("score %d\n", score); 350 if (score > (MAX_CACHED_WORDS - MAX_FAILS_BEFORE_BSOD)) { 351 PRINTF("Congrats !\n"); 352 } 353 if (score < (MAX_CACHED_WORDS - MAX_FAILS_BEFORE_BSOD)) { 354 #ifdef FAIL_IN_BSOD_CAUSE_REBOOT 355 PRINTF("Hmmm, sorry, need to trash your hdd... Ok, just a reboot then\n"); 356 fake_typed = "reboot"; 357 bsod_kgets = bsod_wrapper_gets; 358 return 1; 359 #else 360 PRINTF("Hmmm, sorry, need to trash your hdd... Well, I'll be nice this time\n"); 361 #endif 362 } 363 //return B_KDEBUG_CONT; 364 return B_KDEBUG_QUIT; 365 } 366 367 368 # ifdef AS_DRIVER 369 370 typedef struct { 371 int dummy; 372 } cookie_t; 373 374 const char * device_names[]={DEV_ENTRY, NULL}; 375 376 377 status_t 378 init_hardware(void) { 379 return B_OK; 380 } 381 382 383 status_t 384 init_driver(void) 385 { 386 status_t err; 387 388 err = init_words(FORTUNE_FILE); 389 if (err < B_OK) { 390 dprintf("hangman: error reading fortune file: %s\n", strerror(err)); 391 return B_ERROR; 392 } 393 get_image_symbol(KERNEL_IMAGE_ID, "bsod_gets", B_SYMBOL_TYPE_ANY, (void **)&bsod_gets); 394 add_debugger_command("kdlhangman", kdlhangman, KCMD_HELP); 395 return B_OK; 396 } 397 398 399 void 400 uninit_driver(void) 401 { 402 remove_debugger_command("kdlhangman", kdlhangman); 403 } 404 405 406 const char ** 407 publish_devices() 408 { 409 return device_names; 410 } 411 412 413 status_t 414 khangman_open(const char *name, uint32 flags, cookie_t **cookie) 415 { 416 (void)name; (void)flags; 417 *cookie = (void*)malloc(sizeof(cookie_t)); 418 if (*cookie == NULL) { 419 dprintf("khangman_open : error allocating cookie\n"); 420 goto err0; 421 } 422 memset(*cookie, 0, sizeof(cookie_t)); 423 return B_OK; 424 err0: 425 return B_ERROR; 426 } 427 428 429 status_t 430 khangman_close(void *cookie) 431 { 432 (void)cookie; 433 return B_OK; 434 } 435 436 437 status_t 438 khangman_free(cookie_t *cookie) 439 { 440 free(cookie); 441 return B_OK; 442 } 443 444 445 status_t 446 khangman_read(cookie_t *cookie, off_t position, void *data, size_t *numbytes) 447 { 448 *numbytes = 0; 449 return B_NOT_ALLOWED; 450 } 451 452 453 status_t 454 khangman_write(void *cookie, off_t position, const void *data, size_t *numbytes) 455 { 456 (void)cookie; (void)position; (void)data; (void)numbytes; 457 //*numbytes = 0; 458 /* here we get to kdlhangman */ 459 fake_typed = "kdlhangman"; 460 bsod_saved_kgets = bsod_kgets; 461 bsod_kgets = bsod_wrapper_gets; 462 kernel_debugger("So much more fun in KDL..."); 463 464 return B_OK; 465 } 466 467 468 device_hooks khangman_hooks={ 469 (device_open_hook)khangman_open, 470 khangman_close, 471 (device_free_hook)khangman_free, 472 NULL, 473 (device_read_hook)khangman_read, 474 khangman_write, 475 NULL, 476 NULL, 477 NULL, 478 NULL 479 }; 480 481 482 device_hooks * 483 find_device(const char *name) 484 { 485 (void)name; 486 return &khangman_hooks; 487 } 488 489 490 # else /* as module */ 491 492 493 static status_t 494 std_ops(int32 op, ...) 495 { 496 status_t err; 497 498 switch (op) { 499 case B_MODULE_INIT: 500 err = init_words(FORTUNE_FILE); 501 if (err < B_OK) { 502 dprintf("hangman: error reading fortune file: %s\n", 503 strerror(err)); 504 err = init_words_from_threadnames(); 505 if (err < B_OK) { 506 dprintf("hangman: error getting thread names: %s\n", 507 strerror(err)); 508 return B_ERROR; 509 } 510 } 511 add_debugger_command("kdlhangman", kdlhangman, KCMD_HELP); 512 return B_OK; 513 case B_MODULE_UNINIT: 514 remove_debugger_command("kdlhangman", kdlhangman); 515 return B_OK; 516 } 517 518 return B_ERROR; 519 } 520 521 522 static struct debugger_module_info sModuleInfo = { 523 { 524 "debugger/hangman/v1", 525 B_KEEP_LOADED, 526 &std_ops 527 }, 528 NULL, 529 NULL, 530 NULL, 531 NULL 532 }; 533 534 module_info *modules[] = { 535 (module_info *)&sModuleInfo, 536 NULL 537 }; 538 539 # endif /* AS_DRIVER */ 540 541 #else 542 543 void 544 kdl_trip(void) 545 { 546 int fd; 547 fd = open("/dev/misc/hangman", O_WRONLY); 548 if (fd < B_OK) { 549 puts("hey, you're pissing me off, no /dev/"DEV_ENTRY" !!!"); 550 system("/bin/alert --stop 'It would work better with the hangman driver enabled...\nyou really deserve a forced reboot :P'"); 551 return; 552 } 553 write(fd, "hangme!", 7); 554 close(fd); 555 } 556 557 558 int 559 main(int argc, char *argv) 560 { 561 int score; /* how many correct guesses ? */ 562 /* init */ 563 if (init_words(FORTUNE_FILE) < B_OK) { 564 fprintf(stderr, "error reading fortune file\n"); 565 return 1; 566 } 567 score = play_hangman(); 568 PRINTF("score %d\n", score); 569 if (score > (MAX_CACHED_WORDS - MAX_FAILS_BEFORE_BSOD)) { 570 PRINTF("Congrats !\n"); 571 } 572 if (score < (MAX_CACHED_WORDS - MAX_FAILS_BEFORE_BSOD)) { 573 /* too many fails... gonna kick :p */ 574 kdl_trip(); 575 } 576 return 0; 577 } 578 579 580 #endif 581