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