dejagnu
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[DejaGnu] xml output


From: Matthew Bemis
Subject: [DejaGnu] xml output
Date: Wed, 20 Mar 2002 13:11:10 -0500

rob,
  I am uncertain how to use rcs and cvs, but I added xml output capabilities
to the dejagnu testing framework.
the xml output can be done in two ways
a -x switch for runtest
and an environment variable for when  make check is executed.
DEJA_GNU_XML=1
I attached the files that needed modification for this functionality.
please let me know if there is anything further I can do to submit this as a
patch.

--
Matt Bemis
Alpha Linux Group
University of New Hampshire


# Copyright (C) 1992 - 2001 Free Software Foundation, Inc.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

# Please email any bugs, comments, and/or additions to this file to:
# address@hidden

# This file was written by Rob Savoye. (address@hidden)

# These variables are local to this file.
# This or more warnings and a test fails.
set warning_threshold 3
# This or more errors and a test fails.
set perror_threshold 1

proc mail_file { file to subject } {
    if [file readable $file] {
        catch "exec mail -s \"$subject\" $to < $file"
    }
}
#
# Check for xml output flag or environment variable
#
proc check_xml {} {
    global env
    set x "DEJA_GNU_XML"
    return [format "%s" $env($x)]
}

#
# Open the output logs
#
proc open_logs { } {
    global outdir
    global tool
    global sum_file
    global xml_file
    global xml
    if { !$xml } {
        set xml [catch {check_xml} result ]
        if { $xml } {
            set xml 0
        } else {
            if { $result } {
                set xml 1
            }
        }
    }
    if { ${tool} ==  "" } {
        set tool testrun
    }
    catch "exec rm -f $outdir/$tool.sum"
    set sum_file [open "$outdir/$tool.sum" w]
    if { $xml } {
        catch "exec rm -f $outdir/$tool.xml"
        set xml_file [open "$outdir/$tool.xml" w]
        xml_output "<test_record>"
    }
    catch "exec rm -f $outdir/$tool.log"
    log_file -a "$outdir/$tool.log"
    verbose "Opening log files in $outdir"
    if { ${tool} ==  "testrun" } {
        set tool ""
    }
}


#
# Close the output logs
#
proc close_logs { } {
    global sum_file
    global xml_file
    if { 1 } {
        xml_output "</test_record>"
        catch "close $xml_file"
    }
    catch "close $sum_file"
}

#
# Check build host triplet for pattern
#
# With no arguments it returns the triplet string.
#
proc isbuild { pattern } {
    global build_triplet
    global host_triplet
    
    if ![info exists build_triplet] {
        set build_triplet ${host_triplet}
    }
    if [string match "" $pattern] {
        return $build_triplet
    }
    verbose "Checking pattern \"$pattern\" with $build_triplet" 2
    
    if [string match "$pattern" $build_triplet] {
        return 1
    } else {
        return 0
    }
}

#
# Is $board remote? Return a non-zero value if so.
#
proc is_remote { board } {
    global host_board;
    global target_list;

    verbose "calling is_remote $board" 3;
    # Remove any target variant specifications from the name.
    set board [lindex [split $board "/"] 0];

    # Map the host or build back into their short form.
    if { [board_info build name] == $board } {
        set board "build";
    } elseif { [board_info host name] == $board } {
        set board "host";
    }

    # We're on the "build". The check for the empty string is just for
    # paranoia's sake--we shouldn't ever get one. "unix" is a magic
    # string that should really go away someday.
    if { $board == "build" || $board == "unix" || $board == "" } {
        verbose "board is $board, not remote" 3;
        return 0;
    }

    if { $board == "host" } {
        if { [info exists host_board] && $host_board != "" } {
            verbose "board is $board, is remote" 3;
            return 1;
        } else {
            verbose "board is $board, host is local" 3;
            return 0;
        }
    }

    if { $board == "target" } {
        global current_target_name

        if [info exists current_target_name] {
            # This shouldn't happen, but we'll be paranoid anyway.
            if { $current_target_name != "target" } {
                return [is_remote $current_target_name];
            }
        }
        return 0;
    }
    if [board_info $board exists isremote] {
        verbose "board is $board, isremote is [board_info $board isremote]" 3;
        return [board_info $board isremote];
    }
    return 1;
}
#
# If this is a canadian (3 way) cross. This means the tools are
# being built with a cross compiler for another host.
#
proc is3way {} {
    global host_triplet
    global build_triplet
    
    if ![info exists build_triplet] {
        set build_triplet ${host_triplet}
    }
    verbose "Checking $host_triplet against $build_triplet" 2
    if { "$build_triplet" == "$host_triplet" } {
        return 0
    }
    return 1
}

#
# Check host triplet for pattern
#
# With no arguments it returns the triplet string.
#
proc ishost { pattern } {
    global host_triplet
    
    if [string match "" $pattern] {
        return $host_triplet
    }
    verbose "Checking pattern \"$pattern\" with $host_triplet" 2
    
    if [string match "$pattern" $host_triplet] {
        return 1
    } else {
        return 0
    }
}

#
# Check target triplet for pattern
#
# With no arguments it returns the triplet string.
# Returns 1 if the target looked for, or 0 if not.
#
proc istarget { args } {
    global target_triplet
    
    # if no arg, return the config string
    if [string match "" $args] {
        if [info exists target_triplet] {
            return $target_triplet
        } else {
            perror "No target configuration names found."
        }
    }

    set triplet [lindex $args 0]

    # now check against the cannonical name
    if [info exists target_triplet] {
        verbose "Checking \"$triplet\" against \"$target_triplet\"" 2
        if [string match $triplet $target_triplet] {
            return 1
        }
    }

    # nope, no match
    return 0
}

#
# Check to see if we're running the tests in a native environment
#
# Returns 1 if running native, 0 if on a target.
#
proc isnative { } {
    global target_triplet
    global build_triplet
    
    if [string match $build_triplet $target_triplet] {
        return 1
    }
    return 0
}

#
# unknown -- called by expect if a proc is called that doesn't exist
#
proc unknown { args } {
    global errorCode
    global errorInfo
    global exit_status

    clone_output "ERROR: (DejaGnu) proc \"$args\" does not exist."
    if [info exists errorCode] {
        send_error "The error code is $errorCode\n"
    }
    if [info exists errorInfo] {
        send_error "The info on the error is:\n$errorInfo\n"
    }

    set exit_status 1;
    log_and_exit;
}

#
# Print output to stdout (or stderr) and to log file
#
# If the --all flag (-a) option was used then all messages go the the screen.
# Without this, all messages that start with a keyword are written only to the
# detail log file.  All messages that go to the screen will also appear in the
# detail log.  This should only be used by the framework itself using pass,
# fail, xpass, xfail, warning, perror, note, untested, unresolved, or
# unsupported procedures.
#
proc clone_output { message } {
    global sum_file
    global all_flag
    
    if { $sum_file != "" } {
        puts $sum_file "$message"
    }

    regsub "^\[ \t\]*(\[^ \t\]+).*$" "$message" "\\1" firstword;
    case "$firstword" in {
        {"PASS:" "XFAIL:" "UNRESOLVED:" "UNSUPPORTED:" "UNTESTED:"} {
            if $all_flag {
                send_user "$message\n"
                return "$message"
            } else {
                send_log "$message\n"
            }
        }
        {"ERROR:" "WARNING:" "NOTE:"} {
            send_error "$message\n"
            return "$message"
        }
        default {
            send_user "$message\n"
            return "$message"
        }
    }
}

proc xml_output { message } {
    global xml_file
    if { $xml_file != "" } {
        puts $xml_file "$message"
    }
}

#
# Reset a few counters.
#
proc reset_vars {} {
    global test_names test_counts;
    global warncnt errcnt;

    # other miscellaneous variables
    global prms_id
    global bug_id
    
    # reset them all
    set prms_id 0;
    set bug_id  0;
    set warncnt 0;
    set errcnt  0;
    foreach x $test_names {
        set test_counts($x,count) 0;
    }

    # Variables local to this file.
    global warning_threshold perror_threshold
    set warning_threshold 3
    set perror_threshold 1
}

