Integrate tools/regression/lib/libc/gen into the FreeBSD test suite
as lib/libc/tests/gen The code in test-fnmatch that was used for generating: - bin/sh/tests/builtins/case2.0 - bin/sh/tests/builtins/case3.0 has been left undisturbed. The target `make sh-tests` has been moved over from tools/regression/lib/libc/gen/Makefile to lib/libc/tests/gen/Makefile and made into a PHONY target case2.0 and case3.0 test input generation isn't being done automatically. This needs additional discussion. MFC after: 1 week Sponsored by: EMC / Isilon Storage Division
This commit is contained in:
parent
233193f1e6
commit
fbf5b9f8a2
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=290572
@ -2,8 +2,15 @@
|
|||||||
|
|
||||||
.include <bsd.own.mk>
|
.include <bsd.own.mk>
|
||||||
|
|
||||||
ATF_TESTS_C= arc4random_test
|
ATF_TESTS_C+= arc4random_test
|
||||||
|
ATF_TESTS_C+= fmtcheck2_test
|
||||||
|
ATF_TESTS_C+= fmtmsg_test
|
||||||
|
ATF_TESTS_C+= fnmatch2_test
|
||||||
ATF_TESTS_C+= fpclassify2_test
|
ATF_TESTS_C+= fpclassify2_test
|
||||||
|
ATF_TESTS_C+= ftw_test
|
||||||
|
ATF_TESTS_C+= popen_test
|
||||||
|
ATF_TESTS_C+= posix_spawn_test
|
||||||
|
ATF_TESTS_C+= wordexp_test
|
||||||
|
|
||||||
# TODO: t_closefrom, t_cpuset, t_fmtcheck, t_randomid, t_sleep
|
# TODO: t_closefrom, t_cpuset, t_fmtcheck, t_randomid, t_sleep
|
||||||
# TODO: t_siginfo (fixes require further inspection)
|
# TODO: t_siginfo (fixes require further inspection)
|
||||||
@ -53,7 +60,25 @@ DPADD.nice_test+= ${LIBPTHREAD}
|
|||||||
LDADD.syslog_test+= -lpthread
|
LDADD.syslog_test+= -lpthread
|
||||||
DPADD.syslog_test+= ${LIBPTHREAD}
|
DPADD.syslog_test+= ${LIBPTHREAD}
|
||||||
|
|
||||||
|
CFLAGS+= -I${.CURDIR}
|
||||||
|
|
||||||
|
SRCS.fmtcheck2_test= fmtcheck_test.c
|
||||||
|
SRCS.fnmatch2_test= fnmatch_test.c
|
||||||
|
|
||||||
TESTS_SUBDIRS= execve
|
TESTS_SUBDIRS= execve
|
||||||
TESTS_SUBDIRS+= posix_spawn
|
TESTS_SUBDIRS+= posix_spawn
|
||||||
|
|
||||||
|
# The old testcase name
|
||||||
|
TEST_FNMATCH= test-fnmatch
|
||||||
|
CLEANFILES+= ${GEN_SH_CASE_TESTCASES}
|
||||||
|
sh-tests: .PHONY
|
||||||
|
.for target in clean obj depend all
|
||||||
|
@cd ${.CURDIR} && ${MAKE} PROG=${TEST_FNMATCH} \
|
||||||
|
-DNO_SUBDIR ${target}
|
||||||
|
.endfor
|
||||||
|
@cd ${.OBJDIR} && ./${TEST_FNMATCH} -s 1 > \
|
||||||
|
${SRCTOP}/bin/sh/tests/builtins/case2.0
|
||||||
|
@cd ${.OBJDIR} && ./${TEST_FNMATCH} -s 2 > \
|
||||||
|
${SRCTOP}/bin/sh/tests/builtins/case3.0
|
||||||
|
|
||||||
.include <bsd.test.mk>
|
.include <bsd.test.mk>
|
||||||
|
@ -31,10 +31,13 @@
|
|||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__FBSDID("$FreeBSD$");
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <atf-c.h>
|
||||||
|
|
||||||
struct test_fmt {
|
struct test_fmt {
|
||||||
char *fmt1;
|
char *fmt1;
|
||||||
char *fmt2;
|
char *fmt2;
|
||||||
@ -72,31 +75,31 @@ struct test_fmt {
|
|||||||
{ "%p %30s %#llx %-10.*e", "This number %lu%% and string %s has %qd numbers and %.*g floats", 1 },
|
{ "%p %30s %#llx %-10.*e", "This number %lu%% and string %s has %qd numbers and %.*g floats", 1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
ATF_TC_WITHOUT_HEAD(fmtcheck_test);
|
||||||
main(int argc, char *argv[])
|
ATF_TC_BODY(fmtcheck_test, tc)
|
||||||
{
|
{
|
||||||
int i, n, r;
|
int i;
|
||||||
const char *f, *cf, *f1, *f2;
|
const char *f, *cf, *f1, *f2;
|
||||||
|
|
||||||
printf("1..1\n");
|
for (i = 0; i < nitems(test_fmts); i++) {
|
||||||
r = 0;
|
|
||||||
n = sizeof(test_fmts) / sizeof(test_fmts[0]);
|
|
||||||
for (i=0 ; i<n ; i++) {
|
|
||||||
f1 = test_fmts[i].fmt1;
|
f1 = test_fmts[i].fmt1;
|
||||||
f2 = test_fmts[i].fmt2;
|
f2 = test_fmts[i].fmt2;
|
||||||
f = fmtcheck(f1, f2);
|
f = fmtcheck(f1, f2);
|
||||||
if (test_fmts[i].correct == 1) {
|
if (test_fmts[i].correct == 1)
|
||||||
cf = f1;
|
cf = f1;
|
||||||
} else {
|
else
|
||||||
cf = f2;
|
cf = f2;
|
||||||
}
|
ATF_CHECK_MSG(f == cf,
|
||||||
if (f != cf) {
|
"Test %d: (%s) vs. (%s) failed "
|
||||||
r++;
|
"(should have returned %s)", i + 1, f1, f2,
|
||||||
errx(1, "Test %d: (%s) vs. (%s) failed "
|
(test_fmts[i].correct == 1) ? "1st" : "2nd");
|
||||||
"(should have returned %s)", i, f1, f2,
|
|
||||||
(test_fmts[i].correct == 1) ? "1st" : "2nd");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
printf("ok 1\n");
|
}
|
||||||
exit(0);
|
|
||||||
|
ATF_TP_ADD_TCS(tp)
|
||||||
|
{
|
||||||
|
|
||||||
|
ATF_TP_ADD_TC(tp, fmtcheck_test);
|
||||||
|
|
||||||
|
return (atf_no_error());
|
||||||
}
|
}
|
@ -27,8 +27,8 @@
|
|||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__FBSDID("$FreeBSD$");
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fmtmsg.h>
|
#include <fmtmsg.h>
|
||||||
@ -37,6 +37,8 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <atf-c.h>
|
||||||
|
|
||||||
static char *run_test(long classification, const char *label, int severity,
|
static char *run_test(long classification, const char *label, int severity,
|
||||||
const char *text, const char *action, const char *tag);
|
const char *text, const char *action, const char *tag);
|
||||||
|
|
||||||
@ -217,18 +219,14 @@ run_test(long classification, const char *label, int severity,
|
|||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
ATF_TC_WITHOUT_HEAD(fmtmsg_test);
|
||||||
main(void)
|
ATF_TC_BODY(fmtmsg_test, tc)
|
||||||
{
|
{
|
||||||
size_t i, n;
|
|
||||||
int errors;
|
|
||||||
char *result;
|
char *result;
|
||||||
struct testcase *t;
|
struct testcase *t;
|
||||||
|
int i;
|
||||||
|
|
||||||
n = sizeof(testcases) / sizeof(testcases[0]);
|
for (i = 0; i < nitems(testcases); i++) {
|
||||||
errors = 0;
|
|
||||||
printf("1..%zu\n", n);
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
t = &testcases[i];
|
t = &testcases[i];
|
||||||
if (t->msgverb != NULL)
|
if (t->msgverb != NULL)
|
||||||
setenv("MSGVERB", t->msgverb, 1);
|
setenv("MSGVERB", t->msgverb, 1);
|
||||||
@ -236,16 +234,19 @@ main(void)
|
|||||||
unsetenv("MSGVERB");
|
unsetenv("MSGVERB");
|
||||||
result = run_test(t->classification, t->label, t->severity,
|
result = run_test(t->classification, t->label, t->severity,
|
||||||
t->text, t->action, t->tag);
|
t->text, t->action, t->tag);
|
||||||
if (result != NULL && strcmp(result, t->result) == 0)
|
ATF_CHECK_MSG(result != NULL, "testcase %d failed", i + 1);
|
||||||
printf("ok %zu - correct\n",
|
if (result != NULL)
|
||||||
i + 1);
|
ATF_CHECK_MSG(strcmp(result, t->result) == 0,
|
||||||
else {
|
"results for testcase %d didn't match; "
|
||||||
printf("not ok %zu - %s\n",
|
"`%s` != `%s`", i + 1, result, t->result);
|
||||||
i + 1, result != NULL ? "incorrect" : "failed");
|
|
||||||
errors = 1;
|
|
||||||
}
|
|
||||||
free(result);
|
free(result);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return (errors);
|
|
||||||
|
ATF_TP_ADD_TCS(tp)
|
||||||
|
{
|
||||||
|
|
||||||
|
ATF_TP_ADD_TC(tp, fmtmsg_test);
|
||||||
|
|
||||||
|
return (atf_no_error());
|
||||||
}
|
}
|
188
lib/libc/tests/gen/fnmatch_test.c
Normal file
188
lib/libc/tests/gen/fnmatch_test.c
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2010 Jilles Tjoelker
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <atf-c.h>
|
||||||
|
|
||||||
|
#include "fnmatch_testcases.h"
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
flags_to_string(int flags)
|
||||||
|
{
|
||||||
|
static const int flagvalues[] = { FNM_NOESCAPE, FNM_PATHNAME,
|
||||||
|
FNM_PERIOD, FNM_LEADING_DIR, FNM_CASEFOLD, 0 };
|
||||||
|
static const char flagnames[] = "FNM_NOESCAPE\0FNM_PATHNAME\0FNM_PERIOD\0FNM_LEADING_DIR\0FNM_CASEFOLD\0";
|
||||||
|
static char result[sizeof(flagnames) + 3 * sizeof(int) + 2];
|
||||||
|
char *p;
|
||||||
|
size_t i, len;
|
||||||
|
const char *fp;
|
||||||
|
|
||||||
|
p = result;
|
||||||
|
fp = flagnames;
|
||||||
|
for (i = 0; flagvalues[i] != 0; i++) {
|
||||||
|
len = strlen(fp);
|
||||||
|
if (flags & flagvalues[i]) {
|
||||||
|
if (p != result)
|
||||||
|
*p++ = '|';
|
||||||
|
memcpy(p, fp, len);
|
||||||
|
p += len;
|
||||||
|
flags &= ~flagvalues[i];
|
||||||
|
}
|
||||||
|
fp += len + 1;
|
||||||
|
}
|
||||||
|
if (p == result)
|
||||||
|
memcpy(p, "0", 2);
|
||||||
|
else if (flags != 0)
|
||||||
|
sprintf(p, "%d", flags);
|
||||||
|
else
|
||||||
|
*p = '\0';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(fnmatch_test);
|
||||||
|
ATF_TC_BODY(fnmatch_test, tc)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
int flags, result;
|
||||||
|
struct testcase *t;
|
||||||
|
|
||||||
|
for (i = 0; i < nitems(testcases); i++) {
|
||||||
|
t = &testcases[i];
|
||||||
|
flags = t->flags;
|
||||||
|
do {
|
||||||
|
result = fnmatch(t->pattern, t->string, flags);
|
||||||
|
if (result != t->result)
|
||||||
|
break;
|
||||||
|
if (strchr(t->pattern, '\\') == NULL &&
|
||||||
|
!(flags & FNM_NOESCAPE)) {
|
||||||
|
flags |= FNM_NOESCAPE;
|
||||||
|
result = fnmatch(t->pattern, t->string, flags);
|
||||||
|
if (result != t->result)
|
||||||
|
break;
|
||||||
|
flags = t->flags;
|
||||||
|
}
|
||||||
|
if (strchr(t->pattern, '\\') != NULL &&
|
||||||
|
strchr(t->string, '\\') == NULL &&
|
||||||
|
t->result == FNM_NOMATCH &&
|
||||||
|
!(flags & (FNM_NOESCAPE | FNM_LEADING_DIR))) {
|
||||||
|
flags |= FNM_NOESCAPE;
|
||||||
|
result = fnmatch(t->pattern, t->string, flags);
|
||||||
|
if (result != t->result)
|
||||||
|
break;
|
||||||
|
flags = t->flags;
|
||||||
|
}
|
||||||
|
if ((t->string[0] != '.' || t->pattern[0] == '.' ||
|
||||||
|
t->result == FNM_NOMATCH) &&
|
||||||
|
!(flags & (FNM_PATHNAME | FNM_PERIOD))) {
|
||||||
|
flags |= FNM_PERIOD;
|
||||||
|
result = fnmatch(t->pattern, t->string, flags);
|
||||||
|
if (result != t->result)
|
||||||
|
break;
|
||||||
|
flags = t->flags;
|
||||||
|
}
|
||||||
|
if ((strchr(t->string, '/') == NULL ||
|
||||||
|
t->result == FNM_NOMATCH) &&
|
||||||
|
!(flags & FNM_PATHNAME)) {
|
||||||
|
flags |= FNM_PATHNAME;
|
||||||
|
result = fnmatch(t->pattern, t->string, flags);
|
||||||
|
if (result != t->result)
|
||||||
|
break;
|
||||||
|
flags = t->flags;
|
||||||
|
}
|
||||||
|
if ((((t->string[0] != '.' || t->pattern[0] == '.') &&
|
||||||
|
strstr(t->string, "/.") == NULL) ||
|
||||||
|
t->result == FNM_NOMATCH) &&
|
||||||
|
flags & FNM_PATHNAME && !(flags & FNM_PERIOD)) {
|
||||||
|
flags |= FNM_PERIOD;
|
||||||
|
result = fnmatch(t->pattern, t->string, flags);
|
||||||
|
if (result != t->result)
|
||||||
|
break;
|
||||||
|
flags = t->flags;
|
||||||
|
}
|
||||||
|
if ((((t->string[0] != '.' || t->pattern[0] == '.') &&
|
||||||
|
strchr(t->string, '/') == NULL) ||
|
||||||
|
t->result == FNM_NOMATCH) &&
|
||||||
|
!(flags & (FNM_PATHNAME | FNM_PERIOD))) {
|
||||||
|
flags |= FNM_PATHNAME | FNM_PERIOD;
|
||||||
|
result = fnmatch(t->pattern, t->string, flags);
|
||||||
|
if (result != t->result)
|
||||||
|
break;
|
||||||
|
flags = t->flags;
|
||||||
|
}
|
||||||
|
if ((strchr(t->string, '/') == NULL || t->result == 0)
|
||||||
|
&& !(flags & FNM_LEADING_DIR)) {
|
||||||
|
flags |= FNM_LEADING_DIR;
|
||||||
|
result = fnmatch(t->pattern, t->string, flags);
|
||||||
|
if (result != t->result)
|
||||||
|
break;
|
||||||
|
flags = t->flags;
|
||||||
|
}
|
||||||
|
if (t->result == 0 && !(flags & FNM_CASEFOLD)) {
|
||||||
|
flags |= FNM_CASEFOLD;
|
||||||
|
result = fnmatch(t->pattern, t->string, flags);
|
||||||
|
if (result != t->result)
|
||||||
|
break;
|
||||||
|
flags = t->flags;
|
||||||
|
}
|
||||||
|
if (strchr(t->pattern, '\\') == NULL &&
|
||||||
|
t->result == 0 &&
|
||||||
|
!(flags & (FNM_NOESCAPE | FNM_CASEFOLD))) {
|
||||||
|
flags |= FNM_NOESCAPE | FNM_CASEFOLD;
|
||||||
|
result = fnmatch(t->pattern, t->string, flags);
|
||||||
|
if (result != t->result)
|
||||||
|
break;
|
||||||
|
flags = t->flags;
|
||||||
|
}
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
ATF_CHECK(result == t->result);
|
||||||
|
if (result == t->result)
|
||||||
|
printf("fnmatch(\"%s\", \"%s\", %s) == %d\n",
|
||||||
|
t->pattern, t->string, flags_to_string(flags), result);
|
||||||
|
else
|
||||||
|
printf("fnmatch(\"%s\", \"%s\", %s) != %d (was %d)\n",
|
||||||
|
t->pattern, t->string, flags_to_string(flags),
|
||||||
|
t->result, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TP_ADD_TCS(tp)
|
||||||
|
{
|
||||||
|
|
||||||
|
ATF_TP_ADD_TC(tp, fnmatch_test);
|
||||||
|
|
||||||
|
return (atf_no_error());
|
||||||
|
}
|
176
lib/libc/tests/gen/fnmatch_testcases.h
Normal file
176
lib/libc/tests/gen/fnmatch_testcases.h
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2010 Jilles Tjoelker
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <fnmatch.h>
|
||||||
|
|
||||||
|
struct testcase {
|
||||||
|
const char *pattern;
|
||||||
|
const char *string;
|
||||||
|
int flags;
|
||||||
|
int result;
|
||||||
|
} testcases[] = {
|
||||||
|
"", "", 0, 0,
|
||||||
|
"a", "a", 0, 0,
|
||||||
|
"a", "b", 0, FNM_NOMATCH,
|
||||||
|
"a", "A", 0, FNM_NOMATCH,
|
||||||
|
"*", "a", 0, 0,
|
||||||
|
"*", "aa", 0, 0,
|
||||||
|
"*a", "a", 0, 0,
|
||||||
|
"*a", "b", 0, FNM_NOMATCH,
|
||||||
|
"*a*", "b", 0, FNM_NOMATCH,
|
||||||
|
"*a*b*", "ab", 0, 0,
|
||||||
|
"*a*b*", "qaqbq", 0, 0,
|
||||||
|
"*a*bb*", "qaqbqbbq", 0, 0,
|
||||||
|
"*a*bc*", "qaqbqbcq", 0, 0,
|
||||||
|
"*a*bb*", "qaqbqbb", 0, 0,
|
||||||
|
"*a*bc*", "qaqbqbc", 0, 0,
|
||||||
|
"*a*bb", "qaqbqbb", 0, 0,
|
||||||
|
"*a*bc", "qaqbqbc", 0, 0,
|
||||||
|
"*a*bb", "qaqbqbbq", 0, FNM_NOMATCH,
|
||||||
|
"*a*bc", "qaqbqbcq", 0, FNM_NOMATCH,
|
||||||
|
"*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaa", 0, FNM_NOMATCH,
|
||||||
|
"*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaa", 0, 0,
|
||||||
|
"*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaaa", 0, 0,
|
||||||
|
".*.*.*.*.*.*.*.*.*.*", ".........", 0, FNM_NOMATCH,
|
||||||
|
".*.*.*.*.*.*.*.*.*.*", "..........", 0, 0,
|
||||||
|
".*.*.*.*.*.*.*.*.*.*", "...........", 0, 0,
|
||||||
|
"*?*?*?*?*?*?*?*?*?*?*", "123456789", 0, FNM_NOMATCH,
|
||||||
|
"??????????*", "123456789", 0, FNM_NOMATCH,
|
||||||
|
"*??????????", "123456789", 0, FNM_NOMATCH,
|
||||||
|
"*?*?*?*?*?*?*?*?*?*?*", "1234567890", 0, 0,
|
||||||
|
"??????????*", "1234567890", 0, 0,
|
||||||
|
"*??????????", "1234567890", 0, 0,
|
||||||
|
"*?*?*?*?*?*?*?*?*?*?*", "12345678901", 0, 0,
|
||||||
|
"??????????*", "12345678901", 0, 0,
|
||||||
|
"*??????????", "12345678901", 0, 0,
|
||||||
|
"[x]", "x", 0, 0,
|
||||||
|
"[*]", "*", 0, 0,
|
||||||
|
"[?]", "?", 0, 0,
|
||||||
|
"[", "[", 0, 0,
|
||||||
|
"[[]", "[", 0, 0,
|
||||||
|
"[[]", "x", 0, FNM_NOMATCH,
|
||||||
|
"[*]", "", 0, FNM_NOMATCH,
|
||||||
|
"[*]", "x", 0, FNM_NOMATCH,
|
||||||
|
"[?]", "x", 0, FNM_NOMATCH,
|
||||||
|
"*[*]*", "foo*foo", 0, 0,
|
||||||
|
"*[*]*", "foo", 0, FNM_NOMATCH,
|
||||||
|
"[0-9]", "0", 0, 0,
|
||||||
|
"[0-9]", "5", 0, 0,
|
||||||
|
"[0-9]", "9", 0, 0,
|
||||||
|
"[0-9]", "/", 0, FNM_NOMATCH,
|
||||||
|
"[0-9]", ":", 0, FNM_NOMATCH,
|
||||||
|
"[0-9]", "*", 0, FNM_NOMATCH,
|
||||||
|
"[!0-9]", "0", 0, FNM_NOMATCH,
|
||||||
|
"[!0-9]", "5", 0, FNM_NOMATCH,
|
||||||
|
"[!0-9]", "9", 0, FNM_NOMATCH,
|
||||||
|
"[!0-9]", "/", 0, 0,
|
||||||
|
"[!0-9]", ":", 0, 0,
|
||||||
|
"[!0-9]", "*", 0, 0,
|
||||||
|
"*[0-9]", "a0", 0, 0,
|
||||||
|
"*[0-9]", "a5", 0, 0,
|
||||||
|
"*[0-9]", "a9", 0, 0,
|
||||||
|
"*[0-9]", "a/", 0, FNM_NOMATCH,
|
||||||
|
"*[0-9]", "a:", 0, FNM_NOMATCH,
|
||||||
|
"*[0-9]", "a*", 0, FNM_NOMATCH,
|
||||||
|
"*[!0-9]", "a0", 0, FNM_NOMATCH,
|
||||||
|
"*[!0-9]", "a5", 0, FNM_NOMATCH,
|
||||||
|
"*[!0-9]", "a9", 0, FNM_NOMATCH,
|
||||||
|
"*[!0-9]", "a/", 0, 0,
|
||||||
|
"*[!0-9]", "a:", 0, 0,
|
||||||
|
"*[!0-9]", "a*", 0, 0,
|
||||||
|
"*[0-9]", "a00", 0, 0,
|
||||||
|
"*[0-9]", "a55", 0, 0,
|
||||||
|
"*[0-9]", "a99", 0, 0,
|
||||||
|
"*[0-9]", "a0a0", 0, 0,
|
||||||
|
"*[0-9]", "a5a5", 0, 0,
|
||||||
|
"*[0-9]", "a9a9", 0, 0,
|
||||||
|
"\\*", "*", 0, 0,
|
||||||
|
"\\?", "?", 0, 0,
|
||||||
|
"\\[x]", "[x]", 0, 0,
|
||||||
|
"\\[", "[", 0, 0,
|
||||||
|
"\\\\", "\\", 0, 0,
|
||||||
|
"*\\**", "foo*foo", 0, 0,
|
||||||
|
"*\\**", "foo", 0, FNM_NOMATCH,
|
||||||
|
"*\\\\*", "foo\\foo", 0, 0,
|
||||||
|
"*\\\\*", "foo", 0, FNM_NOMATCH,
|
||||||
|
"\\(", "(", 0, 0,
|
||||||
|
"\\a", "a", 0, 0,
|
||||||
|
"\\*", "a", 0, FNM_NOMATCH,
|
||||||
|
"\\?", "a", 0, FNM_NOMATCH,
|
||||||
|
"\\*", "\\*", 0, FNM_NOMATCH,
|
||||||
|
"\\?", "\\?", 0, FNM_NOMATCH,
|
||||||
|
"\\[x]", "\\[x]", 0, FNM_NOMATCH,
|
||||||
|
"\\[x]", "\\x", 0, FNM_NOMATCH,
|
||||||
|
"\\[", "\\[", 0, FNM_NOMATCH,
|
||||||
|
"\\(", "\\(", 0, FNM_NOMATCH,
|
||||||
|
"\\a", "\\a", 0, FNM_NOMATCH,
|
||||||
|
"\\", "\\", 0, FNM_NOMATCH,
|
||||||
|
"\\", "", 0, 0,
|
||||||
|
"\\*", "\\*", FNM_NOESCAPE, 0,
|
||||||
|
"\\?", "\\?", FNM_NOESCAPE, 0,
|
||||||
|
"\\", "\\", FNM_NOESCAPE, 0,
|
||||||
|
"\\\\", "\\", FNM_NOESCAPE, FNM_NOMATCH,
|
||||||
|
"\\\\", "\\\\", FNM_NOESCAPE, 0,
|
||||||
|
"*\\*", "foo\\foo", FNM_NOESCAPE, 0,
|
||||||
|
"*\\*", "foo", FNM_NOESCAPE, FNM_NOMATCH,
|
||||||
|
"*", ".", FNM_PERIOD, FNM_NOMATCH,
|
||||||
|
"?", ".", FNM_PERIOD, FNM_NOMATCH,
|
||||||
|
".*", ".", 0, 0,
|
||||||
|
".*", "..", 0, 0,
|
||||||
|
".*", ".a", 0, 0,
|
||||||
|
"[0-9]", ".", FNM_PERIOD, FNM_NOMATCH,
|
||||||
|
"a*", "a.", 0, 0,
|
||||||
|
"a/a", "a/a", FNM_PATHNAME, 0,
|
||||||
|
"a/*", "a/a", FNM_PATHNAME, 0,
|
||||||
|
"*/a", "a/a", FNM_PATHNAME, 0,
|
||||||
|
"*/*", "a/a", FNM_PATHNAME, 0,
|
||||||
|
"a*b/*", "abbb/x", FNM_PATHNAME, 0,
|
||||||
|
"a*b/*", "abbb/.x", FNM_PATHNAME, 0,
|
||||||
|
"*", "a/a", FNM_PATHNAME, FNM_NOMATCH,
|
||||||
|
"*/*", "a/a/a", FNM_PATHNAME, FNM_NOMATCH,
|
||||||
|
"b/*", "b/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH,
|
||||||
|
"b*/*", "a/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH,
|
||||||
|
"b/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0,
|
||||||
|
"b*/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0,
|
||||||
|
"a", "A", FNM_CASEFOLD, 0,
|
||||||
|
"A", "a", FNM_CASEFOLD, 0,
|
||||||
|
"[a]", "A", FNM_CASEFOLD, 0,
|
||||||
|
"[A]", "a", FNM_CASEFOLD, 0,
|
||||||
|
"a", "b", FNM_CASEFOLD, FNM_NOMATCH,
|
||||||
|
"a", "a/b", FNM_PATHNAME, FNM_NOMATCH,
|
||||||
|
"*", "a/b", FNM_PATHNAME, FNM_NOMATCH,
|
||||||
|
"*b", "a/b", FNM_PATHNAME, FNM_NOMATCH,
|
||||||
|
"a", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
|
||||||
|
"*", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
|
||||||
|
"*", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
|
||||||
|
"*a", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
|
||||||
|
"*", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH,
|
||||||
|
"*a", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH,
|
||||||
|
"a*b/*", "abbb/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH,
|
||||||
|
};
|
@ -32,50 +32,26 @@
|
|||||||
__FBSDID("$FreeBSD$");
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <ftw.h>
|
#include <ftw.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <spawn.h>
|
#include <spawn.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <atf-c.h>
|
||||||
|
|
||||||
extern char **environ;
|
extern char **environ;
|
||||||
|
|
||||||
static char dir[] = "/tmp/testftw.XXXXXXXXXX";
|
static char template[] = "testftw.XXXXXXXXXX";
|
||||||
|
static char dir[PATH_MAX];
|
||||||
static int failures;
|
static int failures;
|
||||||
static int ftwflags;
|
static int ftwflags;
|
||||||
|
|
||||||
static void
|
|
||||||
cleanup(int ustatus __unused)
|
|
||||||
{
|
|
||||||
int error, status;
|
|
||||||
pid_t pid, waitres;
|
|
||||||
const char *myargs[5];
|
|
||||||
|
|
||||||
err_set_exit(NULL);
|
|
||||||
myargs[0] = "rm";
|
|
||||||
myargs[1] = "-rf";
|
|
||||||
myargs[2] = "--";
|
|
||||||
myargs[3] = dir;
|
|
||||||
myargs[4] = NULL;
|
|
||||||
error = posix_spawnp(&pid, myargs[0], NULL, NULL,
|
|
||||||
__DECONST(char **, myargs), environ);
|
|
||||||
if (error != 0)
|
|
||||||
warn("posix_spawnp rm");
|
|
||||||
else {
|
|
||||||
waitres = waitpid(pid, &status, 0);
|
|
||||||
if (waitres != pid)
|
|
||||||
warnx("waitpid rm failed");
|
|
||||||
else if (status != 0)
|
|
||||||
warnx("rm failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cb(const char *path, const struct stat *st, int type, struct FTW *f)
|
cb(const char *path, const struct stat *st, int type, struct FTW *f)
|
||||||
{
|
{
|
||||||
@ -94,50 +70,59 @@ cb(const char *path, const struct stat *st, int type, struct FTW *f)
|
|||||||
return (0);
|
return (0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
warnx("unexpected path=%s type=%d f.level=%d\n",
|
ATF_CHECK_MSG(false,
|
||||||
|
"unexpected path=%s type=%d f.level=%d\n",
|
||||||
path, type, f->level);
|
path, type, f->level);
|
||||||
failures++;
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
ATF_TC_WITHOUT_HEAD(ftw_test);
|
||||||
main(int argc, char *argv[])
|
ATF_TC_BODY(ftw_test, tc)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
if (!mkdtemp(dir))
|
ATF_REQUIRE_MSG(mkdtemp(template) != NULL, "mkdtemp failed");
|
||||||
err(2, "mkdtemp");
|
|
||||||
|
|
||||||
err_set_exit(cleanup);
|
/* XXX: the path needs to be absolute for the 0/FTW_DEPTH testcases */
|
||||||
|
ATF_REQUIRE_MSG(realpath(template, dir) != NULL,
|
||||||
|
"realpath failed; errno=%d", errno);
|
||||||
|
|
||||||
fd = open(dir, O_DIRECTORY | O_RDONLY);
|
fd = open(dir, O_DIRECTORY|O_RDONLY);
|
||||||
if (fd == -1)
|
ATF_REQUIRE_MSG(fd != -1, "open failed; errno=%d", errno);
|
||||||
err(2, "open %s", dir);
|
|
||||||
|
|
||||||
if (mkdirat(fd, "d1", 0777) == -1)
|
ATF_REQUIRE_MSG(mkdirat(fd, "d1", 0777) == 0,
|
||||||
err(2, "mkdirat d1");
|
"mkdirat failed; errno=%d", errno);
|
||||||
|
|
||||||
if (symlinkat(dir, fd, "d1/looper") == -1)
|
ATF_REQUIRE_MSG(symlinkat(dir, fd, "d1/looper") == 0,
|
||||||
err(2, "symlinkat looper");
|
"symlinkat failed; errno=%d", errno);
|
||||||
|
|
||||||
|
printf("ftwflags=FTW_PHYS\n");
|
||||||
ftwflags = FTW_PHYS;
|
ftwflags = FTW_PHYS;
|
||||||
if (nftw(dir, cb, 10, ftwflags) == -1)
|
ATF_REQUIRE_MSG(nftw(dir, cb, 10, ftwflags) != -1,
|
||||||
err(2, "nftw FTW_PHYS");
|
"nftw FTW_PHYS failed; errno=%d", errno);
|
||||||
ftwflags = FTW_PHYS | FTW_DEPTH;
|
|
||||||
if (nftw(dir, cb, 10, ftwflags) == -1)
|
printf("ftwflags=FTW_PHYS|FTW_DEPTH\n");
|
||||||
err(2, "nftw FTW_PHYS | FTW_DEPTH");
|
ftwflags = FTW_PHYS|FTW_DEPTH;
|
||||||
|
ATF_REQUIRE_MSG(nftw(dir, cb, 10, ftwflags) != -1,
|
||||||
|
"nftw FTW_PHYS|FTW_DEPTH failed; errno=%d", errno);
|
||||||
|
|
||||||
|
printf("ftwflags=0\n");
|
||||||
ftwflags = 0;
|
ftwflags = 0;
|
||||||
if (nftw(dir, cb, 10, ftwflags) == -1)
|
ATF_REQUIRE_MSG(nftw(dir, cb, 10, ftwflags) != -1,
|
||||||
err(2, "nftw 0");
|
"nftw 0 failed; errno=%d", errno);
|
||||||
|
|
||||||
|
printf("ftwflags=FTW_DEPTH\n");
|
||||||
ftwflags = FTW_DEPTH;
|
ftwflags = FTW_DEPTH;
|
||||||
if (nftw(dir, cb, 10, ftwflags) == -1)
|
ATF_REQUIRE_MSG(nftw(dir, cb, 10, ftwflags) != -1,
|
||||||
err(2, "nftw FTW_DEPTH");
|
"nftw FTW_DEPTH failed; errno=%d", errno);
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
}
|
||||||
printf("PASS nftw()\n");
|
|
||||||
|
ATF_TP_ADD_TCS(tp)
|
||||||
cleanup(failures != 0);
|
{
|
||||||
|
|
||||||
return (failures != 0);
|
ATF_TP_ADD_TC(tp, ftw_test);
|
||||||
|
|
||||||
|
return (atf_no_error());
|
||||||
}
|
}
|
251
lib/libc/tests/gen/popen_test.c
Normal file
251
lib/libc/tests/gen/popen_test.c
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2013 Jilles Tjoelker
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Limited test program for popen() as specified by IEEE Std. 1003.1-2008,
|
||||||
|
* with BSD extensions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <atf-c.h>
|
||||||
|
|
||||||
|
static volatile sig_atomic_t got_sigpipe;
|
||||||
|
|
||||||
|
static void
|
||||||
|
sigpipe_handler(int sig __unused)
|
||||||
|
{
|
||||||
|
got_sigpipe = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_cloexec(FILE *fp, const char *mode)
|
||||||
|
{
|
||||||
|
int exp_flags, flags;
|
||||||
|
|
||||||
|
flags = fcntl(fileno(fp), F_GETFD);
|
||||||
|
ATF_CHECK_MSG(flags != -1, "fcntl(F_GETFD) failed; errno=%d", errno);
|
||||||
|
if (flags == -1)
|
||||||
|
return;
|
||||||
|
if (strchr(mode, 'e') != NULL)
|
||||||
|
exp_flags = FD_CLOEXEC;
|
||||||
|
else
|
||||||
|
exp_flags = 0;
|
||||||
|
ATF_CHECK_MSG((flags & FD_CLOEXEC) == exp_flags,
|
||||||
|
"bad cloexec flag; %d != %d", flags, exp_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(popen_all_modes_test);
|
||||||
|
ATF_TC_BODY(popen_all_modes_test, tc)
|
||||||
|
{
|
||||||
|
FILE *fp, *fp2;
|
||||||
|
int i, status;
|
||||||
|
const char *mode;
|
||||||
|
const char *allmodes[] = { "r", "w", "r+", "re", "we", "r+e", "re+" };
|
||||||
|
|
||||||
|
for (i = 0; i < nitems(allmodes); i++) {
|
||||||
|
mode = allmodes[i];
|
||||||
|
fp = popen("exit 7", mode);
|
||||||
|
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
|
||||||
|
if (fp == NULL)
|
||||||
|
continue;
|
||||||
|
check_cloexec(fp, mode);
|
||||||
|
status = pclose(fp);
|
||||||
|
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 7,
|
||||||
|
"bad exit status (no I/O)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(popen_rmodes_test);
|
||||||
|
ATF_TC_BODY(popen_rmodes_test, tc)
|
||||||
|
{
|
||||||
|
FILE *fp, *fp2;
|
||||||
|
const char *rmodes[] = { "r", "r+", "re", "r+e", "re+" };
|
||||||
|
const char *mode;
|
||||||
|
char buf[80];
|
||||||
|
int i, status;
|
||||||
|
|
||||||
|
for (i = 0; i < nitems(rmodes); i++) {
|
||||||
|
mode = rmodes[i];
|
||||||
|
fp = popen("exit 9", mode);
|
||||||
|
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
|
||||||
|
if (fp == NULL)
|
||||||
|
continue;
|
||||||
|
check_cloexec(fp, mode);
|
||||||
|
bool input_error_1 = !(fgetc(fp) != EOF || !feof(fp) || !ferror(fp));
|
||||||
|
ATF_CHECK_MSG(!input_error_1, "input error 1");
|
||||||
|
if (input_error_1)
|
||||||
|
continue;
|
||||||
|
status = pclose(fp);
|
||||||
|
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 9,
|
||||||
|
"bad exit status (input)");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nitems(rmodes); i++) {
|
||||||
|
char *sres;
|
||||||
|
mode = rmodes[i];
|
||||||
|
fp = popen("echo hi there", mode);
|
||||||
|
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
|
||||||
|
if (fp == NULL)
|
||||||
|
continue;
|
||||||
|
check_cloexec(fp, mode);
|
||||||
|
ATF_CHECK_MSG((sres = fgets(buf, sizeof(buf), fp)) != NULL,
|
||||||
|
"Input error 2");
|
||||||
|
if (sres != NULL)
|
||||||
|
ATF_CHECK_MSG(strcmp(buf, "hi there\n") == 0,
|
||||||
|
"Bad input 1");
|
||||||
|
status = pclose(fp);
|
||||||
|
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0,
|
||||||
|
"Bad exit status (input)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(popen_wmodes_test);
|
||||||
|
ATF_TC_BODY(popen_wmodes_test, tc)
|
||||||
|
{
|
||||||
|
FILE *fp, *fp2;
|
||||||
|
const char *wmodes[] = { "w", "r+", "we", "r+e", "re+" };
|
||||||
|
const char *mode;
|
||||||
|
struct sigaction act, oact;
|
||||||
|
int i, j, status;
|
||||||
|
|
||||||
|
for (i = 0; i < nitems(wmodes); i++) {
|
||||||
|
mode = wmodes[i];
|
||||||
|
fp = popen("read x && [ \"$x\" = abcd ]", mode);
|
||||||
|
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
|
||||||
|
if (fp == NULL)
|
||||||
|
continue;
|
||||||
|
check_cloexec(fp, mode);
|
||||||
|
ATF_CHECK_MSG(fputs("abcd\n", fp) != EOF,
|
||||||
|
"Output error 1");
|
||||||
|
status = pclose(fp);
|
||||||
|
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0,
|
||||||
|
"Bad exit status (output)");
|
||||||
|
}
|
||||||
|
|
||||||
|
act.sa_handler = sigpipe_handler;
|
||||||
|
act.sa_flags = SA_RESTART;
|
||||||
|
sigemptyset(&act.sa_mask);
|
||||||
|
ATF_CHECK_MSG(sigaction(SIGPIPE, &act, &oact) != -1,
|
||||||
|
"sigaction() failed");
|
||||||
|
for (i = 0; i < nitems(wmodes); i++) {
|
||||||
|
mode = wmodes[i];
|
||||||
|
fp = popen("exit 88", mode);
|
||||||
|
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
|
||||||
|
if (fp == NULL)
|
||||||
|
continue;
|
||||||
|
check_cloexec(fp, mode);
|
||||||
|
got_sigpipe = 0;
|
||||||
|
while (fputs("abcd\n", fp) != EOF)
|
||||||
|
;
|
||||||
|
ATF_CHECK_MSG(ferror(fp) && errno == EPIPE, "Expected EPIPE");
|
||||||
|
ATF_CHECK_MSG(got_sigpipe, "Expected SIGPIPE");
|
||||||
|
status = pclose(fp);
|
||||||
|
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 88,
|
||||||
|
"Bad exit status (EPIPE)");
|
||||||
|
}
|
||||||
|
ATF_CHECK_MSG(sigaction(SIGPIPE, &oact, NULL) != -1,
|
||||||
|
"sigaction() failed");
|
||||||
|
|
||||||
|
for (i = 0; i < nitems(wmodes); i++) {
|
||||||
|
for (j = 0; j < nitems(wmodes); j++) {
|
||||||
|
mode = wmodes[i];
|
||||||
|
fp = popen("read x", mode);
|
||||||
|
ATF_CHECK_MSG(fp != NULL,
|
||||||
|
"popen(, \"%s\") failed", mode);
|
||||||
|
if (fp == NULL)
|
||||||
|
continue;
|
||||||
|
mode = wmodes[j];
|
||||||
|
fp2 = popen("read x", mode);
|
||||||
|
ATF_CHECK_MSG(fp2 != NULL,
|
||||||
|
"popen(, \"%s\") failed", mode);
|
||||||
|
if (fp2 == NULL) {
|
||||||
|
pclose(fp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* If fp2 inherits fp's pipe, we will deadlock here. */
|
||||||
|
status = pclose(fp);
|
||||||
|
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 1,
|
||||||
|
"bad exit status (2 pipes)");
|
||||||
|
status = pclose(fp2);
|
||||||
|
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 1,
|
||||||
|
"bad exit status (2 pipes)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(popen_rwmodes_test);
|
||||||
|
ATF_TC_BODY(popen_rwmodes_test, tc)
|
||||||
|
{
|
||||||
|
const char *rwmodes[] = { "r+", "r+e", "re+" };
|
||||||
|
FILE *fp, *fp2;
|
||||||
|
const char *mode;
|
||||||
|
char *sres;
|
||||||
|
char buf[80];
|
||||||
|
int i, ires, status;
|
||||||
|
|
||||||
|
for (i = 0; i < nitems(rwmodes); i++) {
|
||||||
|
mode = rwmodes[i];
|
||||||
|
fp = popen("read x && printf '%s\\n' \"Q${x#a}\"", mode);
|
||||||
|
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
|
||||||
|
if (fp == NULL)
|
||||||
|
continue;
|
||||||
|
check_cloexec(fp, mode);
|
||||||
|
ATF_CHECK_MSG((ires = fputs("abcd\n", fp)) != EOF,
|
||||||
|
"Output error 2");
|
||||||
|
if (ires != EOF) {
|
||||||
|
sres = fgets(buf, sizeof(buf), fp);
|
||||||
|
ATF_CHECK_MSG(sres != NULL, "Input error 3");
|
||||||
|
if (sres != NULL)
|
||||||
|
ATF_CHECK_MSG(strcmp(buf, "Qbcd\n") == 0,
|
||||||
|
"Bad input 2");
|
||||||
|
}
|
||||||
|
status = pclose(fp);
|
||||||
|
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0,
|
||||||
|
"bad exit status (I/O)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TP_ADD_TCS(tp)
|
||||||
|
{
|
||||||
|
|
||||||
|
ATF_TP_ADD_TC(tp, popen_all_modes_test);
|
||||||
|
ATF_TP_ADD_TC(tp, popen_rmodes_test);
|
||||||
|
ATF_TP_ADD_TC(tp, popen_wmodes_test);
|
||||||
|
ATF_TP_ADD_TC(tp, popen_rwmodes_test);
|
||||||
|
|
||||||
|
return (atf_no_error());
|
||||||
|
}
|
@ -33,26 +33,27 @@
|
|||||||
__FBSDID("$FreeBSD$");
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <spawn.h>
|
#include <spawn.h>
|
||||||
|
|
||||||
int
|
#include <atf-c.h>
|
||||||
main(int argc, char *argv[])
|
|
||||||
|
char *myenv[2] = { "answer=42", NULL };
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(posix_spawn_simple_test);
|
||||||
|
ATF_TC_BODY(posix_spawn_simple_test, tc)
|
||||||
{
|
{
|
||||||
|
char *myargs[4];
|
||||||
int error, status;
|
int error, status;
|
||||||
pid_t pid, waitres;
|
pid_t pid, waitres;
|
||||||
char *myargs[4];
|
|
||||||
char *myenv[2] = { "answer=42", NULL };
|
|
||||||
|
|
||||||
/* Make sure we have no child processes. */
|
/* Make sure we have no child processes. */
|
||||||
while (waitpid(-1, NULL, 0) != -1)
|
while (waitpid(-1, NULL, 0) != -1)
|
||||||
;
|
;
|
||||||
assert(errno == ECHILD);
|
ATF_REQUIRE_MSG(errno == ECHILD, "errno was not ECHILD: %d", errno);
|
||||||
|
|
||||||
/* Simple test. */
|
/* Simple test. */
|
||||||
myargs[0] = "sh";
|
myargs[0] = "sh";
|
||||||
@ -60,10 +61,18 @@ main(int argc, char *argv[])
|
|||||||
myargs[2] = "exit $answer";
|
myargs[2] = "exit $answer";
|
||||||
myargs[3] = NULL;
|
myargs[3] = NULL;
|
||||||
error = posix_spawnp(&pid, myargs[0], NULL, NULL, myargs, myenv);
|
error = posix_spawnp(&pid, myargs[0], NULL, NULL, myargs, myenv);
|
||||||
assert(error == 0);
|
ATF_REQUIRE(error == 0);
|
||||||
waitres = waitpid(pid, &status, 0);
|
waitres = waitpid(pid, &status, 0);
|
||||||
assert(waitres == pid);
|
ATF_REQUIRE(waitres == pid);
|
||||||
assert(WIFEXITED(status) && WEXITSTATUS(status) == 42);
|
ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(posix_spawn_no_such_command_negative_test);
|
||||||
|
ATF_TC_BODY(posix_spawn_no_such_command_negative_test, tc)
|
||||||
|
{
|
||||||
|
char *myargs[4];
|
||||||
|
int error, status;
|
||||||
|
pid_t pid, waitres;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the executable does not exist, the function shall either fail
|
* If the executable does not exist, the function shall either fail
|
||||||
@ -75,16 +84,20 @@ main(int argc, char *argv[])
|
|||||||
error = posix_spawn(&pid, myargs[0], NULL, NULL, myargs, myenv);
|
error = posix_spawn(&pid, myargs[0], NULL, NULL, myargs, myenv);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
waitres = waitpid(pid, &status, 0);
|
waitres = waitpid(pid, &status, 0);
|
||||||
assert(waitres == pid);
|
ATF_REQUIRE(waitres == pid);
|
||||||
assert(WIFEXITED(status) && WEXITSTATUS(status) == 127);
|
ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 127);
|
||||||
} else {
|
} else {
|
||||||
assert(error == ENOENT);
|
ATF_REQUIRE(error == ENOENT);
|
||||||
waitres = waitpid(-1, NULL, 0);
|
waitres = waitpid(-1, NULL, 0);
|
||||||
assert(waitres == -1 && errno == ECHILD);
|
ATF_REQUIRE(waitres == -1 && errno == ECHILD);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
printf("PASS posix_spawn()\n");
|
|
||||||
printf("PASS posix_spawnp()\n");
|
ATF_TP_ADD_TCS(tp)
|
||||||
|
{
|
||||||
return (0);
|
|
||||||
|
ATF_TP_ADD_TC(tp, posix_spawn_simple_test);
|
||||||
|
ATF_TP_ADD_TC(tp, posix_spawn_no_such_command_negative_test);
|
||||||
|
|
||||||
|
return (atf_no_error());
|
||||||
}
|
}
|
77
lib/libc/tests/gen/test-fnmatch.c
Normal file
77
lib/libc/tests/gen/test-fnmatch.c
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "fnmatch_testcases.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
write_sh_tests(const char *progname, int num)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
struct testcase *t;
|
||||||
|
|
||||||
|
printf("# Generated by %s -s %d, do not edit.\n", progname, num);
|
||||||
|
printf("# $" "FreeBSD$\n");
|
||||||
|
printf("failures=\n");
|
||||||
|
printf("failed() { printf '%%s\\n' \"Failed: $1 '$2' '$3'\"; failures=x$failures; }\n");
|
||||||
|
if (num == 1) {
|
||||||
|
printf("testmatch() { eval \"case \\$2 in ''$1) ;; *) failed testmatch \\\"\\$@\\\";; esac\"; }\n");
|
||||||
|
printf("testnomatch() { eval \"case \\$2 in ''$1) failed testnomatch \\\"\\$@\\\";; esac\"; }\n");
|
||||||
|
} else if (num == 2) {
|
||||||
|
printf("# We do not treat a backslash specially in this case,\n");
|
||||||
|
printf("# but this is not the case in all shells.\n");
|
||||||
|
printf("netestmatch() { case $2 in $1) ;; *) failed netestmatch \"$@\";; esac; }\n");
|
||||||
|
printf("netestnomatch() { case $2 in $1) failed netestnomatch \"$@\";; esac; }\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nitems(testcases); i++) {
|
||||||
|
t = &testcases[i];
|
||||||
|
if (strchr(t->pattern, '\'') != NULL ||
|
||||||
|
strchr(t->string, '\'') != NULL)
|
||||||
|
continue;
|
||||||
|
if (t->flags == 0 && strcmp(t->pattern, "\\") == 0)
|
||||||
|
continue;
|
||||||
|
if (num == 1 && t->flags == 0)
|
||||||
|
printf("test%smatch '%s' '%s'\n",
|
||||||
|
t->result == FNM_NOMATCH ? "no" : "",
|
||||||
|
t->pattern, t->string);
|
||||||
|
if (num == 2 && (t->flags == FNM_NOESCAPE ||
|
||||||
|
(t->flags == 0 && strchr(t->pattern, '\\') == NULL)))
|
||||||
|
printf("netest%smatch '%s' '%s'\n",
|
||||||
|
t->result == FNM_NOMATCH ? "no" : "",
|
||||||
|
t->pattern, t->string);
|
||||||
|
}
|
||||||
|
printf("[ -z \"$failures\" ]\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(char *progname)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "usage: %s [-s num]\n", progname);
|
||||||
|
fprintf(stderr, "-s option writes tests for sh(1), num is 1 or 2\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int opt;
|
||||||
|
|
||||||
|
while ((opt = getopt(argc, argv, "s:")) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 's':
|
||||||
|
return (write_sh_tests(argv[0], atoi(optarg)));
|
||||||
|
default:
|
||||||
|
usage(argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usage(argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
360
lib/libc/tests/gen/wordexp_test.c
Normal file
360
lib/libc/tests/gen/wordexp_test.c
Normal file
@ -0,0 +1,360 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2003 Tim J. Robbins
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test program for wordexp() and wordfree() as specified by
|
||||||
|
* IEEE Std. 1003.1-2001.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <wordexp.h>
|
||||||
|
|
||||||
|
#include <atf-c.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
chld_handler(int x)
|
||||||
|
{
|
||||||
|
int status, serrno;
|
||||||
|
|
||||||
|
(void)x;
|
||||||
|
serrno = errno;
|
||||||
|
while (waitpid(-1, &status, WNOHANG) > 0)
|
||||||
|
;
|
||||||
|
errno = serrno;
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(simple_test);
|
||||||
|
ATF_TC_BODY(simple_test, tc)
|
||||||
|
{
|
||||||
|
wordexp_t we;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* Test that the macros are there. */
|
||||||
|
(void)(WRDE_APPEND + WRDE_DOOFFS + WRDE_NOCMD + WRDE_REUSE +
|
||||||
|
WRDE_SHOWERR + WRDE_UNDEF);
|
||||||
|
(void)(WRDE_BADCHAR + WRDE_BADVAL + WRDE_CMDSUB + WRDE_NOSPACE +
|
||||||
|
WRDE_SYNTAX);
|
||||||
|
|
||||||
|
/* Simple test. */
|
||||||
|
r = wordexp("hello world", &we, 0);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordc == 2);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordv[2] == NULL);
|
||||||
|
wordfree(&we);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(long_output_test);
|
||||||
|
ATF_TC_BODY(long_output_test, tc)
|
||||||
|
{
|
||||||
|
char longdata[6 * 10000 + 1];
|
||||||
|
wordexp_t we;
|
||||||
|
int i, r;
|
||||||
|
|
||||||
|
/* Long output. */
|
||||||
|
for (i = 0; i < 10000; i++)
|
||||||
|
snprintf(longdata + 6 * i, 7, "%05d ", i);
|
||||||
|
r = wordexp(longdata, &we, 0);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordc == 10000);
|
||||||
|
ATF_REQUIRE(we.we_wordv[10000] == NULL);
|
||||||
|
wordfree(&we);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(WRDE_DOOFFS_test);
|
||||||
|
ATF_TC_BODY(WRDE_DOOFFS_test, tc)
|
||||||
|
{
|
||||||
|
wordexp_t we;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
we.we_offs = 3;
|
||||||
|
r = wordexp("hello world", &we, WRDE_DOOFFS);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordc == 2);
|
||||||
|
ATF_REQUIRE(we.we_wordv[0] == NULL);
|
||||||
|
ATF_REQUIRE(we.we_wordv[1] == NULL);
|
||||||
|
ATF_REQUIRE(we.we_wordv[2] == NULL);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[3], "hello") == 0);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[4], "world") == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordv[5] == NULL);
|
||||||
|
wordfree(&we);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(WRDE_REUSE_test);
|
||||||
|
ATF_TC_BODY(WRDE_REUSE_test, tc)
|
||||||
|
{
|
||||||
|
wordexp_t we;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = wordexp("hello world", &we, 0);
|
||||||
|
r = wordexp("hello world", &we, WRDE_REUSE);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordc == 2);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordv[2] == NULL);
|
||||||
|
wordfree(&we);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(WRDE_APPEND_test);
|
||||||
|
ATF_TC_BODY(WRDE_APPEND_test, tc)
|
||||||
|
{
|
||||||
|
wordexp_t we;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = wordexp("this is", &we, 0);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
r = wordexp("a test", &we, WRDE_APPEND);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordc == 4);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[0], "this") == 0);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[1], "is") == 0);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[2], "a") == 0);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[3], "test") == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordv[4] == NULL);
|
||||||
|
wordfree(&we);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(WRDE_DOOFFS__WRDE_APPEND_test);
|
||||||
|
ATF_TC_BODY(WRDE_DOOFFS__WRDE_APPEND_test, tc)
|
||||||
|
{
|
||||||
|
wordexp_t we;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
we.we_offs = 2;
|
||||||
|
r = wordexp("this is", &we, WRDE_DOOFFS);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
r = wordexp("a test", &we, WRDE_APPEND|WRDE_DOOFFS);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
r = wordexp("of wordexp", &we, WRDE_APPEND|WRDE_DOOFFS);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordc == 6);
|
||||||
|
ATF_REQUIRE(we.we_wordv[0] == NULL);
|
||||||
|
ATF_REQUIRE(we.we_wordv[1] == NULL);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[2], "this") == 0);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[3], "is") == 0);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[4], "a") == 0);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[5], "test") == 0);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[6], "of") == 0);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[7], "wordexp") == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordv[8] == NULL);
|
||||||
|
wordfree(&we);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(WRDE_UNDEF_test);
|
||||||
|
ATF_TC_BODY(WRDE_UNDEF_test, tc)
|
||||||
|
{
|
||||||
|
wordexp_t we;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = wordexp("${dont_set_me}", &we, WRDE_UNDEF);
|
||||||
|
ATF_REQUIRE(r == WRDE_BADVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(WRDE_NOCMD_test);
|
||||||
|
ATF_TC_BODY(WRDE_NOCMD_test, tc)
|
||||||
|
{
|
||||||
|
wordexp_t we;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = wordexp("`date`", &we, WRDE_NOCMD);
|
||||||
|
ATF_REQUIRE(r == WRDE_CMDSUB);
|
||||||
|
r = wordexp("\"`date`\"", &we, WRDE_NOCMD);
|
||||||
|
ATF_REQUIRE(r == WRDE_CMDSUB);
|
||||||
|
r = wordexp("$(date)", &we, WRDE_NOCMD);
|
||||||
|
ATF_REQUIRE(r == WRDE_CMDSUB);
|
||||||
|
r = wordexp("\"$(date)\"", &we, WRDE_NOCMD);
|
||||||
|
ATF_REQUIRE(r == WRDE_CMDSUB);
|
||||||
|
r = wordexp("$((3+5))", &we, WRDE_NOCMD);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
r = wordexp("\\$\\(date\\)", &we, WRDE_NOCMD|WRDE_REUSE);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
r = wordexp("'`date`'", &we, WRDE_NOCMD|WRDE_REUSE);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
r = wordexp("'$(date)'", &we, WRDE_NOCMD|WRDE_REUSE);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
wordfree(&we);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(WRDE_BADCHAR_test);
|
||||||
|
ATF_TC_BODY(WRDE_BADCHAR_test, tc)
|
||||||
|
{
|
||||||
|
wordexp_t we;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = wordexp("'\n|&;<>(){}'", &we, 0);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
r = wordexp("\"\n|&;<>(){}\"", &we, WRDE_REUSE);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
r = wordexp("\\\n\\|\\&\\;\\<\\>\\(\\)\\{\\}", &we, WRDE_REUSE);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
wordfree(&we);
|
||||||
|
r = wordexp("test \n test", &we, 0);
|
||||||
|
ATF_REQUIRE(r == WRDE_BADCHAR);
|
||||||
|
r = wordexp("test | test", &we, 0);
|
||||||
|
ATF_REQUIRE(r == WRDE_BADCHAR);
|
||||||
|
r = wordexp("test & test", &we, 0);
|
||||||
|
ATF_REQUIRE(r == WRDE_BADCHAR);
|
||||||
|
r = wordexp("test ; test", &we, 0);
|
||||||
|
ATF_REQUIRE(r == WRDE_BADCHAR);
|
||||||
|
r = wordexp("test > test", &we, 0);
|
||||||
|
ATF_REQUIRE(r == WRDE_BADCHAR);
|
||||||
|
r = wordexp("test < test", &we, 0);
|
||||||
|
ATF_REQUIRE(r == WRDE_BADCHAR);
|
||||||
|
r = wordexp("test ( test", &we, 0);
|
||||||
|
ATF_REQUIRE(r == WRDE_BADCHAR);
|
||||||
|
r = wordexp("test ) test", &we, 0);
|
||||||
|
ATF_REQUIRE(r == WRDE_BADCHAR);
|
||||||
|
r = wordexp("test { test", &we, 0);
|
||||||
|
ATF_REQUIRE(r == WRDE_BADCHAR);
|
||||||
|
r = wordexp("test } test", &we, 0);
|
||||||
|
ATF_REQUIRE(r == WRDE_BADCHAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(WRDE_SYNTAX_test);
|
||||||
|
ATF_TC_BODY(WRDE_SYNTAX_test, tc)
|
||||||
|
{
|
||||||
|
wordexp_t we;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = wordexp("'", &we, 0);
|
||||||
|
ATF_REQUIRE(r == WRDE_SYNTAX);
|
||||||
|
r = wordexp("'", &we, WRDE_UNDEF);
|
||||||
|
ATF_REQUIRE(r == WRDE_SYNTAX);
|
||||||
|
r = wordexp("'\\'", &we, 0);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordc == 1);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[0], "\\") == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordv[1] == NULL);
|
||||||
|
wordfree(&we);
|
||||||
|
/* Two syntax errors that are not detected by the current we_check(). */
|
||||||
|
r = wordexp("${IFS:+'}", &we, 0);
|
||||||
|
ATF_REQUIRE(r == WRDE_SYNTAX);
|
||||||
|
r = wordexp("${IFS:+'}", &we, WRDE_UNDEF);
|
||||||
|
ATF_REQUIRE(r == WRDE_SYNTAX);
|
||||||
|
r = wordexp("$(case)", &we, 0);
|
||||||
|
ATF_REQUIRE(r == WRDE_SYNTAX);
|
||||||
|
r = wordexp("$(case)", &we, WRDE_UNDEF);
|
||||||
|
ATF_REQUIRE(r == WRDE_SYNTAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(with_SIGCHILD_handler_test);
|
||||||
|
ATF_TC_BODY(with_SIGCHILD_handler_test, tc)
|
||||||
|
{
|
||||||
|
struct sigaction sa;
|
||||||
|
wordexp_t we;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* With a SIGCHLD handler that reaps all zombies. */
|
||||||
|
sa.sa_flags = 0;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_handler = chld_handler;
|
||||||
|
r = sigaction(SIGCHLD, &sa, NULL);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
r = wordexp("hello world", &we, 0);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordc == 2);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordv[2] == NULL);
|
||||||
|
wordfree(&we);
|
||||||
|
sa.sa_handler = SIG_DFL;
|
||||||
|
r = sigaction(SIGCHLD, &sa, NULL);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(with_unused_non_default_IFS_test);
|
||||||
|
ATF_TC_BODY(with_unused_non_default_IFS_test, tc)
|
||||||
|
{
|
||||||
|
wordexp_t we;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With IFS set to a non-default value (without depending on whether
|
||||||
|
* IFS is inherited or not).
|
||||||
|
*/
|
||||||
|
r = setenv("IFS", ":", 1);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
r = wordexp("hello world", &we, 0);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordc == 2);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordv[2] == NULL);
|
||||||
|
wordfree(&we);
|
||||||
|
r = unsetenv("IFS");
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(with_used_non_default_IFS_test);
|
||||||
|
ATF_TC_BODY(with_used_non_default_IFS_test, tc)
|
||||||
|
{
|
||||||
|
wordexp_t we;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With IFS set to a non-default value, and using it.
|
||||||
|
*/
|
||||||
|
r = setenv("IFS", ":", 1);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
r = wordexp("${IFS+hello:world}", &we, 0);
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordc == 2);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
|
||||||
|
ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
|
||||||
|
ATF_REQUIRE(we.we_wordv[2] == NULL);
|
||||||
|
wordfree(&we);
|
||||||
|
r = unsetenv("IFS");
|
||||||
|
ATF_REQUIRE(r == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TP_ADD_TCS(tp)
|
||||||
|
{
|
||||||
|
ATF_TP_ADD_TC(tp, simple_test);
|
||||||
|
ATF_TP_ADD_TC(tp, long_output_test);
|
||||||
|
ATF_TP_ADD_TC(tp, WRDE_DOOFFS_test);
|
||||||
|
ATF_TP_ADD_TC(tp, WRDE_REUSE_test);
|
||||||
|
ATF_TP_ADD_TC(tp, WRDE_APPEND_test);
|
||||||
|
ATF_TP_ADD_TC(tp, WRDE_DOOFFS__WRDE_APPEND_test);
|
||||||
|
ATF_TP_ADD_TC(tp, WRDE_UNDEF_test);
|
||||||
|
ATF_TP_ADD_TC(tp, WRDE_NOCMD_test);
|
||||||
|
ATF_TP_ADD_TC(tp, WRDE_BADCHAR_test);
|
||||||
|
ATF_TP_ADD_TC(tp, WRDE_SYNTAX_test);
|
||||||
|
ATF_TP_ADD_TC(tp, with_SIGCHILD_handler_test);
|
||||||
|
ATF_TP_ADD_TC(tp, with_unused_non_default_IFS_test);
|
||||||
|
ATF_TP_ADD_TC(tp, with_used_non_default_IFS_test);
|
||||||
|
|
||||||
|
return (atf_no_error());
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
# $FreeBSD$
|
|
||||||
|
|
||||||
TESTS= test-fmtcheck test-fmtmsg test-fnmatch \
|
|
||||||
test-ftw test-popen test-posix_spawn test-wordexp
|
|
||||||
|
|
||||||
.PHONY: tests
|
|
||||||
tests: ${TESTS}
|
|
||||||
for p in ${TESTS}; do ${.OBJDIR}/$$p; done
|
|
||||||
|
|
||||||
.PHONY: clean
|
|
||||||
clean:
|
|
||||||
-rm -f ${TESTS}
|
|
||||||
|
|
||||||
sh-tests: test-fnmatch
|
|
||||||
./test-fnmatch -s 1 >../../../bin/sh/builtins/case2.0
|
|
||||||
./test-fnmatch -s 2 >../../../bin/sh/builtins/case3.0
|
|
@ -1,390 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright (c) 2010 Jilles Tjoelker
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
|
||||||
__FBSDID("$FreeBSD$");
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fnmatch.h>
|
|
||||||
|
|
||||||
struct testcase {
|
|
||||||
const char *pattern;
|
|
||||||
const char *string;
|
|
||||||
int flags;
|
|
||||||
int result;
|
|
||||||
} testcases[] = {
|
|
||||||
"", "", 0, 0,
|
|
||||||
"a", "a", 0, 0,
|
|
||||||
"a", "b", 0, FNM_NOMATCH,
|
|
||||||
"a", "A", 0, FNM_NOMATCH,
|
|
||||||
"*", "a", 0, 0,
|
|
||||||
"*", "aa", 0, 0,
|
|
||||||
"*a", "a", 0, 0,
|
|
||||||
"*a", "b", 0, FNM_NOMATCH,
|
|
||||||
"*a*", "b", 0, FNM_NOMATCH,
|
|
||||||
"*a*b*", "ab", 0, 0,
|
|
||||||
"*a*b*", "qaqbq", 0, 0,
|
|
||||||
"*a*bb*", "qaqbqbbq", 0, 0,
|
|
||||||
"*a*bc*", "qaqbqbcq", 0, 0,
|
|
||||||
"*a*bb*", "qaqbqbb", 0, 0,
|
|
||||||
"*a*bc*", "qaqbqbc", 0, 0,
|
|
||||||
"*a*bb", "qaqbqbb", 0, 0,
|
|
||||||
"*a*bc", "qaqbqbc", 0, 0,
|
|
||||||
"*a*bb", "qaqbqbbq", 0, FNM_NOMATCH,
|
|
||||||
"*a*bc", "qaqbqbcq", 0, FNM_NOMATCH,
|
|
||||||
"*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaa", 0, FNM_NOMATCH,
|
|
||||||
"*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaa", 0, 0,
|
|
||||||
"*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaaa", 0, 0,
|
|
||||||
".*.*.*.*.*.*.*.*.*.*", ".........", 0, FNM_NOMATCH,
|
|
||||||
".*.*.*.*.*.*.*.*.*.*", "..........", 0, 0,
|
|
||||||
".*.*.*.*.*.*.*.*.*.*", "...........", 0, 0,
|
|
||||||
"*?*?*?*?*?*?*?*?*?*?*", "123456789", 0, FNM_NOMATCH,
|
|
||||||
"??????????*", "123456789", 0, FNM_NOMATCH,
|
|
||||||
"*??????????", "123456789", 0, FNM_NOMATCH,
|
|
||||||
"*?*?*?*?*?*?*?*?*?*?*", "1234567890", 0, 0,
|
|
||||||
"??????????*", "1234567890", 0, 0,
|
|
||||||
"*??????????", "1234567890", 0, 0,
|
|
||||||
"*?*?*?*?*?*?*?*?*?*?*", "12345678901", 0, 0,
|
|
||||||
"??????????*", "12345678901", 0, 0,
|
|
||||||
"*??????????", "12345678901", 0, 0,
|
|
||||||
"[x]", "x", 0, 0,
|
|
||||||
"[*]", "*", 0, 0,
|
|
||||||
"[?]", "?", 0, 0,
|
|
||||||
"[", "[", 0, 0,
|
|
||||||
"[[]", "[", 0, 0,
|
|
||||||
"[[]", "x", 0, FNM_NOMATCH,
|
|
||||||
"[*]", "", 0, FNM_NOMATCH,
|
|
||||||
"[*]", "x", 0, FNM_NOMATCH,
|
|
||||||
"[?]", "x", 0, FNM_NOMATCH,
|
|
||||||
"*[*]*", "foo*foo", 0, 0,
|
|
||||||
"*[*]*", "foo", 0, FNM_NOMATCH,
|
|
||||||
"[0-9]", "0", 0, 0,
|
|
||||||
"[0-9]", "5", 0, 0,
|
|
||||||
"[0-9]", "9", 0, 0,
|
|
||||||
"[0-9]", "/", 0, FNM_NOMATCH,
|
|
||||||
"[0-9]", ":", 0, FNM_NOMATCH,
|
|
||||||
"[0-9]", "*", 0, FNM_NOMATCH,
|
|
||||||
"[!0-9]", "0", 0, FNM_NOMATCH,
|
|
||||||
"[!0-9]", "5", 0, FNM_NOMATCH,
|
|
||||||
"[!0-9]", "9", 0, FNM_NOMATCH,
|
|
||||||
"[!0-9]", "/", 0, 0,
|
|
||||||
"[!0-9]", ":", 0, 0,
|
|
||||||
"[!0-9]", "*", 0, 0,
|
|
||||||
"*[0-9]", "a0", 0, 0,
|
|
||||||
"*[0-9]", "a5", 0, 0,
|
|
||||||
"*[0-9]", "a9", 0, 0,
|
|
||||||
"*[0-9]", "a/", 0, FNM_NOMATCH,
|
|
||||||
"*[0-9]", "a:", 0, FNM_NOMATCH,
|
|
||||||
"*[0-9]", "a*", 0, FNM_NOMATCH,
|
|
||||||
"*[!0-9]", "a0", 0, FNM_NOMATCH,
|
|
||||||
"*[!0-9]", "a5", 0, FNM_NOMATCH,
|
|
||||||
"*[!0-9]", "a9", 0, FNM_NOMATCH,
|
|
||||||
"*[!0-9]", "a/", 0, 0,
|
|
||||||
"*[!0-9]", "a:", 0, 0,
|
|
||||||
"*[!0-9]", "a*", 0, 0,
|
|
||||||
"*[0-9]", "a00", 0, 0,
|
|
||||||
"*[0-9]", "a55", 0, 0,
|
|
||||||
"*[0-9]", "a99", 0, 0,
|
|
||||||
"*[0-9]", "a0a0", 0, 0,
|
|
||||||
"*[0-9]", "a5a5", 0, 0,
|
|
||||||
"*[0-9]", "a9a9", 0, 0,
|
|
||||||
"\\*", "*", 0, 0,
|
|
||||||
"\\?", "?", 0, 0,
|
|
||||||
"\\[x]", "[x]", 0, 0,
|
|
||||||
"\\[", "[", 0, 0,
|
|
||||||
"\\\\", "\\", 0, 0,
|
|
||||||
"*\\**", "foo*foo", 0, 0,
|
|
||||||
"*\\**", "foo", 0, FNM_NOMATCH,
|
|
||||||
"*\\\\*", "foo\\foo", 0, 0,
|
|
||||||
"*\\\\*", "foo", 0, FNM_NOMATCH,
|
|
||||||
"\\(", "(", 0, 0,
|
|
||||||
"\\a", "a", 0, 0,
|
|
||||||
"\\*", "a", 0, FNM_NOMATCH,
|
|
||||||
"\\?", "a", 0, FNM_NOMATCH,
|
|
||||||
"\\*", "\\*", 0, FNM_NOMATCH,
|
|
||||||
"\\?", "\\?", 0, FNM_NOMATCH,
|
|
||||||
"\\[x]", "\\[x]", 0, FNM_NOMATCH,
|
|
||||||
"\\[x]", "\\x", 0, FNM_NOMATCH,
|
|
||||||
"\\[", "\\[", 0, FNM_NOMATCH,
|
|
||||||
"\\(", "\\(", 0, FNM_NOMATCH,
|
|
||||||
"\\a", "\\a", 0, FNM_NOMATCH,
|
|
||||||
"\\", "\\", 0, FNM_NOMATCH,
|
|
||||||
"\\", "", 0, 0,
|
|
||||||
"\\*", "\\*", FNM_NOESCAPE, 0,
|
|
||||||
"\\?", "\\?", FNM_NOESCAPE, 0,
|
|
||||||
"\\", "\\", FNM_NOESCAPE, 0,
|
|
||||||
"\\\\", "\\", FNM_NOESCAPE, FNM_NOMATCH,
|
|
||||||
"\\\\", "\\\\", FNM_NOESCAPE, 0,
|
|
||||||
"*\\*", "foo\\foo", FNM_NOESCAPE, 0,
|
|
||||||
"*\\*", "foo", FNM_NOESCAPE, FNM_NOMATCH,
|
|
||||||
"*", ".", FNM_PERIOD, FNM_NOMATCH,
|
|
||||||
"?", ".", FNM_PERIOD, FNM_NOMATCH,
|
|
||||||
".*", ".", 0, 0,
|
|
||||||
".*", "..", 0, 0,
|
|
||||||
".*", ".a", 0, 0,
|
|
||||||
"[0-9]", ".", FNM_PERIOD, FNM_NOMATCH,
|
|
||||||
"a*", "a.", 0, 0,
|
|
||||||
"a/a", "a/a", FNM_PATHNAME, 0,
|
|
||||||
"a/*", "a/a", FNM_PATHNAME, 0,
|
|
||||||
"*/a", "a/a", FNM_PATHNAME, 0,
|
|
||||||
"*/*", "a/a", FNM_PATHNAME, 0,
|
|
||||||
"a*b/*", "abbb/x", FNM_PATHNAME, 0,
|
|
||||||
"a*b/*", "abbb/.x", FNM_PATHNAME, 0,
|
|
||||||
"*", "a/a", FNM_PATHNAME, FNM_NOMATCH,
|
|
||||||
"*/*", "a/a/a", FNM_PATHNAME, FNM_NOMATCH,
|
|
||||||
"b/*", "b/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH,
|
|
||||||
"b*/*", "a/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH,
|
|
||||||
"b/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0,
|
|
||||||
"b*/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0,
|
|
||||||
"a", "A", FNM_CASEFOLD, 0,
|
|
||||||
"A", "a", FNM_CASEFOLD, 0,
|
|
||||||
"[a]", "A", FNM_CASEFOLD, 0,
|
|
||||||
"[A]", "a", FNM_CASEFOLD, 0,
|
|
||||||
"a", "b", FNM_CASEFOLD, FNM_NOMATCH,
|
|
||||||
"a", "a/b", FNM_PATHNAME, FNM_NOMATCH,
|
|
||||||
"*", "a/b", FNM_PATHNAME, FNM_NOMATCH,
|
|
||||||
"*b", "a/b", FNM_PATHNAME, FNM_NOMATCH,
|
|
||||||
"a", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
|
|
||||||
"*", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
|
|
||||||
"*", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
|
|
||||||
"*a", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
|
|
||||||
"*", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH,
|
|
||||||
"*a", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH,
|
|
||||||
"a*b/*", "abbb/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
flags_to_string(int flags)
|
|
||||||
{
|
|
||||||
static const int flagvalues[] = { FNM_NOESCAPE, FNM_PATHNAME,
|
|
||||||
FNM_PERIOD, FNM_LEADING_DIR, FNM_CASEFOLD, 0 };
|
|
||||||
static const char flagnames[] = "FNM_NOESCAPE\0FNM_PATHNAME\0FNM_PERIOD\0FNM_LEADING_DIR\0FNM_CASEFOLD\0";
|
|
||||||
static char result[sizeof(flagnames) + 3 * sizeof(int) + 2];
|
|
||||||
char *p;
|
|
||||||
size_t i, len;
|
|
||||||
const char *fp;
|
|
||||||
|
|
||||||
p = result;
|
|
||||||
fp = flagnames;
|
|
||||||
for (i = 0; flagvalues[i] != 0; i++) {
|
|
||||||
len = strlen(fp);
|
|
||||||
if (flags & flagvalues[i]) {
|
|
||||||
if (p != result)
|
|
||||||
*p++ = '|';
|
|
||||||
memcpy(p, fp, len);
|
|
||||||
p += len;
|
|
||||||
flags &= ~flagvalues[i];
|
|
||||||
}
|
|
||||||
fp += len + 1;
|
|
||||||
}
|
|
||||||
if (p == result)
|
|
||||||
memcpy(p, "0", 2);
|
|
||||||
else if (flags != 0)
|
|
||||||
sprintf(p, "%d", flags);
|
|
||||||
else
|
|
||||||
*p = '\0';
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
write_sh_tests(const char *progname, int num)
|
|
||||||
{
|
|
||||||
size_t i, n;
|
|
||||||
struct testcase *t;
|
|
||||||
|
|
||||||
printf("# Generated by %s -s %d, do not edit.\n", progname, num);
|
|
||||||
printf("# $" "FreeBSD$\n");
|
|
||||||
printf("failures=\n");
|
|
||||||
printf("failed() { printf '%%s\\n' \"Failed: $1 '$2' '$3'\"; failures=x$failures; }\n");
|
|
||||||
if (num == 1) {
|
|
||||||
printf("testmatch() { eval \"case \\$2 in ''$1) ;; *) failed testmatch \\\"\\$@\\\";; esac\"; }\n");
|
|
||||||
printf("testnomatch() { eval \"case \\$2 in ''$1) failed testnomatch \\\"\\$@\\\";; esac\"; }\n");
|
|
||||||
} else if (num == 2) {
|
|
||||||
printf("# We do not treat a backslash specially in this case,\n");
|
|
||||||
printf("# but this is not the case in all shells.\n");
|
|
||||||
printf("netestmatch() { case $2 in $1) ;; *) failed netestmatch \"$@\";; esac; }\n");
|
|
||||||
printf("netestnomatch() { case $2 in $1) failed netestnomatch \"$@\";; esac; }\n");
|
|
||||||
}
|
|
||||||
n = sizeof(testcases) / sizeof(testcases[0]);
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
t = &testcases[i];
|
|
||||||
if (strchr(t->pattern, '\'') != NULL ||
|
|
||||||
strchr(t->string, '\'') != NULL)
|
|
||||||
continue;
|
|
||||||
if (t->flags == 0 && strcmp(t->pattern, "\\") == 0)
|
|
||||||
continue;
|
|
||||||
if (num == 1 && t->flags == 0)
|
|
||||||
printf("test%smatch '%s' '%s'\n",
|
|
||||||
t->result == FNM_NOMATCH ? "no" : "",
|
|
||||||
t->pattern, t->string);
|
|
||||||
if (num == 2 && (t->flags == FNM_NOESCAPE ||
|
|
||||||
(t->flags == 0 && strchr(t->pattern, '\\') == NULL)))
|
|
||||||
printf("netest%smatch '%s' '%s'\n",
|
|
||||||
t->result == FNM_NOMATCH ? "no" : "",
|
|
||||||
t->pattern, t->string);
|
|
||||||
}
|
|
||||||
printf("[ -z \"$failures\" ]\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
size_t i, n;
|
|
||||||
int opt, flags, result, extra, errors;
|
|
||||||
struct testcase *t;
|
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "s:")) != -1) {
|
|
||||||
switch (opt) {
|
|
||||||
case 's':
|
|
||||||
return (write_sh_tests(argv[0], atoi(optarg)));
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "usage: %s [-s num]\n", argv[0]);
|
|
||||||
fprintf(stderr, "-s option writes tests for sh(1), num is 1 or 2\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n = sizeof(testcases) / sizeof(testcases[0]);
|
|
||||||
errors = 0;
|
|
||||||
printf("1..%zu\n", n);
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
t = &testcases[i];
|
|
||||||
flags = t->flags;
|
|
||||||
extra = 0;
|
|
||||||
do {
|
|
||||||
result = fnmatch(t->pattern, t->string, flags);
|
|
||||||
if (result != t->result)
|
|
||||||
break;
|
|
||||||
if (strchr(t->pattern, '\\') == NULL &&
|
|
||||||
!(flags & FNM_NOESCAPE)) {
|
|
||||||
flags |= FNM_NOESCAPE;
|
|
||||||
result = fnmatch(t->pattern, t->string, flags);
|
|
||||||
if (result != t->result)
|
|
||||||
break;
|
|
||||||
flags = t->flags;
|
|
||||||
extra++;
|
|
||||||
}
|
|
||||||
if (strchr(t->pattern, '\\') != NULL &&
|
|
||||||
strchr(t->string, '\\') == NULL &&
|
|
||||||
t->result == FNM_NOMATCH &&
|
|
||||||
!(flags & (FNM_NOESCAPE | FNM_LEADING_DIR))) {
|
|
||||||
flags |= FNM_NOESCAPE;
|
|
||||||
result = fnmatch(t->pattern, t->string, flags);
|
|
||||||
if (result != t->result)
|
|
||||||
break;
|
|
||||||
flags = t->flags;
|
|
||||||
extra++;
|
|
||||||
}
|
|
||||||
if ((t->string[0] != '.' || t->pattern[0] == '.' ||
|
|
||||||
t->result == FNM_NOMATCH) &&
|
|
||||||
!(flags & (FNM_PATHNAME | FNM_PERIOD))) {
|
|
||||||
flags |= FNM_PERIOD;
|
|
||||||
result = fnmatch(t->pattern, t->string, flags);
|
|
||||||
if (result != t->result)
|
|
||||||
break;
|
|
||||||
flags = t->flags;
|
|
||||||
extra++;
|
|
||||||
}
|
|
||||||
if ((strchr(t->string, '/') == NULL ||
|
|
||||||
t->result == FNM_NOMATCH) &&
|
|
||||||
!(flags & FNM_PATHNAME)) {
|
|
||||||
flags |= FNM_PATHNAME;
|
|
||||||
result = fnmatch(t->pattern, t->string, flags);
|
|
||||||
if (result != t->result)
|
|
||||||
break;
|
|
||||||
flags = t->flags;
|
|
||||||
extra++;
|
|
||||||
}
|
|
||||||
if ((((t->string[0] != '.' || t->pattern[0] == '.') &&
|
|
||||||
strstr(t->string, "/.") == NULL) ||
|
|
||||||
t->result == FNM_NOMATCH) &&
|
|
||||||
flags & FNM_PATHNAME && !(flags & FNM_PERIOD)) {
|
|
||||||
flags |= FNM_PERIOD;
|
|
||||||
result = fnmatch(t->pattern, t->string, flags);
|
|
||||||
if (result != t->result)
|
|
||||||
break;
|
|
||||||
flags = t->flags;
|
|
||||||
extra++;
|
|
||||||
}
|
|
||||||
if ((((t->string[0] != '.' || t->pattern[0] == '.') &&
|
|
||||||
strchr(t->string, '/') == NULL) ||
|
|
||||||
t->result == FNM_NOMATCH) &&
|
|
||||||
!(flags & (FNM_PATHNAME | FNM_PERIOD))) {
|
|
||||||
flags |= FNM_PATHNAME | FNM_PERIOD;
|
|
||||||
result = fnmatch(t->pattern, t->string, flags);
|
|
||||||
if (result != t->result)
|
|
||||||
break;
|
|
||||||
flags = t->flags;
|
|
||||||
extra++;
|
|
||||||
}
|
|
||||||
if ((strchr(t->string, '/') == NULL || t->result == 0)
|
|
||||||
&& !(flags & FNM_LEADING_DIR)) {
|
|
||||||
flags |= FNM_LEADING_DIR;
|
|
||||||
result = fnmatch(t->pattern, t->string, flags);
|
|
||||||
if (result != t->result)
|
|
||||||
break;
|
|
||||||
flags = t->flags;
|
|
||||||
extra++;
|
|
||||||
}
|
|
||||||
if (t->result == 0 && !(flags & FNM_CASEFOLD)) {
|
|
||||||
flags |= FNM_CASEFOLD;
|
|
||||||
result = fnmatch(t->pattern, t->string, flags);
|
|
||||||
if (result != t->result)
|
|
||||||
break;
|
|
||||||
flags = t->flags;
|
|
||||||
extra++;
|
|
||||||
}
|
|
||||||
if (strchr(t->pattern, '\\') == NULL &&
|
|
||||||
t->result == 0 &&
|
|
||||||
!(flags & (FNM_NOESCAPE | FNM_CASEFOLD))) {
|
|
||||||
flags |= FNM_NOESCAPE | FNM_CASEFOLD;
|
|
||||||
result = fnmatch(t->pattern, t->string, flags);
|
|
||||||
if (result != t->result)
|
|
||||||
break;
|
|
||||||
flags = t->flags;
|
|
||||||
extra++;
|
|
||||||
}
|
|
||||||
} while (0);
|
|
||||||
if (result == t->result)
|
|
||||||
printf("ok %zu - fnmatch(\"%s\", \"%s\", %s) = %d (+%d)\n",
|
|
||||||
i + 1, t->pattern, t->string,
|
|
||||||
flags_to_string(flags),
|
|
||||||
result, extra);
|
|
||||||
else {
|
|
||||||
printf("not ok %zu - fnmatch(\"%s\", \"%s\", %s) = %d != %d\n",
|
|
||||||
i + 1, t->pattern, t->string,
|
|
||||||
flags_to_string(flags),
|
|
||||||
result, t->result);
|
|
||||||
errors = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (errors);
|
|
||||||
}
|
|
@ -1,227 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright (c) 2013 Jilles Tjoelker
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Limited test program for popen() as specified by IEEE Std. 1003.1-2008,
|
|
||||||
* with BSD extensions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
|
||||||
__FBSDID("$FreeBSD$");
|
|
||||||
|
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
static int failures;
|
|
||||||
static volatile sig_atomic_t got_sigpipe;
|
|
||||||
|
|
||||||
static void
|
|
||||||
sigpipe_handler(int sig __unused)
|
|
||||||
{
|
|
||||||
got_sigpipe = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
check_cloexec(FILE *fp, const char *mode)
|
|
||||||
{
|
|
||||||
int flags;
|
|
||||||
|
|
||||||
flags = fcntl(fileno(fp), F_GETFD);
|
|
||||||
if (flags == -1)
|
|
||||||
fprintf(stderr, "fcntl(F_GETFD) failed\n"), failures++;
|
|
||||||
else if ((flags & FD_CLOEXEC) !=
|
|
||||||
(strchr(mode, 'e') != NULL ? FD_CLOEXEC : 0))
|
|
||||||
fprintf(stderr, "Bad cloexec flag\n"), failures++;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
FILE *fp, *fp2;
|
|
||||||
int i, j, status;
|
|
||||||
const char *mode;
|
|
||||||
const char *allmodes[] = { "r", "w", "r+", "re", "we", "r+e", "re+" };
|
|
||||||
const char *rmodes[] = { "r", "r+", "re", "r+e", "re+" };
|
|
||||||
const char *wmodes[] = { "w", "r+", "we", "r+e", "re+" };
|
|
||||||
const char *rwmodes[] = { "r+", "r+e", "re+" };
|
|
||||||
char buf[80];
|
|
||||||
struct sigaction act, oact;
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(allmodes) / sizeof(allmodes[0]); i++) {
|
|
||||||
mode = allmodes[i];
|
|
||||||
fp = popen("exit 7", mode);
|
|
||||||
if (fp == NULL) {
|
|
||||||
fprintf(stderr, "popen(, \"%s\") failed", mode);
|
|
||||||
failures++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
check_cloexec(fp, mode);
|
|
||||||
status = pclose(fp);
|
|
||||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 7)
|
|
||||||
fprintf(stderr, "Bad exit status (no I/O)\n"), failures++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(rmodes) / sizeof(rmodes[0]); i++) {
|
|
||||||
mode = rmodes[i];
|
|
||||||
fp = popen("exit 9", mode);
|
|
||||||
if (fp == NULL) {
|
|
||||||
fprintf(stderr, "popen(, \"%s\") failed", mode);
|
|
||||||
failures++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
check_cloexec(fp, mode);
|
|
||||||
if (fgetc(fp) != EOF || !feof(fp) || ferror(fp))
|
|
||||||
fprintf(stderr, "Input error 1\n"), failures++;
|
|
||||||
status = pclose(fp);
|
|
||||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 9)
|
|
||||||
fprintf(stderr, "Bad exit status (input)\n"), failures++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(rmodes) / sizeof(rmodes[0]); i++) {
|
|
||||||
mode = rmodes[i];
|
|
||||||
fp = popen("echo hi there", mode);
|
|
||||||
if (fp == NULL) {
|
|
||||||
fprintf(stderr, "popen(, \"%s\") failed", mode);
|
|
||||||
failures++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
check_cloexec(fp, mode);
|
|
||||||
if (fgets(buf, sizeof(buf), fp) == NULL)
|
|
||||||
fprintf(stderr, "Input error 2\n"), failures++;
|
|
||||||
else if (strcmp(buf, "hi there\n") != 0)
|
|
||||||
fprintf(stderr, "Bad input 1\n"), failures++;
|
|
||||||
status = pclose(fp);
|
|
||||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
|
||||||
fprintf(stderr, "Bad exit status (input)\n"), failures++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(wmodes) / sizeof(wmodes[0]); i++) {
|
|
||||||
mode = wmodes[i];
|
|
||||||
fp = popen("read x && [ \"$x\" = abcd ]", mode);
|
|
||||||
if (fp == NULL) {
|
|
||||||
fprintf(stderr, "popen(, \"%s\") failed", mode);
|
|
||||||
failures++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
check_cloexec(fp, mode);
|
|
||||||
if (fputs("abcd\n", fp) == EOF)
|
|
||||||
fprintf(stderr, "Output error 1\n"), failures++;
|
|
||||||
status = pclose(fp);
|
|
||||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
|
||||||
fprintf(stderr, "Bad exit status (output)\n"), failures++;
|
|
||||||
}
|
|
||||||
|
|
||||||
act.sa_handler = sigpipe_handler;
|
|
||||||
act.sa_flags = SA_RESTART;
|
|
||||||
sigemptyset(&act.sa_mask);
|
|
||||||
if (sigaction(SIGPIPE, &act, &oact) == -1)
|
|
||||||
fprintf(stderr, "sigaction() failed\n"), failures++;
|
|
||||||
for (i = 0; i < sizeof(wmodes) / sizeof(wmodes[0]); i++) {
|
|
||||||
mode = wmodes[i];
|
|
||||||
fp = popen("exit 88", mode);
|
|
||||||
if (fp == NULL) {
|
|
||||||
fprintf(stderr, "popen(, \"%s\") failed", mode);
|
|
||||||
failures++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
check_cloexec(fp, mode);
|
|
||||||
got_sigpipe = 0;
|
|
||||||
while (fputs("abcd\n", fp) != EOF)
|
|
||||||
;
|
|
||||||
if (!ferror(fp) || errno != EPIPE)
|
|
||||||
fprintf(stderr, "Expected EPIPE\n"), failures++;
|
|
||||||
if (!got_sigpipe)
|
|
||||||
fprintf(stderr, "Expected SIGPIPE\n"), failures++;
|
|
||||||
status = pclose(fp);
|
|
||||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 88)
|
|
||||||
fprintf(stderr, "Bad exit status (EPIPE)\n"), failures++;
|
|
||||||
}
|
|
||||||
if (sigaction(SIGPIPE, &oact, NULL) == -1)
|
|
||||||
fprintf(stderr, "sigaction() failed\n"), failures++;
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(rwmodes) / sizeof(rwmodes[0]); i++) {
|
|
||||||
mode = rwmodes[i];
|
|
||||||
fp = popen("read x && printf '%s\\n' \"Q${x#a}\"", mode);
|
|
||||||
if (fp == NULL) {
|
|
||||||
fprintf(stderr, "popen(, \"%s\") failed", mode);
|
|
||||||
failures++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
check_cloexec(fp, mode);
|
|
||||||
if (fputs("abcd\n", fp) == EOF)
|
|
||||||
fprintf(stderr, "Output error 2\n"), failures++;
|
|
||||||
if (fgets(buf, sizeof(buf), fp) == NULL)
|
|
||||||
fprintf(stderr, "Input error 3\n"), failures++;
|
|
||||||
else if (strcmp(buf, "Qbcd\n") != 0)
|
|
||||||
fprintf(stderr, "Bad input 2\n"), failures++;
|
|
||||||
status = pclose(fp);
|
|
||||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
|
||||||
fprintf(stderr, "Bad exit status (I/O)\n"), failures++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(wmodes) / sizeof(wmodes[0]); i++) {
|
|
||||||
for (j = 0; j < sizeof(wmodes) / sizeof(wmodes[0]); j++) {
|
|
||||||
mode = wmodes[i];
|
|
||||||
fp = popen("read x", mode);
|
|
||||||
if (fp == NULL) {
|
|
||||||
fprintf(stderr, "popen(, \"%s\") failed", mode);
|
|
||||||
failures++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
mode = wmodes[j];
|
|
||||||
fp2 = popen("read x", mode);
|
|
||||||
if (fp2 == NULL) {
|
|
||||||
fprintf(stderr, "popen(, \"%s\") failed", mode);
|
|
||||||
failures++;
|
|
||||||
pclose(fp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* If fp2 inherits fp's pipe, we will deadlock here. */
|
|
||||||
status = pclose(fp);
|
|
||||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 1) {
|
|
||||||
fprintf(stderr, "Bad exit status (2 pipes)\n");
|
|
||||||
failures++;
|
|
||||||
}
|
|
||||||
status = pclose(fp2);
|
|
||||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 1) {
|
|
||||||
fprintf(stderr, "Bad exit status (2 pipes)\n");
|
|
||||||
failures++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (failures == 0)
|
|
||||||
printf("PASS popen()\n");
|
|
||||||
|
|
||||||
return (failures != 0);
|
|
||||||
}
|
|
@ -1,271 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright (c) 2003 Tim J. Robbins
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test program for wordexp() and wordfree() as specified by
|
|
||||||
* IEEE Std. 1003.1-2001.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
|
||||||
__FBSDID("$FreeBSD$");
|
|
||||||
|
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <wordexp.h>
|
|
||||||
|
|
||||||
static void
|
|
||||||
chld_handler(int x)
|
|
||||||
{
|
|
||||||
int status, serrno;
|
|
||||||
|
|
||||||
(void)x;
|
|
||||||
serrno = errno;
|
|
||||||
while (waitpid(-1, &status, WNOHANG) > 0)
|
|
||||||
;
|
|
||||||
errno = serrno;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
struct sigaction sa;
|
|
||||||
wordexp_t we;
|
|
||||||
int r;
|
|
||||||
int i;
|
|
||||||
char longdata[6 * 10000 + 1];
|
|
||||||
|
|
||||||
/* Test that the macros are there. */
|
|
||||||
(void)(WRDE_APPEND + WRDE_DOOFFS + WRDE_NOCMD + WRDE_REUSE +
|
|
||||||
WRDE_SHOWERR + WRDE_UNDEF);
|
|
||||||
(void)(WRDE_BADCHAR + WRDE_BADVAL + WRDE_CMDSUB + WRDE_NOSPACE +
|
|
||||||
WRDE_SYNTAX);
|
|
||||||
|
|
||||||
/* Simple test. */
|
|
||||||
r = wordexp("hello world", &we, 0);
|
|
||||||
assert(r == 0);
|
|
||||||
assert(we.we_wordc == 2);
|
|
||||||
assert(strcmp(we.we_wordv[0], "hello") == 0);
|
|
||||||
assert(strcmp(we.we_wordv[1], "world") == 0);
|
|
||||||
assert(we.we_wordv[2] == NULL);
|
|
||||||
wordfree(&we);
|
|
||||||
|
|
||||||
/* Long output. */
|
|
||||||
for (i = 0; i < 10000; i++)
|
|
||||||
snprintf(longdata + 6 * i, 7, "%05d ", i);
|
|
||||||
r = wordexp(longdata, &we, 0);
|
|
||||||
assert(r == 0);
|
|
||||||
assert(we.we_wordc == 10000);
|
|
||||||
assert(we.we_wordv[10000] == NULL);
|
|
||||||
wordfree(&we);
|
|
||||||
|
|
||||||
/* WRDE_DOOFFS */
|
|
||||||
we.we_offs = 3;
|
|
||||||
r = wordexp("hello world", &we, WRDE_DOOFFS);
|
|
||||||
assert(r == 0);
|
|
||||||
assert(we.we_wordc == 2);
|
|
||||||
assert(we.we_wordv[0] == NULL);
|
|
||||||
assert(we.we_wordv[1] == NULL);
|
|
||||||
assert(we.we_wordv[2] == NULL);
|
|
||||||
assert(strcmp(we.we_wordv[3], "hello") == 0);
|
|
||||||
assert(strcmp(we.we_wordv[4], "world") == 0);
|
|
||||||
assert(we.we_wordv[5] == NULL);
|
|
||||||
wordfree(&we);
|
|
||||||
|
|
||||||
/* WRDE_REUSE */
|
|
||||||
r = wordexp("hello world", &we, 0);
|
|
||||||
r = wordexp("hello world", &we, WRDE_REUSE);
|
|
||||||
assert(r == 0);
|
|
||||||
assert(we.we_wordc == 2);
|
|
||||||
assert(strcmp(we.we_wordv[0], "hello") == 0);
|
|
||||||
assert(strcmp(we.we_wordv[1], "world") == 0);
|
|
||||||
assert(we.we_wordv[2] == NULL);
|
|
||||||
wordfree(&we);
|
|
||||||
|
|
||||||
/* WRDE_APPEND */
|
|
||||||
r = wordexp("this is", &we, 0);
|
|
||||||
assert(r == 0);
|
|
||||||
r = wordexp("a test", &we, WRDE_APPEND);
|
|
||||||
assert(r == 0);
|
|
||||||
assert(we.we_wordc == 4);
|
|
||||||
assert(strcmp(we.we_wordv[0], "this") == 0);
|
|
||||||
assert(strcmp(we.we_wordv[1], "is") == 0);
|
|
||||||
assert(strcmp(we.we_wordv[2], "a") == 0);
|
|
||||||
assert(strcmp(we.we_wordv[3], "test") == 0);
|
|
||||||
assert(we.we_wordv[4] == NULL);
|
|
||||||
wordfree(&we);
|
|
||||||
|
|
||||||
/* WRDE_DOOFFS + WRDE_APPEND */
|
|
||||||
we.we_offs = 2;
|
|
||||||
r = wordexp("this is", &we, WRDE_DOOFFS);
|
|
||||||
assert(r == 0);
|
|
||||||
r = wordexp("a test", &we, WRDE_APPEND|WRDE_DOOFFS);
|
|
||||||
assert(r == 0);
|
|
||||||
r = wordexp("of wordexp", &we, WRDE_APPEND|WRDE_DOOFFS);
|
|
||||||
assert(r == 0);
|
|
||||||
assert(we.we_wordc == 6);
|
|
||||||
assert(we.we_wordv[0] == NULL);
|
|
||||||
assert(we.we_wordv[1] == NULL);
|
|
||||||
assert(strcmp(we.we_wordv[2], "this") == 0);
|
|
||||||
assert(strcmp(we.we_wordv[3], "is") == 0);
|
|
||||||
assert(strcmp(we.we_wordv[4], "a") == 0);
|
|
||||||
assert(strcmp(we.we_wordv[5], "test") == 0);
|
|
||||||
assert(strcmp(we.we_wordv[6], "of") == 0);
|
|
||||||
assert(strcmp(we.we_wordv[7], "wordexp") == 0);
|
|
||||||
assert(we.we_wordv[8] == NULL);
|
|
||||||
wordfree(&we);
|
|
||||||
|
|
||||||
/* WRDE_UNDEF */
|
|
||||||
r = wordexp("${dont_set_me}", &we, WRDE_UNDEF);
|
|
||||||
assert(r == WRDE_BADVAL);
|
|
||||||
|
|
||||||
/* WRDE_NOCMD */
|
|
||||||
r = wordexp("`date`", &we, WRDE_NOCMD);
|
|
||||||
assert(r == WRDE_CMDSUB);
|
|
||||||
r = wordexp("\"`date`\"", &we, WRDE_NOCMD);
|
|
||||||
assert(r == WRDE_CMDSUB);
|
|
||||||
r = wordexp("$(date)", &we, WRDE_NOCMD);
|
|
||||||
assert(r == WRDE_CMDSUB);
|
|
||||||
r = wordexp("\"$(date)\"", &we, WRDE_NOCMD);
|
|
||||||
assert(r == WRDE_CMDSUB);
|
|
||||||
r = wordexp("$((3+5))", &we, WRDE_NOCMD);
|
|
||||||
assert(r == 0);
|
|
||||||
r = wordexp("\\$\\(date\\)", &we, WRDE_NOCMD|WRDE_REUSE);
|
|
||||||
assert(r == 0);
|
|
||||||
r = wordexp("'`date`'", &we, WRDE_NOCMD|WRDE_REUSE);
|
|
||||||
assert(r == 0);
|
|
||||||
r = wordexp("'$(date)'", &we, WRDE_NOCMD|WRDE_REUSE);
|
|
||||||
assert(r == 0);
|
|
||||||
wordfree(&we);
|
|
||||||
|
|
||||||
/* WRDE_BADCHAR */
|
|
||||||
r = wordexp("'\n|&;<>(){}'", &we, 0);
|
|
||||||
assert(r == 0);
|
|
||||||
r = wordexp("\"\n|&;<>(){}\"", &we, WRDE_REUSE);
|
|
||||||
assert(r == 0);
|
|
||||||
r = wordexp("\\\n\\|\\&\\;\\<\\>\\(\\)\\{\\}", &we, WRDE_REUSE);
|
|
||||||
assert(r == 0);
|
|
||||||
wordfree(&we);
|
|
||||||
r = wordexp("test \n test", &we, 0);
|
|
||||||
assert(r == WRDE_BADCHAR);
|
|
||||||
r = wordexp("test | test", &we, 0);
|
|
||||||
assert(r == WRDE_BADCHAR);
|
|
||||||
r = wordexp("test & test", &we, 0);
|
|
||||||
assert(r == WRDE_BADCHAR);
|
|
||||||
r = wordexp("test ; test", &we, 0);
|
|
||||||
assert(r == WRDE_BADCHAR);
|
|
||||||
r = wordexp("test > test", &we, 0);
|
|
||||||
assert(r == WRDE_BADCHAR);
|
|
||||||
r = wordexp("test < test", &we, 0);
|
|
||||||
assert(r == WRDE_BADCHAR);
|
|
||||||
r = wordexp("test ( test", &we, 0);
|
|
||||||
assert(r == WRDE_BADCHAR);
|
|
||||||
r = wordexp("test ) test", &we, 0);
|
|
||||||
assert(r == WRDE_BADCHAR);
|
|
||||||
r = wordexp("test { test", &we, 0);
|
|
||||||
assert(r == WRDE_BADCHAR);
|
|
||||||
r = wordexp("test } test", &we, 0);
|
|
||||||
assert(r == WRDE_BADCHAR);
|
|
||||||
|
|
||||||
/* WRDE_SYNTAX */
|
|
||||||
r = wordexp("'", &we, 0);
|
|
||||||
assert(r == WRDE_SYNTAX);
|
|
||||||
r = wordexp("'", &we, WRDE_UNDEF);
|
|
||||||
assert(r == WRDE_SYNTAX);
|
|
||||||
r = wordexp("'\\'", &we, 0);
|
|
||||||
assert(r == 0);
|
|
||||||
assert(we.we_wordc == 1);
|
|
||||||
assert(strcmp(we.we_wordv[0], "\\") == 0);
|
|
||||||
assert(we.we_wordv[1] == NULL);
|
|
||||||
wordfree(&we);
|
|
||||||
/* Two syntax errors that are not detected by the current we_check(). */
|
|
||||||
r = wordexp("${IFS:+'}", &we, 0);
|
|
||||||
assert(r == WRDE_SYNTAX);
|
|
||||||
r = wordexp("${IFS:+'}", &we, WRDE_UNDEF);
|
|
||||||
assert(r == WRDE_SYNTAX);
|
|
||||||
r = wordexp("$(case)", &we, 0);
|
|
||||||
assert(r == WRDE_SYNTAX);
|
|
||||||
r = wordexp("$(case)", &we, WRDE_UNDEF);
|
|
||||||
assert(r == WRDE_SYNTAX);
|
|
||||||
|
|
||||||
/* With a SIGCHLD handler that reaps all zombies. */
|
|
||||||
sa.sa_flags = 0;
|
|
||||||
sigemptyset(&sa.sa_mask);
|
|
||||||
sa.sa_handler = chld_handler;
|
|
||||||
r = sigaction(SIGCHLD, &sa, NULL);
|
|
||||||
assert(r == 0);
|
|
||||||
r = wordexp("hello world", &we, 0);
|
|
||||||
assert(r == 0);
|
|
||||||
assert(we.we_wordc == 2);
|
|
||||||
assert(strcmp(we.we_wordv[0], "hello") == 0);
|
|
||||||
assert(strcmp(we.we_wordv[1], "world") == 0);
|
|
||||||
assert(we.we_wordv[2] == NULL);
|
|
||||||
wordfree(&we);
|
|
||||||
sa.sa_handler = SIG_DFL;
|
|
||||||
r = sigaction(SIGCHLD, &sa, NULL);
|
|
||||||
assert(r == 0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* With IFS set to a non-default value (without depending on whether
|
|
||||||
* IFS is inherited or not).
|
|
||||||
*/
|
|
||||||
r = setenv("IFS", ":", 1);
|
|
||||||
assert(r == 0);
|
|
||||||
r = wordexp("hello world", &we, 0);
|
|
||||||
assert(r == 0);
|
|
||||||
assert(we.we_wordc == 2);
|
|
||||||
assert(strcmp(we.we_wordv[0], "hello") == 0);
|
|
||||||
assert(strcmp(we.we_wordv[1], "world") == 0);
|
|
||||||
assert(we.we_wordv[2] == NULL);
|
|
||||||
wordfree(&we);
|
|
||||||
r = unsetenv("IFS");
|
|
||||||
assert(r == 0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* With IFS set to a non-default value, and using it.
|
|
||||||
*/
|
|
||||||
r = setenv("IFS", ":", 1);
|
|
||||||
assert(r == 0);
|
|
||||||
r = wordexp("${IFS+hello:world}", &we, 0);
|
|
||||||
assert(r == 0);
|
|
||||||
assert(we.we_wordc == 2);
|
|
||||||
assert(strcmp(we.we_wordv[0], "hello") == 0);
|
|
||||||
assert(strcmp(we.we_wordv[1], "world") == 0);
|
|
||||||
assert(we.we_wordv[2] == NULL);
|
|
||||||
wordfree(&we);
|
|
||||||
r = unsetenv("IFS");
|
|
||||||
assert(r == 0);
|
|
||||||
|
|
||||||
printf("PASS wordexp()\n");
|
|
||||||
printf("PASS wordfree()\n");
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user