/* Generate alix_sysent.c from syscalls.list
   Copyright (C) 1991 Free Software Foundation

This file is part of the GNU Hurd.

The GNU Hurd 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 1, or (at your option)
any later version.

The GNU Hurd 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 the GNU Hurd; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

/* Written by Michael I. Bushnell.  */

#include <stdio.h>

struct section
{
  int first;
  int last;
  char name[20];
  struct section *next;
};

struct section *seclist;

main ()
{
  char buf[100];
  int number;
  char type[20];
  int nargs;
  char name[20];
  char comment[80];
  int curnum;
  int scanret;
  struct section *tmp;
  FILE *list;
  FILE *cfile, *hfile;
  FILE *libfile;

  setbuffer (stdout, 0, 0);
  seclist = 0;

  list = fopen ("syscalls.list", "r");
  if (list == 0)
    {
      perror ("syscalls.list");
      exit (1);
    }
  cfile = fopen ("alix_sysent.c", "w");
  if (cfile == 0)
    {
      perror ("alix_sysent.c");
      exit (1);
    }
  hfile = fopen ("alix_sysent.h", "w");
  if (hfile == 0)
    {
      perror ("alix_sysent.h");
      exit (1);
    }
  libfile = fopen ("syscall.h", "w");
  if (libfile == 0)
    {
      perror ("syscall.h");
      exit (1);
    }

  fprintf (cfile, "\n\n/* This file is automatically generated from\n\
   syscalls.list by alix_makesysent. */\n");
  fprintf (cfile, "#include \"mach.h\"\n");
  fprintf (cfile, "#include <cthreads.h>\n");
  fprintf (cfile, "#include <gnu/posix1_limits.h>\n");
  fprintf (cfile, "#include <gnu/signal.h>\n");
  fprintf (cfile, "#include <hurd/hurd_types.h>\n");
  fprintf (cfile, "#include \"alix_sysent.h\"\n");
  fprintf (cfile, "#include \"alix.h\"\n");
  fprintf (cfile, "#if defined (COMPAT_43) && ! defined (COMPAT_44)\n");
  fprintf (cfile, "#error Cannot define COMPAT_43 without COMPAT_44\n");
  fprintf (cfile, "#endif\n");

  fprintf (hfile, "\n\n/* This file is automatically generated from\n\
   syscalls.list by alix_makesysent. */\n");
  fprintf (hfile, "/* Info for each syscall */\n");
  fprintf (hfile, "struct sysent\n");
  fprintf (hfile, "{\n");
  fprintf (hfile, "  char *name;\t		/* printable name */\n");
  fprintf (hfile, "  void *vector;\t\t	/* address of vector routine */\n");
  fprintf (hfile, "  int nargs;	       \t	/* number of arguments */\n");
  fprintf (hfile, "  int modregs;\t\t\t/* syscall needs 4th regs arg */\n");
  fprintf (hfile, "};\n");
  fprintf (hfile, "\n");
  fprintf (hfile, "/* Info for a set of syscalls */\n");
  fprintf (hfile, "struct systab\n");
  fprintf (hfile, "{\n");
  fprintf (hfile, "  int min;			/* first entry */\n");
  fprintf (hfile, "  int max;			/* last entry */\n");
  fprintf (hfile, "  struct sysent *tab;\t	/* table of entries */\n");
  fprintf (hfile, "};\n");
  fprintf (hfile, "\n");
  fprintf (hfile, "struct systab systab[];\n");
  fprintf (hfile, "\n");
  fprintf (hfile, "typedef int syscall_t(void *, int *, int *);\n");
  fprintf (hfile, "typedef int syscallreg_t(void *, int *, int *, int *);\n");

  fprintf (libfile, "\n\n/* This file is automatically generated from\n\
   sysalls.list by alix_makesysent. */\n");
  
  while (fgets (buf, 100, list) != NULL)
    {
      if (buf[0] == '#' || buf[0] == '\n')
	continue;

      scanret = sscanf (buf, "section %s %d\n", name, &number);
      if (scanret == 2)
	{
	  /* End old section */
	  if (seclist)
	    {
	      seclist->last = curnum - 1;
	      fprintf (cfile, "};\n\n");
	    }
	  
	  tmp = (struct section *) malloc (sizeof (struct section));
	  tmp->next = seclist;
	  seclist = tmp;
	  
	  seclist->first = number;
	  strcpy (seclist->name, name);
	  curnum = number;

	  /* Start new section */
	  fprintf (cfile, "struct sysent sysent_%s[] = \n{\n", name);
	  fprintf (hfile, "\n\n/* %s syscalls */\n", name);
	  fprintf (libfile, "\n\n/* %s syscalls*/\n", name);
	  continue;
	}
      
      comment[0] = '\0';
      name[0] = '\0';
      scanret = sscanf (buf, "%d %s %d %s %s\n", 
			&number, type, &nargs, name, comment);

      if (scanret < 2)
	{
	badformat:
	  fprintf (stderr, "Bad line format\n");
	  exit (1);
	}
      if (!seclist)
	{
	  fprintf (stderr, "Missing section directive\n");
	  exit (1);
	}
      if (number != curnum++)
	{
	  fprintf (stderr, "Unexpected syscall number %d\n", number);
	  exit (1);
	}
      if (!strcmp (type, "STD"))
	{
	  if (scanret < 4)
	    goto badformat;
	  if (strlen (name) <= 4)
	    fprintf (cfile, "  {\"%s\", %s, %d, 0},\t\t\t/* %d %s */\n",
		   name, name, nargs, number, comment);
	  else if (strlen (name) >= 13)
	    fprintf (cfile, "  {\"%s\", %s, %d, 0}, /* %d %s */\n",
		     name, name, nargs, number, comment);
	  else if (strlen (name) >= 9)
	    fprintf (cfile, "  {\"%s\", %s, %d, 0},\t/* %d %s */\n",
		     name, name, nargs, number, comment);
	  else
	    fprintf (cfile, "  {\"%s\", %s, %d, 0},\t\t/* %d %s */\n",
		     name, name, nargs, number, comment);
	  fprintf (hfile, "syscall_t %s;\n", name);
	  fprintf (libfile, "#define SYS_%s %d\n", name, number);
	}
      else if (!strcmp (type, "STDREGS"))
	{
	  if (scanret < 4)
	    goto badformat;
	  if (strlen (name) <= 4)
	    fprintf (cfile, "  {\"%s\", %s, %d, 1},\t\t\t/* %d %s */\n",
		     name, name, nargs, number, comment);
	  else if (strlen (name) >= 13)
	    fprintf (cfile, "  {\"%s\", %s, %d, 1}, /* %d %s */\n",
		     name, name, nargs, number, comment);
	  else if (strlen (name) >= 9)
	    fprintf (cfile, "  {\"%s\", %s, %d, 1},\t/* %d %s */\n",
		     name, name, nargs, number, comment);
	  else
	    fprintf (cfile, "  {\"%s\", %s, %d, 1},\t\t/* %d %s */\n",
		     name, name, nargs, number, comment);
	  fprintf (hfile, "syscallreg_t %s;\n", name);
	  fprintf (libfile, "#define SYS_%s %d\n", name, number);
	}
      else if (!strcmp (type, "CPT43")
	       || !strcmp (type, "LCPT43")
	       || !strcmp (type, "RCPT43"))
	{
	  if (scanret < 4)
	    goto badformat;
	  fprintf (cfile, "#ifdef COMPAT_43\n");
	  fprintf (cfile, 
		   "  {\"%s_compat43\", %s_compat43, %d, %d}, /* %d %s */\n",
		   name, name, nargs, !(strcmp (type, "RCPT43")),
		   number, comment);
	  fprintf (cfile, "#else\n");
	  fprintf (cfile, "  {\"nosys\", 0, 0, 0},\n");
	  fprintf (cfile, "#endif\n");
	  fprintf (hfile, "#ifdef COMPAT_43\n");
	  fprintf (hfile, "syscall%s_t %s_compat43;\n", 
		   (strcmp (type, "RCPT43")) ? "" : "reg", name);
	  fprintf (hfile, "#endif\n");
	  if (!strcmp (type, "LCPT43"))
	    fprintf (libfile, "#define SYS_%s %d\n", name, number);
	}
      else if (!strcmp (type, "CPT44")
	       || !strcmp (type, "LCPT44"))
	{
	  if (scanret < 4)
	    goto badformat;
	  fprintf (cfile, "#ifdef COMPAT_44\n");
	  fprintf (cfile,
		   "  {\"%s_compat44\", %s_compat44, %d, 0}, /* %d %s */\n",
		   name, name, nargs, number, comment);
	  fprintf (cfile, "#else\n");
	  fprintf (cfile, "  {\"nosys\", 0, 0, 0},\n");
	  fprintf (cfile, "#endif\n");
	  fprintf (hfile, "#ifdef COMPAT_44\n");
	  fprintf (hfile, "syscall_t %s_compat44;\n", name);
	  fprintf (hfile, "#endif\n");
	  if (!strcmp (type, "LCPT44"))
	    fprintf (libfile, "#define SYS_%s %d\n", name, number);
	}
      else if (!strcmp (type, "UNIMPL")
	       || !strcmp (type, "OBSOL"))
	fprintf (cfile, "  {\"nosys\", 0, 0, 0},\t\t\t/* %d %s %s */\n",
		 number, name, comment);
      else
	{
	  fprintf (stderr, "unknown type %s\n", type);
	  exit (1);
	}
    }

  /* End last section */
  seclist->last = curnum - 1;
  fprintf (cfile, "};\n\n");
  
  /* Print out global table */

  fprintf (cfile, "struct systab systab[] =\n{\n");
  while (seclist)
    {
      fprintf (cfile, "  {%d, %d, sysent_%s},\n", 
	       seclist->first, seclist->last, seclist->name);
      seclist = seclist->next;
    }
  fprintf (cfile, "  {0, 0, 0},\n};\n");
  exit (0);
}