proc log_and_exit {} {
    global exit_status;
    global tool mail_logs outdir mailing_list;

    log_summary total;
    # extract version number
    if {[info procs ${tool}_version] != ""} {
        if {[catch "${tool}_version" output]} {
            warning "${tool}_version failed:\n$output"
        }
    }
    close_logs
    cleanup
    verbose -log "runtest completed at [timestamp -format %c]"
    if $mail_logs {
        mail_file $outdir/$tool.sum $mailing_list "Dejagnu Summary Log"
    }
    remote_close host
    remote_close target
    exit $exit_status
}
#
# Print summary of all pass/fail counts
#
proc log_summary { args } {
    global tool
    global sum_file
    global xml_file
    global exit_status
    global mail_logs
    global outdir
    global mailing_list
    global current_target_name
    global test_counts;
    global testcnt;

    if { [llength $args] == 0 } {
        set which "count";
    } else {
        set which [lindex $args 0];
    }

    if { [llength $args] == 0 } {
        clone_output "\n\t\t=== $tool Summary for $current_target_name ===\n"
    } else {
        clone_output "\n\t\t=== $tool Summary ===\n"
    }

    # If the tool set `testcnt', it wants us to do a sanity check on the
    # total count, so compare the reported number of testcases with the
    # expected number.  Maintaining an accurate count in `testcnt' isn't easy
    # so it's not clear how often this will be used.
    if [info exists testcnt] {
        if { $testcnt > 0 } {
            set totlcnt 0;
            # total all the testcases reported
            foreach x { FAIL PASS XFAIL XPASS UNTESTED UNRESOLVED UNSUPPORTED } 
{
                incr totlcnt test_counts($x,$which);
            }
            set testcnt test_counts(total,$which);
            
            if { $testcnt>$totlcnt || $testcnt<$totlcnt } {
                if { $testcnt > $totlcnt } {
                    set mismatch "unreported  [expr $testcnt-$totlcnt]"
                }
                if { $testcnt < $totlcnt } {
                    set mismatch "misreported [expr $totlcnt-$testcnt]"
                }
            } else {
                verbose "# of testcases run         $testcnt"
            }

            if [info exists mismatch] {
                clone_output "### ERROR: totals do not equal number of 
testcases run"
                clone_output "### ERROR: # of testcases expected    $testcnt"
                clone_output "### ERROR: # of testcases reported    $totlcnt"
                clone_output "### ERROR: # of testcases $mismatch\n"
            }
        }
    }
    if { 1 } {
        xml_output "  <summary>"
    }  
    foreach x { PASS FAIL XPASS XFAIL UNRESOLVED UNTESTED UNSUPPORTED } {
        set val $test_counts($x,$which);
        if { $val > 0 } {
            set mess "# of $test_counts($x,name)";
            if { 1 } { 
                xml_output "    <result>\n      <type>$x</type>"
                xml_output "      <description>$mess</description>"
                xml_output "      <total>$val</total>\n    </result>"
            }
            if { [string length $mess] < 24 } {
                append mess "\t";
            }
            clone_output "$mess\t$val";
        }
    }
    if { 1 } {
        xml_output "  </summary>"
   }
}

#
# Close all open files, remove temp file and core files
#
proc cleanup {} {
    global sum_file
    global xml_file
    global exit_status
    global done_list
    global subdir
    
    #catch "exec rm -f [glob xgdb core *.x *.o *_soc a.out]"
    #catch "exec rm -f [glob -nocomplain $subdir/*.o $subdir/*.x $subdir/*_soc]"
}

#
# Setup a flag to control whether a failure is expected or not
#
# Multiple target triplet patterns can be specified for targets
# for which the test fails.  A bug report ID can be specified,
# which is a string without '-'.
#
proc setup_xfail { args } {
    global xfail_flag
    global xfail_prms
    
    set xfail_prms 0
    set argc [ llength $args ]
    for { set i 0 } { $i < $argc } { incr i } {
        set sub_arg [ lindex $args $i ]
        # is a prms number. we assume this is a string with no '-' characters
        if [regexp "^\[^\-\]+$" $sub_arg] { 
            set xfail_prms $sub_arg
            continue
        }
        if [istarget $sub_arg] {
            set xfail_flag 1
            continue
        }
    }
}


# check to see if a conditional xfail is triggered
#       message {targets} {include} {exclude}
#              
#
proc check_conditional_xfail { args } {
    global compiler_flags

    set all_args [lindex $args 0]

    set message [lindex $all_args 0]

    set target_list [lindex $all_args 1]
    verbose "Limited to targets: $target_list" 3

    # get the list of flags to look for
    set includes [lindex $all_args 2]
    verbose "Will search for options $includes" 3

    # get the list of flags to exclude
    if { [llength $all_args] > 3 } {
        set excludes [lindex $all_args 3]
        verbose "Will exclude for options $excludes" 3
    } else {
        set excludes ""
    }
    
    # loop through all the targets, checking the options for each one
    verbose "Compiler flags are: $compiler_flags" 2
    
    set incl_hit 0
    set excl_hit 0
    foreach targ $target_list {
        if [istarget $targ] {
            # look through the compiler options for flags we want to see
            # this is really messy cause each set of options to look for
            # may also be a list. We also want to find each element of the
            # list, regardless of order to make sure they're found.
            # So we look for lists in side of lists, and make sure all 
            # the elements match before we decide this is legit.
            for { set i 0 } { $i < [llength $includes] } { incr i } {
                set incl_hit 0
                set opt [lindex $includes $i]
                verbose "Looking for $opt to include in the compiler flags" 2
                foreach j "$opt" {
                    if [string match "* $j *" $compiler_flags] {
                        verbose "Found $j to include in the compiler flags" 2
                        incr incl_hit
                    }
                }
                # if the number of hits we get is the same as the number of
                # specified options, then we got a match
                if {$incl_hit == [llength $opt]} {
                    break
                } else {
                    set incl_hit 0
                }
            }
            # look through the compiler options for flags we don't
            # want to see
            for { set i 0 } { $i < [llength $excludes] } { incr i } {
                set excl_hit 0
                set opt [lindex $excludes $i]
                verbose "Looking for $opt to exclude in the compiler flags" 2
                foreach j "$opt" {
                    if [string match "* $j *" $compiler_flags] {
                        verbose "Found $j to exclude in the compiler flags" 2
                        incr excl_hit
                    }
                }
                # if the number of hits we get is the same as the number of
                # specified options, then we got a match
                if {$excl_hit == [llength $opt]} {
                    break
                } else {
                    set excl_hit 0
                }
            }

            # if we got a match for what to include, but didn't find any reasons
            # to exclude this, then we got a match! So return one to turn this 
into
            # an expected failure.
            if {$incl_hit && ! $excl_hit } {
                verbose "This is a conditional match" 2
                return 1
            } else {
                verbose "This is not a conditional match" 2
                return 0
            }
        }
    }
    return 0
}

#
# Clear the xfail flag for a particular target
#
proc clear_xfail { args } {
    global xfail_flag
    global xfail_prms
    
    set argc [ llength $args ]
    for { set i 0 } { $i < $argc } { incr i } {
        set sub_arg [ lindex $args $i ]
        case $sub_arg in {
            "*-*-*" {                   # is a configuration triplet
                if [istarget $sub_arg] {
                    set xfail_flag 0
                    set xfail_prms 0
                }
                continue
            }
        }
    }
}

#
# Record that a test has passed or failed (perhaps unexpectedly)
#
# This is an internal procedure, only used in this file.
#
proc record_test { type message args } {
    global exit_status
    global prms_id bug_id
    global xfail_flag xfail_prms
    global errcnt warncnt
    global warning_threshold perror_threshold
    global pf_prefix

    if { [llength $args] > 0 } {
        set count [lindex $args 0];
    } else {
        set count 1;
    }
    if [info exists pf_prefix] {
        set message [concat $pf_prefix " " $message];
    }

    # If we have too many warnings or errors,
    # the output of the test can't be considered correct.
    if { $warning_threshold > 0 && $warncnt >= $warning_threshold
         || $perror_threshold > 0 && $errcnt >= $perror_threshold } {
        verbose "Error/Warning threshold exceeded: \
                 $errcnt $warncnt (max. $perror_threshold $warning_threshold)"
        set type UNRESOLVED
    }

    incr_count $type;
    xml_output "  <$type>$message</$type>";
    switch $type {
        PASS {
            if $prms_id {
                set message [concat $message "\t(PRMS $prms_id)"]
            }
        }
        FAIL {
            set exit_status 1
            if $prms_id {
                set message [concat $message "\t(PRMS $prms_id)"]
            }
        }
        XPASS {
            set exit_status 1
            if { $xfail_prms != 0 } {
                set message [concat $message "\t(PRMS $xfail_prms)"]
            }
        }
        XFAIL {
            if { $xfail_prms != 0 } {
                set message [concat $message "\t(PRMS $xfail_prms)"]
            }
        }
        UNTESTED {
            # The only reason we look at the xfail stuff is to pick up
            # `xfail_prms'.
            if { $xfail_flag && $xfail_prms != 0 } {
                set message [concat $message "\t(PRMS $xfail_prms)"]
            } elseif $prms_id {
                set message [concat $message "\t(PRMS $prms_id)"]
            }
        }
        UNRESOLVED {
            set exit_status 1
            # The only reason we look at the xfail stuff is to pick up
            # `xfail_prms'.
            if { $xfail_flag && $xfail_prms != 0 } {
                set message [concat $message "\t(PRMS $xfail_prms)"]
            } elseif $prms_id {
                set message [concat $message "\t(PRMS $prms_id)"]
            }
        }
        UNSUPPORTED {
            # The only reason we look at the xfail stuff is to pick up
            # `xfail_prms'.
            if { $xfail_flag && $xfail_prms != 0 } {
                set message [concat $message "\t(PRMS $xfail_prms)"]
            } elseif $prms_id {
                set message [concat $message "\t(PRMS $prms_id)"]
            }
        }
        default {
            perror "record_test called with bad type `$type'"
            set errcnt 0
            return
        }
    }

    if $bug_id {
        set message [concat $message "\t(BUG $bug_id)"]
    }

    global multipass_name
    if { $multipass_name != "" } {
        set message [format "$type: %s: $message" "$multipass_name"]
    } else {
        set message "$type: $message"
    }
    clone_output "$message"

    # If a command name exists in the $local_record_procs associative
    # array for this type of result, then invoke it.

    set lowcase_type [string tolower $type]
    global local_record_procs
    if {[info exists local_record_procs($lowcase_type)]} {
        $local_record_procs($lowcase_type) "$message"
    }
    
    # Reset these so they're ready for the next test case.  We don't reset
    # prms_id or bug_id here.  There may be multiple tests for them.  Instead
    # they are reset in the main loop after each test.  It is also the
    # testsuite driver's responsibility to reset them after each testcase.
    set warncnt 0
    set errcnt 0
    set xfail_flag 0
    set xfail_prms 0
}

