Revert accidentally merged commits

This reverts the following commits:

abd1fa1 test-suite: Log everything to a file in non-verbose mode
50f37d1 Implement test-stat the prints the modification time.
fc7fe85 gitk: Swap positions of 'next' and 'prev' buttons in the 'Find' section.
f80f1db Need diff -u -b in t7401 because some lines end in CRLF.
85763c8 Implement thread-specific die() routines; use one in start_async().
4eb0463 Make report() from usage.c public as vreport().
ddce705 Skip tests that fail due to incomplete implementations, missing tools...
a094080 Do not issue the warning about the fallback of the PREFIX.

These were brought in by the merge commit dc8b641 that merged my private
work-in-progress branch. Only these two commits remain:

1e52e22 Windows: Work around intermittent failures in mingw_rename
ccd3859 Windows: Better support PAGER settings with spaces in the path

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
This commit is contained in:
Johannes Sixt
2009-04-13 21:43:27 +02:00
parent 7eaf89fd20
commit a36adafee4
17 changed files with 229 additions and 317 deletions

View File

@@ -28,10 +28,9 @@ const char *system_path(const char *path)
!(prefix = strip_path_suffix(argv0_path, BINDIR)) &&
!(prefix = strip_path_suffix(argv0_path, "git"))) {
prefix = PREFIX;
/*
* RUNTIME_PREFIX requested, but prefix computation failed.
* Using static fallback.
*/
fprintf(stderr, "RUNTIME_PREFIX requested, "
"but prefix computation failed. "
"Using static fallback '%s'.\n", prefix);
}
#endif

View File

@@ -150,7 +150,6 @@
#endif
/* General helper functions */
extern void vreport(const char *prefix, const char *err, va_list params);
extern void usage(const char *err) NORETURN;
extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));

View File

@@ -2057,7 +2057,7 @@ proc makewindow {} {
button .tf.lbar.fnext -text [mc "next"] -command {dofind 1 1}
button .tf.lbar.fprev -text [mc "prev"] -command {dofind -1 1}
label .tf.lbar.flab2 -text " [mc "commit"] "
pack .tf.lbar.flabel .tf.lbar.fprev .tf.lbar.fnext .tf.lbar.flab2 \
pack .tf.lbar.flabel .tf.lbar.fnext .tf.lbar.fprev .tf.lbar.flab2 \
-side left -fill y
set gdttype [mc "containing:"]
set gm [tk_optionMenu .tf.lbar.gdttype gdttype \

View File

@@ -293,22 +293,9 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
}
#ifdef __MINGW32__
static int close_fd = -1;
NORETURN void die_from_thread(const char *err, va_list params)
{
vreport("fatal: ", err, params);
if (close_fd >= 0)
close(close_fd);
_endthreadex(128);
exit(128); /* silence compiler */
}
static __stdcall unsigned run_thread(void *data)
{
struct async *async = data;
close_fd = async->fd_for_proc;
extern NORETURN void die_from_thread(const char *err, va_list params);
set_die_routine(die_from_thread);
return async->proc(async->fd_for_proc, async->data);
}
#endif
@@ -362,9 +349,6 @@ int finish_async(struct async *async)
else if (!GetExitCodeThread(async->tid, &ret))
ret = error("cannot get thread exit code: %lu", GetLastError());
CloseHandle(async->tid);
if (ret)
/* test suite tests for this string */
error("waitpid (async) failed");
#endif
return ret;
}

1
t/.gitignore vendored
View File

@@ -1,3 +1,2 @@
/trash directory*
/test-results
/test-log

View File

