5.4   The Shell Presentation

At this point, you have extracted all the information needed to write your own WindSh version of ifShow( ). The remaining task is to format the ifShow( ) output. The first two formatting routines are general and should be placed in installDir/host/resource/tcl/net-core.tcl. Place the final procedure in installDir/host/resource/tcl/app-config/WindSh/01NetShow.tcl because it is shell specific.

The first formatting routine, ifFlagsFormat, converts the if_flags field to a list of bit names by checking each flag bit (see the include file installDir/target/h/net/if.h):

proc ifFlagsFormat {flags} { 
    set result "" 
 
    if {$flags & 0x1}       {append result "UP "} 
    if {$flags & 0x2}       {append result "BROADCAST "} 
    if {$flags & 0x4}       {append result "DEBUG "} 
    if {$flags & 0x8}       {append result "LOOPBACK "} 
    if {$flags & 0x10}      {append result "POINT-TO-POINT "} 
    if {!($flags & 0x20)}   {append result "TRAILERS "} 
    if {$flags & 0x40}      {append result "RUNNING "} 
    if {!($flags & 0x80)}   {append result "ARP "} 
    if {$flags & 0x100}     {append result "PROMISC "} 
    if {$flags & 0x200}     {append result "ALLMULTI "} 
 
return $result 
}

The second formatting routine, ifAddrFormat, prints an Internet address in the standard dotted-decimal form.

proc ifAddrFormat {octetList} { 
    return [format "%d.%d.%d.%d" \ 
        [lindex $octetList 0] [lindex $octetList 1] \ 
        [lindex $octetList 2] [lindex $octetList 3]] 
}

All these routines are combined in a single file, which is stored in the installDir/host/resource/tcl directory.

Example 5-1:  net-core.tcl

proc netIfList {} { 
    set block [wtxMemRead [lindex [wtxSymFind -name ifnet] 1] 4] 
    set ifnet [memBlockGet -l $block] 
    return [wtxGopherEval "$ifnet {! +4 *}"] 
    }
proc netIfInfo {netIf} { return [wtxGopherEval "$netIf <*$> +22 @w +2 @w +4 @@ +4 @@@@@"] } proc netIfAddrList {netIf} { return [wtxGopherEval "$netIf +8 * {+16 * {<*{+4 @b@b@b@b 0}> +4 <*{+4 @b@b@b@b 0}>+12 *}0}"] }
proc ifFlagsFormat {flags} { set result ""
if {$flags & 0x1} {append result "UP "} if {$flags & 0x2} {append result "BROADCAST "} if {$flags & 0x4} {append result "DEBUG "} if {$flags & 0x8} {append result "LOOPBACK "} if {$flags & 0x10} {append result "POINT-TO-POINT "} if {!($flags & 0x20)} {append result "TRAILERS "} if {$flags & 0x40} {append result "RUNNING "} if {!($flags & 0x80)} {append result "ARP "} if {$flags & 0x100} {append result "PROMISC "} if {$flags & 0x200}         {append result "ALLMULTI "}
return $result }
proc ifAddrFormat {octetList} { return [format "%d.%d.%d.%d" \ [lindex $octetList 0] [lindex $octetList 1] \ [lindex $octetList 2] [lindex $octetList 3]] }

To complete the new version of the shell routine ifShowSh, call the procedures you created in the proper sequence and format the output. This final routine, ifShowSh, is declared as a shellproc rather than a proc. WindSh makes a Tcl procedure declared as a shellproc available to the C-expression-interpreter prompt of the shell. It does this by defining the procedure under another name and recording the original name of the procedure in a list of functions that may be called from the C shell prompt. Such functions must take a variable argument list, indicated in Tcl by the word args, because such functions are invoked by the C-expression interpreter with ten integer arguments, just as built-in shell routines are. Store this file in the installDir/host/resource/tcl/app-config/WindSh directory.

Example 5-2:  01NetShow.tcl

# source the data extraction and formatting routines 
 
source [wtxPath host resource tcl]net-core.tcl
# extract the data and display it in the shell shellproc ifShowSh {args} { foreach netIf [netIfList] { set ifInfo [netIfInfo $netIf] puts stdout [format "%s (unit number %d):" \ [lindex $ifInfo 0] [lindex $ifInfo 1]] puts stdout [format " Flags: (%#x) %s" \ [lindex $ifInfo 2] \ [ifFlagsFormat [lindex $ifInfo 2]]] set ifAddrList [netIfAddrList $netIf] while {[llength $ifAddrList] >= 8} { set iAddr [lrange $ifAddrList 0 3] set dAddr [lrange $ifAddrList 4 7] set ifAddrList [lrange $ifAddrList 12 end] puts stdout " Internet address: [ifAddrFormat $iAddr] " puts stdout " Destination/Broadcast address: \ [ifAddrFormat $dAddr]" }
puts stdout [format " Metric is %d" \ [lindex $ifInfo 4]] puts stdout [format " Maximum Transfer Unit size is %d" \ [lindex $ifInfo 3]] puts stdout [format " %d packets received; %d packets sent" \ [lindex $ifInfo 5] [lindex $ifInfo 7]] puts stdout [format " %d input errors; %d output errors" \ [lindex $ifInfo 6] [lindex $ifInfo 8]] puts stdout [format " %d collisions" \ [lindex $ifInfo 9]] } }

A side effect of installing a shell extension as a shellproc is that it becomes available at the CrossWind prompt. When CrossWind starts, it reads the WindSh Tcl files and makes new procedures that invoke the shell functions available. These procedures are automatically renamed to be consistent with GDB naming conventions; for example, you can invoke ifShow( ) by typing wind-if-show at the GDB prompt. This can be done any time after GDB is attached to a WTX target:

(gdb) tar wtx mv147 
Connecting to target server...  
Connected to mv147@aven. 
        Attached to target server mv147@aven, CPU is MC68020. 
Looking for all loaded modules: 
        vxWorks: (no debugging symbols found)...ok 
Done. 
(gdb) wind-if-show 
ln (unit number 0): 
        Flags: (0x63) UP BROADCAST RUNNING ARP  
        Internet address: 147.11.80.39 
        Destination/Broadcast address: 147.11.255.255...

The shell extension ifShow( ) does not take any parameters, but it could easily be modified to do so. Shellprocs (that is, Tcl routines designed to be invoked by the WindSh C interpreter) are always invoked with ten integer arguments. If a string is given as a parameter at the shell's C prompt, that string is stored on the target and the address is substituted as the parameter. This allows shellprocs to simulate target routines; for example, if a shellproc were to spawn a task whose name was given as one of the parameters of the shellproc, it would be possible to supply that string address directly to the taskSpawn( ) call.