#
# Record that a test has passed
#
proc pass { message } {
    global xfail_flag compiler_conditional_xfail_data

    # if we have a conditional xfail setup, then see if our compiler flags match
    if [ info exists compiler_conditional_xfail_data ] {
        if [check_conditional_xfail $compiler_conditional_xfail_data] {
            set xfail_flag 1
        }
        unset compiler_conditional_xfail_data
    }
    
    if $xfail_flag {
        record_test XPASS $message
    } else {
        record_test PASS $message
    }
}

#
# Record that a test has failed
#
proc fail { message } {
    global xfail_flag compiler_conditional_xfail_data

    # if we have a conditional xfail setup, then see if our compiler flags match
    if [ info exists compiler_conditional_xfail_data ] {
        if [check_conditional_xfail $compiler_conditional_xfail_data] {
            set xfail_flag 1
        }
        unset compiler_conditional_xfail_data
    }

    if $xfail_flag {
        record_test XFAIL $message
    } else {
        record_test FAIL $message
    }
}

#
# Record that a test has passed unexpectedly
#
proc xpass { message } {
    record_test XPASS $message
}

#
# Record that a test has failed unexpectedly
#
proc xfail { message } {
    record_test XFAIL $message
}

#
# Set warning threshold
#
proc set_warning_threshold { threshold } {
    set warning_threshold $threshold
}

#
# Get warning threshold
#
proc get_warning_threshold { } {
    return $warning_threshold
}

#
# Prints warning messages
# These are warnings from the framework, not from the tools being tested.
# It takes a string, and an optional number and returns nothing.
#
proc warning { args } {
    global warncnt
 
    if { [llength $args] > 1 } {
        set warncnt [lindex $args 1]
    } else {
        incr warncnt
    }
    set message [lindex $args 0]
    
    clone_output "WARNING: $message"

    global errorInfo
    if [info exists errorInfo] {
        unset errorInfo
    }
}

#
# Prints error messages
# These are errors from the framework, not from the tools being tested. 
# It takes a string, and an optional number and returns nothing.
#
proc perror { args } {
    global errcnt

    if { [llength $args] > 1 } {
        set errcnt [lindex $args 1]
    } else {
        incr errcnt
    }
    set message [lindex $args 0]
    
    clone_output "ERROR: $message"

    global errorInfo
    if [info exists errorInfo] {
        unset errorInfo
    }
}

#
# Prints informational messages
#
# These are messages from the framework, not from the tools being tested.
# This means that it is currently illegal to call this proc outside
# of dejagnu proper.
#
proc note { message } {
    clone_output "NOTE: $message"

    # ??? It's not clear whether we should do this.  Let's not, and only do
    # so if we find a real need for it.
    #global errorInfo
    #if [info exists errorInfo] {
    #   unset errorInfo
    #}
}

#
# untested -- mark the test case as untested
#
proc untested { message } {
    record_test UNTESTED $message
}

#
# Mark the test case as unresolved
#
proc unresolved { message } {
    record_test UNRESOLVED $message
}

#
# Mark the test case as unsupported
#
# Usually this is used for a test that is missing OS support.
#
proc unsupported { message } {
    record_test UNSUPPORTED $message
}

#
# Set up the values in the test_counts array (name and initial totals).
#
proc init_testcounts { } {
    global test_counts test_names;
    set test_counts(TOTAL,name) "testcases run"
    set test_counts(PASS,name) "expected passes"
    set test_counts(FAIL,name) "unexpected failures"
    set test_counts(XFAIL,name) "expected failures"
    set test_counts(XPASS,name) "unexpected successes"
    set test_counts(WARNING,name) "warnings"
    set test_counts(ERROR,name) "errors"
    set test_counts(UNSUPPORTED,name) "unsupported tests"
    set test_counts(UNRESOLVED,name) "unresolved testcases"
    set test_counts(UNTESTED,name) "untested testcases"
    set j "";

    foreach i [lsort [array names test_counts]] {
        regsub ",.*$" "$i" "" i;
        if { $i == $j } {
            continue;
        }
        set test_counts($i,total) 0;
        lappend test_names $i;
        set j $i;
    }
}

#
# Increment NAME in the test_counts array; the amount to increment can be
# is optional (defaults to 1).
#
proc incr_count { name args } {
    global test_counts;

    if { [llength $args] == 0 } {
        set count 1;
    } else {
        set count [lindex $args 0];
    }
    if [info exists test_counts($name,count)] {
        incr test_counts($name,count) $count;
        incr test_counts($name,total) $count;
    } else {
        perror "$name doesn't exist in incr_count"
    }
}


#
# Create an exp_continue proc if it doesn't exist
#
# For compatablity with old versions.
#
global argv0
if ![info exists argv0] {
    proc exp_continue { } {
        continue -expect
    }
}
# Test Framework Driver
# Copyright (C) 1992 - 2001 Free Software Foundation, Inc.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

# Please email any bugs, comments, and/or additions to this file to:
# address@hidden

# This file was written by Rob Savoye. (address@hidden)

set frame_version       1.4.0
if ![info exists argv0] {
    send_error "Must use a version of Expect greater than 5.0\n"
    exit 1
}

#
# trap some signals so we know whats happening. These definitions are only
# temporary until we read in the library stuff
#
trap { send_user "\nterminated\n";             exit 1 } SIGTERM
trap { send_user "\ninterrupted by user\n";    exit 1 } SIGINT
trap { send_user "\nsigquit\n";                exit 1 } SIGQUIT

#
# Initialize a few global variables used by all tests.
# `reset_vars' resets several of these, we define them here to document their
# existence.  In fact, it would be nice if all globals used by some interface
# of dejagnu proper were documented here.
#
# Keep these all lowercase.  Interface variables used by the various
# testsuites (eg: the gcc testsuite) should be in all capitals
# (eg: TORTURE_OPTIONS).
#
set mail_logs   0               ;# flag for mailing of summary and diff logs
set psum_file   "latest"        ;# file name of previous summary to diff against

set exit_status 0               ;# exit code returned by this program

set xfail_flag  0
set xfail_prms  0
set sum_file    ""              ;# name of the file that contains the summary 
log
set xml_file    ""              ;# name of the xml output if requested
set xml         0               ;# flag for requesting xml output
set base_dir    ""              ;# the current working directory
set logname     ""              ;# the users login name
set prms_id     0               ;# GNATS prms id number
set bug_id      0               ;# optional bug id number
set dir         ""              ;# temp variable for directory names
set srcdir      "."             ;# source directory containing the test suite
set ignoretests ""              ;# list of tests to not execute
set objdir      "."             ;# directory where test case binaries live
set reboot      0
set configfile  site.exp        ;# (local to this file)
set multipass   ""              ;# list of passes and var settings
set errno       "";             ;# 
#
# These describe the host and target environments.
#
set build_triplet  ""           ;# type of architecture to run tests on
set build_os       ""           ;# type of os the tests are running on
set build_vendor   ""           ;# vendor name of the OS or workstation the 
test are running on
set build_cpu      ""           ;# type of the cpu tests are running on
set host_triplet   ""           ;# type of architecture to run tests on, 
sometimes remotely
set host_os        ""           ;# type of os the tests are running on
set host_vendor    ""           ;# vendor name of the OS or workstation the 
test are running on
set host_cpu       ""           ;# type of the cpu tests are running on
set target_triplet ""           ;# type of architecture to run tests on, final 
remote
set target_os      ""           ;# type of os the tests are running on
set target_vendor  ""           ;# vendor name of the OS or workstation the 
test are running on
set target_cpu     ""           ;# type of the cpu tests are running on
set target_alias   ""           ;# standard abbreviation of target
set compiler_flags ""           ;# the flags used by the compiler

#
# some convenience abbreviations
#
if ![info exists hex] {
    set hex "0x\[0-9A-Fa-f\]+"
}
if ![info exists decimal] {
    set decimal "\[0-9\]+"
}

#
# set the base dir (current working directory)
#
set base_dir [pwd]

#
# These are tested in case they are not initialized in $configfile. They are
# tested here instead of the init module so they can be overridden by command
# line options.
#
if ![info exists all_flag] {
    set all_flag 0
}
if ![info exists binpath] {
    set binpath ""
}
if ![info exists debug] {
    set debug 0
}
if ![info exists options] {
    set options ""
}
if ![info exists outdir] {
    set outdir "."
}
if ![info exists reboot] {
    set reboot 1
}
if ![info exists tracelevel] {
    set tracelevel 0
}
if ![info exists verbose] {
    set verbose 0
}

