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
init_words(char * from)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
init_words_from_threadnames(void)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
print_hangman(int fails)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
display_word(int current,uint32 tried_letters)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
play_hangman(void)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 *
bsod_wrapper_gets(char * prompt,char * p,int len)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
kdlhangman(int argc,char ** argv)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
init_hardware(void)378 init_hardware(void) {
379 return B_OK;
380 }
381
382
383 status_t
init_driver(void)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
uninit_driver(void)400 uninit_driver(void)
401 {
402 remove_debugger_command("kdlhangman", kdlhangman);
403 }
404
405
406 const char **
publish_devices()407 publish_devices()
408 {
409 return device_names;
410 }
411
412
413 status_t
khangman_open(const char * name,uint32 flags,cookie_t ** cookie)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
khangman_close(void * cookie)430 khangman_close(void *cookie)
431 {
432 (void)cookie;
433 return B_OK;
434 }
435
436
437 status_t
khangman_free(cookie_t * cookie)438 khangman_free(cookie_t *cookie)
439 {
440 free(cookie);
441 return B_OK;
442 }
443
444
445 status_t
khangman_read(cookie_t * cookie,off_t position,void * data,size_t * numbytes)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
khangman_write(void * cookie,off_t position,const void * data,size_t * numbytes)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 *
find_device(const char * name)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
std_ops(int32 op,...)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
kdl_trip(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
main(int argc,char * argv)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