ZCPR33 PROGRAMMING NOTES ======================== Note Number: 002 Author: Jay Sage Date: June 6, 1987 The Design of Shells Under ZCPR33 The ZCPR33 command processor follows a very clear and strict hierarchy for acquiring new commands. It goes as shown below, with step 1 having the highest priority and step 5 the lowest. The way this hierarchy functions is described in more detail in the ZCPR33 Users Guide. We will focus here on the effect this hierarchy has on the design of shells. 1. Commands pending in the multiple command line buffer 2. Commands from a ZEX script 3. Commands from a SUBMIT script 4. A shell command 5. User input The significant change here from ZCPR30 is in the position of ZEX input. In ZCPR30, ZEX simply took over the function of user input and thus appeared in the hierarchy in parallel with user input at the lowest priority level. This would have led to very bizarre behavior under shells, and so special, and rather lengthy, code was included in every shell to see if ZEX was running and, if so, to feed its input to the multiple command line buffer. This resulted in completely useless loads of the shell code for each line of the ZEX script. For all practical purposes, ZEX scripts could not be run under shells. Since the ZCPR33 command processor has been redesigned to place ZEX above shells in the hierarchy, this code should not be included in new shells and should be removed from existing shells. There was a second inefficiency in the way shells operated that I fixed shortly after ZCPR3 was introduced (my first programming contribution). A little background is required to understand this situation. Shells have two distinct personalities or functions. When a shell is invoked by a user command, its function is to install itself on the shell stack so that later, when there are no pending commands at levels 1, 2, and 3 in the hierarchy above, the command processor will invoke that shell automatically. When that happens, the shell's second personality comes into play. When invoked not by the user but by the command processor, the shell is to perform its real work (this depends on the kind of shell). The shells that Richard Conn first created for ZCPR30 worked strictly according to this model. This resulted in very annoying behavior when the user entered the shell command alone on a command line. The shell would be loaded from disk, would note that it had been invoked by the user, would install its command on the shell stack, and then would return to the command processor. Next, the command processor, noting that no commands were pending in the command buffer, would turn to the shell stack and execute the command on the top of the stack (the shell we just installed). It would load the shell from disk (again), and the shell code, noting that it had been invoked not by the user but by the command processor, would perform its shell function. This second loading of the shell from disk was a complete waste of time and disk activity, since the shell code was already in memory. Many years ago I added code to the common shells to prevent this double loading. When the shell was invoked by the user, the code I added would check to see if there were any commands pending in the multiple command line buffer. If there were, after installing itself on the stack it would terminate execution as before. However, if there were no commands pending, it would proceed to carry out its shell function immediately. This cut the time to start up a shell in half. The logic behind this approach worked most of the time, but it had a flaw. If a SUBMIT job were in progress at the time the shell was installed by the user, even using a single command on the command line, the shell should not have started to perform its shell function but should have returned to the command processor for the next SUBMIT command. I did not include the SUBMIT capability in my implementation of ZCPR3, and so I never thought of this. With the new command acquisitiion hierarcy under ZCPR33, the shell should not proceed directly to its shell function when commands are pending from either the command line, a ZEX script, or a SUBMIT script. Pseudo-code for a shell should look like this: entry: Initialization functions IF invoked by user (shell bit in command status flag not set) push the shell command onto the shell stack IF multiple command line not empty, return IF ZEX running, return IF SUBMIT running, return ENDIF (invoked by user) Perform real shell function Return end The three tests that determine whether the code should terminate after the command is pushed onto the shell stack can be performed easily using calls to library routines. The code will look like this. call getcl2 ; Z3LIB routine returns with zero flag ; ..reset if there are more commands in ; ..the command line buffer jr nz,ccp ; If pending commands in buffer, return call getzrun ; Z3LIB routine resets zero flag if ZEX ; ..is running jr nz,ccp ; If ZEX is running, return to CCP call getsrun ; Z33LIB routine resets zero flag if SUBMIT ; ..is running ccp: jp nz,gotoccp ; If SUBMIT is running, return to CCP ; Else fall through to shell function code shellfunction: