aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/ChangeLog5
-rw-r--r--contrib/dg-extract-results.py592
-rwxr-xr-xcontrib/dg-extract-results.sh459
3 files changed, 1056 insertions, 0 deletions
diff --git a/contrib/ChangeLog b/contrib/ChangeLog
new file mode 100644
index 0000000..8ce6765
--- /dev/null
+++ b/contrib/ChangeLog
@@ -0,0 +1,5 @@
+2018-08-06 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * dg-extract-results.sh: Move from gdb/testsuite.
+ Update from gcc repo.
+ * dg-extract-results.py: New from gcc repo.
diff --git a/contrib/dg-extract-results.py b/contrib/dg-extract-results.py
new file mode 100644
index 0000000..4b02a5b
--- /dev/null
+++ b/contrib/dg-extract-results.py
@@ -0,0 +1,592 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2014 Free Software Foundation, Inc.
+#
+# This script 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 3, or (at your option)
+# any later version.
+
+import sys
+import getopt
+import re
+import io
+from datetime import datetime
+from operator import attrgetter
+
+# True if unrecognised lines should cause a fatal error. Might want to turn
+# this on by default later.
+strict = False
+
+# True if the order of .log segments should match the .sum file, false if
+# they should keep the original order.
+sort_logs = True
+
+# A version of open() that is safe against whatever binary output
+# might be added to the log.
+def safe_open (filename):
+ if sys.version_info >= (3, 0):
+ return open (filename, 'r', errors = 'surrogateescape')
+ return open (filename, 'r')
+
+# Force stdout to handle escape sequences from a safe_open file.
+if sys.version_info >= (3, 0):
+ sys.stdout = io.TextIOWrapper (sys.stdout.buffer,
+ errors = 'surrogateescape')
+
+class Named:
+ def __init__ (self, name):
+ self.name = name
+
+class ToolRun (Named):
+ def __init__ (self, name):
+ Named.__init__ (self, name)
+ # The variations run for this tool, mapped by --target_board name.
+ self.variations = dict()
+
+ # Return the VariationRun for variation NAME.
+ def get_variation (self, name):
+ if name not in self.variations:
+ self.variations[name] = VariationRun (name)
+ return self.variations[name]
+
+class VariationRun (Named):
+ def __init__ (self, name):
+ Named.__init__ (self, name)
+ # A segment of text before the harness runs start, describing which
+ # baseboard files were loaded for the target.
+ self.header = None
+ # The harnesses run for this variation, mapped by filename.
+ self.harnesses = dict()
+ # A list giving the number of times each type of result has
+ # been seen.
+ self.counts = []
+
+ # Return the HarnessRun for harness NAME.
+ def get_harness (self, name):
+ if name not in self.harnesses:
+ self.harnesses[name] = HarnessRun (name)
+ return self.harnesses[name]
+
+class HarnessRun (Named):
+ def __init__ (self, name):
+ Named.__init__ (self, name)
+ # Segments of text that make up the harness run, mapped by a test-based
+ # key that can be used to order them.
+ self.segments = dict()
+ # Segments of text that make up the harness run but which have
+ # no recognized test results. These are typically harnesses that
+ # are completely skipped for the target.
+ self.empty = []
+ # A list of results. Each entry is a pair in which the first element
+ # is a unique sorting key and in which the second is the full
+ # PASS/FAIL line.
+ self.results = []
+
+ # Add a segment of text to the harness run. If the segment includes
+ # test results, KEY is an example of one of them, and can be used to
+ # combine the individual segments in order. If the segment has no
+ # test results (e.g. because the harness doesn't do anything for the
+ # current configuration) then KEY is None instead. In that case
+ # just collect the segments in the order that we see them.
+ def add_segment (self, key, segment):
+ if key:
+ assert key not in self.segments
+ self.segments[key] = segment
+ else:
+ self.empty.append (segment)
+
+class Segment:
+ def __init__ (self, filename, start):
+ self.filename = filename
+ self.start = start
+ self.lines = 0
+
+class Prog:
+ def __init__ (self):
+ # The variations specified on the command line.
+ self.variations = []
+ # The variations seen in the input files.
+ self.known_variations = set()
+ # The tools specified on the command line.
+ self.tools = []
+ # Whether to create .sum rather than .log output.
+ self.do_sum = True
+ # Regexps used while parsing.
+ self.test_run_re = re.compile (r'^Test Run By (\S+) on (.*)$')
+ self.tool_re = re.compile (r'^\t\t=== (.*) tests ===$')
+ self.result_re = re.compile (r'^(PASS|XPASS|FAIL|XFAIL|UNRESOLVED'
+ r'|WARNING|ERROR|UNSUPPORTED|UNTESTED'
+ r'|KFAIL):\s*(.+)')
+ self.completed_re = re.compile (r'.* completed at (.*)')
+ # Pieces of text to write at the head of the output.
+ # start_line is a pair in which the first element is a datetime
+ # and in which the second is the associated 'Test Run By' line.
+ self.start_line = None
+ self.native_line = ''
+ self.target_line = ''
+ self.host_line = ''
+ self.acats_premable = ''
+ # Pieces of text to write at the end of the output.
+ # end_line is like start_line but for the 'runtest completed' line.
+ self.acats_failures = []
+ self.version_output = ''
+ self.end_line = None
+ # Known summary types.
+ self.count_names = [
+ '# of DejaGnu errors\t\t',
+ '# of expected passes\t\t',
+ '# of unexpected failures\t',
+ '# of unexpected successes\t',
+ '# of expected failures\t\t',
+ '# of unknown successes\t\t',
+ '# of known failures\t\t',
+ '# of untested testcases\t\t',
+ '# of unresolved testcases\t',
+ '# of unsupported tests\t\t'
+ ]
+ self.runs = dict()
+
+ def usage (self):
+ name = sys.argv[0]
+ sys.stderr.write ('Usage: ' + name
+ + ''' [-t tool] [-l variant-list] [-L] log-or-sum-file ...
+
+ tool The tool (e.g. g++, libffi) for which to create a
+ new test summary file. If not specified then output
+ is created for all tools.
+ variant-list One or more test variant names. If the list is
+ not specified then one is constructed from all
+ variants in the files for <tool>.
+ sum-file A test summary file with the format of those
+ created by runtest from DejaGnu.
+ If -L is used, merge *.log files instead of *.sum. In this
+ mode the exact order of lines may not be preserved, just different
+ Running *.exp chunks should be in correct order.
+''')
+ sys.exit (1)
+
+ def fatal (self, what, string):
+ if not what:
+ what = sys.argv[0]
+ sys.stderr.write (what + ': ' + string + '\n')
+ sys.exit (1)
+
+ # Parse the command-line arguments.
+ def parse_cmdline (self):
+ try:
+ (options, self.files) = getopt.getopt (sys.argv[1:], 'l:t:L')
+ if len (self.files) == 0:
+ self.usage()
+ for (option, value) in options:
+ if option == '-l':
+ self.variations.append (value)
+ elif option == '-t':
+ self.tools.append (value)
+ else:
+ self.do_sum = False
+ except getopt.GetoptError as e:
+ self.fatal (None, e.msg)
+
+ # Try to parse time string TIME, returning an arbitrary time on failure.
+ # Getting this right is just a nice-to-have so failures should be silent.
+ def parse_time (self, time):
+ try:
+ return datetime.strptime (time, '%c')
+ except ValueError:
+ return datetime.now()
+
+ # Parse an integer and abort on failure.
+ def parse_int (self, filename, value):
+ try:
+ return int (value)
+ except ValueError:
+ self.fatal (filename, 'expected an integer, got: ' + value)
+
+ # Return a list that represents no test results.
+ def zero_counts (self):
+ return [0 for x in self.count_names]
+
+ # Return the ToolRun for tool NAME.
+ def get_tool (self, name):
+ if name not in self.runs:
+ self.runs[name] = ToolRun (name)
+ return self.runs[name]
+
+ # Add the result counts in list FROMC to TOC.
+ def accumulate_counts (self, toc, fromc):
+ for i in range (len (self.count_names)):
+ toc[i] += fromc[i]
+
+ # Parse the list of variations after 'Schedule of variations:'.
+ # Return the number seen.
+ def parse_variations (self, filename, file):
+ num_variations = 0
+ while True:
+ line = file.readline()
+ if line == '':
+ self.fatal (filename, 'could not parse variation list')
+ if line == '\n':
+ break
+ self.known_variations.add (line.strip())
+ num_variations += 1
+ return num_variations
+
+ # Parse from the first line after 'Running target ...' to the end
+ # of the run's summary.
+ def parse_run (self, filename, file, tool, variation, num_variations):
+ header = None
+ harness = None
+ segment = None
+ final_using = 0
+
+ # If this is the first run for this variation, add any text before
+ # the first harness to the header.
+ if not variation.header:
+ segment = Segment (filename, file.tell())
+ variation.header = segment
+
+ # Parse the rest of the summary (the '# of ' lines).
+ if len (variation.counts) == 0:
+ variation.counts = self.zero_counts()
+
+ # Parse up until the first line of the summary.
+ if num_variations == 1:
+ end = '\t\t=== ' + tool.name + ' Summary ===\n'
+ else:
+ end = ('\t\t=== ' + tool.name + ' Summary for '
+ + variation.name + ' ===\n')
+ while True:
+ line = file.readline()
+ if line == '':
+ self.fatal (filename, 'no recognised summary line')
+ if line == end:
+ break
+
+ # Look for the start of a new harness.
+ if line.startswith ('Running ') and line.endswith (' ...\n'):
+ # Close off the current harness segment, if any.
+ if harness:
+ segment.lines -= final_using
+ harness.add_segment (first_key, segment)
+ name = line[len ('Running '):-len(' ...\n')]
+ harness = variation.get_harness (name)
+ segment = Segment (filename, file.tell())
+ first_key = None
+ final_using = 0
+ continue
+
+ # Record test results. Associate the first test result with
+ # the harness segment, so that if a run for a particular harness
+ # has been split up, we can reassemble the individual segments
+ # in a sensible order.
+ #
+ # dejagnu sometimes issues warnings about the testing environment
+ # before running any tests. Treat them as part of the header
+ # rather than as a test result.
+ match = self.result_re.match (line)
+ if match and (harness or not line.startswith ('WARNING:')):
+ if not harness:
+ self.fatal (filename, 'saw test result before harness name')
+ name = match.group (2)
+ # Ugly hack to get the right order for gfortran.
+ if name.startswith ('gfortran.dg/g77/'):
+ name = 'h' + name
+ key = (name, len (harness.results))
+ harness.results.append ((key, line))
+ if not first_key and sort_logs:
+ first_key = key
+ if line.startswith ('ERROR: (DejaGnu)'):
+ for i in range (len (self.count_names)):
+ if 'DejaGnu errors' in self.count_names[i]:
+ variation.counts[i] += 1
+ break
+
+ # 'Using ...' lines are only interesting in a header. Splitting
+ # the test up into parallel runs leads to more 'Using ...' lines
+ # than there would be in a single log.
+ if line.startswith ('Using '):
+ final_using += 1
+ else:
+ final_using = 0
+
+ # Add other text to the current segment, if any.
+ if segment:
+ segment.lines += 1
+
+ # Close off the final harness segment, if any.
+ if harness:
+ segment.lines -= final_using
+ harness.add_segment (first_key, segment)
+
+ while True:
+ before = file.tell()
+ line = file.readline()
+ if line == '':
+ break
+ if line == '\n':
+ continue
+ if not line.startswith ('# '):
+ file.seek (before)
+ break
+ found = False
+ for i in range (len (self.count_names)):
+ if line.startswith (self.count_names[i]):
+ count = line[len (self.count_names[i]):-1].strip()
+ variation.counts[i] += self.parse_int (filename, count)
+ found = True
+ break
+ if not found:
+ self.fatal (filename, 'unknown test result: ' + line[:-1])
+
+ # Parse an acats run, which uses a different format from dejagnu.
+ # We have just skipped over '=== acats configuration ==='.
+ def parse_acats_run (self, filename, file):
+ # Parse the preamble, which describes the configuration and logs
+ # the creation of support files.
+ record = (self.acats_premable == '')
+ if record:
+ self.acats_premable = '\t\t=== acats configuration ===\n'
+ while True:
+ line = file.readline()
+ if line == '':
+ self.fatal (filename, 'could not parse acats preamble')
+ if line == '\t\t=== acats tests ===\n':
+ break
+ if record:
+ self.acats_premable += line
+
+ # Parse the test results themselves, using a dummy variation name.
+ tool = self.get_tool ('acats')
+ variation = tool.get_variation ('none')
+ self.parse_run (filename, file, tool, variation, 1)
+
+ # Parse the failure list.
+ while True:
+ before = file.tell()
+ line = file.readline()
+ if line.startswith ('*** FAILURES: '):
+ self.acats_failures.append (line[len ('*** FAILURES: '):-1])
+ continue
+ file.seek (before)
+ break
+
+ # Parse the final summary at the end of a log in order to capture
+ # the version output that follows it.
+ def parse_final_summary (self, filename, file):
+ record = (self.version_output == '')
+ while True:
+ line = file.readline()
+ if line == '':
+ break
+ if line.startswith ('# of '):
+ continue
+ if record:
+ self.version_output += line
+ if line == '\n':
+ break
+
+ # Parse a .log or .sum file.
+ def parse_file (self, filename, file):
+ tool = None
+ target = None
+ num_variations = 1
+ while True:
+ line = file.readline()
+ if line == '':
+ return
+
+ # Parse the list of variations, which comes before the test
+ # runs themselves.
+ if line.startswith ('Schedule of variations:'):
+ num_variations = self.parse_variations (filename, file)
+ continue
+
+ # Parse a testsuite run for one tool/variation combination.
+ if line.startswith ('Running target '):
+ name = line[len ('Running target '):-1]
+ if not tool:
+ self.fatal (filename, 'could not parse tool name')
+ if name not in self.known_variations:
+ self.fatal (filename, 'unknown target: ' + name)
+ self.parse_run (filename, file, tool,
+ tool.get_variation (name),
+ num_variations)
+ # If there is only one variation then there is no separate
+ # summary for it. Record any following version output.
+ if num_variations == 1:
+ self.parse_final_summary (filename, file)
+ continue
+
+ # Parse the start line. In the case where several files are being
+ # parsed, pick the one with the earliest time.
+ match = self.test_run_re.match (line)
+ if match:
+ time = self.parse_time (match.group (2))
+ if not self.start_line or self.start_line[0] > time:
+ self.start_line = (time, line)
+ continue
+
+ # Parse the form used for native testing.
+ if line.startswith ('Native configuration is '):
+ self.native_line = line
+ continue
+
+ # Parse the target triplet.
+ if line.startswith ('Target is '):
+ self.target_line = line
+ continue
+
+ # Parse the host triplet.
+ if line.startswith ('Host is '):
+ self.host_line = line
+ continue
+
+ # Parse the acats premable.
+ if line == '\t\t=== acats configuration ===\n':
+ self.parse_acats_run (filename, file)
+ continue
+
+ # Parse the tool name.
+ match = self.tool_re.match (line)
+ if match:
+ tool = self.get_tool (match.group (1))
+ continue
+
+ # Skip over the final summary (which we instead create from
+ # individual runs) and parse the version output.
+ if tool and line == '\t\t=== ' + tool.name + ' Summary ===\n':
+ if file.readline() != '\n':
+ self.fatal (filename, 'expected blank line after summary')
+ self.parse_final_summary (filename, file)
+ continue
+
+ # Parse the completion line. In the case where several files
+ # are being parsed, pick the one with the latest time.
+ match = self.completed_re.match (line)
+ if match:
+ time = self.parse_time (match.group (1))
+ if not self.end_line or self.end_line[0] < time:
+ self.end_line = (time, line)
+ continue
+
+ # Sanity check to make sure that important text doesn't get
+ # dropped accidentally.
+ if strict and line.strip() != '':
+ self.fatal (filename, 'unrecognised line: ' + line[:-1])
+
+ # Output a segment of text.
+ def output_segment (self, segment):
+ with safe_open (segment.filename) as file:
+ file.seek (segment.start)
+ for i in range (segment.lines):
+ sys.stdout.write (file.readline())
+
+ # Output a summary giving the number of times each type of result has
+ # been seen.
+ def output_summary (self, tool, counts):
+ for i in range (len (self.count_names)):
+ name = self.count_names[i]
+ # dejagnu only prints result types that were seen at least once,
+ # but acats always prints a number of unexpected failures.
+ if (counts[i] > 0
+ or (tool.name == 'acats'
+ and name.startswith ('# of unexpected failures'))):
+ sys.stdout.write ('%s%d\n' % (name, counts[i]))
+
+ # Output unified .log or .sum information for a particular variation,
+ # with a summary at the end.
+ def output_variation (self, tool, variation):
+ self.output_segment (variation.header)
+ for harness in sorted (variation.harnesses.values(),
+ key = attrgetter ('name')):
+ sys.stdout.write ('Running ' + harness.name + ' ...\n')
+ if self.do_sum:
+ harness.results.sort()
+ for (key, line) in harness.results:
+ sys.stdout.write (line)
+ else:
+ # Rearrange the log segments into test order (but without
+ # rearranging text within those segments).
+ for key in sorted (harness.segments.keys()):
+ self.output_segment (harness.segments[key])
+ for segment in harness.empty:
+ self.output_segment (segment)
+ if len (self.variations) > 1:
+ sys.stdout.write ('\t\t=== ' + tool.name + ' Summary for '
+ + variation.name + ' ===\n\n')
+ self.output_summary (tool, variation.counts)
+
+ # Output unified .log or .sum information for a particular tool,
+ # with a summary at the end.
+ def output_tool (self, tool):
+ counts = self.zero_counts()
+ if tool.name == 'acats':
+ # acats doesn't use variations, so just output everything.
+ # It also has a different approach to whitespace.
+ sys.stdout.write ('\t\t=== ' + tool.name + ' tests ===\n')
+ for variation in tool.variations.values():
+ self.output_variation (tool, variation)
+ self.accumulate_counts (counts, variation.counts)
+ sys.stdout.write ('\t\t=== ' + tool.name + ' Summary ===\n')
+ else:
+ # Output the results in the usual dejagnu runtest format.
+ sys.stdout.write ('\n\t\t=== ' + tool.name + ' tests ===\n\n'
+ 'Schedule of variations:\n')
+ for name in self.variations:
+ if name in tool.variations:
+ sys.stdout.write (' ' + name + '\n')
+ sys.stdout.write ('\n')
+ for name in self.variations:
+ if name in tool.variations:
+ variation = tool.variations[name]
+ sys.stdout.write ('Running target '
+ + variation.name + '\n')
+ self.output_variation (tool, variation)
+ self.accumulate_counts (counts, variation.counts)
+ sys.stdout.write ('\n\t\t=== ' + tool.name + ' Summary ===\n\n')
+ self.output_summary (tool, counts)
+
+ def main (self):
+ self.parse_cmdline()
+ try:
+ # Parse the input files.
+ for filename in self.files:
+ with safe_open (filename) as file:
+ self.parse_file (filename, file)
+
+ # Decide what to output.
+ if len (self.variations) == 0:
+ self.variations = sorted (self.known_variations)
+ else:
+ for name in self.variations:
+ if name not in self.known_variations:
+ self.fatal (None, 'no results for ' + name)
+ if len (self.tools) == 0:
+ self.tools = sorted (self.runs.keys())
+
+ # Output the header.
+ if self.start_line:
+ sys.stdout.write (self.start_line[1])
+ sys.stdout.write (self.native_line)
+ sys.stdout.write (self.target_line)
+ sys.stdout.write (self.host_line)
+ sys.stdout.write (self.acats_premable)
+
+ # Output the main body.
+ for name in self.tools:
+ if name not in self.runs:
+ self.fatal (None, 'no results for ' + name)
+ self.output_tool (self.runs[name])
+
+ # Output the footer.
+ if len (self.acats_failures) > 0:
+ sys.stdout.write ('*** FAILURES: '
+ + ' '.join (self.acats_failures) + '\n')
+ sys.stdout.write (self.version_output)
+ if self.end_line:
+ sys.stdout.write (self.end_line[1])
+ except IOError as e:
+ self.fatal (e.filename, e.strerror)
+
+Prog().main()
diff --git a/contrib/dg-extract-results.sh b/contrib/dg-extract-results.sh
new file mode 100755
index 0000000..6ee3d26
--- /dev/null
+++ b/contrib/dg-extract-results.sh
@@ -0,0 +1,459 @@
+#! /bin/sh
+
+# For a specified tool and optional list of test variants, extract
+# test results from one or more test summary (.sum) files and combine
+# the results into a new test summary file, sent to the standard output.
+# The resulting file can be used with test result comparison scripts for
+# results from tests that were run in parallel. See usage() below.
+
+# Copyright (C) 2008, 2009, 2010, 2012 Free Software Foundation
+# Contributed by Janis Johnson <janis187@us.ibm.com>
+#
+# This file is part of GCC.
+#
+# GCC 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 3, or (at your option)
+# any later version.
+#
+# GCC 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 GCC; see the file COPYING. If not, write to
+# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+PROGNAME=dg-extract-results.sh
+
+# Try to use the python version if possible, since it tends to be faster.
+PYTHON_VER=`echo "$0" | sed 's/sh$/py/'`
+if test "$PYTHON_VER" != "$0" &&
+ test -f "$PYTHON_VER" &&
+ python -c 'import sys, getopt, re, io, datetime, operator; sys.exit (0 if sys.version_info >= (2, 6) else 1)' \
+ > /dev/null 2> /dev/null; then
+ exec python $PYTHON_VER "$@"
+fi
+
+usage() {
+ cat <<EOF >&2
+Usage: $PROGNAME [-t tool] [-l variant-list] [-L] sum-file ...
+
+ tool The tool (e.g. g++, libffi) for which to create a
+ new test summary file. If not specified then all
+ specified sum files must be for the same tool.
+ variant-list One or more test variant names. If the list is
+ not specified then one is constructed from all
+ variants in the files for <tool>.
+ sum-file A test summary file with the format of those
+ created by runtest from DejaGnu.
+ If -L is used, merge *.log files instead of *.sum. In this
+ mode the exact order of lines may not be preserved, just different
+ Running *.exp chunks should be in correct order.
+EOF
+}
+
+# Write a message to the standard error.
+
+msg() {
+ echo "$@" >&2
+}
+
+# Parse the command-line options.
+
+VARIANTS=""
+TOOL=""
+MODE="sum"
+
+while getopts "l:t:L" ARG; do
+ case $ARG in
+ l) VARIANTS="${VARIANTS} ${OPTARG}";;
+ t) test -z "$TOOL" || (msg "${PROGNAME}: only one tool can be specified"; exit 1);
+ TOOL="${OPTARG}";;
+ L) MODE="log";;
+ \?) usage; exit 0;;
+ esac
+done
+shift `expr ${OPTIND} - 1`
+
+if test $# -lt 1 ; then
+ usage
+ exit 1
+fi
+
+TMPDIR=${TMPDIR-/tmp}
+SUM_FILES="$@"
+FIRST_SUM=$1
+TMP=
+trap 'EXIT_STATUS=$?; rm -rf $TMP && exit $EXIT_STATUS' 0
+# Create a (secure) tmp directory for tmp files.
+{
+ TMP=`(umask 077 && mktemp -d -q "${TMPDIR}/dg-combine-results-$$-XXXXXX") 2>/dev/null` &&
+ test -n "$TMP" && test -d "$TMP"
+} ||
+{
+ TMP=${TMPDIR}/dg-combine-results-$$-$RANDOM
+ (umask 077 && mkdir $TMP)
+} ||
+{
+ msg "${PROGNAME}: cannot create a temporary directory"
+ { (exit 1); exit 1; }
+}
+
+# Find a good awk.
+
+if test -z "$AWK" ; then
+ for AWK in gawk nawk awk
+ do
+ if type $AWK 2>&1 | grep 'not found' > /dev/null 2>&1 ; then
+ :
+ else
+ break
+ fi
+ done
+fi
+
+# Verify that the specified summary files exist.
+
+ERROR=0
+for FILE in $SUM_FILES
+do
+ if ! test -f $FILE ; then
+ msg "${PROGNAME}: file $FILE does not exist."
+ ERROR=1
+ fi
+done
+test $ERROR -eq 0 || exit 1
+
+# Test if grep supports the '--text' option
+
+GREP=grep
+
+if echo -e '\x00foo\x00' | $GREP --text foo > /dev/null 2>&1 ; then
+ GREP="grep --text"
+else
+ # Our grep does not recognize the '--text' option. We have to
+ # treat our files in order to remove any non-printable character.
+ for file in $SUM_FILES ; do
+ mv $file ${file}.orig
+ cat -v ${file}.orig > $file
+ done
+fi
+
+if [ -z "$TOOL" ]; then
+ # If no tool was specified, all specified summary files must be for
+ # the same tool.
+
+ CNT=`$GREP '=== .* tests ===' $SUM_FILES | $AWK '{ print $3 }' | sort -u | wc -l`
+ if [ $CNT -eq 1 ]; then
+ TOOL=`$GREP '=== .* tests ===' $FIRST_SUM | $AWK '{ print $2 }'`
+ else
+ msg "${PROGNAME}: sum files are for multiple tools, specify a tool"
+ msg ""
+ usage
+ exit 1
+ fi
+else
+ # Ignore the specified summary files that are not for this tool. This
+ # should keep the relevant files in the same order.
+
+ SUM_FILES=`$GREP -l "=== $TOOL" $SUM_FILES`
+ if test -z "$SUM_FILES" ; then
+ msg "${PROGNAME}: none of the specified files are results for $TOOL"
+ exit 1
+ fi
+fi
+
+if [ "$TOOL" = acats ]; then
+ # Acats *.sum or *.log files aren't dejagnu generated, and they have
+ # somewhat different format.
+ ACATS_AWK=${TMP}/acats.awk
+ cat <<EOF > $ACATS_AWK
+BEGIN {
+ print_prologue=1; curfile=""; insummary=0
+ passcnt=0; failcnt=0; unsupcnt=0; failures=""
+}
+/^[ \t]*=== acats configuration ===/ {
+ insummary=0
+ if (print_prologue) print
+ next
+}
+/^[ \t]*=== acats tests ===/ {
+ if (print_prologue) print
+ print_prologue=0
+ next
+}
+/^Running chapter / {
+ if (curfile) close (curfile)
+ curfile="${TMP}/chapter-"\$3
+ print >> curfile
+ next
+}
+/^[ \t]*=== acats Summary ===/ {
+ if (curfile) close (curfile)
+ curfile=""
+ insummary=1
+ next
+}
+/^# of expected passes/ { if (insummary == 1) passcnt += \$5; next; }
+/^# of unexpected failures/ { if (insummary == 1) failcnt += \$5; next; }
+/^# of unsupported tests/ { if (insummary == 1) unsupcnt += \$5; next; }
+/^\*\*\* FAILURES: / {
+ if (insummary == 1) {
+ if (failures) sub(/^\*\*\* FAILURES:/,"")
+ failures=failures""\$0
+ }
+}
+{
+ if (print_prologue) { print; next }
+ if (curfile) print >> curfile
+}
+END {
+ system ("cat ${TMP}/chapter-*")
+ print " === acats Summary ==="
+ print "# of expected passes " passcnt
+ print "# of unexpected failures " failcnt
+ if (unsupcnt) print "# of unsupported tests " unsupcnt
+ if (failures) print failures
+}
+EOF
+
+ rm -f ${TMP}/chapter-*
+ $AWK -f $ACATS_AWK $SUM_FILES
+ exit 0
+fi
+
+# If no variants were specified, find all variants in the remaining
+# summary files. Otherwise, ignore specified variants that aren't in
+# any of those summary files.
+
+if test -z "$VARIANTS" ; then
+ VAR_AWK=${TMP}/variants.awk
+ cat <<EOF > $VAR_AWK
+/^Schedule of variations:/ { in_vars=1; next }
+/^$/ { in_vars=0 }
+/^Running target/ { exit }
+{ if (in_vars==1) print \$1; else next }
+EOF
+
+ touch ${TMP}/varlist
+ for FILE in $SUM_FILES; do
+ $AWK -f $VAR_AWK $FILE >> ${TMP}/varlist
+ done
+ VARIANTS="`sort -u ${TMP}/varlist`"
+else
+ VARS="$VARIANTS"
+ VARIANTS=""
+ for VAR in $VARS
+ do
+ $GREP "Running target $VAR" $SUM_FILES > /dev/null && VARIANTS="$VARIANTS $VAR"
+ done
+fi
+
+# Find out if we have more than one variant, or any at all.
+
+VARIANT_COUNT=0
+for VAR in $VARIANTS
+do
+ VARIANT_COUNT=`expr $VARIANT_COUNT + 1`
+done
+
+if test $VARIANT_COUNT -eq 0 ; then
+ msg "${PROGNAME}: no file for $TOOL has results for the specified variants"
+ exit 1
+fi
+
+cat $SUM_FILES \
+ | $AWK '/^Running/ { if ($2 != "target" && $3 == "...") print "EXPFILE: "$2 } ' \
+ | sort -u > ${TMP}/expfiles
+
+# Write the begining of the combined summary file.
+
+head -n 2 $FIRST_SUM
+echo
+echo " === $TOOL tests ==="
+echo
+echo "Schedule of variations:"
+for VAR in $VARIANTS
+do
+ echo " $VAR"
+done
+echo
+
+# For each test variant for the tool, copy test reports from each of the
+# summary files. Set up two awk scripts from within the loop to
+# initialize VAR and TOOL with the script, rather than assuming that the
+# available version of awk can pass variables from the command line.
+
+for VAR in $VARIANTS
+do
+ GUTS_AWK=${TMP}/guts.awk
+ cat << EOF > $GUTS_AWK
+BEGIN {
+ variant="$VAR"
+ firstvar=1
+ expfileno=1
+ cnt=0
+ print_using=0
+ need_close=0
+}
+/^EXPFILE: / {
+ expfiles[expfileno] = \$2
+ expfilesr[\$2] = expfileno
+ expfileno = expfileno + 1
+}
+/^Running target / {
+ curvar = \$3
+ if (variant == curvar && firstvar == 1) { print; print_using=1; firstvar = 0 }
+ next
+}
+/^Using / {
+ if (variant == curvar && print_using) { print; next }
+}
+/^Running .*\\.exp \\.\\.\\./ {
+ print_using=0
+ if (variant == curvar) {
+ if (need_close) close(curfile)
+ curfile="${TMP}/list"expfilesr[\$2]
+ expfileseen[\$2]=expfileseen[\$2] + 1
+ need_close=0
+ testname="00"
+ next
+ }
+}
+/^\t\t=== .* ===$/ { curvar = ""; next }
+/^(PASS|XPASS|FAIL|XFAIL|UNRESOLVED|WARNING|ERROR|UNSUPPORTED|UNTESTED|KFAIL):/ {
+ testname=\$2
+ # Ugly hack for gfortran.dg/dg.exp
+ if ("$TOOL" == "gfortran" && testname ~ /^gfortran.dg\/g77\//)
+ testname="h"testname
+}
+/^$/ { if ("$MODE" == "sum") next }
+{ if (variant == curvar && curfile) {
+ if ("$MODE" == "sum") {
+ printf "%s %08d|", testname, cnt >> curfile
+ cnt = cnt + 1
+ }
+ filewritten[curfile]=1
+ need_close=1
+ print >> curfile
+ } else
+ next
+}
+END {
+ n=1
+ while (n < expfileno) {
+ if (expfileseen[expfiles[n]]) {
+ print "Running "expfiles[n]" ..."
+ if (filewritten["${TMP}/list"n]) {
+ if (expfileseen[expfiles[n]] == 1)
+ cmd="cat"
+ else
+ cmd="LC_ALL=C sort"
+ if ("$MODE" == "sum")
+ system (cmd" ${TMP}/list"n" | sed -n 's/^[^ ]* [^ |]*|//p'")
+ else
+ system ("cat ${TMP}/list"n)
+ }
+ }
+ n = n + 1
+ }
+}
+EOF
+
+ SUMS_AWK=${TMP}/sums.awk
+ rm -f $SUMS_AWK
+ cat << EOF > $SUMS_AWK
+BEGIN {
+ variant="$VAR"
+ tool="$TOOL"
+ passcnt=0; failcnt=0; untstcnt=0; xpasscnt=0; xfailcnt=0; kpasscnt=0; kfailcnt=0; unsupcnt=0; unrescnt=0; dgerrorcnt=0;
+ curvar=""; insummary=0
+}
+/^Running target / { curvar = \$3; next }
+/^ERROR: \(DejaGnu\)/ { if (variant == curvar) dgerrorcnt += 1 }
+/^# of / { if (variant == curvar) insummary = 1 }
+/^# of expected passes/ { if (insummary == 1) passcnt += \$5; next; }
+/^# of unexpected successes/ { if (insummary == 1) xpasscnt += \$5; next; }
+/^# of unexpected failures/ { if (insummary == 1) failcnt += \$5; next; }
+/^# of expected failures/ { if (insummary == 1) xfailcnt += \$5; next; }
+/^# of unknown successes/ { if (insummary == 1) kpasscnt += \$5; next; }
+/^# of known failures/ { if (insummary == 1) kfailcnt += \$5; next; }
+/^# of untested testcases/ { if (insummary == 1) untstcnt += \$5; next; }
+/^# of unresolved testcases/ { if (insummary == 1) unrescnt += \$5; next; }
+/^# of unsupported tests/ { if (insummary == 1) unsupcnt += \$5; next; }
+/^$/ { if (insummary == 1)
+ { insummary = 0; curvar = "" }
+ next
+ }
+{ next }
+END {
+ printf ("\t\t=== %s Summary for %s ===\n\n", tool, variant)
+ if (dgerrorcnt != 0) printf ("# of DejaGnu errors\t\t%d\n", dgerrorcnt)
+ if (passcnt != 0) printf ("# of expected passes\t\t%d\n", passcnt)
+ if (failcnt != 0) printf ("# of unexpected failures\t%d\n", failcnt)
+ if (xpasscnt != 0) printf ("# of unexpected successes\t%d\n", xpasscnt)
+ if (xfailcnt != 0) printf ("# of expected failures\t\t%d\n", xfailcnt)
+ if (kpasscnt != 0) printf ("# of unknown successes\t\t%d\n", kpasscnt)
+ if (kfailcnt != 0) printf ("# of known failures\t\t%d\n", kfailcnt)
+ if (untstcnt != 0) printf ("# of untested testcases\t\t%d\n", untstcnt)
+ if (unrescnt != 0) printf ("# of unresolved testcases\t%d\n", unrescnt)
+ if (unsupcnt != 0) printf ("# of unsupported tests\t\t%d\n", unsupcnt)
+}
+EOF
+
+ PVAR=`echo $VAR | sed 's,/,.,g'`
+ TMPFILE=${TMP}/var-$PVAR
+ rm -f $TMPFILE
+ rm -f ${TMP}/list*
+ cat ${TMP}/expfiles $SUM_FILES | $AWK -f $GUTS_AWK
+ cat $SUM_FILES | $AWK -f $SUMS_AWK > $TMPFILE
+ # If there are multiple variants, output the counts for this one;
+ # otherwise there will just be the final counts at the end.
+ test $VARIANT_COUNT -eq 1 || cat $TMPFILE
+done
+
+# Set up an awk script to get the combined summary counts for the tool.
+
+TOTAL_AWK=${TMP}/total.awk
+cat << EOF > $TOTAL_AWK
+BEGIN {
+ tool="$TOOL"
+ passcnt=0; failcnt=0; untstcnt=0; xpasscnt=0; xfailcnt=0; kfailcnt=0; unsupcnt=0; unrescnt=0; dgerrorcnt=0
+}
+/^# of DejaGnu errors/ { dgerrorcnt += \$5 }
+/^# of expected passes/ { passcnt += \$5 }
+/^# of unexpected failures/ { failcnt += \$5 }
+/^# of unexpected successes/ { xpasscnt += \$5 }
+/^# of expected failures/ { xfailcnt += \$5 }
+/^# of unknown successes/ { kpasscnt += \$5 }
+/^# of known failures/ { kfailcnt += \$5 }
+/^# of untested testcases/ { untstcnt += \$5 }
+/^# of unresolved testcases/ { unrescnt += \$5 }
+/^# of unsupported tests/ { unsupcnt += \$5 }
+END {
+ printf ("\n\t\t=== %s Summary ===\n\n", tool)
+ if (dgerrorcnt != 0) printf ("# of DejaGnu errors\t\t%d\n", dgerrorcnt)
+ if (passcnt != 0) printf ("# of expected passes\t\t%d\n", passcnt)
+ if (failcnt != 0) printf ("# of unexpected failures\t%d\n", failcnt)
+ if (xpasscnt != 0) printf ("# of unexpected successes\t%d\n", xpasscnt)
+ if (xfailcnt != 0) printf ("# of expected failures\t\t%d\n", xfailcnt)
+ if (kpasscnt != 0) printf ("# of unknown successes\t\t%d\n", kpasscnt)
+ if (kfailcnt != 0) printf ("# of known failures\t\t%d\n", kfailcnt)
+ if (untstcnt != 0) printf ("# of untested testcases\t\t%d\n", untstcnt)
+ if (unrescnt != 0) printf ("# of unresolved testcases\t%d\n", unrescnt)
+ if (unsupcnt != 0) printf ("# of unsupported tests\t\t%d\n", unsupcnt)
+}
+EOF
+
+# Find the total summaries for the tool and add to the end of the output.
+cat ${TMP}/var-* | $AWK -f $TOTAL_AWK
+
+# This is ugly, but if there's version output from the compiler under test
+# at the end of the file, we want it. The other thing that might be there
+# is the final summary counts.
+tail -2 $FIRST_SUM | $GREP '^#' > /dev/null || tail -2 $FIRST_SUM
+
+exit 0