#
# verbose [-n] [-log] [--] message [level]
#
# Print MESSAGE if the verbose level is >= LEVEL.
# The default value of LEVEL is 1.
# "-n" says to not print a trailing newline.
# "-log" says to add the text to the log file even if it won't be printed.
# Note that the apparent behaviour of `send_user' dictates that if the message
# is printed it is also added to the log file.
# Use "--" if MESSAGE begins with "-".
#
# This is defined here rather than in framework.exp so we can use it
# while still loading in the support files.
#
proc verbose { args } {
    global verbose
    set newline 1
    set logfile 0

    set i 0
    if { [string index [lindex $args 0] 0] == "-" } {
        for { set i 0 } { $i < [llength $args] } { incr i } {
            if { [lindex $args $i] == "--" } {
                incr i
                break
            } elseif { [lindex $args $i] == "-n" } {
                set newline 0
            } elseif { [lindex $args $i] == "-log" } {
                set logfile 1
            } elseif { [lindex $args $i] == "-x" } {
                set xml 1
            } elseif { [string index [lindex $args $i] 0] == "-" } {
                clone_output "ERROR: verbose: illegal argument: [lindex $args 
$i]"
                return
            } else {
                break
            }
        }
        if { [llength $args] == $i } {
            clone_output "ERROR: verbose: nothing to print"
            return
        }
    }

    set level 1
    if { [llength $args] > $i + 1 } {
        set level [lindex $args [expr $i+1]]
    }
    set message [lindex $args $i]
    
    if { $verbose >= $level } {
        # There is no need for the "--" argument here, but play it safe.
        # We assume send_user also sends the text to the log file (which
        # appears to be the case though the docs aren't clear on this).
        if { $newline } {
            send_user -- "$message\n"
        } else {
            send_user -- "$message"
        }
    } elseif { $logfile } {
        if { $newline } {
            send_log "$message\n"
        } else {
            send_log "$message"
        }
    }
}

#
# Transform a tool name to get the installed name.
# target_triplet is the canonical target name.  target_alias is the
# target name used when configure was run.
#
proc transform { name } {
    global target_triplet
    global target_alias
    global host_triplet
    global board;

    if [string match $target_triplet $host_triplet] {
        return $name
    }
    if [string match "native" $target_triplet] {
        return $name
    }
    if [board_info host exists no_transform_name] {
        return $name
    }
    if [string match "" $target_triplet] {
        return $name
    } else {
        if [info exists board] {
            if [board_info $board exists target_install] {
                set target_install [board_info $board target_install];
            }
        }
        if [target_info exists target_install] {
            set target_install [target_info target_install];
        }
        if [info exists target_alias] {
            set tmp ${target_alias}-${name};
        } elseif [info exists target_install] {
            if { [lsearch -exact $target_install $target_alias] >= 0 } {
                set tmp ${target_alias}-${name};
            } else {
                set tmp "[lindex $target_install 0]-${name}";
            }
        }
        verbose "Transforming $name to $tmp";
        return $tmp;
    }
}

#
# findfile arg0 [arg1] [arg2]
#
# Find a file and see if it exists. If you only care about the false
# condition, then you'll need to pass a null "" for arg1.
#       arg0 is the filename to look for. If the only arg,
#            then that's what gets returned. If this is the
#            only arg, then if it exists, arg0 gets returned.
#            if it doesn't exist, return only the prog name.
#       arg1 is optional, and it's what gets returned if
#            the file exists.
#       arg2 is optional, and it's what gets returned if
#            the file doesn't exist.
#
proc findfile { args } {    
    # look for the file
    verbose "Seeing if [lindex $args 0] exists." 2
    if [file exists [lindex $args 0]] {
        if { [llength $args] > 1 } {
            verbose "Found file, returning [lindex $args 1]"
            return [lindex $args 1]
        } else {
            verbose "Found file, returning [lindex $args 0]"
            return [lindex $args 0]
        }
    } else {
        if { [llength $args] > 2 } {
            verbose "Didn't find file [lindex $args 0], returning [lindex $args 
2]"
            return [lindex $args 2]
        } else {
            verbose "Didn't find file, returning [file tail [lindex $args 0]]"
            return [transform [file tail [lindex $args 0]]]
        }
    }
}

#
# load_file [-1] [--] file1 [ file2 ... ]
#
# Utility to source a file.  All are sourced in order unless the flag "-1"
# is given in which case we stop after finding the first one.
# The result is 1 if a file was found, 0 if not.
# If a tcl error occurs while sourcing a file, we print an error message
# and exit.
#
# ??? Perhaps add an optional argument of some descriptive text to add to
# verbose and error messages (eg: -t "library file" ?).
#
proc load_file { args } {
    set i 0
    set only_one 0
    if { [lindex $args $i] == "-1" } {
        set only_one 1
        incr i
    }
    if { [lindex $args $i] == "--" } {
        incr i
    }

    set found 0
    foreach file [lrange $args $i end] {
        verbose "Looking for $file" 2
        # In Tcl7.5a2, "file exists" can fail if the filename looks
        # like ~/FILE and the environment variable HOME does not
        # exist.
        if {! [catch {file exists $file} result] && $result} {
            set found 1
            verbose "Found $file"
            if { [catch "uplevel #0 source $file"] == 1 } {
                send_error "ERROR: tcl error sourcing $file.\n"
                global errorInfo
                if [info exists errorInfo] {
                    send_error "$errorInfo\n"
                }
                exit 1
            }
            if $only_one {
                break
            }
        }
    }
    return $found
}

#
# search_and_load_file -- search DIRLIST looking for FILELIST.
# TYPE is used when displaying error and progress messages.
#
proc search_and_load_file { type filelist dirlist } {
    set found 0;

    foreach dir $dirlist {
        foreach initfile $filelist {
            verbose "Looking for $type ${dir}/${initfile}" 1
            if [file exists ${dir}/${initfile}] {
                set found 1
                set error ""
                if { ${type} != "library file" } {
                    send_user "Using ${dir}/${initfile} as ${type}.\n"
                } else {
                    verbose "Loading ${dir}/${initfile}"
                }
                if [catch "uplevel #0 source ${dir}/${initfile}" error]==1 {
                    global errorInfo
                    send_error "ERROR: tcl error sourcing ${type} 
${dir}/${initfile}.\n${error}\n"
                    if [info exists errorInfo] {
                        send_error "$errorInfo\n"
                    }
                    exit 1
                }
                break
            }
        }
        if $found {
            break
        }
    }
    return $found;
}

#
# Give a usage statement.
#
proc usage { } {
    global tool;

    send_user "USAGE: runtest \[options...\]\n"
    send_user "\t--all (-a)\t\tPrint all test output to screen\n"
    send_user "\t--build \[string\]\tThe canonical config name of the build 
machine\n"
    send_user "\t--host \[string\]\t\tThe canonical config name of the host 
machine\n"
    send_user "\t--host_board \[name\]\tThe host board to use\n"
    send_user "\t--target \[string\]\tThe canonical config name of the target 
board\n"
    send_user "\t--debug (-de)\t\tSet expect debugging ON\n"
    send_user "\t--help (-he)\t\tPrint help text\n"
    send_user "\t--mail \[name(s)\]\tWhom to mail the results to\n"
    send_user "\t--ignore \[name(s)\]\tThe names of specific tests to ignore\n"
    send_user "\t--objdir \[name\]\t\tThe test suite binary directory\n"
    send_user "\t--outdir \[name\]\t\tThe directory to put logs in\n"
    send_user "\t--reboot \[name\]\t\tReboot the target (if supported)\n"
    send_user "\t--srcdir \[name\]\t\tThe test suite source code directory\n"
    send_user "\t--strace \[number\]\tSet expect tracing ON\n"
    send_user "\t--target_board \[name(s)\] The list of target boards to run 
tests on\n"
    send_user "\t--tool\[name(s)\]\t\tRun tests on these tools\n"
    send_user "\t--tool_exec \[name\]\tThe path to the tool executable to 
test\n"
    send_user "\t--tool_opts \[options\]\tA list of additional options to pass 
to the tool\n"
    send_user "\t--directory (-di) name\tRun only the tests in directory 
'name'\n"
    send_user "\t--verbose (-v)\t\tEmit verbose output\n"
    send_user "\t--version (-V)\t\tEmit all version numbers\n"
    send_user "\t--D\[0-1\]\t\tTcl debugger\n"
    send_user "\tscript.exp\[=arg(s)\]\tRun these tests only\n"
    if { [info exists tool] } {
        if { [info proc ${tool}_option_help] != "" } {
            ${tool}_option_help;
        }
    }
}

#
# Parse the arguments the first time looking for these.  We will ultimately
# parse them twice.  Things are complicated because:
# - we want to parse --verbose early on
# - we don't want config files to override command line arguments
#   (eg: $base_dir/$configfile vs --host/--target)
# - we need some command line arguments before we can process some config files
#   (eg: --objdir before $objdir/$configfile, --host/--target before $DEJAGNU)
# The use of `arg_host_triplet' and `arg_target_triplet' lets us avoid parsing
# the arguments three times.
#

set arg_host_triplet ""
set arg_target_triplet ""
set arg_build_triplet ""
set argc [ llength $argv ]
for { set i 0 } { $i < $argc } { incr i } {
    set option [lindex $argv $i]

    # make all options have two hyphens
    switch -glob -- $option {
        "--*" {
        }
        "-*" {
            set option "-$option"
        }
    }

    # split out the argument for options that take them
    switch -glob -- $option {
        "--*=*" {
            regexp {^[^=]*=(.*)$} $option nil optarg
        }
        "--bu*" -
        "--ho*" -
        "--ig*"  -
        "--m*"  -
        "--n*"  -
        "--ob*" -
        "--ou*" -
        "--sr*" -
        "--st*" -
        "--ta*" -
        "--di*" -
        "--to*" {
            incr i
            set optarg [lindex $argv $i]
        }
    }

    switch -glob -- $option {
        "--bu*" {                       # (--build) the build host configuration
            set arg_build_triplet $optarg
            continue
        }
        
        "--host_bo*" {
            set host_board $optarg
            continue
        }
        
        "--ho*" {                       # (--host) the host configuration
            set arg_host_triplet $optarg
            continue
        }

        "--ob*" {                       # (--objdir) where the test case object 
code lives
            set objdir $optarg
            continue
        }

        "--sr*" {                       # (--srcdir) where the testsuite source 
code lives
            set srcdir $optarg
            continue
        }
        
        "--target_bo*" {
            set target_list $optarg;
            continue;
        }

        "--ta*" {                       # (--target) the target configuration
            set arg_target_triplet $optarg
            continue
        }

        "--tool_opt*" {
            set TOOL_OPTIONS $optarg
            continue
        }

        "--tool_exec*" {
            set TOOL_EXECUTABLE $optarg
            continue
        }

        "--tool_ro*" {
            set tool_root_dir $optarg
            continue;
        }

        "--to*" {                       # (--tool) specify tool name
            set tool $optarg
            set comm_line_tool $optarg;
            continue
        }

        "--di*" {
            set cmdline_dir_to_run $optarg
            puts "cmdline_dir_to_run = $cmdline_dir_to_run"
            continue
        }

        "--v" -
        "--verb*" {                     # (--verbose) verbose output
            incr verbose
            continue
        }
    }
}
verbose "Verbose level is $verbose"

