/*
 *  This file is part of ixemul.library for the Amiga.
 *  Copyright (C) 1991, 1992  Markus M. Wild
 *  Changed to avoid buffer overflows by J. Hoehle and
 *  restricted output length for: str(n)cat, strlen
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/tracecntl.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/ioctl_compat.h>
#include <sys/termios.h>
#include <exec/types.h>
#include <libraries/dos.h>

#include <inline/exec.h>
extern struct MsgPort *CreatePort (char *, int);
extern void DeletePort (struct MsgPort *);

#define OUT_WIDTH  80	/* big enough (>30) to hold first information */
#define LWS  ".35"	/* output Limited argument Width */
			/* Requires compiler string concatenation (ANSI-C) */

void print_call (FILE *output, struct trace_packet *tp);

int print_all = 0;
int skip_sigsetmask = 0;
FILE *output;

void
dummy_handler ()
{
}

int
main (int argc, char *argv[])
{
  char *logfile = "-";
  struct trace_packet tp = { 0,};
  struct MsgPort *mp;
  int c, in = 0;

  signal (SIGMSG, dummy_handler);

  while ((c = getopt (argc, argv, "aimo:p:s:")) != EOF)
    switch (c)
      {
      case 'a':
	print_all = 1;
	break;

      case 'i':
	in = 1;
	break;

      case 'm':
	skip_sigsetmask = 1;
	break;

      case 'o':
	logfile = optarg;
	break;

      case 'p':
	tp.tp_pid = atoi (optarg);
	break;
	
      case 's':
        tp.tp_syscall = atoi (optarg);
        break;

      default:
	fprintf (stderr, 
		 "%s [-a] [-m] [-o logfile] [-p pid] [-s syscall-number]\n"
		 "  -a  trace all calls (else __-calls are skipped)\n"
		 "  -i  trace entry to functions. Default is exit.\n"
		 "  -m  skip sigsetmask() calls (they're heavily used inside the library)\n"
		 "  -o  log output to logfile (default is stdout)\n"
		 "  -p  only trace process pid (default is to trace all processes)\n"
		 "  -s  only trace this syscall (default is to trace all calls)\n",
		 argv[0]);
        return 1;
      }

  if (logfile[0] == '-' && !logfile[1])
    output = stdout;
  else
    output = fopen (logfile, "w");

  if (!output)
    {
      perror ("fopen");
      return 1;
    }

  if ((mp = CreatePort (0, 0)))
    {
      tp.tp_tracer_port = mp;
      if (tracecntl (TRACE_INSTALL_HANDLER, &tp) == 0)
	{
	  while (1)
	    {
	      struct Message *msg;
	      long sigs;

	      sigs = Wait ((1 << mp->mp_SigBit) | SIGBREAKF_CTRL_C);
	      while ((msg = GetMsg (mp)))
		{
	          if (msg != (struct Message *) &tp)
		    {
		      fprintf (stderr, "Got alien message! Don't do that ever again ;-)\n");
		    } 
	          else
		    {
		      if (in)
			tp.tp_action = TRACE_ACTION_JMP;
		      if (! tp.tp_is_entry || tp.tp_action == TRACE_ACTION_JMP)
		        print_call (output, &tp);
		    }
	          Signal ((struct Task *) msg->mn_ReplyPort, SIGBREAKF_CTRL_E);
	        }
	      if (sigs & SIGBREAKF_CTRL_C)
		break;
	    }
	  tracecntl (TRACE_REMOVE_HANDLER, &tp);
	}
      else
	perror ("tracecntl");
      
      DeletePort (mp);
    }
  else
    perror ("CreatePort");
}

void vp (), vp_fcntl (), vp_ioctl (), vp_open (), vp_pipe ();


