/*-
 * Copyright (c) 2014, Matthew Macy <kmacy@FreeBSD.ORG>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice unmodified, this list of conditions, and the following
 *    disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 */
/*
 * Copyright 1991-1998 by Open Software Foundation, Inc. 
 *              All Rights Reserved 
 * 
 * Permission to use, copy, modify, and distribute this software and 
 * its documentation for any purpose and without fee is hereby granted, 
 * provided that the above copyright notice appears in all copies and 
 * that both the copyright notice and this permission notice appear in 
 * supporting documentation. 
 *  
 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE. 
 *  
 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
 */
/*
 * cmk1.1
 */
/*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * All Rights Reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie Mellon
 * the rights to redistribute these changes.
 */
/*
 * 92/03/03  16:25:23  jeffreyh
 * 	Changes from TRUNK
 * 	[92/02/26  12:32:39  jeffreyh]
 * 
 * 92/01/14  16:46:47  rpd
 * 	Changed Indefinite types from MustBeLong to ShouldBeLong.
 * 	Added itCheckFlags, itCheckDeallocate, itCheckIsLong.
 * 	Removed itServerCopy.
 * 	[92/01/09            rpd]
 * 
 * 91/08/28  11:17:27  jsb
 * 	Removed itMsgKindType.
 * 	[91/08/12            rpd]
 * 
 * 91/07/31  18:11:12  dbg
 * 	Indefinite-length inline arrays.
 * 
 * 	Change itDeallocate to an enumerated type, to allow for
 * 	user-specified deallocate flag.
 * 
 * 	Add itCStringDecl.
 * 	[91/07/17            dbg]
 * 
 * 91/06/25  10:32:09  rpd
 * 	Changed itCalculateNameInfo to change type names from mach_port_t
 * 	to ipc_port_t for KernelServer and KernelUser interfaces.
 * 	[91/05/28            rpd]
 * 
 * 91/02/05  17:56:02  mrt
 * 	Changed to new Mach copyright
 * 	[91/02/01  17:56:12  mrt]
 * 
 * 90/06/02  15:05:54  rpd
 * 	Created for new IPC.
 * 	[90/03/26  21:14:07  rpd]
 * 
 * 07-Apr-89  Richard Draves (rpd) at Carnegie-Mellon University
 *	Extensive revamping.  Added polymorphic arguments.
 *	Allow multiple variable-sized inline arguments in messages.
 *
 * 17-Aug-88  Mary Thompson (mrt) at Carnegie-Mellon University
 *	Removed translation of MSG_TYPE_INVALID as that type
 *	is no longer defined by the kernel.
 * 
 * 19-Feb-88  Mary Thompson (mrt) at Carnegie-Mellon University
 *	Changed itPrintTrans and itPrintDecl to reflect new translation syntax.
 *	Changed itCheckDecl to set itServerType to itType if is is strNULL.
 *
 *  4-Feb-88  Mary Thompson (mrt) at Carnegie-Mellon University
 *	Added a check to itCheckDecl to make sure that in-line
 *	variable length arrays have a non-zero maximum length.
 *
 * 22-Dec-87  David Golub (dbg) at Carnegie-Mellon University
 *	Removed warning message for translation.
 *
 * 16-Nov-87  David Golub (dbg) at Carnegie-Mellon University
 *	Changed itVarArrayDecl to take a 'max' parameter for maximum
 *	number of elements, and to make type not be 'struct'.
 *	Added itDestructor.
 *
 * 18-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
 *	Added initialization of itPortType
 *
 * 14-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
 *	Added initialization for itTidType
 *
 * 15-Jun-87  David Black (dlb) at Carnegie-Mellon University
 *	Fixed prototype for itAlloc; was missing itServerType field.
 *
 * 10-Jun-87  Mary Thompson (mrt) at Carnegie-Mellon University
 *	Removed extern from procedure definitions to make hi-c happy
 *	Changed the c type names of itDummyType from caddr_t to
 *	char * and of itCountType from u_int to unsigned int to
 *	eliminate the need to import sys/types.h into the mig generated
 *	code.
 *
 * 28-May-87  Richard Draves (rpd) at Carnegie-Mellon University
 *	Created.
 */

