#include <sys/types.h>
#include <sys/syscall.h>

#include <stdio.h>

struct syscall {
  char *name;
  int   vec;
} syscalls[] = {
#define SYSTEM_CALL(func,vec) { #func, vec},
#include <sys/syscall.def>
#undef SYSTEM_CALL
};

int nsyscall = sizeof(syscalls) / sizeof (syscalls[0]);

#define BASEREL                         \
"\txref\t_ixemulbase\n\txdef\t_%s\n_%s\n\tmove.l\t_ixemulbase(a4),a0\n\tjmp\t%d(a0)\n"

#define BASEREL_IX_GETA4                \
"\txref\t_ixemulbase\n\txdef\t_%s\n_%s\n\tmove.l\t_ixemulbase,a0\n\tjmp\t%d(a0)\n"

#define NOBASEREL                       \
"\txref\t_ixemulbase\n\txdef\t_%s\n_%s\n\tmove.l\t_ixemulbase,a0\n\tjmp\t%d(a0)\n"

#define PROFILING                       \
"\txref\t_ixemulbase\n\txdef\t_%s\n_%s\n\tsection\t\"DATA\",data\nPROF%s\n\tdc.l\t0\
\tsection\t\"CODE\",code\n\tlink\ta5,#0\n\tlea\tPROF%s,a0\n\tjsr\tmcount\n\
\tunlk\ta5\n\tmove.l\t_ixemulbase,a0\n\tjmp\t%d(a0)\n"

void usage(void)
{
  fprintf(stderr, "Usage: gen_glue baserel | no-baserel | profiling\n");
  exit(1);
}

int main(int argc, char **argv)
{
  FILE *fp;
  struct syscall *sc;
  int i, v, baserel = 0, profiling = 0;

  if (argc != 2)
    usage();
  if (!strcmp(argv[1], "baserel"))
    {
      baserel = 1; profiling = 0;
    }
  else if (!strcmp(argv[1], "no-baserel"))
    {
      baserel = 0; profiling = 0;
    }
  else if (!strcmp(argv[1], "profiling"))
    {
      baserel = 0; profiling = 1;
    }
  else usage();

  for (i = 0, sc = syscalls; i < nsyscall; i++, sc++)
    {
      char name[strlen (sc->name) + 3];

      if (!memcmp(sc->name, "__obsolete", 10))
        continue;
      if (!memcmp(sc->name, "__must_recompile", 16))
        continue;
      if (!memcmp(sc->name, "__stk", 5))
        continue;
      v = -(sc->vec + 4)*6;
      sprintf (name, "%s.s", sc->name);

      fp = fopen (name, "w");

      if (!fp)
        {
          perror (sc->name);
          exit (20);
        }

      if (baserel)
        if (sc->vec == SYS_ix_geta4)
          fprintf (fp, BASEREL_IX_GETA4, sc->name, sc->name, v);
        else
          fprintf (fp, BASEREL, sc->name, sc->name, v);
      else if (profiling)
        fprintf (fp, PROFILING, sc->name, sc->name, sc->name, sc->name, v);
      else
        fprintf (fp, NOBASEREL, sc->name, sc->name, v);
      fclose (fp);
    }
  return (0);
}