struct call {
  int  interesting;
  char *name;
  void (*func)(...);
  char *fmt;
  char *rfmt;
} call_table[] = {
  { 1, "bad call",	vp,	"",		"",		},
  { 1, "abort",	vp,	"()",		"",		},
  { 1, "abs",	vp,	"(%d)",		"%d",		},
  { 1, "access",	vp,	"(\"%s\", %d)",	"%d",		},
  { 1, "alarm",	vp,	"(%d)",		"%d",		},
  { 1, "atexit",	vp,	"($%lx)",	"%d",		},
  { 1, "atof",	vp,	"(\"%s\")",		"%g",		},
  { 1, "atoi",	vp,	"(\"%s\")",		"%d",		},
  { 1, "atol",	vp,	"(\"%s\")",		"%d",		},
  { 1, "bcmp",	vp,	"($%lx, $%lx, %d)",	"%d",		},
  { 1, "bcopy",	vp,	"($%lx, $%lx, %d)",	"",		},
  { 1, "bsearch",	vp,	"($%lx, $%lx, %d, %d, $%lx)", 	"$%lx",		},
  { 1, "bzero",	vp,	"($%lx, %d)",	"",		},
  { 1, "calloc",	vp,	"(%d, %d)",	"$%lx",		},
  { 1, "cfgetispeed",vp,	"($%lx)",	"%d",		},
  { 1, "cfgetospeed",vp,	"($%lx)",	"%d",		},
  { 1, "cfmakeraw",	vp,	"($%lx)",	"%d",		},
  { 1, "cfree",	vp,	"($%lx)",	"",		},
  { 1, "cfsetispeed",vp,	"($%lx)",	"%d",		},
  { 1, "cfsetospeed",vp,	"($%lx)",	"%d",		},
  { 1, "cfsetspeed",	vp,	"($%lx)",	"%d",		},
  { 1, "chdir",	vp,	"(\"%s\")",		"%d",		},
  { 1, "chmod",	vp,	"(\"%s\", %o)",	"%d",		},
  { 1, "chown",	vp,	"(\"%s\", %d, %d)",	"%d",		},
  { 1, "clock",	vp,	"()",		"%d",		},
  { 1, "close",	vp,	"(%d)",		"%d",		},
  { 1, "creat",	vp,	"(\"%s\", %o)",	"%d",		},
  { 1, "CreateExtIO",vp,	"($%lx, %d)",	"$%lx",		},
  { 1, "CreatePort",	vp,	"(\"%s\", %d)",	"$%lx",		},
  { 1, "CreateStdIO",vp,	"($%lx)",	"$%lx",		},
  { 1, "CreateTask",	vp,	"(\"%s\", %d, $%lx, %d)",	"$%lx",		},
  { 1, "DeleteExtIO",vp,	"($%lx)",	"",		},
  { 1, "DeletePort",	vp,	"($%lx)",	"",		},
  { 1, "DeleteStdIO",vp,	"($%lx)",	"",		},
  { 1, "DeleteTask",	vp,	"($%lx)",	"",		},
  { 1, "difftime",	vp,	"(%d, %d)",	"%d",		},
  { 1, "div",	vp,	"(%d, %d)",	"%d",		},
  { 1, "dup",	vp,	"(%d)",		"%d",		},
  { 1, "dup2",	vp,	"(%d, %d)",	"%d",		},
  { 1, "exit",	vp,	"(%d)",		"",		},
  { 1, "fchmod",	vp,	"(%d, %o)",	"%d",		},
  { 1, "fcntl",	vp_fcntl,	"(%d, \"%s\", %d)", "%d",		},
  { 1, "ffs",	vp,	"(%d)",		"%d",		},
  { 1, "flock",	vp,	"(%d, %d)",	"%d",		},
  { 1, "free",	vp,	"($%lx)",	"",		},
  { 1, "frexp",	vp,	"(%g, %g)",	"%g",		},
  { 1, "fstat",	vp, 	"(%d, $%lx)",	"%d",		},
  { 1, "fsync",	vp,	"(%d)",		"%d",		},
  { 1, "ftime",	vp,	"(%d)",		"%d",		},
  { 1, "ftruncate",	vp,	"(%d, %d)",	"%d",		},
  { 1, "getcwd",	vp,	"(\"%s\", %d)",	"%d",		},
  { 1, "getdtablesize",vp,	"()",		"%d",		},
  { 1, "getegid",	vp,	"(%d)",		"%d",		},
  { 1, "getenv",	vp,	"(\"%s\")",		"\"%s\"",		},
  { 1, "geteuid",	vp,	"()",		"%d",		},
  { 1, "getgid",	vp,	"()",		"%d",		},
  { 1, "getgrgid",	vp,	"()",		"%d",		},
  { 1, "getgroups",	vp,	"(%d, $%lx)",	"%d",		},
  { 1, "gethostname",vp,	"(\"%s\", %d)",	"%d",		},
  { 1, "getitimer",	vp,	"(%d, $%lx)",	"%d",		},
  { 1, "getpagesize",vp,	"()",		"%d",		},
  { 1, "getpgrp",	vp,	"(%d)",		"%d",		},
  { 1, "getpid",	vp,	"()",		"$%lx",		},
  { 1, "getppid",	vp,	"()",		"$%lx",		},
  { 1, "getpriority",vp,	"(%d, %d)",	"%d",		},
  { 1, "getpwnam",	vp,	"(\"%s\")",		"$%lx",		},
  { 1, "getpwuid",	vp,	"(%d)",		"$%lx",		},
  { 1, "getrlimit",	vp,	"(%d, $%lx)",	"%d",		},
  { 1, "getrusage",	vp,	"(%d, $%lx)",	"%d",		},
  { 1, "gettimeofday",vp,	"($%lx, $%lx)",	"%d",		},
  { 1, "getuid",	vp,	"()",		"%d",		},
  { 1, "getwd",	vp,	"(\"%s\")",		"%d",		},
  { 1, "index",	vp,	"(\"%s\", %c)",	"$%lx",		},
  { 1, "initgroups",	vp,	"(\"%s\", %d)",	"%d",		},
  { 1, "insque",	vp,	"($%lx, $%lx)",	"",		},
  { 1, "ioctl",		vp_ioctl,	"(%d, $%lx, $%lx)", "%d",		},
  { 1, "isalnum",	vp,	"(%c)",		"%d",		},
  { 1, "isalpha",	vp,	"(%c)",		"%d",		},
  { 1, "isatty",	vp,	"(%d)",		"%d",		},
  { 1, "iscntrl",	vp,	"(%c)",		"%d",		},
  { 1, "isdigit",	vp,	"(%c)",		"%d",		},
  { 1, "isgraph",	vp,	"(%c)",		"%d",		},
  { 1, "islower",	vp,	"(%c)",		"%d",		},
  { 1, "isprint",	vp,	"(%c)",		"%d",		},
  { 1, "ispunct",	vp,	"(%c)",		"%d",		},
  { 1, "isspace",	vp,	"(%c)",		"%d",		},
  { 1, "isupper",	vp,	"(%c)",		"%d",		},
  { 1, "isxdigit",	vp,	"(%c)",		"%d",		},
  { 1, "ix_startup",	vp,	"(\"%s\", %d, %d, \"%s\", $%lx, $%lx)", "%d",		},
  { 1, "kill",	vp,	"($%lx, %d)",	"%d",		},
  { 1, "killpg",	vp,	"($%lx, %d)",	"%d",		},
  { 1, "labs",	vp,	"(%d)",		"%d",		},
  { 1, "ldiv",	vp,	"(%d, %d)",	"%d",		},
  { 1, "link",	vp,	"(\"%s\", \"%s\")",	"%d",		},
  { 1, "longjmp",	vp,	"($%lx, %d)",	"%d",		},
  { 1, "longjmperror",vp,	"()",		"",		},
  { 1, "lseek",	vp,	"(%d, %d, %d)",	"%d",		},
  { 1, "lstat",	vp,	"(\"%s\", $%lx)",		"%d",		},
  { 1, "malloc",	vp,	"(%d)",		"$%lx",		},
  { 1, "memalign",	vp,	"(%d, %d)",	"$%lx",		},
  { 1, "memccpy",	vp,	"($%lx, $%lx, %d, %d)", "$%lx",		},
  { 1, "memchr",	vp,	"($%lx, %d, %d)",	"$%lx",		},
  { 1, "memcmp",	vp,	"($%lx, $%lx, %d)",	"%d",		},
  { 1, "memcpy",	vp,	"($%lx, $%lx, %d)",	"$%lx",		},
  { 1, "memmove",	vp,	"($%lx, $%lx, %d)",	"$%lx",		},
  { 1, "memset",	vp,	"($%lx, %d, %d)",	"$%lx",		},
  { 1, "mkdir",	vp,	"(\"%s\", %o)",	"%d",		},
  { 1, "mkstemp",	vp,	"(\"%s\")",		"%d",		},
  { 1, "mktemp",	vp,	"(\"%s\")",		"\"%s\"",		},
  { 1, "open",	vp_open,	"(\"%s\", \"%s\", %o)",	"%d",		},
  { 1, "pause",	vp,	"()",	"%d",		},
  { 1, "perror",	vp,	"(\"%s\")",	"%d",		},
  { 1, "pipe",	vp_pipe,	"([%d, %d])",	"%d",		},
  { 1, "psig",	vp,	"bad call",	"",		},
  { 1, "psignal",	vp,	"(%d, \"%s\")",	"",		},
  { 1, "putenv",	vp,	"(\"%s\")",		"",		},
  { 1, "qsort",	vp,	"($%lx, %d, %d, $%lx)",	"",		},
  { 1, "rand",	vp,	"()",	"%d",		},
  { 1, "random",	vp,	"()",	"%d",		},
  { 1, "read",	vp,	"(%d, $%lx, %d)",	"%d",		},
  { 1, "readlink",	vp,	"(\"%s\", \"%s\", %d)",		"%d",		},
  { 1, "readv",	vp,	"(%d, $%lx, %d)",	"%d",		},
  { 1, "realloc",	vp,	"($%lx, %d)",	"$%lx",		},
  { 1, "remove",	vp,	"(\"%s\")",	"%d",		},
  { 1, "remque",	vp,	"($%lx)",	"",		},
  { 1, "rename",	vp,	"(\"%s\", \"%s\")",	"%d",		},
  { 1, "rindex",	vp,	"(\"%s\", %c)",	"$%lx",		},
  { 1, "rmdir",	vp,	"(\"%s\")",	"%d",		},
  { 1, "select",	vp,	"(%d, $%lx, $%lx, $%lx, $%lx)",	"%d",		},
  { 1, "setenv",	vp,	"(\"%s\", \"%s\", %d)",	"%d",		},
  { 1, "setgroups",	vp,	"(%d, $%lx)",	"%d",		},
  { 1, "sethostname",vp,	"(\"%s\", %d)",	"%d",		},
  { 1, "setitimer",	vp,	"(%d, $%lx, $%lx)",	"%d",		},
  { 1, "setjmp",	vp,	"($%lx, %d)",	"%d",		},
  { 1, "setpgrp",	vp,	"($%lx, $%lx)",	"%d",		},
  { 1, "setpriority",vp,	"(%d, %d, %d)",	"%d",		},
  { 1, "setrlimit",	vp,	"(%d, $%lx)",	"%d",		},
  { 1, "settimeofday",vp,	"($%lx, $%lx)",	"%d",		},
  { 1, "sigaction",	vp,	"(%d, $%lx, $%lx)",	"%d",		},
  { 1, "sigaddset",	vp,	"($%lx, %d)",	"%d",		},
  { 1, "sigblock",	vp,	"($%lx)",	"%d",		},
  { 1, "sigdelset",	vp,	"($%lx, %d)",	"%d",		},
  { 1, "sigemptyset",vp,	"($%lx)",	"%d",		},
  { 1, "sigfillset",	vp,	"($%lx)",	"%d",		},
  { 1, "siginterrupt",vp,	"(%d, %d)",	"%d",		},
  { 1, "sigismember",vp,	"($%lx, %d)",	"%d",		},
  { 1, "siglongjmp",	vp,	"($%lx, %d)",	"%d",		},
  { 1, "signal",	vp,	"(%d, $%lx)",	"$%lx",		},
  { 1, "sigpause",	vp,	"($%lx)",	"%d",		},
  { 1, "sigpending",	vp,	"($%lx)",	"%d",		},
  { 1, "sigprocmask",vp,	"(%d, $%lx, $%lx)",	 "%d",		},
  { 1, "sigreturn",	vp,	"($%lx)",	"%d",		},
  { 1, "sigsetjmp",	vp,	"($%lx, %d)",	"%d",		},
  { 1, "sigsetmask",	vp,	"($%lx)",	"$%lx",		},
  { 1, "sigstack",	vp,	"($%lx)",	"%d",		},
  { 1, "sigsuspend",	vp,	"($%lx)",	"%d",		},
  { 1, "sigvec",	vp,	"(%d, $%lx, $%lx)",	"%d",		},
  { 1, "sleep",	vp,	"(%d)",	"%d",		},
  { 1, "srand",	vp,	"(%d)",	"",		},
  { 1, "srandom",	vp,	"(%d)",	"",		},
  { 1, "stat",	vp,	"(\"%s\", $%lx)",	"%d",		},
  { 1, "strcasecmp",	vp,	"(\"%s\", \"%s\")",	"%d",		},
  { 1, "strcat",	vp,	"(\"%"LWS"s\", \"%"LWS"s\")",	"$%lx",		},
  { 1, "strchr",	vp,	"(\"%s\", %c)",	"$%lx",		},
  { 1, "strcmp",	vp,	"(\"%"LWS"s\", \"%"LWS"s\")",	"%d",		},
  { 1, "strcoll",	vp,	"(\"%s\", \"%s\")",	"%d",		},
  { 1, "strcpy",	vp,	"($%lx, \"%s\")",	"$%lx",		},
  { 1, "strcspn",	vp,	"(\"%s\", \"%s\")",	"%d",		},
  { 1, "strdup",	vp,	"(\"%s\")",		"$%lx",		},
  { 1, "strerror",	vp,	"(%d)",		"\"%s\"",		},
  { 1, "strftime",	vp,	"(\"%s\", %d, \"%s\", $%lx)", "%d",		},
  { 1, "strlen",	vp,	"(\"%s\")",	"%d",		},
  { 1, "strmode",	vp,	"(\"%s\", %o)",	"",		},
  { 1, "strncasecmp",vp,	"(\"%s\", \"%s\", %d)",	"%d",		},
  { 1, "strncat",	vp,	"(\"%s\", \"%s\", %d)",	"$%lx",		},
  { 1, "strncmp",	vp,	"(\"%"LWS"s\", \"%"LWS"s\", %d)",	"%d",		},
  { 1, "strncpy",	vp,	"($%lx, \"%s\", %d)", "$%lx",		},
  { 1, "strpbrk",	vp,	"(\"%s\", \"%s\")",	"$%lx",		},
  { 1, "strrchr",	vp,	"(\"%s\", %c)",	"$%lx",		},
  { 1, "strsep",	vp,	"($%lx, \"%s\")",	"\"%s\"",		},
  { 1, "strspn",	vp,	"(\"%s\", \"%s\")",	"%d",		},
  { 1, "strstr",	vp,	"(\"%s\", \"%s\")",	"\"%s\"",		},
  { 1, "strtok",	vp,	"(\"%s\", \"%s\")",	"\"%s\"",		},
  { 1, "strtol",	vp,	"(\"%s\", $%lx, %d)",	"%d",		},
  { 1, "strtoul",	vp,	"(\"%s\", $%lx, %d)",	"%d",		},
  { 1, "strunvis",	vp,	"(\"%s\", \"%s\")",	"%d",		},
  { 1, "strvis",	vp,	"(\"%s\", \"%s\")",	"%d",		},
  { 1, "strvisx",	vp,	"(\"%s\", \"%s\", %d, %d)",	"%d",		},
  { 1, "strxfrm",	vp,	"(\"%s\", \"%s\", %d)",	"%d",		},
  { 1, "swab",	vp,	"($%lx, $%lx, %d)",	"",		},
  { 1, "symlink",	vp,	"(\"%s\", \"%s\")",	"%d",		},
  { 1, "system",	vp,	"(\"%s\")",	"%d",		},
  { 1, "tcgetattr",	vp,	"(%d, $%lx)",	"%d",		},
  { 1, "tcgetpgrp",	vp,	"(%d)",	"$%lx",		},
  { 1, "tcsetattr",	vp,	"(%d, $%lx)",	"%d",		},
  { 1, "tcsetpgrp",	vp,	"(%d, $%lx)",	"%d",		},
  { 1, "time",	vp,	"($%lx)",	"%d",		},
  { 1, "tmpnam",	vp,	"(\"%s\")",	"\"%s\"",		},
  { 1, "tolower",	vp,	"(%c)",	"%c",		},
  { 1, "toupper",	vp,	"(%c)", "%c",		},
  { 1, "truncate",	vp,	"(\"%s\", %d)",	"%d",		},
  { 1, "ualarm",	vp,	"(%d, %d)",	"%d",		},
  { 1, "umask",	vp,	"(%o)",	"%d",		},
  { 1, "unlink",	vp,	"(\"%s\")",	"%d",		},
  { 1, "unvis",	vp,	"(\"%s\", %c, $%lx, %d)",	"%d",		},
  { 1, "usleep",	vp,	"(%d)",	"%d",		},
  { 1, "utime",	vp,	"(\"%s\", $%lx)",	"%d",		},
  { 1, "utimes",	vp,	"(\"%s\", $%lx)",	"%d",		},
  { 1, "valloc",	vp,	"(%d)",	"$%lx",		},
  { 1, "vis",	vp,	"(\"%s\", %c, $%lx, %d)",	"\"%s\"",		},
  { 1, "write",	vp,	"(%d, $%lx, %d)",	"%d",		},
  { 1, "writev",	vp,	"(%d, $%lx, %d)",	"%d",		},
  { 1, "_exit",	vp,	"(%d)",	"",		},
  { 1, "_longjmp",	vp,	"($%lx, %d)",	"",		},
  { 1, "_setjmp",	vp,	"($%lx)",	"%d",		},
  { 1, "_wb_parse",	vp,	"($%lx, $%lx, \"%s\")",	"%d",		},
  { 1, "_cli_parse",	vp,	"($%lx, %d, \"%s\", $%lx, $%lx)",	"%d",		},
  { 1, "_main",	vp,	"($%lx, $%lx, $%lx)",	"%d",		},
  { 0, "__adddf3",	vp,	"(%g, %g)",	"%g",		},
  { 0, "__addsf3",	vp,	"(%g, %g)",	"%g",		},
  { 0, "__ashldi3",	vp,	"($%0lx%08lx, %d)", "$%0lx%08lx",		},
  { 0, "__ashlsi3",	vp,	"(%d)",	"%d",		},
  { 0, "__ashrdi3",	vp,	"($%0lx%08lx, %d)", "$%0lx%08lx",		},
  { 0, "__ashrsi3",	vp,	"(%d)",	"%d",		},
  { 0, "__clear_cache",vp,	"()","",		},
  { 0, "__cmpdf2",	vp,	"(%g, %g)",	"%d",		},
  { 0, "__cmpdi2",	vp,	"($%0lx%08lx, $%0lx%08lx)", "%d",		},
  { 0, "__cmpsf2",	vp,	"(%g, %g)",	"%d",		},
  { 0, "__divdf3",	vp,	"(%g, %g)",	"%g",		},
  { 0, "__divdi3",	vp,	"($%0lx%08lx, $%0lx%08lx)", "$%0lx%08lx",		},
  { 0, "__divsf3",	vp,	"(%g, %g)",	"%g",		},
  { 0, "__divsi3",	vp,	"(%d, %d)",	"%d",		},
  { 0, "__eqdf2",	vp,	"(%g, %g)",	"%d",		},
  { 0, "__eqsf2",	vp,	"(%g, %g)",	"%d",		},
  { 0, "__extendsfdf2",vp,	"(%g)",	"%g",		},
  { 0, "__fixdfdi",	vp,	"(%g)", "$%0lx%08lx)",		},
  { 0, "__fixdfsi",	vp,	"(%g)",	"%g",		},
  { 0, "__fixsfdi",	vp,	"(%g)",	"$%0lx%08lx",		},
  { 0, "__fixsfsi",	vp,	"(%g)",	"%d",		},
  { 0, "__fixunsdfdi",vp,	"(%g)",	"$%0lx%08lx",		},
  { 0, "__fixunsdfsi",vp,	"(%g)",	"%d",		},
  { 0, "__fixunssfdi",vp,	"(%g)",	"$%0lx%08lx",		},
  { 0, "__fixunssfsi",vp,	"(%g)",	"%d",		},
  { 0, "__floatdidf",vp,	"($%0lx%08lx)","%g",		},
  { 0, "__floatdisf",vp,	"($%0lx%08lx)","%g",		},
  { 0, "__floatsidf",vp,	"(%d)",	"%g",		},
  { 0, "__floatsisf",vp,	"(%d)",	"%g",		},
  { 0, "__gedf2",	vp,	"(%g, %g)",	"%d",		},
  { 0, "__gesf2",	vp,	"(%g, %g)",	"%d",		},
  { 0, "__gtdf2",	vp,	"(%g, %g)",	"%d",		},
  { 0, "__gtsf2",	vp,	"(%g, %g)",	"%d",		},
  { 0, "__ledf2",	vp,	"(%g, %g)",	"%d",		},
  { 0, "__lesf2",	vp,	"(%g, %g)",	"%d",		},
  { 0, "__lshldi3",	vp,	"($%0lx%08lx, %d)", "($%0lx%08lx)",		},
  { 0, "__lshlsi3",	vp,	"(%d, %d)",	"%d",		},
  { 0, "__lshrdi3",	vp,	"($%0lx%08lx, %d)", "($%0lx%08lx)",		},
  { 0, "__lshrsi3",	vp,	"(%d, %d)",	"%d",		},
  { 0, "__ltdf2",	vp,	"(%g, %g)",	"%d",		},
  { 0, "__ltsf2",	vp,	"(%g, %g)",	"%d",		},
  { 0, "__moddi3",	vp,	"($%0lx%08lx, $%0lx%08lx)",	"$%0lx%08lx",		},
  { 0, "__modsi3",	vp,	"(%d, %d)",	"%d",		},
  { 0, "__muldf3",	vp,	"(%g, %g)",	"%g",		},
  { 0, "__muldi3",	vp,	"($%0lx%08lx, $%0lx%08lx)",	"$%0lx%08lx",		},
  { 0, "__mulsf3",	vp,	"(%g, %g)",	"%g",		},
  { 0, "__mulsi3",	vp,	"(%d, %d)",	"%d",		},
  { 0, "__nedf2",	vp,	"(%g, %g)",	"%d",		},
  { 0, "__negdf2",	vp,	"(%g)",	"%g",		},
  { 0, "__negdi2",	vp,	"($%0lx%08lx)",	"$%0lx%08lx",		},
  { 0, "__negsf2",	vp,	"(%g)",	"%g",		},
  { 0, "__nesf2",	vp,	"(%g)",	"%g",		},
  { 0, "__subdf3",	vp,	"(%g, %g)",	"%g",		},
  { 0, "__subsf3",	vp,	"(%g, %g)",	"%g",		},
  { 0, "__truncdfsf2",vp,	"(%g)",	"%g",		},
  { 0, "__ucmpdi2",	vp,	"($%0lx%08lx, $%0lx%08lx)",	"%d",		},
  { 0, "__udivdi3",	vp,	"($%0lx%08lx, $%0lx%08lx)", "$%0lx%08lx",		},
  { 0, "__udivmoddi4",vp,	"($%0lx%08lx, $%0lx%08lx, $%0lx%08lx, $%0lx%08lx)", "",		},
  { 0, "__udivsi3",	vp,	"(%d, %d)",	"%d",		},
  { 0, "__umoddi3",	vp,	"($%0lx%08lx, $%0lx%08lx)",	"$%0lx%08lx",		},
  { 0, "__umodsi3",	vp,	"(%d, %d)",	"%d",		},
  { 1, "ix_get_vars",vp,	"($%lx, $%lx)",	"",		},
  { 1, "modf",	vp,	"(%g, $%lx)",	"%g",		},
  { 1, "opendir",	vp,	"(\"%s\")",	"$%lx",		},
  { 1, "readdir",	vp,	"($%lx)",	"$%lx",		},
  { 1, "rewinddir",	vp,	"($%lx)",	"",		},
  { 1, "closedir",	vp,	"($%lx)",	"",		},
  { 1, "telldir",	vp,	"($%lx)",	"%d",		},
  { 1, "seekdir",	vp,	"($%lx, %d)",	"%d",		},
  { 1, "ssystem",	vp,	"(\"%s\")",	"%d",		},
  { 1, "isinf",	vp,	"(%g)",	"%d",		},
  { 1, "isnan",	vp,	"(%g)",	"%d",		},
  { 1, "ldexp",	vp,	"(%g, %d)",	"%g",		},
  { 1, "achmod",	vp,	"(\"%s\", $%lx)",	"%d",		},
  { 1, "stricmp",	vp,	"(\"%s\", \"%s\")",	"%d",		},
  { 1, "strnicmp",	vp,	"(\"%s\", \"%s\", %d)",	"%d",		},
  { 1, "atan",	vp,	"(%g)",	"%g",		},
  { 1, "sin",	vp,	"(%g)",	"%g",		},
  { 1, "cos",	vp,	"(%g)",	"%g",		},
  { 1, "tan",	vp,	"(%g)",	"%g",		},
  { 1, "sincos",	vp,	"($%lx, %g)",	"%g",		},
  { 1, "sinh",	vp,	"(%g)",	"%g",		},
  { 1, "cosh",	vp,	"(%g)",	"%g",		},
  { 1, "tanh",	vp,	"(%g)",	"%g",		},
  { 1, "exp",	vp,	"(%g)",	"%g",		},
  { 1, "log",	vp,	"(%g)",	"%g",		},
  { 1, "pow",	vp,	"(%g, %g)",	"%g",		},
  { 1, "sqrt",	vp,	"(%g)",	"%g",		},
  { 1, "asin",	vp,	"(%g)",	"%g",		},
  { 1, "acos",	vp,	"(%g)",	"%g",		},
  { 1, "log10",	vp,	"(%g)",	"%g",		},
  { 1, "fabs",	vp,	"(%g)",	"%g",		},
  { 1, "initstate",	vp,	"(%d, $%lx, %d)",	"$%lx",		},
  { 1, "setstate",	vp,	"($%lx)",	"$%lx",		},
  { 1, "ix_exec_entry",vp,	"(%d, $%lx, $%lx, $%lx, $%lx)",	"%d",		},
  { 1, "ix_get_vars2",vp,	"(%d, $%lx, $%lx, $%lx, $%lx, $%lx, $%lx)",	"",		},
  { 1, "execve",	vp,	"(\"%s\", $%lx, $%lx)",	"%d",		},
  { 1, "execl",	vp,	"(\"%s\", \"%s\", \"%s\", ...)",	"%d",		},
  { 1, "execv",	vp,	"(\"%s\", $%lx)",	"%d",		},
  { 1, "execle",	vp,	"(\"%s\", $%lx, $%lx)",	"%d",		},
  { 1, "execlp",	vp,	"(\"%s\", \"%s\", \"%s\", ...)",	"%d",		},
  { 1, "execvp",	vp,	"(\"%s\", $%lx)",	"%d",		},
  { 1, "vfork",	vp,	"()",	"%d",		},
  { 1, "wait4",	vp,	"($%lx, $%lx, $%lx, $%lx)",	"%d",		},
  { 1, "wait",	vp,	"($%lx)",	"%d",		},
  { 1, "wait3",	vp,	"($%lx, $%lx, $%lx)",	"%d",		},
  { 1, "waitpid",	vp,	"($%lx, $%lx, $%lx)",	"%d",		},
  { 1, "vfork_resume",vp,	"()",	"",		},
  { 1, "profil",	vp,	"($%lx, %d, %d, $%lx)",	"%d",		},
  { 1, "ptrace",	vp,	"(%d, $%lx, $%lx, $%lx)",	"%d",		},
  { 1, "clearerr",	vp,	"($%lx)",	"",		},
  { 1, "fclose",	vp,	"($%lx)",	"%d",		},
  { 1, "fdopen",	vp,	"(%d, \"%s\")",	"$%lx",		},
  { 1, "feof",	vp,	"($%lx)",	"%d",		},
  { 1, "ferror",	vp,	"($%lx)",	"%d",		},
  { 1, "fflush",	vp,	"($%lx)",	"%d",		},
  { 1, "fgetc",	vp,	"($%lx)",	"%d",		},
  { 1, "fgetline",	vp,	"($%lx, $%lx)",	"\"%s\"",		},
  { 1, "fgetpos",	vp,	"($%lx, $%lx)",	"%d",		},
  { 1, "fgets",	vp,	"(\"%s\", %d, $%lx)",	"$%lx",		},
  { 1, "fileno",	vp,	"($%lx)",	"%d",		},
  { 1, "f_prealloc",	vp,	"()",	"",		},
  { 1, "fopen",	vp,	"(\"%s\", \"%s\")",	"$%lx",		},
  { 1, "fprintf",	vp,	"($%lx, \"%s\", ...)",	"%d",		},
  { 1, "fpurge",	vp,	"($%lx)",	"%d",		},
  { 1, "fputc",	vp,	"(%d, $%lx)",	"%d",		},
  { 1, "fputs",	vp,	"(\"%s\", $%lx)",	"%d",		},
  { 1, "fread",	vp,	"($%lx, %d, %d, $%lx)",	"%d",		},
  { 1, "freopen",	vp,	"(\"%s\", \"%s\", $%lx)",	"$%lx",		},
  { 1, "fscanf",	vp,	"($%lx, \"%s\", ...)",	"%d",		},
  { 1, "fseek",	vp,	"($%lx, %d, %d)",	"%d",		},
  { 1, "fsetpos",	vp,	"($%lx, $%lx)",	"%d",		},
  { 1, "ftell",	vp,	"($%lx)",	"%d",		},
  { 1, "funopen",	vp,	"($%lx, $%lx, $%lx, $%lx, $%lx)",	"%d",		},
  { 1, "fwrite",	vp,	"($%lx, %d, %d, $%lx)",	"%d",		},
  { 1, "getc",	vp,	"($%lx)",	"%d",		},
  { 1, "getchar",	vp,	"()",	"%d",		},
  { 1, "gets",	vp,	"(\"%s\")",	"\"%s\"",		},
  { 1, "getw",	vp,	"($%lx)",	"%d",		},
  { 1, "printf",	vp,	"(\"%s\", ...)",	"%d",		},
  { 1, "putc",	vp,	"(%d, $%lx)",	"%d",		},
  { 1, "putchar",	vp,	"(%d)",	"%d",		},
  { 1, "puts",	vp,	"(\"%s\")",	"%d",		},
  { 1, "putw",	vp,	"(%d, $%lx)",	"%d",		},
  { 1, "rewind",	vp,	"($%lx)",	"%d",		},
  { 1, "scanf",	vp,	"(\"%s\", ...)",	"%d",		},
  { 1, "setbuf",	vp,	"($%lx, $%lx)",	"",		},
  { 1, "setbuffer",	vp,	"($%lx, $%lx, %d)",	"",		},
  { 1, "setlinebuf",	vp,	"($%lx)",	"",		},
  { 1, "setvbuf",	vp,	"($%lx, $%lx, %d, %d)",	"%d",		},
  { 1, "snprintf",	vp,	"(\"%s\", %d, \"%s\", ...)",	"%d",		},
  { 1, "sprintf",	vp,	"($%lx, \"%s\", ...)",	"%d",		},
  { 1, "sscanf",	vp,	"(\"%s\", \"%s\", ...)",	"%d",		},
  { 1, "tempnam",	vp,	"(\"%s\", \"%s\")",	"\"%s\"",		},
  { 1, "tmpfile",	vp,	"()",	"$%lx",		},
  { 1, "ungetc",	vp,	"(%d, $%lx)",	"%d",		},
  { 1, "vfprintf",	vp,	"($%lx, \"%s\", $%lx)",	"%d",		},
  { 1, "vprintf",	vp,	"(\"%s\", $%lx)",	"%d",		},
  { 1, "vscanf",	vp,	"(\"%s\", $%lx)",	"%d",		},
  { 1, "vsnprintf",	vp,	"(\"%s\", %d, \"%s\", $%lx)",	"%d",		},
  { 1, "vsprintf",	vp,	"(\"%s\", $%lx)",	"%d",		},
  { 1, "vsscanf",	vp,	"(\"%s\", \"%s\", $%lx)",	"%d",		},
  { 1, "crypt",	vp,	"(\"%s\", \"%s\")",	"\"%s\"",		},
  { 1, "des_cipher",	vp,	"(\"%s\", \"%s\", %d, %d)",	"%d",		},
  { 1, "des_setkey",	vp,	"(\"%s\")",	"%d",		},
  { 1, "encrypt",	vp,	"(\"%s\", %d)", "%d",		},
  { 1, "setkey",	vp,	"(\"%s\")",	"%d",		},
  { 1, "fnmatch",	vp,	"(\"%s\", \"%s\", %d)",	"%d",		},
  { 1, "fts_children",vp,	"($%lx)",	"$%lx",		},
  { 1, "fts_close",	vp,	"($%lx)",	"%d",		},
  { 1, "fts_open",	vp,	"($%lx, %d, $%lx)",	"$%lx",		},
  { 1, "fts_read",	vp,	"($%lx)",	"$%lx",		},
  { 1, "fts_set",	vp,	"($%lx, $%lx, %d)",	"%d",		},
  { 1, "cuserid",	vp,	"(\"%s\")",	"\"%s\"",		},
  { 1, "getlogin",	vp,	"()",	"\"%s\"",		},
  { 1, "glob",	vp,	"(\"%s\", %d, $%lx, $%lx)",	"%d",		},
  { 1, "globfree",	vp,	"($%lx)",	"",		},
  { 1, "__amiga_filehandle",vp,	"(%d)",	"$%lx",		},
  { 1, "times",	vp,	"($%lx)",	"$%lx",		},
  { 1, "mblen",	vp,	"(\"%s\", %d)",	"%d",		},
  { 1, "mbstowcs",	vp,	"($%lx, \"%s\", %d)",	"%d",		},
  { 1, "mbtowc",	vp,	"($%lx, \"%s\", %d)",	"%d",		},
  { 1, "wcstombs",	vp,	"(\"%s\", $%lx, %d)",	"%d",		},
  { 1, "wctomb",	vp,	"(\"%s\", $%lx)",	"%d",		},
  { 1, "heapsort",	vp,	"($%lx, %d, %d, $%lx)",	"%d",		},
  { 1, "radixsort",	vp,	"($%lx, %d, \"%s\", %d)",	"%d",		},
  { 0, "__sflush",	vp,	"()",	"",		},
  { 0, "__slbexpand",vp,	"()",	"",		},
  { 0, "__sfp",	vp,	"()",	"",		},
  { 0, "__sflags",	vp,	"()",	"",		},
  { 0, "__sfvwrite",	vp,	"()",	"",		},
  { 0, "__smakebuf",	vp,	"()",	"",		},
  { 0, "__srefill",	vp,	"()",	"",		},
  { 0, "__srget",	vp,	"()",	"",		},
  { 0, "__sclose",	vp,	"()",	"",		},
  { 0, "__sread",	vp,	"()",	"",		},
  { 0, "__sseek",	vp,	"()",	"",		},
  { 0, "__swrite",	vp,	"()",	"",		},
  { 0, "__svfscanf",	vp,	"()",	"",		},
  { 0, "__swbuf",	vp,	"()",	"",		},
  { 0, "__swsetup",	vp,	"()",	"",		},
  { 1, "fchdir",	vp,	"(%d)",	"%d",		},
  { 1, "strtod",	vp,	"(\"%s\", $%lx)",	"%g",		},
  { 1, "setgrent",	vp,	"()",	"",		},
  { 1, "getgrent",	vp,	"()",	"",		},
  { 1, "endgrent",	vp,	"()",	"",		},
  { 1, "ix_resident",vp,	"(%d, $%lx, %d, $%lx)",	"",		},
  { 1, "ix_geta4",	vp,	"()",	"",		},
  { 1, "ix_check_cpu",vp,	"(%d)",	"",		},
  { 1, "tracecntl",	vp,	"(%d, $%lx)",	"%d",		},
  { 1, "sysconf",	vp,	"(%d)",	"%d",	},
  { 1, "pathconf",	vp,	"(\"%s\", %d)", "%d",	},
  { 1, "fpathconf",	vp,	"(%d, %d)",	"%d",	},
  { 1, "getfsstat",	vp,	"($%lx, %d, %d)", "%d",	},
  { 1, "fstatfs",	vp,	"(%d, $%lx)", "%d", },
  { 1, "getmntinfo",	vp,	"($%lx, %d)",	"%d", },
  { 1, "getgrnam",	vp,	"(\"%s\")",	"%d", },
  { 1, "endpwent",	vp,	"()",	"", },
  { 1, "sync",		vp,	"()",	"", },
  { 1, "fork",		vp,	"()",	"%d", },
  { 1, "mkfifo",	vp,	"(\"%s\", %o)",	"%d", },
  { 1, "mknod",		vp,	"(\"%s\", %o)",	"%d", },
  { 1, "setuid",	vp,	"(%d)",	"%d", },
  { 1, "nice",		vp,	"(%d)",	"%d", },
  { 1, "floor",		vp,	"(%g)",	"%g", },
  { 1, "ceil",		vp,	"(%g)",	"%g", },
  { 1, "setgid",	vp,	"(%d)",	"%d", },
  { 1, "vfork",		vp,	"()",	"%d", },
};

