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