@@ -21,7 +21,7 @@ $(T):
@echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS)
pre-clean:
$(RM) -r test-results test-log
$(RM) -r test-results
clean:
$(RM) -r 'trash directory'.* test-results
@@ -42,24 +42,3 @@ valgrind:
GIT_TEST_OPTS=--valgrind $(MAKE)
.PHONY: pre-clean $(T) aggregate-results clean valgrind
-include Makefile.local
GIT_SKIP_TESTS := $(GIT_SKIP_TESTS_LOCAL)
# git am does not treat absolute path to mbox file correctly
GIT_SKIP_TESTS += t4150.18
# output contains CRLF (I think)
GIT_SKIP_TESTS += t7401.14
# output contains CRLF (I think)
GIT_SKIP_TESTS += t7508.1[68]
# cannot run fake.sendmail for some reason
GIT_SKIP_TESTS += t9001
# there's a problem with GIT_DIR in test 12 (why only there?)
# needs fixups with $PWD instead of $(pwd) - tries to run rsh c
GIT_SKIP_TESTS += t9200
# CGI.pm not found
GIT_SKIP_TESTS += t9500
export GIT_SKIP_TESTS
NO_SVN_TESTS=SkipThem
export NO_SVN_TESTS

View File

@@ -39,7 +39,6 @@ Standard options
EOF
test_expect_success 'test help' '
set +x &&
test_must_fail test-parse-options -h > output 2> output.err &&
test ! -s output &&
test_cmp expect.err output.err
@@ -159,7 +158,6 @@ error: did you mean \`--boolean\` (with two dashes ?)
EOF
test_expect_success 'detect possible typos' '
set +x &&
test_must_fail test-parse-options -boolean > output 2> output.err &&
test ! -s output &&
test_cmp typo.err output.err
@@ -225,7 +223,6 @@ Callback: "not set", 1
EOF
test_expect_success 'OPT_CALLBACK() and callback errors work' '
set +x &&
test_must_fail test-parse-options --no-length > output 2> output.err &&
test_cmp expect output &&
test_cmp expect.err output.err

View File

@@ -71,7 +71,6 @@ test_expect_success 'fails with any bad rev or many good revs' '
'
test_expect_success 'fails silently when using -q' '
set +x &&
test_must_fail git rev-parse --verify --quiet 2>error &&
test -z "$(cat error)" &&
test_must_fail git rev-parse -q --verify foo 2>error &&

View File

@@ -245,7 +245,11 @@ test_expect_success 'am works from file (relative path given) in subdirectory' '
test -z "$(git diff second)"
'
test_expect_success 'am works from file (absolute path given) in subdirectory' '
case $(uname -s) in
*MINGW*) test_expect=test_expect_failure;;
*) test_expect=test_expect_success;;
esac
$test_expect 'am works from file (absolute path given) in subdirectory' '
rm -fr subdir &&
git checkout first &&
P=$(pwd) &&

View File

@@ -247,7 +247,6 @@ EOF
test_expect_success 'set-head --auto fails w/multiple HEADs' '
(cd test &&
set +x &&
test_must_fail git remote set-head --auto two >output 2>&1 &&
test_cmp expect output)
'

View File

@@ -95,15 +95,30 @@ git checkout master'
test_expect_success 'pull renaming branch into unrenaming one' \
'
git show-branch
test_must_fail git pull . white &&
git ls-files -s &&
test "$(git ls-files -u B | wc -l)" -eq 3 &&
test "$(git ls-files -s N | wc -l)" -eq 1 &&
git pull . white && {
echo "BAD: should have conflicted"
return 1
}
git ls-files -s
test "$(git ls-files -u B | wc -l)" -eq 3 || {
echo "BAD: should have left stages for B"
return 1
}
test "$(git ls-files -s N | wc -l)" -eq 1 || {
echo "BAD: should have merged N"
return 1
}
sed -ne "/^g/{
p
q
}" B | grep master &&
test "$(git diff white N | wc -l)" -eq 0
}" B | grep master || {
echo "BAD: should have listed our change first"
return 1
}
test "$(git diff white N | wc -l)" -eq 0 || {
echo "BAD: should have taken colored branch"
return 1
}
'
test_expect_success 'pull renaming branch into another renaming one' \
@@ -111,44 +126,95 @@ test_expect_success 'pull renaming branch into another renaming one' \
rm -f B
git reset --hard
git checkout red
test_must_fail git pull . white &&
test "$(git ls-files -u B | wc -l)" -eq 3 &&
test "$(git ls-files -s N | wc -l)" -eq 1 &&
git pull . white && {
echo "BAD: should have conflicted"
return 1
}
test "$(git ls-files -u B | wc -l)" -eq 3 || {
echo "BAD: should have left stages"
return 1
}
test "$(git ls-files -s N | wc -l)" -eq 1 || {
echo "BAD: should have merged N"
return 1
}
sed -ne "/^g/{
p
q
}" B | grep red &&
test "$(git diff white N | wc -l)" -eq 0
}" B | grep red || {
echo "BAD: should have listed our change first"
return 1
}
test "$(git diff white N | wc -l)" -eq 0 || {
echo "BAD: should have taken colored branch"
return 1
}
'
test_expect_success 'pull unrenaming branch into renaming one' \
'
git reset --hard
git show-branch
test_must_fail git pull . master &&
test "$(git ls-files -u B | wc -l)" -eq 3 &&
test "$(git ls-files -s N | wc -l)" -eq 1 &&
git pull . master && {
echo "BAD: should have conflicted"
return 1
}
test "$(git ls-files -u B | wc -l)" -eq 3 || {
echo "BAD: should have left stages"
return 1
}
test "$(git ls-files -s N | wc -l)" -eq 1 || {
echo "BAD: should have merged N"
return 1
}
sed -ne "/^g/{
p
q
}" B | grep red &&
test "$(git diff white N | wc -l)" -eq 0
}" B | grep red || {
echo "BAD: should have listed our change first"
return 1
}
test "$(git diff white N | wc -l)" -eq 0 || {
echo "BAD: should have taken colored branch"
return 1
}
'
test_expect_success 'pull conflicting renames' \
'
git reset --hard
git show-branch
test_must_fail git pull . blue &&
test "$(git ls-files -u A | wc -l)" -eq 1 &&
test "$(git ls-files -u B | wc -l)" -eq 1 &&
test "$(git ls-files -u C | wc -l)" -eq 1 &&
test "$(git ls-files -s N | wc -l)" -eq 1 &&
git pull . blue && {
echo "BAD: should have conflicted"
return 1
}
test "$(git ls-files -u A | wc -l)" -eq 1 || {
echo "BAD: should have left a stage"
return 1
}
test "$(git ls-files -u B | wc -l)" -eq 1 || {
echo "BAD: should have left a stage"
return 1
}
test "$(git ls-files -u C | wc -l)" -eq 1 || {
echo "BAD: should have left a stage"
return 1
}
test "$(git ls-files -s N | wc -l)" -eq 1 || {
echo "BAD: should have merged N"
return 1
}
sed -ne "/^g/{
p
q
}" B | grep red &&
test "$(git diff white N | wc -l)" -eq 0
}" B | grep red || {
echo "BAD: should have listed our change first"
return 1
}
test "$(git diff white N | wc -l)" -eq 0 || {
echo "BAD: should have taken colored branch"
return 1
}
'
test_expect_success 'interference with untracked working tree file' '
@@ -156,8 +222,14 @@ test_expect_success 'interference with untracked working tree file' '
git reset --hard
git show-branch
echo >A this file should not matter
test_must_fail git pull . white &&
test -f A
git pull . white && {
echo "BAD: should have conflicted"
return 1
}
test -f A || {
echo "BAD: should have left A intact"
return 1
}
'
test_expect_success 'interference with untracked working tree file' '
@@ -167,8 +239,14 @@ test_expect_success 'interference with untracked working tree file' '
git show-branch
rm -f A
echo >A this file should not matter
test_must_fail git pull . red &&
test -f A
git pull . red && {
echo "BAD: should have conflicted"
return 1
}
test -f A || {
echo "BAD: should have left A intact"
return 1
}
'
test_expect_success 'interference with untracked working tree file' '
@@ -178,8 +256,14 @@ test_expect_success 'interference with untracked working tree file' '
git checkout -f master
git tag -f anchor
git show-branch
git pull . yellow
test ! -f M &&
git pull . yellow || {
echo "BAD: should have cleanly merged"
return 1
}
test -f M && {
echo "BAD: should have removed M"
return 1
}
git reset --hard anchor
'
@@ -192,8 +276,14 @@ test_expect_success 'updated working tree file should prevent the merge' '
git show-branch
echo >>M one line addition
cat M >M.saved
test_must_fail git pull . yellow &&
diff M M.saved &&
git pull . yellow && {
echo "BAD: should have complained"
return 1
}
diff M M.saved || {
echo "BAD: should have left M intact"
return 1
}
rm -f M.saved
'
@@ -207,8 +297,14 @@ test_expect_success 'updated working tree file should prevent the merge' '
echo >>M one line addition
cat M >M.saved
git update-index M
test_must_fail git pull . yellow &&
diff M M.saved &&
git pull . yellow && {
echo "BAD: should have complained"
return 1
}
diff M M.saved || {
echo "BAD: should have left M intact"
return 1
}
rm -f M.saved
'
@@ -220,9 +316,18 @@ test_expect_success 'interference with untracked working tree file' '
git tag -f anchor
git show-branch
echo >M this file should not matter
git pull . master &&
test -f M &&
! (git ls-files -s | grep M) &&
git pull . master || {
echo "BAD: should have cleanly merged"
return 1
}
test -f M || {
echo "BAD: should have left M intact"
return 1
}
git ls-files -s | grep M && {
echo "BAD: M must be untracked in the result"
return 1
}
git reset --hard anchor
'

View File

@@ -73,12 +73,33 @@ test_expect_success 'merge white into red (A->B,M->N)' \
'
git checkout -b red-white red &&
git merge white &&
git write-tree >/dev/null &&
test -f B &&
test -f N &&
test -f R &&
! test -f A &&
! test -f M
git write-tree >/dev/null || {
echo "BAD: merge did not complete"
return 1
}
test -f B || {
echo "BAD: B does not exist in working directory"
return 1
}
test -f N || {
echo "BAD: N does not exist in working directory"
return 1
}
test -f R || {
echo "BAD: R does not exist in working directory"
return 1
}
test -f A && {
echo "BAD: A still exists in working directory"
return 1
}
test -f M && {
echo "BAD: M still exists in working directory"
return 1
}
return 0
'
# This test broke in 8371234ecaaf6e14fe3f2082a855eff1bbd79ae9
@@ -87,12 +108,32 @@ test_expect_success 'merge blue into white (A->B, mod A, A untracked)' \
git checkout -b white-blue white &&
echo dirty >A &&
git merge blue &&
git write-tree >/dev/null &&
test -f A &&
test `cat A` = dirty &&
test -f B &&
test -f N &&
! test -f M
git write-tree >/dev/null || {
echo "BAD: merge did not complete"
return 1
}
test -f A || {
echo "BAD: A does not exist in working directory"
return 1
}
test `cat A` = dirty || {
echo "BAD: A content is wrong"
return 1
}
test -f B || {
echo "BAD: B does not exist in working directory"
return 1
}
test -f N || {
echo "BAD: N does not exist in working directory"
return 1
}
test -f M && {
echo "BAD: M still exists in working directory"
return 1
}
return 0
'
test_done

View File

@@ -14,8 +14,6 @@ esac
. ./test-lib.sh
export GIT_TEST_CMP='diff -u -b' # some lines end in CRLF
add_file () {
sm=$1
shift

View File

@@ -399,8 +399,20 @@ from refs/heads/branch
INPUT_END
test_expect_success \
'F: non-fast-forward update skips' \
'test_must_fail git fast-import <input &&
test $old_branch = `git rev-parse --verify branch^0`
'if git fast-import <input
then
echo BAD gfi did not fail
return 1
else
if test $old_branch = `git rev-parse --verify branch^0`
then
: branch unaffected and failure returned
return 0
else
echo BAD gfi changed branch $old_branch
return 1
fi
fi
'
test_expect_success \
'F: verify pack' \

View File

@@ -60,7 +60,6 @@ export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
export EDITOR VISUAL
GIT_TEST_CMP=${GIT_TEST_CMP:-diff -u}
TEST_DIRECTORY=$(pwd)
# Protect ourselves from common misconfiguration to export
# CDPATH into the environment
@@ -168,15 +167,9 @@ fi
exec 5>&1
if test "$verbose" = "t"
then
set_x= set_nox=
exec 4>&2 3>&1
else
test_log_dir="$TEST_DIRECTORY/test-log"
mkdir -p "$test_log_dir"
test_log_path="$test_log_dir/${0%.sh}-$$"
set_x='set -x;'
set_nox='set +x'
exec 3>"$test_log_path" 4>&3
exec 4>/dev/null 3>/dev/null
fi
test_failure=0
@@ -310,9 +303,8 @@ test_debug () {
}
test_run_ () {
eval >&3 2>&4 $set_x "$1" '
eval_ret=$?
$set_nox'
eval >&3 2>&4 "$1"
eval_ret="$?"
return 0
}
@@ -548,6 +540,7 @@ test_done () {
# Test the binaries we have just built. The tests are kept in
# t/ subdirectory and are run in 'trash directory' subdirectory.
TEST_DIRECTORY=$(pwd)
if test -z "$valgrind"
then
if test -z "$GIT_TEST_INSTALLED"

View File

@@ -1,170 +0,0 @@
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#ifdef EMULATE
#define HINT fprintf(stderr, "emulated stat\n")
#include <errno.h>
#include <windows.h>
#include <unistd.h>
/* Use mingw_lstat() instead of lstat()/stat() and
* mingw_fstat() instead of fstat() on Windows.
*/
int mingw_lstat(const char *file_name, struct stat *buf);
int mingw_fstat(int fd, struct stat *buf);
#define fstat mingw_fstat
#define lstat mingw_lstat
#define stat(x,y) mingw_lstat(x,y)
#define PATH_MAX 260
static inline int file_attr_to_st_mode (DWORD attr)
{
int fMode = S_IREAD;
if (attr & FILE_ATTRIBUTE_DIRECTORY)
fMode |= S_IFDIR;
else
fMode |= S_IFREG;
if (!(attr & FILE_ATTRIBUTE_READONLY))
fMode |= S_IWRITE;
return fMode;
}
static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata)
{
if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata))
return 0;
switch (GetLastError()) {
case ERROR_ACCESS_DENIED:
case ERROR_SHARING_VIOLATION:
case ERROR_LOCK_VIOLATION:
case ERROR_SHARING_BUFFER_EXCEEDED:
return EACCES;
case ERROR_BUFFER_OVERFLOW:
return ENAMETOOLONG;
case ERROR_NOT_ENOUGH_MEMORY:
return ENOMEM;
default:
return ENOENT;
}
}
static inline time_t filetime_to_time_t(const FILETIME *ft)
{
long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
winTime /= 10000000; /* Nano to seconds resolution */
return (time_t)winTime;
}
/* We keep the do_lstat code in a separate function to avoid recursion.
* When a path ends with a slash, the stat will fail with ENOENT. In
* this case, we strip the trailing slashes and stat again.
*/
static int do_lstat(const char *file_name, struct stat *buf)
{
WIN32_FILE_ATTRIBUTE_DATA fdata;
if (!(errno = get_file_attr(file_name, &fdata))) {
buf->st_ino = 0;
buf->st_gid = 0;
buf->st_uid = 0;
buf->st_nlink = 1;
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
return 0;
}
return -1;
}
/* We provide our own lstat/fstat functions, since the provided
* lstat/fstat functions are so slow. These stat functions are
* tailored for Git's usage (read: fast), and are not meant to be
* complete. Note that Git stat()s are redirected to mingw_lstat()
* too, since Windows doesn't really handle symlinks that well.
*/
int mingw_lstat(const char *file_name, struct stat *buf)
{
int namelen;
static char alt_name[PATH_MAX];
if (!do_lstat(file_name, buf))
return 0;
/* if file_name ended in a '/', Windows returned ENOENT;
* try again without trailing slashes
*/
if (errno != ENOENT)
return -1;
namelen = strlen(file_name);
if (namelen && file_name[namelen-1] != '/')
return -1;
while (namelen && file_name[namelen-1] == '/')
--namelen;
if (!namelen || namelen >= PATH_MAX)
return -1;
memcpy(alt_name, file_name, namelen);
alt_name[namelen] = 0;
return do_lstat(alt_name, buf);
}
#undef fstat
int mingw_fstat(int fd, struct stat *buf)
{
HANDLE fh = (HANDLE)_get_osfhandle(fd);
BY_HANDLE_FILE_INFORMATION fdata;
if (fh == INVALID_HANDLE_VALUE) {
errno = EBADF;
return -1;
}
/* direct non-file handles to MS's fstat() */
if (GetFileType(fh) != FILE_TYPE_DISK)
return fstat(fd, buf);
if (GetFileInformationByHandle(fh, &fdata)) {
buf->st_ino = 0;
buf->st_gid = 0;
buf->st_uid = 0;
buf->st_nlink = 1;
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
return 0;
}
errno = EBADF;
return -1;
}
#else
#define HINT (void)0
#endif
int main(int argc, char**argv)
{
int i;
int err = 0;
HINT;
for (i = 1; i < argc; i++)
{
struct stat st;
if (stat(argv[i], &st)) {
perror(argv[i]);
err = 1;
continue;
}
printf("%s: %s\n", argv[i], ctime(&st.st_mtime));
}
return err;
}

40
usage.c
View File

@@ -5,7 +5,7 @@
*/
#include "git-compat-util.h"
void vreport(const char *prefix, const char *err, va_list params)
static void report(const char *prefix, const char *err, va_list params)
{
char msg[1024];
vsnprintf(msg, sizeof(msg), err, params);
@@ -20,52 +20,30 @@ static NORETURN void usage_builtin(const char *err)
static NORETURN void die_builtin(const char *err, va_list params)
{
vreport("fatal: ", err, params);
report("fatal: ", err, params);
exit(128);
}
static void error_builtin(const char *err, va_list params)
{
vreport("error: ", err, params);
report("error: ", err, params);
}
static void warn_builtin(const char *warn, va_list params)
{
vreport("warning: ", warn, params);
report("warning: ", warn, params);
}
typedef void (*die_fn_t)(const char *err, va_list params) NORETURN;
static DWORD tls_index;
static void tls_init(void) __attribute__((constructor));
static void tls_init(void)
{
tls_index = TlsAlloc();
}
struct routines {
die_fn_t die_routine;
};
/* If we are in a dlopen()ed .so write to a global variable would segfault
* (ugh), so keep things static. */
static void (*usage_routine)(const char *err) NORETURN = usage_builtin;
static void (*die_routine)(const char *err, va_list params) NORETURN = die_builtin;
static void (*error_routine)(const char *err, va_list params) = error_builtin;
static void (*warn_routine)(const char *err, va_list params) = warn_builtin;
void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN)
{
struct routines *r = TlsGetValue(tls_index);
if (r == NULL) {
/* avoid die()! */
r = calloc(sizeof(*r), 1);
if (r == NULL) {
fprintf(stderr, "cannot allocate thread-local storage");
return;
}
TlsSetValue(tls_index, r);
}
r->die_routine = routine;
die_routine = routine;
}
void usage(const char *err)
@@ -76,13 +54,9 @@ void usage(const char *err)
void die(const char *err, ...)
{
va_list params;
struct routines *r = TlsGetValue(tls_index);
va_start(params, err);
if (r == NULL || r->die_routine == NULL)
die_builtin(err, params);
else
r->die_routine(err, params);
die_routine(err, params);
va_end(params);
}