/* should help make things less mystic... */
#define TP_SCALL(tp) (tp->tp_argv[0])
/* this is only valid if !tp->tp_is_entry */
#define TP_RESULT(tp) (tp->tp_argv[1])
#define TP_ERROR(tp) (* tp->tp_errno)
/* tp_argv[2] is the return address */
#define TP_FIRSTARG(tp) (tp->tp_argv[3])

void
print_call (FILE *output, struct trace_packet *tp)
{
  char line[OUT_WIDTH+2];	/* for \n\0 */
  char *argfield;
  int space, len;
  struct call *c;

  space = sizeof (line) - 1;
  len = sprintf (line, "$%lx: %c", tp->tp_message.mn_ReplyPort,
  	         tp->tp_is_entry ? '>' : '<');
  argfield = line + len;
  space -= len;

  if (TP_SCALL (tp) > sizeof (call_table) / sizeof (struct call))
    {
      if (tp->tp_is_entry)
        sprintf (argfield, "SYS_%d()\n", TP_SCALL (tp));
      else
        sprintf (argfield, "SYS_%d() = $%lx (%d)\n", 
		  TP_SCALL (tp), TP_RESULT (tp), TP_ERROR (tp));
    }
  else
    {
      c = call_table + TP_SCALL (tp);

      if ((!print_all && !c->interesting) || 
	  (skip_sigsetmask && TP_SCALL (tp) == SYS_sigsetmask))
	return;

      /* we can write space-1 real characters in the buffer, \n is not counted */
      c->func (argfield, space-1, c, tp);
    }

  fputs (line, output);
}