#
# get the users login name
#
if [string match "" $logname] {
    if [info exists env(USER)] {
        set logname $env(USER)
    } else {
        if [info exists env(LOGNAME)] {
            set logname $env(LOGNAME)
        } else {
            # try getting it with whoami
            catch "set logname [exec whoami]" tmp
            if [string match "*couldn't find*to execute*" $tmp] {
                # try getting it with who am i
                unset tmp
                catch "set logname [exec who am i]" tmp
                if [string match "*Command not found*" $tmp] {  
                    send_user "ERROR: couldn't get the users login name\n"
                    set logname "Unknown"
                } else {
                    set logname [lindex [split $logname " !"] 1]
                }
            }
        }
    }
}

#
# lookfor_file -- try to find a file by searching up multiple directory levels
#
proc lookfor_file { dir name } {
    foreach x ".. ../.. ../../.. ../../../.." {
        verbose "$dir/$name"
        if [file exists $dir/$name] {
            return $dir/$name;
        }
        set dir [remote_file build dirname $dir];
    }
    return ""
}

#
# load_lib -- load a library by sourcing it
#
# If there a multiple files with the same name, stop after the first one found.
# The order is first look in the install dir, then in a parallel dir in the
# source tree, (up one or two levels), then in the current dir.
#
proc load_lib { file } {
    global verbose libdir srcdir base_dir execpath tool
    global loaded_libs

    if [info exists loaded_libs($file)] {
        return;
    }

    set loaded_libs($file) "";

    if { [search_and_load_file "library file" $file [list $libdir $libdir/lib 
[file dirname [file dirname $srcdir]]/dejagnu/lib $srcdir/lib . [file dirname 
[file dirname [file dirname $srcdir]]]/dejagnu/lib]] == 0 } {
        send_error "ERROR: Couldn't find library file $file.\n"
        exit 1
    }
}

verbose "Login name is $logname"

#
# Begin sourcing the config files.
# All are sourced in order.
#
# Search order:
#       $HOME/.dejagnurc -> $base_dir/$configfile -> $objdir/$configfile
#       -> installed -> $DEJAGNU
#
# ??? It might be nice to do $HOME last as it would allow it to be the
# ultimate override.  Though at present there is still $DEJAGNU.
#
# For the normal case, we rely on $base_dir/$configfile to set
# host_triplet and target_triplet.
#

load_file ~/.dejagnurc $base_dir/$configfile

#
# If objdir didn't get set in $base_dir/$configfile, set it to $base_dir.
# Make sure we source $objdir/$configfile in case $base_dir/$configfile doesn't
# exist and objdir was given on the command line.
#

if [expr [string match "." $objdir] || [string match $srcdir $objdir]] {
    set objdir $base_dir
} else {
    load_file $objdir/$configfile
}

# Well, this just demonstrates the real problem...
if ![info exists tool_root_dir] {
    set tool_root_dir [file dirname $objdir];
    if [file exists "$tool_root_dir/testsuite"] {
        set tool_root_dir [file dirname $tool_root_dir];
    }
}

verbose "Using test sources in $srcdir"
verbose "Using test binaries in $objdir"
verbose "Tool root directory is $tool_root_dir"

set execpath [file dirname $argv0]
set libdir   [file dirname $execpath]/dejagnu
if [info exists env(DEJAGNULIBS)] {
    set libdir $env(DEJAGNULIBS)
}

verbose "Using $libdir to find libraries"

#
# If the host or target was given on the command line, override the above
# config files.  We allow $DEJAGNU to massage them though in case it would
# ever want to do such a thing.
#
if { $arg_host_triplet != "" } {
    set host_triplet $arg_host_triplet
}
if { $arg_build_triplet != "" } {
    set build_triplet $arg_build_triplet
}

# if we only specify --host, then that must be the build machne too, and we're
# stuck using the old functionality of a simple cross test
if [expr { $build_triplet == ""  &&  $host_triplet != "" } ] {
    set build_triplet $host_triplet
}
# if we only specify --build, then we'll use that as the host too
if [expr { $build_triplet != "" && $host_triplet == "" } ] {
    set host_triplet $build_triplet
}
unset arg_host_triplet arg_build_triplet

#
# If the build machine type hasn't been specified by now, use config.guess.
#

if [expr  { $build_triplet == ""  &&  $host_triplet == ""} ] {
    # find config.guess
    foreach dir "$libdir $libdir/libexec $libdir/.. $srcdir/.. $srcdir/../.." {
        verbose "Looking for ${dir}/config.guess" 2
        if [file exists ${dir}/config.guess] {
            set config_guess ${dir}/config.guess
            verbose "Found ${dir}/config.guess"
            break
        }
    }
    
    # get the canonical config name
    if ![info exists config_guess] {
        send_error "ERROR: Couldn't find config.guess program.\n"
        exit 1
    }
    catch "exec $config_guess" build_triplet
    case $build_triplet in {
        { "No uname command or uname output not recognized" "Unable to guess 
system type" } {
            verbose "WARNING: Uname output not recognized"
            set build_triplet unknown
        }
    }
    verbose "Assuming build host is $build_triplet"
    if { $host_triplet == "" } {
        set host_triplet $build_triplet
    }

}

#
# Figure out the target. If the target hasn't been specified, then we have to
# assume we are native.
#
if { $arg_target_triplet != "" } {
    set target_triplet $arg_target_triplet
} elseif { $target_triplet == "" } {
    set target_triplet $build_triplet
    verbose "Assuming native target is $target_triplet" 2
}
unset arg_target_triplet
#
# Default target_alias to target_triplet.
#
if ![info exists target_alias] {
    set target_alias $target_triplet
}

proc get_local_hostname { } {
    if [catch "info hostname" hb] {
        set hb ""
    } else {
        regsub "\\..*$" $hb "" hb;
    }
    verbose "hostname=$hb" 3;
    return $hb;
}

#
# We put these here so that they can be overridden later by site.exp or
# friends.
# 
# Set up the target as machine NAME. We also load base-config.exp as a
# default configuration. The config files are sourced with the global
# variable $board set to the name of the current target being defined.
#
proc setup_target_hook { whole_name name } {
    global board;
    global host_board;

    if [info exists host_board] {
        set hb $host_board;
    } else {
        set hb [get_local_hostname];
    }

    set board $whole_name;

    global board_type;
    set board_type "target";

    load_config base-config.exp;
    if ![load_board_description ${name} ${whole_name} ${hb}] {
        if { $name != "unix" } {
            perror "couldn't load description file for ${name}";
            exit 1;
        } else {
            load_generic_config "unix"
        }
    }

    if [board_info $board exists generic_name] {
        load_tool_target_config [board_info $board generic_name];
    }

    unset board;
    unset board_type;

    push_target $whole_name;

    if { [info procs ${whole_name}_init] != "" } {
        ${whole_name}_init $whole_name;
    }

    if { ![isnative] && ![is_remote target] } {
        global env build_triplet target_triplet
        if { (![info exists env(DEJAGNU)]) && ($build_triplet != 
$target_triplet) } {
            warning "Assuming target board is the local machine (which is 
probably wrong).\nYou may need to set your DEJAGNU environment variable."
        }
    }
}

#
# Clean things up afterwards.
#
proc cleanup_target_hook { name } {
    global tool;
    # Clean up the target board.
    if { [info procs "${name}_exit"] != "" } {
        ${name}_exit;
    }
    # We also call the tool exit routine here.
    if [info exists tool] {
        if { [info procs "${tool}_exit"] != "" } {
            ${tool}_exit;
        }
    }
    remote_close target;
    pop_target;
}

proc setup_host_hook { name } {
    global board;
    global board_info;
    global board_type;

    set board $name;
    set board_type "host";

    load_board_description $name;
    unset board;
    unset board_type;
    push_host $name;
    if { [info proc ${name}_init] != "" } {
        ${name}_init $name;
    }
}

proc setup_build_hook { name } {
    global board;
    global board_info;
    global board_type;

    set board $name;
    set board_type "build";

    load_board_description $name;
    unset board;
    unset board_type;
    push_build $name;
    if { [info proc ${name}_init] != "" } {
        ${name}_init $name;
    }
}

#
# Find and load the global config file if it exists.
# The global config file is used to set the connect mode and other
# parameters specific to each particular target.
# These files assume the host and target have been set.
#

