--- /dev/null
+! Self-modifying reproducing Z-code.
+!
+! Generates random junk and sees how the interpreter behaves. If it's clever
+! it shouldn't die except for @quit and stack overflow.
+!
+! inform \$MAX_STATIC_DATA=40000 crashme.inf
+!
+! Written by Evin Robertson 1999. Placed in public domain.
+
+Array randstuff -> 32767;
+Array checkfix -> 257;
+
+Global replay = 0;
+
+Array filename string "CRASHME.MEM";
+
+#iftrue (#version_number <= 3);
+Constant Granularity = 2;
+Constant FileMult = 2;
+#endif;
+
+#iftrue (#version_number >= 4 && #version_number <= 5);
+Constant Granularity = 4;
+Constant FileMult = 4;
+#endif;
+
+#iftrue (#version_number >= 6 && #version_number <= 7);
+Constant Granularity = 4;
+Constant FileMult = 8;
+#endif;
+
+#iftrue (#version_number == 8);
+Constant Granularity = 8;
+Constant FileMult = 8;
+#endif;
+
+
+[ Main i a g r c l t game_size checksum;
+ game_size = FileMult * (0-->13); ! game size
+
+ r = randstuff % Granularity;
+ if(r)
+ r = Granularity - r;
+
+ a = randstuff + r;
+ c = a / Granularity;
+ l = 32767 - r;
+
+ if(replay) {
+ print "You are running crashme's output. This will repeat the test run which generated this output.^";
+ } else {
+ print "This program generates random Z-code which is run to test the robustness of your Z-machine interpreter. Most likely this will infinite loop. Do not run if you can't kill your interpreter when it is tightly looping.^Will attempt to write CRASHME.MEM which should be a valid Z-machine game which contains the same code that will be run.^";
+ }
+ print "Press 'q' to abort.^";
+ @read_char 1 -> i;
+ if(i == 'Q' or 'q')
+ @quit;
+
+ replay++;
+
+
+ if(replay == 1) {
+ for(i=0: i < l: i++)
+ a->i = random(256) - 1;
+ for(i=0: i < 13: i++)
+ a->i = (emptyfunc * Granularity)->i;
+
+ checksum = 0;
+ for(i=0: i < l: i++)
+ checksum = checksum + a->i;
+ g = 0-->6; ! globals location
+ for(i=0: i < 480: i++)
+ checksum = checksum + g->i;
+
+ for(i=0: i < 257: i++) {
+ if(-255 <= checksum && checksum <= 0) {
+ checkfix->i = -checksum;
+ break;
+ } else {
+ checkfix->i = 255;
+ checksum = checksum + 255;
+ }
+ }
+ #IFV5; @save 0 game_size filename -> t; #ENDIF;
+ }
+
+ ! reduce the chances that it'll attempt to write over the same file
+ for(i=0: i <= 11: i++)
+ filename->i = 0;
+
+ @call_vn c;
+ print "^Done.^";
+];
+
+[ emptyfunc;
+ print "starting...^";
+];