#include <stdio.h>

#include "type.h"
#include <sys/types.h>
#include <mach/message.h>
#include <mach/std_types.h>
#include <mach/ndr.h>
#include "mig_machine.h"
#include "routine.h"
#include "error.h"
#include "alloc.h"
#include "global.h"
#include "strdefs.h"

#define PortSize  (sizeof (mach_port_t) * NBBY)

ipc_type_t *itRetCodeType;      /* used for return codes */
ipc_type_t *itNdrCodeType;      /* used for NDR format labels */
ipc_type_t *itDummyType;        /* used for camelot dummy args */
ipc_type_t *itTidType;          /* used for camelot tids */
ipc_type_t *itRequestPortType;  /* used for default Request port arg */
ipc_type_t *itZeroReplyPortType;/* used for dummy Reply port arg */
ipc_type_t *itRealReplyPortType;/* used for default Reply port arg */
ipc_type_t *itWaitTimeType;     /* used for dummy WaitTime args */
ipc_type_t *itMsgOptionType;    /* used for dummy MsgOption args */

static ipc_type_t *list = itNULL;

static string_t machine_integer_name;
static u_int machine_integer_size;
static u_int machine_integer_bits;

/*
 *  Searches for a named type.  We use a simple
 *  self-organizing linked list.
 */
ipc_type_t *
itLookUp(identifier_t name)
{
	register ipc_type_t *it, **last;
  
	for (it = *(last = &list); it != itNULL; it = *(last = &it->itNext))
		if (streql(name, it->itName))
		{
			/* move this type to the front of the list */
			*last = it->itNext;
			it->itNext = list;
			list = it;
      
			return it;
		}
  
	return itNULL;
}

/*
 *  Enters a new name-type association into
 *  our self-organizing linked list.
 */
void
itInsert(identifier_t name, ipc_type_t *it)
{
	it->itName = name;
	it->itNext = list;
	list = it;
}

static ipc_type_t *
itAlloc(void)
{
	static ipc_type_t prototype =
		{
			strNULL,  /* identifier_t itName */
			0,        /* ipc_type_t *itNext */
			0,        /* u_int itTypeSize */
			0,        /* u_int itPadSize */
			0,        /* u_int itMinTypeSize */
			0,        /* u_int itInName */
			0,        /* u_int itOutName */
			0,        /* u_int itSize */
			1,        /* u_int itNumber */
			0,        /* u_int itKPD_Number */
			TRUE,     /* boolean_t itInLine */
			FALSE,    /* boolean_t itMigInLine */
			FALSE,    /* boolean_t itPortType */
			strNULL,  /* string_t itInNameStr */
			strNULL,  /* string_t itOutNameStr */
			TRUE,     /* boolean_t itStruct */
			FALSE,    /* boolean_t itString */
			FALSE,    /* boolean_t itVarArray */
			FALSE,    /* boolean_t itNoOptArray */
			FALSE,    /* boolean_t itNative */
			FALSE,    /* boolean_t itNativePointer */
			itNULL,   /* ipc_type_t *itElement */
			strNULL,  /* identifier_t itUserType */
			strNULL,  /* identifier_t itServerType */
			strNULL,  /* identifier_t itTransType */
			strNULL,  /* identifier_t itUserKPDType */
			strNULL,  /* identifier_t itServerKPDType */
			strNULL,  /* identifier_t itInTrans */
			strNULL,  /* identifier_t itOutTrans */
			strNULL  /* identifier_t itDestructor */
		};
	register ipc_type_t *new;
  
	new = (ipc_type_t *) malloc(sizeof *new);
	if (new == itNULL)
		fatal("itAlloc(): %s", strerror(errno));
	*new = prototype;
	return new;
}

/*
 * Convert an IPC type-name into a string.
 */
static const char *
itNameToString(u_int name)
{
	char buffer[100];
  
	(void) sprintf(buffer, "%u", name);
	return strmake(buffer);
}

