Decoded: Sopwith (1984) by David L. Clark
Source file: BMBLIB.C
Beginner friendly, line-by-line code walkthrough by MaiZure

BMBLIB.C manages command line argument reading and registers. Code quality is
lower than most files in this archive. It was clearly written by multiple period
over different times with different expectations

Original code:
http://davidlclark.com/page/sopwith-source-code

Original code with line numbers
http://www.maizure.org/projects/decoded-sopwith/BMBLIB_linenum.txt


1     COMMENT
2     COMMENT
3     BLANK
4     COMMENT
5     COMMENT
6     COMMENT
7     COMMENT
8     COMMENT
9     COMMENT
10    COMMENT
11    COMMENT
12    COMMENT
13    COMMENT
14    BLANK
15    COMMENT
16    COMMENT
17    COMMENT
18    COMMENT
19    BLANK
20    BLANK
21    Include OS header (dos.h)
22    Include main game header (dos.h)
23    Include C standard library header (string.h)
24    BLANK
25    BLANK
26    Set the system global to DOS
27    BLANK
28    BLANK
29    BLANK
30    BLANK
31    BLANK
32    COMMENT
33    COMMENT
34    COMMENT
35    BLANK
36    BLANK
37    BLANK
38    BLANK

GET SOPWITH LOADTIME ARGUMENTS FROM THE CONSOLE
This is a classic example of a programmer "gettin' stuff done" hoping that it
will work like magic (it does) and that no one will ever look at this code again.
Variadic function argument processing 101 in 1984! If this seems complicated,
part of the reason is that this function can do a lot more work than is was
finally used for in the final build of Sopwith.

39    Declares getflags with 4 arguments
40    Argument 1 is the standard argument count from the command line
41    Argument 2 is the standard argument input vector from the command line
42    Argument 3 is a string that specifies the format of argument 4
43    Argument 4 is a vector of pointers for each command line flag in Sopwith
44    BLOCK START - getflags, processes custom command line arguments
45    Declares pointer to the input arguments and a pointer to an end point
46    Declares three iterators
47    Declares a character pointer to be used within the input string
48    Declares pointer to the command line switch we're interested in
49    Declares pointer to be used within the input string
50    Declares a variable pointer that scans at the argument level
51    Declares a pointers to our variable pointer (yes this is really a ***)
52    Declares a pointer to the character within the format
53    Declare initial return status to 0 (FAIL)
54    Declares a status flag
55    BLANK
56    Points our local argument pointer to the input argument vector
57    Points our iterator to the argument counter
58    Skip the program's name on the command line (always arg0)
59    BLANK
60    BLOCK START - While arguments remain...
61    Point to the first character of the argument
62    If it's not a switch, then we're done..break to next line on line 137
63    BLOCK START - EOL check, check 2nd character for another '-'
64    Increment to the next
65    Reduce the count
66    End loop on EOL
67    BLOCK END - EOL Check
68    BLANK
69    Label for handling a single switch
70    Set the flag variable to the switch reference
71    Point a variable to the beginning of the variadic fields vector
72    BLANK
73    BLOCK START - Loop on the format string
74    Reset offset iterator to 0
75    Check the length of the switch (should always be 1 in this build)
76    BLANK
77    COMMENT
78    BLANK
79    If there is a match or a special character then...(no specials now)
80    We found our desired position in the format string, so break loop
81    BLANK
82    Increment format a string based on determined size
83    Plus one more byte to next start
84    BLOCK END - Loop on the format string
85    BLANK
86    BLOCK START - Unexpected format, no input or end of format string
87    BLOCK START - Find the offset (position) of the end of string
88    Go to the last character...
89    and overwrites end of character with \0
90    BLOCK START - No final character, then we're at the end
91    Set return status to 1 (SUCCESS)
92    Jump to the end of the procedure
93    BLOCK END - No final character
94    BLOCK END - Find offset
95    Something really went off the rails...end process
96    BLOCK END - Unexpected format
97    BLANK
98    Set the switch to the matching format pointer offset
99    Increment the argument pointer as well
100   The pointer's pointer!
101   Still need to resolve the switch
102   BLOCK START - Check for more, Check if we're looking beyond the argument
      and between switches (we should be if all is well)