/* the program contained a bug du to the fact that
 * when snprintf or vsnprintf are called with a zero or negative size,
 * they return -1 as an error marker but not any length.
 */
void
vp (char *buf, int len, struct call *c, struct trace_packet *tp)
{
  int nl = snprintf (buf, len+1, "%s", c->name);

  len -= nl; if (len <= 0) goto finish;
  buf += nl;
  if (tp->tp_is_entry || !c->rfmt[0])
    vsnprintf (buf, len+1, c->fmt, (_VA_LIST_) & TP_FIRSTARG (tp));
  else
    {
      nl = vsnprintf (buf, len+1, c->fmt, (_VA_LIST_) & TP_FIRSTARG (tp));
      len -= nl; if (len <= 0) goto finish;
      buf += nl;
      nl = snprintf (buf, len+1, "=");
      len -= nl; if (len <= 0) goto finish;
      buf += nl;
      nl = vsnprintf (buf, len+1, c->rfmt, (_VA_LIST_) & TP_RESULT (tp));
      len -= nl; if (len <= 0) goto finish;
      buf += nl;
      nl = snprintf (buf, len+1, " (%d)", TP_ERROR (tp));
    }

  finish:
  strcat (buf, "\n");
}

const char *
get_fcntl_cmd (int cmd)
{
  switch (cmd)
    {
    case F_DUPFD:
	return "F_DUPFD";

    case F_GETFD:
	return "F_GETFD";

    case F_SETFD:
	return "F_SETFD";

    case F_GETFL:
	return "F_GETFL";

    case F_SETFL:
	return "F_SETFL";
	
    case F_GETOWN:
	return "F_GETOWN";

    case F_SETOWN:
	return "F_SETOWN";

    case F_GETLK:
	return "F_GETLK";

    case F_SETLK:
	return "F_SETLK";

    case F_SETLKW:
	return "F_SETLKW";

    default:
	return "F_unknown";
    }
}