/*
 * Calculate itTypeSize, itPadSize, itMinTypeSize
 * Every type needs this info; it is recalculated
 * when itInLine, itNumber, or itSize changes.
 */
static void
itCalculateSizeInfo(register ipc_type_t *it)
{
	if (!IS_KERN_PROC_DATA(it))
	{
		u_int bytes = (it->itNumber * it->itSize + 7) / 8;
		u_int padding = machine_padding(bytes);
    
		it->itTypeSize = bytes;
		it->itPadSize = padding;
		if (IS_VARIABLE_SIZED_UNTYPED(it)) {
			/*
			 * for these arrays, the argCount is not a akbRequest|akbReply,
			 * therefore we need to account here for the space of the count
			 * (itMinTypeSize is used only in rtFindSize)
			 */
			it->itMinTypeSize = sizeof (mach_msg_type_number_t);
			/*
			 * NDR encoded VarString carry the extra offset 4-bytes fields
			 * for MIG, it should be always 0;
			 */
			if (it->itString)
				it->itMinTypeSize += sizeof (mach_msg_type_number_t);
		} else
			it->itMinTypeSize = bytes + padding;
    } else {
		/*
		 * 1) ports 2) OOL 3) ports OOL
		 * all have the same size = sizeof(mach_msg_descriptor_t)
		 */
		u_int bytes;
		if (IS_MULTIPLE_KPD(it))
			bytes = it->itKPD_Number * sizeof(mach_msg_descriptor_t);
		else
			bytes = sizeof(mach_msg_descriptor_t);
    
		it->itTypeSize = bytes;
		it->itPadSize = 0;
		it->itMinTypeSize = bytes;
	}
  
	/* Unfortunately, these warning messages can't give a type name;
	   we haven't seen a name yet (it might stay anonymous.) */
  
	if ((it->itTypeSize == 0) && !it->itVarArray && !it->itNative)
		warn("sizeof(%s) == 0");
}

/*
 * Fill in default values for some fields used in code generation:
 *  itInNameStr, itOutNameStr, itUserType, itServerType, itTransType
 * Every argument's type should have these values filled in.
 */
static void
itCalculateNameInfo(register ipc_type_t *it)
{
	if (it->itInNameStr == strNULL)
		it->itInNameStr = strmake(itNameToString(it->itInName));
	if (it->itOutNameStr == strNULL)
		it->itOutNameStr = strmake(itNameToString(it->itOutName));
  
	if (it->itUserType == strNULL)
		it->itUserType = it->itName;
	if (it->itServerType == strNULL)
		it->itServerType = it->itName;
#if 0
	/*
	 *  KernelServer and KernelUser interfaces get special treatment here.
	 *  On the kernel side of the interface, ports are really internal
	 *  port pointers (ipc_port_t), not port names (mach_port_t).
	 *  At this point, we don't know if the argument is in or out,
	 *  so we don't know if we should look at itInName or itOutName.
	 *  Looking at both should be OK.
	 *
	 *  This is definitely a hack, but I think it is cleaner than
	 *  mucking with type declarations throughout the kernel .def files,
	 *  hand-conditionalizing on KERNEL_SERVER and KERNEL_USER.
	 */
  
	if (IsKernelServer &&
		streql(it->itServerType, "mach_port_t") &&
		(((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) &&
		  (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)) ||
		 MACH_MSG_TYPE_PORT_ANY(it->itInName) ||
		 MACH_MSG_TYPE_PORT_ANY(it->itOutName)))
		it->itServerType = "ipc_port_t";
  
	if (IsKernelUser &&
		streql(it->itUserType, "mach_port_t") &&
		(((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) &&
		  (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)) ||
		 MACH_MSG_TYPE_PORT_ANY(it->itInName) ||
		 MACH_MSG_TYPE_PORT_ANY(it->itOutName)))
		it->itUserType = "ipc_port_t";
#endif /* 0 */
  
	if (it->itTransType == strNULL)
		it->itTransType = it->itServerType;
}

/******************************************************
 *  Checks for non-implemented types, conflicting type
 *  flags and whether the long or short form of msg type
 *  descriptor is appropriate. Called after each type statement
 *  is parsed.
 ******************************************************/
