1# Test Framework Driver
2# Copyright (C) 1992 - 2002, 2003 Free Software Foundation, Inc.
3
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program; if not, write to the Free Software
16# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18# Please email any bugs, comments, and/or additions to this file to:
19# bug-dejagnu@gnu.org
20
21# This file was written by Rob Savoye. (rob@welcomehome.org)
22
23set frame_version	1.4.4
24if ![info exists argv0] {
25    send_error "Must use a version of Expect greater than 5.0\n"
26    exit 1
27}
28
29#
30# trap some signals so we know whats happening. These definitions are only
31# temporary until we read in the library stuff
32#
33trap { send_user "\nterminated\n";             exit 1 } SIGTERM
34trap { send_user "\ninterrupted by user\n";    exit 1 } SIGINT
35trap { send_user "\nsigquit\n";                exit 1 } SIGQUIT
36
37#
38# Initialize a few global variables used by all tests.
39# `reset_vars' resets several of these, we define them here to document their
40# existence.  In fact, it would be nice if all globals used by some interface
41# of dejagnu proper were documented here.
42#
43# Keep these all lowercase.  Interface variables used by the various
44# testsuites (eg: the gcc testsuite) should be in all capitals
45# (eg: TORTURE_OPTIONS).
46#
47set mail_logs   0		;# flag for mailing of summary and diff logs
48set psum_file   "latest"	;# file name of previous summary to diff against
49
50set exit_status	0		;# exit code returned by this program
51
52set xfail_flag  0		;# indicates that a failure is expected
53set xfail_prms	0		;# GNATS prms id number for this expected failure
54set kfail_flag  0		;# indicates that it is a known failure
55set kfail_prms	0		;# bug id for the description of the known failure
56set sum_file	""		;# name of the file that contains the summary log
57set base_dir	""		;# the current working directory
58set xml_file    ""              ;# name of the xml output if requested
59set xml         0               ;# flag for requesting xml
60set logname     ""		;# the users login name
61set prms_id	0               ;# GNATS prms id number
62set bug_id	0               ;# optional bug id number
63set dir		""		;# temp variable for directory names
64set srcdir      "."		;# source directory containing the test suite
65set ignoretests ""		;# list of tests to not execute
66set objdir	"."		;# directory where test case binaries live
67set reboot      0
68set configfile  site.exp	;# (local to this file)
69set multipass   ""		;# list of passes and var settings
70set errno	"";		;#
71set exit_error  0		;# Toggle for whether to set the exit status
72;# on Tcl bugs in test case drivers.
73#
74# These describe the host and target environments.
75#
76set build_triplet  ""		;# type of architecture to run tests on
77set build_os	   ""		;# type of os the tests are running on
78set build_vendor   ""		;# vendor name of the OS or workstation the test are running on
79set build_cpu      ""		;# type of the cpu tests are running on
80set host_triplet   ""		;# type of architecture to run tests on, sometimes remotely
81set host_os	   ""		;# type of os the tests are running on
82set host_vendor    ""		;# vendor name of the OS or workstation the test are running on
83set host_cpu       ""		;# type of the cpu tests are running on
84set target_triplet ""		;# type of architecture to run tests on, final remote
85set target_os	   ""		;# type of os the tests are running on
86set target_vendor  ""		;# vendor name of the OS or workstation the test are running on
87set target_cpu     ""		;# type of the cpu tests are running on
88set target_alias   ""		;# standard abbreviation of target
89set compiler_flags ""		;# the flags used by the compiler
90
91#
92# some convenience abbreviations
93#
94if ![info exists hex] {
95    set hex "0x\[0-9A-Fa-f\]+"
96}
97if ![info exists decimal] {
98    set decimal "\[0-9\]+"
99}
100
101#
102# set the base dir (current working directory)
103#
104set base_dir [pwd]
105
106#
107# These are tested in case they are not initialized in $configfile. They are
108# tested here instead of the init module so they can be overridden by command
109# line options.
110#
111if ![info exists all_flag] {
112    set all_flag 0
113}
114if ![info exists binpath] {
115    set binpath ""
116}
117if ![info exists debug] {
118    set debug 0
119}
120if ![info exists options] {
121    set options ""
122}
123if ![info exists outdir] {
124    set outdir "."
125}
126if ![info exists reboot] {
127    set reboot 1
128}
129if ![info exists tracelevel] {
130    set tracelevel 0
131}
132if ![info exists verbose] {
133    set verbose 0
134}
135
136#
137# verbose [-n] [-log] [--] message [level]
138#
139# Print MESSAGE if the verbose level is >= LEVEL.
140# The default value of LEVEL is 1.
141# "-n" says to not print a trailing newline.
142# "-log" says to add the text to the log file even if it won't be printed.
143# Note that the apparent behaviour of `send_user' dictates that if the message
144# is printed it is also added to the log file.
145# Use "--" if MESSAGE begins with "-".
146#
147# This is defined here rather than in framework.exp so we can use it
148# while still loading in the support files.
149#
150proc verbose { args } {
151    global verbose
152    set newline 1
153    set logfile 0
154
155    set i 0
156    if { [string index [lindex $args 0] 0] == "-" } {
157	for { set i 0 } { $i < [llength $args] } { incr i } {
158	    if { [lindex $args $i] == "--" } {
159		incr i
160		break
161	    } elseif { [lindex $args $i] == "-n" } {
162		set newline 0
163	    } elseif { [lindex $args $i] == "-log" } {
164		set logfile 1
165            } elseif { [lindex $args $i] == "-x" } {
166                set xml 1
167	    } elseif { [string index [lindex $args $i] 0] == "-" } {
168		clone_output "ERROR: verbose: illegal argument: [lindex $args $i]"
169		return
170	    } else {
171		break
172	    }
173	}
174	if { [llength $args] == $i } {
175	    clone_output "ERROR: verbose: nothing to print"
176	    return
177	}
178    }
179
180    set level 1
181    if { [llength $args] > $i + 1 } {
182	set level [lindex $args [expr $i+1]]
183    }
184    set message [lindex $args $i]
185
186    if { $verbose >= $level } {
187	# There is no need for the "--" argument here, but play it safe.
188	# We assume send_user also sends the text to the log file (which
189	# appears to be the case though the docs aren't clear on this).
190	if { $newline } {
191	    send_user -- "$message\n"
192	} else {
193	    send_user -- "$message"
194	}
195    } elseif { $logfile } {
196	if { $newline } {
197	    send_log "$message\n"
198	} else {
199	    send_log "$message"
200	}
201    }
202}
203
204#
205# Transform a tool name to get the installed name.
206# target_triplet is the canonical target name.  target_alias is the
207# target name used when configure was run.
208#
209proc transform { name } {
210    global target_triplet
211    global target_alias
212    global host_triplet
213    global board
214
215    if [string match $target_triplet $host_triplet] {
216	return $name
217    }
218    if [string match "native" $target_triplet] {
219	return $name
220    }
221    if [board_info host exists no_transform_name] {
222	return $name
223    }
224    if [string match "" $target_triplet] {
225	return $name
226    } else {
227	if [info exists board] {
228	    if [board_info $board exists target_install] {
229		set target_install [board_info $board target_install]
230	    }
231	}
232	if [target_info exists target_install] {
233	    set target_install [target_info target_install]
234	}
235	if [info exists target_alias] {
236	    set tmp ${target_alias}-${name}
237	} elseif [info exists target_install] {
238	    if { [lsearch -exact $target_install $target_alias] >= 0 } {
239		set tmp ${target_alias}-${name}
240	    } else {
241		set tmp "[lindex $target_install 0]-${name}"
242	    }
243	}
244	verbose "Transforming $name to $tmp"
245	return $tmp
246    }
247}
248
249#
250# findfile arg0 [arg1] [arg2]
251#
252# Find a file and see if it exists. If you only care about the false
253# condition, then you'll need to pass a null "" for arg1.
254#	arg0 is the filename to look for. If the only arg,
255#            then that's what gets returned. If this is the
256#            only arg, then if it exists, arg0 gets returned.
257#            if it doesn't exist, return only the prog name.
258#       arg1 is optional, and it's what gets returned if
259#	     the file exists.
260#       arg2 is optional, and it's what gets returned if
261#            the file doesn't exist.
262#
263proc findfile { args } {
264    # look for the file
265    verbose "Seeing if [lindex $args 0] exists." 2
266    if [file exists [lindex $args 0]] {
267	if { [llength $args] > 1 } {
268	    verbose "Found file, returning [lindex $args 1]"
269	    return [lindex $args 1]
270	} else {
271	    verbose "Found file, returning [lindex $args 0]"
272	    return [lindex $args 0]
273	}
274    } else {
275	if { [llength $args] > 2 } {
276	    verbose "Didn't find file [lindex $args 0], returning [lindex $args 2]"
277	    return [lindex $args 2]
278	} else {
279	    verbose "Didn't find file, returning [file tail [lindex $args 0]]"
280	    return [transform [file tail [lindex $args 0]]]
281	}
282    }
283}
284
285#
286# load_file [-1] [--] file1 [ file2 ... ]
287#
288# Utility to source a file.  All are sourced in order unless the flag "-1"
289# is given in which case we stop after finding the first one.
290# The result is 1 if a file was found, 0 if not.
291# If a tcl error occurs while sourcing a file, we print an error message
292# and exit.
293#
294# ??? Perhaps add an optional argument of some descriptive text to add to
295# verbose and error messages (eg: -t "library file" ?).
296#
297proc load_file { args } {
298    set i 0
299    set only_one 0
300    if { [lindex $args $i] == "-1" } {
301	set only_one 1
302	incr i
303    }
304    if { [lindex $args $i] == "--" } {
305	incr i
306    }
307
308    set found 0
309    foreach file [lrange $args $i end] {
310	verbose "Looking for $file" 2
311        # In Tcl7.5a2, "file exists" can fail if the filename looks
312	# like ~/FILE and the environment variable HOME does not
313	# exist.
314        if {! [catch {file exists $file} result] && $result} {
315	    set found 1
316	    verbose "Found $file"
317	    if { [catch "uplevel #0 source $file"] == 1 } {
318		send_error "ERROR: tcl error sourcing $file.\n"
319		global errorInfo
320		if [info exists errorInfo] {
321		    send_error "$errorInfo\n"
322		}
323		exit 1
324	    }
325	    if $only_one {
326		break
327	    }
328	}
329    }
330    return $found
331}
332
333#
334# search_and_load_file -- search DIRLIST looking for FILELIST.
335# TYPE is used when displaying error and progress messages.
336#
337proc search_and_load_file { type filelist dirlist } {
338    set found 0
339
340    foreach dir $dirlist {
341	foreach initfile $filelist {
342	    verbose "Looking for $type ${dir}/${initfile}" 2
343	    if [file exists ${dir}/${initfile}] {
344		set found 1
345		set error ""
346		if { ${type} != "library file" } {
347		    send_user "Using ${dir}/${initfile} as ${type}.\n"
348		} else {
349		    verbose "Loading ${dir}/${initfile}"
350		}
351		if [catch "uplevel #0 source ${dir}/${initfile}" error]==1 {
352		    global errorInfo
353		    send_error "ERROR: tcl error sourcing ${type} ${dir}/${initfile}.\n${error}\n"
354		    if [info exists errorInfo] {
355			send_error "$errorInfo\n"
356		    }
357		    exit 1
358		}
359		break
360	    }
361	}
362	if $found {
363	    break
364	}
365    }
366    return $found
367}
368
369#
370# Give a usage statement.
371#
372proc usage { } {
373    global tool
374
375    send_user "USAGE: runtest \[options...\]\n"
376    send_user "\t--all (-a)\t\tPrint all test output to screen\n"
377    send_user "\t--build \[string\]\tThe canonical config name of the build machine\n"
378    send_user "\t--host \[string\]\t\tThe canonical config name of the host machine\n"
379    send_user "\t--host_board \[name\]\tThe host board to use\n"
380    send_user "\t--target \[string\]\tThe canonical config name of the target board\n"
381    send_user "\t--status (-sta)\t\tSet the exit status to fail on Tcl errors\n"
382    send_user "\t--debug (-de)\t\tSet expect debugging ON\n"
383    send_user "\t--help (-he)\t\tPrint help text\n"
384    send_user "\t--mail \[name(s)\]\tWhom to mail the results to\n"
385    send_user "\t--ignore \[name(s)\]\tThe names of specific tests to ignore\n"
386    send_user "\t--objdir \[name\]\t\tThe test suite binary directory\n"
387    send_user "\t--outdir \[name\]\t\tThe directory to put logs in\n"
388    send_user "\t--reboot \[name\]\t\tReboot the target (if supported)\n"
389    send_user "\t--srcdir \[name\]\t\tThe test suite source code directory\n"
390    send_user "\t--strace \[number\]\tSet expect tracing ON\n"
391    send_user "\t--target_board \[name(s)\] The list of target boards to run tests on\n"
392    send_user "\t--tool\[name(s)\]\t\tRun tests on these tools\n"
393    send_user "\t--tool_exec \[name\]\tThe path to the tool executable to test\n"
394    send_user "\t--tool_opts \[options\]\tA list of additional options to pass to the tool\n"
395    send_user "\t--directory (-di) name\tRun only the tests in directory 'name'\n"
396    send_user "\t--verbose (-v)\t\tEmit verbose output\n"
397    send_user "\t--version (-V)\t\tEmit all version numbers\n"
398    send_user "\t--xml (-x)\t\tTurn on XML output generation\n"
399    send_user "\t--D\[0-1\]\t\tTcl debugger\n"
400    send_user "\tscript.exp\[=arg(s)\]\tRun these tests only\n"
401    if { [info exists tool] } {
402	if { [info proc ${tool}_option_help] != "" } {
403	    ${tool}_option_help
404	}
405    }
406}
407
408#
409# Parse the arguments the first time looking for these.  We will ultimately
410# parse them twice.  Things are complicated because:
411# - we want to parse --verbose early on
412# - we don't want config files to override command line arguments
413#   (eg: $base_dir/$configfile vs --host/--target)
414# - we need some command line arguments before we can process some config files
415#   (eg: --objdir before $objdir/$configfile, --host/--target before $DEJAGNU)
416# The use of `arg_host_triplet' and `arg_target_triplet' lets us avoid parsing
417# the arguments three times.
418#
419
420set arg_host_triplet ""
421set arg_target_triplet ""
422set arg_build_triplet ""
423set argc [ llength $argv ]
424for { set i 0 } { $i < $argc } { incr i } {
425    set option [lindex $argv $i]
426
427    # make all options have two hyphens
428    switch -glob -- $option {
429        "--*" {
430        }
431        "-*" {
432	    set option "-$option"
433        }
434    }
435
436    # split out the argument for options that take them
437    switch -glob -- $option {
438	"--*=*" {
439	    regexp {^[^=]*=(.*)$} $option nil optarg
440	}
441	"--bu*" -
442	"--ho*" -
443	"--ig*"  -
444	"--m*"  -
445	"--n*"  -
446	"--ob*" -
447	"--ou*" -
448	"--sr*" -
449	"--str*" -
450        "--ta*" -
451	"--di*" -
452	"--to*" {
453	    incr i
454	    set optarg [lindex $argv $i]
455	}
456    }
457
458    switch -glob -- $option {
459	"--bu*" {			# (--build) the build host configuration
460	    set arg_build_triplet $optarg
461	    continue
462	}
463
464	"--host_bo*" {
465	    set host_board $optarg
466	    continue
467	}
468
469	"--ho*" {			# (--host) the host configuration
470	    set arg_host_triplet $optarg
471	    continue
472	}
473
474	"--ob*" {			# (--objdir) where the test case object code lives
475	    set objdir $optarg
476	    continue
477	}
478
479	"--sr*" {			# (--srcdir) where the testsuite source code lives
480	    set srcdir $optarg
481	    continue
482	}
483
484	"--target_bo*" {
485	    set target_list $optarg
486	    continue
487	}
488
489	"--ta*" {			# (--target) the target configuration
490	    set arg_target_triplet $optarg
491	    continue
492	}
493
494	"--tool_opt*" {
495	    set TOOL_OPTIONS $optarg
496	    continue
497	}
498
499	"--tool_exec*" {
500	    set TOOL_EXECUTABLE $optarg
501	    continue
502	}
503
504	"--tool_ro*" {
505	    set tool_root_dir $optarg
506	    continue
507	}
508
509	"--to*" {			# (--tool) specify tool name
510	    set tool $optarg
511	    set comm_line_tool $optarg
512	    continue
513        }
514
515	"--di*" {
516	    set cmdline_dir_to_run $optarg
517	    continue
518	}
519
520	"--v" -
521	"--verb*" {			# (--verbose) verbose output
522	    incr verbose
523	    continue
524	}
525
526	"[A-Z0-9_-.]*=*" { # process makefile style args like CC=gcc, etc...
527	    if [regexp "^(\[A-Z0-9_-\]+)=(.*)$" $option junk var val] {
528		set $var $val
529		verbose "$var is now $val"
530		append makevars "set $var $val;" ;# FIXME: Used anywhere?
531		unset junk var val
532	    } else {
533		send_error "Illegal variable specification:\n"
534		send_error "$option\n"
535	    }
536	    continue
537	}
538
539    }
540}
541verbose "Verbose level is $verbose"
542
543#
544# get the users login name
545#
546if [string match "" $logname] {
547    if [info exists env(USER)] {
548	set logname $env(USER)
549    } else {
550	if [info exists env(LOGNAME)] {
551	    set logname $env(LOGNAME)
552	} else {
553	    # try getting it with whoami
554	    catch "set logname [exec whoami]" tmp
555	    if [string match "*couldn't find*to execute*" $tmp] {
556		# try getting it with who am i
557		unset tmp
558		catch "set logname [exec who am i]" tmp
559		if [string match "*Command not found*" $tmp] {
560		    send_user "ERROR: couldn't get the users login name\n"
561		    set logname "Unknown"
562		} else {
563		    set logname [lindex [split $logname " !"] 1]
564		}
565	    }
566	}
567    }
568}
569
570#
571# lookfor_file -- try to find a file by searching up multiple directory levels
572#
573proc lookfor_file { dir name } {
574    foreach x ".. ../.. ../../.. ../../../.." {
575	verbose "$dir/$name" 2
576	if [file exists $dir/$name] {
577	    return $dir/$name
578	}
579	set dir [remote_file build dirname $dir]
580    }
581    return ""
582}
583
584#
585# load_lib -- load a library by sourcing it
586#
587# If there a multiple files with the same name, stop after the first one found.
588# The order is first look in the install dir, then in a parallel dir in the
589# source tree, (up one or two levels), then in the current dir.
590#
591proc load_lib { file } {
592    global verbose libdir srcdir base_dir execpath tool
593    global loaded_libs
594
595    if [info exists loaded_libs($file)] {
596	return
597    }
598
599    set loaded_libs($file) ""
600
601    if { [search_and_load_file "library file" $file [list ../lib $libdir $libdir/lib [file dirname [file dirname $srcdir]]/dejagnu/lib $srcdir/lib $execpath/lib . [file dirname [file dirname [file dirname $srcdir]]]/dejagnu/lib]] == 0 } {
602	send_error "ERROR: Couldn't find library file $file.\n"
603	exit 1
604    }
605}
606
607verbose "Login name is $logname"
608
609#
610# Begin sourcing the config files.
611# All are sourced in order.
612#
613# Search order:
614#	$HOME/.dejagnurc -> $base_dir/$configfile -> $objdir/$configfile
615#	-> installed -> $DEJAGNU
616#
617# ??? It might be nice to do $HOME last as it would allow it to be the
618# ultimate override.  Though at present there is still $DEJAGNU.
619#
620# For the normal case, we rely on $base_dir/$configfile to set
621# host_triplet and target_triplet.
622#
623
624load_file ~/.dejagnurc $base_dir/$configfile
625
626#
627# If objdir didn't get set in $base_dir/$configfile, set it to $base_dir.
628# Make sure we source $objdir/$configfile in case $base_dir/$configfile doesn't
629# exist and objdir was given on the command line.
630#
631
632if [expr [string match "." $objdir] || [string match $srcdir $objdir]] {
633    set objdir $base_dir
634} else {
635    load_file $objdir/$configfile
636}
637
638# Well, this just demonstrates the real problem...
639if ![info exists tool_root_dir] {
640    set tool_root_dir [file dirname $objdir]
641    if [file exists "$tool_root_dir/testsuite"] {
642	set tool_root_dir [file dirname $tool_root_dir]
643    }
644}
645
646verbose "Using test sources in $srcdir"
647verbose "Using test binaries in $objdir"
648verbose "Tool root directory is $tool_root_dir"
649
650set execpath [file dirname $argv0]
651set libdir   [file dirname $execpath]/dejagnu
652if [info exists env(DEJAGNULIBS)] {
653    set libdir $env(DEJAGNULIBS)
654}
655
656verbose "Using $libdir to find libraries"
657
658#
659# If the host or target was given on the command line, override the above
660# config files.  We allow $DEJAGNU to massage them though in case it would
661# ever want to do such a thing.
662#
663if { $arg_host_triplet != "" } {
664    set host_triplet $arg_host_triplet
665}
666if { $arg_build_triplet != "" } {
667    set build_triplet $arg_build_triplet
668}
669
670# if we only specify --host, then that must be the build machne too, and we're
671# stuck using the old functionality of a simple cross test
672if [expr { $build_triplet == ""  &&  $host_triplet != "" } ] {
673    set build_triplet $host_triplet
674}
675# if we only specify --build, then we'll use that as the host too
676if [expr { $build_triplet != "" && $host_triplet == "" } ] {
677    set host_triplet $build_triplet
678}
679unset arg_host_triplet arg_build_triplet
680
681#
682# If the build machine type hasn't been specified by now, use config.guess.
683#
684
685if [expr  { $build_triplet == ""  &&  $host_triplet == ""} ] {
686    # find config.guess
687    foreach dir "$libdir $libdir/libexec $libdir/.. $execpath $srcdir $srcdir/.. $srcdir/../.." {
688	verbose "Looking for ${dir}/config.guess" 2
689	if [file exists ${dir}/config.guess] {
690	    set config_guess ${dir}/config.guess
691	    verbose "Found ${dir}/config.guess"
692	    break
693	}
694    }
695
696    # get the canonical config name
697    if ![info exists config_guess] {
698	send_error "ERROR: Couldn't find config.guess program.\n"
699	exit 1
700    }
701    catch "exec $config_guess" build_triplet
702    case $build_triplet in {
703	{ "No uname command or uname output not recognized" "Unable to guess system type" } {
704	    verbose "WARNING: Uname output not recognized"
705	    set build_triplet unknown
706	}
707    }
708    verbose "Assuming build host is $build_triplet"
709    if { $host_triplet == "" } {
710	set host_triplet $build_triplet
711    }
712
713}
714
715#
716# Figure out the target. If the target hasn't been specified, then we have to
717# assume we are native.
718#
719if { $arg_target_triplet != "" } {
720    set target_triplet $arg_target_triplet
721} elseif { $target_triplet == "" } {
722    set target_triplet $build_triplet
723    verbose "Assuming native target is $target_triplet" 2
724}
725unset arg_target_triplet
726#
727# Default target_alias to target_triplet.
728#
729if ![info exists target_alias] {
730    set target_alias $target_triplet
731}
732
733proc get_local_hostname { } {
734    if [catch "info hostname" hb] {
735	set hb ""
736    } else {
737	regsub "\\..*$" $hb "" hb
738    }
739    verbose "hostname=$hb" 3
740    return $hb
741}
742
743#
744# We put these here so that they can be overridden later by site.exp or
745# friends.
746#
747# Set up the target as machine NAME. We also load base-config.exp as a
748# default configuration. The config files are sourced with the global
749# variable $board set to the name of the current target being defined.
750#
751proc setup_target_hook { whole_name name } {
752    global board
753    global host_board
754
755    if [info exists host_board] {
756	set hb $host_board
757    } else {
758	set hb [get_local_hostname]
759    }
760
761    set board $whole_name
762
763    global board_type
764    set board_type "target"
765
766    load_config base-config.exp
767    if ![load_board_description ${name} ${whole_name} ${hb}] {
768	if { $name != "unix" } {
769	    perror "couldn't load description file for ${name}"
770	    exit 1
771	} else {
772	    load_generic_config "unix"
773	}
774    }
775
776    if [board_info $board exists generic_name] {
777	load_tool_target_config [board_info $board generic_name]
778    }
779
780    unset board
781    unset board_type
782
783    push_target $whole_name
784
785    if { [info procs ${whole_name}_init] != "" } {
786	${whole_name}_init $whole_name
787    }
788
789    if { ![isnative] && ![is_remote target] } {
790	global env build_triplet target_triplet
791	if { (![info exists env(DEJAGNU)]) && ($build_triplet != $target_triplet) } {
792	    warning "Assuming target board is the local machine (which is probably wrong).\nYou may need to set your DEJAGNU environment variable."
793	}
794    }
795}
796
797#
798# Clean things up afterwards.
799#
800proc cleanup_target_hook { name } {
801    global tool
802    # Clean up the target board.
803    if { [info procs "${name}_exit"] != "" } {
804	${name}_exit
805    }
806    # We also call the tool exit routine here.
807    if [info exists tool] {
808	if { [info procs "${tool}_exit"] != "" } {
809	    ${tool}_exit
810	}
811    }
812    remote_close target
813    pop_target
814}
815
816proc setup_host_hook { name } {
817    global board
818    global board_info
819    global board_type
820
821    set board $name
822    set board_type "host"
823
824    load_board_description $name
825    unset board
826    unset board_type
827    push_host $name
828    if { [info proc ${name}_init] != "" } {
829	${name}_init $name
830    }
831}
832
833proc setup_build_hook { name } {
834    global board
835    global board_info
836    global board_type
837
838    set board $name
839    set board_type "build"
840
841    load_board_description $name
842    unset board
843    unset board_type
844    push_build $name
845    if { [info proc ${name}_init] != "" } {
846	${name}_init $name
847    }
848}
849
850#
851# Find and load the global config file if it exists.
852# The global config file is used to set the connect mode and other
853# parameters specific to each particular target.
854# These files assume the host and target have been set.
855#
856
857if { [load_file -- $libdir/$configfile] == 0 } {
858    # If $DEJAGNU isn't set either then there isn't any global config file.
859    # Warn the user as there really should be one.
860    if { ! [info exists env(DEJAGNU)] } {
861	send_error "WARNING: Couldn't find the global config file.\n"
862    }
863}
864
865if [info exists env(DEJAGNU)] {
866    if { [load_file -- $env(DEJAGNU)] == 0 } {
867	# It may seem odd to only issue a warning if there isn't a global
868	# config file, but issue an error if $DEJAGNU is erroneously defined.
869	# Since $DEJAGNU is set there is *supposed* to be a global config file,
870	# so the current behaviour seems reasonable.
871	send_error "WARNING: global config file $env(DEJAGNU) not found.\n"
872    }
873    if ![info exists boards_dir] {
874	set boards_dir "[file dirname $env(DEJAGNU)]/boards"
875    }
876}
877
878if ![info exists boards_dir] {
879    set boards_dir ""
880}
881
882#
883# parse out the config parts of the triplet name
884#
885
886# build values
887if { $build_cpu == "" } {
888    regsub -- "-.*-.*" ${build_triplet} "" build_cpu
889}
890if { $build_vendor == "" } {
891    regsub -- "^\[a-z0-9\]*-" ${build_triplet} "" build_vendor
892    regsub -- "-.*" ${build_vendor} "" build_vendor
893}
894if { $build_os == "" } {
895    regsub -- ".*-.*-" ${build_triplet} "" build_os
896}
897
898# host values
899if { $host_cpu == "" } {
900    regsub -- "-.*-.*" ${host_triplet} "" host_cpu
901}
902if { $host_vendor == "" } {
903    regsub -- "^\[a-z0-9\]*-" ${host_triplet} "" host_vendor
904    regsub -- "-.*" ${host_vendor} "" host_vendor
905}
906if { $host_os == "" } {
907    regsub -- ".*-.*-" ${host_triplet} "" host_os
908}
909
910# target values
911if { $target_cpu == "" } {
912    regsub -- "-.*-.*" ${target_triplet} "" target_cpu
913}
914if { $target_vendor == "" } {
915    regsub -- "^\[a-z0-9\]*-" ${target_triplet} "" target_vendor
916    regsub -- "-.*" ${target_vendor} "" target_vendor
917}
918if { $target_os == "" } {
919    regsub -- ".*-.*-" ${target_triplet} "" target_os
920}
921
922#
923# Load the primary tool initialization file.
924#
925
926proc load_tool_init { file } {
927    global srcdir
928    global loaded_libs
929
930    if [info exists loaded_libs($file)] {
931	return
932    }
933
934    set loaded_libs($file) ""
935
936    if [file exists ${srcdir}/lib/$file] {
937	verbose "Loading library file ${srcdir}/lib/$file"
938	if { [catch "uplevel #0 source ${srcdir}/lib/$file"] == 1 } {
939	    send_error "ERROR: tcl error sourcing library file ${srcdir}/lib/$file.\n"
940	    global errorInfo
941	    if [info exists errorInfo] {
942		send_error "$errorInfo\n"
943	    }
944	    exit 1
945	}
946    } else {
947	warning "Couldn't find tool init file"
948    }
949}
950
951#
952# load the testing framework libraries
953#
954load_lib utils.exp
955load_lib framework.exp
956load_lib debugger.exp
957load_lib remote.exp
958load_lib target.exp
959load_lib targetdb.exp
960load_lib libgloss.exp
961
962# Initialize the test counters and reset them to 0.
963init_testcounts
964reset_vars
965
966#
967# Parse the command line arguments.
968#
969
970# Load the tool initialization file. Allow the --tool option to override
971# what's set in the site.exp file.
972if [info exists comm_line_tool] {
973    set tool $comm_line_tool
974}
975
976if [info exists tool] {
977    load_tool_init ${tool}.exp
978}
979
980set argc [ llength $argv ]
981for { set i 0 } { $i < $argc } { incr i } {
982    set option [ lindex $argv $i ]
983
984    # make all options have two hyphens
985    switch -glob -- $option {
986        "--*" {
987        }
988        "-*" {
989	    set option "-$option"
990        }
991    }
992
993    # split out the argument for options that take them
994    switch -glob -- $option {
995	"--*=*" {
996	    regexp {^[^=]*=(.*)$} $option nil optarg
997	}
998	"--bu*" -
999	"--ho*" -
1000	"--ig*"  -
1001	"--m*"  -
1002	"--n*"  -
1003	"--ob*" -
1004	"--ou*" -
1005	"--sr*" -
1006	"--str*" -
1007        "--ta*" -
1008	"--di*" -
1009	"--to*" {
1010	    incr i
1011	    set optarg [lindex $argv $i]
1012	}
1013    }
1014
1015    switch -glob -- $option {
1016	"--V*" -
1017	"--vers*" {			# (--version) version numbers
1018	    send_user "Expect version is\t[exp_version]\n"
1019	    send_user "Tcl version is\t\t[ info tclversion ]\n"
1020	    send_user "Framework version is\t$frame_version\n"
1021	    exit
1022	}
1023
1024	"--v*" {			# (--verbose) verbose output
1025	    # Already parsed.
1026	    continue
1027	}
1028
1029	"--bu*" {			# (--build) the build host configuration
1030	    # Already parsed (and don't set again).  Let $DEJAGNU rename it.
1031	    continue
1032	}
1033
1034	"--ho*" {			# (--host) the host configuration
1035	    # Already parsed (and don't set again).  Let $DEJAGNU rename it.
1036	    continue
1037	}
1038
1039	"--target_bo*" {
1040	    # Set it again, father knows best.
1041	    set target_list $optarg
1042	    continue
1043	}
1044
1045	"--ta*" {			# (--target) the target configuration
1046	    # Already parsed (and don't set again).  Let $DEJAGNU rename it.
1047	    continue
1048	}
1049
1050	"--a*" {			# (--all) print all test output to screen
1051	    set all_flag 1
1052	    verbose "Print all test output to screen"
1053	    continue
1054	}
1055
1056	"--di*" {
1057	    # Already parsed (and don't set again).  Let $DEJAGNU rename it.
1058	    # set cmdline_dir_to_run $optarg
1059	    continue
1060	}
1061
1062
1063	"--de*" {			# (--debug) expect internal debugging
1064	    if [file exists ./dbg.log] {
1065		catch "exec rm -f ./dbg.log"
1066	    }
1067	    if { $verbose > 2 } {
1068		exp_internal -f dbg.log 1
1069	    } else {
1070		exp_internal -f dbg.log 0
1071	    }
1072	    verbose "Expect Debugging is ON"
1073	    continue
1074	}
1075
1076	"--D[01]" {			# (-Debug) turn on Tcl debugger
1077	    verbose "Tcl debugger is ON"
1078	    continue
1079	}
1080
1081	"--m*" {			# (--mail) mail the output
1082	    set mailing_list $optarg
1083            set mail_logs 1
1084	    verbose "Mail results to $mailing_list"
1085	    continue
1086	}
1087
1088	"--r*" {			# (--reboot) reboot the target
1089	    set reboot 1
1090	    verbose "Will reboot the target (if supported)"
1091	    continue
1092	}
1093
1094	"--ob*" {			# (--objdir) where the test case object code lives
1095	    # Already parsed, but parse again to make sure command line
1096	    # options override any config file.
1097	    set objdir $optarg
1098	    verbose "Using test binaries in $objdir"
1099	    continue
1100	}
1101
1102	"--ou*" {			# (--outdir) where to put the output files
1103	    set outdir $optarg
1104	    verbose "Test output put in $outdir"
1105	    continue
1106	}
1107
1108	"*.exp" {			#  specify test names to run
1109	    set all_runtests($option) ""
1110	    verbose "Running only tests $option"
1111	    continue
1112	}
1113
1114	"*.exp=*" {			#  specify test names to run
1115	    set tmp [split $option "="]
1116	    set all_runtests([lindex $tmp 0]) [lindex $tmp 1]
1117	    verbose "Running only tests $option"
1118	    unset tmp
1119	    continue
1120	}
1121
1122	"--ig*" {			#  (--ignore) specify test names to exclude
1123	    set ignoretests $optarg
1124	    verbose "Ignoring test $ignoretests"
1125	    continue
1126	}
1127
1128	"--sr*" {			# (--srcdir) where the testsuite source code lives
1129	    # Already parsed, but parse again to make sure command line
1130	    # options override any config file.
1131
1132	    set srcdir $optarg
1133	    continue
1134	}
1135
1136	"--str*" {			# (--strace) expect trace level
1137	    set tracelevel $optarg
1138	    strace $tracelevel
1139	    verbose "Source Trace level is now $tracelevel"
1140	    continue
1141	}
1142
1143	"--sta*" {			# (--status) exit status flag
1144	    set exit_error 1
1145	    verbose "Tcl errors will set an ERROR exit status"
1146	    continue
1147	}
1148
1149	"--tool_opt*" {
1150	    continue
1151	}
1152
1153	"--tool_exec*" {
1154	    set TOOL_EXECUTABLE $optarg
1155	    continue
1156	}
1157
1158	"--tool_ro*" {
1159	    set tool_root_dir $optarg
1160	    continue
1161	}
1162
1163	"--to*" {			# (--tool) specify tool name
1164	    set tool $optarg
1165	    verbose "Testing $tool"
1166	    continue
1167        }
1168
1169        "--x*" {
1170            set xml 1
1171            verbose "XML logging turned on"
1172            continue
1173	}
1174
1175	"--he*" {			# (--help) help text
1176	    usage
1177	    exit 0
1178	}
1179
1180	"[A-Z0-9_-.]*=*" { # skip makefile style args like CC=gcc, etc... (processed in first pass)
1181	    continue
1182	}
1183
1184	default {
1185	    if [info exists tool] {
1186		if { [info proc ${tool}_option_proc] != "" } {
1187		    if [${tool}_option_proc $option] {
1188			continue
1189		    }
1190		}
1191	    }
1192	    send_error "\nIllegal Argument \"$option\"\n"
1193	    send_error "try \"runtest --help\" for option list\n"
1194	    exit 1
1195	}
1196    }
1197
1198}
1199
1200#
1201# check for a few crucial variables
1202#
1203if ![info exists tool] {
1204    send_error "WARNING: No tool specified\n"
1205    set tool ""
1206}
1207
1208#
1209# initialize a few Tcl variables to something other than their default
1210#
1211if { $verbose > 2 } {
1212    log_user 1
1213} else {
1214    log_user 0
1215}
1216
1217set timeout 10
1218
1219
1220
1221#
1222# open log files
1223#
1224open_logs
1225
1226# print the config info
1227clone_output "Test Run By $logname on [timestamp -format %c]"
1228if [is3way]  {
1229    clone_output "Target is $target_triplet"
1230    clone_output "Host   is $host_triplet"
1231    clone_output "Build  is $build_triplet"
1232} else {
1233    if [isnative] {
1234	clone_output "Native configuration is $target_triplet"
1235    } else {
1236	clone_output "Target is $target_triplet"
1237	clone_output "Host   is $host_triplet"
1238    }
1239}
1240
1241clone_output "\n\t\t=== $tool tests ===\n"
1242
1243#
1244# Look for the generic board configuration file. It searches in several
1245# places: ${libdir}/config, ${libdir}/../config, and $boards_dir.
1246#
1247
1248proc load_generic_config { name } {
1249    global srcdir
1250    global configfile
1251    global libdir
1252    global env
1253    global board
1254    global board_info
1255    global boards_dir
1256    global board_type
1257
1258    if [info exists board] {
1259	if ![info exists board_info($board,generic_name)] {
1260	    set board_info($board,generic_name) $name
1261	}
1262    }
1263
1264    if [info exists board_type] {
1265	set type "for $board_type"
1266    } else {
1267	set type ""
1268    }
1269
1270    set dirlist [concat ${libdir}/config [file dirname $libdir]/config $boards_dir]
1271    set result [search_and_load_file "generic interface file $type" ${name}.exp $dirlist]
1272
1273    return $result
1274}
1275
1276#
1277# Load the tool-specific target description.
1278#
1279proc load_config { args } {
1280    global srcdir
1281    global board_type
1282
1283    set found 0
1284
1285    return [search_and_load_file "tool-and-target-specific interface file" $args [list ${srcdir}/config ${srcdir}/../config ${srcdir}/../../config ${srcdir}/../../../config]]
1286}
1287
1288#
1289# Find the files that set up the configuration for the target. There
1290# are assumed to be two of them; one defines a basic set of
1291# functionality for the target that can be used by all tool
1292# testsuites, and the other defines any necessary tool-specific
1293# functionality. These files are loaded via load_config.
1294#
1295# These used to all be named $target_abbrev-$tool.exp, but as the
1296# $tool variable goes away, it's now just $target_abbrev.exp.  First
1297# we look for a file named with both the abbrev and the tool names.
1298# Then we look for one named with just the abbrev name. Finally, we
1299# look for a file called default, which is the default actions, as
1300# some tools could be purely host based. Unknown is mostly for error
1301# trapping.
1302#
1303
1304proc load_tool_target_config { name } {
1305    global target_os libdir srcdir
1306
1307    set found [load_config "${name}.exp" "${target_os}.exp" "default.exp" "unknown.exp"]
1308
1309    if { $found == 0 } {
1310	send_error "WARNING: Couldn't find tool config file for $name, using default.\n"
1311	# If we can't load the tool init file, this must be a simple natively hosted
1312	# test suite, so we use the default procs for Unix.
1313	if { [search_and_load_file "library file" default.exp [list $libdir $libdir/config [file dirname [file dirname $srcdir]]/dejagnu/config $srcdir/config . [file dirname [file dirname [file dirname $srcdir]]]/dejagnu/config]] == 0 } {
1314	    send_error "ERROR: Couldn't find default tool init file.\n"
1315	    exit 1
1316	}
1317    }
1318}
1319
1320#
1321# Find the file that describes the machine specified by board_name.
1322#
1323
1324proc load_board_description { board_name args } {
1325    global srcdir
1326    global configfile
1327    global libdir
1328    global env
1329    global board
1330    global board_info
1331    global boards_dir
1332    global board_type
1333
1334    set dejagnu ""
1335
1336    if { [llength $args] > 0 } {
1337	set whole_name [lindex $args 0]
1338    } else {
1339	set whole_name $board_name
1340    }
1341
1342    set board_info($whole_name,name) $whole_name
1343    if ![info exists board] {
1344	set board $whole_name
1345	set board_set 1
1346    } else {
1347	set board_set 0
1348    }
1349
1350    set dirlist {}
1351    if { [llength $args] > 1 } {
1352	set suffix [lindex $args 1]
1353	if { ${suffix} != "" } {
1354	    foreach x ${boards_dir} {
1355		lappend dirlist ${x}/${suffix}
1356	    }
1357	    lappend dirlist ${libdir}/baseboards/${suffix}
1358	}
1359    }
1360    set dirlist [concat $dirlist $boards_dir]
1361    lappend dirlist ${libdir}/baseboards
1362    verbose "dirlist is $dirlist"
1363    if [info exists board_type] {
1364	set type "for $board_type"
1365    } else {
1366	set type ""
1367    }
1368    if ![info exists board_info($whole_name,isremote)] {
1369	set board_info($whole_name,isremote) 1
1370	if [info exists board_type] {
1371	    if { $board_type == "build" } {
1372		set board_info($whole_name,isremote) 0
1373	    }
1374	}
1375	if { ${board_name} == [get_local_hostname] } {
1376	    set board_info($whole_name,isremote) 0
1377	}
1378    }
1379    search_and_load_file "standard board description file $type" standard.exp $dirlist
1380    set found [search_and_load_file "board description file $type" ${board_name}.exp $dirlist]
1381    if { $board_set != 0 } {
1382	unset board
1383    }
1384
1385    return $found
1386}
1387
1388#
1389# Find the base-level file that describes the machine specified by args. We
1390# only look in one directory, ${libdir}/baseboards.
1391#
1392
1393proc load_base_board_description { board_name } {
1394    global srcdir
1395    global configfile
1396    global libdir
1397    global env
1398    global board
1399    global board_info
1400    global board_type
1401
1402    set board_set 0
1403    set board_info($board_name,name) $board_name
1404    if ![info exists board] {
1405	set board $board_name
1406	set board_set 1
1407    }
1408    if [info exists board_type] {
1409	set type "for $board_type"
1410    } else {
1411	set type ""
1412    }
1413    if ![info exists board_info($board_name,isremote)] {
1414	set board_info($board_name,isremote) 1
1415	if [info exists board_type] {
1416	    if { $board_type == "build" } {
1417		set board_info($board_name,isremote) 0
1418	    }
1419	}
1420    }
1421
1422    if { ${board_name} == [get_local_hostname] } {
1423	set board_info($board_name,isremote) 0
1424    }
1425    set found [search_and_load_file "board description file $type" ${board_name}.exp ${libdir}/baseboards]
1426    if { $board_set != 0 } {
1427	unset board
1428    }
1429
1430    return $found
1431}
1432
1433#
1434# Source the testcase in TEST_FILE_NAME.
1435#
1436
1437proc runtest { test_file_name } {
1438    global prms_id
1439    global bug_id
1440    global test_result
1441    global errcnt
1442    global errorInfo
1443    global tool
1444
1445    clone_output "Running $test_file_name ..."
1446    set prms_id	0
1447    set bug_id	0
1448    set test_result ""
1449
1450    if [file exists $test_file_name] {
1451	set timestart [timestamp]
1452
1453	if [info exists tool] {
1454	    if { [info procs "${tool}_init"] != "" } {
1455		${tool}_init $test_file_name
1456	    }
1457	}
1458
1459	if { [catch "uplevel #0 source $test_file_name"] == 1 } {
1460	    # If we have a Tcl error, propogate the exit status do make
1461	    # notices the error.
1462	    global exit_status exit_error
1463	    # exit error is set by a command line option
1464	    if { $exit_status == 0 } {
1465		set exit_status $exit_error
1466	    }
1467	    # We can't call `perror' here, it resets `errorInfo'
1468	    # before we want to look at it.  Also remember that perror
1469	    # increments `errcnt'.  If we do call perror we'd have to
1470	    # reset errcnt afterwards.
1471	    clone_output "ERROR: tcl error sourcing $test_file_name."
1472	    if [info exists errorInfo] {
1473		clone_output "ERROR: $errorInfo"
1474		unset errorInfo
1475	    }
1476	}
1477
1478	if [info exists tool] {
1479	    if { [info procs "${tool}_finish"] != "" } {
1480		${tool}_finish
1481	    }
1482	}
1483	set timeend [timestamp]
1484	set timediff [expr $timeend - $timestart]
1485	verbose -log "testcase $test_file_name completed in $timediff seconds" 4
1486    } else {
1487	# This should never happen, but maybe if the file got removed
1488	# between the `find' above and here.
1489	perror "$test_file_name does not exist."
1490	# ??? This is a hack.  We want to send a message to stderr and
1491	# to the summary file (just like perror does), but we don't
1492	# want the next testcase to get a spurious "unresolved" because
1493	# errcnt != 0.  Calling `clone_output' is also supposed to be a
1494	# no-no (see the comments for clone_output).
1495	set errcnt 0
1496    }
1497}
1498
1499#
1500# Trap some signals so we know what's happening.  These replace the previous
1501# ones because we've now loaded the library stuff.
1502#
1503if ![exp_debug] {
1504    foreach sig "{SIGTERM {terminated}} \
1505             {SIGINT  {interrupted by user}} \
1506             {SIGQUIT {interrupted by user}} \
1507             {SIGSEGV {segmentation violation}}" {
1508	set signal [lindex $sig 0]
1509	set str [lindex $sig 1]
1510	trap "send_error \"got a \[trap -name\] signal, $str \\n\"; log_and_exit;" $signal
1511	verbose "setting trap for $signal to $str" 1
1512    }
1513    unset signal str sig
1514}
1515
1516#
1517# Given a list of targets, process any iterative lists.
1518#
1519proc process_target_variants { target_list } {
1520    set result {}
1521    foreach x $target_list {
1522	if [regexp "\\(" $x] {
1523	    regsub "^.*\\((\[^()\]*)\\)$" "$x" "\\1" variant_list
1524	    regsub "\\(\[^(\]*$" "$x" "" x
1525	    set list [process_target_variants $x]
1526	    set result {}
1527	    foreach x $list {
1528		set result [concat $result [iterate_target_variants $x [split $variant_list ","]]]
1529	    }
1530	} elseif [regexp "\{" $x] {
1531	    regsub "^.*\{(\[^\{\}\]*)\}$" "$x" "\\1" variant_list
1532	    regsub "\{\[^\{\]*$" "$x" "" x
1533	    set list [process_target_variants $x]
1534	    foreach x $list {
1535		foreach i [split $variant_list ","] {
1536		    set name $x
1537		    if { $i != "" } {
1538			append name "/" $i
1539		    }
1540		    lappend result $name
1541		}
1542	    }
1543	} else {
1544	    lappend result "$x"
1545	}
1546    }
1547    return $result
1548}
1549
1550proc iterate_target_variants { target variants } {
1551    return [iterate_target_variants_two $target $target $variants]
1552}
1553
1554#
1555# Given a list of variants, produce the list of all possible combinations.
1556#
1557proc iterate_target_variants_two { orig_target target variants } {
1558
1559    if { [llength $variants] == 0 } {
1560	return [list $target]
1561    } else {
1562	if { [llength $variants] > 1 } {
1563	    set result [iterate_target_variants_two $orig_target $target [lrange $variants 1 end]]
1564	} else {
1565	    if { $target != $orig_target } {
1566		set result [list $target]
1567	    } else {
1568		set result {}
1569	    }
1570	}
1571	if { [lindex $variants 0] != "" } {
1572	    append target "/" [lindex $variants 0]
1573	    return [concat $result [iterate_target_variants_two $orig_target $target [lrange $variants 1 end]]]
1574	} else {
1575	    return [concat $result $target]
1576	}
1577    }
1578}
1579
1580setup_build_hook [get_local_hostname]
1581
1582if [info exists host_board] {
1583    setup_host_hook $host_board
1584} else {
1585    set hb [get_local_hostname]
1586    if { $hb != "" } {
1587	setup_host_hook $hb
1588    }
1589}
1590
1591#
1592# main test execution loop
1593#
1594
1595if [info exists errorInfo] {
1596    unset errorInfo
1597}
1598# make sure we have only single path delimiters
1599regsub -all "\(\[^/\]\)//*" $srcdir "\\1/" srcdir
1600
1601if ![info exists target_list] {
1602    # Make sure there is at least one target machine. It's probably a Unix box,
1603    # but that's just a guess.
1604    set target_list { "unix" }
1605} else {
1606    verbose "target list is $target_list"
1607}
1608
1609#
1610# Iterate through the list of targets.
1611#
1612global current_target
1613
1614set target_list [process_target_variants $target_list]
1615
1616set target_count [llength $target_list]
1617
1618clone_output "Schedule of variations:"
1619foreach current_target $target_list {
1620    clone_output "    $current_target"
1621}
1622clone_output ""
1623
1624
1625foreach current_target $target_list {
1626    verbose "target is $current_target"
1627    set current_target_name $current_target
1628    set tlist [split $current_target /]
1629    set current_target [lindex $tlist 0]
1630    set board_variant_list [lrange $tlist 1 end]
1631
1632    # Set the counts for this target to 0.
1633    reset_vars
1634    clone_output "Running target $current_target_name"
1635
1636    setup_target_hook $current_target_name $current_target
1637
1638    # If multiple passes requested, set them up.  Otherwise prepare just one.
1639    # The format of `MULTIPASS' is a list of elements containing
1640    # "{ name var1=value1 ... }" where `name' is a generic name for the pass and
1641    # currently has no other meaning.
1642
1643    global env
1644
1645    if { [info exists MULTIPASS] } {
1646	set multipass $MULTIPASS
1647    }
1648    if { $multipass == "" } {
1649	set multipass { "" }
1650    }
1651
1652    # If PASS is specified, we want to run only the tests specified.
1653    # Its value should be a number or a list of numbers that specify
1654    # the passes that we want to run.
1655    if [info exists PASS] {
1656	set pass $PASS
1657    } else {
1658	set pass ""
1659    }
1660
1661    if {$pass != ""} {
1662	set passes [list]
1663	foreach p $pass {
1664	    foreach multipass_elem $multipass {
1665		set multipass_name [lindex $multipass_elem 0]
1666		if {$p == $multipass_name} {
1667	    	    lappend passes $multipass_elem
1668		    break
1669		}
1670	    }
1671	}
1672	set multipass $passes
1673    }
1674
1675    foreach pass $multipass {
1676
1677	# multipass_name is set for `record_test' to use (see framework.exp).
1678	if { [lindex $pass 0] != "" } {
1679	    set multipass_name [lindex $pass 0]
1680	    clone_output "Running pass `$multipass_name' ..."
1681	} else {
1682	    set multipass_name ""
1683	}
1684	set restore ""
1685	foreach varval [lrange $pass 1 end] {
1686	    set tmp [string first "=" $varval]
1687	    set var [string range $varval 0 [expr $tmp - 1]]
1688	    # Save previous value.
1689	    if [info exists $var] {
1690		lappend restore "$var [list [eval concat \$$var]]"
1691	    } else {
1692		lappend restore "$var"
1693	    }
1694	    # Handle "CFLAGS=$CFLAGS foo".
1695	    # FIXME: Do we need to `catch' this?
1696	    eval set $var \[string range \"$varval\" [expr $tmp + 1] end\]
1697	    verbose "$var is now [eval concat \$$var]"
1698	    unset tmp var
1699	}
1700
1701	# look for the top level testsuites. if $tool doesn't
1702	# exist and there are no subdirectories in $srcdir, then
1703	# we default to srcdir.
1704	set test_top_dirs [lsort [getdirs -all ${srcdir} "${tool}*"]]
1705	if { ${test_top_dirs} == "" } {
1706	    set test_top_dirs ${srcdir}
1707	} else {
1708	    # JYG:
1709	    # DejaGNU's notion of test tree and test files is very
1710	    # general:
1711	    # given ${srcdir} and ${tool}, any subdirectory (at any
1712	    # level deep) with the "${tool}" prefix starts a test tree
1713	    # given a test tree, any *.exp file underneath (at any
1714	    # level deep) is a test file.
1715	    #
1716	    # For test tree layouts with ${tool} prefix on
1717	    # both a parent and a child directory, we need to eliminate
1718	    # the child directory entry from test_top_dirs list.
1719	    # e.g. gdb.hp/gdb.base-hp/ would result in two entries
1720	    # in the list: gdb.hp, gdb.hp/gdb.base-hp.
1721	    # If the latter not eliminated, test files under
1722	    # gdb.hp/gdb.base-hp would be run twice (since test files
1723	    # are gathered from all sub-directories underneath a
1724	    # directory).
1725	    #
1726	    # Since ${tool} may be g++, etc. which could confuse
1727	    # regexp, we cannot do the simpler test:
1728	    #     ...
1729	    #     if [regexp "${srcdir}/.*${tool}.*/.*${tool}.*" ${dir}]
1730	    #     ...
1731	    # instead, we rely on the fact that test_top_dirs is
1732	    # a sorted list of entries, and any entry that contains
1733	    # the previous valid test top dir entry in its own pathname
1734	    # must be excluded.
1735
1736	    set temp_top_dirs ""
1737	    set prev_dir ""
1738	    foreach dir "${test_top_dirs}" {
1739		if { [string length ${prev_dir}] == 0 ||
1740		     [string first "${prev_dir}/" ${dir}] == -1} {
1741	            # the first top dir entry, or an entry that
1742		    # does not share the previous entry's entire
1743	            # pathname, record it as a valid top dir entry.
1744		    #
1745		    lappend temp_top_dirs ${dir}
1746		    set prev_dir ${dir}
1747		}
1748	    }
1749	    set test_top_dirs ${temp_top_dirs}
1750	}
1751	verbose "Top level testsuite dirs are ${test_top_dirs}" 2
1752	set testlist ""
1753	if [info exists all_runtests] {
1754	    foreach x [array names all_runtests] {
1755		verbose "trying to glob ${srcdir}/${x}" 2
1756		set s [glob -nocomplain ${srcdir}/$x]
1757		if { $s != "" } {
1758		    set testlist [concat $testlist $s]
1759		}
1760	    }
1761	}
1762	#
1763	# If we have a list of tests, run all of them.
1764	#
1765	if { $testlist != "" } {
1766	    foreach test_name $testlist {
1767		if { ${ignoretests} != "" } {
1768		    if { 0 <= [lsearch ${ignoretests} [file tail ${test_name}]]} {
1769			continue
1770		    }
1771		}
1772
1773		# set subdir to the tail of the dirname after $srcdir,
1774		# for the driver files that want it.  XXX this is silly.
1775		# drivers should get a single var, not "$srcdir/$subdir"
1776		set subdir [file dirname $test_name]
1777		set p [expr [string length $srcdir]-1]
1778		while {0 < $p && [string index $srcdir $p] == "/"} {
1779		    incr p -1
1780		}
1781		if {[string range $subdir 0 $p] == $srcdir} {
1782		    set subdir [string range $subdir [expr $p+1] end]
1783		    regsub "^/" $subdir "" subdir
1784		}
1785
1786		# XXX not the right thing to do.
1787		set runtests [list [file tail $test_name] ""]
1788
1789		runtest $test_name
1790	    }
1791	} else {
1792	    #
1793	    # Go digging for tests.
1794	    #
1795	    foreach dir "${test_top_dirs}" {
1796		if { ${dir} != ${srcdir} } {
1797		    # Ignore this directory if is a directory to be
1798		    # ignored.
1799		    if {[info exists ignoredirs] && $ignoredirs != ""} {
1800			set found 0
1801			foreach directory $ignoredirs {
1802			    if [string match "*${directory}*" $dir] {
1803				set found 1
1804				break
1805			    }
1806			}
1807			if {$found} {
1808			    continue
1809			}
1810		    }
1811
1812		    # Run the test if dir_to_run was specified as a
1813		    # value (for example in MULTIPASS) and the test
1814		    # directory matches that directory.
1815		    if {[info exists dir_to_run] && $dir_to_run != ""} {
1816			# JYG: dir_to_run might be a space delimited list
1817			# of directories.  Look for match on each item.
1818			set found 0
1819			foreach directory $dir_to_run {
1820			    if [string match "*${directory}*" $dir] {
1821				set found 1
1822				break
1823			    }
1824			}
1825			if {!$found} {
1826			    continue
1827			}
1828		    }
1829
1830		    # Run the test if cmdline_dir_to_run was specified
1831		    # by the user using --directory and the test
1832		    # directory matches that directory
1833		    if {[info exists cmdline_dir_to_run] \
1834			    && $cmdline_dir_to_run != ""} {
1835			# JYG: cmdline_dir_to_run might be a space delimited
1836			# list of directories.  Look for match on each item.
1837			set found 0
1838			foreach directory $cmdline_dir_to_run {
1839			    if [string match "*${directory}*" $dir] {
1840				set found 1
1841				break
1842			    }
1843			}
1844			if {!$found} {
1845			    continue
1846			}
1847		    }
1848
1849		    foreach test_name [lsort [find ${dir} *.exp]] {
1850			if { ${test_name} == "" } {
1851			    continue
1852			}
1853			# Ignore this one if asked to.
1854			if { ${ignoretests} != "" } {
1855			    if { 0 <= [lsearch ${ignoretests} [file tail ${test_name}]]} {
1856				continue
1857			    }
1858			}
1859
1860			# Get the path after the $srcdir so we know
1861			# the subdir we're in.
1862			set subdir [file dirname $test_name]
1863			# We used to do
1864			# regsub $srcdir [file dirname $test_name] "" subdir
1865			# but what if [file dirname $test_name] contains regexp
1866			# characters? We lose. Instead...
1867			set first [string first $srcdir $subdir]
1868			if { $first >= 0 } {
1869			    set first [expr $first + [string length $srcdir]]
1870			    set subdir [string range $subdir $first end]
1871			    regsub "^/" "$subdir" "" subdir
1872			}
1873			if { "$srcdir" == "$subdir" || "$srcdir" == "$subdir/" } {
1874			    set subdir ""
1875			}
1876			# Check to see if the range of tests is limited,
1877			# set `runtests' to a list of two elements: the script name
1878			# and any arguments ("" if none).
1879			if [info exists all_runtests] {
1880			    verbose "searching for $test_name in [array names all_runtests]"
1881			    if { 0 > [lsearch [array names all_runtests] [file tail $test_name]]} {
1882				if { 0 > [lsearch [array names all_runtests] $test_name] } {
1883				    continue
1884				}
1885			    }
1886			    set runtests [list [file tail $test_name] $all_runtests([file tail $test_name])]
1887			} else {
1888			    set runtests [list [file tail $test_name] ""]
1889			}
1890			runtest $test_name
1891		    }
1892		}
1893	    }
1894	    # Restore the variables set by this pass.
1895	    foreach varval $restore {
1896		if { [llength $varval] > 1 } {
1897		    verbose "Restoring [lindex $varval 0] to [lindex $varval 1]" 4
1898		    set [lindex $varval 0] [lindex $varval 1]
1899		} else {
1900		    verbose "Restoring [lindex $varval 0] to `unset'" 4
1901		    unset [lindex $varval 0]
1902		}
1903	    }
1904	}
1905    }
1906    cleanup_target_hook $current_target
1907    if { $target_count > 1 } {
1908	log_summary
1909    }
1910}
1911
1912log_and_exit
1913