/*
 * This code constructs the glue between InterfaceLib and ROMlib.
Much of this code came from genptocflags.h

Here are some of the issues we have to deal with:

Routines may have more than one name
Sync and ASync variants of various PB routines
Points must be handled specially
We'd like the ability to log things
Routines that have more than 8 arguments require special work


 */

/*
 * See comment in mkctopflags.cpp
 */

#define M(x) ({								\
		x vvv;							\
		(__builtin_classify_type (vvv) == POINTER_CLASS &&	\
						sizeof(x) != 3 ?	\
		   pointer_arg						\
		 :							\
		   (sizeof(x) <= 4 ?					\
		     flagmap[sizeof(x)]					\
		    :							\
		     four_byte_arg					\
	            )							\
                 );							\
	     })

#define POINTER_CLASS 5 /* this is is a gcc specific thing that */
	/* may even very from gcc version to version, but works for 2.7 */

#define Point	notapoint
#define	Cell	notacell

#include "rsys/common.h"
#include "rsys/everything.h"

/* for `EXIT_SUCCESS' */
#include <stdlib.h>
#include <stdarg.h>

#include <string.h>

PRIVATE int
compare (const void *a, const void *b)
{
  const char *p1, *p2;
  int retval;

  p1 = *(const char **) a;
  p2 = *(const char **) b;
  retval = strcmp (p1, p2);
  return retval;
}

PRIVATE boolean_t
ignore_func_p (const char *func_name)
{
  static const char *exceptions[] =
  {
    "new_draw_scroll",
    "new_pos_ctl",
    "cdef16",
    "cdef0",
    "cdef1008",
    "ROMlib_myfilt",
    "ROMlib_mysound",
    "ROMlib_mytrack",
    "ldef0",
    "mdef0",
    "mbdf0",
    "ROMlib_myjobproc",
    "ROMlib_mystlproc",
    "ROMlib_stlfilterproc",
    "ROMlib_numsonlyfilterproc",
    "ROMlib_circle_ok",
    "ROMlib_orientation",
    "donotPrArc",
    "donotPrBits",
    "donotPrLine",
    "donotPrOval",
    "donotPrPutPic",
    "textasPS",
    "donotPrPoly",
    "donotPrRRect",
    "donotPrRect",
    "donotPrRgn",
    "donotPrText",
    "dcmp_template",
    "wdef0",
    "wdef16",
    "ROMlib_Fsethv",
    "ROMlib_Fgethv",
    "ROMlib_Fxstr2dec",
    "ROMlib_FnextX",
    "PhysicalGestalt",
    "GestaltTablesOnly",
    "ROMlib_stdftrack",
    "unused_stdfile",
    "ROMlib_filebox",
    "ROMlib_stdffilt",
    "unused_stdfile_2",
    "unixmount",
    "snth5",
    "pack8_unknown_selector",
    "donotPrGetPic",
    "PrArc",
    "PrBits",
    "PrLine",
    "PrOval",
    "PrGetPic",
    "PrPutPic",
    "PrPoly",
    "PrRRect",
    "PrRect",
    "PrRgn",
    "PrTxMeas",
    "PrText",
    "PrComment",
    "ReadComment",
    "DeviceLoopDrawingProcTemplate",
    "EventHandlerTemplate",
    "CoercePtrTemplate",
    "CoerceDescTemplate",
    "GetSpecificHighLevelEventProcTemplate",
    "LoadSeg",
    "ROMlib_licensefilt",
    "C_SysError",
    "_AE_hdlr_table_alloc",
    "_AE_hdlr_delete",
    "_AE_hdlr_lookup",
    "_AE_hdlr_install",
  };
  static boolean_t been_here = FALSE;
  boolean_t retval;

  if (!been_here)
    {
      qsort (exceptions, NELEM (exceptions), sizeof exceptions[0], compare);
      been_here = TRUE;
    }

  retval = !!bsearch (&func_name, exceptions, NELEM (exceptions),
		      sizeof exceptions[0], compare);
  return retval;
}