static void
itCheckDecl(identifier_t name, register ipc_type_t *it)
{
	it->itName = name;
  
	itCalculateNameInfo(it);
  
	/* do a bit of error checking, mostly necessary because of
	   limitations in Mig */
  
	if (it->itVarArray) {
		if ((it->itInTrans != strNULL) || (it->itOutTrans != strNULL))
			error("%s: can't translate variable-sized arrays", name);
    
		if (it->itDestructor != strNULL)
			error("%s: can't destroy variable-sized array", name);
	}
}

/*
 *  Pretty-prints translation/destruction/type information.
 */
static void
itPrintTrans(register ipc_type_t *it)
{
	if (!streql(it->itName, it->itUserType))
		printf("\tCUserType:\t%s\n", it->itUserType);
  
	if (!streql(it->itName, it->itServerType))
		printf("\tCServerType:\t%s\n", it->itServerType);
  
	if (it->itInTrans != strNULL)
		printf("\tInTran:\t\t%s %s(%s)\n",
			   it->itTransType, it->itInTrans, it->itServerType);
  
	if (it->itOutTrans != strNULL)
		printf("\tOutTran:\t%s %s(%s)\n",
			   it->itServerType, it->itOutTrans, it->itTransType);
  
	if (it->itDestructor != strNULL)
		printf("\tDestructor:\t%s(%s)\n", it->itDestructor, it->itTransType);
}

/*
 *  Pretty-prints type declarations.
 */
static void
itPrintDecl(identifier_t name, ipc_type_t *it)
{
	printf("Type %s = ", name);
	if (!it->itInLine)
		printf("^ ");
	if (it->itVarArray)
		if (it->itNumber == 0 || it->itMigInLine)
			printf("array [] of ");
		else
			printf("array [*:%d] of ", it->itNumber);
    else if (it->itStruct && ((it->itNumber != 1) ||
                              (it->itInName == MACH_MSG_TYPE_STRING_C)))
		printf("struct [%d] of ", it->itNumber);
    else if (it->itNumber != 1)
		printf("array [%d] of ", it->itNumber);
  
	if (streql(it->itInNameStr, it->itOutNameStr))
		printf("(%s,", it->itInNameStr);
	else
		printf("(%s|%s", it->itInNameStr, it->itOutNameStr);
  
	printf(" %d)\n", it->itSize);
  
	itPrintTrans(it);
  
	printf("\n");
}

/*
 *  Handles named type-specs, which can occur in type
 *  declarations or in argument lists.  For example,
 * type foo = type-spec; // itInsert will get called later
 * routine foo(arg : bar = type-spec); // itInsert won't get called
 */
void
itTypeDecl(identifier_t name, ipc_type_t *it)
{
	itCheckDecl(name, it);
  
	if (BeVerbose)
		itPrintDecl(name, it);
}

/*
 *  Handles declarations like
 * type new = name;
 * type new = inname|outname;
 */
ipc_type_t *
itShortDecl(u_int inname,  string_t instr, u_int outname, string_t outstr, u_int defsize)
{
	register ipc_type_t *it;
  
	if (defsize == 0)
		error("must use full IPC type decl");
  
	it = itAlloc();
	it->itInName = inname;
	it->itInNameStr = instr;
	it->itOutName = outname;
	it->itOutNameStr = outstr;
	it->itSize = defsize;
	if (inname == MACH_MSG_TYPE_STRING_C)
	{
		it->itStruct = FALSE;
		it->itString = TRUE;
	}
	/*
	 * I check only inname, because outname
	 * has to be a port as well (polymorphic types
	 * are now restricted to port rights)
	 */
	if (MACH_MSG_TYPE_PORT_ANY(inname) ||
		inname == MACH_MSG_TYPE_POLYMORPHIC) {
		it->itPortType = TRUE;
		it->itKPD_Number = 1;
	}
  
	itCalculateSizeInfo(it);
	return it;
}

static ipc_type_t *
itCopyType(ipc_type_t *old)
{
	register ipc_type_t *new = itAlloc();
  
	*new = *old;
	new->itName = strNULL;
	new->itNext = itNULL;
	new->itElement = old;
  
	/* size info still valid */
	return new;
}