if { [load_file -- $libdir/$configfile] == 0 } {
    # If $DEJAGNU isn't set either then there isn't any global config file.
    # Warn the user as there really should be one.
    if { ! [info exists env(DEJAGNU)] } {
        send_error "WARNING: Couldn't find the global config file.\n"
    }
}

if [info exists env(DEJAGNU)] {
    if { [load_file -- $env(DEJAGNU)] == 0 } {
        # It may seem odd to only issue a warning if there isn't a global
        # config file, but issue an error if $DEJAGNU is erroneously defined.
        # Since $DEJAGNU is set there is *supposed* to be a global config file,
        # so the current behaviour seems reasonable.
        send_error "WARNING: global config file $env(DEJAGNU) not found.\n"
    }
    if ![info exists boards_dir] {
        set boards_dir "[file dirname $env(DEJAGNU)]/boards";
    }
}

if ![info exists boards_dir] {
    set boards_dir ""
}

#
# parse out the config parts of the triplet name
#

# build values
if { $build_cpu == "" } {
    regsub -- "-.*-.*" ${build_triplet} "" build_cpu
}
if { $build_vendor == "" } {
    regsub -- "^\[a-z0-9\]*-" ${build_triplet} "" build_vendor
    regsub -- "-.*" ${build_vendor} "" build_vendor
}
if { $build_os == "" } {
    regsub -- ".*-.*-" ${build_triplet} "" build_os
}

# host values
if { $host_cpu == "" } {
    regsub -- "-.*-.*" ${host_triplet} "" host_cpu
}
if { $host_vendor == "" } {
    regsub -- "^\[a-z0-9\]*-" ${host_triplet} "" host_vendor
    regsub -- "-.*" ${host_vendor} "" host_vendor
}
if { $host_os == "" } {
    regsub -- ".*-.*-" ${host_triplet} "" host_os
}

# target values
if { $target_cpu == "" } {
    regsub -- "-.*-.*" ${target_triplet} "" target_cpu
}
if { $target_vendor == "" } {
    regsub -- "^\[a-z0-9\]*-" ${target_triplet} "" target_vendor
    regsub -- "-.*" ${target_vendor} "" target_vendor
}
if { $target_os == "" } {
    regsub -- ".*-.*-" ${target_triplet} "" target_os
}

#
# Load the primary tool initialization file.
#

proc load_tool_init { file } {
    global srcdir
    global loaded_libs

    if [info exists loaded_libs($file)] {
        return;
    }

    set loaded_libs($file) "";

    if [file exists ${srcdir}/lib/$file] {
        verbose "Loading library file ${srcdir}/lib/$file"
        if { [catch "uplevel #0 source ${srcdir}/lib/$file"] == 1 } {
            send_error "ERROR: tcl error sourcing library file 
${srcdir}/lib/$file.\n"
            global errorInfo
            if [info exists errorInfo] {
                send_error "$errorInfo\n"
            }
            exit 1
        }
    } else {
        warning "Couldn't find tool init file"
    }
}

#
# load the testing framework libraries
#
load_lib utils.exp
load_lib framework.exp
load_lib debugger.exp
load_lib remote.exp
load_lib target.exp
load_lib targetdb.exp
load_lib libgloss.exp

# Initialize the test counters and reset them to 0.
init_testcounts;
reset_vars;

#
# Parse the command line arguments.
#

# Load the tool initialization file. Allow the --tool option to override
# what's set in the site.exp file.
if [info exists comm_line_tool] {
    set tool $comm_line_tool;
}

if [info exists tool] {
    load_tool_init ${tool}.exp;
}

set argc [ llength $argv ]
for { set i 0 } { $i < $argc } { incr i } {
    set option [ lindex $argv $i ]

    # make all options have two hyphens
    switch -glob -- $option {
        "--*" {
        }
        "-*" {
            set option "-$option"
        }
    }

    # split out the argument for options that take them
    switch -glob -- $option {
        "--*=*" {
            regexp {^[^=]*=(.*)$} $option nil optarg
        }
        "--bu*" -
        "--ho*" -
        "--ig*"  -
        "--m*"  -
        "--n*"  -
        "--ob*" -
        "--ou*" -
        "--sr*" -
        "--st*" -
        "--ta*" -
        "--di*" -
        "--to*" {
            incr i
            set optarg [lindex $argv $i]
        }
    }

    switch -glob -- $option {
        "--V*" -
        "--vers*" {                     # (--version) version numbers
            send_user "Expect version is\t[exp_version]\n"
            send_user "Tcl version is\t\t[ info tclversion ]\n"
            send_user "Framework version is\t$frame_version\n"
            exit
        }

        "--v*" {                        # (--verbose) verbose output
            # Already parsed.
            continue
        }

        "--bu*" {                       # (--build) the build host configuration
            # Already parsed (and don't set again).  Let $DEJAGNU rename it.
            continue
        }
        
        "--ho*" {                       # (--host) the host configuration
            # Already parsed (and don't set again).  Let $DEJAGNU rename it.
            continue
        }

        "--target_bo*" {
            # Set it again, father knows best.
            set target_list $optarg;
            continue;
        }
        
        "--ta*" {                       # (--target) the target configuration
            # Already parsed (and don't set again).  Let $DEJAGNU rename it.
            continue
        }

        "--a*" {                        # (--all) print all test output to 
screen
            set all_flag 1
            verbose "Print all test output to screen"
            continue
        }
        
        "--di*" {
            # Already parsed (and don't set again).  Let $DEJAGNU rename it.
            # set cmdline_dir_to_run $optarg
            continue
        }

        
        "--de*" {                       # (--debug) expect internal debugging
            if [file exists ./dbg.log] {
                catch "exec rm -f ./dbg.log"
            }
            if { $verbose > 2 } {
                exp_internal -f dbg.log 1
            } else {
                exp_internal -f dbg.log 0
            }
            verbose "Expect Debugging is ON"
            continue
        }
        
        "--D[01]" {                     # (-Debug) turn on Tcl debugger
            verbose "Tcl debugger is ON"
            continue
        }
        
        "--m*" {                        # (--mail) mail the output
            set mailing_list $optarg
            set mail_logs 1
            verbose "Mail results to $mailing_list"
            continue
        }
        
        "--r*" {                        # (--reboot) reboot the target
            set reboot 1
            verbose "Will reboot the target (if supported)"
            continue
        }
        
        "--ob*" {                       # (--objdir) where the test case object 
code lives
            # Already parsed, but parse again to make sure command line
            # options override any config file.
            set objdir $optarg
            verbose "Using test binaries in $objdir"
            continue
        }
        
        "--ou*" {                       # (--outdir) where to put the output 
files
            set outdir $optarg
            verbose "Test output put in $outdir"
            continue
        }
        
        "*.exp" {                       #  specify test names to run
            set all_runtests($option) ""
            verbose "Running only tests $option"
            continue
        }

        "*.exp=*" {                     #  specify test names to run
            set tmp [split $option "="]
            set all_runtests([lindex $tmp 0]) [lindex $tmp 1]
            verbose "Running only tests $option"
            unset tmp
            continue
        }
        
        "--ig*" {                       #  (--ignore) specify test names to 
exclude
            set ignoretests $optarg
            verbose "Ignoring test $ignoretests"
            continue
        }

        "--sr*" {                       # (--srcdir) where the testsuite source 
code lives
            # Already parsed, but parse again to make sure command line
            # options override any config file.
            
            set srcdir $optarg
            continue
        }
        
        "--st*" {                       # (--strace) expect trace level
            set tracelevel $optarg
            strace $tracelevel
            verbose "Source Trace level is now $tracelevel"
            continue
        }
        
        "--tool_opt*" {
            continue
        }

        "--tool_exec*" {
            set TOOL_EXECUTABLE $optarg
            continue
        }

        "--tool_ro*" {
            set tool_root_dir $optarg
            continue;
        }

        "--to*" {                       # (--tool) specify tool name
            set tool $optarg
            verbose "Testing $tool"
            continue
        }
        "--x*" {
            set xml 1
            verbose "XML logging turned on"
            continue
        }

        "[A-Z0-9_-.]*=*" { # process makefile style args like CC=gcc, etc...
            if [regexp "^(\[A-Z0-9_-\]+)=(.*)$" $option junk var val] {
                set $var $val
                verbose "$var is now $val"
                append makevars "set $var $val;" ;# FIXME: Used anywhere?
                unset junk var val
            } else {
                send_error "Illegal variable specification:\n"
                send_error "$option\n"
            }
            continue
        }

        "--he*" {                       # (--help) help text
            usage;
            exit 0      
        }

        default {
            if [info exists tool] {
                if { [info proc ${tool}_option_proc] != "" } {
                    if [${tool}_option_proc $option] {
                        continue;
                    }
                }
            }
            send_error "\nIllegal Argument \"$option\"\n"
            send_error "try \"runtest --help\" for option list\n"
            exit 1
        }
    }
}

#
# check for a few crucial variables
#
if ![info exists tool] {
    send_error "WARNING: No tool specified\n"
    set tool ""
}

#
# initialize a few Tcl variables to something other than their default
#
if { $verbose > 2 } {
    log_user 1
} else {
    log_user 0
}

set timeout 10



#
# open log files
#
open_logs

# print the config info
clone_output "Test Run By $logname on [timestamp -format %c]"
if [is3way]  {
    clone_output "Target is $target_triplet"
    clone_output "Host   is $host_triplet"  
    clone_output "Build  is $build_triplet"
} else {
    if [isnative] {
        clone_output "Native configuration is $target_triplet"
    } else {
        clone_output "Target is $target_triplet"
        clone_output "Host   is $host_triplet"
    }
}

