Decoded: Rogue (1980) by Toy, Arnold, Wichman DOS version (1983) by Mel Sibony and Jon Lane Source file: CROOT.C Beginner friendly, line-by-line code walkthrough by MaiZure CROOT.C is a modified runtime loader included with Aztec C. This is technically not part of the game, but it is included in the DOS source distribution and may be interesting for code archaeologists, so I'll go through it. Study this along with BEGIN.ASM to understand how a DOS program is launched. Original code: https://britzl.github.io/roguearchive/ Original code with line numbers http://www.maizure.org/projects/decoded-rogue/CROOT_linenum.txt 1 COMMENT 2 COMMENT 3 COMMENT 4 BLANK 5 Declares a global pointer for the user argument vector 6 Declares a global counter for the argument vector length 7 BLANK 8 Declares noper with no arguments 9 BLOCK START - noper, a quick NOP function in C 10 Returns nothing -- probably still incurs function call overhead since Aztec C in 1983 wasn't known for aggressive optimizations. This function wouldn't be run anyway since it's only used as a function pointer placeholder that is remapped at runtime. 11 BLOCK END - noper 12 BLANK 13 Sets up a cls_ function pointer and temporarily maps it to the nop above 14 BLANK SET UP GAME ENTRY (CROOT) This function is part of the 'true' entry point for Rogue and is called from BEGIN.ASM. BEGIN.ASM takes the process argument pointers from the DOS PSP and puts them on the stack. This function moves them to the heap. Once the environment is properly set up, the game main() takes over and never returns. 15 Declares Croot with two arguments 16 Argument 1 is a pointer to a character (Arg2 is argument number/index) 17 BLOCK START - Croot, sets up process arguments on the heap for the game 18 Declares a pointer to our argument pointer 19 Declares a function pointer for sbrk - linked to SBRK.ASM 20 BLANK 21 Allocates space for two argument vector pointers (the first is unused) 22 Sets the first argument to null 23 Set the temporary pointer to the first argument 24 BLOCK START - argument processing loop 25 While the character we're looking at is blank or a tab... 26 Skip to the next character 27 If we've hit the end of the arguments... 28 End the processing 29 BLOCK START - Process a new argument (cp sits at the start of an arg) 30 Copy and increment the pointer to the argument base 31 Add to the argument counter 32 Attempt to allocate a byte on the heap. If a non-zero return (a failure) 33 Output a 14 byte error to stderr 34 Exit process with errno 200 35 End check for memory allocation failure 36 Loop to find the base of the next argument 37 If a space or tab is detected, then we're at the end of the arg list 38 Set the pointer to 0, which would cause the top level loop to break 39 Break out of this inner loop to prevent incrementing pointer again 40 End check for space or tab 41 BLOCK END - process a new argument 42 BLOCK END - argument processing loop 43 Clear the temporary pointer 44 Run the game! 45 Exit success 46 BLOCK END - Croot 47 BLANK EXIT GAME 48 Define exit with one argument (exit value) 49 BLOCK START - exit, wraps the DOS exit syscall and unloads the game 50 Run the function pointer previously defined as NOP, but should have been redefined if the game successfully runs. 51 Check if we're in debug mode 52 Run ComOff (not defined in this source code -- maybe part of Aztec C?) 53 End 54 Undo game environment and return to a state that DOS can pick up 55 Invoke the actual DOS API syscall to exit process 56 BLOCK END - exit 57 BLANK 58 EOF˙