PRIVATE void
dump_header (void)
{
  printf (

"#include \"rsys/common.h\"\n"
"#include \"rsys/interfacelib.h\"\n"
"\n"
"#include \"rsys/cfm.h\"\n"
"#include \"rsys/pef.h\"\n"
"#include \"rsys/file.h\"\n"
"\n"
// "#include \"ppc_stubs.h\"\n"
"\n"
"\n"
"#include \"SegmentLdr.h\"\n"
"#include \"DialogMgr.h\"\n"
"#include \"FontMgr.h\"\n"
"#include \"MenuMgr.h\"\n"
"#include \"TextEdit.h\"\n"
"#include \"OSUtil.h\"\n"
"#include \"ToolboxEvent.h\"\n"
"#include \"CQuickDraw.h\"\n"
"#include \"AliasMgr.h\"\n"
"#include \"MemoryMgr.h\"\n"
"#include \"Gestalt.h\"\n"
"#include \"ToolboxUtil.h\"\n"
"#include \"BinaryDecimal.h\"\n"
"#include \"AppleEvents.h\"\n"
"#include \"QuickDraw.h\"\n"
"#include \"ListMgr.h\"\n"
"#include \"DeskMgr.h\"\n"
"#include \"StdFilePkg.h\"\n"
"#include \"PrintMgr.h\"\n"
"#include \"FileMgr.h\"\n"
"#include \"ControlMgr.h\"\n"
"#include \"MenuMgr.h\"\n"
"#include \"ScrapMgr.h\"\n"
"#include \"SoundMgr.h\"\n"
"#include \"TimeMgr.h\"\n"
"#include \"Iconutil.h\"\n"
"#include \"ResourceMgr.h\"\n"
"#include \"HelpMgr.h\"\n"
"#include \"ScriptMgr.h\"\n"
"#include \"OSEvent.h\"\n"
"#include \"ProcessMgr.h\"\n"
"#include \"EditionMgr.h\"\n"
"#include \"Finder.h\"\n"
"#include \"ADB.h\"\n"
"#include \"Disk.h\"\n"
"#include \"DiskInit.h\"\n"
"#include \"Package.h\"\n"
"#include \"ThinkC.h\"\n"
"#include \"ShutDown.h\"\n"
"#include \"QuickTime.h\"\n"
"#include \"SysErr.h\"\n"
"\n"
"#include \"rsys/time.h\"\n"
"#include \"rsys/mixed_mode.h\"\n"
"#include \"rsys/executor.h\"\n"
"#include \"rsys/interfacelib.h\"\n"
"#include \"rsys/mathlib.h\"\n"
"#include \"rsys/launch.h\"\n"
"#include \"rsys/emustubs.h\"\n"
"#include \"rsys/mixed_mode.h\"\n\n"
"#define SetPalette C_SetPalette\n\n"
"typedef uint32 PointAsLong;\n"
);
}

#undef	Point
#undef	Cell
typedef	char Point[3];
typedef	char Cell[3];

typedef enum
{
  void_arg,
  one_byte_arg,
  two_byte_arg,
  point_arg,
  four_byte_arg,
  pointer_arg,
}
arg_t;

PRIVATE void
process_a_func (int n_args, const char *name, arg_t ret_type, ...);

#define void struct {}
#define register

unsigned long flagmap[] =
{
  void_arg,
  one_byte_arg,
  two_byte_arg,
  point_arg,
  four_byte_arg,
};

#undef	P0
#undef	P1
#undef	P2
#undef	P3
#undef	P4
#undef	P5
#undef	P6
#undef	P7
#undef	P8
#undef	P9
#undef	P10
#undef	P11