/*
 * A call to itCopyType is almost always followed with itResetType.
 * The exception is itPrevDecl.  Also called before adding any new
 * translation/destruction/type info (see parser.y).
 *
 * type new = old; // new doesn't get old's info
 * type new = array[*:10] of old;
 * // new doesn't get old's info, but new->itElement does
 * type new = array[*:10] of struct[3] of old;
 * // new and new->itElement don't get old's info
 */

ipc_type_t *
itResetType(ipc_type_t *old)
{
	/* reset all special translation/destruction/type info */
  
	old->itInTrans = strNULL;
	old->itOutTrans = strNULL;
	old->itDestructor = strNULL;
	old->itUserType = strNULL;
	old->itServerType = strNULL;
	old->itTransType = strNULL;
	return old;
}

/*
 *  Handles the declaration
 * type new = old;
 */
ipc_type_t *
itPrevDecl(identifier_t name)
{
	register ipc_type_t *old;
  
	old = itLookUp(name);
	if (old == itNULL) {
		error("type '%s' not defined", name);
		return itAlloc();
	}
	else
		return itCopyType(old);
}

/*
 *  Handles the declarations
 * type new = array[] of old; // number is oo
 * type new = array[*] of old; // number is oo
 * type new = array[*:number] of old;
 */
ipc_type_t *
itVarArrayDecl(u_int number, register ipc_type_t *old)
{
	register ipc_type_t *it = itResetType(itCopyType(old));
  
	if (!it->itInLine) {
		/* already an initialized KPD */
		if (it->itKPD_Number != 1 || !number)
			error("IPC type decl is too complicated for Kernel Processed Data");
		it->itKPD_Number *= number;
		it->itNumber = 1;
		it->itInLine = FALSE;
		it->itStruct = FALSE;
    } else if (it->itVarArray)
		error("IPC type decl is too complicated");
	else if (number) {
		it->itNumber *= number;
		/*
		 * Bounded [Scalar, Port] VarArray: in-line!
		 */
		it->itInLine = TRUE;
		it->itStruct = FALSE;
		if (it->itPortType)
			it->itKPD_Number *= number;
    } else {
		it->itNumber = 0;
		/*
		 * UnBounded [Scalar, Port] VarArray: always in-line
		 * interface and out-of-line mechanism!
		 */
		it->itMigInLine = TRUE;
		it->itInLine = FALSE;
		it->itStruct = TRUE;
		it->itKPD_Number = 1;
	}
  
	it->itVarArray = TRUE;
	it->itString = FALSE;
  
	itCalculateSizeInfo(it);
	return it;
}

/*
 *  Handles the declaration
 * type new = array[number] of old;
 */
ipc_type_t *
itArrayDecl(u_int number, ipc_type_t *old)
{
	register ipc_type_t *it = itResetType(itCopyType(old));
  
	if (!it->itInLine) {
		/* already an initialized KPD */
		if (it->itKPD_Number != 1)
			error("IPC type decl is too complicated for Kernel Processed Data");
		it->itKPD_Number *= number;
		it->itNumber = 1;
		it->itStruct = FALSE;
		it->itString = FALSE;
		it->itVarArray = FALSE;
    } else if (it->itVarArray)
		error("IPC type decl is too complicated");
	else {
		it->itNumber *= number;
		it->itStruct = FALSE;
		it->itString = FALSE;
		if (it->itPortType)
			it->itKPD_Number *= number;
	}
  
	itCalculateSizeInfo(it);
	return it;
}

/*
 *  Handles the declaration
 * type new = ^ old;
 */
ipc_type_t *
itPtrDecl(ipc_type_t *it)
{
	if (!it->itInLine && !it->itMigInLine)
		error("IPC type decl is already defined to be Out-Of-Line");
	it->itInLine = FALSE;
	it->itStruct = TRUE;
	it->itString = FALSE;
	it->itMigInLine = FALSE;
	it->itKPD_Number = 1;
  
	itCalculateSizeInfo(it);
	return it;
}

