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