#include <stdio.h>
#include <string.h>
#ifndef NO_UNISTD_H
#include <sys/unistd.h>
#endif

/* A simple glue file for embedded targets so we can get the real exit
   status from the program. This assumes we're using GNU ld and can use
   the -wrap option, and that write(1, ...) does something useful. */

/* There is a bunch of weird cruft with #ifdef UNDERSCORES. This is needed
   because currently GNU ld doesn't deal well with a.out targets and
   the -wrap option. When GNU ld is fixed, this should definitely be
   removed. Note that we actually wrap __exit, not _exit on a target
   that has UNDERSCORES defined.  On non-UNDERSCORE targets, we
   wrap _exit separately; it's actually a different function.  */

#ifdef WRAP_M68K_AOUT
#define REAL_EXIT(code) asm ( "trap %0" : : "i" (0) );
#define REAL_ABORT() REAL_EXIT(6)
#define ORIG_EXIT _exit
#define ORIG_ABORT abort
#else
#ifdef UNDERSCORES
#define REAL_EXIT _real___exit
#define REAL_MAIN _real__main
#define REAL_ABORT _real__abort
#define ORIG_EXIT _wrap___exit
#define ORIG_ABORT _wrap__abort
#define ORIG_MAIN _wrap__main
#else
#define REAL_EXIT __real_exit
#ifndef VXWORKS
#define REAL__EXIT __real__exit
#endif
#define REAL_MAIN __real_main
#define REAL_ABORT __real_abort
#define ORIG_EXIT __wrap_exit
#define ORIG__EXIT __wrap__exit
#define ORIG_ABORT __wrap_abort
#define ORIG_MAIN __wrap_main
#endif
#endif

#ifdef REAL_MAIN
extern void REAL_EXIT ();
extern void REAL_ABORT ();
extern int REAL_MAIN (int argc, char **argv, char **envp);
#endif
#ifdef REAL__EXIT
extern void REAL__EXIT ();
#endif

static int done_exit_message = 0;

int ___constval = 1;

#ifdef VXWORKS
static void __runexit();
#endif

static char *
write_int(val, ptr)
     int val;
     char *ptr;
{
  char c;
  if (val<0) {
    *(ptr++) = '-';
    val = -val;
  }
  if (val>9) {
    ptr = write_int (val/10, ptr);
  }
  c = (val%10)+'0';
  *(ptr++) = c;
  return ptr;
}

void
ORIG_EXIT (code)
     int code;
{
  char buf[30];
  char *ptr;

#ifdef VXWORKS
  __runexit ();
#endif
  strcpy (buf, "\n*** EXIT code ");
  ptr = write_int (code, buf + strlen(buf));
  *(ptr++) = '\n';
  write (1, buf, ptr-buf);
  done_exit_message = 1;
  REAL_EXIT (code);
  while (___constval);
}

#ifdef ORIG__EXIT
void
ORIG__EXIT (code)
     int code;
{
  char buf[30];
  char *ptr;

  /* Since exit may call _exit, we need to avoid a second message.  */
  if (! done_exit_message)
    {
      strcpy (buf, "\n*** EXIT code ");
      ptr = write_int (code, buf + strlen(buf));
      *(ptr++) = '\n';
      write (1, buf, ptr-buf);
    }

  REAL__EXIT (code);
  while (___constval);
}
#endif

void
ORIG_ABORT ()
{
  write (1, "\n*** EXIT code 4242\n", 20);
  REAL_ABORT ();
  while (___constval);
  abort ();
}

#ifdef REAL_MAIN
int
ORIG_MAIN (argc, argv, envp)
     int argc;
     char **argv;
     char **envp;
{
#ifdef WRAP_FILE_ARGS
  extern int __argc;
  extern char *__args[];

  exit (REAL_MAIN (__argc,__args,envp));
#else
  exit (REAL_MAIN (argc, argv, envp));
#endif
  while (___constval);
}
#endif

#ifdef VXWORKS
void
_exit (status)
     int status;
{
  REAL_EXIT (status);
}

typedef (*PFV)(void);

static PFV __list[32];
static int __listcnt = 0;
static int __running = 0;

int
atexit (PFV func)
{
  __list[__listcnt++] = func;
}

static void
__runexit ()
{
  int i;
  if (__running++)
    return;

  for (i = 0; i < __listcnt; i++)
    __list[i]();
  __running = 0;
}
#endif
