ARX.O, RARX.O, PARX.O, QARX.O - C runtime startup modules These do various things: most of them parse the command line into separate args, all of them load the stack pointer to the top of free memory, and set up argc & argv for procedure main. They then call main, and on return exit to the system (or in the case of PARX.O execute the next program in the pipe). In addition, they all define an external label exit which can be jumped to in order to terminate the program with extreme prejudice. The difference between them is how clever they are. In order of increasing intelligence we have: QARX.O (Q for quick): ignores the command line args - does no argc/argv setup at all. ARX.O parse the command line into arguments, argv is set up from these, however the program name is not available as argv[0]. argc is set as needed. RARX.O (R for redirection): parse the command line, but if it finds arguments with a leading < > or >> these don't reach argv, instead they are used to do redirection of standard input & output just like UNIX does it, to give an example, A>PROG normally PROG would take standard input from the keyboard, and send standard output to the screen, however if it were invoked as follows: A>PROG FILE2 standard input would read from FILE1, and FILE2 would be created to hold the standard output, in addition A>PROG >>FILE3 will send output to FILE3, but if the file exists it is opened for append rather than being created anew. PARX.O (P for pipe): does all that RARX.O does, it also will look for | chars in the command line, and do pipes like UNIX does, so PROG | PROG1 | PROG2 will work. A few words of warning are in order here: because the Z80 is not the worlds biggest CPU, I haven't figured out a way to do multi-tasking (but I'm working on it (?!?!)). As a result of this, each program in the pipe must finish before the next one can start, requiring that all the information passing from one to the next be stored on disk: so if you do a CAT *.Z | ... you may find yourself in a lot of trouble when CAT runs out of room to save all the stuff that was in *.Z. It goes without saying that all programs in the pipe EXCEPT THE LAST must have been linked with PARX, and the last needs either PARX or RARX: the reason being that in the first example, PROG1 would be invoked with a command line looking like: PROG1 PROGRAM ARG1 ARG2 argv (word) ----> argv[0] - argv[1] - argv[2] argc is 3 - 3 arguments [argument | | | [argument count max] vector] | | v | | second arg string | v | first arg string v normally program name, not available under CP/M The way I set these up is to use the command line tail saved by CP/M at location 0x80 - as an example: A>PROGRAM ARG1 ARG2 would leave 0080: 0A 20 41 52 47 31 20 41-52 47 32 00 00 00 00 00 . ARG1 ARG2..... in memory. After ARX has done its stuff, the following will be elsewhere in memory: high in memory argv[3] NULL pointer (i.e. zero word) argv[2] 0x87 - address of ARG2 string (terminated by zero byte) argv[1] 0x82 - address of ARG1 string argv[0] pointer to a zero byte (not the NULL pointer) lower in memory and on the stack will be found: start of stack (high in memory) argv address of argv[0] whereever it is in memory argc 3 in this case - three valid arguments return address return as created by the call to main end of stack (lower in memory) Usually spaces (and some other chars) can be a problem to get into command line arguments, so the following 'escape' sequences are recognised - using backslash '\' as the lead in character: '\ ' backslash space - gets converted to a space, allow spaces to get into arguments, usually spaces are used to separate arguments '\t' backslash 't' - gets converted to a tab '\n' backslash 'n' - gets converted to a linefeed (newline) '\r' backslash 'r' - gets converted to a carriage return '\b' backslash 'b' - gets converted to a backspace '\f' backslash 'f' - gets converted to a formfeed '\\' backslash backslash - gets converted to a single backslash '\e' backslash 'e' - gets converted to an escape (may not be implemented yet)