clone_output "\n\t\t=== $tool tests ===\n"

#
# Look for the generic board configuration file. It searches in several
# places: ${libdir}/config, ${libdir}/../config, and $boards_dir.
#

proc load_generic_config { name } {
    global srcdir;
    global configfile;
    global libdir;
    global env;
    global board;
    global board_info;
    global boards_dir;
    global board_type;

    if [info exists board] {
        if ![info exists board_info($board,generic_name)] {
            set board_info($board,generic_name) $name;
        }
    }

    if [info exists board_type] {
        set type "for $board_type";
    } else {
        set type ""
    }

    set dirlist [concat ${libdir}/config [file dirname $libdir]/config 
$boards_dir];
    set result [search_and_load_file "generic interface file $type" ${name}.exp 
$dirlist];

    return $result;
}

#
# Load the tool-specific target description.
#
proc load_config { args } {
    global srcdir;
    global board_type;

    set found 0;

    return [search_and_load_file "tool-and-target-specific interface file" 
$args [list ${srcdir}/config ${srcdir}/../config ${srcdir}/../../config 
${srcdir}/../../../config]];
}

#
# Find the files that set up the configuration for the target. There
# are assumed to be two of them; one defines a basic set of
# functionality for the target that can be used by all tool
# testsuites, and the other defines any necessary tool-specific
# functionality. These files are loaded via load_config.  
#
# These used to all be named $target_abbrev-$tool.exp, but as the
# $tool variable goes away, it's now just $target_abbrev.exp.  First
# we look for a file named with both the abbrev and the tool names.
# Then we look for one named with just the abbrev name. Finally, we
# look for a file called default, which is the default actions, as
# some tools could be purely host based. Unknown is mostly for error
# trapping.
#

proc load_tool_target_config { name } {
    global target_os

    set found [load_config "${name}.exp" "${target_os}.exp" "default.exp" 
"unknown.exp"];

    if { $found == 0 } {
        send_error "ERROR: Couldn't find tool config file for $name.\n"
    }
}


#
# Find the file that describes the machine specified by board_name.
#

proc load_board_description { board_name args } {
    global srcdir;
    global configfile;
    global libdir;
    global env;
    global board;
    global board_info
    global boards_dir;
    global board_type;

    set dejagnu ""

    if { [llength $args] > 0 } {
        set whole_name [lindex $args 0];
    } else {
        set whole_name $board_name;
    }

    set board_info($whole_name,name) $whole_name;
    if ![info exists board] {
        set board $whole_name;
        set board_set 1;
    } else {
        set board_set 0;
    }

    set dirlist {};
    if { [llength $args] > 1 } {
        set suffix [lindex $args 1];
        if { ${suffix} != "" } {
            foreach x ${boards_dir} {
                lappend dirlist ${x}/${suffix}
            }
            lappend dirlist ${libdir}/baseboards/${suffix};
        }
    }
    set dirlist [concat $dirlist $boards_dir];
    lappend dirlist ${libdir}/baseboards;
    verbose "dirlist is $dirlist"
    if [info exists board_type] {
        set type "for $board_type";
    } else {
        set type "";
    }
    if ![info exists board_info($whole_name,isremote)] {
        set board_info($whole_name,isremote) 1;
        if [info exists board_type] {
            if { $board_type == "build" } {
                set board_info($whole_name,isremote) 0;
            }
        }
        if { ${board_name} == [get_local_hostname] } {
            set board_info($whole_name,isremote) 0;
        }
    }
    search_and_load_file "standard board description file $type" standard.exp 
$dirlist;
    set found [search_and_load_file "board description file $type" 
${board_name}.exp $dirlist];
    if { $board_set != 0 } {
        unset board;
    }

    return $found;
}

#
# Find the base-level file that describes the machine specified by args. We
# only look in one directory, ${libdir}/baseboards.
#

proc load_base_board_description { board_name } {
    global srcdir;
    global configfile;
    global libdir;
    global env;
    global board;
    global board_info
    global board_type;

    set board_set 0;
    set board_info($board_name,name) $board_name;
    if ![info exists board] {
        set board $board_name;
        set board_set 1;
    }
    if [info exists board_type] {
        set type "for $board_type";
    } else {
        set type ""
    };
    if ![info exists board_info($board_name,isremote)] {
        set board_info($board_name,isremote) 1;
        if [info exists board_type] {
            if { $board_type == "build" } {
                set board_info($board_name,isremote) 0;
            }
        }
    }

    if { ${board_name} == [get_local_hostname] } {
        set board_info($board_name,isremote) 0;
    }
    set found [search_and_load_file "board description file $type" 
${board_name}.exp ${libdir}/baseboards];
    if { $board_set != 0 } {
        unset board;
    }

    return $found;
}

#
# Source the testcase in TEST_FILE_NAME.
#

proc runtest { test_file_name } {
    global prms_id
    global bug_id
    global test_result
    global errcnt
    global errorInfo
    global tool

    clone_output "Running $test_file_name ..."
    set prms_id 0
    set bug_id  0
    set test_result ""

    if [file exists $test_file_name] {
        set timestart [timestamp];

        if [info exists tool] {
            if { [info procs "${tool}_init"] != "" } {
                ${tool}_init $test_file_name;
            }
        }

        if { [catch "uplevel #0 source $test_file_name"] == 1 } {
            # We can't call `perror' here, it resets `errorInfo'
            # before we want to look at it.  Also remember that perror
            # increments `errcnt'.  If we do call perror we'd have to
            # reset errcnt afterwards.   
            clone_output "ERROR: tcl error sourcing $test_file_name."
            if [info exists errorInfo] {
                clone_output "ERROR: $errorInfo"
                unset errorInfo
            }
        }

        if [info exists tool] {
            if { [info procs "${tool}_finish"] != "" } {
                ${tool}_finish;
            }
        }
        set timeend [timestamp];
        set timediff [expr $timeend - $timestart];
        verbose -log "testcase $test_file_name completed in $timediff seconds" 4
    } else {
        # This should never happen, but maybe if the file got removed
        # between the `find' above and here.
        perror "$test_file_name does not exist."
        # ??? This is a hack.  We want to send a message to stderr and
        # to the summary file (just like perror does), but we don't
        # want the next testcase to get a spurious "unresolved" because
        # errcnt != 0.  Calling `clone_output' is also supposed to be a
        # no-no (see the comments for clone_output).
        set errcnt 0
    }
}

#
# Trap some signals so we know what's happening.  These replace the previous
# ones because we've now loaded the library stuff.
#
if ![exp_debug] {
    foreach sig "{SIGTERM {terminated}} \
             {SIGINT  {interrupted by user}} \
             {SIGQUIT {interrupted by user}} \
             {SIGSEGV {segmentation violation}}" {
         set signal [lindex $sig 0];
         set str [lindex $sig 1];
         trap "send_error \"got a \[trap -name\] signal, $str \\n\"; 
log_and_exit;" $signal;
         verbose "setting trap for $signal to $str" 1
    }
    unset signal str sig;
}

#
# Given a list of targets, process any iterative lists.
# 
proc process_target_variants { target_list } {
    set result {};
    foreach x $target_list {
        if [regexp "\\(" $x] {
            regsub "^.*\\((\[^()\]*)\\)$" "$x" "\\1" variant_list;
            regsub "\\(\[^(\]*$" "$x" "" x;
            set list [process_target_variants $x];
            set result {}
            foreach x $list {
                set result [concat $result [iterate_target_variants $x [split 
$variant_list ","]]];
            }
        } elseif [regexp "\{" $x] {
            regsub "^.*\{(\[^\{\}\]*)\}$" "$x" "\\1" variant_list;
            regsub "\{\[^\{\]*$" "$x" "" x;
            set list [process_target_variants $x];
            foreach x $list {
                foreach i [split $variant_list ","] {
                    set name $x;
                    if { $i != "" } {
                        append name "/" $i;
                    }
                    lappend result $name;
                }
            }
        } else {
            lappend result "$x";
        }
    }
    return $result;
}

proc iterate_target_variants { target variants } {
    return [iterate_target_variants_two $target $target $variants];
}

#
# Given a list of variants, produce the list of all possible combinations.
#
proc iterate_target_variants_two { orig_target target variants } {

    if { [llength $variants] == 0 } {
        return [list $target];
    } else {
        if { [llength $variants] > 1 } {
            set result [iterate_target_variants_two $orig_target $target 
[lrange $variants 1 end]];
        } else {
            if { $target != $orig_target } {
                set result [list $target];
            } else {
                set result {};
            }
        }
        if { [lindex $variants 0] != "" } {
            append target "/" [lindex $variants 0];
            return [concat $result [iterate_target_variants_two $orig_target 
$target [lrange $variants 1 end]]];
        } else {
            return [concat $result $target];
        }
    }
}

setup_build_hook [get_local_hostname];

if [info exists host_board] {
    setup_host_hook $host_board;
} else {
    set hb [get_local_hostname];
    if { $hb != "" } {
        setup_host_hook $hb;
    }
}

#
# main test execution loop
#

if [info exists errorInfo] {
    unset errorInfo
}
# make sure we have only single path delimiters
regsub -all "\(\[^/\]\)//*" $srcdir "\\1/" srcdir

if ![info exists target_list] {
# Make sure there is at least one target machine. It's probably a Unix box,
# but that's just a guess.
    set target_list { "unix" }
} else {
    verbose "target list is $target_list"
}