/*
 *  Handles the declaration
 * type new = struct[number] of old;
 */
ipc_type_t *
itStructDecl(u_int number, ipc_type_t *old)
{
	register ipc_type_t *it = itResetType(itCopyType(old));
  
	if (!it->itInLine || it->itVarArray)
		error("IPC type decl is too complicated");
	it->itNumber *= number;
	it->itStruct = TRUE;
	it->itString = FALSE;
  
	itCalculateSizeInfo(it);
	return it;
}

/*
 * Treat 'c_string[n]' as
 * 'array[n] of (MSG_TYPE_STRING_C, 8)'
 */
ipc_type_t *
itCStringDecl(u_int count, boolean_t varying)
{
	register ipc_type_t *it;
	register ipc_type_t *itElement;
  
    itElement = itShortDecl(MACH_MSG_TYPE_STRING_C,
							"MACH_MSG_TYPE_STRING_C",
							MACH_MSG_TYPE_STRING_C,
							"MACH_MSG_TYPE_STRING_C",
							8);
	itCheckDecl("char", itElement);
  
	it = itResetType(itCopyType(itElement));
	it->itNumber = count;
	it->itVarArray = varying;
	it->itStruct = FALSE;
	it->itString = TRUE;
  
	itCalculateSizeInfo(it);
	return it;
}

extern ipc_type_t *
itMakeSubCountType(u_int count, boolean_t varying, string_t name __unused)
{
	register ipc_type_t *it;
	register ipc_type_t *itElement;
  
    itElement = itShortDecl(machine_integer_size,
							machine_integer_name,
							machine_integer_size,
							machine_integer_name,
							machine_integer_bits);
	itCheckDecl("mach_msg_type_number_t", itElement);
  
	it = itResetType(itCopyType(itElement));
	it->itNumber = count;
	/*
	 * I cannot consider it as a Fixed array, otherwise MiG will try
	 * to follow the path for efficient copy of arrays
	 */
	it->itVarArray = FALSE;
	it->itStruct = FALSE;
	it->itString = FALSE;
	it->itInLine = TRUE;
	it->itName = "mach_msg_type_number_t *";
	if (varying)
		it->itVarArray = TRUE;
	else
		/* to skip the optimized copy of fixed array: in fact we need to
		 * reference each element and we also miss a user type for it */
		it->itNoOptArray = TRUE;
  
	itCalculateSizeInfo(it);
	itCalculateNameInfo(it);
	return it;
}

extern ipc_type_t *
itMakeCountType(void)
{
	ipc_type_t *it = itAlloc();
  
	it->itName = "mach_msg_type_number_t";
	it->itInName = machine_integer_size;
	it->itInNameStr = machine_integer_name;
	it->itOutName = machine_integer_size;
	it->itOutNameStr = machine_integer_name;
	it->itSize = machine_integer_bits;
  
	itCalculateSizeInfo(it);
	itCalculateNameInfo(it);
	return it;
}

extern ipc_type_t *
itMakePolyType(void)
{
	ipc_type_t *it = itAlloc();
  
	it->itName = "mach_msg_type_name_t";
	it->itInName = machine_integer_size;
	it->itInNameStr = machine_integer_name;
	it->itOutName = machine_integer_size;
	it->itOutNameStr = machine_integer_name;
	it->itSize = machine_integer_bits;
  
	itCalculateSizeInfo(it);
	itCalculateNameInfo(it);
	return it;
}

extern ipc_type_t *
itMakeDeallocType(void)
{
	ipc_type_t *it = itAlloc();
  
	it->itName = "boolean_t";
	it->itInName = MACH_MSG_TYPE_BOOLEAN;
	it->itInNameStr = "MACH_MSG_TYPE_BOOLEAN";
	it->itOutName = MACH_MSG_TYPE_BOOLEAN;
	it->itOutNameStr = "MACH_MSG_TYPE_BOOLEAN";
	it->itSize = machine_integer_bits;
  
	itCalculateSizeInfo(it);
	itCalculateNameInfo(it);
	return it;
}

