3 # include <KernelExport.h>
8 #include <directories.h>
18 /* as driver or module */
21 /* do we reboot on loose ? */
22 //#define FAIL_IN_BSOD_CAUSE_REBOOT 1
24 /* shortcut to be able to exit (and take a screenshot) */
25 #define CAN_EXIT_ON_DASH
27 #define MAX_FAILS_BEFORE_BSOD 0
30 # define FORTUNE_FILE kSystemDataDirectory "/fortunes/Fortunes"
32 # define FORTUNE_FILE "/etc/fortunes/default"
35 #define KCMD_HELP "A funny KDL hangman game :-)"
37 #define DEV_ENTRY "misc/hangman"
39 #define KERNEL_IMAGE_ID 1
42 #define MAX_LETTERS 10
44 #define MAX_CACHED_WORDS 5
46 char words
[MAX_CACHED_WORDS
][MAX_LETTERS
+1];
50 /* design ripped off from http://www.latms.berkeley.k12.ca.us/perl/node30.html :) */
51 static char hungman
[] = \
62 static char hungman_ansi
[] = \
65 " | \033[36m%c\033[0m \n" \
66 " | \033[35m%c%c%c\033[0m \n" \
67 " | \033[35m%c %c\033[0m \n" \
74 char bigbuffer
[BIGBUFFSZ
];
76 #define BIT_FROM_LETTER(l) (0x1 << (l - 'a'))
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
);
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
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
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 */
117 init_words(char *from
)
121 int current
, beg
, end
, i
;
124 memset((void *)words
, 0, sizeof(words
));
125 fd
= open(from
, O_RDONLY
);
128 /* lseek() seems to always return 0 from the kernel ??? */
129 if (fstat(fd
, &st
)) {
133 sz
= (size_t)st
.st_size
;
134 // sz = (size_t)lseek(fd, 0, SEEK_END);
135 // dprintf("khangman: lseek(): %ld\n", sz);
137 dprintf("hangman: fortune file too small\n");
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
) {
156 for (i
= beg
; i
< end
; i
++)
157 bigbuffer
[i
] = tolower(bigbuffer
[i
]);
158 strncpy(&(words
[current
][0]), &(bigbuffer
[beg
]), end
- beg
);
166 for (current = 0; current < MAX_CACHED_WORDS; current++)
167 dprintf("%s\n", words[current]);
174 init_words_from_threadnames(void)
177 int current
, beg
, end
, i
;
180 memset((void *)words
, 0, sizeof(words
));
181 srand((unsigned int)(system_time() & 0x0ffffffff));
182 for (current
= 0; current
< MAX_CACHED_WORDS
; ) {
185 if (get_thread_info(rand() % 200, &ti
) != B_OK
)
187 sz
= strnlen(ti
.name
, B_OS_NAME_LENGTH
);
188 if (sz
<= MIN_LETTERS
)
190 offset
= (rand() % (sz
- MIN_LETTERS
));
191 //dprintf("thread '%-.32s' + %d\n", ti.name, offset);
192 p
= ti
.name
+ 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
) {
201 for (i
= beg
; i
< end
; i
++)
202 p
[i
] = tolower(p
[i
]);
203 strncpy(&(words
[current
][0]), &(p
[beg
]), end
- beg
);
211 for (current = 0; current < MAX_CACHED_WORDS; current++)
212 dprintf("%s\n", words[current]);
219 print_hangman(int fails
)
225 (fails
> 3)?'\\':' ',
227 (fails
> 5)?'\\':' ');
232 display_word(int current
, uint32 tried_letters
)
236 while (words
[current
][i
]) {
237 PRINTF("%c", (BIT_FROM_LETTER(words
[current
][i
]) & tried_letters
)?(words
[current
][i
]):HIDDEN_LETTER
);
249 uint32 tried_letters
;
254 for (current
= 0; current
< MAX_CACHED_WORDS
; current
++) {
257 for (bad_guesses
= 0; bad_guesses
< 6; bad_guesses
++) {
261 display_word(current
, tried_letters
);
262 str
= GETS(bigbuffer
);
265 PRINTF("buffer:%s\n", str
);
267 #ifdef CAN_EXIT_ON_DASH
268 if (str
[0] == '-') /* emergency exit */
271 if (!isalpha(str
[0])) {
272 PRINTF("not a letter\n");
274 try = tolower(str
[0]);
275 if (BIT_FROM_LETTER(try) & tried_letters
) {
276 PRINTF("%c already tried\n", try);
279 str
= words
[current
];
282 tried_letters
|= BIT_FROM_LETTER(try);
284 if (!(BIT_FROM_LETTER(*str
) & tried_letters
))
293 //PRINTF("gotone:%d, gotit:%d, tried_letters:%08lx\n", gotone, gotit, tried_letters);
294 } while(tried_letters
!= 0x03ffffff && !gotit
&& gotone
);
297 print_hangman(bad_guesses
+1);
299 if (bad_guesses
< 6) {
300 display_word(current
, 0x03ffffff);
301 if (strlen(words
[current
]) < 5)
302 PRINTF("That was easy :-P\n");
303 else if (strlen(words
[current
]) < 7)
304 PRINTF("Good one !\n");
306 PRINTF("You got this hard one ! :-)\n");
317 #ifdef _KERNEL_MODE /* driver parts */
320 #ifndef __HAIKU__ /* BeOS intimacy revealed */
321 //char *bsod_wrapper_gets(char *p, int len)
322 //char *bsod_wrapper_gets(int len, char *p)
324 bsod_wrapper_gets(char *prompt
, char *p
, int len
)
326 /* fall back to the normal gets() */
327 bsod_kgets
= bsod_saved_kgets
;
329 // bsod_kgets = bsod_gets;
330 /* and fake some typing */
331 strcpy(p
, fake_typed
);
340 kdlhangman(int argc
, char **argv
)
344 if (argc
> 1 && strcmp(argv
[1], "--help") == 0) {
345 PRINTF("%s\n", KCMD_HELP
);
349 score
= play_hangman();
350 PRINTF("score %d\n", score
);
351 if (score
> (MAX_CACHED_WORDS
- MAX_FAILS_BEFORE_BSOD
)) {
352 PRINTF("Congrats !\n");
354 if (score
< (MAX_CACHED_WORDS
- MAX_FAILS_BEFORE_BSOD
)) {
355 #ifdef FAIL_IN_BSOD_CAUSE_REBOOT
356 PRINTF("Hmmm, sorry, need to trash your hdd... Ok, just a reboot then\n");
357 fake_typed
= "reboot";
358 bsod_kgets
= bsod_wrapper_gets
;
361 PRINTF("Hmmm, sorry, need to trash your hdd... Well, I'll be nice this time\n");
364 //return B_KDEBUG_CONT;
365 return B_KDEBUG_QUIT
;
375 const char * device_names
[]={DEV_ENTRY
, NULL
};
379 init_hardware(void) {
389 err
= init_words(FORTUNE_FILE
);
391 dprintf("hangman: error reading fortune file: %s\n", strerror(err
));
394 get_image_symbol(KERNEL_IMAGE_ID
, "bsod_gets", B_SYMBOL_TYPE_ANY
, (void **)&bsod_gets
);
395 add_debugger_command("kdlhangman", kdlhangman
, KCMD_HELP
);
403 remove_debugger_command("kdlhangman", kdlhangman
);
415 khangman_open(const char *name
, uint32 flags
, cookie_t
**cookie
)
417 (void)name
; (void)flags
;
418 *cookie
= (void*)malloc(sizeof(cookie_t
));
419 if (*cookie
== NULL
) {
420 dprintf("khangman_open : error allocating cookie\n");
423 memset(*cookie
, 0, sizeof(cookie_t
));
431 khangman_close(void *cookie
)
439 khangman_free(cookie_t
*cookie
)
447 khangman_read(cookie_t
*cookie
, off_t position
, void *data
, size_t *numbytes
)
450 return B_NOT_ALLOWED
;
455 khangman_write(void *cookie
, off_t position
, const void *data
, size_t *numbytes
)
457 (void)cookie
; (void)position
; (void)data
; (void)numbytes
;
459 /* here we get to kdlhangman */
460 fake_typed
= "kdlhangman";
461 bsod_saved_kgets
= bsod_kgets
;
462 bsod_kgets
= bsod_wrapper_gets
;
463 kernel_debugger("So much more fun in KDL...");
469 device_hooks khangman_hooks
={
470 (device_open_hook
)khangman_open
,
472 (device_free_hook
)khangman_free
,
474 (device_read_hook
)khangman_read
,
484 find_device(const char *name
)
487 return &khangman_hooks
;
491 # else /* as module */
495 std_ops(int32 op
, ...)
501 err
= init_words(FORTUNE_FILE
);
503 dprintf("hangman: error reading fortune file: %s\n",
505 err
= init_words_from_threadnames();
507 dprintf("hangman: error getting thread names: %s\n",
512 add_debugger_command("kdlhangman", kdlhangman
, KCMD_HELP
);
514 case B_MODULE_UNINIT
:
515 remove_debugger_command("kdlhangman", kdlhangman
);
523 static struct debugger_module_info sModuleInfo
= {
525 "debugger/hangman/v1",
535 module_info
*modules
[] = {
536 (module_info
*)&sModuleInfo
,
540 # endif /* AS_DRIVER */
548 fd
= open("/dev/misc/hangman", O_WRONLY
);
550 puts("hey, you're pissing me off, no /dev/"DEV_ENTRY
" !!!");
551 system("/bin/alert --stop 'It would work better with the hangman driver enabled...\nyou really deserve a forced reboot :P'");
554 write(fd
, "hangme!", 7);
560 main(int argc
, char *argv
)
562 int score
; /* how many correct guesses ? */
564 if (init_words(FORTUNE_FILE
) < B_OK
) {
565 fprintf(stderr
, "error reading fortune file\n");
568 score
= play_hangman();
569 PRINTF("score %d\n", score
);
570 if (score
> (MAX_CACHED_WORDS
- MAX_FAILS_BEFORE_BSOD
)) {
571 PRINTF("Congrats !\n");
573 if (score
< (MAX_CACHED_WORDS
- MAX_FAILS_BEFORE_BSOD
)) {
574 /* too many fails... gonna kick :p */