char *
get_open_mode (int mode)
{
  static char buf[120];
  
  switch (mode & O_ACCMODE)
    {
    case O_RDONLY: 
      strcpy (buf, "O_RDONLY");
      break;
      
    case O_WRONLY:
      strcpy (buf, "O_WRONLY");
      break;
      
    case O_RDWR:
      strcpy (buf, "O_RDWR");
      break;
      
    default:
      strcpy (buf, "O_illegal");
      break;
    }

#define ADD(flag) \
  if (mode & flag) strcat (buf, "|" #flag);

  ADD (O_NONBLOCK);  
  ADD (O_APPEND);
  ADD (O_SHLOCK);
  ADD (O_EXLOCK);
  ADD (O_ASYNC);
  ADD (O_FSYNC);
  ADD (O_CREAT);
  ADD (O_TRUNC);
  ADD (O_EXCL);
#undef ADD
  
  return buf;
}

char *
get_ioctl_cmd (int cmd)
{
  static char buf[12];

  /* only deal with those commands that are really implemented somehow in
     ixemul.library. The others are dummies anyway, so they don't matter */

  switch (cmd)
    {
    case FIONREAD:
      return "FIONREAD";

    case FIONBIO:
      return "FIONBIO";

    case FIOASYNC:
      /* not yet implemented, but important to know if some program tries
         to use it ! */
      return "FIOASYNC";

    case TIOCGETA:
      return "TIOCGETA";

    case TIOCSETA:
      return "TIOCSETA";

    case TIOCSETAW:
      return "TIOCSETAW";

    case TIOCSETAF:
      return "TIOCSETAF";

    case TIOCGETP:
      return "TIOCGETP";

    case TIOCSETN:
      return "TIOCSETN";

    case TIOCSETP:
      return "TIOCSETP";

    case TIOCGWINSZ:
      return "TIOCGWINSZ";

    case TIOCOUTQ:
      return "TIOCOUTQ";

    case TIOCSWINSZ:
      return "TIOCSWINSZ";
      
    default:
      sprintf (buf, "$%lx", cmd);
      return buf;
    }
}


void
vp_fcntl (char *buf, int len, struct call *c, struct trace_packet *tp)
{
  long *argv = & TP_FIRSTARG (tp);
  
  if (tp->tp_is_entry)
    if (argv[1] == F_GETFL || argv[1] == F_SETFL)
      snprintf (buf, len+1, "fcntl(%d, %s, %s)",
	        argv[0], get_fcntl_cmd (argv[1]), get_open_mode (argv[2]));
    else
      snprintf (buf, len+1, "fcntl(%d, %s, %d)",
	        argv[0], get_fcntl_cmd (argv[1]), argv[2]);
  else
    if (argv[1] == F_GETFL || argv[1] == F_SETFL)
      snprintf (buf, len+1, "fcntl(%d, %s, %s) = %d (%d)",
	        argv[0], get_fcntl_cmd (argv[1]), 
		get_open_mode (argv[2]), TP_RESULT (tp), TP_ERROR (tp));
    else
      snprintf (buf, len+1, "fcntl(%d, %s, %d) = %d (%d)",
	        argv[0], get_fcntl_cmd (argv[1]), argv[2], 
		TP_RESULT (tp), TP_ERROR (tp));

  strcat (buf, "\n");
}


void
vp_ioctl (char *buf, int len, struct call *c, struct trace_packet *tp)
{
  long *argv = & TP_FIRSTARG (tp);
  
  if (tp->tp_is_entry)
    snprintf (buf, len+1, "ioctl(%d, %s, $%lx)",
	      argv[0], get_ioctl_cmd (argv[1]), argv[2]);
  else
    snprintf (buf, len+1, "ioctl(%d, %s, $%lx) = %d (%d)",
	      argv[0], get_ioctl_cmd (argv[1]), argv[2],
	      TP_RESULT (tp), TP_ERROR (tp));

  strcat (buf, "\n");
}


void
vp_open (char *buf, int len, struct call *c, struct trace_packet *tp)
{
  long *argv = & TP_FIRSTARG (tp);

  if (tp->tp_is_entry)
    snprintf (buf, len+1, "open(\"%s\", %s)", argv[0], get_open_mode (argv[1]));
  else
    snprintf (buf, len+1, "open(\"%s\", %s) = %d (%d)", argv[0], 
	      get_open_mode (argv[1]), TP_RESULT (tp), TP_ERROR (tp));

  strcat (buf, "\n");
}

void
vp_pipe (char *buf, int len, struct call *c, struct trace_packet *tp)
{
  long *argv = & TP_FIRSTARG (tp);

  if (tp->tp_is_entry)
    snprintf (buf, len+1, "pipe($%lx)", argv[0]);
  else
    {
      int *pv = (int *) argv[0];
    
      snprintf (buf, len+1, "pipe([%d, %d]) = %d (%d)", 
		pv[0], pv[1], TP_RESULT (tp), TP_ERROR (tp));
    }

  strcat (buf, "\n");
}