extern ipc_type_t *
itNativeType(id, ptr, badval)
    identifier_t id;
    boolean_t ptr;
    identifier_t badval;
{
	ipc_type_t *it = itAlloc();
  
	it->itInName = MACH_MSG_TYPE_BYTE;
	it->itInNameStr = "MACH_MSG_TYPE_BYTE";
	it->itOutName = MACH_MSG_TYPE_BYTE;
	it->itOutNameStr = "MACH_MSG_TYPE_BYTE";
	it->itInLine = TRUE;
	it->itNative = TRUE;
	it->itNativePointer = ptr;
	it->itServerType = id;
	it->itUserType = id;
	it->itTransType = id;
	it->itBadValue = badval;
  
	itCalculateSizeInfo(it);
	itCalculateNameInfo(it);
	return it;
}

/*
 *  Initializes the pre-defined types.
 */
void
init_type(void)
{
	u_int size;
  
	size = NBBY * sizeof (natural_t);
	if (size == 32) {
		machine_integer_name = "MACH_MSG_TYPE_INTEGER_32";
		machine_integer_size = MACH_MSG_TYPE_INTEGER_32;
	}
	else if (size == 64) {
		machine_integer_name = "MACH_MSG_TYPE_INTEGER_64";
		machine_integer_size = MACH_MSG_TYPE_INTEGER_64;
	}
	else
		error("init_type unknown size %d", size);
  
	machine_integer_bits = size;
  
	itRetCodeType = itAlloc();
	itRetCodeType->itName = "kern_return_t";
	itRetCodeType->itInName = machine_integer_size;
	itRetCodeType->itInNameStr = machine_integer_name;
	itRetCodeType->itOutName = machine_integer_size;
	itRetCodeType->itOutNameStr = machine_integer_name;
	itRetCodeType->itSize = machine_integer_bits;
	itCalculateSizeInfo(itRetCodeType);
	itCalculateNameInfo(itRetCodeType);
  
	itNdrCodeType = itAlloc();
	itNdrCodeType->itName = "NDR_record_t";
	itNdrCodeType->itInName = 0;
	itNdrCodeType->itInNameStr = "NDR_record_t";
	itNdrCodeType->itOutName = 0;
	itNdrCodeType->itOutNameStr = "NDR_record_t";
	itNdrCodeType->itSize = sizeof(NDR_record_t) * 8;
	itCalculateSizeInfo(itNdrCodeType);
	itCalculateNameInfo(itNdrCodeType);
  
	itDummyType = itAlloc();
	itDummyType->itName = "char *";
	itDummyType->itInName = MACH_MSG_TYPE_UNSTRUCTURED;
	itDummyType->itInNameStr = "MACH_MSG_TYPE_UNSTRUCTURED";
	itDummyType->itOutName = MACH_MSG_TYPE_UNSTRUCTURED;
	itDummyType->itOutNameStr = "MACH_MSG_TYPE_UNSTRUCTURED";
	itDummyType->itSize = PortSize;
	itCalculateSizeInfo(itDummyType);
	itCalculateNameInfo(itDummyType);
  
	itTidType = itAlloc();
	itTidType->itName = "tid_t";
	itTidType->itInName = machine_integer_size;
	itTidType->itInNameStr = machine_integer_name;
	itTidType->itOutName = machine_integer_size;
	itTidType->itOutNameStr = machine_integer_name;
	itTidType->itSize = machine_integer_bits;
	itTidType->itNumber = 6;
	itCalculateSizeInfo(itTidType);
	itCalculateNameInfo(itTidType);
  
	itRequestPortType = itAlloc();
	itRequestPortType->itName = "mach_port_t";
	itRequestPortType->itInName = MACH_MSG_TYPE_COPY_SEND;
	itRequestPortType->itInNameStr = "MACH_MSG_TYPE_COPY_SEND";
	itRequestPortType->itOutName = MACH_MSG_TYPE_PORT_SEND;
	itRequestPortType->itOutNameStr = "MACH_MSG_TYPE_PORT_SEND";
	itRequestPortType->itSize = PortSize;
	itCalculateSizeInfo(itRequestPortType);
	itCalculateNameInfo(itRequestPortType);
  
	itZeroReplyPortType = itAlloc();
	itZeroReplyPortType->itName = "mach_port_t";
	itZeroReplyPortType->itInName = 0;
	itZeroReplyPortType->itInNameStr = "0";
	itZeroReplyPortType->itOutName = 0;
	itZeroReplyPortType->itOutNameStr = "0";
	itZeroReplyPortType->itSize = PortSize;
	itCalculateSizeInfo(itZeroReplyPortType);
	itCalculateNameInfo(itZeroReplyPortType);
  
	itRealReplyPortType = itAlloc();
	itRealReplyPortType->itName = "mach_port_t";
	itRealReplyPortType->itInName = MACH_MSG_TYPE_MAKE_SEND_ONCE;
	itRealReplyPortType->itInNameStr = "MACH_MSG_TYPE_MAKE_SEND_ONCE";
	itRealReplyPortType->itOutName = MACH_MSG_TYPE_PORT_SEND_ONCE;
	itRealReplyPortType->itOutNameStr = "MACH_MSG_TYPE_PORT_SEND_ONCE";
	itRealReplyPortType->itSize = PortSize;
	itCalculateSizeInfo(itRealReplyPortType);
	itCalculateNameInfo(itRealReplyPortType);
  
	itWaitTimeType = itMakeCountType();
	itMsgOptionType = itMakeCountType();
}