103   BLOCK START - Argument count check, if there is more...
104   Advance through the argument list
105   Count down
106   We should now be pointing at next
107   BLOCK END - Argument count check
108   BLOCK END - Check for more
109   BLANK
110   SWITCH - Check switch value (most are deprecated in this build)
111   Case # -- append (not used)
112   Reset the offset to 0
113   BLOCK START - More to read
114   Convert the string value to a long integer (end check)
115   The offset is the difference between beginning and end
116   Set arg pointer to the end (next arg)
117   BLOCK END - More to read
118   BLOCK START - No more to append
119   If we're already looking at the next argument...
120   Move back
121   Add back to count
122   End if
123   Somehow there's a flag without a valid input
124   BLOCK END - No more to append
125   End case for #
126   BLANK
127   Case for *: unused in this version
128   End case for *
129   BLANK
130   Case & - this is the only one used. Asset the flag in memory
131   End case for &
132   END SWITCH
133   BLANK
134   If there is more expected and the pointer is valid go back to line 69
135   Next argument
136   BLOCK END - While arguments remain...
137   BLANK
138   Goto label for end of arugment processing
139   Reset input vector pointer to end (or failure point) of arguments
140   Set argument count to 0 (Attempts to make this reentrant?)
141   Return status, success or fail
142   BLOCK END - getflags, processes custom command line arguments
143   BLANK
144   BLANK

INTERFACE FUNCTIONS BETWEEN DOS/STRING AND SOPWITH CODE
The following half-dozen functions translate Sopwith code in to respective OS
and library functions. These use ANSI C formats so I suspect they were written
later for portability.

145   Declares helper function with 2 arguments, a string and a position
146   BLOCK START - index, returns valid chars at position in a string or NULL
147   Declare a local char
148   BLANK
149   Returns the character or NULL
150   BLOCK END - index
151   BLANK
152   BLANK
153   Defines inportb that takes an unsigned int port number
154   BLOCK START - inportb, reads a byte from a port
155   Returns the byte value read from the port as an (intended) 2-byte int
156   BLOCK END - inportb
157   BLANK
158   BLANK
159   Defines movblock with 5 arguments: source offset and segment..
160   ..Destination offset and segment...
161   ..and the size to move
162   BLOCK START - movblock, moves a block of memory across segments (FAR)
163   Call movedata with the input arguments
164   BLOCK END - movblock
165   BLANK
166   BLANK
167   BLANK
168   Defines movmem with 3 arguments, *source, *destination, and size to move
169   BLOCK START - movmem, moves a block of memory from src to dest (NEAR)
170   Calls memmove to perform the move
171   BLOCK END - movmem
172   BLANK
173   BLANK
174   BLANK
175   Defines outportb with two arguments, a target port and a data byte
176   BLOCK START - outportb, writes input data to the input port
177   Returns success or failure of writing input data to the input port
178   BLOCK END - outportb
179   BLANK
180   BLANK
181   Defines setmem with 3 arguments: mem pointer, size, and value
182   BLOCK START - setmem, sets a block of memory to the input value
183   Calls memset with the same arguments to set memory to the value
184   BLOCK END - setmem
185   BLANK
186   BLANK

WRAPPER FOR INVOKING DOS API INTERRUPTS IN C
187   Defines sysint with 3 arguments: int number, input and output reg values
188   BLOCK START - sysint, performs x86/DOS API interrupts
189   Declares a REGS union from DOS.H. Format varies by implementation, but
      this generally includes DI, SI, BP, FLAGS, BX, CX, DX, and AX
190   Declares a SREGS structure for the six segment registers
191   Declares a return value
192   BLANK
193   Sets the register state for AX based on input value
194   Sets the register state for BX based on input value
195   Sets the register state for CX based on input value
196   Sets the register state for DX based on input value
197   Sets the register state for DS based on input value
198   Invokes the input interrupt number and register values
199   Reads the output register values for AX
200   Reads the output register values for BX
201   Reads the output register values for CX
202   Reads the output register values for DX
203   Reads the output register values for DS
204   Returns the interrupt result (usually AX but depends on int number)
205   BLOCK END - sysint
206   BLANK
207   BLANK

WRAPPER FOR INVOKING SOFTWARE INTERRUPTS IN C
208   Defines sysint21 with 2 arguments: input register values and output
209   BLOCK START systint21, invokes DOS software interrupt
210   Declares a REGS union from DOS.H. Format varies, but this generally includes
      DI, SI, BP, FLAGS, BX, CX, DX, and AX
211   Declares a SREGS structure for the six segment registers
212   Declares a return value variable that usually matches AX
213   BLANK
214   Sets the register state for AX based on input value
215   Sets the register state for BX based on input value
216   Sets the register state for CX based on input value
217   Sets the register state for DX based on input value
218   Sets the register state for DS based on input value
219   Invokes interrupt 21 with features based on AH value in AX
220   Reads the output register values for AX
221   Reads the output register values for BX
222   Reads the output register values for CX
223   Reads the output register values for DX
224   Reads the output register values for DS
225   Returns the interrupt result (usually matches AX depending on call)
226   BLOCK END - sysint21
227   EOF