xref: /aosp_15_r20/external/mksh/src/check.pl (revision 7c356e860f31eadd15fd599fcfdb9fd21f16a9d4)
1*7c356e86SAndroid Build Coastguard Worker# $MirOS: src/bin/mksh/check.pl,v 1.51 2020/06/22 17:10:59 tg Exp $
2*7c356e86SAndroid Build Coastguard Worker# $OpenBSD: th,v 1.1 2013/12/02 20:39:44 millert Exp $
3*7c356e86SAndroid Build Coastguard Worker#-
4*7c356e86SAndroid Build Coastguard Worker# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
5*7c356e86SAndroid Build Coastguard Worker#		2012, 2013, 2014, 2015, 2017
6*7c356e86SAndroid Build Coastguard Worker#	mirabilos <[email protected]>
7*7c356e86SAndroid Build Coastguard Worker#
8*7c356e86SAndroid Build Coastguard Worker# Provided that these terms and disclaimer and all copyright notices
9*7c356e86SAndroid Build Coastguard Worker# are retained or reproduced in an accompanying document, permission
10*7c356e86SAndroid Build Coastguard Worker# is granted to deal in this work without restriction, including un-
11*7c356e86SAndroid Build Coastguard Worker# limited rights to use, publicly perform, distribute, sell, modify,
12*7c356e86SAndroid Build Coastguard Worker# merge, give away, or sublicence.
13*7c356e86SAndroid Build Coastguard Worker#
14*7c356e86SAndroid Build Coastguard Worker# This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
15*7c356e86SAndroid Build Coastguard Worker# the utmost extent permitted by applicable law, neither express nor
16*7c356e86SAndroid Build Coastguard Worker# implied; without malicious intent or gross negligence. In no event
17*7c356e86SAndroid Build Coastguard Worker# may a licensor, author or contributor be held liable for indirect,
18*7c356e86SAndroid Build Coastguard Worker# direct, other damage, loss, or other issues arising in any way out
19*7c356e86SAndroid Build Coastguard Worker# of dealing in the work, even if advised of the possibility of such
20*7c356e86SAndroid Build Coastguard Worker# damage or existence of a defect, except proven that it results out
21*7c356e86SAndroid Build Coastguard Worker# of said person's immediate fault when using the work as intended.
22*7c356e86SAndroid Build Coastguard Worker#-
23*7c356e86SAndroid Build Coastguard Worker# Example test:
24*7c356e86SAndroid Build Coastguard Worker#		name: a-test
25*7c356e86SAndroid Build Coastguard Worker#		description:
26*7c356e86SAndroid Build Coastguard Worker#			a test to show how tests are done
27*7c356e86SAndroid Build Coastguard Worker#		arguments: !-x!-f!
28*7c356e86SAndroid Build Coastguard Worker#		stdin:
29*7c356e86SAndroid Build Coastguard Worker#			echo -n *
30*7c356e86SAndroid Build Coastguard Worker#			false
31*7c356e86SAndroid Build Coastguard Worker#		expected-stdout: !
32*7c356e86SAndroid Build Coastguard Worker#			*
33*7c356e86SAndroid Build Coastguard Worker#		expected-stderr:
34*7c356e86SAndroid Build Coastguard Worker#			+ echo -n *
35*7c356e86SAndroid Build Coastguard Worker#			+ false
36*7c356e86SAndroid Build Coastguard Worker#		expected-exit: 1
37*7c356e86SAndroid Build Coastguard Worker#		---
38*7c356e86SAndroid Build Coastguard Worker#	This runs the test-program (eg, mksh) with the arguments -x and -f,
39*7c356e86SAndroid Build Coastguard Worker#	standard input is a file containing "echo hi*\nfalse\n". The program
40*7c356e86SAndroid Build Coastguard Worker#	is expected to produce "hi*" (no trailing newline) on standard output,
41*7c356e86SAndroid Build Coastguard Worker#	"+ echo hi*\n+false\n" on standard error, and an exit code of 1.
42*7c356e86SAndroid Build Coastguard Worker#
43*7c356e86SAndroid Build Coastguard Worker#
44*7c356e86SAndroid Build Coastguard Worker# Format of test files:
45*7c356e86SAndroid Build Coastguard Worker# - blank lines and lines starting with # are ignored
46*7c356e86SAndroid Build Coastguard Worker# - a test file contains a series of tests
47*7c356e86SAndroid Build Coastguard Worker# - a test is a series of tag:value pairs ended with a "---" line
48*7c356e86SAndroid Build Coastguard Worker#   (leading/trailing spaces are stripped from the first line of value)
49*7c356e86SAndroid Build Coastguard Worker# - test tags are:
50*7c356e86SAndroid Build Coastguard Worker#	Tag			Flag	Description
51*7c356e86SAndroid Build Coastguard Worker#	-----			----	-----------
52*7c356e86SAndroid Build Coastguard Worker#	name			r	The name of the test; should be unique
53*7c356e86SAndroid Build Coastguard Worker#	description		m	What test does
54*7c356e86SAndroid Build Coastguard Worker#	arguments		M	Arguments to pass to the program;
55*7c356e86SAndroid Build Coastguard Worker#					default is no arguments.
56*7c356e86SAndroid Build Coastguard Worker#	script			m	Value is written to a file which
57*7c356e86SAndroid Build Coastguard Worker#					is passed as an argument to the program
58*7c356e86SAndroid Build Coastguard Worker#					(after the arguments from arguments)
59*7c356e86SAndroid Build Coastguard Worker#	stdin			m	Value is written to a file which is
60*7c356e86SAndroid Build Coastguard Worker#					used as standard-input for the program;
61*7c356e86SAndroid Build Coastguard Worker#					default is to use /dev/null.
62*7c356e86SAndroid Build Coastguard Worker#	perl-setup		m	Value is a perl script which is executed
63*7c356e86SAndroid Build Coastguard Worker#					just before the test is run. Try to
64*7c356e86SAndroid Build Coastguard Worker#					avoid using this...
65*7c356e86SAndroid Build Coastguard Worker#	perl-cleanup		m	Value is a perl script which is executed
66*7c356e86SAndroid Build Coastguard Worker#					just after the test is run. Try to
67*7c356e86SAndroid Build Coastguard Worker#					avoid using this...
68*7c356e86SAndroid Build Coastguard Worker#	env-setup		M	Value is a list of NAME=VALUE elements
69*7c356e86SAndroid Build Coastguard Worker#					which are put in the environment before
70*7c356e86SAndroid Build Coastguard Worker#					the test is run. If the =VALUE is
71*7c356e86SAndroid Build Coastguard Worker#					missing, NAME is removed from the
72*7c356e86SAndroid Build Coastguard Worker#					environment. Programs are run with
73*7c356e86SAndroid Build Coastguard Worker#					the following minimal environment:
74*7c356e86SAndroid Build Coastguard Worker#					    HOME, LD_LIBRARY_PATH, LOCPATH,
75*7c356e86SAndroid Build Coastguard Worker#					    LOGNAME, PATH, SHELL, UNIXMODE,
76*7c356e86SAndroid Build Coastguard Worker#					    UNIXROOT, USER
77*7c356e86SAndroid Build Coastguard Worker#					(values taken from the environment of
78*7c356e86SAndroid Build Coastguard Worker#					the test harness).
79*7c356e86SAndroid Build Coastguard Worker#					CYGWIN is set to nodosfilewarning.
80*7c356e86SAndroid Build Coastguard Worker#					ENV is set to /nonexistant.
81*7c356e86SAndroid Build Coastguard Worker#					__progname is set to the -p argument.
82*7c356e86SAndroid Build Coastguard Worker#					__perlname is set to $^X (perlexe).
83*7c356e86SAndroid Build Coastguard Worker#					@utflocale@ is substituted from -U.
84*7c356e86SAndroid Build Coastguard Worker#	file-setup		mps	Used to create files, directories
85*7c356e86SAndroid Build Coastguard Worker#					and symlinks. First word is either
86*7c356e86SAndroid Build Coastguard Worker#					file, dir or symlink; second word is
87*7c356e86SAndroid Build Coastguard Worker#					permissions; this is followed by a
88*7c356e86SAndroid Build Coastguard Worker#					quoted word that is the name of the
89*7c356e86SAndroid Build Coastguard Worker#					file; the end-quote should be followed
90*7c356e86SAndroid Build Coastguard Worker#					by a newline, then the file data
91*7c356e86SAndroid Build Coastguard Worker#					(if any). The first word may be
92*7c356e86SAndroid Build Coastguard Worker#					preceded by a ! to strip the trailing
93*7c356e86SAndroid Build Coastguard Worker#					newline in a symlink.
94*7c356e86SAndroid Build Coastguard Worker#	file-result		mps	Used to verify a file, symlink or
95*7c356e86SAndroid Build Coastguard Worker#					directory is created correctly.
96*7c356e86SAndroid Build Coastguard Worker#					The first word is either
97*7c356e86SAndroid Build Coastguard Worker#					file, dir or symlink; second word is
98*7c356e86SAndroid Build Coastguard Worker#					expected permissions; third word
99*7c356e86SAndroid Build Coastguard Worker#					is user-id; fourth is group-id;
100*7c356e86SAndroid Build Coastguard Worker#					fifth is "exact" or "pattern"
101*7c356e86SAndroid Build Coastguard Worker#					indicating whether the file contents
102*7c356e86SAndroid Build Coastguard Worker#					which follow is to be matched exactly
103*7c356e86SAndroid Build Coastguard Worker#					or if it is a regular expression.
104*7c356e86SAndroid Build Coastguard Worker#					The fifth argument is the quoted name
105*7c356e86SAndroid Build Coastguard Worker#					of the file that should be created.
106*7c356e86SAndroid Build Coastguard Worker#					The end-quote should be followed
107*7c356e86SAndroid Build Coastguard Worker#					by a newline, then the file data
108*7c356e86SAndroid Build Coastguard Worker#					(if any). The first word may be
109*7c356e86SAndroid Build Coastguard Worker#					preceded by a ! to strip the trailing
110*7c356e86SAndroid Build Coastguard Worker#					newline in the file contents.
111*7c356e86SAndroid Build Coastguard Worker#					The permissions, user and group fields
112*7c356e86SAndroid Build Coastguard Worker#					may be * meaning accept any value.
113*7c356e86SAndroid Build Coastguard Worker#	time-limit			Time limit - the program is sent a
114*7c356e86SAndroid Build Coastguard Worker#					SIGKILL N seconds. Default is no
115*7c356e86SAndroid Build Coastguard Worker#					limit.
116*7c356e86SAndroid Build Coastguard Worker#	expected-fail			'yes' if the test is expected to fail.
117*7c356e86SAndroid Build Coastguard Worker#	expected-exit			expected exit code. Can be a number,
118*7c356e86SAndroid Build Coastguard Worker#					or a C expression using the variables
119*7c356e86SAndroid Build Coastguard Worker#					e, s and w (exit code, termination
120*7c356e86SAndroid Build Coastguard Worker#					signal, and status code).
121*7c356e86SAndroid Build Coastguard Worker#	expected-stdout		m	What the test should generate on stdout;
122*7c356e86SAndroid Build Coastguard Worker#					default is to expect no output.
123*7c356e86SAndroid Build Coastguard Worker#	expected-stdout-pattern	m	A perl pattern which matches the
124*7c356e86SAndroid Build Coastguard Worker#					expected output.
125*7c356e86SAndroid Build Coastguard Worker#	expected-stderr		m	What the test should generate on stderr;
126*7c356e86SAndroid Build Coastguard Worker#					default is to expect no output.
127*7c356e86SAndroid Build Coastguard Worker#	expected-stderr-pattern	m	A perl pattern which matches the
128*7c356e86SAndroid Build Coastguard Worker#					expected standard error.
129*7c356e86SAndroid Build Coastguard Worker#	category		m	Specify a comma separated list of
130*7c356e86SAndroid Build Coastguard Worker#					'categories' of program that the test
131*7c356e86SAndroid Build Coastguard Worker#					is to be run for. A category can be
132*7c356e86SAndroid Build Coastguard Worker#					negated by prefixing the name with a !.
133*7c356e86SAndroid Build Coastguard Worker#					The idea is that some tests in a
134*7c356e86SAndroid Build Coastguard Worker#					test suite may apply to a particular
135*7c356e86SAndroid Build Coastguard Worker#					program version and shouldn't be run
136*7c356e86SAndroid Build Coastguard Worker#					on other versions. The category(s) of
137*7c356e86SAndroid Build Coastguard Worker#					the program being tested can be
138*7c356e86SAndroid Build Coastguard Worker#					specified on the command line.
139*7c356e86SAndroid Build Coastguard Worker#					One category os:XXX is predefined
140*7c356e86SAndroid Build Coastguard Worker#					(XXX is the operating system name,
141*7c356e86SAndroid Build Coastguard Worker#					eg, linux, dec_osf).
142*7c356e86SAndroid Build Coastguard Worker#	need-ctty			'yes' if the test needs a ctty, run
143*7c356e86SAndroid Build Coastguard Worker#					with -C regress:no-ctty to disable.
144*7c356e86SAndroid Build Coastguard Worker# Flag meanings:
145*7c356e86SAndroid Build Coastguard Worker#	r	tag is required (eg, a test must have a name tag).
146*7c356e86SAndroid Build Coastguard Worker#	m	value can be multiple lines. Lines must be prefixed with
147*7c356e86SAndroid Build Coastguard Worker#		a tab. If the value part of the initial tag:value line is
148*7c356e86SAndroid Build Coastguard Worker#			- empty: the initial blank line is stripped.
149*7c356e86SAndroid Build Coastguard Worker#			- a lone !: the last newline in the value is stripped;
150*7c356e86SAndroid Build Coastguard Worker#	M	value can be multiple lines (prefixed by a tab) and consists
151*7c356e86SAndroid Build Coastguard Worker#		of multiple fields, delimited by a field separator character.
152*7c356e86SAndroid Build Coastguard Worker#		The value must start and end with the f-s-c.
153*7c356e86SAndroid Build Coastguard Worker#	p	tag takes parameters (used with m).
154*7c356e86SAndroid Build Coastguard Worker#	s	tag can be used several times.
155*7c356e86SAndroid Build Coastguard Worker
156*7c356e86SAndroid Build Coastguard Worker# require Config only if it exists
157*7c356e86SAndroid Build Coastguard Worker# pull EINTR from POSIX.pm or Errno.pm if they exist
158*7c356e86SAndroid Build Coastguard Worker# otherwise just skip it
159*7c356e86SAndroid Build Coastguard WorkerBEGIN {
160*7c356e86SAndroid Build Coastguard Worker	eval {
161*7c356e86SAndroid Build Coastguard Worker		require Config;
162*7c356e86SAndroid Build Coastguard Worker		import Config;
163*7c356e86SAndroid Build Coastguard Worker		1;
164*7c356e86SAndroid Build Coastguard Worker	};
165*7c356e86SAndroid Build Coastguard Worker	$EINTR = 0;
166*7c356e86SAndroid Build Coastguard Worker	eval {
167*7c356e86SAndroid Build Coastguard Worker		require POSIX;
168*7c356e86SAndroid Build Coastguard Worker		$EINTR = POSIX::EINTR();
169*7c356e86SAndroid Build Coastguard Worker	};
170*7c356e86SAndroid Build Coastguard Worker	if ($@) {
171*7c356e86SAndroid Build Coastguard Worker		eval {
172*7c356e86SAndroid Build Coastguard Worker			require Errno;
173*7c356e86SAndroid Build Coastguard Worker			$EINTR = Errno::EINTR();
174*7c356e86SAndroid Build Coastguard Worker		} or do {
175*7c356e86SAndroid Build Coastguard Worker			$EINTR = 0;
176*7c356e86SAndroid Build Coastguard Worker		};
177*7c356e86SAndroid Build Coastguard Worker	}
178*7c356e86SAndroid Build Coastguard Worker};
179*7c356e86SAndroid Build Coastguard Worker
180*7c356e86SAndroid Build Coastguard Workeruse Getopt::Std;
181*7c356e86SAndroid Build Coastguard Worker
182*7c356e86SAndroid Build Coastguard Worker$os = defined $^O ? $^O : 'unknown';
183*7c356e86SAndroid Build Coastguard Worker
184*7c356e86SAndroid Build Coastguard Worker($prog = $0) =~ s#.*/##;
185*7c356e86SAndroid Build Coastguard Worker
186*7c356e86SAndroid Build Coastguard Worker$Usage = <<EOF ;
187*7c356e86SAndroid Build Coastguard WorkerUsage: $prog [-Pv] [-C cat] [-e e=v] [-p prog] [-s fn] [-T dir] \
188*7c356e86SAndroid Build Coastguard Worker       [-t tmo] [-U lcl] name ...
189*7c356e86SAndroid Build Coastguard Worker	-C c	Specify the comma separated list of categories the program
190*7c356e86SAndroid Build Coastguard Worker		belongs to (see category field).
191*7c356e86SAndroid Build Coastguard Worker	-e e=v	Set the environment variable e to v for all tests
192*7c356e86SAndroid Build Coastguard Worker		(if no =v is given, the current value is used)
193*7c356e86SAndroid Build Coastguard Worker		Only one -e option can be given at the moment, sadly.
194*7c356e86SAndroid Build Coastguard Worker	-P	program (-p) string has multiple words, and the program is in
195*7c356e86SAndroid Build Coastguard Worker		the path (kludge option)
196*7c356e86SAndroid Build Coastguard Worker	-p p	Use p as the program to test
197*7c356e86SAndroid Build Coastguard Worker	-s s	Read tests from file s; if s is a directory, it is recursively
198*7c356e86SAndroid Build Coastguard Worker		scanned for test files (which end in .t).
199*7c356e86SAndroid Build Coastguard Worker	-T dir	Use dir instead of /tmp to hold temporary files
200*7c356e86SAndroid Build Coastguard Worker	-t t	Use t as default time limit for tests (default is unlimited)
201*7c356e86SAndroid Build Coastguard Worker	-U lcl	Use lcl as UTF-8 locale (e.g. C.UTF-8) instead of the default
202*7c356e86SAndroid Build Coastguard Worker	-v	Verbose mode: print reason test failed.
203*7c356e86SAndroid Build Coastguard Worker	name	specifies the name of the test(s) to run; if none are
204*7c356e86SAndroid Build Coastguard Worker		specified, all tests are run.
205*7c356e86SAndroid Build Coastguard WorkerEOF
206*7c356e86SAndroid Build Coastguard Worker
207*7c356e86SAndroid Build Coastguard Worker# See comment above for flag meanings
208*7c356e86SAndroid Build Coastguard Worker%test_fields = (
209*7c356e86SAndroid Build Coastguard Worker	'name',				'r',
210*7c356e86SAndroid Build Coastguard Worker	'description',			'm',
211*7c356e86SAndroid Build Coastguard Worker	'arguments',			'M',
212*7c356e86SAndroid Build Coastguard Worker	'script',			'm',
213*7c356e86SAndroid Build Coastguard Worker	'stdin',			'm',
214*7c356e86SAndroid Build Coastguard Worker	'perl-setup',			'm',
215*7c356e86SAndroid Build Coastguard Worker	'perl-cleanup',			'm',
216*7c356e86SAndroid Build Coastguard Worker	'env-setup',			'M',
217*7c356e86SAndroid Build Coastguard Worker	'file-setup',			'mps',
218*7c356e86SAndroid Build Coastguard Worker	'file-result',			'mps',
219*7c356e86SAndroid Build Coastguard Worker	'time-limit',			'',
220*7c356e86SAndroid Build Coastguard Worker	'expected-fail',		'',
221*7c356e86SAndroid Build Coastguard Worker	'expected-exit',		'',
222*7c356e86SAndroid Build Coastguard Worker	'expected-stdout',		'm',
223*7c356e86SAndroid Build Coastguard Worker	'expected-stdout-pattern',	'm',
224*7c356e86SAndroid Build Coastguard Worker	'expected-stderr',		'm',
225*7c356e86SAndroid Build Coastguard Worker	'expected-stderr-pattern',	'm',
226*7c356e86SAndroid Build Coastguard Worker	'category',			'm',
227*7c356e86SAndroid Build Coastguard Worker	'need-ctty',			'',
228*7c356e86SAndroid Build Coastguard Worker	'need-pass',			'',
229*7c356e86SAndroid Build Coastguard Worker	);
230*7c356e86SAndroid Build Coastguard Worker# Filled in by read_test()
231*7c356e86SAndroid Build Coastguard Worker%internal_test_fields = (
232*7c356e86SAndroid Build Coastguard Worker	':full-name', 1,		# file:name
233*7c356e86SAndroid Build Coastguard Worker	':long-name', 1,		# dir/file:lineno:name
234*7c356e86SAndroid Build Coastguard Worker	);
235*7c356e86SAndroid Build Coastguard Worker
236*7c356e86SAndroid Build Coastguard Worker# Categories of the program under test. Provide the current
237*7c356e86SAndroid Build Coastguard Worker# os by default.
238*7c356e86SAndroid Build Coastguard Worker%categories = (
239*7c356e86SAndroid Build Coastguard Worker	"os:$os", '1'
240*7c356e86SAndroid Build Coastguard Worker	);
241*7c356e86SAndroid Build Coastguard Worker
242*7c356e86SAndroid Build Coastguard Worker$nfailed = 0;
243*7c356e86SAndroid Build Coastguard Worker$nifailed = 0;
244*7c356e86SAndroid Build Coastguard Worker$nxfailed = 0;
245*7c356e86SAndroid Build Coastguard Worker$npassed = 0;
246*7c356e86SAndroid Build Coastguard Worker$nxpassed = 0;
247*7c356e86SAndroid Build Coastguard Worker
248*7c356e86SAndroid Build Coastguard Worker%known_tests = ();
249*7c356e86SAndroid Build Coastguard Worker
250*7c356e86SAndroid Build Coastguard Workerif (!getopts('C:Ee:Pp:s:T:t:U:v')) {
251*7c356e86SAndroid Build Coastguard Worker    print STDERR $Usage;
252*7c356e86SAndroid Build Coastguard Worker    exit 1;
253*7c356e86SAndroid Build Coastguard Worker}
254*7c356e86SAndroid Build Coastguard Worker
255*7c356e86SAndroid Build Coastguard Workerdie "$prog: no program specified (use -p)\n" if !defined $opt_p;
256*7c356e86SAndroid Build Coastguard Workerdie "$prog: no test set specified (use -s)\n" if !defined $opt_s;
257*7c356e86SAndroid Build Coastguard Worker$test_prog = $opt_p;
258*7c356e86SAndroid Build Coastguard Worker$verbose = defined $opt_v && $opt_v;
259*7c356e86SAndroid Build Coastguard Worker$is_ebcdic = defined $opt_E && $opt_E;
260*7c356e86SAndroid Build Coastguard Worker$test_set = $opt_s;
261*7c356e86SAndroid Build Coastguard Worker$temp_base = $opt_T || "/tmp";
262*7c356e86SAndroid Build Coastguard Worker$utflocale = $opt_U || (($os eq "hpux") ? "en_US.utf8" : "en_US.UTF-8");
263*7c356e86SAndroid Build Coastguard Workerif (defined $opt_t) {
264*7c356e86SAndroid Build Coastguard Worker    die "$prog: bad -t argument (should be number > 0): $opt_t\n"
265*7c356e86SAndroid Build Coastguard Worker	if $opt_t !~ /^\d+$/ || $opt_t <= 0;
266*7c356e86SAndroid Build Coastguard Worker    $default_time_limit = $opt_t;
267*7c356e86SAndroid Build Coastguard Worker}
268*7c356e86SAndroid Build Coastguard Worker$program_kludge = defined $opt_P ? $opt_P : 0;
269*7c356e86SAndroid Build Coastguard Worker
270*7c356e86SAndroid Build Coastguard Workerif ($is_ebcdic) {
271*7c356e86SAndroid Build Coastguard Worker	$categories{'shell:ebcdic-yes'} = 1;
272*7c356e86SAndroid Build Coastguard Worker	$categories{'shell:ascii-no'} = 1;
273*7c356e86SAndroid Build Coastguard Worker} else {
274*7c356e86SAndroid Build Coastguard Worker	$categories{'shell:ebcdic-no'} = 1;
275*7c356e86SAndroid Build Coastguard Worker	$categories{'shell:ascii-yes'} = 1;
276*7c356e86SAndroid Build Coastguard Worker}
277*7c356e86SAndroid Build Coastguard Worker
278*7c356e86SAndroid Build Coastguard Workerif (defined $opt_C) {
279*7c356e86SAndroid Build Coastguard Worker    foreach $c (split(',', $opt_C)) {
280*7c356e86SAndroid Build Coastguard Worker	$c =~ s/\s+//;
281*7c356e86SAndroid Build Coastguard Worker	die "$prog: categories can't be negated on the command line\n"
282*7c356e86SAndroid Build Coastguard Worker	    if ($c =~ /^!/);
283*7c356e86SAndroid Build Coastguard Worker	$categories{$c} = 1;
284*7c356e86SAndroid Build Coastguard Worker    }
285*7c356e86SAndroid Build Coastguard Worker}
286*7c356e86SAndroid Build Coastguard Worker
287*7c356e86SAndroid Build Coastguard Worker# Note which tests are to be run.
288*7c356e86SAndroid Build Coastguard Worker%do_test = ();
289*7c356e86SAndroid Build Coastguard Workergrep($do_test{$_} = 1, @ARGV);
290*7c356e86SAndroid Build Coastguard Worker$all_tests = @ARGV == 0;
291*7c356e86SAndroid Build Coastguard Worker
292*7c356e86SAndroid Build Coastguard Worker# Set up a very minimal environment
293*7c356e86SAndroid Build Coastguard Worker%new_env = ();
294*7c356e86SAndroid Build Coastguard Workerforeach $env (('HOME', 'LD_LIBRARY_PATH', 'LOCPATH', 'LOGNAME',
295*7c356e86SAndroid Build Coastguard Worker  'PATH', 'PERLIO', 'SHELL', 'UNIXMODE', 'UNIXROOT', 'USER')) {
296*7c356e86SAndroid Build Coastguard Worker    $new_env{$env} = $ENV{$env} if defined $ENV{$env};
297*7c356e86SAndroid Build Coastguard Worker}
298*7c356e86SAndroid Build Coastguard Worker$new_env{'CYGWIN'} = 'nodosfilewarning';
299*7c356e86SAndroid Build Coastguard Worker$new_env{'ENV'} = '/nonexistant';
300*7c356e86SAndroid Build Coastguard Worker
301*7c356e86SAndroid Build Coastguard Workerif (($os eq 'VMS') || ($Config{perlpath} =~ m/$Config{_exe}$/i)) {
302*7c356e86SAndroid Build Coastguard Worker	$new_env{'__perlname'} = $Config{perlpath};
303*7c356e86SAndroid Build Coastguard Worker} else {
304*7c356e86SAndroid Build Coastguard Worker	$new_env{'__perlname'} = $Config{perlpath} . $Config{_exe};
305*7c356e86SAndroid Build Coastguard Worker}
306*7c356e86SAndroid Build Coastguard Worker$new_env{'__perlname'} = $^X if ($new_env{'__perlname'} eq '') and -f $^X and -x $^X;
307*7c356e86SAndroid Build Coastguard Workerif ($new_env{'__perlname'} eq '') {
308*7c356e86SAndroid Build Coastguard Worker	foreach $pathelt (split /:/,$ENV{'PATH'}) {
309*7c356e86SAndroid Build Coastguard Worker		chomp($pathelt = `pwd`) if $pathelt eq '';
310*7c356e86SAndroid Build Coastguard Worker		my $x = $pathelt . '/' . $^X;
311*7c356e86SAndroid Build Coastguard Worker		next unless -f $x and -x $x;
312*7c356e86SAndroid Build Coastguard Worker		$new_env{'__perlname'} = $x;
313*7c356e86SAndroid Build Coastguard Worker		last;
314*7c356e86SAndroid Build Coastguard Worker	}
315*7c356e86SAndroid Build Coastguard Worker}
316*7c356e86SAndroid Build Coastguard Worker$new_env{'__perlname'} = $^X if ($new_env{'__perlname'} eq '');
317*7c356e86SAndroid Build Coastguard Worker
318*7c356e86SAndroid Build Coastguard Workerif (defined $opt_e) {
319*7c356e86SAndroid Build Coastguard Worker    # XXX need a way to allow many -e arguments...
320*7c356e86SAndroid Build Coastguard Worker    if ($opt_e =~ /^([a-zA-Z_]\w*)(|=(.*))$/) {
321*7c356e86SAndroid Build Coastguard Worker	$new_env{$1} = $2 eq '' ? $ENV{$1} : $3;
322*7c356e86SAndroid Build Coastguard Worker    } else {
323*7c356e86SAndroid Build Coastguard Worker	die "$0: bad -e argument: $opt_e\n";
324*7c356e86SAndroid Build Coastguard Worker    }
325*7c356e86SAndroid Build Coastguard Worker}
326*7c356e86SAndroid Build Coastguard Worker%old_env = %ENV;
327*7c356e86SAndroid Build Coastguard Worker
328*7c356e86SAndroid Build Coastguard Workerchop($pwd = `pwd 2>/dev/null`);
329*7c356e86SAndroid Build Coastguard Workerdie "$prog: couldn't get current working directory\n" if $pwd eq '';
330*7c356e86SAndroid Build Coastguard Workerdie "$prog: couldn't cd to $pwd - $!\n" if !chdir($pwd);
331*7c356e86SAndroid Build Coastguard Worker
332*7c356e86SAndroid Build Coastguard Workerdie "$prog: couldn't cd to $temp_base - $!\n" if !chdir($temp_base);
333*7c356e86SAndroid Build Coastguard Workerdie "$prog: couldn't get temporary directory base\n" unless -d '.';
334*7c356e86SAndroid Build Coastguard Worker$temps = sprintf("chk%d-%d.", $$, time());
335*7c356e86SAndroid Build Coastguard Worker$tempi = 0;
336*7c356e86SAndroid Build Coastguard Workeruntil (mkdir(($tempdir = sprintf("%s%03d", $temps, $tempi)), 0700)) {
337*7c356e86SAndroid Build Coastguard Worker    die "$prog: couldn't get temporary directory\n" if $tempi++ >= 999;
338*7c356e86SAndroid Build Coastguard Worker}
339*7c356e86SAndroid Build Coastguard Workerdie "$prog: couldn't cd to $tempdir - $!\n" if !chdir($tempdir);
340*7c356e86SAndroid Build Coastguard Workerchop($temp_dir = `pwd 2>/dev/null`);
341*7c356e86SAndroid Build Coastguard Workerdie "$prog: couldn't get temporary directory\n" if $temp_dir eq '';
342*7c356e86SAndroid Build Coastguard Workerdie "$prog: couldn't cd to $pwd - $!\n" if !chdir($pwd);
343*7c356e86SAndroid Build Coastguard Worker
344*7c356e86SAndroid Build Coastguard Workerif (!$program_kludge) {
345*7c356e86SAndroid Build Coastguard Worker    $test_prog = "$pwd/$test_prog" if (substr($test_prog, 0, 1) ne '/') &&
346*7c356e86SAndroid Build Coastguard Worker      ($os ne 'os2' || substr($test_prog, 1, 1) ne ':');
347*7c356e86SAndroid Build Coastguard Worker    die "$prog: $test_prog is not executable - bye\n"
348*7c356e86SAndroid Build Coastguard Worker      if (! -x $test_prog && $os ne 'os2');
349*7c356e86SAndroid Build Coastguard Worker}
350*7c356e86SAndroid Build Coastguard Worker
351*7c356e86SAndroid Build Coastguard Worker@trap_sigs = ('TERM', 'QUIT', 'INT', 'PIPE', 'HUP');
352*7c356e86SAndroid Build Coastguard Worker@SIG{@trap_sigs} = ('cleanup_exit') x @trap_sigs;
353*7c356e86SAndroid Build Coastguard Worker$child_kill_ok = 0;
354*7c356e86SAndroid Build Coastguard Worker$SIG{'ALRM'} = 'catch_sigalrm';
355*7c356e86SAndroid Build Coastguard Worker
356*7c356e86SAndroid Build Coastguard Worker$| = 1;
357*7c356e86SAndroid Build Coastguard Worker
358*7c356e86SAndroid Build Coastguard Worker# Create temp files
359*7c356e86SAndroid Build Coastguard Worker$temps = "${temp_dir}/rts";
360*7c356e86SAndroid Build Coastguard Worker$tempi = "${temp_dir}/rti";
361*7c356e86SAndroid Build Coastguard Worker$tempo = "${temp_dir}/rto";
362*7c356e86SAndroid Build Coastguard Worker$tempe = "${temp_dir}/rte";
363*7c356e86SAndroid Build Coastguard Worker$tempdir = "${temp_dir}/rtd";
364*7c356e86SAndroid Build Coastguard Workermkdir($tempdir, 0700) or die "$prog: couldn't mkdir $tempdir - $!\n";
365*7c356e86SAndroid Build Coastguard Worker
366*7c356e86SAndroid Build Coastguard Workerif (-d $test_set) {
367*7c356e86SAndroid Build Coastguard Worker    $file_prefix_skip = length($test_set) + 1;
368*7c356e86SAndroid Build Coastguard Worker    $ret = &process_test_dir($test_set);
369*7c356e86SAndroid Build Coastguard Worker} else {
370*7c356e86SAndroid Build Coastguard Worker    $file_prefix_skip = 0;
371*7c356e86SAndroid Build Coastguard Worker    $ret = &process_test_file($test_set);
372*7c356e86SAndroid Build Coastguard Worker}
373*7c356e86SAndroid Build Coastguard Worker&cleanup_exit() if !defined $ret;
374*7c356e86SAndroid Build Coastguard Worker
375*7c356e86SAndroid Build Coastguard Worker$tot_failed = $nfailed + $nifailed + $nxfailed;
376*7c356e86SAndroid Build Coastguard Worker$tot_passed = $npassed + $nxpassed;
377*7c356e86SAndroid Build Coastguard Workerif ($tot_failed || $tot_passed) {
378*7c356e86SAndroid Build Coastguard Worker    print "Total failed: $tot_failed";
379*7c356e86SAndroid Build Coastguard Worker    print " ($nifailed ignored)" if $nifailed;
380*7c356e86SAndroid Build Coastguard Worker    print " ($nxfailed unexpected)" if $nxfailed;
381*7c356e86SAndroid Build Coastguard Worker    print " (as expected)" if $nfailed && !$nxfailed && !$nifailed;
382*7c356e86SAndroid Build Coastguard Worker    print " ($nfailed expected)" if $nfailed && ($nxfailed || $nifailed);
383*7c356e86SAndroid Build Coastguard Worker    print "\nTotal passed: $tot_passed";
384*7c356e86SAndroid Build Coastguard Worker    print " ($nxpassed unexpected)" if $nxpassed;
385*7c356e86SAndroid Build Coastguard Worker    print "\n";
386*7c356e86SAndroid Build Coastguard Worker}
387*7c356e86SAndroid Build Coastguard Worker
388*7c356e86SAndroid Build Coastguard Worker&cleanup_exit('ok');
389*7c356e86SAndroid Build Coastguard Worker
390*7c356e86SAndroid Build Coastguard Workersub
391*7c356e86SAndroid Build Coastguard Workercleanup_exit
392*7c356e86SAndroid Build Coastguard Worker{
393*7c356e86SAndroid Build Coastguard Worker    local($sig, $exitcode) = ('', 1);
394*7c356e86SAndroid Build Coastguard Worker
395*7c356e86SAndroid Build Coastguard Worker    if ($_[0] eq 'ok') {
396*7c356e86SAndroid Build Coastguard Worker	unless ($nxfailed) {
397*7c356e86SAndroid Build Coastguard Worker		$exitcode = 0;
398*7c356e86SAndroid Build Coastguard Worker	} else {
399*7c356e86SAndroid Build Coastguard Worker		$exitcode = 1;
400*7c356e86SAndroid Build Coastguard Worker	}
401*7c356e86SAndroid Build Coastguard Worker    } elsif ($_[0] ne '') {
402*7c356e86SAndroid Build Coastguard Worker	$sig = $_[0];
403*7c356e86SAndroid Build Coastguard Worker    }
404*7c356e86SAndroid Build Coastguard Worker
405*7c356e86SAndroid Build Coastguard Worker    unlink($tempi, $tempo, $tempe, $temps);
406*7c356e86SAndroid Build Coastguard Worker    &scrub_dir($tempdir) if defined $tempdir;
407*7c356e86SAndroid Build Coastguard Worker    rmdir($tempdir) if defined $tempdir;
408*7c356e86SAndroid Build Coastguard Worker    rmdir($temp_dir) if defined $temp_dir;
409*7c356e86SAndroid Build Coastguard Worker
410*7c356e86SAndroid Build Coastguard Worker    if ($sig) {
411*7c356e86SAndroid Build Coastguard Worker	$SIG{$sig} = 'DEFAULT';
412*7c356e86SAndroid Build Coastguard Worker	kill $sig, $$;
413*7c356e86SAndroid Build Coastguard Worker	return;
414*7c356e86SAndroid Build Coastguard Worker    }
415*7c356e86SAndroid Build Coastguard Worker    exit $exitcode;
416*7c356e86SAndroid Build Coastguard Worker}
417*7c356e86SAndroid Build Coastguard Worker
418*7c356e86SAndroid Build Coastguard Workersub
419*7c356e86SAndroid Build Coastguard Workercatch_sigalrm
420*7c356e86SAndroid Build Coastguard Worker{
421*7c356e86SAndroid Build Coastguard Worker    $SIG{'ALRM'} = 'catch_sigalrm';
422*7c356e86SAndroid Build Coastguard Worker    kill(9, $child_pid) if $child_kill_ok;
423*7c356e86SAndroid Build Coastguard Worker    $child_killed = 1;
424*7c356e86SAndroid Build Coastguard Worker}
425*7c356e86SAndroid Build Coastguard Worker
426*7c356e86SAndroid Build Coastguard Workersub
427*7c356e86SAndroid Build Coastguard Workerprocess_test_dir
428*7c356e86SAndroid Build Coastguard Worker{
429*7c356e86SAndroid Build Coastguard Worker    local($dir) = @_;
430*7c356e86SAndroid Build Coastguard Worker    local($ret, $file);
431*7c356e86SAndroid Build Coastguard Worker    local(@todo) = ();
432*7c356e86SAndroid Build Coastguard Worker
433*7c356e86SAndroid Build Coastguard Worker    if (!opendir(DIR, $dir)) {
434*7c356e86SAndroid Build Coastguard Worker	print STDERR "$prog: can't open directory $dir - $!\n";
435*7c356e86SAndroid Build Coastguard Worker	return undef;
436*7c356e86SAndroid Build Coastguard Worker    }
437*7c356e86SAndroid Build Coastguard Worker    while (defined ($file = readdir(DIR))) {
438*7c356e86SAndroid Build Coastguard Worker	push(@todo, $file) if $file =~ /^[^.].*\.t$/;
439*7c356e86SAndroid Build Coastguard Worker    }
440*7c356e86SAndroid Build Coastguard Worker    closedir(DIR);
441*7c356e86SAndroid Build Coastguard Worker
442*7c356e86SAndroid Build Coastguard Worker    foreach $file (@todo) {
443*7c356e86SAndroid Build Coastguard Worker	$file = "$dir/$file";
444*7c356e86SAndroid Build Coastguard Worker	if (-d $file) {
445*7c356e86SAndroid Build Coastguard Worker	    $ret = &process_test_dir($file);
446*7c356e86SAndroid Build Coastguard Worker	} elsif (-f _) {
447*7c356e86SAndroid Build Coastguard Worker	    $ret = &process_test_file($file);
448*7c356e86SAndroid Build Coastguard Worker	}
449*7c356e86SAndroid Build Coastguard Worker	last if !defined $ret;
450*7c356e86SAndroid Build Coastguard Worker    }
451*7c356e86SAndroid Build Coastguard Worker
452*7c356e86SAndroid Build Coastguard Worker    return $ret;
453*7c356e86SAndroid Build Coastguard Worker}
454*7c356e86SAndroid Build Coastguard Worker
455*7c356e86SAndroid Build Coastguard Workersub
456*7c356e86SAndroid Build Coastguard Workerprocess_test_file
457*7c356e86SAndroid Build Coastguard Worker{
458*7c356e86SAndroid Build Coastguard Worker    local($file) = @_;
459*7c356e86SAndroid Build Coastguard Worker    local($ret);
460*7c356e86SAndroid Build Coastguard Worker
461*7c356e86SAndroid Build Coastguard Worker    if (!open(IN, $file)) {
462*7c356e86SAndroid Build Coastguard Worker	print STDERR "$prog: can't open $file - $!\n";
463*7c356e86SAndroid Build Coastguard Worker	return undef;
464*7c356e86SAndroid Build Coastguard Worker    }
465*7c356e86SAndroid Build Coastguard Worker    binmode(IN);
466*7c356e86SAndroid Build Coastguard Worker    while (1) {
467*7c356e86SAndroid Build Coastguard Worker	$ret = &read_test($file, IN, *test);
468*7c356e86SAndroid Build Coastguard Worker	last if !defined $ret || !$ret;
469*7c356e86SAndroid Build Coastguard Worker	next if !$all_tests && !$do_test{$test{'name'}};
470*7c356e86SAndroid Build Coastguard Worker	next if !&category_check(*test);
471*7c356e86SAndroid Build Coastguard Worker	$ret = &run_test(*test);
472*7c356e86SAndroid Build Coastguard Worker	last if !defined $ret;
473*7c356e86SAndroid Build Coastguard Worker    }
474*7c356e86SAndroid Build Coastguard Worker    close(IN);
475*7c356e86SAndroid Build Coastguard Worker
476*7c356e86SAndroid Build Coastguard Worker    return $ret;
477*7c356e86SAndroid Build Coastguard Worker}
478*7c356e86SAndroid Build Coastguard Worker
479*7c356e86SAndroid Build Coastguard Workersub
480*7c356e86SAndroid Build Coastguard Workerrun_test
481*7c356e86SAndroid Build Coastguard Worker{
482*7c356e86SAndroid Build Coastguard Worker    local(*test) = @_;
483*7c356e86SAndroid Build Coastguard Worker    local($name) = $test{':full-name'};
484*7c356e86SAndroid Build Coastguard Worker
485*7c356e86SAndroid Build Coastguard Worker    return undef if !&scrub_dir($tempdir);
486*7c356e86SAndroid Build Coastguard Worker
487*7c356e86SAndroid Build Coastguard Worker    if (defined $test{'stdin'}) {
488*7c356e86SAndroid Build Coastguard Worker	return undef if !&write_file($tempi, $test{'stdin'});
489*7c356e86SAndroid Build Coastguard Worker	$ifile = $tempi;
490*7c356e86SAndroid Build Coastguard Worker    } else {
491*7c356e86SAndroid Build Coastguard Worker	$ifile = '/dev/null';
492*7c356e86SAndroid Build Coastguard Worker    }
493*7c356e86SAndroid Build Coastguard Worker
494*7c356e86SAndroid Build Coastguard Worker    if (defined $test{'script'}) {
495*7c356e86SAndroid Build Coastguard Worker	return undef if !&write_file($temps, $test{'script'});
496*7c356e86SAndroid Build Coastguard Worker    }
497*7c356e86SAndroid Build Coastguard Worker
498*7c356e86SAndroid Build Coastguard Worker    if (!chdir($tempdir)) {
499*7c356e86SAndroid Build Coastguard Worker	print STDERR "$prog: couldn't cd to $tempdir - $!\n";
500*7c356e86SAndroid Build Coastguard Worker	return undef;
501*7c356e86SAndroid Build Coastguard Worker    }
502*7c356e86SAndroid Build Coastguard Worker
503*7c356e86SAndroid Build Coastguard Worker    if (defined $test{'file-setup'}) {
504*7c356e86SAndroid Build Coastguard Worker	local($i);
505*7c356e86SAndroid Build Coastguard Worker	local($type, $perm, $rest, $c, $len, $name);
506*7c356e86SAndroid Build Coastguard Worker
507*7c356e86SAndroid Build Coastguard Worker	for ($i = 0; $i < $test{'file-setup'}; $i++) {
508*7c356e86SAndroid Build Coastguard Worker	    $val = $test{"file-setup:$i"};
509*7c356e86SAndroid Build Coastguard Worker
510*7c356e86SAndroid Build Coastguard Worker	    # format is: type perm "name"
511*7c356e86SAndroid Build Coastguard Worker	    ($type, $perm, $rest) =
512*7c356e86SAndroid Build Coastguard Worker		split(' ', $val, 3);
513*7c356e86SAndroid Build Coastguard Worker	    $c = substr($rest, 0, 1);
514*7c356e86SAndroid Build Coastguard Worker	    $len = index($rest, $c, 1) - 1;
515*7c356e86SAndroid Build Coastguard Worker	    $name = substr($rest, 1, $len);
516*7c356e86SAndroid Build Coastguard Worker	    $rest = substr($rest, 2 + $len);
517*7c356e86SAndroid Build Coastguard Worker	    $perm = oct($perm) if $perm =~ /^\d+$/;
518*7c356e86SAndroid Build Coastguard Worker	    if ($type eq 'file') {
519*7c356e86SAndroid Build Coastguard Worker		return undef if !&write_file($name, $rest);
520*7c356e86SAndroid Build Coastguard Worker		if (!chmod($perm, $name)) {
521*7c356e86SAndroid Build Coastguard Worker		    print STDERR
522*7c356e86SAndroid Build Coastguard Worker		  "$prog:$test{':long-name'}: can't chmod $perm $name - $!\n";
523*7c356e86SAndroid Build Coastguard Worker		    return undef;
524*7c356e86SAndroid Build Coastguard Worker		}
525*7c356e86SAndroid Build Coastguard Worker	    } elsif ($type eq 'dir') {
526*7c356e86SAndroid Build Coastguard Worker		if (!mkdir($name, $perm)) {
527*7c356e86SAndroid Build Coastguard Worker		    print STDERR
528*7c356e86SAndroid Build Coastguard Worker		  "$prog:$test{':long-name'}: can't mkdir $perm $name - $!\n";
529*7c356e86SAndroid Build Coastguard Worker		    return undef;
530*7c356e86SAndroid Build Coastguard Worker		}
531*7c356e86SAndroid Build Coastguard Worker	    } elsif ($type eq 'symlink') {
532*7c356e86SAndroid Build Coastguard Worker		local($oumask) = umask($perm);
533*7c356e86SAndroid Build Coastguard Worker		local($ret) = symlink($rest, $name);
534*7c356e86SAndroid Build Coastguard Worker		umask($oumask);
535*7c356e86SAndroid Build Coastguard Worker		if (!$ret) {
536*7c356e86SAndroid Build Coastguard Worker		    print STDERR
537*7c356e86SAndroid Build Coastguard Worker	    "$prog:$test{':long-name'}: couldn't create symlink $name - $!\n";
538*7c356e86SAndroid Build Coastguard Worker		    return undef;
539*7c356e86SAndroid Build Coastguard Worker		}
540*7c356e86SAndroid Build Coastguard Worker	    }
541*7c356e86SAndroid Build Coastguard Worker	}
542*7c356e86SAndroid Build Coastguard Worker    }
543*7c356e86SAndroid Build Coastguard Worker
544*7c356e86SAndroid Build Coastguard Worker    if (defined $test{'perl-setup'}) {
545*7c356e86SAndroid Build Coastguard Worker	eval $test{'perl-setup'};
546*7c356e86SAndroid Build Coastguard Worker	if ($@ ne '') {
547*7c356e86SAndroid Build Coastguard Worker	    print STDERR "$prog:$test{':long-name'}: error running perl-setup - $@\n";
548*7c356e86SAndroid Build Coastguard Worker	    return undef;
549*7c356e86SAndroid Build Coastguard Worker	}
550*7c356e86SAndroid Build Coastguard Worker    }
551*7c356e86SAndroid Build Coastguard Worker
552*7c356e86SAndroid Build Coastguard Worker    $pid = fork;
553*7c356e86SAndroid Build Coastguard Worker    if (!defined $pid) {
554*7c356e86SAndroid Build Coastguard Worker	print STDERR "$prog: can't fork - $!\n";
555*7c356e86SAndroid Build Coastguard Worker	return undef;
556*7c356e86SAndroid Build Coastguard Worker    }
557*7c356e86SAndroid Build Coastguard Worker    if (!$pid) {
558*7c356e86SAndroid Build Coastguard Worker	@SIG{@trap_sigs} = ('DEFAULT') x @trap_sigs;
559*7c356e86SAndroid Build Coastguard Worker	$SIG{'ALRM'} = 'DEFAULT';
560*7c356e86SAndroid Build Coastguard Worker	if (defined $test{'env-setup'}) {
561*7c356e86SAndroid Build Coastguard Worker	    local($var, $val, $i);
562*7c356e86SAndroid Build Coastguard Worker
563*7c356e86SAndroid Build Coastguard Worker	    foreach $var (split(substr($test{'env-setup'}, 0, 1),
564*7c356e86SAndroid Build Coastguard Worker		$test{'env-setup'}))
565*7c356e86SAndroid Build Coastguard Worker	    {
566*7c356e86SAndroid Build Coastguard Worker		$i = index($var, '=');
567*7c356e86SAndroid Build Coastguard Worker		next if $i == 0 || $var eq '';
568*7c356e86SAndroid Build Coastguard Worker		if ($i < 0) {
569*7c356e86SAndroid Build Coastguard Worker		    delete $new_env{$var};
570*7c356e86SAndroid Build Coastguard Worker		} else {
571*7c356e86SAndroid Build Coastguard Worker		    $new_env{substr($var, 0, $i)} = substr($var, $i + 1);
572*7c356e86SAndroid Build Coastguard Worker		}
573*7c356e86SAndroid Build Coastguard Worker	    }
574*7c356e86SAndroid Build Coastguard Worker	}
575*7c356e86SAndroid Build Coastguard Worker	if (!open(STDIN, "< $ifile")) {
576*7c356e86SAndroid Build Coastguard Worker		print STDERR "$prog: couldn't open $ifile in child - $!\n";
577*7c356e86SAndroid Build Coastguard Worker		kill('TERM', $$);
578*7c356e86SAndroid Build Coastguard Worker	}
579*7c356e86SAndroid Build Coastguard Worker	binmode(STDIN);
580*7c356e86SAndroid Build Coastguard Worker	if (!open(STDOUT, "> $tempo")) {
581*7c356e86SAndroid Build Coastguard Worker		print STDERR "$prog: couldn't open $tempo in child - $!\n";
582*7c356e86SAndroid Build Coastguard Worker		kill('TERM', $$);
583*7c356e86SAndroid Build Coastguard Worker	}
584*7c356e86SAndroid Build Coastguard Worker	binmode(STDOUT);
585*7c356e86SAndroid Build Coastguard Worker	if (!open(STDERR, "> $tempe")) {
586*7c356e86SAndroid Build Coastguard Worker		print STDOUT "$prog: couldn't open $tempe in child - $!\n";
587*7c356e86SAndroid Build Coastguard Worker		kill('TERM', $$);
588*7c356e86SAndroid Build Coastguard Worker	}
589*7c356e86SAndroid Build Coastguard Worker	binmode(STDERR);
590*7c356e86SAndroid Build Coastguard Worker	if ($program_kludge) {
591*7c356e86SAndroid Build Coastguard Worker	    @argv = split(' ', $test_prog);
592*7c356e86SAndroid Build Coastguard Worker	} else {
593*7c356e86SAndroid Build Coastguard Worker	    @argv = ($test_prog);
594*7c356e86SAndroid Build Coastguard Worker	}
595*7c356e86SAndroid Build Coastguard Worker	if (defined $test{'arguments'}) {
596*7c356e86SAndroid Build Coastguard Worker		push(@argv,
597*7c356e86SAndroid Build Coastguard Worker		     split(substr($test{'arguments'}, 0, 1),
598*7c356e86SAndroid Build Coastguard Worker			   substr($test{'arguments'}, 1)));
599*7c356e86SAndroid Build Coastguard Worker	}
600*7c356e86SAndroid Build Coastguard Worker	push(@argv, $temps) if defined $test{'script'};
601*7c356e86SAndroid Build Coastguard Worker
602*7c356e86SAndroid Build Coastguard Worker	#XXX realpathise, use command -v/whence -p/which, or sth. like that
603*7c356e86SAndroid Build Coastguard Worker	#XXX if !$program_kludge, we get by with not doing it for now tho
604*7c356e86SAndroid Build Coastguard Worker	$new_env{'__progname'} = $argv[0];
605*7c356e86SAndroid Build Coastguard Worker
606*7c356e86SAndroid Build Coastguard Worker	# The following doesn't work with perl5...  Need to do it explicitly - yuck.
607*7c356e86SAndroid Build Coastguard Worker	#%ENV = %new_env;
608*7c356e86SAndroid Build Coastguard Worker	foreach $k (keys(%ENV)) {
609*7c356e86SAndroid Build Coastguard Worker	    delete $ENV{$k};
610*7c356e86SAndroid Build Coastguard Worker	}
611*7c356e86SAndroid Build Coastguard Worker	$ENV{$k} = $v while ($k,$v) = each %new_env;
612*7c356e86SAndroid Build Coastguard Worker
613*7c356e86SAndroid Build Coastguard Worker	exec { $argv[0] } @argv;
614*7c356e86SAndroid Build Coastguard Worker	print STDERR "$prog: couldn't execute $test_prog - $!\n";
615*7c356e86SAndroid Build Coastguard Worker	kill('TERM', $$);
616*7c356e86SAndroid Build Coastguard Worker	exit(95);
617*7c356e86SAndroid Build Coastguard Worker    }
618*7c356e86SAndroid Build Coastguard Worker    $child_pid = $pid;
619*7c356e86SAndroid Build Coastguard Worker    $child_killed = 0;
620*7c356e86SAndroid Build Coastguard Worker    $child_kill_ok = 1;
621*7c356e86SAndroid Build Coastguard Worker    alarm($test{'time-limit'}) if defined $test{'time-limit'};
622*7c356e86SAndroid Build Coastguard Worker    while (1) {
623*7c356e86SAndroid Build Coastguard Worker	$xpid = waitpid($pid, 0);
624*7c356e86SAndroid Build Coastguard Worker	$child_kill_ok = 0;
625*7c356e86SAndroid Build Coastguard Worker	if ($xpid < 0) {
626*7c356e86SAndroid Build Coastguard Worker	    if ($EINTR) {
627*7c356e86SAndroid Build Coastguard Worker		next if $! == $EINTR;
628*7c356e86SAndroid Build Coastguard Worker	    }
629*7c356e86SAndroid Build Coastguard Worker	    print STDERR "$prog: error waiting for child - $!\n";
630*7c356e86SAndroid Build Coastguard Worker	    return undef;
631*7c356e86SAndroid Build Coastguard Worker	}
632*7c356e86SAndroid Build Coastguard Worker	last;
633*7c356e86SAndroid Build Coastguard Worker    }
634*7c356e86SAndroid Build Coastguard Worker    $status = $?;
635*7c356e86SAndroid Build Coastguard Worker    alarm(0) if defined $test{'time-limit'};
636*7c356e86SAndroid Build Coastguard Worker
637*7c356e86SAndroid Build Coastguard Worker    $failed = 0;
638*7c356e86SAndroid Build Coastguard Worker    $why = '';
639*7c356e86SAndroid Build Coastguard Worker
640*7c356e86SAndroid Build Coastguard Worker    if ($child_killed) {
641*7c356e86SAndroid Build Coastguard Worker	$failed = 1;
642*7c356e86SAndroid Build Coastguard Worker	$why .= "\ttest timed out (limit of $test{'time-limit'} seconds)\n";
643*7c356e86SAndroid Build Coastguard Worker    }
644*7c356e86SAndroid Build Coastguard Worker
645*7c356e86SAndroid Build Coastguard Worker    $ret = &eval_exit($test{'long-name'}, $status, $test{'expected-exit'});
646*7c356e86SAndroid Build Coastguard Worker    return undef if !defined $ret;
647*7c356e86SAndroid Build Coastguard Worker    if (!$ret) {
648*7c356e86SAndroid Build Coastguard Worker	local($expl);
649*7c356e86SAndroid Build Coastguard Worker
650*7c356e86SAndroid Build Coastguard Worker	$failed = 1;
651*7c356e86SAndroid Build Coastguard Worker	if (($status & 0xff) == 0x7f) {
652*7c356e86SAndroid Build Coastguard Worker	    $expl = "stopped";
653*7c356e86SAndroid Build Coastguard Worker	} elsif (($status & 0xff)) {
654*7c356e86SAndroid Build Coastguard Worker	    $expl = "signal " . ($status & 0x7f);
655*7c356e86SAndroid Build Coastguard Worker	} else {
656*7c356e86SAndroid Build Coastguard Worker	    $expl = "exit-code " . (($status >> 8) & 0xff);
657*7c356e86SAndroid Build Coastguard Worker	}
658*7c356e86SAndroid Build Coastguard Worker	$why .=
659*7c356e86SAndroid Build Coastguard Worker	"\tunexpected exit status $status ($expl), expected $test{'expected-exit'}\n";
660*7c356e86SAndroid Build Coastguard Worker    }
661*7c356e86SAndroid Build Coastguard Worker
662*7c356e86SAndroid Build Coastguard Worker    $tmp = &check_output($test{'long-name'}, $tempo, 'stdout',
663*7c356e86SAndroid Build Coastguard Worker		$test{'expected-stdout'}, $test{'expected-stdout-pattern'});
664*7c356e86SAndroid Build Coastguard Worker    return undef if !defined $tmp;
665*7c356e86SAndroid Build Coastguard Worker    if ($tmp ne '') {
666*7c356e86SAndroid Build Coastguard Worker	$failed = 1;
667*7c356e86SAndroid Build Coastguard Worker	$why .= $tmp;
668*7c356e86SAndroid Build Coastguard Worker    }
669*7c356e86SAndroid Build Coastguard Worker
670*7c356e86SAndroid Build Coastguard Worker    $tmp = &check_output($test{'long-name'}, $tempe, 'stderr',
671*7c356e86SAndroid Build Coastguard Worker		$test{'expected-stderr'}, $test{'expected-stderr-pattern'});
672*7c356e86SAndroid Build Coastguard Worker    return undef if !defined $tmp;
673*7c356e86SAndroid Build Coastguard Worker    if ($tmp ne '') {
674*7c356e86SAndroid Build Coastguard Worker	$failed = 1;
675*7c356e86SAndroid Build Coastguard Worker	$why .= $tmp;
676*7c356e86SAndroid Build Coastguard Worker    }
677*7c356e86SAndroid Build Coastguard Worker
678*7c356e86SAndroid Build Coastguard Worker    $tmp = &check_file_result(*test);
679*7c356e86SAndroid Build Coastguard Worker    return undef if !defined $tmp;
680*7c356e86SAndroid Build Coastguard Worker    if ($tmp ne '') {
681*7c356e86SAndroid Build Coastguard Worker	$failed = 1;
682*7c356e86SAndroid Build Coastguard Worker	$why .= $tmp;
683*7c356e86SAndroid Build Coastguard Worker    }
684*7c356e86SAndroid Build Coastguard Worker
685*7c356e86SAndroid Build Coastguard Worker    if (defined $test{'perl-cleanup'}) {
686*7c356e86SAndroid Build Coastguard Worker	eval $test{'perl-cleanup'};
687*7c356e86SAndroid Build Coastguard Worker	if ($@ ne '') {
688*7c356e86SAndroid Build Coastguard Worker	    print STDERR "$prog:$test{':long-name'}: error running perl-cleanup - $@\n";
689*7c356e86SAndroid Build Coastguard Worker	    return undef;
690*7c356e86SAndroid Build Coastguard Worker	}
691*7c356e86SAndroid Build Coastguard Worker    }
692*7c356e86SAndroid Build Coastguard Worker
693*7c356e86SAndroid Build Coastguard Worker    if (!chdir($pwd)) {
694*7c356e86SAndroid Build Coastguard Worker	print STDERR "$prog: couldn't cd to $pwd - $!\n";
695*7c356e86SAndroid Build Coastguard Worker	return undef;
696*7c356e86SAndroid Build Coastguard Worker    }
697*7c356e86SAndroid Build Coastguard Worker
698*7c356e86SAndroid Build Coastguard Worker    if ($failed) {
699*7c356e86SAndroid Build Coastguard Worker	if (!$test{'expected-fail'}) {
700*7c356e86SAndroid Build Coastguard Worker	    if ($test{'need-pass'}) {
701*7c356e86SAndroid Build Coastguard Worker		print "FAIL $name\n";
702*7c356e86SAndroid Build Coastguard Worker		$nxfailed++;
703*7c356e86SAndroid Build Coastguard Worker	    } else {
704*7c356e86SAndroid Build Coastguard Worker		print "FAIL $name (ignored)\n";
705*7c356e86SAndroid Build Coastguard Worker		$nifailed++;
706*7c356e86SAndroid Build Coastguard Worker	    }
707*7c356e86SAndroid Build Coastguard Worker	} else {
708*7c356e86SAndroid Build Coastguard Worker	    print "fail $name (as expected)\n";
709*7c356e86SAndroid Build Coastguard Worker	    $nfailed++;
710*7c356e86SAndroid Build Coastguard Worker	}
711*7c356e86SAndroid Build Coastguard Worker	$why = "\tDescription"
712*7c356e86SAndroid Build Coastguard Worker		. &wrap_lines($test{'description'}, " (missing)\n")
713*7c356e86SAndroid Build Coastguard Worker		. $why;
714*7c356e86SAndroid Build Coastguard Worker    } elsif ($test{'expected-fail'}) {
715*7c356e86SAndroid Build Coastguard Worker	print "PASS $name (unexpectedly)\n";
716*7c356e86SAndroid Build Coastguard Worker	$nxpassed++;
717*7c356e86SAndroid Build Coastguard Worker    } else {
718*7c356e86SAndroid Build Coastguard Worker	print "pass $name\n";
719*7c356e86SAndroid Build Coastguard Worker	$npassed++;
720*7c356e86SAndroid Build Coastguard Worker    }
721*7c356e86SAndroid Build Coastguard Worker    print $why if $verbose;
722*7c356e86SAndroid Build Coastguard Worker    return 0;
723*7c356e86SAndroid Build Coastguard Worker}
724*7c356e86SAndroid Build Coastguard Worker
725*7c356e86SAndroid Build Coastguard Workersub
726*7c356e86SAndroid Build Coastguard Workercategory_check
727*7c356e86SAndroid Build Coastguard Worker{
728*7c356e86SAndroid Build Coastguard Worker    local(*test) = @_;
729*7c356e86SAndroid Build Coastguard Worker    local($c);
730*7c356e86SAndroid Build Coastguard Worker
731*7c356e86SAndroid Build Coastguard Worker    return 0 if ($test{'need-ctty'} && defined $categories{'regress:no-ctty'});
732*7c356e86SAndroid Build Coastguard Worker    return 1 if (!defined $test{'category'});
733*7c356e86SAndroid Build Coastguard Worker    local($ok) = 0;
734*7c356e86SAndroid Build Coastguard Worker    foreach $c (split(',', $test{'category'})) {
735*7c356e86SAndroid Build Coastguard Worker	$c =~ s/\s+//;
736*7c356e86SAndroid Build Coastguard Worker	if ($c =~ /^!/) {
737*7c356e86SAndroid Build Coastguard Worker	    $c = $';
738*7c356e86SAndroid Build Coastguard Worker	    return 0 if (defined $categories{$c});
739*7c356e86SAndroid Build Coastguard Worker	    $ok = 1;
740*7c356e86SAndroid Build Coastguard Worker	} else {
741*7c356e86SAndroid Build Coastguard Worker	    $ok = 1 if (defined $categories{$c});
742*7c356e86SAndroid Build Coastguard Worker	}
743*7c356e86SAndroid Build Coastguard Worker    }
744*7c356e86SAndroid Build Coastguard Worker    return $ok;
745*7c356e86SAndroid Build Coastguard Worker}
746*7c356e86SAndroid Build Coastguard Worker
747*7c356e86SAndroid Build Coastguard Workersub
748*7c356e86SAndroid Build Coastguard Workerscrub_dir
749*7c356e86SAndroid Build Coastguard Worker{
750*7c356e86SAndroid Build Coastguard Worker    local($dir) = @_;
751*7c356e86SAndroid Build Coastguard Worker    local(@todo) = ();
752*7c356e86SAndroid Build Coastguard Worker    local($file);
753*7c356e86SAndroid Build Coastguard Worker
754*7c356e86SAndroid Build Coastguard Worker    if (!opendir(DIR, $dir)) {
755*7c356e86SAndroid Build Coastguard Worker	print STDERR "$prog: couldn't open directory $dir - $!\n";
756*7c356e86SAndroid Build Coastguard Worker	return undef;
757*7c356e86SAndroid Build Coastguard Worker    }
758*7c356e86SAndroid Build Coastguard Worker    while (defined ($file = readdir(DIR))) {
759*7c356e86SAndroid Build Coastguard Worker	push(@todo, $file) if $file ne '.' && $file ne '..';
760*7c356e86SAndroid Build Coastguard Worker    }
761*7c356e86SAndroid Build Coastguard Worker    closedir(DIR);
762*7c356e86SAndroid Build Coastguard Worker    foreach $file (@todo) {
763*7c356e86SAndroid Build Coastguard Worker	$file = "$dir/$file";
764*7c356e86SAndroid Build Coastguard Worker	if (-d $file) {
765*7c356e86SAndroid Build Coastguard Worker	    return undef if !&scrub_dir($file);
766*7c356e86SAndroid Build Coastguard Worker	    if (!rmdir($file)) {
767*7c356e86SAndroid Build Coastguard Worker		print STDERR "$prog: couldn't rmdir $file - $!\n";
768*7c356e86SAndroid Build Coastguard Worker		return undef;
769*7c356e86SAndroid Build Coastguard Worker	    }
770*7c356e86SAndroid Build Coastguard Worker	} else {
771*7c356e86SAndroid Build Coastguard Worker	    if (!unlink($file)) {
772*7c356e86SAndroid Build Coastguard Worker		print STDERR "$prog: couldn't unlink $file - $!\n";
773*7c356e86SAndroid Build Coastguard Worker		return undef;
774*7c356e86SAndroid Build Coastguard Worker	    }
775*7c356e86SAndroid Build Coastguard Worker	}
776*7c356e86SAndroid Build Coastguard Worker    }
777*7c356e86SAndroid Build Coastguard Worker    return 1;
778*7c356e86SAndroid Build Coastguard Worker}
779*7c356e86SAndroid Build Coastguard Worker
780*7c356e86SAndroid Build Coastguard Workersub
781*7c356e86SAndroid Build Coastguard Workerwrite_file
782*7c356e86SAndroid Build Coastguard Worker{
783*7c356e86SAndroid Build Coastguard Worker    local($file, $str) = @_;
784*7c356e86SAndroid Build Coastguard Worker
785*7c356e86SAndroid Build Coastguard Worker    if (!open(TEMP, "> $file")) {
786*7c356e86SAndroid Build Coastguard Worker	print STDERR "$prog: can't open $file - $!\n";
787*7c356e86SAndroid Build Coastguard Worker	return undef;
788*7c356e86SAndroid Build Coastguard Worker    }
789*7c356e86SAndroid Build Coastguard Worker    binmode(TEMP);
790*7c356e86SAndroid Build Coastguard Worker    print TEMP $str;
791*7c356e86SAndroid Build Coastguard Worker    if (!close(TEMP)) {
792*7c356e86SAndroid Build Coastguard Worker	print STDERR "$prog: error writing $file - $!\n";
793*7c356e86SAndroid Build Coastguard Worker	return undef;
794*7c356e86SAndroid Build Coastguard Worker    }
795*7c356e86SAndroid Build Coastguard Worker    return 1;
796*7c356e86SAndroid Build Coastguard Worker}
797*7c356e86SAndroid Build Coastguard Worker
798*7c356e86SAndroid Build Coastguard Workersub
799*7c356e86SAndroid Build Coastguard Workercheck_output
800*7c356e86SAndroid Build Coastguard Worker{
801*7c356e86SAndroid Build Coastguard Worker    local($name, $file, $what, $expect, $expect_pat) = @_;
802*7c356e86SAndroid Build Coastguard Worker    local($got) = '';
803*7c356e86SAndroid Build Coastguard Worker    local($why) = '';
804*7c356e86SAndroid Build Coastguard Worker    local($ret);
805*7c356e86SAndroid Build Coastguard Worker
806*7c356e86SAndroid Build Coastguard Worker    if (!open(TEMP, "< $file")) {
807*7c356e86SAndroid Build Coastguard Worker	print STDERR "$prog:$name($what): couldn't open $file after running program - $!\n";
808*7c356e86SAndroid Build Coastguard Worker	return undef;
809*7c356e86SAndroid Build Coastguard Worker    }
810*7c356e86SAndroid Build Coastguard Worker    binmode(TEMP);
811*7c356e86SAndroid Build Coastguard Worker    while (<TEMP>) {
812*7c356e86SAndroid Build Coastguard Worker	$got .= $_;
813*7c356e86SAndroid Build Coastguard Worker    }
814*7c356e86SAndroid Build Coastguard Worker    close(TEMP);
815*7c356e86SAndroid Build Coastguard Worker    return compare_output($name, $what, $expect, $expect_pat, $got);
816*7c356e86SAndroid Build Coastguard Worker}
817*7c356e86SAndroid Build Coastguard Worker
818*7c356e86SAndroid Build Coastguard Workersub
819*7c356e86SAndroid Build Coastguard Workercompare_output
820*7c356e86SAndroid Build Coastguard Worker{
821*7c356e86SAndroid Build Coastguard Worker    local($name, $what, $expect, $expect_pat, $got) = @_;
822*7c356e86SAndroid Build Coastguard Worker    local($why) = '';
823*7c356e86SAndroid Build Coastguard Worker
824*7c356e86SAndroid Build Coastguard Worker    if (defined $expect_pat) {
825*7c356e86SAndroid Build Coastguard Worker	$_ = $got;
826*7c356e86SAndroid Build Coastguard Worker	$ret = eval "$expect_pat";
827*7c356e86SAndroid Build Coastguard Worker	if ($@ ne '') {
828*7c356e86SAndroid Build Coastguard Worker	    print STDERR "$prog:$name($what): error evaluating $what pattern: $expect_pat - $@\n";
829*7c356e86SAndroid Build Coastguard Worker	    return undef;
830*7c356e86SAndroid Build Coastguard Worker	}
831*7c356e86SAndroid Build Coastguard Worker	if (!$ret) {
832*7c356e86SAndroid Build Coastguard Worker	    $why = "\tunexpected $what - wanted pattern";
833*7c356e86SAndroid Build Coastguard Worker	    $why .= &wrap_lines($expect_pat);
834*7c356e86SAndroid Build Coastguard Worker	    $why .= "\tgot";
835*7c356e86SAndroid Build Coastguard Worker	    $why .= &wrap_lines($got);
836*7c356e86SAndroid Build Coastguard Worker	}
837*7c356e86SAndroid Build Coastguard Worker    } else {
838*7c356e86SAndroid Build Coastguard Worker	$expect = '' if !defined $expect;
839*7c356e86SAndroid Build Coastguard Worker	if ($got ne $expect) {
840*7c356e86SAndroid Build Coastguard Worker	    $why .= "\tunexpected $what - " . &first_diff($expect, $got) . "\n";
841*7c356e86SAndroid Build Coastguard Worker	    $why .= "\twanted";
842*7c356e86SAndroid Build Coastguard Worker	    $why .= &wrap_lines($expect);
843*7c356e86SAndroid Build Coastguard Worker	    $why .= "\tgot";
844*7c356e86SAndroid Build Coastguard Worker	    $why .= &wrap_lines($got);
845*7c356e86SAndroid Build Coastguard Worker	}
846*7c356e86SAndroid Build Coastguard Worker    }
847*7c356e86SAndroid Build Coastguard Worker    return $why;
848*7c356e86SAndroid Build Coastguard Worker}
849*7c356e86SAndroid Build Coastguard Worker
850*7c356e86SAndroid Build Coastguard Workersub
851*7c356e86SAndroid Build Coastguard Workerwrap_lines
852*7c356e86SAndroid Build Coastguard Worker{
853*7c356e86SAndroid Build Coastguard Worker    local($str, $empty) = @_;
854*7c356e86SAndroid Build Coastguard Worker    local($nonl) = substr($str, -1, 1) ne "\n";
855*7c356e86SAndroid Build Coastguard Worker
856*7c356e86SAndroid Build Coastguard Worker    return (defined $empty ? $empty : " nothing\n") if $str eq '';
857*7c356e86SAndroid Build Coastguard Worker    substr($str, 0, 0) = ":\n";
858*7c356e86SAndroid Build Coastguard Worker    $str =~ s/\n/\n\t\t/g;
859*7c356e86SAndroid Build Coastguard Worker    if ($nonl) {
860*7c356e86SAndroid Build Coastguard Worker	$str .= "\n\t[incomplete last line]\n";
861*7c356e86SAndroid Build Coastguard Worker    } else {
862*7c356e86SAndroid Build Coastguard Worker	chop($str);
863*7c356e86SAndroid Build Coastguard Worker	chop($str);
864*7c356e86SAndroid Build Coastguard Worker    }
865*7c356e86SAndroid Build Coastguard Worker    return $str;
866*7c356e86SAndroid Build Coastguard Worker}
867*7c356e86SAndroid Build Coastguard Worker
868*7c356e86SAndroid Build Coastguard Workersub
869*7c356e86SAndroid Build Coastguard Workerfirst_diff
870*7c356e86SAndroid Build Coastguard Worker{
871*7c356e86SAndroid Build Coastguard Worker    local($exp, $got) = @_;
872*7c356e86SAndroid Build Coastguard Worker    local($lineno, $char) = (1, 1);
873*7c356e86SAndroid Build Coastguard Worker    local($i, $exp_len, $got_len);
874*7c356e86SAndroid Build Coastguard Worker    local($ce, $cg);
875*7c356e86SAndroid Build Coastguard Worker
876*7c356e86SAndroid Build Coastguard Worker    $exp_len = length($exp);
877*7c356e86SAndroid Build Coastguard Worker    $got_len = length($got);
878*7c356e86SAndroid Build Coastguard Worker    if ($exp_len != $got_len) {
879*7c356e86SAndroid Build Coastguard Worker	if ($exp_len < $got_len) {
880*7c356e86SAndroid Build Coastguard Worker	    if (substr($got, 0, $exp_len) eq $exp) {
881*7c356e86SAndroid Build Coastguard Worker		return "got too much output";
882*7c356e86SAndroid Build Coastguard Worker	    }
883*7c356e86SAndroid Build Coastguard Worker	} elsif (substr($exp, 0, $got_len) eq $got) {
884*7c356e86SAndroid Build Coastguard Worker	    return "got too little output";
885*7c356e86SAndroid Build Coastguard Worker	}
886*7c356e86SAndroid Build Coastguard Worker    }
887*7c356e86SAndroid Build Coastguard Worker    for ($i = 0; $i < $exp_len; $i++) {
888*7c356e86SAndroid Build Coastguard Worker	$ce = substr($exp, $i, 1);
889*7c356e86SAndroid Build Coastguard Worker	$cg = substr($got, $i, 1);
890*7c356e86SAndroid Build Coastguard Worker	last if $ce ne $cg;
891*7c356e86SAndroid Build Coastguard Worker	$char++;
892*7c356e86SAndroid Build Coastguard Worker	if ($ce eq "\n") {
893*7c356e86SAndroid Build Coastguard Worker	    $lineno++;
894*7c356e86SAndroid Build Coastguard Worker	    $char = 1;
895*7c356e86SAndroid Build Coastguard Worker	}
896*7c356e86SAndroid Build Coastguard Worker    }
897*7c356e86SAndroid Build Coastguard Worker    return "first difference: line $lineno, char $char (wanted " .
898*7c356e86SAndroid Build Coastguard Worker	&format_char($ce) . ", got " . &format_char($cg);
899*7c356e86SAndroid Build Coastguard Worker}
900*7c356e86SAndroid Build Coastguard Worker
901*7c356e86SAndroid Build Coastguard Workersub
902*7c356e86SAndroid Build Coastguard Workerformat_char
903*7c356e86SAndroid Build Coastguard Worker{
904*7c356e86SAndroid Build Coastguard Worker    local($ch, $s, $q);
905*7c356e86SAndroid Build Coastguard Worker
906*7c356e86SAndroid Build Coastguard Worker    $ch = ord($_[0]);
907*7c356e86SAndroid Build Coastguard Worker    $q = "'";
908*7c356e86SAndroid Build Coastguard Worker
909*7c356e86SAndroid Build Coastguard Worker    if ($is_ebcdic) {
910*7c356e86SAndroid Build Coastguard Worker	if ($ch == 0x15) {
911*7c356e86SAndroid Build Coastguard Worker		return $q . '\n' . $q;
912*7c356e86SAndroid Build Coastguard Worker	} elsif ($ch == 0x16) {
913*7c356e86SAndroid Build Coastguard Worker		return $q . '\b' . $q;
914*7c356e86SAndroid Build Coastguard Worker	} elsif ($ch == 0x05) {
915*7c356e86SAndroid Build Coastguard Worker		return $q . '\t' . $q;
916*7c356e86SAndroid Build Coastguard Worker	} elsif ($ch < 64 || $ch == 255) {
917*7c356e86SAndroid Build Coastguard Worker		return sprintf("X'%02X'", $ch);
918*7c356e86SAndroid Build Coastguard Worker	}
919*7c356e86SAndroid Build Coastguard Worker	return sprintf("'%c' (X'%02X')", $ch, $ch);
920*7c356e86SAndroid Build Coastguard Worker    }
921*7c356e86SAndroid Build Coastguard Worker
922*7c356e86SAndroid Build Coastguard Worker    $s = sprintf("0x%02X (", $ch);
923*7c356e86SAndroid Build Coastguard Worker    if ($ch == 10) {
924*7c356e86SAndroid Build Coastguard Worker	return $s . $q . '\n' . $q . ')';
925*7c356e86SAndroid Build Coastguard Worker    } elsif ($ch == 13) {
926*7c356e86SAndroid Build Coastguard Worker	return $s . $q . '\r' . $q . ')';
927*7c356e86SAndroid Build Coastguard Worker    } elsif ($ch == 8) {
928*7c356e86SAndroid Build Coastguard Worker	return $s . $q . '\b' . $q . ')';
929*7c356e86SAndroid Build Coastguard Worker    } elsif ($ch == 9) {
930*7c356e86SAndroid Build Coastguard Worker	return $s . $q . '\t' . $q . ')';
931*7c356e86SAndroid Build Coastguard Worker    } elsif ($ch > 127) {
932*7c356e86SAndroid Build Coastguard Worker	$ch -= 128;
933*7c356e86SAndroid Build Coastguard Worker	$s .= "M-";
934*7c356e86SAndroid Build Coastguard Worker    }
935*7c356e86SAndroid Build Coastguard Worker    if ($ch < 32) {
936*7c356e86SAndroid Build Coastguard Worker	return sprintf("%s^%c)", $s, $ch + ord('@'));
937*7c356e86SAndroid Build Coastguard Worker    } elsif ($ch == 127) {
938*7c356e86SAndroid Build Coastguard Worker	return $s . "^?)";
939*7c356e86SAndroid Build Coastguard Worker    }
940*7c356e86SAndroid Build Coastguard Worker    return sprintf("%s'%c')", $s, $ch);
941*7c356e86SAndroid Build Coastguard Worker}
942*7c356e86SAndroid Build Coastguard Worker
943*7c356e86SAndroid Build Coastguard Workersub
944*7c356e86SAndroid Build Coastguard Workereval_exit
945*7c356e86SAndroid Build Coastguard Worker{
946*7c356e86SAndroid Build Coastguard Worker    local($name, $status, $expect) = @_;
947*7c356e86SAndroid Build Coastguard Worker    local($expr);
948*7c356e86SAndroid Build Coastguard Worker    local($w, $e, $s) = ($status, ($status >> 8) & 0xff, $status & 0x7f);
949*7c356e86SAndroid Build Coastguard Worker
950*7c356e86SAndroid Build Coastguard Worker    $e = -1000 if $status & 0xff;
951*7c356e86SAndroid Build Coastguard Worker    $s = -1000 if $s == 0x7f;
952*7c356e86SAndroid Build Coastguard Worker    if (!defined $expect) {
953*7c356e86SAndroid Build Coastguard Worker	$expr = '$w == 0';
954*7c356e86SAndroid Build Coastguard Worker    } elsif ($expect =~ /^(|-)\d+$/) {
955*7c356e86SAndroid Build Coastguard Worker	$expr = "\$e == $expect";
956*7c356e86SAndroid Build Coastguard Worker    } else {
957*7c356e86SAndroid Build Coastguard Worker	$expr = $expect;
958*7c356e86SAndroid Build Coastguard Worker	$expr =~ s/\b([wse])\b/\$$1/g;
959*7c356e86SAndroid Build Coastguard Worker	$expr =~ s/\b(SIG[A-Z][A-Z0-9]*)\b/&$1/g;
960*7c356e86SAndroid Build Coastguard Worker    }
961*7c356e86SAndroid Build Coastguard Worker    $w = eval $expr;
962*7c356e86SAndroid Build Coastguard Worker    if ($@ ne '') {
963*7c356e86SAndroid Build Coastguard Worker	print STDERR "$prog:$test{':long-name'}: bad expected-exit expression: $expect ($@)\n";
964*7c356e86SAndroid Build Coastguard Worker	return undef;
965*7c356e86SAndroid Build Coastguard Worker    }
966*7c356e86SAndroid Build Coastguard Worker    return $w;
967*7c356e86SAndroid Build Coastguard Worker}
968*7c356e86SAndroid Build Coastguard Worker
969*7c356e86SAndroid Build Coastguard Workersub
970*7c356e86SAndroid Build Coastguard Workerread_test
971*7c356e86SAndroid Build Coastguard Worker{
972*7c356e86SAndroid Build Coastguard Worker    local($file, $in, *test) = @_;
973*7c356e86SAndroid Build Coastguard Worker    local($field, $val, $flags, $do_chop, $need_redo, $start_lineno);
974*7c356e86SAndroid Build Coastguard Worker    local(%cnt, $sfield);
975*7c356e86SAndroid Build Coastguard Worker
976*7c356e86SAndroid Build Coastguard Worker    %test = ();
977*7c356e86SAndroid Build Coastguard Worker    %cnt = ();
978*7c356e86SAndroid Build Coastguard Worker    while (<$in>) {
979*7c356e86SAndroid Build Coastguard Worker	chop;
980*7c356e86SAndroid Build Coastguard Worker	next if /^\s*$/;
981*7c356e86SAndroid Build Coastguard Worker	next if /^ *#/;
982*7c356e86SAndroid Build Coastguard Worker	last if /^\s*---\s*$/;
983*7c356e86SAndroid Build Coastguard Worker	$start_lineno = $. if !defined $start_lineno;
984*7c356e86SAndroid Build Coastguard Worker	if (!/^([-\w]+):\s*(|\S|\S.*\S)\s*$/) {
985*7c356e86SAndroid Build Coastguard Worker	    print STDERR "$prog:$file:$.: unrecognised line \"$_\"\n";
986*7c356e86SAndroid Build Coastguard Worker	    return undef;
987*7c356e86SAndroid Build Coastguard Worker	}
988*7c356e86SAndroid Build Coastguard Worker	($field, $val) = ($1, $2);
989*7c356e86SAndroid Build Coastguard Worker	$sfield = $field;
990*7c356e86SAndroid Build Coastguard Worker	$flags = $test_fields{$field};
991*7c356e86SAndroid Build Coastguard Worker	if (!defined $flags) {
992*7c356e86SAndroid Build Coastguard Worker	    print STDERR "$prog:$file:$.: unrecognised field \"$field\"\n";
993*7c356e86SAndroid Build Coastguard Worker	    return undef;
994*7c356e86SAndroid Build Coastguard Worker	}
995*7c356e86SAndroid Build Coastguard Worker	if ($flags =~ /s/) {
996*7c356e86SAndroid Build Coastguard Worker	    local($cnt) = $cnt{$field}++;
997*7c356e86SAndroid Build Coastguard Worker	    $test{$field} = $cnt{$field};
998*7c356e86SAndroid Build Coastguard Worker	    $cnt = 0 if $cnt eq '';
999*7c356e86SAndroid Build Coastguard Worker	    $sfield .= ":$cnt";
1000*7c356e86SAndroid Build Coastguard Worker	} elsif (defined $test{$field}) {
1001*7c356e86SAndroid Build Coastguard Worker	    print STDERR "$prog:$file:$.: multiple \"$field\" fields\n";
1002*7c356e86SAndroid Build Coastguard Worker	    return undef;
1003*7c356e86SAndroid Build Coastguard Worker	}
1004*7c356e86SAndroid Build Coastguard Worker	$do_chop = $flags !~ /m/;
1005*7c356e86SAndroid Build Coastguard Worker	$need_redo = 0;
1006*7c356e86SAndroid Build Coastguard Worker	if ($val eq '' || $val eq '!' || $flags =~ /p/) {
1007*7c356e86SAndroid Build Coastguard Worker	    if ($flags =~ /[Mm]/) {
1008*7c356e86SAndroid Build Coastguard Worker		if ($flags =~ /p/) {
1009*7c356e86SAndroid Build Coastguard Worker		    if ($val =~ /^!/) {
1010*7c356e86SAndroid Build Coastguard Worker			$do_chop = 1;
1011*7c356e86SAndroid Build Coastguard Worker			$val = $';
1012*7c356e86SAndroid Build Coastguard Worker		    } else {
1013*7c356e86SAndroid Build Coastguard Worker			$do_chop = 0;
1014*7c356e86SAndroid Build Coastguard Worker		    }
1015*7c356e86SAndroid Build Coastguard Worker		    if ($val eq '') {
1016*7c356e86SAndroid Build Coastguard Worker			print STDERR
1017*7c356e86SAndroid Build Coastguard Worker		"$prog:$file:$.: no parameters given for field \"$field\"\n";
1018*7c356e86SAndroid Build Coastguard Worker			return undef;
1019*7c356e86SAndroid Build Coastguard Worker		    }
1020*7c356e86SAndroid Build Coastguard Worker		} else {
1021*7c356e86SAndroid Build Coastguard Worker		    if ($val eq '!') {
1022*7c356e86SAndroid Build Coastguard Worker			$do_chop = 1;
1023*7c356e86SAndroid Build Coastguard Worker		    }
1024*7c356e86SAndroid Build Coastguard Worker		    $val = '';
1025*7c356e86SAndroid Build Coastguard Worker		}
1026*7c356e86SAndroid Build Coastguard Worker		while (<$in>) {
1027*7c356e86SAndroid Build Coastguard Worker		    last if !/^\t/;
1028*7c356e86SAndroid Build Coastguard Worker		    $val .= $';
1029*7c356e86SAndroid Build Coastguard Worker		}
1030*7c356e86SAndroid Build Coastguard Worker		chop $val if $do_chop;
1031*7c356e86SAndroid Build Coastguard Worker		$do_chop = 1;
1032*7c356e86SAndroid Build Coastguard Worker		$need_redo = 1;
1033*7c356e86SAndroid Build Coastguard Worker
1034*7c356e86SAndroid Build Coastguard Worker		# Syntax check on fields that can several instances
1035*7c356e86SAndroid Build Coastguard Worker		# (can give useful line numbers this way)
1036*7c356e86SAndroid Build Coastguard Worker
1037*7c356e86SAndroid Build Coastguard Worker		if ($field eq 'file-setup') {
1038*7c356e86SAndroid Build Coastguard Worker		    local($type, $perm, $rest, $c, $len, $name);
1039*7c356e86SAndroid Build Coastguard Worker
1040*7c356e86SAndroid Build Coastguard Worker		    # format is: type perm "name"
1041*7c356e86SAndroid Build Coastguard Worker		    if ($val !~ /^[ \t]*(\S+)[ \t]+(\S+)[ \t]+([^ \t].*)/) {
1042*7c356e86SAndroid Build Coastguard Worker			print STDERR
1043*7c356e86SAndroid Build Coastguard Worker		    "$prog:$file:$.: bad parameter line for file-setup field\n";
1044*7c356e86SAndroid Build Coastguard Worker			return undef;
1045*7c356e86SAndroid Build Coastguard Worker		    }
1046*7c356e86SAndroid Build Coastguard Worker		    ($type, $perm, $rest) = ($1, $2, $3);
1047*7c356e86SAndroid Build Coastguard Worker		    if ($type !~ /^(file|dir|symlink)$/) {
1048*7c356e86SAndroid Build Coastguard Worker			print STDERR
1049*7c356e86SAndroid Build Coastguard Worker		    "$prog:$file:$.: bad file type for file-setup: $type\n";
1050*7c356e86SAndroid Build Coastguard Worker			return undef;
1051*7c356e86SAndroid Build Coastguard Worker		    }
1052*7c356e86SAndroid Build Coastguard Worker		    if ($perm !~ /^\d+$/) {
1053*7c356e86SAndroid Build Coastguard Worker			print STDERR
1054*7c356e86SAndroid Build Coastguard Worker		    "$prog:$file:$.: bad permissions for file-setup: $type\n";
1055*7c356e86SAndroid Build Coastguard Worker			return undef;
1056*7c356e86SAndroid Build Coastguard Worker		    }
1057*7c356e86SAndroid Build Coastguard Worker		    $c = substr($rest, 0, 1);
1058*7c356e86SAndroid Build Coastguard Worker		    if (($len = index($rest, $c, 1) - 1) <= 0) {
1059*7c356e86SAndroid Build Coastguard Worker			print STDERR
1060*7c356e86SAndroid Build Coastguard Worker    "$prog:$file:$.: missing end quote for file name in file-setup: $rest\n";
1061*7c356e86SAndroid Build Coastguard Worker			return undef;
1062*7c356e86SAndroid Build Coastguard Worker		    }
1063*7c356e86SAndroid Build Coastguard Worker		    $name = substr($rest, 1, $len);
1064*7c356e86SAndroid Build Coastguard Worker		    if ($name =~ /^\// || $name =~ /(^|\/)\.\.(\/|$)/) {
1065*7c356e86SAndroid Build Coastguard Worker			# Note: this is not a security thing - just a sanity
1066*7c356e86SAndroid Build Coastguard Worker			# check - a test can still use symlinks to get at files
1067*7c356e86SAndroid Build Coastguard Worker			# outside the test directory.
1068*7c356e86SAndroid Build Coastguard Worker			print STDERR
1069*7c356e86SAndroid Build Coastguard Worker"$prog:$file:$.: file name in file-setup is absolute or contains ..: $name\n";
1070*7c356e86SAndroid Build Coastguard Worker			return undef;
1071*7c356e86SAndroid Build Coastguard Worker		    }
1072*7c356e86SAndroid Build Coastguard Worker		}
1073*7c356e86SAndroid Build Coastguard Worker		if ($field eq 'file-result') {
1074*7c356e86SAndroid Build Coastguard Worker		    local($type, $perm, $uid, $gid, $matchType,
1075*7c356e86SAndroid Build Coastguard Worker			  $rest, $c, $len, $name);
1076*7c356e86SAndroid Build Coastguard Worker
1077*7c356e86SAndroid Build Coastguard Worker		    # format is: type perm uid gid matchType "name"
1078*7c356e86SAndroid Build Coastguard Worker		    if ($val !~ /^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S.*)/) {
1079*7c356e86SAndroid Build Coastguard Worker			print STDERR
1080*7c356e86SAndroid Build Coastguard Worker		    "$prog:$file:$.: bad parameter line for file-result field\n";
1081*7c356e86SAndroid Build Coastguard Worker			return undef;
1082*7c356e86SAndroid Build Coastguard Worker		    }
1083*7c356e86SAndroid Build Coastguard Worker		    ($type, $perm, $uid, $gid, $matchType, $rest)
1084*7c356e86SAndroid Build Coastguard Worker			= ($1, $2, $3, $4, $5, $6);
1085*7c356e86SAndroid Build Coastguard Worker		    if ($type !~ /^(file|dir|symlink)$/) {
1086*7c356e86SAndroid Build Coastguard Worker			print STDERR
1087*7c356e86SAndroid Build Coastguard Worker		    "$prog:$file:$.: bad file type for file-result: $type\n";
1088*7c356e86SAndroid Build Coastguard Worker			return undef;
1089*7c356e86SAndroid Build Coastguard Worker		    }
1090*7c356e86SAndroid Build Coastguard Worker		    if ($perm !~ /^\d+$/ && $perm ne '*') {
1091*7c356e86SAndroid Build Coastguard Worker			print STDERR
1092*7c356e86SAndroid Build Coastguard Worker		    "$prog:$file:$.: bad permissions for file-result: $perm\n";
1093*7c356e86SAndroid Build Coastguard Worker			return undef;
1094*7c356e86SAndroid Build Coastguard Worker		    }
1095*7c356e86SAndroid Build Coastguard Worker		    if ($uid !~ /^\d+$/ && $uid ne '*') {
1096*7c356e86SAndroid Build Coastguard Worker			print STDERR
1097*7c356e86SAndroid Build Coastguard Worker		    "$prog:$file:$.: bad user-id for file-result: $uid\n";
1098*7c356e86SAndroid Build Coastguard Worker			return undef;
1099*7c356e86SAndroid Build Coastguard Worker		    }
1100*7c356e86SAndroid Build Coastguard Worker		    if ($gid !~ /^\d+$/ && $gid ne '*') {
1101*7c356e86SAndroid Build Coastguard Worker			print STDERR
1102*7c356e86SAndroid Build Coastguard Worker		    "$prog:$file:$.: bad group-id for file-result: $gid\n";
1103*7c356e86SAndroid Build Coastguard Worker			return undef;
1104*7c356e86SAndroid Build Coastguard Worker		    }
1105*7c356e86SAndroid Build Coastguard Worker		    if ($matchType !~ /^(exact|pattern)$/) {
1106*7c356e86SAndroid Build Coastguard Worker			print STDERR
1107*7c356e86SAndroid Build Coastguard Worker		"$prog:$file:$.: bad match type for file-result: $matchType\n";
1108*7c356e86SAndroid Build Coastguard Worker			return undef;
1109*7c356e86SAndroid Build Coastguard Worker		    }
1110*7c356e86SAndroid Build Coastguard Worker		    $c = substr($rest, 0, 1);
1111*7c356e86SAndroid Build Coastguard Worker		    if (($len = index($rest, $c, 1) - 1) <= 0) {
1112*7c356e86SAndroid Build Coastguard Worker			print STDERR
1113*7c356e86SAndroid Build Coastguard Worker    "$prog:$file:$.: missing end quote for file name in file-result: $rest\n";
1114*7c356e86SAndroid Build Coastguard Worker			return undef;
1115*7c356e86SAndroid Build Coastguard Worker		    }
1116*7c356e86SAndroid Build Coastguard Worker		    $name = substr($rest, 1, $len);
1117*7c356e86SAndroid Build Coastguard Worker		    if ($name =~ /^\// || $name =~ /(^|\/)\.\.(\/|$)/) {
1118*7c356e86SAndroid Build Coastguard Worker			# Note: this is not a security thing - just a sanity
1119*7c356e86SAndroid Build Coastguard Worker			# check - a test can still use symlinks to get at files
1120*7c356e86SAndroid Build Coastguard Worker			# outside the test directory.
1121*7c356e86SAndroid Build Coastguard Worker			print STDERR
1122*7c356e86SAndroid Build Coastguard Worker"$prog:$file:$.: file name in file-result is absolute or contains ..: $name\n";
1123*7c356e86SAndroid Build Coastguard Worker			return undef;
1124*7c356e86SAndroid Build Coastguard Worker		    }
1125*7c356e86SAndroid Build Coastguard Worker		}
1126*7c356e86SAndroid Build Coastguard Worker	    } elsif ($val eq '') {
1127*7c356e86SAndroid Build Coastguard Worker		print STDERR
1128*7c356e86SAndroid Build Coastguard Worker		    "$prog:$file:$.: no value given for field \"$field\"\n";
1129*7c356e86SAndroid Build Coastguard Worker		return undef;
1130*7c356e86SAndroid Build Coastguard Worker	    }
1131*7c356e86SAndroid Build Coastguard Worker	}
1132*7c356e86SAndroid Build Coastguard Worker	$val .= "\n" if !$do_chop;
1133*7c356e86SAndroid Build Coastguard Worker	$test{$sfield} = $val;
1134*7c356e86SAndroid Build Coastguard Worker	redo if $need_redo;
1135*7c356e86SAndroid Build Coastguard Worker    }
1136*7c356e86SAndroid Build Coastguard Worker    if ($_ eq '') {
1137*7c356e86SAndroid Build Coastguard Worker	if (%test) {
1138*7c356e86SAndroid Build Coastguard Worker	    print STDERR
1139*7c356e86SAndroid Build Coastguard Worker	      "$prog:$file:$start_lineno: end-of-file while reading test\n";
1140*7c356e86SAndroid Build Coastguard Worker	    return undef;
1141*7c356e86SAndroid Build Coastguard Worker	}
1142*7c356e86SAndroid Build Coastguard Worker	return 0;
1143*7c356e86SAndroid Build Coastguard Worker    }
1144*7c356e86SAndroid Build Coastguard Worker
1145*7c356e86SAndroid Build Coastguard Worker    while (($field, $val) = each %test_fields) {
1146*7c356e86SAndroid Build Coastguard Worker	if ($val =~ /r/ && !defined $test{$field}) {
1147*7c356e86SAndroid Build Coastguard Worker	    print STDERR
1148*7c356e86SAndroid Build Coastguard Worker	      "$prog:$file:$start_lineno: required field \"$field\" missing\n";
1149*7c356e86SAndroid Build Coastguard Worker	    return undef;
1150*7c356e86SAndroid Build Coastguard Worker	}
1151*7c356e86SAndroid Build Coastguard Worker    }
1152*7c356e86SAndroid Build Coastguard Worker
1153*7c356e86SAndroid Build Coastguard Worker    $test{':full-name'} = substr($file, $file_prefix_skip) . ":$test{'name'}";
1154*7c356e86SAndroid Build Coastguard Worker    $test{':long-name'} = "$file:$start_lineno:$test{'name'}";
1155*7c356e86SAndroid Build Coastguard Worker
1156*7c356e86SAndroid Build Coastguard Worker    # Syntax check on specific fields
1157*7c356e86SAndroid Build Coastguard Worker    if (defined $test{'expected-fail'}) {
1158*7c356e86SAndroid Build Coastguard Worker	if ($test{'expected-fail'} !~ /^(yes|no)$/) {
1159*7c356e86SAndroid Build Coastguard Worker	    print STDERR
1160*7c356e86SAndroid Build Coastguard Worker	      "$prog:$test{':long-name'}: bad value for expected-fail field\n";
1161*7c356e86SAndroid Build Coastguard Worker	    return undef;
1162*7c356e86SAndroid Build Coastguard Worker	}
1163*7c356e86SAndroid Build Coastguard Worker	$test{'expected-fail'} = $1 eq 'yes';
1164*7c356e86SAndroid Build Coastguard Worker    } else {
1165*7c356e86SAndroid Build Coastguard Worker	$test{'expected-fail'} = 0;
1166*7c356e86SAndroid Build Coastguard Worker    }
1167*7c356e86SAndroid Build Coastguard Worker    if (defined $test{'need-ctty'}) {
1168*7c356e86SAndroid Build Coastguard Worker	if ($test{'need-ctty'} !~ /^(yes|no)$/) {
1169*7c356e86SAndroid Build Coastguard Worker	    print STDERR
1170*7c356e86SAndroid Build Coastguard Worker	      "$prog:$test{':long-name'}: bad value for need-ctty field\n";
1171*7c356e86SAndroid Build Coastguard Worker	    return undef;
1172*7c356e86SAndroid Build Coastguard Worker	}
1173*7c356e86SAndroid Build Coastguard Worker	$test{'need-ctty'} = $1 eq 'yes';
1174*7c356e86SAndroid Build Coastguard Worker    } else {
1175*7c356e86SAndroid Build Coastguard Worker	$test{'need-ctty'} = 0;
1176*7c356e86SAndroid Build Coastguard Worker    }
1177*7c356e86SAndroid Build Coastguard Worker    if (defined $test{'need-pass'}) {
1178*7c356e86SAndroid Build Coastguard Worker	if ($test{'need-pass'} !~ /^(yes|no)$/) {
1179*7c356e86SAndroid Build Coastguard Worker	    print STDERR
1180*7c356e86SAndroid Build Coastguard Worker	      "$prog:$test{':long-name'}: bad value for need-pass field\n";
1181*7c356e86SAndroid Build Coastguard Worker	    return undef;
1182*7c356e86SAndroid Build Coastguard Worker	}
1183*7c356e86SAndroid Build Coastguard Worker	$test{'need-pass'} = $1 eq 'yes';
1184*7c356e86SAndroid Build Coastguard Worker    } else {
1185*7c356e86SAndroid Build Coastguard Worker	$test{'need-pass'} = 1;
1186*7c356e86SAndroid Build Coastguard Worker    }
1187*7c356e86SAndroid Build Coastguard Worker    if (defined $test{'arguments'}) {
1188*7c356e86SAndroid Build Coastguard Worker	local($firstc) = substr($test{'arguments'}, 0, 1);
1189*7c356e86SAndroid Build Coastguard Worker
1190*7c356e86SAndroid Build Coastguard Worker	if (substr($test{'arguments'}, -1, 1) ne $firstc) {
1191*7c356e86SAndroid Build Coastguard Worker	    print STDERR "$prog:$test{':long-name'}: arguments field doesn't start and end with the same character\n";
1192*7c356e86SAndroid Build Coastguard Worker	    return undef;
1193*7c356e86SAndroid Build Coastguard Worker	}
1194*7c356e86SAndroid Build Coastguard Worker    }
1195*7c356e86SAndroid Build Coastguard Worker    if (defined $test{'env-setup'}) {
1196*7c356e86SAndroid Build Coastguard Worker	local($firstc) = substr($test{'env-setup'}, 0, 1);
1197*7c356e86SAndroid Build Coastguard Worker
1198*7c356e86SAndroid Build Coastguard Worker	if (substr($test{'env-setup'}, -1, 1) ne $firstc) {
1199*7c356e86SAndroid Build Coastguard Worker	    print STDERR "$prog:$test{':long-name'}: env-setup field doesn't start and end with the same character\n";
1200*7c356e86SAndroid Build Coastguard Worker	    return undef;
1201*7c356e86SAndroid Build Coastguard Worker	}
1202*7c356e86SAndroid Build Coastguard Worker
1203*7c356e86SAndroid Build Coastguard Worker	$test{'env-setup'} =~ s/\@utflocale\@/$utflocale/g;
1204*7c356e86SAndroid Build Coastguard Worker    }
1205*7c356e86SAndroid Build Coastguard Worker    if (defined $test{'expected-exit'}) {
1206*7c356e86SAndroid Build Coastguard Worker	local($val) = $test{'expected-exit'};
1207*7c356e86SAndroid Build Coastguard Worker
1208*7c356e86SAndroid Build Coastguard Worker	if ($val =~ /^(|-)\d+$/) {
1209*7c356e86SAndroid Build Coastguard Worker	    if ($val < 0 || $val > 255) {
1210*7c356e86SAndroid Build Coastguard Worker		print STDERR "$prog:$test{':long-name'}: expected-exit value $val not in 0..255\n";
1211*7c356e86SAndroid Build Coastguard Worker		return undef;
1212*7c356e86SAndroid Build Coastguard Worker	    }
1213*7c356e86SAndroid Build Coastguard Worker	} elsif ($val !~ /^([\s\d<>+=*%\/&|!()-]|\b[wse]\b|\bSIG[A-Z][A-Z0-9]*\b)+$/) {
1214*7c356e86SAndroid Build Coastguard Worker	    print STDERR "$prog:$test{':long-name'}: bad expected-exit expression: $val\n";
1215*7c356e86SAndroid Build Coastguard Worker	    return undef;
1216*7c356e86SAndroid Build Coastguard Worker	}
1217*7c356e86SAndroid Build Coastguard Worker    } else {
1218*7c356e86SAndroid Build Coastguard Worker	$test{'expected-exit'} = 0;
1219*7c356e86SAndroid Build Coastguard Worker    }
1220*7c356e86SAndroid Build Coastguard Worker    if (defined $test{'expected-stdout'}
1221*7c356e86SAndroid Build Coastguard Worker	&& defined $test{'expected-stdout-pattern'})
1222*7c356e86SAndroid Build Coastguard Worker    {
1223*7c356e86SAndroid Build Coastguard Worker	print STDERR "$prog:$test{':long-name'}: can't use both expected-stdout and expected-stdout-pattern\n";
1224*7c356e86SAndroid Build Coastguard Worker	return undef;
1225*7c356e86SAndroid Build Coastguard Worker    }
1226*7c356e86SAndroid Build Coastguard Worker    if (defined $test{'expected-stderr'}
1227*7c356e86SAndroid Build Coastguard Worker	&& defined $test{'expected-stderr-pattern'})
1228*7c356e86SAndroid Build Coastguard Worker    {
1229*7c356e86SAndroid Build Coastguard Worker	print STDERR "$prog:$test{':long-name'}: can't use both expected-stderr and expected-stderr-pattern\n";
1230*7c356e86SAndroid Build Coastguard Worker	return undef;
1231*7c356e86SAndroid Build Coastguard Worker    }
1232*7c356e86SAndroid Build Coastguard Worker    if (defined $test{'time-limit'}) {
1233*7c356e86SAndroid Build Coastguard Worker	if ($test{'time-limit'} !~ /^\d+$/ || $test{'time-limit'} == 0) {
1234*7c356e86SAndroid Build Coastguard Worker	    print STDERR
1235*7c356e86SAndroid Build Coastguard Worker	      "$prog:$test{':long-name'}: bad value for time-limit field\n";
1236*7c356e86SAndroid Build Coastguard Worker	    return undef;
1237*7c356e86SAndroid Build Coastguard Worker	}
1238*7c356e86SAndroid Build Coastguard Worker    } elsif (defined $default_time_limit) {
1239*7c356e86SAndroid Build Coastguard Worker	$test{'time-limit'} = $default_time_limit;
1240*7c356e86SAndroid Build Coastguard Worker    }
1241*7c356e86SAndroid Build Coastguard Worker
1242*7c356e86SAndroid Build Coastguard Worker    if (defined $known_tests{$test{'name'}}) {
1243*7c356e86SAndroid Build Coastguard Worker	print STDERR "$prog:$test{':long-name'}: warning: duplicate test name ${test{'name'}}\n";
1244*7c356e86SAndroid Build Coastguard Worker    }
1245*7c356e86SAndroid Build Coastguard Worker    $known_tests{$test{'name'}} = 1;
1246*7c356e86SAndroid Build Coastguard Worker
1247*7c356e86SAndroid Build Coastguard Worker    return 1;
1248*7c356e86SAndroid Build Coastguard Worker}
1249*7c356e86SAndroid Build Coastguard Worker
1250*7c356e86SAndroid Build Coastguard Workersub
1251*7c356e86SAndroid Build Coastguard Workertty_msg
1252*7c356e86SAndroid Build Coastguard Worker{
1253*7c356e86SAndroid Build Coastguard Worker    local($msg) = @_;
1254*7c356e86SAndroid Build Coastguard Worker
1255*7c356e86SAndroid Build Coastguard Worker    open(TTY, "> /dev/tty") || return 0;
1256*7c356e86SAndroid Build Coastguard Worker    print TTY $msg;
1257*7c356e86SAndroid Build Coastguard Worker    close(TTY);
1258*7c356e86SAndroid Build Coastguard Worker    return 1;
1259*7c356e86SAndroid Build Coastguard Worker}
1260*7c356e86SAndroid Build Coastguard Worker
1261*7c356e86SAndroid Build Coastguard Workersub
1262*7c356e86SAndroid Build Coastguard Workernever_called_funcs
1263*7c356e86SAndroid Build Coastguard Worker{
1264*7c356e86SAndroid Build Coastguard Worker	return 0;
1265*7c356e86SAndroid Build Coastguard Worker	&tty_msg("hi\n");
1266*7c356e86SAndroid Build Coastguard Worker	&never_called_funcs();
1267*7c356e86SAndroid Build Coastguard Worker	&catch_sigalrm();
1268*7c356e86SAndroid Build Coastguard Worker	$old_env{'foo'} = 'bar';
1269*7c356e86SAndroid Build Coastguard Worker	$internal_test_fields{'foo'} = 'bar';
1270*7c356e86SAndroid Build Coastguard Worker}
1271*7c356e86SAndroid Build Coastguard Worker
1272*7c356e86SAndroid Build Coastguard Workersub
1273*7c356e86SAndroid Build Coastguard Workercheck_file_result
1274*7c356e86SAndroid Build Coastguard Worker{
1275*7c356e86SAndroid Build Coastguard Worker    local(*test) = @_;
1276*7c356e86SAndroid Build Coastguard Worker
1277*7c356e86SAndroid Build Coastguard Worker    return '' if (!defined $test{'file-result'});
1278*7c356e86SAndroid Build Coastguard Worker
1279*7c356e86SAndroid Build Coastguard Worker    local($why) = '';
1280*7c356e86SAndroid Build Coastguard Worker    local($i);
1281*7c356e86SAndroid Build Coastguard Worker    local($type, $perm, $uid, $gid, $rest, $c, $len, $name);
1282*7c356e86SAndroid Build Coastguard Worker    local(@stbuf);
1283*7c356e86SAndroid Build Coastguard Worker
1284*7c356e86SAndroid Build Coastguard Worker    for ($i = 0; $i < $test{'file-result'}; $i++) {
1285*7c356e86SAndroid Build Coastguard Worker	$val = $test{"file-result:$i"};
1286*7c356e86SAndroid Build Coastguard Worker
1287*7c356e86SAndroid Build Coastguard Worker	# format is: type perm "name"
1288*7c356e86SAndroid Build Coastguard Worker	($type, $perm, $uid, $gid, $matchType, $rest) =
1289*7c356e86SAndroid Build Coastguard Worker	    split(' ', $val, 6);
1290*7c356e86SAndroid Build Coastguard Worker	$c = substr($rest, 0, 1);
1291*7c356e86SAndroid Build Coastguard Worker	$len = index($rest, $c, 1) - 1;
1292*7c356e86SAndroid Build Coastguard Worker	$name = substr($rest, 1, $len);
1293*7c356e86SAndroid Build Coastguard Worker	$rest = substr($rest, 2 + $len);
1294*7c356e86SAndroid Build Coastguard Worker	$perm = oct($perm) if $perm =~ /^\d+$/;
1295*7c356e86SAndroid Build Coastguard Worker
1296*7c356e86SAndroid Build Coastguard Worker	@stbuf = lstat($name);
1297*7c356e86SAndroid Build Coastguard Worker	if (!@stbuf) {
1298*7c356e86SAndroid Build Coastguard Worker	    $why .= "\texpected $type \"$name\" not created\n";
1299*7c356e86SAndroid Build Coastguard Worker	    next;
1300*7c356e86SAndroid Build Coastguard Worker	}
1301*7c356e86SAndroid Build Coastguard Worker	if ($perm ne '*' && ($stbuf[2] & 07777) != $perm) {
1302*7c356e86SAndroid Build Coastguard Worker	    $why .= "\t$type \"$name\" has unexpected permissions\n";
1303*7c356e86SAndroid Build Coastguard Worker	    $why .= sprintf("\t\texpected 0%o, found 0%o\n",
1304*7c356e86SAndroid Build Coastguard Worker		    $perm, $stbuf[2] & 07777);
1305*7c356e86SAndroid Build Coastguard Worker	}
1306*7c356e86SAndroid Build Coastguard Worker	if ($uid ne '*' && $stbuf[4] != $uid) {
1307*7c356e86SAndroid Build Coastguard Worker	    $why .= "\t$type \"$name\" has unexpected user-id\n";
1308*7c356e86SAndroid Build Coastguard Worker	    $why .= sprintf("\t\texpected %d, found %d\n",
1309*7c356e86SAndroid Build Coastguard Worker		    $uid, $stbuf[4]);
1310*7c356e86SAndroid Build Coastguard Worker	}
1311*7c356e86SAndroid Build Coastguard Worker	if ($gid ne '*' && $stbuf[5] != $gid) {
1312*7c356e86SAndroid Build Coastguard Worker	    $why .= "\t$type \"$name\" has unexpected group-id\n";
1313*7c356e86SAndroid Build Coastguard Worker	    $why .= sprintf("\t\texpected %d, found %d\n",
1314*7c356e86SAndroid Build Coastguard Worker		    $gid, $stbuf[5]);
1315*7c356e86SAndroid Build Coastguard Worker	}
1316*7c356e86SAndroid Build Coastguard Worker
1317*7c356e86SAndroid Build Coastguard Worker	if ($type eq 'file') {
1318*7c356e86SAndroid Build Coastguard Worker	    if (-l _ || ! -f _) {
1319*7c356e86SAndroid Build Coastguard Worker		$why .= "\t$type \"$name\" is not a regular file\n";
1320*7c356e86SAndroid Build Coastguard Worker	    } else {
1321*7c356e86SAndroid Build Coastguard Worker		local $tmp = &check_output($test{'long-name'}, $name,
1322*7c356e86SAndroid Build Coastguard Worker			    "$type contents in \"$name\"",
1323*7c356e86SAndroid Build Coastguard Worker			    $matchType eq 'exact' ? $rest : undef
1324*7c356e86SAndroid Build Coastguard Worker			    $matchType eq 'pattern' ? $rest : undef);
1325*7c356e86SAndroid Build Coastguard Worker		return undef if (!defined $tmp);
1326*7c356e86SAndroid Build Coastguard Worker		$why .= $tmp;
1327*7c356e86SAndroid Build Coastguard Worker	    }
1328*7c356e86SAndroid Build Coastguard Worker	} elsif ($type eq 'dir') {
1329*7c356e86SAndroid Build Coastguard Worker	    if ($rest !~ /^\s*$/) {
1330*7c356e86SAndroid Build Coastguard Worker		print STDERR "$prog:$test{':long-name'}: file-result test for directory $name should not have content specified\n";
1331*7c356e86SAndroid Build Coastguard Worker		return undef;
1332*7c356e86SAndroid Build Coastguard Worker	    }
1333*7c356e86SAndroid Build Coastguard Worker	    if (-l _ || ! -d _) {
1334*7c356e86SAndroid Build Coastguard Worker		$why .= "\t$type \"$name\" is not a directory\n";
1335*7c356e86SAndroid Build Coastguard Worker	    }
1336*7c356e86SAndroid Build Coastguard Worker	} elsif ($type eq 'symlink') {
1337*7c356e86SAndroid Build Coastguard Worker	    if (!-l _) {
1338*7c356e86SAndroid Build Coastguard Worker		$why .= "\t$type \"$name\" is not a symlink\n";
1339*7c356e86SAndroid Build Coastguard Worker	    } else {
1340*7c356e86SAndroid Build Coastguard Worker		local $content = readlink($name);
1341*7c356e86SAndroid Build Coastguard Worker		if (!defined $content) {
1342*7c356e86SAndroid Build Coastguard Worker		    print STDERR "$prog:$test{':long-name'}: file-result test for $type $name failed - could not readlink - $!\n";
1343*7c356e86SAndroid Build Coastguard Worker		    return undef;
1344*7c356e86SAndroid Build Coastguard Worker		}
1345*7c356e86SAndroid Build Coastguard Worker		local $tmp = &compare_output($test{'long-name'},
1346*7c356e86SAndroid Build Coastguard Worker			    "$type contents in \"$name\"",
1347*7c356e86SAndroid Build Coastguard Worker			    $matchType eq 'exact' ? $rest : undef
1348*7c356e86SAndroid Build Coastguard Worker			    $matchType eq 'pattern' ? $rest : undef);
1349*7c356e86SAndroid Build Coastguard Worker		return undef if (!defined $tmp);
1350*7c356e86SAndroid Build Coastguard Worker		$why .= $tmp;
1351*7c356e86SAndroid Build Coastguard Worker	    }
1352*7c356e86SAndroid Build Coastguard Worker	}
1353*7c356e86SAndroid Build Coastguard Worker    }
1354*7c356e86SAndroid Build Coastguard Worker
1355*7c356e86SAndroid Build Coastguard Worker    return $why;
1356*7c356e86SAndroid Build Coastguard Worker}
1357*7c356e86SAndroid Build Coastguard Worker
1358*7c356e86SAndroid Build Coastguard Workersub
1359*7c356e86SAndroid Build Coastguard WorkerHELP_MESSAGE
1360*7c356e86SAndroid Build Coastguard Worker{
1361*7c356e86SAndroid Build Coastguard Worker    print STDERR $Usage;
1362*7c356e86SAndroid Build Coastguard Worker    exit 0;
1363*7c356e86SAndroid Build Coastguard Worker}
1364