#
# Iterate through the list of targets.
#
global current_target;

set target_list [process_target_variants $target_list];

set target_count [llength $target_list]

clone_output "Schedule of variations:"
foreach current_target $target_list {
    clone_output "    $current_target"
}
clone_output ""


foreach current_target $target_list {
    verbose "target is $current_target";
    set current_target_name $current_target;
    set tlist [split $current_target /];
    set current_target [lindex $tlist 0];
    set board_variant_list [lrange $tlist 1 end];

    # Set the counts for this target to 0.
    reset_vars;
    clone_output "Running target $current_target_name"

    setup_target_hook $current_target_name $current_target;

# If multiple passes requested, set them up.  Otherwise prepare just one.
# The format of `MULTIPASS' is a list of elements containing
# "{ name var1=value1 ... }" where `name' is a generic name for the pass and
# currently has no other meaning.

    global env

    if { [info exists MULTIPASS] } {
        set multipass $MULTIPASS
    }
    if { $multipass == "" } {
        set multipass { "" }
    }

# If PASS is specified, we want to run only the tests specified.
# Its value should be a number or a list of numbers that specify
# the passes that we want to run.
    if [info exists PASS] {
        set pass $PASS
    } else {
        set pass ""
    }

    if {$pass != ""} {
        set passes [list]
        foreach p $pass {
            foreach multipass_elem $multipass {
                set multipass_name [lindex $multipass_elem 0]
                if {$p == $multipass_name} {
                    lappend passes $multipass_elem
                    break;
                }
            }
        }
        set multipass $passes
    }

    foreach pass $multipass {

        # multipass_name is set for `record_test' to use (see framework.exp).
        if { [lindex $pass 0] != "" } {
            set multipass_name [lindex $pass 0]
            clone_output "Running pass `$multipass_name' ..."
        } else {
            set multipass_name ""
        }
        set restore ""
        foreach varval [lrange $pass 1 end] {
            set tmp [string first "=" $varval]
            set var [string range $varval 0 [expr $tmp - 1]]
            # Save previous value.
            if [info exists $var] {
                lappend restore "$var [list [eval concat \$$var]]"
            } else {
                lappend restore "$var"
            }
            # Handle "CFLAGS=$CFLAGS foo".
            # FIXME: Do we need to `catch' this?
            eval set $var \[string range \"$varval\" [expr $tmp + 1] end\]
            verbose "$var is now [eval concat \$$var]"
            unset tmp var
        }

        # look for the top level testsuites. if $tool doesn't
        # exist and there are no subdirectories in $srcdir, then
        # we default to srcdir.
        set test_top_dirs [lsort [getdirs -all ${srcdir} "${tool}*"]]
        if { ${test_top_dirs} == "" } {
            set test_top_dirs ${srcdir}
        } else {
            # JYG:
            # DejaGNU's notion of test tree and test files is very
            # general:
            # given ${srcdir} and ${tool}, any subdirectory (at any
            # level deep) with the "${tool}" prefix starts a test tree;
            # given a test tree, any *.exp file underneath (at any
            # level deep) is a test file.
            #
            # For test tree layouts with ${tool} prefix on
            # both a parent and a child directory, we need to eliminate
            # the child directory entry from test_top_dirs list.
            # e.g. gdb.hp/gdb.base-hp/ would result in two entries
            # in the list: gdb.hp, gdb.hp/gdb.base-hp.
            # If the latter not eliminated, test files under
            # gdb.hp/gdb.base-hp would be run twice (since test files
            # are gathered from all sub-directories underneath a
            # directory).
            #
            # Since ${tool} may be g++, etc. which could confuse
            # regexp, we cannot do the simpler test:
            #     ...
            #     if [regexp "${srcdir}/.*${tool}.*/.*${tool}.*" ${dir}]
            #     ...
            # instead, we rely on the fact that test_top_dirs is
            # a sorted list of entries, and any entry that contains
            # the previous valid test top dir entry in its own pathname
            # must be excluded.

            set temp_top_dirs ""
            set prev_dir ""
            foreach dir "${test_top_dirs}" {
                if { [string length ${prev_dir}] == 0 ||
                     [string first "${prev_dir}/" ${dir}] == -1} {
                    # the first top dir entry, or an entry that
                    # does not share the previous entry's entire
                    # pathname, record it as a valid top dir entry.
                    #
                    lappend temp_top_dirs ${dir}
                    set prev_dir ${dir}
                }
            }
            set test_top_dirs ${temp_top_dirs}
        }
        verbose "Top level testsuite dirs are ${test_top_dirs}" 2
        set testlist "";
        if [info exists all_runtests] {
            foreach x [array names all_runtests] {
                verbose "trying to glob ${srcdir}/${x}" 2
                set s [glob -nocomplain ${srcdir}/$x];
                if { $s != "" } {
                    set testlist [concat $testlist $s];
                }
            }
        }
        #
        # If we have a list of tests, run all of them.
        #
        if { $testlist != "" } {
            foreach test_name $testlist {
                if { ${ignoretests} != "" } {
                    if { 0 <= [lsearch ${ignoretests} [file tail 
${test_name}]]} {
                        continue
                    }
                }

                # set subdir to the tail of the dirname after $srcdir,
                # for the driver files that want it.  XXX this is silly.
                # drivers should get a single var, not "$srcdir/$subdir"
                set subdir [file dirname $test_name]
                set p [expr [string length $srcdir]-1]
                while {0 < $p && [string index $srcdir $p] == "/"} {
                    incr p -1
                }
                if {[string range $subdir 0 $p] == $srcdir} {
                    set subdir [string range $subdir [expr $p+1] end];
                    regsub "^/" $subdir "" subdir
                }

                # XXX not the right thing to do.
                set runtests [list [file tail $test_name] ""]

                runtest $test_name;
            }
        } else {
            #
            # Go digging for tests.
            #
            foreach dir "${test_top_dirs}" {
                if { ${dir} != ${srcdir} } {
                    # Ignore this directory if is a directory to be
                    # ignored.
                    if {[info exists ignoredirs] && $ignoredirs != ""} {
                        set found 0
                        foreach directory $ignoredirs {
                            if [string match "*${directory}*" $dir] {
                                set found 1
                                break
                            }
                        }
                        if {$found} {
                            continue
                        }
                    }

                    # Run the test if dir_to_run was specified as a
                    # value (for example in MULTIPASS) and the test
                    # directory matches that directory.
                    if {[info exists dir_to_run] && $dir_to_run != ""} {
                        # JYG: dir_to_run might be a space delimited list
                        # of directories.  Look for match on each item.
                        set found 0
                        foreach directory $dir_to_run {
                            if [string match "*${directory}*" $dir] {
                                set found 1
                                break
                            }
                        }
                        if {!$found} {
                            continue
                        }
                    }

                    # Run the test if cmdline_dir_to_run was specified
                    # by the user using --directory and the test
                    # directory matches that directory
                    if {[info exists cmdline_dir_to_run] \
                            && $cmdline_dir_to_run != ""} {
                        # JYG: cmdline_dir_to_run might be a space delimited
                        # list of directories.  Look for match on each item.
                        set found 0
                        foreach directory $cmdline_dir_to_run {
                            if [string match "*${directory}*" $dir] {
                                set found 1
                                break
                            }
                        }
                        if {!$found} {
                            continue
                        }
                    }

                    foreach test_name [lsort [find ${dir} *.exp]] {
                        if { ${test_name} == "" } {
                            continue
                        }
                        # Ignore this one if asked to.
                        if { ${ignoretests} != "" } {
                            if { 0 <= [lsearch ${ignoretests} [file tail 
${test_name}]]} {
                                continue
                            }
                        }

                        # Get the path after the $srcdir so we know
                        # the subdir we're in.
                        set subdir [file dirname $test_name]
                        # We used to do
                        # regsub $srcdir [file dirname $test_name] "" subdir
                        # but what if [file dirname $test_name] contains regexp
                        # characters? We lose. Instead...
                        set first [string first $srcdir $subdir]
                        if { $first >= 0 } {
                            set first [expr $first + [string length $srcdir]];
                            set subdir [string range $subdir $first end];
                            regsub "^/" "$subdir" "" subdir;
                        }
                        if { "$srcdir" == "$subdir" || "$srcdir" == "$subdir/" 
} {
                            set subdir ""
                        }
                        # Check to see if the range of tests is limited,
                        # set `runtests' to a list of two elements: the script 
name
                        # and any arguments ("" if none).
                        if [info exists all_runtests] {
                            verbose "searching for $test_name in [array names 
all_runtests]"
                            if { 0 > [lsearch [array names all_runtests] [file 
tail $test_name]]} {
                                if { 0 > [lsearch [array names all_runtests] 
$test_name] } {
                                    continue
                                }
                            }
                            set runtests [list [file tail $test_name] 
$all_runtests([file tail $test_name])]
                        } else {
                            set runtests [list [file tail $test_name] ""]
                        }
                        runtest $test_name;
                    }
                }
            }
            # Restore the variables set by this pass.
            foreach varval $restore {
                if { [llength $varval] > 1 } {
                    verbose "Restoring [lindex $varval 0] to [lindex $varval 
1]" 4;
                    set [lindex $varval 0] [lindex $varval 1];
                } else {
                    verbose "Restoring [lindex $varval 0] to `unset'" 4;
                    unset [lindex $varval 0];
                }
            }
        }
    }
    cleanup_target_hook $current_target;
    if { $target_count > 1 } {
        log_summary;
    }
}

log_and_exit;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]