#define P11(v, t0, n0, t1, n1, t2, n2, t3, n3, t4, n4, t5, n5, t6, n6, t7, n7, t8, n8, t9, n9, t10, n10, t11, n11) \
process_a_func (11, #n0, M(t0), M(t1), #n1, M(t2), #n2, M(t3), #n3, M(t4), #n4, M(t5), #n5, M(t6), #n6, M(t7), #n7, M(t8), #n8, M(t9), #n9, M(t10), #n10, M(t11), #n11);

#define P10(v, t0, n0, t1, n1, t2, n2, t3, n3, t4, n4, t5, n5, t6, n6, t7, n7, t8, n8, t9, n9, t10, n10) \
process_a_func (10, #n0, M(t0), M(t1), #n1, M(t2), #n2, M(t3), #n3, M(t4), #n4, M(t5), #n5, M(t6), #n6, M(t7), #n7, M(t8), #n8, M(t9), #n9, M(t10), #n10);

#define P9(v, t0, n0, t1, n1, t2, n2, t3, n3, t4, n4, t5, n5, t6, n6, t7, n7, t8, n8, t9, n9) \
process_a_func (9, #n0, M(t0), M(t1), #n1, M(t2), #n2, M(t3), #n3, M(t4), #n4, M(t5), #n5, M(t6), #n6, M(t7), #n7, M(t8), #n8, M(t9), #n9);

#define P8(v, t0, n0, t1, n1, t2, n2, t3, n3, t4, n4, t5, n5, t6, n6, t7, n7, t8, n8) \
process_a_func (8, #n0, M(t0), M(t1), #n1, M(t2), #n2, M(t3), #n3, M(t4), #n4, M(t5), #n5, M(t6), #n6, M(t7), #n7, M(t8), #n8);

#define P7(v, t0, n0, t1, n1, t2, n2, t3, n3, t4, n4, t5, n5, t6, n6, t7, n7) \
process_a_func (7, #n0, M(t0), M(t1), #n1, M(t2), #n2, M(t3), #n3, M(t4), #n4, M(t5), #n5, M(t6), #n6, M(t7), #n7);

#define P6(v, t0, n0, t1, n1, t2, n2, t3, n3, t4, n4, t5, n5, t6, n6) \
process_a_func (6, #n0, M(t0), M(t1), #n1, M(t2), #n2, M(t3), #n3, M(t4), #n4, M(t5), #n5, M(t6), #n6);

#define P5(v, t0, n0, t1, n1, t2, n2, t3, n3, t4, n4, t5, n5) \
process_a_func (5, #n0, M(t0), M(t1), #n1, M(t2), #n2, M(t3), #n3, M(t4), #n4, M(t5), #n5);

#define P4(v, t0, n0, t1, n1, t2, n2, t3, n3, t4, n4) \
process_a_func (4, #n0, M(t0), M(t1), #n1, M(t2), #n2, M(t3), #n3, M(t4), #n4);

#define P3(v, t0, n0, t1, n1, t2, n2, t3, n3) \
process_a_func (3, #n0, M(t0), M(t1), #n1, M(t2), #n2, M(t3), #n3);

#define P2(v, t0, n0, t1, n1, t2, n2) \
process_a_func (2, #n0, M(t0), M(t1), #n1, M(t2), #n2);

#define P1(v, t0, n0, t1, n1)	\
process_a_func (1, #n0, M(t0), M(t1), #n1);

#define P0(v, t0, n0) \
process_a_func (0, #n0, M(t0));

PUBLIC int
main ()
{
  dump_header ();
@fndecls@
  return EXIT_SUCCESS;
}

#undef void

PRIVATE char *
arg_type (arg_t t)
{
  char *retval;

  switch (t)
    {
    case void_arg:
      retval = "void";
      break;
    case one_byte_arg:
      retval = "uint8";
      break;
    case two_byte_arg:
      retval = "uint16";
      break;
    case point_arg:
      retval = "PointAsLong";
      break;
    case four_byte_arg:
      retval = "uint32";
      break;
    case pointer_arg:
      retval = "void *";
      break;
    }
  return retval;
}

PRIVATE void
process_a_func (int n_args, const char *name, arg_t ret_type, ...)
{
  if (!ignore_func_p (name))
    {
      int n_points;
      int i;
      va_list ap;

      n_points = 0;
      if (ret_type == point_arg)
	{
	  fprintf (stderr, "'%s' returns Point\n", name);
	}

      if (n_args <= 8)
	printf ("\nPRIVATE %s\nprivate_%s (", arg_type (ret_type), name);
      else
	printf ("\nPUBLIC %s\n%s_SYSV4 (", arg_type (ret_type), name);

      if (n_args == 0)
	printf ("void");
      else
	{
	  va_start(ap, ret_type);
	  for (i = 0; i < n_args; ++i)
	    {
	      arg_t t;
	      const char *arg_name;

	      if (i)
		printf (", ");
	      t = va_arg (ap, int);
	      arg_name = va_arg (ap, const char *);
	      printf ("%s ", arg_type (t));
	      if (t != point_arg)
		printf ("%s", arg_name);
	      else
		{
		  printf ("pal_%d", n_points);
		  ++n_points;
		}
	    }
	  va_end(ap);
	} 

      printf (")\n{\n");
      if (ret_type != void_arg)
	printf ("  %s retval;\n", arg_type (ret_type)); 
      for (i = 0; i < n_points; ++i)
	printf ("  Point point_%d;\n", i);

      if (n_points > 0)
	printf ("\n");

      for (i = 0; i < n_points; ++i)
	printf ("  point_%d.h = pal_%d;\n  point_%d.v = pal_%d >> 16;\n",
		i, i, i, i);
      printf ("  warning_trace_info (NULL_STRING);\n  ");
      if (ret_type != void_arg)
	printf ("retval = ");
      printf ("%s (", name);

      n_points = 0;
      va_start(ap, ret_type);
      for (i = 0; i < n_args; ++i)
	{
	  arg_t t;
	  const char *arg_name;

	  t = va_arg (ap, int);
	  arg_name = va_arg (ap, const char *);
	  if (i)
	    printf (", ");
	  if (t != point_arg)
	    printf ("%s", arg_name);
	  else
	    {
	      printf ("point_%d", n_points);
	      ++n_points;
	    }
	}
      va_end(ap);

      printf (");\n");
      if (ret_type != void_arg)
	printf ("  return retval;\n");
      printf ("}\n");
    }
}

