# Copyright (C) 1992 - 2002, 2003 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: # bug-dejagnu@gnu.org # This file was written by Rob Savoye. (rob@welcomehome.org) # # Most of the procedures found here mimic their unix counter-part. # This file is sourced by runtest.exp, so they are usable by any test case. # # # Gets the directories in a directory, or in a directory tree. # args: the first is the dir to look in, the next # is the pattern to match. It # defaults to *. Patterns are csh style # globbing rules # options: -all search the tree recursively # returns: a list of dirs or NULL; the root directory is not returned. # proc getdirs { args } { if { [lindex $args 0] == "-all" } { set alldirs 1 set args [lrange $args 1 end] } else { set alldirs 0 } set path [lindex $args 0] if { [llength $args] > 1} { set pattern [lindex $args 1] } else { set pattern "*" } verbose "Looking in ${path} for directories that match \"${pattern}\"" 3 catch "glob ${path}/${pattern}" tmp if { ${tmp} != "" } { foreach i ${tmp} { if [file isdirectory $i] { switch -- "[file tail $i]" { "testsuite" - "config" - "lib" - "CVS" - "RCS" - "SCCS" { verbose "Ignoring directory [file tail $i]" 3 continue } default { if [file readable $i] { verbose "Found directory [file tail $i]" 3 lappend dirs $i if { $alldirs } { eval lappend dirs [getdirs -all $i $pattern] } } } } } } } else { perror "$tmp" return "" } if ![info exists dirs] { return "" } else { return $dirs } } # # Finds paths of all non-directory files, recursively, whose names match # a pattern. Certain directory name are not searched (see proc getdirs). # rootdir - search in this directory and its subdirectories, recursively. # pattern - specified with Tcl string match "globbing" rules. # returns: a possibly empty list of pathnames. # proc find { rootdir pattern } { set files [list] if { [string length $rootdir] == 0 || [string length $pattern] == 0 } { return $files } # find all the directories set dirs [concat [getdirs -all $rootdir] $rootdir] # find all the files in the directories that match the pattern foreach i $dirs { verbose "Looking in $i" 3 foreach match [glob -nocomplain $i/$pattern] { if ![file isdirectory $match] { lappend files $match verbose "Adding $match to file list" 3 } } } return $files } # # Search the path for a file. This is basically a version # of the BSD-unix which utility. This procedure depends on # the shell environment variable $PATH. It returns 0 if $PATH # does not exist or the binary is not in the path. If the # binary is in the path, it returns the full path to the binary. # proc which { file } { global env # strip off any extraneous arguments (like flags to the compiler) set file [lindex $file 0] # if it exists then the path must be OK # ??? What if $file has no path and "." isn't in $PATH? if [file exists $file] { return $file } if [info exists env(PATH)] { set path [split $env(PATH) ":"] } else { return 0 } foreach i $path { verbose "Checking against $i" 3 if [file exists $i/$file] { if [file executable $i/$file] { return $i/$file } else { warning "$i/$file exists but is not an executable" } } } # not in path return 0 } # # Looks for a string in a file. # return:list of lines that matched or NULL if none match. # args: first arg is the filename, # second is the pattern, # third are any options. # Options: line - puts line numbers of match in list # proc grep { args } { set file [lindex $args 0] set pattern [lindex $args 1] verbose "Grepping $file for the pattern \"$pattern\"" 3 set argc [llength $args] if { $argc > 2 } { for { set i 2 } { $i < $argc } { incr i } { append options [lindex $args $i] append options " " } } else { set options "" } set i 0 set fd [open $file r] while { [gets $fd cur_line]>=0 } { incr i if [regexp -- "$pattern" $cur_line match] { if ![string match "" $options] { foreach opt $options { case $opt in { "line" { lappend grep_out [concat $i $match] } } } } else { lappend grep_out $match } } } close $fd unset fd unset i if ![info exists grep_out] { set grep_out "" } return $grep_out } # # Remove elements based on patterns. elements are delimited by spaces. # pattern is the pattern to look for using glob style matching # list is the list to check against # returns the new list # proc prune { list pattern } { set tmp {} foreach i $list { verbose "Checking pattern \"$pattern\" against $i" 3 if ![string match $pattern $i] { lappend tmp $i } else { verbose "Removing element $i from list" 3 } } return $tmp } # # Attempt to kill a process that you started on the local machine. # proc slay { name } { set in [open [concat "|ps"] r] while {[gets $in line]>-1} { if ![string match "*expect*slay*" $line] { if [string match "*$name*" $line] { set pid [lindex $line 0] catch "exec kill -9 $pid]" verbose "Killing $name, pid = $pid\n" } } } close $in } # # Convert a relative path to an absolute one on the local machine. # proc absolute { path } { if [string match "." $path] { return [pwd] } set basedir [pwd] cd $path set path [pwd] cd $basedir return $path } # # Source a file and trap any real errors. This ignores extraneous # output. returns a 1 if there was an error, otherwise it returns 0. # proc psource { file } { global errorInfo global errorCode unset errorInfo if [file exists $file] { catch "source $file" if [info exists errorInfo] { send_error "ERROR: errors in $file\n" send_error "$errorInfo" return 1 } } return 0 } # # Check if a testcase should be run or not # # RUNTESTS is a copy of global `runtests'. # # This proc hides the details of global `runtests' from the test scripts, and # implements uniform handling of "script arguments" where those arguments are # file names (ie: the "foo" in make check RUNTESTFLAGS="bar.exp=foo"). # "glob" style expressions are supported as well as multiple files (with # spaces between them). # Eg: RUNTESTFLAGS="bar.exp=foo1.c foo2.c foo3*.c bar/baz*.c" # proc runtest_file_p { runtests testcase } { if [string length [lindex $runtests 1]] { foreach ptn [lindex $runtests 1] { if [string match "*/$ptn" $testcase] { return 1 } if [string match $ptn $testcase] { return 1 } } return 0 } return 1 } # # Delete various system verbosities from TEXT on SYSTEM # # An example is: # ld.so: warning: /usr/lib/libc.so.1.8.1 has older revision than expected 9 # # SYSTEM is typical $target_triplet or $host_triplet. # # # Compares two files line-by-line # returns 1 it the files match, # returns 0 if there was a file error, # returns -1 if they didn't match. # proc diff { file_1 file_2 } { set eof -1 set differences 0 if [file exists ${file_1}] { set file_a [open ${file_1} r] } else { warning "${file_1} doesn't exist" return 0 } if [file exists ${file_2}] { set file_b [open ${file_2} r] } else { warning "${file_2} doesn't exist" return 0 } verbose "# Diff'ing: ${file_1} ${file_2}\n" 1 set list_a "" while { [gets ${file_a} line] != ${eof} } { if [regexp "^#.*$" ${line}] { continue } else { lappend list_a ${line} } } close ${file_a} set list_b "" while { [gets ${file_b} line] != ${eof} } { if [regexp "^#.*$" ${line}] { continue } else { lappend list_b ${line} } } close ${file_b} for { set i 0 } { $i < [llength $list_a] } { incr i } { set line_a [lindex ${list_a} ${i}] set line_b [lindex ${list_b} ${i}] # verbose "\t${file_1}: ${i}: ${line_a}\n" 3 # verbose "\t${file_2}: ${i}: ${line_b}\n" 3 if [string compare ${line_a} ${line_b}] { verbose "line #${i}\n" 2 verbose "\< ${line_a}\n" 2 verbose "\> ${line_b}\n" 2 send_log "line #${i}\n" send_log "\< ${line_a}\n" send_log "\> ${line_b}\n" set differences -1 } } if { $differences == -1 || [llength ${list_a}] != [llength ${list_b}] } { verbose "Files not the same" 2 set differences -1 } else { verbose "Files are the same" 2 set differences 1 } return ${differences} } # # Set an environment variable # proc setenv { var val } { global env set env($var) $val } # # Unset an environment variable # proc unsetenv { var } { global env unset env($var) } # # Get a value from an environment variable # proc getenv { var } { global env if [info exists env($var)] { return $env($var) } else { return "" } }