+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
+ * Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
+ * Copyright (C) 2004 Theodore Y. Ts'o <tytso@mit.edu>
+ * Copyright (C) 2006 Mike McCormack
+ * Copyright (C) 2006 Christian Couder
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "cache.h"
+#include "quote.h"
+
+/* Stolen from "imap-send.c". */
+static int git_vasprintf(char **strp, const char *fmt, va_list ap)
+{
+ int len;
+ char tmp[1024];
+
+ if ((len = vsnprintf(tmp, sizeof(tmp), fmt, ap)) < 0 ||
+ !(*strp = xmalloc(len + 1)))
+ return -1;
+ if (len >= (int)sizeof(tmp))
+ vsprintf(*strp, fmt, ap);
+ else
+ memcpy(*strp, tmp, len + 1);
+ return len;
+}
+
+/* Stolen from "imap-send.c". */
+int nfvasprintf(char **str, const char *fmt, va_list va)
+{
+ int ret = git_vasprintf(str, fmt, va);
+ if (ret < 0)
+ die("Fatal: Out of memory\n");
+ return ret;
+}
+
+/* Get a trace file descriptor from GIT_TRACE env variable. */
+static int get_trace_fd(int *need_close)
+{
+ char *trace = getenv("GIT_TRACE");
+
+ if (!trace || !strcmp(trace, "0") || !strcasecmp(trace," false"))
+ return 0;
+ if (!strcmp(trace, "1") || !strcasecmp(trace, "true"))
+ return STDERR_FILENO;
+ if (strlen(trace) == 1 && isdigit(*trace))
+ return atoi(trace);
+ if (*trace == '/') {
+ int fd = open(trace, O_WRONLY | O_APPEND | O_CREAT, 0666);
+ if (fd == -1) {
+ fprintf(stderr,
+ "Could not open '%s' for tracing: %s\n"
+ "Defaulting to tracing on stderr...\n",
+ trace, strerror(errno));
+ return STDERR_FILENO;
+ }
+ *need_close = 1;
+ return fd;
+ }
+
+ fprintf(stderr, "What does '%s' for GIT_TRACE means ?\n", trace);
+ fprintf(stderr, "If you want to trace into a file, "
+ "then please set GIT_TRACE to an absolute pathname "
+ "(starting with /).\n");
+ fprintf(stderr, "Defaulting to tracing on stderr...\n");
+
+ return STDERR_FILENO;
+}
+
+static const char err_msg[] = "Could not trace into fd given by "
+ "GIT_TRACE environment variable";
+
+void trace_printf(const char *format, ...)
+{
+ char *trace_str;
+ va_list rest;
+ int need_close = 0;
+ int fd = get_trace_fd(&need_close);
+
+ if (!fd)
+ return;
+
+ va_start(rest, format);
+ nfvasprintf(&trace_str, format, rest);
+ va_end(rest);
+
+ write_or_whine(fd, trace_str, strlen(trace_str), err_msg);
+
+ free(trace_str);
+
+ if (need_close)
+ close(fd);
+}
+
+void trace_argv_printf(const char **argv, int count, const char *format, ...)
+{
+ char *argv_str, *format_str, *trace_str;
+ size_t argv_len, format_len, trace_len;
+ va_list rest;
+ int need_close = 0;
+ int fd = get_trace_fd(&need_close);
+
+ if (!fd)
+ return;
+
+ /* Get the argv string. */
+ argv_str = sq_quote_argv(argv, count);
+ argv_len = strlen(argv_str);
+
+ /* Get the formated string. */
+ va_start(rest, format);
+ nfvasprintf(&format_str, format, rest);
+ va_end(rest);
+
+ /* Allocate buffer for trace string. */
+ format_len = strlen(format_str);
+ trace_len = argv_len + format_len + 1; /* + 1 for \n */
+ trace_str = xmalloc(trace_len + 1);
+
+ /* Copy everything into the trace string. */
+ strncpy(trace_str, format_str, format_len);
+ strncpy(trace_str + format_len, argv_str, argv_len);
+ strcpy(trace_str + trace_len - 1, "\n");
+
+ write_or_whine(fd, trace_str, trace_len, err_msg);
+
+ free(argv_str);
+ free(format_str);
+ free(trace_str);
+
+ if (need_close)
+ close(fd);
+}