/******************************************************
 *  Make sure return values of functions are assignable.
 ******************************************************/
void
itCheckReturnType(identifier_t name, ipc_type_t *it)
{
	if (!it->itStruct)
		error("type of %s is too complicated", name);
	if ((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) ||
		(it->itOutName == MACH_MSG_TYPE_POLYMORPHIC))
		error("type of %s can't be polymorphic", name);
}


/******************************************************
 *  Called by routine.c to check that request ports are
 *  simple and correct ports with send rights.
 ******************************************************/
void
itCheckRequestPortType(identifier_t name, ipc_type_t *it)
{
/*    error("Port size = %d %d name = %s\n", PortSize, it->itSize, it->itName);
	  error("server = %s user = %x\n",it->itServerType, it->itUserType);
*/
	if (((it->itOutName != MACH_MSG_TYPE_PORT_SEND) &&
		 (it->itOutName != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
		 (it->itOutName != MACH_MSG_TYPE_POLYMORPHIC)) ||
		(it->itNumber != 1) ||
		(it->itSize != PortSize) ||
		!it->itInLine ||
		!it->itStruct ||
		it->itVarArray)
		error("argument %s isn't a proper request port", name);
}


/******************************************************
 *  Called by routine.c to check that reply ports are
 *  simple and correct ports with send rights.
 ******************************************************/
void
itCheckReplyPortType(identifier_t name, ipc_type_t *it)
{
	if (((it->itOutName != MACH_MSG_TYPE_PORT_SEND) &&
		 (it->itOutName != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
		 (it->itOutName != MACH_MSG_TYPE_POLYMORPHIC) &&
		 (it->itOutName != 0)) ||
		(it->itNumber != 1) ||
		(it->itSize != PortSize) ||
		!it->itInLine ||
		!it->itStruct ||
		it->itVarArray)
		error("argument %s isn't a proper reply port", name);
}


/******************************************************
 *  Used by routine.c to check that WaitTime is a
 *  simple bit machine_integer_bits integer.
 ******************************************************/
void
itCheckIntType(identifier_t name, ipc_type_t *it)
{
	if ((it->itInName != machine_integer_size) ||
		(it->itOutName != machine_integer_size) ||
		(it->itNumber != 1) ||
		(it->itSize != machine_integer_bits) ||
		!it->itInLine ||
		!it->itStruct ||
		it->itVarArray)
		error("argument %s isn't a proper integer", name);
}

void
itCheckTokenType(identifier_t name, ipc_type_t *it)
{
	if (it->itMigInLine || it->itNoOptArray || it->itString ||
		it->itTypeSize != 8 || !it->itInLine || !it->itStruct ||
		it->itVarArray || it->itPortType)
		error("argument %s isn't a proper Token", name);
}
