A.3.1.1 Shell Sections

A shell section is similar to a function in other programming languages. You can pass multiple parameters to a shell section and receive multiple return values. Each shell section has a separate symbol table for storing its variables and their values.

The entrypoint sections used by the Setup program ([Identify], [ReturnOptions], [InstallOption]) are shell sections. The other types of sections ([Install] and [Detect]) are called by a command line in a shell section.

Shell Syntax

The following is the syntax for calling a shell section:

shell inf_file_path section_name [Args]*
 
inf_file_path
Specifies the full or partial path of the INF file in which the section is located. An empty string (““) indicates the current file.
section_name
Identifies the section (name in square brackets).
Args
Zero or more comma-separated or whitespace-separated arguments.

You can use the shell command from within a shell section to call another shell section (in the same file or in a different INF file).

$Shell Code

For a shell operation, Setup sets the value of the variable $ShellCode to one of the following:

!SHELL_CODE_OK

Shelling operation was successful

!SHELL_CODE_NO_SUCH_INF

Named INF file could not be located

!SHELL_CODE_NO_SUCH_SECTION

The INF file did not contain named section

!SHELL_CODE_ERROR

Parsing error in INF section

Programmers must check the value of $ShellCode before assuming that the return values and side-effects of the shelling operation actually apply.

Symbol Table Levels

Setup stores all its variable names and their values in its internal memory in an area called the symbol table. The shell statement has a special and very important effect on the symbol table.

When a shell statement is processed, a completely new symbol table is created. The original symbol table values are no longer directly accessible, and new variables and values are stored in this new, separate table. When the shelled section returns, this new symbol table is discarded. This behavior is similar to the “block scoping” rules common in procedural programming languages such as C.

The reason for such behavior is to avoid duplication or “collision” of variable names. The writer of an INF subroutine which is the target of a shell statement can be sure that variables he creates will not accidentally override global values.

This multi-level symbol table mechanism creates a new problem: how does a shelled section change or reference the value of a variable outside of its private, temporary symbol table? The answer is that Setup has special syntax for referencing variables which are nonlocal. The possibilities are:

local

$(MyVar)

reference to local variable MyVar

global

$(!MyVar)

reference to global variable MyVar

global

$(!G:MyVar)

reference to global variable MyVar

parent

$(!P:MyVar)

reference to caller’s variable MyVar

The outermost (or base) Setup symbol table is called the global symbol table. Variables created by Setup itself during initialization and the top-level INF file reside in the global symbol table. Setup allows access to three possibly distinct symbol tables: the local one, the one belonging to the shelling INF section, and the global one.

Passing Arguments to a Shell Section

The Setup program stores a shell’s input parameters in the shell’s symbol table using variables of the form $N, where N refers to the zero-based position of the parameter in the argument list. The shell can then use the $(var) notation to retrieve the argument’s value, that is, $($0) retrieves the value of Arg0, $($1) is the value of Arg1, and so on. Using the Return command, a shell section can return zero or more values to the section that called it. The following example shows a shell section that retrieves its arguments and returns two values:

[SampleShellSection]
 
; retrieve the input parameters
 
set Arg0 = $($0)
set Arg1 = $($1)
   .
   .
   .
; return two values
 
set Option = "OptionString"
Return STATUS_SUCCESSFUL $(Option)
 
Return Values From a Shell Section

The Setup program stores a shell section’s return values in the symbol table of its parent shell section (that is, the shell that called it), using variables of the form $RN, where N refers to the zero-based position of value in the list of return values. The parent shell can then use the $(var) notation to retrieve the return values (that is, $($R0) retrieves the first return value, $($R1)the second return value, and so on). The Setup program uses the $RN variable to store the number of return values. In addition to the values returned by a shell section, the Setup program sets the ShellCode global variable to indicate whether errors occurred during its interpretation of the section. The following example shows the command lines that call a shell section, then retrieve the results:

; pass two parameters to AShellSection
 
set Arg0 = "argument 0"
set Arg1 = argument1
 
; invoke section named AShellSection in the current inf file
 
shell "" AShellSection $(Arg0) $(Arg1)
 
; check ShellCode for internal errors during AShellSection execution
 
ifint $($ShellCode) != $(!SHELL_CODE_OK)
exit
endif
 
; get the return values
 
set Status = $($R0)
set Option = $($R1)
ifint $($R#) > 2
set OptionText = $($R2)
endif