/* idl2wrs.c
 * DCE RPC IDL to Wireshark dissector compiler
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

/*
TODO
   check that every cnf defined type,hffield,rename,... has been referenced
   at least once and if not,   abort with an error

   need to distinguish between NTTIME (absolute time) and relative time

   prune_xxx should only act inside of '[' ']'

   add support for bool8,16,32,64 with tfs strings

   add the remaining array type  (uvarray)

   add code to verify that union tag length is correct
*/
/* List of built in types :
   WERROR	A 32 bit integer holding a DCE/NT status code.

   uint8	A 8 bit integer
   int8

   uint16	A 16 bit integer
   int16

   uint32	A 32 bit integer
   int32

   uint64	A 64 bit integer

   udlong	A 64 bit integer aligned on 4 byte boundary
   dlong

   time_t	A 32 bit integer holding a unix style time_t

   NTTIME_hyper A 64 bit integer representing a NTTIME
   NTTIME_1sec

   unistr		A conformant and varying unicode string

   ascstr		A conformant and varying ascii string


   SID			A SID structure.

   uuid_t	A 16 byte FT_GUID blob.
   GUID


   policy_handle
   bool8
   uuid_t
   policy_handle
   NTTIME
*/

/* All field dissectors that call a normal type
   (i.e. not a pointer, not an array)
   has a local variable  unsigned param declared which is passed on to the
   type dissector.
   The default value is 0 but the PARAM_VALUE conformance tag can be used to
   change it.
   This is only meaningful if the called type dissector actually does anything
   with this parameter.
*/

#define _GNU_SOURCE

#include <glib.h>
#include <glib/gstdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <wsutil/strtoi.h>

#undef IDL2WRS_DEBUG

#define DISSECTORNAME_MAXLEN 256

#define BASE_BUFFER_SIZE 256

static FILE *tfh, *eth_code, *eth_hdr, *eth_hf, *eth_hfarr, *eth_ett, *eth_ettarr, *eth_ft, *eth_handoff;
static char *uuid=NULL;
static char *version=NULL;
static const char *pointer_default=NULL;
static char *ifname=NULL;
static char hf_status[BASE_BUFFER_SIZE];
static int lineno,linepos;
static char line[4 * BASE_BUFFER_SIZE];

static void FPRINTF(FILE *fh, const char *format, ...)
{
	va_list args;

#ifdef IDL2WRS_DEBUG
	va_start(args, format);
	vfprintf (stderr, format, args);
	va_end(args);
#endif
	if (fh) {
		va_start(args, format);
		vfprintf (fh, format, args);
		va_end(args);
	}
}

typedef struct _pointer_item_t {
	struct _pointer_item_t *next;
	const char *type;
} pointer_item_t;

#define BI_CASE			0x00000001
#define BI_CASE_DEFAULT		0x00000002
#define BI_IN			0x00000004
#define BI_OUT			0x00000008
#define BI_SIZE_IS		0x00000010
#define BI_LENGTH_IS		0x00000020
#define BI_POINTER		0x00000040
#define BI_BITMAP8		0x00000100
#define BI_BITMAP32		0x00000200
#define BI_SWITCH_TYPE		0x00000400
typedef struct _bracket_item_t {
	unsigned int flags;
	const char *case_name;
	pointer_item_t *pointer_list;
	int union_tag_size;
} bracket_item_t;

typedef struct _no_emit_item_t {
	struct _no_emit_item_t *next;
	char *name;
} no_emit_item_t;
static no_emit_item_t *no_emit_list=NULL;

typedef struct _hf_rename_item_t {
	struct _hf_rename_item_t *next;
	int refcount;	/* number of times this rename has been referenced */
	char *old_name;
	char *new_name;
} hf_rename_item_t;
static hf_rename_item_t *hf_rename_list=NULL;

typedef struct _enum_list_t {
	struct _enum_list_t *next;
	char *name;
	int val;
} enum_list_t;

typedef struct _token_item_t {
	struct _token_item_t *next;
	char *str;
} token_item_t;
static token_item_t *token_list=NULL;
static token_item_t *last_token_item=NULL;

typedef struct _type_item_t {
	struct _type_item_t *next;
	char *name;
	char *dissector;
	char *ft_type;
	char *base_type;
	char *mask;
	char *vals;
	int alignment;
} type_item_t;
static type_item_t *type_list=NULL;

typedef struct _union_tag_size_item_t {
	struct _union_tag_size_item_t *next;
	char *name;
	int size;
} union_tag_size_item_t;
static union_tag_size_item_t *union_tag_size_list=NULL;

typedef struct _hf_field_item_t {
	struct _hf_field_item_t *next;
	char *name;
	char *ft_type;
} hf_field_item_t;
static hf_field_item_t *hf_field_list=NULL;

typedef struct _dissector_param_value_t {
	struct _dissector_param_value_t *next;
	char *name;
	char *value;
} dissector_param_value_t;
static dissector_param_value_t *dissector_param_list=NULL;

static type_item_t *find_type(char *name);
static int Exit(int code);

static void
register_dissector_param_value(const char *name, const char *value)
{
	dissector_param_value_t *dpv;
	dpv=g_new0(dissector_param_value_t, 1);
	if (!dpv) {
		FPRINTF(stderr, "Can't allocate memory. Exit.\n");
		exit(10);
	}
	dpv->next=dissector_param_list;
	dissector_param_list=dpv;
	dpv->name=g_strdup(name);
	dpv->value=g_strdup(value);
}

static const char *
find_dissector_param_value(char *name)
{
	dissector_param_value_t *dpv;
	for(dpv=dissector_param_list;dpv;dpv=dpv->next){
		if(!g_strcmp0(name,dpv->name)){
			return dpv->value;
		}
	}
	return "0";
}

static pointer_item_t *
prepend_pointer_list(pointer_item_t *ptrs, int num_pointers)
{
	pointer_item_t *pi;

	pi=ptrs;
	while(pi){
		if(num_pointers)num_pointers--;
		pi=pi->next;
	}
	pi=ptrs;
	while(num_pointers--){
		pi=g_new0(pointer_item_t, 1);
		if (!pi) {
			FPRINTF(stderr, "Can't allocate memory. Exit.\n");
			exit(10);
		}
		pi->next=ptrs;
		pi->type=pointer_default;
		ptrs=pi;
	}
	ptrs=pi;

	return ptrs;
}

static const char *
ptr_to_define(const char *pointer_type)
{
	if(!g_strcmp0(pointer_type, "unique")){
		return "NDR_POINTER_UNIQUE";
	} else if(!g_strcmp0(pointer_type, "ref")){
		return "NDR_POINTER_REF";
	} else if(!g_strcmp0(pointer_type, "ptr")){
		return "NDR_POINTER_PTR";
	}

	FPRINTF(stderr, "prt_to_define, 	weirdo pointer :%s\n", pointer_type);
	exit(10);
}

static int
get_union_tag_size(char *name)
{
	union_tag_size_item_t *utsi;
	for(utsi=union_tag_size_list;utsi;utsi=utsi->next){
		if(!g_strcmp0(name, utsi->name)){
			return utsi->size;
		}
	}
	FPRINTF(stderr, "ERROR: size of tag for union:%s is not known\n", name);
	FPRINTF(stderr, "  use the UNION_TAG_SIZE directive to specify it in the conformance file\n");
	exit(10);
}


/* this function will add an entry to the hf_rename list */
static void
register_hf_rename(const char *old_name, const char *new_name)
{
	hf_rename_item_t *new_item;
	new_item=g_new0(hf_rename_item_t, 1);
	if (!new_item) {
		FPRINTF(stderr, "Can't allocate memory. Exit.\n");
		exit(10);
	}
	new_item->next=hf_rename_list;
	hf_rename_list=new_item;
	new_item->refcount=0;
	new_item->old_name=g_strdup(old_name);
	new_item->new_name=g_strdup(new_name);
}

/* this function checks that all hf_rename fields have actually been referenced
   if not	out conformance file is stale
*/
static void
check_hf_rename_refcount(void)
{
	hf_rename_item_t *hri;

	/* don't generate code for renamed hf fields  just return the new name*/
	for(hri=hf_rename_list;hri;hri=hri->next){
		if(!hri->refcount){
			FPRINTF(stderr, "ERROR: the hf_rename field:%s was never referenced. it is likely the conformance file is stale\n", hri->old_name);
			exit(10);
		}
	}
}

static hf_field_item_t *
find_hf_field(char *name)
{
	hf_field_item_t *hfi;

	for(hfi=hf_field_list;hfi;hfi=hfi->next){
		if(!g_strcmp0(hfi->name, name)){
			break;
		}
	}
	if (!hfi) {
		FPRINTF(stderr, "find_hf_field:  unknown hf_field:%s\n",name);
		Exit(10);
	}

	return hfi;
}


/* this function will create the code required for a hf field.
   it MIGHT rename the field so a user MUST use the name returned
   from this function.
   for fields that are to be renamed  no code is generated
*/
static const char *
register_hf_field(const char *hf_name, const char *title, const char *filter_name, const char *ft_type, const char *base_type, const char *valsstring, const char *mask, const char *blurb)
{
	hf_field_item_t *hfi;
	hf_rename_item_t *hri;

	/* don't generate code for renamed hf fields  just return the new name*/
	for(hri=hf_rename_list;hri;hri=hri->next){
		if(!strncmp(hf_name, hri->old_name, strlen(hf_name))){
			hfi=find_hf_field(hri->new_name);
			if(g_strcmp0(ft_type, hfi->ft_type)){
				FPRINTF(stderr, "register_hf_field:  hf_fields %s and %s have different types %s %s\n",hf_name,hfi->name,ft_type,hfi->ft_type);
				Exit(10);
			}
			hri->refcount++;
			return hri->new_name;
		}
	}

	hfi=g_new0(hf_field_item_t, 1);
	if (!hfi) {
		FPRINTF(stderr, "Can't allocate memory. Exit.\n");
		exit(10);
	}
	hfi->next=hf_field_list;
	hf_field_list=hfi;
	hfi->name=g_strdup(hf_name);
	hfi->ft_type=g_strdup(ft_type);

	FPRINTF(eth_hf, "static int %s;\n", hf_name);
	FPRINTF(eth_hfarr, "		{ &%s,\n", hf_name);
	FPRINTF(eth_hfarr, "		  { \"%s\", \"%s\", %s, %s,\n", title, filter_name, ft_type, base_type);
	FPRINTF(eth_hfarr, "		  %s, %s,\n", valsstring, mask);
	if (strlen(blurb) > 0)
		FPRINTF(eth_hfarr, "		 \"%s\", HFILL }},\n", blurb);
	else
		FPRINTF(eth_hfarr, "		 NULL, HFILL }},\n");
	FPRINTF(eth_hfarr, "\n");

	return hf_name;
}

/* this function will parse the no emit list and decide whether code should
   be generated for this dissector or if we should only register the type.
*/
static int
check_if_to_emit(char *name)
{
	no_emit_item_t *nel;

	for(nel=no_emit_list;nel;nel=nel->next){
		if(!g_strcmp0(name, nel->name)){
			FPRINTF(NULL, "SKIPPED emitting of %s\n",name);
			return 0;
		}
	}
	return 1;
}

#if 0
static void
prune_keywords(char *name)
{
	token_item_t *ti;

	for(ti=token_list;ti;ti=ti->next){
		if(!ti->next){
			break;
		}
		if(!g_strcmp0(ti->next->str, name)){
			if(!g_strcmp0(ti->next->next->str, ",")){
				ti->next=ti->next->next->next;
			} else {
				ti->next=ti->next->next;
			}
		}
	}
}
#endif

static void
rename_tokens(const char *old_name, const char *new_name)
{
	token_item_t *ti;

	for(ti=token_list;ti;ti=ti->next){
		if(!g_strcmp0(ti->str, old_name)){
			ti->str=g_strdup(new_name);
		}
	}
}

static void
prune_keyword_parameters(const char *name)
{
	token_item_t *ti, *tmpti;

	for(ti=token_list;ti;ti=ti->next){
		if(!g_strcmp0(ti->str, name)){
			if(!g_strcmp0(ti->next->str, "(")){
				tmpti=ti;
				while(1){
					if(!g_strcmp0(tmpti->str, ")")){
						ti->next=tmpti->next;
						break;
					}
					tmpti=tmpti->next;
				}
			}
		}
	}
}

/* this function will parse a bracket item
	   [ ... ]
   it will return the token of the next item following the ']'
*/
static token_item_t *
parsebrackets(token_item_t *ti, bracket_item_t **bracket){
	bracket_item_t *br;
	const type_item_t *type_item;

	if(g_strcmp0(ti->str, "[")){
		FPRINTF(stderr, "ERROR: parsebrackets first token is not '['\n");
		Exit(10);
	}
	ti=ti->next;

	br=g_new0(bracket_item_t, 1);
	if (!br) {
		FPRINTF(stderr, "Can't allocate memory. Exit.\n");
		exit(10);
	}
	*bracket=br;
	br->flags=0;
	br->case_name=NULL;
	br->pointer_list=NULL;

	while(ti){
		if( !g_strcmp0(ti->str, "{")
		  ||!g_strcmp0(ti->str, "}")){
			FPRINTF(stderr, "ERROR: parsebrackets '{' '}' inside bracket item\n");
			Exit(10);
		}

		if(!g_strcmp0(ti->str, "[")){
			FPRINTF(stderr, "ERROR: parsebrackets '[' inside bracket item\n");
			Exit(10);
		}

		/* finished */
		if(!g_strcmp0(ti->str, "]")){
			/* check for [ ... ] [ ...] */
			ti=ti->next;

			if(!g_strcmp0(ti->str, "[")){
				ti=ti->next;
				continue;
			}
			return ti;
		}

		/* just ignore all ',' */
		if(!g_strcmp0(ti->str, ",")){
			ti=ti->next;
			continue;
		}

		/* case '(' tag ')' */
		if(!g_strcmp0(ti->str, "case")){
			br->flags|=BI_CASE;
			ti=ti->next;

			if(g_strcmp0(ti->str, "(")){
				FPRINTF(stderr, "ERROR: parsebrackets case not followed by '('\n");
				Exit(10);
			}
			ti=ti->next;

			/* name */
			br->case_name=ti->str;
			ti=ti->next;

			if(g_strcmp0(ti->str, ")")){
				FPRINTF(stderr, "ERROR: parsebrackets case does not end with ')'\n");
				Exit(10);
			}
			ti=ti->next;
			continue;
		}

		/* default */
		if(!g_strcmp0(ti->str, "default")){
			br->flags|=BI_CASE;
			br->flags|=BI_CASE_DEFAULT;
			br->case_name="default";
			ti=ti->next;
			continue;
		}


		/* in */
		if(!g_strcmp0(ti->str, "in")){
			br->flags|=BI_IN;
			ti=ti->next;
			continue;
		}

		/* out */
		if(!g_strcmp0(ti->str, "out")){
			br->flags|=BI_OUT;
			ti=ti->next;
			continue;
		}

		/* public : we don't care about this one */
		if(!g_strcmp0(ti->str, "public")){
			ti=ti->next;
			continue;
		}

		/* gensize : we don't care about this one */
		if(!g_strcmp0(ti->str, "gensize")){
			ti=ti->next;
			continue;
		}

		/* switch_is */
		if(!g_strcmp0(ti->str, "switch_is")){
			FPRINTF(stderr, "WARNING: parsebrackets can not handle switch_is properly yet  so we can not verify the tag size\n");
			while(ti){
				if(!g_strcmp0(ti->str, ")")){
					ti=ti->next;
					break;
				}
				ti=ti->next;
			}
			continue;
		}

		/* switch_is */
		if(!g_strcmp0(ti->str, "subcontext")){
			while(ti){
				if(!g_strcmp0(ti->str, ")")){
					ti=ti->next;
					break;
				}
				ti=ti->next;
			}
			continue;
		}

		/* value   we don't care about this one so just skip it */
		if(!g_strcmp0(ti->str, "value")){
			int level;
			ti=ti->next;
			if( g_strcmp0(ti->str, "(") ){
				FPRINTF(stderr, "WARNING: parsebrackets value was not followed by '('\n");
				Exit(10);
			}
			level=0;
			while(ti){
				if(!g_strcmp0(ti->str, "(")){
					ti=ti->next;
					level++;
					continue;
				}
				if(!g_strcmp0(ti->str, ")")){
					ti=ti->next;
					level--;
					if(level){
						continue;
					}
					break;
				}
				ti=ti->next;
			}
			continue;
		}

		/* range   we don't care about this one so just skip it */
		if(!g_strcmp0(ti->str, "range")){
			int level;
			ti=ti->next;
			if( g_strcmp0(ti->str, "(") ){
				FPRINTF(stderr, "WARNING: parsebrackets range was not followed by '('\n");
				Exit(10);
			}
			level=0;
			while(ti){
				if(!g_strcmp0(ti->str, "(")){
					ti=ti->next;
					level++;
					continue;
				}
				if(!g_strcmp0(ti->str, ")")){
					ti=ti->next;
					level--;
					if(level){
						continue;
					}
					break;
				}
				ti=ti->next;
			}
			continue;
		}

		/* flag   we don't care about this one so just skip it */
		if(!g_strcmp0(ti->str, "flag")){
			int level;
			ti=ti->next;
			if( g_strcmp0(ti->str, "(") ){
				FPRINTF(stderr, "WARNING: parsebrackets flag was not followed by '('\n");
				Exit(10);
			}
			level=0;
			while(ti){
				if(!g_strcmp0(ti->str, "(")){
					ti=ti->next;
					level++;
					continue;
				}
				if(!g_strcmp0(ti->str, ")")){
					ti=ti->next;
					level--;
					if(level){
						continue;
					}
					break;
				}
				ti=ti->next;
			}
			continue;
		}

		/* switch_type */
		if(!g_strcmp0(ti->str, "switch_type")){
			br->flags|=BI_SWITCH_TYPE;
			ti=ti->next;

			if(g_strcmp0(ti->str, "(")){
				FPRINTF(stderr, "WARNING: parsebrackets switch_type was not followed by '('\n");
				Exit(10);
			}
			ti=ti->next;

			type_item=find_type(ti->str);
			if(!type_item){
				FPRINTF(stderr, "ERROR : parsebrackets switch_type unknown type %s\n",ti->str);
				Exit(10);
			}
			br->union_tag_size=type_item->alignment;
			ti=ti->next;

			if(g_strcmp0(ti->str, ")")){
				FPRINTF(stderr, "WARNING: parsebrackets switch_type did not end with ')'\n");
				Exit(10);
			}
			ti=ti->next;

			continue;
		}

		/* size_is */
		if(!g_strcmp0(ti->str, "size_is")){
			br->flags|=BI_SIZE_IS;
			ti=ti->next;
			continue;
		}

		/* length_is */
		if(!g_strcmp0(ti->str, "length_is")){
			br->flags|=BI_LENGTH_IS;
			ti=ti->next;
			continue;
		}

		/* bitmap8bit */
		if(!g_strcmp0(ti->str, "bitmap8bit")){
			br->flags|=BI_BITMAP8;
			ti=ti->next;
			continue;
		}

		/* bitmap32bit */
		if(!g_strcmp0(ti->str, "bitmap32bit")){
			br->flags|=BI_BITMAP32;
			ti=ti->next;
			continue;
		}

		/* ref, unique or ptr */
		if(!g_strcmp0(ti->str, "ref")
		|| !g_strcmp0(ti->str, "unique")
		|| !g_strcmp0(ti->str, "ptr")){
			pointer_item_t *newpi;

			br->flags|=BI_POINTER;
			newpi=g_new0(pointer_item_t, 1);
			if (!newpi) {
				FPRINTF(stderr, "Can't allocate memory. Exit.\n");
				exit(10);
			}
			newpi->next=NULL;
			newpi->type=ti->str;
			newpi->next=br->pointer_list;
			br->pointer_list=newpi;
			ti=ti->next;
			continue;
		}
		if(ti){
			FPRINTF(stderr, "ERROR: parsebrackets should not be reached  unknown tag:%s\n", ti->str);
		}
		Exit(10);
	}

	return NULL;
}

/* this function will register a new type learnt from the IDL file
*/
static type_item_t *
register_new_type(const char *name, const char *dissectorname, const char *ft_type, const char *base_type, const char *mask, const char *valsstring, int alignment){
	type_item_t *new_type;

	FPRINTF(NULL,"XXX new type:%s dissector:%s Type:%s Base:%s Mask:%s Vals:%s alignment:%d\n", name, dissectorname, ft_type, base_type, mask, valsstring, alignment);

	new_type=g_new0(type_item_t, 1);
	if (!new_type) {
		FPRINTF(stderr, "Can't allocate memory. Exit.\n");
		exit(10);
	}
	new_type->next=type_list;
	new_type->name=g_strdup(name);
	new_type->dissector=g_strdup(dissectorname);
	new_type->ft_type=g_strdup(ft_type);
	new_type->base_type=g_strdup(base_type);
	new_type->mask=g_strdup(mask);
	new_type->vals=g_strdup(valsstring);
	new_type->alignment=alignment;
	type_list=new_type;

	return new_type;
}


/* this function will print the remaining content of the token list
*/
static void printtokenlist(int count)
{
	token_item_t *ti;
	FPRINTF(stderr, "TOKENLIST:\n");
	for(ti=token_list;ti&&count;count--,ti=ti->next){
		FPRINTF(stderr, "Token \"%s\"\n",ti->str);
	}
	if(!count){
		FPRINTF(stderr, "	 ...\n");
	}
}


/* this function will parse the header and pick up the fields
 * we are interested in.
 * the header is supposed to start at the very first token and look like
 * [ <fields> ] interface <ifname> {
 *
 * we are interested in the fields:
 *	   uuid
 *	   version
 *	   pointer_default
 *
 * this function will also g_remove the header from the token list
 */
static void parseheader(void)
{
	char filter_name[BASE_BUFFER_SIZE];
	token_item_t *ti;
	int level=0;
	int major, minor;

	ti=token_list;
	if(!ti){
		FPRINTF(stderr, "ERROR: no tokens\n");
		Exit(10);
	}

	/* first token must be '[' */
	if( g_strcmp0(ti->str, "[") ){
		FPRINTF(stderr, "ERROR: first token is not '['\n");
		Exit(10);
	}

	for(ti=token_list;ti;ti=ti->next){
		if( !g_strcmp0(ti->str, "[")){
			level++;
			continue;
		}
		if( !g_strcmp0(ti->str, "]")){
			level--;
			if(!level){
				token_list=ti->next;
				break;
			}
		}
		if(level==1){
			if( !g_strcmp0(ti->str, "uuid")){
				uuid=ti->next->next->str;
				FPRINTF(NULL,"UUID:%s\n",uuid);
			}
			if( !g_strcmp0(ti->str, "version")){
				version=ti->next->next->str;
				FPRINTF(NULL,"VERSION:%s\n",version);
			}
			if( !g_strcmp0(ti->str, "pointer_default")){
				if(!g_strcmp0(ti->next->next->str, "unique")){
					pointer_default="unique";
				} else if(!g_strcmp0(ti->next->next->str, "ptr")){
					pointer_default="ptr";
				} else {
					FPRINTF(stderr, "ERROR: unknown pointer type\n");
					Exit(10);
				}
				FPRINTF(NULL,"POINTER_DEFAULT:%s\n",pointer_default);
			}
		}
	}
	if(!token_list){
		FPRINTF(stderr, "ERROR: ran out of tokens inside header\n");
		Exit(10);
	}
	/* interface */
	if(g_strcmp0(token_list->str, "interface")){
		FPRINTF(stderr, "ERROR: interface not found\n");
		Exit(10);
	}
	token_list=token_list->next;
	if (!token_list){
		FPRINTF(stderr, "ERROR: ran out of tokens\n");
		Exit(10);
	}
	/* interface name */
	ifname=token_list->str;
	token_list=token_list->next;
	FPRINTF(NULL,"Interface:%s\n",ifname);

	/* opnum */
	snprintf(hf_status, BASE_BUFFER_SIZE, "hf_%s_opnum", ifname);
	snprintf(filter_name, BASE_BUFFER_SIZE, "%s.opnum", ifname);
	register_hf_field(hf_status, "Operation", filter_name, "FT_UINT16", "BASE_DEC", "NULL", "0", "");

	/* status */
	snprintf(hf_status, BASE_BUFFER_SIZE, "hf_%s_rc", ifname);
	snprintf(filter_name, BASE_BUFFER_SIZE, "%s.rc", ifname);
	register_hf_field(hf_status, "Return code", filter_name, "FT_UINT32", "BASE_HEX|BASE_EXT_STRING", "&NT_errors_ext", "0", "");

	FPRINTF(eth_ett, "static int ett_%s;\n", ifname);
	FPRINTF(eth_ettarr, "		 &ett_%s,\n", ifname);

	/* the body must start with { */
	if(g_strcmp0(token_list->str, "{")){
		FPRINTF(stderr, "ERROR: body does not start with '{'\n");
		Exit(10);
	}

	/* skip the initial '{' */
	token_list=token_list->next;

	if(!uuid){
		FPRINTF(stderr, "ERROR: no uuid found\n");
		Exit(10);
	}
	FPRINTF(eth_code,"static e_guid_t uuid_dcerpc_%s = {\n", ifname);
	FPRINTF(eth_code,"	  0x%c%c%c%c%c%c%c%c, 0x%c%c%c%c, 0x%c%c%c%c,\n",uuid[1],uuid[2],uuid[3],uuid[4],uuid[5],uuid[6],uuid[7],uuid[8],uuid[10],uuid[11],uuid[12],uuid[13],uuid[15],uuid[16],uuid[17],uuid[18]);
	FPRINTF(eth_code,"	  { 0x%c%c, 0x%c%c, 0x%c%c, 0x%c%c, 0x%c%c, 0x%c%c, 0x%c%c, 0x%c%c}\n",uuid[20],uuid[21],uuid[22],uuid[23],uuid[25],uuid[26],uuid[27],uuid[28],uuid[29],uuid[30],uuid[31],uuid[32],uuid[33],uuid[34],uuid[35],uuid[36]);
	FPRINTF(eth_code,"};\n");
	FPRINTF(eth_code,"\n");

	sscanf(version, "%d.%d", &major, &minor);
	FPRINTF(eth_code,"static uint16_t ver_%s = %d;\n", ifname, major);
	FPRINTF(eth_code,"\n");

	FPRINTF(eth_handoff, "	  dcerpc_init_uuid(proto_%s, ett_%s,\n", ifname, ifname);
	FPRINTF(eth_handoff, "		  &uuid_dcerpc_%s, ver_%s,\n", ifname, ifname);
	FPRINTF(eth_handoff, "		  function_dissectors, hf_%s_opnum);\n", ifname);
}



/* this helper function is called by the tokenizer and will just append the
   current token to the linked list
*/
static void pushtoken(char *token)
{
	token_item_t *new_token_item;
	new_token_item=g_new0(token_item_t, 1);
	if (!new_token_item) {
		FPRINTF(stderr, "Can't allocate memory. Exit.\n");
		exit(10);
	}
	new_token_item->next=NULL;
	new_token_item->str=token;
	if(!token_list){
		token_list=new_token_item;
	} else {
		last_token_item->next=new_token_item;
	}
	last_token_item=new_token_item;
}

/* this function reads the idl file and translates it into tokens.
   the tokens are stored in a linked list  token_list of type token_item_t
*/
static void tokenize(FILE *fh)
{
	int ch;
	int fullinecomment=0;
	int normalcomment=0;
	int insidequote=0;
	char qs[4 * BASE_BUFFER_SIZE];
	int qspos=0;
	int insidetoken=0;
	char token[4 * BASE_BUFFER_SIZE];
	int tokenpos=0;

	while(!feof(fh)){
		ch=fgetc(fh);

		/* full line comment */
		if(fullinecomment){
			if( (ch=='\n')||(ch=='\r') ){
				fullinecomment=0;
				linepos=0;
			}
			continue;
		}
		if( (ch=='#')&&(linepos==0) ){
			fullinecomment=1;
			continue;
		}

		/* normal comment */
		if(normalcomment==0){
			if(ch=='/'){
				int nextch;
				nextch=fgetc(fh);
				if(nextch=='*'){
					normalcomment=1;
					continue;
				}
				ungetc(nextch, fh);
			}
		} else {
			if(ch=='*'){
				int nextch;
				nextch=fgetc(fh);
				if(nextch=='/'){
					normalcomment=0;
					continue;
				}
				ungetc(nextch, fh);
			}
			continue;
		}

		/* quoted string */
		if(insidequote){
			if(ch=='"'){
				insidequote=0;
				qs[qspos++]='"';
				qs[qspos]=0;
				pushtoken(g_strdup(qs));
				continue;
			} else {
				qs[qspos++]=(char)ch;
				continue;
			}
		} else {
			if(ch=='"'){
				insidequote=1;
				qs[0]='"';
				qspos=1;
				continue;
			}
		}


		switch(ch){
		case '\n':
		case '\r':
			if(insidetoken){
				insidetoken=0;
				token[tokenpos]=0;
				pushtoken(g_strdup(token));
			}
			line[linepos]=0;

			linepos=0;
			lineno++;
			break;
		case '\t':
		case ' ':
			if(insidetoken){
				insidetoken=0;
				token[tokenpos]=0;
				pushtoken(g_strdup(token));
			}
			break;
		case '[':
		case ']':
		case '(':
		case ')':
		case ',':
		case ';':
		case '*':
		case '=':
			if(insidetoken){
				insidetoken=0;
				token[tokenpos]=0;
				pushtoken(g_strdup(token));
			}
			token[0]=(char)ch;
			token[1]=0;
			pushtoken(g_strdup(token));
			break;
		default:
			if(!insidetoken){
				tokenpos=0;
			}
			insidetoken=1;
			token[tokenpos++]=(char)ch;
			line[linepos++]=(char)ch;
			break;
		}

	}
}


static type_item_t *
find_type(char *name)
{
	type_item_t *tmptype;
	for(tmptype=type_list;tmptype;tmptype=tmptype->next){
		if(!g_strcmp0(tmptype->name, name)){
			break;
		}
	}
	/* autogenerate built in types */
	if(!tmptype){
		char dissectorname[DISSECTORNAME_MAXLEN];
		if(!g_strcmp0(name,"uint16")){
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    offset=dissect_ndr_uint16(tvb, offset, pinfo, tree, di, drep, hf_index, NULL);\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("uint16", dissectorname, "FT_UINT16", "BASE_DEC", "0", "NULL", 2);
		} else if(!g_strcmp0(name,"int16")){
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    offset=dissect_ndr_uint16(tvb, offset, pinfo, tree, di, drep, hf_index, NULL);\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("int16", dissectorname, "FT_INT16", "BASE_DEC", "0", "NULL", 2);
		} else if(!g_strcmp0(name,"uint32")){
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    offset=dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep, hf_index, NULL);\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("uint32", dissectorname, "FT_UINT32", "BASE_DEC", "0", "NULL", 4);
		} else if( (!g_strcmp0(name,"int32"))
			|| (!g_strcmp0(name,"long")) ){
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    offset=dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep, hf_index, NULL);\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			if (!g_strcmp0(name,"int32"))
				tmptype=register_new_type("int32", dissectorname, "FT_INT32", "BASE_DEC", "0", "NULL", 4);
			else
				tmptype=register_new_type("long", dissectorname, "FT_INT32", "BASE_DEC", "0", "NULL", 4);
		} else if( (!g_strcmp0(name,"uint8")) ){
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    offset=dissect_ndr_uint8(tvb, offset, pinfo, tree, di, drep, hf_index, NULL);\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("uint8", dissectorname, "FT_UINT8", "BASE_DEC", "0", "NULL", 1);
		} else if( (!g_strcmp0(name,"int8"))
			|| (!g_strcmp0(name, "char")) ){
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    offset=dissect_ndr_uint8(tvb, offset, pinfo, tree, di, drep, hf_index, NULL);\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			if (!g_strcmp0(name,"int8"))
				tmptype=register_new_type("int8", dissectorname, "FT_INT8", "BASE_DEC", "0", "NULL", 1);
			else
				tmptype=register_new_type("char", dissectorname, "FT_INT8", "BASE_DEC", "0", "NULL", 1);
		} else if(!g_strcmp0(name,"bool8")){
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    offset=dissect_ndr_uint8(tvb, offset, pinfo, tree, di, drep, hf_index, NULL);\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("bool8", dissectorname, "FT_INT8", "BASE_DEC", "0", "NULL", 1);
		} else if(!g_strcmp0(name,"unistr")){
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    offset=dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep, 2, hf_index, false, NULL);\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("unistr", dissectorname, "FT_STRING", "BASE_NONE", "0", "NULL", 4);
		} else if(!g_strcmp0(name,"ascstr")){
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    offset=dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep, 1, hf_index, false, NULL);\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("ascstr", dissectorname, "FT_STRING", "BASE_NONE", "0", "NULL", 4);
		} else if(!g_strcmp0(name,"GUID")
			||!g_strcmp0(name,"uuid_t")){
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    offset=dissect_ndr_uuid_t(tvb, offset, pinfo, tree, di, drep, hf_index, NULL);\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type(name, dissectorname, "FT_GUID", "BASE_NONE", "0", "NULL", 4);
		} else if(!g_strcmp0(name,"policy_handle")){
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static e_ctx_hnd policy_hnd;\n");
			FPRINTF(eth_code, "static proto_item *hnd_item;\n");
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, di, drep,\n");
			FPRINTF(eth_code, " 				  hf_index, &policy_hnd, &hnd_item,\n");
			FPRINTF(eth_code, " 				  param);\n");

			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("policy_handle", dissectorname, "FT_BYTES", "BASE_NONE", "0", "NULL", 4);
		} else if(!g_strcmp0(name,"NTTIME")){
			/* 8 bytes, aligned to 4 bytes */
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    offset = dissect_ndr_nt_NTTIME(tvb, offset, pinfo, tree, di, drep, hf_index);\n");

			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("NTTIME", dissectorname, "FT_ABSOLUTE_TIME", "ABSOLUTE_TIME_LOCAL", "0", "NULL", 4);
		} else if(!g_strcmp0(name,"NTTIME_hyper")){
			/* 8 bytes, aligned to 8 bytes */
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    ALIGN_TO_8_BYTES;\n");
			FPRINTF(eth_code, "    offset = dissect_ndr_nt_NTTIME(tvb, offset, pinfo, tree, di, drep, hf_index);\n");

			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("NTTIME_hyper", dissectorname, "FT_ABSOLUTE_TIME", "ABSOLUTE_TIME_LOCAL", "0", "NULL", 4);
		} else if(!g_strcmp0(name,"NTTIME_1sec")){
			/* 8 bytes, aligned to 8 bytes */
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    ALIGN_TO_8_BYTES;\n");
			FPRINTF(eth_code, "    offset = dissect_ndr_nt_NTTIME(tvb, offset, pinfo, tree, di, drep, hf_index);\n");

			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("NTTIME_1sec", dissectorname, "FT_ABSOLUTE_TIME", "ABSOLUTE_TIME_LOCAL", "0", "NULL", 4);
		} else if(!g_strcmp0(name,"udlong")){
			/* 8 bytes, aligned to 4 bytes */
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "    offset=dissect_ndr_duint32(tvb, offset, pinfo, tree, di, drep, hf_index, NULL);\n");
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("udlong", dissectorname, "FT_UINT64", "BASE_DEC", "0", "NULL", 4);
		} else if(!g_strcmp0(name,"dlong")){
			/* 8 bytes, aligned to 4 bytes */
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "    offset=dissect_ndr_duint32(tvb, offset, pinfo, tree, di, drep, hf_index, NULL);\n");
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("dlong", dissectorname, "FT_INT64", "BASE_DEC", "0", "NULL", 4);
		} else if(!g_strcmp0(name,"uint64")){
			/* 8 bytes, aligned to 8 bytes */
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    \n");
			FPRINTF(eth_code, "    ALIGN_TO_8_BYTES;\n");
			FPRINTF(eth_code, "    offset=dissect_ndr_uint64(tvb, offset, pinfo, tree, di, drep, hf_index, NULL);\n");
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("uint64", dissectorname, "FT_UINT64", "BASE_DEC", "0", "NULL", 8);
		} else if(!g_strcmp0(name,"time_t")){
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "    offset=dissect_ndr_time_t(tvb, offset, pinfo, tree, di, drep, hf_index, NULL);\n");
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("time_t", dissectorname, "FT_ABSOLUTE_TIME", "ABSOLUTE_TIME_LOCAL", "0", "NULL", 4);
		} else if(!g_strcmp0(name,"SID")){
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    offset=dissect_ndr_nt_SID_with_options(tvb, offset, pinfo, tree, di, drep, param, hf_index);\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("SID", dissectorname, "FT_STRING", "BASE_NONE", "0", "NULL", 4);
		} else if(!g_strcmp0(name,"WERROR")){
			snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, name);
			FPRINTF(NULL,"\nAutogenerating built-in type:%s\n------------\n",name);
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    \n");
			FPRINTF(eth_code, "    offset=dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep, hf_index, NULL);\n");
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");
			tmptype=register_new_type("WERROR", dissectorname, "FT_UINT32", "BASE_DEC|BASE_EXT_STRING", "0", "&WERR_errors_ext", 4);
		}
	}

	return tmptype;
}


/* this function will skip past an entire declare ... ; statement */
static void skipdeclare(void)
{
	token_item_t *ti;

	/* first must be the keyword const */
	ti=token_list;
	if(strncmp(ti->str, "declare", 7)){
		FPRINTF(stderr, "ERROR: skipdeclare  first token is not 'declare'\n");
		Exit(10);
	}
	while(ti->str[0] != ';'){
		ti=ti->next;
	}
	ti=ti->next;

	token_list=ti;
}

/* this function will parse a
	   const
   and generate the appropriate code
   const must be followed by a suitable keyword [uint16|uint32|...]
   the const will later be g_removed from the token list
   the function assumes that the const is the first object in the token_list
*/
static void parseconst(void)
{
	token_item_t *ti;
	char *name, *value;

	/* first must be the keyword const */
	ti=token_list;
	if(strncmp(ti->str, "const", 5)){
		FPRINTF(stderr, "ERROR: const  first token is not 'const'\n");
		Exit(10);
	}
	ti=ti->next;

	/* just skip second token */
	ti=ti->next;

	/* third is a variable and not a type */
	if(find_type(ti->str)){
		FPRINTF(stderr, "ERROR: const, not a variable name:%s\n", ti->str);
		Exit(10);
	}
	name=ti->str;
	ti=ti->next;

	/* fourth is '=' */
	if(ti->str[0] != '='){
		FPRINTF(stderr, "ERROR: const  fourth token is not '='\n");
		Exit(10);
	}
	ti=ti->next;

	/* fifth is the value */
	value=ti->str;
	ti=ti->next;

	/* sixth is ';' */
	if(ti->str[0] != ';'){
		FPRINTF(stderr, "ERROR: const  sixth token is not ';'\n");
		Exit(10);
	}
	ti=ti->next;

	FPRINTF(NULL,"\nCONST:%s\n-------\n",name);

	FPRINTF(eth_hdr, "#define %s		%s\n", name, value);

	FPRINTF(NULL,"\n----------\nEND CONST:%s\n",name);

	token_list=ti;
}

/* this function will parse a
	   typedef struct {
   construct and generate the appropriate code.
   the typedef will be g_removed from the token_list once it has been processed
   the function assumes that the typedef is the first object in the token_list
   the function will be called twice, once with pass=0 and once with pass=1
   which controls whether subdissectors are to be generated or whether the
   struct dissector itself is to be generated
*/
static void parsetypedefstruct(int pass)
{
	token_item_t *ti, *tmpti;
	char *struct_name;
	char dissectorname[DISSECTORNAME_MAXLEN];
	char tmpstr[BASE_BUFFER_SIZE], *ptmpstr;
	int level, num_pointers;
	static int alignment;
	type_item_t *type_item;
	char hf_index[BASE_BUFFER_SIZE];
	bracket_item_t *bi=NULL;
	pointer_item_t *pi;
	const char *pointer_type;
	char *field_name;
	uint32_t fixed_array_size;
	int is_array_of_pointers;
	int empty_struct = 0;

	ti=token_list;
	if(g_strcmp0(ti->str, "typedef")){
		FPRINTF(stderr, "ERROR: typedefstruct  first token is not 'typedef'\n");
		Exit(10);
	}
	ti=ti->next;

	if(!g_strcmp0(ti->str, "[")){
		ti=parsebrackets(ti, &bi);
	}
	/* check that we know how to handle the bracket thing */
	if(bi){
		if(bi->flags){
			FPRINTF(stderr, "ERROR: typedefstruct unknown bracket flags encountered : 0x%08x\n",bi->flags);
			Exit(10);
		}
	}

	if(g_strcmp0(ti->str, "struct")){
		FPRINTF(stderr, "ERROR: typedefstruct  second token is not 'struct'\n");
		Exit(10);
	}
	ti=ti->next;

	if(g_strcmp0(ti->str, "{")){
		FPRINTF(stderr, "ERROR: typedefstruct  third token is not '{'\n");
		Exit(10);
	}
	ti=ti->next;

	/* Check if the struct is empty (search if there is no end bracket) */
	if(g_strcmp0(ti->str, "}") == 0){
		empty_struct = 1;
	}

	/* search forward until the '}' so we can find the name of the struct */
	for(tmpti=ti,level=0;tmpti;tmpti=tmpti->next){
		if(!g_strcmp0(tmpti->str, "{")){
			level++;
			continue;
		}
		if(!g_strcmp0(tmpti->str, "}")){
			if(!level){
				break;
			}
			level--;
			continue;
		}
	}
	if(!tmpti || !tmpti->next){
		FPRINTF(stderr, "ERROR: typedefstruct  missing matching '}'\n");
		Exit(10);
	}

	struct_name=tmpti->next->str;
	snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, struct_name);

	FPRINTF(NULL,"\nSTRUCT:%s pass:%d\n-------\n",struct_name,pass);

	if(!check_if_to_emit(dissectorname)){
		FPRINTF(NULL,"NOEMIT Skipping this struct dissector.\n");
		ti=tmpti;
		goto typedef_struct_finished;
	}

	/* this is pass 0  so reset alignment to zero and update as items are
	   processed. we need alignment when pass 1 is run.
	   set alignment initially to 1 so we don't fail for empty structs
	*/
	if(pass==0){
		alignment=1;
	}
	/* pass 1  generate header for the struct dissector */
	if(pass==1){
		FPRINTF(eth_ett, "static int ett_%s_%s;\n", ifname, struct_name);
		FPRINTF(eth_ettarr, "		 &ett_%s_%s,\n", ifname, struct_name);
		FPRINTF(eth_hdr, "int %s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param);\n", dissectorname);
		FPRINTF(eth_code, "\n");
		FPRINTF(eth_code, "int\n");
		FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo _U_, proto_tree *parent_tree, dcerpc_info *di _U_, uint8_t *drep _U_, int hf_index, uint32_t param _U_)\n", dissectorname);
		FPRINTF(eth_code, "{\n");
		FPRINTF(eth_code, "    proto_item *item=NULL;\n");
		if(!empty_struct){
			FPRINTF(eth_code, "    proto_tree *tree=NULL;\n");
		}
		FPRINTF(eth_code, "    int old_offset;\n");
		FPRINTF(eth_code, "\n");
		switch(alignment){
		case 1:
			break;
		case 2:
			FPRINTF(eth_code, "    ALIGN_TO_2_BYTES;\n");
			FPRINTF(eth_code, "\n");
			break;
		case 4:
			FPRINTF(eth_code, "    ALIGN_TO_4_BYTES;\n");
			FPRINTF(eth_code, "\n");
			break;
		case 8:
			FPRINTF(eth_code, "    ALIGN_TO_8_BYTES;\n");
			FPRINTF(eth_code, "\n");
			break;
		default:
			FPRINTF(stderr, "ERROR: can not handle alignment:%d\n",alignment);
			Exit(10);
		}
		FPRINTF(eth_code, "    old_offset=offset;\n");
		FPRINTF(eth_code, "    if(parent_tree){\n");
		FPRINTF(eth_code, " 	   item=proto_tree_add_item(parent_tree, hf_index, tvb, offset, -1, ENC_NA);\n");
		if(!empty_struct){
			FPRINTF(eth_code, " 	   tree=proto_item_add_subtree(item, ett_%s_%s);\n", ifname, struct_name);
		}
		FPRINTF(eth_code, "    }\n");
		FPRINTF(eth_code, "\n");
	}

	/* scan the struct and create all subdissectors */
	level=0;
	while(ti){
		if(!g_strcmp0(ti->str, "{")){
			level++;
			ti=ti->next;
			continue;
		}
		if(!g_strcmp0(ti->str, "}")){
			if(!level){
				break;
			}
			level--;
			ti=ti->next;
			continue;
		}
		if(!g_strcmp0(ti->str, "[")){
			ti=parsebrackets(ti, &bi);
			continue;
		}

		/* check that we know how to handle the bracket thing */
		if(bi){
			if(bi->flags&(~(BI_SIZE_IS|BI_LENGTH_IS|BI_POINTER))){
				FPRINTF(stderr, "ERROR: typedefstruct unknown bracket flags encountered : 0x%08x\n",bi->flags);
				Exit(10);
			}
		}

		/* handle the type, verify that we KNOW this type */
		type_item=find_type(ti->str);
		if(!type_item){
			FPRINTF(stderr, "ERROR : typedefstruct unknown type %s\n",ti->str);
			Exit(10);
		}
		ti=ti->next;
		/* count the levels of pointers */
		for(num_pointers=0;!g_strcmp0(ti->str, "*");ti=ti->next){
			num_pointers++;
			/* pointers are aligned at 4 byte boundaries */
			if(alignment<4){
				alignment=4;
			}
		}
		/* now that we know how many real pointers there were we must
		   prepend default pointers to the list so it has the right
		   length.
		*/
		pi=prepend_pointer_list(bi?bi->pointer_list:NULL, num_pointers);
		/* keep track of alignment */
		if(alignment<type_item->alignment){
			alignment=type_item->alignment;
		}

		field_name=ti->str;
		ti=ti->next;

		/* see if it is a fixed array */
		fixed_array_size=0;
		is_array_of_pointers=0;
		if(!g_strcmp0(ti->str, "[")){
			/* this might be a fixed array */
			ti=ti->next;

			if(!g_strcmp0("]", ti->str)){
				/* this is just a normal [] array */
				fixed_array_size=0;
			} else if(!g_strcmp0("*", ti->str)){
				pi=prepend_pointer_list(pi, num_pointers+1);
				fixed_array_size=0;
				is_array_of_pointers=1;
				ti=ti->next;
			} else if (!ws_strtou32(ti->str, NULL, &fixed_array_size)) {
				FPRINTF(stderr, "ERROR: invalid integer: %s\n", ti->str);
				Exit(10);
			} else {
				ti=ti->next;
			}

			if(g_strcmp0(ti->str, "]")){
				FPRINTF(stderr, "ERROR: typedefstruct  fixed array does not end with ']' it ended with %s\n",ti->str);
				Exit(10);
			}
			ti=ti->next;
		}

		snprintf(hf_index, BASE_BUFFER_SIZE, "hf_%s_%s_%s", ifname, struct_name, field_name);
		/* pass 0  generate subdissectors */
		if(pass==0){
			char filter_name[BASE_BUFFER_SIZE];
			const char *hf;

			snprintf(tmpstr, BASE_BUFFER_SIZE, "%s_dissect_%s_%s", ifname, struct_name, field_name);
			ptmpstr=g_strdup(tmpstr);

			if(check_if_to_emit(tmpstr)){
			  snprintf(filter_name, BASE_BUFFER_SIZE, "%s.%s.%s", ifname, struct_name, field_name);
			  hf=register_hf_field(hf_index, field_name, filter_name, type_item->ft_type, type_item->base_type, type_item->vals, type_item->mask, "");
			  FPRINTF(eth_code, "static unsigned\n");
			  FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep)\n", ptmpstr);
			  FPRINTF(eth_code, "{\n");
			  FPRINTF(eth_code, "	 uint32_t param=%s;\n",find_dissector_param_value(ptmpstr));
			  FPRINTF(eth_code, "	 offset=%s(tvb, offset, pinfo, tree, di, drep, %s, param);\n", type_item->dissector, hf);
			  FPRINTF(eth_code, "	 return offset;\n");
			  FPRINTF(eth_code, "}\n");
			  FPRINTF(eth_code, "\n");
			} else {
			  FPRINTF(NULL,"NOEMIT Skipping this struct item :%s\n",tmpstr);
			}

			if(is_array_of_pointers){
				pointer_type=pi->type;
				pi=pi->next;
				snprintf(tmpstr, BASE_BUFFER_SIZE, "%s_%s", pointer_type, ptmpstr);
				if(check_if_to_emit(tmpstr)){
				  FPRINTF(eth_code, "static unsigned\n");
				  FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep)\n", tmpstr);
				  FPRINTF(eth_code, "{\n");
				  FPRINTF(eth_code, "	 offset=dissect_ndr_embedded_pointer(tvb, offset, pinfo, tree, di, drep, %s, %s, \"%s\", -1);\n", ptmpstr, ptr_to_define(pointer_type), field_name);
				  FPRINTF(eth_code, "	 return offset;\n");
				  FPRINTF(eth_code, "}\n");
				  FPRINTF(eth_code, "\n");
				} else {
				  FPRINTF(NULL,"NOEMIT Skipping this struct item :%s\n",tmpstr);
				}

				ptmpstr=g_strdup(tmpstr);
			} else if(fixed_array_size){
				snprintf(tmpstr, BASE_BUFFER_SIZE, "fixedarray_%s", ptmpstr);
				if(check_if_to_emit(tmpstr)){
				  FPRINTF(eth_code, "static unsigned\n");
				  FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep)\n", tmpstr);
				  FPRINTF(eth_code, "{\n");
				  FPRINTF(eth_code, "	 int count=%d;\n",fixed_array_size);
				  FPRINTF(eth_code, "	 while(count--){\n");
				  FPRINTF(eth_code, "		 offset=%s(tvb, offset, pinfo, tree, di, drep);\n", ptmpstr);
				  FPRINTF(eth_code, "	 }\n");
				  FPRINTF(eth_code, "\n");
				  FPRINTF(eth_code, "	 return offset;\n");
				  FPRINTF(eth_code, "}\n");
				  FPRINTF(eth_code, "\n");
				} else {
				  FPRINTF(NULL,"NOEMIT Skipping this struct item :%s\n",tmpstr);
				}
				ptmpstr=g_strdup(tmpstr);
			}

			/* handle switch_is */
			if(bi){
			  switch(bi->flags&(BI_SIZE_IS|BI_LENGTH_IS)){
			  case 0:
				break;
			  case BI_SIZE_IS:
				snprintf(tmpstr, BASE_BUFFER_SIZE, "ucarray_%s", ptmpstr);
				if(check_if_to_emit(tmpstr)){
				  FPRINTF(eth_code, "static unsigned\n");
				  FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep)\n", tmpstr);
				  FPRINTF(eth_code, "{\n");
				  FPRINTF(eth_code, "	 offset=dissect_ndr_ucarray(tvb, offset, pinfo, tree, di, drep, %s);\n", ptmpstr);
				  FPRINTF(eth_code, "	 return offset;\n");
				  FPRINTF(eth_code, "}\n");
				  FPRINTF(eth_code, "\n");
				} else {
				  FPRINTF(NULL,"NOEMIT Skipping this struct item :%s\n",tmpstr);
				}
				ptmpstr=g_strdup(tmpstr);
				break;
			  case BI_LENGTH_IS:
				snprintf(tmpstr, BASE_BUFFER_SIZE, "uvarray_%s", ptmpstr);
				if(check_if_to_emit(tmpstr)){
				  FPRINTF(eth_code, "static unsigned\n");
				  FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep)\n", tmpstr);
				  FPRINTF(eth_code, "{\n");
				  FPRINTF(eth_code, "	 offset=dissect_ndr_uvarray(tvb, offset, pinfo, tree, di, drep, %s);\n", ptmpstr);
				  FPRINTF(eth_code, "	 return offset;\n");
				  FPRINTF(eth_code, "}\n");
				  FPRINTF(eth_code, "\n");
				} else {
				  FPRINTF(NULL,"NOEMIT Skipping this struct item :%s\n",tmpstr);
				}
				ptmpstr=g_strdup(tmpstr);
				break;
			  case BI_SIZE_IS|BI_LENGTH_IS:
				snprintf(tmpstr, BASE_BUFFER_SIZE, "ucvarray_%s", ptmpstr);
				if(check_if_to_emit(tmpstr)){
				  FPRINTF(eth_code, "static unsigned\n");
				  FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep)\n", tmpstr);
				  FPRINTF(eth_code, "{\n");
				  FPRINTF(eth_code, "	 offset=dissect_ndr_ucvarray(tvb, offset, pinfo, tree, di, drep, %s);\n", ptmpstr);
				  FPRINTF(eth_code, "	 return offset;\n");
				  FPRINTF(eth_code, "}\n");
				  FPRINTF(eth_code, "\n");
				} else {
				  FPRINTF(NULL,"NOEMIT Skipping this struct item :%s\n",tmpstr);
				}
				ptmpstr=g_strdup(tmpstr);
				break;
			  default:
				FPRINTF(stderr, "ERROR: typedefstruct can not handle this combination of sizeis/lengthis\n");
				Exit(10);
			  }
			}

			/* handle pointers */
			while(num_pointers--){
				pointer_type=pi->type;
				pi=pi->next;
				snprintf(tmpstr, BASE_BUFFER_SIZE, "%s_%s", pointer_type, ptmpstr);
				if(check_if_to_emit(tmpstr)){
				  FPRINTF(eth_code, "static unsigned\n");
				  FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep)\n", tmpstr);
				  FPRINTF(eth_code, "{\n");
				  FPRINTF(eth_code, "	 offset=dissect_ndr_embedded_pointer(tvb, offset, pinfo, tree, di, drep, %s, %s, \"%s\", -1);\n", ptmpstr, ptr_to_define(pointer_type), field_name);
				  FPRINTF(eth_code, "	 return offset;\n");
				  FPRINTF(eth_code, "}\n");
				  FPRINTF(eth_code, "\n");
				} else {
				  FPRINTF(NULL,"NOEMIT Skipping this struct item :%s\n",tmpstr);
				}

				ptmpstr=g_strdup(tmpstr);
			}
		}

		if(pass==1){
			snprintf(tmpstr, BASE_BUFFER_SIZE, "%s_dissect_%s_%s", ifname, struct_name, field_name);
			ptmpstr=g_strdup(tmpstr);

			/* handle fixedsizearrays */
			if(is_array_of_pointers){
				pointer_type=pi->type;
				pi=pi->next;
				snprintf(tmpstr, BASE_BUFFER_SIZE, "%s_%s", pointer_type, ptmpstr);
				ptmpstr=g_strdup(tmpstr);
			} else if(fixed_array_size){
				snprintf(tmpstr, BASE_BUFFER_SIZE, "fixedarray_%s", ptmpstr);
				ptmpstr=g_strdup(tmpstr);
			}

			/* handle switch_is */
			if(bi){
			  switch(bi->flags&(BI_SIZE_IS|BI_LENGTH_IS)){
			  case 0:
				break;
			  case BI_SIZE_IS:
				snprintf(tmpstr, BASE_BUFFER_SIZE, "ucarray_%s", ptmpstr);
				ptmpstr=g_strdup(tmpstr);
				break;
			  case BI_LENGTH_IS:
				snprintf(tmpstr, BASE_BUFFER_SIZE, "uvarray_%s", ptmpstr);
				ptmpstr=g_strdup(tmpstr);
				break;
			  case BI_SIZE_IS|BI_LENGTH_IS:
				snprintf(tmpstr, BASE_BUFFER_SIZE, "ucvarray_%s", ptmpstr);
				ptmpstr=g_strdup(tmpstr);
				break;
			  default:
				FPRINTF(stderr, "ERROR: typedefstruct can not handle this combination of sizeis/lengthis\n");
				Exit(10);
			  }
			}

			/* handle pointers */
			while(num_pointers--){
				pointer_type=pi->type;
				pi=pi->next;
				snprintf(tmpstr, BASE_BUFFER_SIZE, "%s_%s", pointer_type, ptmpstr);
				ptmpstr=g_strdup(tmpstr);
			}

			FPRINTF(eth_code, "    offset=%s(tvb, offset, pinfo, tree, di, drep);\n", ptmpstr);
			FPRINTF(eth_code, "\n");
		}

		if(g_strcmp0(ti->str,";")){
			FPRINTF(stderr, "ERROR: field does not en with ';'\n");
			Exit(10);
		}
		ti=ti->next;
		bi=NULL; /* clear bi before we start on the next field */
	}

	if(pass==1){
		FPRINTF(eth_code, "    proto_item_set_len(item, offset-old_offset);\n");
		FPRINTF(eth_code, "\n");
		FPRINTF(eth_code, "    return offset;\n");
		FPRINTF(eth_code, "}\n");
		register_new_type(struct_name, dissectorname, "FT_NONE", "BASE_NONE", "0", "NULL", alignment);
	}


typedef_struct_finished:
	FPRINTF(NULL,"\nEND STRUCT:%s pass:%d\n-------\n",struct_name,pass);

	/* only advance token_list for pass==1
	   ti now points to the '}' token
	*/
	if(pass==1){
		if(!ti || g_strcmp0(ti->str,"}")){
			FPRINTF(stderr, "ERROR: struct does not end with '}'\n");
			Exit(10);
		}
		ti=ti->next;

		/* just skip the name */
		ti=ti->next;

		if(!ti || g_strcmp0(ti->str,";")){
			FPRINTF(stderr, "ERROR: struct does not end with ';'\n");
			Exit(10);
		}
		ti=ti->next;

		token_list=ti;
	}
}

/* this function will parse a
	   typedef bitmap {
   construct and generate the appropriate code.
   the typedef will be g_removed from the token_list once it has been processed
   the function assumes that the typedef is the first object in the token_list
   the function will be called twice, once with pass=0 and once with pass=1
   which controls whether subdissectors are to be generated or whether the
   bitmap dissector itself is to be generated

   bitmaps are by default 32 bits
*/
static void parsetypedefbitmap(int pass)
{
	token_item_t *ti, *tmpti;
	char *bitmap_name;
	char dissectorname[BASE_BUFFER_SIZE], hf_bitname[BASE_BUFFER_SIZE];
	int alignment;
	unsigned int val;
	char *name, *value;
	bracket_item_t *bi=NULL;

	ti=token_list;
	if(g_strcmp0(ti->str, "typedef")){
		FPRINTF(stderr, "ERROR: typedefbitmap  first token is not 'typedef'\n");
		Exit(10);
	}
	ti=ti->next;

	alignment=4;  /* default size is 32 bits */

	if(!g_strcmp0(ti->str, "[")){
		ti=parsebrackets(ti, &bi);
	}
	/* check that we know how to handle the bracket thing */
	if(bi){
		if(bi->flags&(~(BI_BITMAP32|BI_BITMAP8))){
			FPRINTF(stderr, "ERROR: typedefbitmap unknown bracket flags encountered : 0x%08x\n",bi->flags);
			Exit(10);
		}
		if(bi->flags&BI_BITMAP32){
			alignment=4;
		}
		if(bi->flags&BI_BITMAP8){
			alignment=1;
		}
	}


	if(g_strcmp0(ti->str, "bitmap")){
		FPRINTF(stderr, "ERROR: typedefbitmap  second token is not 'bitmap'\n");
		Exit(10);
	}
	ti=ti->next;

	if(g_strcmp0(ti->str, "{")){
		FPRINTF(stderr, "ERROR: typedefbitmap  third token is not '{'\n");
		Exit(10);
	}
	ti=ti->next;

	/* search forward until the '}' so we can find the name of the bitmap */
	for(tmpti=ti;tmpti;tmpti=tmpti->next){
		if(!g_strcmp0(tmpti->str, "{")){
			FPRINTF(stderr, "ERROR: typedefbitmap '{' encountered inside bitmap\n");
			Exit(10);
		}
		if(!g_strcmp0(tmpti->str, "}")){
			break;
		}
	}
	if (!tmpti || !tmpti->next){
		FPRINTF(stderr, "ERROR: typedefbitmap missing matching '}'\n");
		Exit(10);
	}
	bitmap_name=tmpti->next->str;
	snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, bitmap_name);

	FPRINTF(NULL,"\nBITMAP:%s pass:%d\n-------\n",bitmap_name,pass);

	/* pass 1  generate header for the struct dissector */
	if(pass==1){
		FPRINTF(eth_ett, "static int ett_%s_%s;\n", ifname, bitmap_name);
		FPRINTF(eth_ettarr, "		 &ett_%s_%s,\n", ifname, bitmap_name);
		FPRINTF(eth_hdr, "int %s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param);\n", dissectorname);
		FPRINTF(eth_code, "\n");
		FPRINTF(eth_code, "int\n");
		FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *parent_tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
		FPRINTF(eth_code, "{\n");
		FPRINTF(eth_code, "    proto_item *item=NULL;\n");
		FPRINTF(eth_code, "    proto_tree *tree=NULL;\n");
		switch(alignment){
		case 1:
			FPRINTF(eth_code, "    uint8_t flags;\n");
			FPRINTF(eth_code, "\n");
			break;
		case 4:
			FPRINTF(eth_code, "    uint32_t flags;\n");
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "    ALIGN_TO_4_BYTES;\n");
			break;
		default:
			FPRINTF(stderr, "ERROR: typedefbitmap can not handle alignment:%d\n",alignment);
			Exit(10);
		}
		FPRINTF(eth_code, "\n");
		FPRINTF(eth_code, "    if(parent_tree){\n");
		FPRINTF(eth_code, " 	   item=proto_tree_add_item(parent_tree, hf_index, tvb, offset, %d, ENC_LITTLE_ENDIAN);\n", alignment);
		FPRINTF(eth_code, " 	   tree=proto_item_add_subtree(item, ett_%s_%s);\n", ifname, bitmap_name);
		FPRINTF(eth_code, "    }\n");
		FPRINTF(eth_code, "\n");
		switch(alignment){
		case 1:
			FPRINTF(eth_code, "    offset=dissect_ndr_uint8(tvb, offset, pinfo, NULL, di, drep, -1, &flags);\n");
			FPRINTF(eth_code, "\n");
			break;
		case 4:
			FPRINTF(eth_code, "    offset=dissect_ndr_uint32(tvb, offset, pinfo, NULL, di, drep, -1, &flags);\n");
			FPRINTF(eth_code, "\n");
			break;
		default:
			FPRINTF(stderr, "ERROR: typedefbitmap can not handle alignment:%d\n",alignment);
			Exit(10);
		}
		FPRINTF(eth_code, "\n");
	}

	/* scan the struct and create call for all bits */
	while(ti){
		if(!g_strcmp0(ti->str, "}")){
			break;
		}
		if(!g_strcmp0(ti->str, "[")){
			FPRINTF(stderr, "ERROR: typedefbitmap can not handle '[' yet\n");
			Exit(10);
		}

		name=ti->str;
		ti=ti->next;
		snprintf(hf_bitname, BASE_BUFFER_SIZE, "hf_%s_%s_%s", ifname, bitmap_name, name);

		if(g_strcmp0(ti->str, "=")){
			FPRINTF(stderr, "ERROR: typedefbitmap i expected a '=' here\n");
			Exit(10);
		}
		ti=ti->next;

		value=ti->str;
		ti=ti->next;
		val=0;
		if(!strncmp(value, "0x", 2)){
			sscanf(value, "0x%x", &val);
		} else {
			FPRINTF(stderr, "ERROR: typedefbitmap can only handle hexadecimal constants\n");
			Exit(10);
		}

		if((val == 0) || (val&(val-1))){
			FPRINTF(stderr, "ERROR: typedefbitmap can only handle single bit fields\n");
			Exit(10);
		}

		if(pass==0){
			char filter_name[BASE_BUFFER_SIZE], base_name[BASE_BUFFER_SIZE], tfs_name[BASE_BUFFER_SIZE];

			snprintf(filter_name, BASE_BUFFER_SIZE, "%s.%s.%s", ifname, bitmap_name, name);
			snprintf(base_name, BASE_BUFFER_SIZE, "%d", alignment*8);
			snprintf(tfs_name, BASE_BUFFER_SIZE, "TFS(&%s_tfs)", name);
			register_hf_field(hf_bitname, name, filter_name, "FT_BOOLEAN", base_name, tfs_name, value, "");

			FPRINTF(eth_code, "static const true_false_string %s_tfs = {\n",name);
			FPRINTF(eth_code, "    \"%s is SET\",\n", name);
			FPRINTF(eth_code, "    \"%s is NOT set\"\n", name);
			FPRINTF(eth_code, "};\n");
			FPRINTF(eth_code, "\n");
		}

		if(pass==1){
			FPRINTF(eth_code, "    proto_tree_add_boolean(tree, %s, tvb, offset-%d, %d, flags);\n", hf_bitname, alignment, alignment);
			FPRINTF(eth_code, "    if(flags&%s){\n", value);
			FPRINTF(eth_code, " 	   proto_item_append_text(item, \" %s\");\n", name);
			FPRINTF(eth_code, "    }\n");
			FPRINTF(eth_code, "    flags&=(~%s);\n", value);
			FPRINTF(eth_code, "\n");
		}

		if(!g_strcmp0(ti->str, ",")){
			ti=ti->next;
			continue;
		}
	}

	if(pass==1){
		FPRINTF(eth_code, "    if(flags){\n");
		FPRINTF(eth_code, " 	   proto_item_append_text(item, \"UNKNOWN-FLAGS\");\n");
		FPRINTF(eth_code, "    }\n");
		FPRINTF(eth_code, "\n");
		FPRINTF(eth_code, "    return offset;\n");
		FPRINTF(eth_code, "}\n");
		switch(alignment){
		case 1:
			register_new_type(bitmap_name, dissectorname, "FT_UINT8", "BASE_HEX", "0", "NULL", alignment);
			break;
		case 4:
			register_new_type(bitmap_name, dissectorname, "FT_UINT32", "BASE_HEX", "0", "NULL", alignment);
			break;
		default:
			FPRINTF(stderr, "ERROR: typedefbitmap can not handle alignment:%d\n",alignment);
			Exit(10);
		}
	}

	FPRINTF(NULL,"\nEND BITMAP:%s pass:%d\n-------\n",bitmap_name,pass);

	/* only advance token_list for pass==1
	   ti now points to the '}' token
	*/
	if(pass==1){
		if(!ti || g_strcmp0(ti->str,"}")){
			FPRINTF(stderr, "ERROR: bitmap does not end with '}'\n");
			Exit(10);
		}
		ti=ti->next;

		/* just skip the name */
		ti=ti->next;

		if(!ti || g_strcmp0(ti->str,";")){
			FPRINTF(stderr, "ERROR: bitmap does not end with ';'\n");
			Exit(10);
		}
		ti=ti->next;

		token_list=ti;
	}
}

/* a case tag might be a negative number, i.e. contain a '-' sign which
   is not valid inside a symbol name in c.
*/
static const char *
case2str(const char *str)
{
	char *newstr;
	if(str[0]!='-'){
		return str;
	}
	newstr=g_strdup(str);
	newstr[0]='m';
	return newstr;
}

/* this function will parse a
	typedef union {
	construct and generate the appropriate code.
	the typedef will be g_removed from the token_list once it has been processed
	the function assumes that the typedef is the first object in the token_list
	the function will be called twice, once with pass=0 and once with pass=1
	which controls whether subdissectors are to be generated or whether the
	union dissector itself is to be generated
*/
static void parsetypedefunion(int pass)
{
	char *union_name;
	token_item_t *ti, *tmpti;
	char dissectorname[BASE_BUFFER_SIZE];
	bracket_item_t *bi=NULL;
	char tmpstr[BASE_BUFFER_SIZE], *ptmpstr;
	int level, num_pointers;
	static int alignment;
	type_item_t *type_item;
	char hf_index[BASE_BUFFER_SIZE];
	int tag_alignment, item_alignment;

	ti=token_list;
	if(g_strcmp0(ti->str, "typedef")){
		FPRINTF(stderr, "ERROR: typedefunion  first token is not 'typedef'\n");
		Exit(10);
	}
	ti=ti->next;

	if(!g_strcmp0(ti->str, "[")){
		ti=parsebrackets(ti, &bi);
	}
	/* check that we know how to handle the bracket thing */
	if(bi){
		if(bi->flags&(~(BI_SWITCH_TYPE))){
			FPRINTF(stderr, "ERROR: typedefunion unknown bracket flags encountered : 0x%08x\n",bi->flags);
			Exit(10);
		}
	}

	if(g_strcmp0(ti->str, "union")){
		FPRINTF(stderr, "ERROR: typedefunion  second token is not 'union'\n");
		Exit(10);
	}
	ti=ti->next;

	if(g_strcmp0(ti->str, "{")){
		FPRINTF(stderr, "ERROR: typedefunion  third token is not '{'\n");
		Exit(10);
	}
	ti=ti->next;

	/* search forward until the '}' so we can find the name of the union */
	for(tmpti=ti,level=0;tmpti;tmpti=tmpti->next){
		if(!g_strcmp0(tmpti->str, "{")){
			level++;
			continue;
		}
		if(!g_strcmp0(tmpti->str, "}")){
			if(!level){
				break;
			}
			level--;
			continue;
		}
	}

	if (!tmpti || !tmpti->next){
		FPRINTF(stderr, "ERROR: typedefunion  missing matching '}'\n");
		Exit(10);
	}
	union_name=tmpti->next->str;
	snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_union_%s", ifname, union_name);

	FPRINTF(NULL,"\nUNION:%s pass:%d\n-------\n",union_name,pass);

	if(bi && bi->flags&BI_SWITCH_TYPE){
		tag_alignment=bi->union_tag_size;
	} else {
		tag_alignment=get_union_tag_size(union_name);
	}

	/* this is pass 0  so reset alignment to the minimum possible value
	   and update as items are processed.
	   we need alignment when pass 1 is run
	*/
	if(pass==0){
		alignment=tag_alignment;
	}

	/* pass 1  generate header for the struct dissector */
	if(pass==1){
		FPRINTF(eth_ett, "static int ett_%s_%s;\n", ifname, union_name);
		FPRINTF(eth_ettarr, "		 &ett_%s_%s,\n", ifname, union_name);
		FPRINTF(eth_code, "\n");
		FPRINTF(eth_code, "static unsigned\n");
		FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *parent_tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
		FPRINTF(eth_code, "{\n");
		FPRINTF(eth_code, "    proto_item *item=NULL;\n");
		FPRINTF(eth_code, "    proto_tree *tree=NULL;\n");
		FPRINTF(eth_code, "    int old_offset;\n");
		/* we do alignment on the tag itself here so that
		   we skip any alignment padding prior to where the tag
		   itself starts, this makes the byterange in the hexpane
		   for the union expansion start with the first byte of the tag
		*/
		switch(tag_alignment){
		case 1:
			break;
		case 2:
			FPRINTF(eth_code, "    uint16_t level;\n");
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "    ALIGN_TO_2_BYTES;\n");
			FPRINTF(eth_code, "\n");
			break;
		case 4:
			FPRINTF(eth_code, "    uint32_t level = 0;\n");
			FPRINTF(eth_code, "\n");
			FPRINTF(eth_code, "    ALIGN_TO_4_BYTES;\n");
			FPRINTF(eth_code, "\n");
			break;
		default:
			FPRINTF(stderr, "ERROR: typedefunion 1 can not handle alignment:%d\n",alignment);
			Exit(10);
		}
		FPRINTF(eth_code, "    old_offset=offset;\n");
		FPRINTF(eth_code, "    if(parent_tree){\n");
		FPRINTF(eth_code, " 	   tree=proto_tree_add_subtree(parent_tree, tvb, offset, -1, ett_%s_%s, &item, \"%s\");\n", ifname, union_name, union_name);
		FPRINTF(eth_code, "    }\n");
		FPRINTF(eth_code, "\n");
		switch(tag_alignment){
		case 1:
			break;
		case 2:
			FPRINTF(eth_code, "    offset=dissect_ndr_uint16(tvb, offset, pinfo, tree,\n");
			FPRINTF(eth_code, " 							 di, drep, hf_index, &level);\n");
		break;
		case 4:
			FPRINTF(eth_code, "    offset=dissect_ndr_uint32(tvb, offset, pinfo, tree,\n");
			FPRINTF(eth_code, " 							 di, drep, hf_index, &level);\n");
			break;
		default:
			FPRINTF(stderr, "ERROR: typedefunion 2 can not handle alignment:%d\n",alignment);
			Exit(10);
		}
		FPRINTF(eth_code, "\n");
		FPRINTF(eth_code, "    switch(level){\n");
	}

	/* scan the struct and create all subdissectors */
	level=0;
	while(ti){
		if(!g_strcmp0(ti->str, "{")){
			ti=ti->next;
			level++;
			continue;
		}
		if(!g_strcmp0(ti->str, "}")){
			if(!level){
				break;
			}
			ti=ti->next;
			level--;
			continue;
		}
		if(!g_strcmp0(ti->str, "[")){
			ti=parsebrackets(ti, &bi);
			continue;
		}

		if(!bi){
			FPRINTF(stderr, "ERROR : typedefunion no brackets found for case\n");
			Exit(10);
		}
		/* make sure we catch when we havent implemented everything
		   yet.
		   we currently only know about CASE and CASE_DEFAULT flags
		*/
		if(bi->flags&(~(BI_CASE|BI_CASE_DEFAULT|BI_POINTER))){
			FPRINTF(stderr, "ERROR: typedefunion unknown bracket flags encountered : 0x%08x\n",bi->flags);
			Exit(10);
		}
		if(!(bi->flags&BI_CASE)){
			FPRINTF(stderr, "ERROR : typedefunion no case found in brackets\n");
			Exit(10);
		}
#ifdef g_removeD
		/* only empty default cases for now */
		if(bi->flags&BI_CASE_DEFAULT){
			if(g_strcmp0(ti->str,";")){
				FPRINTF(stderr, "ERROR: default tag is not empty\n");
				Exit(10);
			}
			ti=ti->next;
			continue;
		}
#endif

		/* just skip all and any 'empty' arms */
		if(!g_strcmp0(ti->str, ";")){
			ti=ti->next;
			continue;
		}

		/* handle the type, verify that we KNOW this type */
		type_item=find_type(ti->str);
		if(!type_item){
			FPRINTF(stderr, "ERROR : typedefunion unknown type %s\n",ti->str);
			Exit(10);
		}
		ti=ti->next;
		/* count the levels of pointers */
		for(num_pointers=0;!g_strcmp0(ti->str, "*");ti=ti->next){
			num_pointers++;
		}

		/* keep track of alignment */
		if(num_pointers){
			item_alignment=4;
		} else {
			item_alignment=type_item->alignment;
		}
		if(alignment<item_alignment){
			alignment=item_alignment;
		}

		snprintf(hf_index, BASE_BUFFER_SIZE, "hf_%s_%s_%s_%s", ifname, union_name, case2str(bi->case_name), ti->str);
		/* pass 0  generate subdissectors */
		if(pass==0){
			char filter_name[BASE_BUFFER_SIZE];
			const char *hf;

			snprintf(tmpstr, BASE_BUFFER_SIZE, "%s_dissect_union_%s_%s_%s", ifname, union_name, case2str(bi->case_name), ti->str);
			ptmpstr=g_strdup(tmpstr);

			snprintf(filter_name, BASE_BUFFER_SIZE, "%s.%s.%s", ifname, union_name, ti->str);
			hf=register_hf_field(hf_index, ti->str, filter_name, type_item->ft_type, type_item->base_type, type_item->vals, type_item->mask, "");

			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep)\n", ptmpstr);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    uint32_t param=%s;\n",find_dissector_param_value(ptmpstr));
			FPRINTF(eth_code, "    offset=%s(tvb, offset, pinfo, tree, di, drep, %s, param);\n", type_item->dissector, hf);
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");

			/* handle pointers */
			while(num_pointers--){
				snprintf(tmpstr, BASE_BUFFER_SIZE, "%s_%s", ptmpstr, "unique");
				FPRINTF(eth_code, "static unsigned\n");
				FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep)\n", tmpstr);
				FPRINTF(eth_code, "{\n");
				FPRINTF(eth_code, "    offset=dissect_ndr_embedded_pointer(tvb, offset, pinfo, tree, di, drep, %s, NDR_POINTER_UNIQUE, \"%s\", -1);\n", ptmpstr, ti->str);
				FPRINTF(eth_code, "    return offset;\n");
				FPRINTF(eth_code, "}\n");
				FPRINTF(eth_code, "\n");

				ptmpstr=g_strdup(tmpstr);

			}
		}

		if(pass==1){
			/* handle pointers */
			snprintf(tmpstr, BASE_BUFFER_SIZE, "%s_dissect_union_%s_%s_%s", ifname, union_name, case2str(bi->case_name), ti->str);
			ptmpstr=g_strdup(tmpstr);
			while(num_pointers--){
				snprintf(tmpstr, BASE_BUFFER_SIZE, "%s_%s", ptmpstr, "unique");
				ptmpstr=g_strdup(tmpstr);
			}

			if(bi->flags&BI_CASE_DEFAULT){
				FPRINTF(eth_code, "    default:\n");
			} else {
				FPRINTF(eth_code, "    case %s:\n",bi->case_name);
			}
			/* each arm itself is aligned independently */
			switch(item_alignment){
			case 1:
				break;
			case 2:
				FPRINTF(eth_code, " 	   ALIGN_TO_2_BYTES;\n");
				break;
			case 4:
				FPRINTF(eth_code, " 	   ALIGN_TO_4_BYTES;\n");
				break;
			case 8:
				FPRINTF(eth_code, " 	   ALIGN_TO_8_BYTES;\n");
				break;
			default:
				FPRINTF(stderr, "ERROR: typedefunion 3 can not handle alignment:%d\n",item_alignment);
				Exit(10);
			}
			FPRINTF(eth_code, " 	   offset=%s(tvb, offset, pinfo, tree, di, drep);\n", ptmpstr);
			FPRINTF(eth_code, " 	   break;\n");
			FPRINTF(eth_code, "\n");
		}
		ti=ti->next;

		if(g_strcmp0(ti->str,";")){
			FPRINTF(stderr, "ERROR: field does not end with ';'\n");
			Exit(10);
		}
		ti=ti->next;
	}

	if(pass==1){
		FPRINTF(eth_code, "    }\n");
		FPRINTF(eth_code, "\n");
		FPRINTF(eth_code, "    proto_item_set_len(item, offset-old_offset);\n");
		FPRINTF(eth_code, "\n");
		FPRINTF(eth_code, "   return offset;\n");
		FPRINTF(eth_code, "}\n");
		switch(tag_alignment){
		case 2:
			register_new_type(union_name, dissectorname, "FT_UINT16", "BASE_DEC", "0", "NULL", alignment);
			break;
		case 4:
			register_new_type(union_name, dissectorname, "FT_UINT32", "BASE_DEC", "0", "NULL", alignment);
			break;
		default:
			FPRINTF(stderr, "ERROR: typedefunion 4 can not handle alignment:%d\n",alignment);
			Exit(10);
		}
	}

	FPRINTF(NULL,"\nEND UNION:%s pass:%d\n-------\n",union_name,pass);

	/* only advance token_list for pass==1
	   ti now points to the '}' token
	*/
	if(pass==1){
		if(!ti || g_strcmp0(ti->str,"}")){
			FPRINTF(stderr, "ERROR: union does not end with '}'\n");
			Exit(10);
		}
		ti=ti->next;

		/* just skip the name */
		ti=ti->next;

		if(!ti || g_strcmp0(ti->str,";")){
			FPRINTF(stderr, "ERROR: union does not end with ';'\n");
			Exit(10);
		}
		ti=ti->next;

		token_list=ti;
	}
}


/* this function will parse a
	   WERROR function (
   construct and generate the appropriate code.
   the function will be g_removed from the token_list once it has been processed
   the function assumes that the function is the first object in the token_list
   the function will be called three times with
	 pass=0   generate subdissectors and entries for the function table
	 pass=1   generate code for the REQUEST
	 pass=2   generate code for the REPLY
*/
static void parsefunction(int pass)
{
	char *function_name;
	static int funcno=0;
	token_item_t *ti;
	bracket_item_t *bi=NULL;
	pointer_item_t *pi;
	const char *pointer_type;

	char tmpstr[BASE_BUFFER_SIZE], *ptmpstr;
	int level, num_pointers;
	type_item_t *type_item;
	char hf_index[BASE_BUFFER_SIZE];

	ti=token_list;
	if(g_strcmp0(ti->str, "WERROR")){
		FPRINTF(stderr, "ERROR: function  first token is not 'WERROR'\n");
		Exit(10);
	}
	ti=ti->next;

	function_name=ti->str;
	ti=ti->next;

	if(g_strcmp0(ti->str, "(")){
		FPRINTF(stderr, "ERROR: function  third token is not '('\n");
		Exit(10);
	}
	ti=ti->next;

	FPRINTF(NULL,"\nFUNCTION:%s pass:%d\n-------\n",function_name,pass);

	if(pass==0){
		FPRINTF(eth_ft, "	 { %d, \"%s\",\n",funcno,function_name);
		FPRINTF(eth_ft, "		 %s_dissect_%s_request,\n", ifname, function_name);
		FPRINTF(eth_ft, "		 %s_dissect_%s_response },\n", ifname, function_name);
		funcno++;
	}

	/* pass 1,2  generate header for the function dissector */
	if((pass==1)||(pass==2)){
		FPRINTF(eth_code, "\n");
		FPRINTF(eth_code, "static unsigned\n");
		FPRINTF(eth_code, "%s_dissect_%s_%s(tvbuff_t *tvb _U_, unsigned offset _U_, packet_info *pinfo _U_, proto_tree *tree _U_, dcerpc_info* di _U_, uint8_t *drep _U_)\n", ifname, function_name, (pass==1)?"request":"response");
		FPRINTF(eth_code, "{\n");
	}

	/* scan the struct and create all subdissectors */
	level=0;
	while(ti){
		if(!g_strcmp0(ti->str, "(")){
			ti=ti->next;
			level++;
			continue;
		}
		if(!g_strcmp0(ti->str, ")")){
			if(!level){
				break;
			}
			ti=ti->next;
			level--;
			continue;
		}
		if(!g_strcmp0(ti->str, "[")){
			ti=parsebrackets(ti, &bi);
			continue;
		}

		if(!bi){
			FPRINTF(stderr, "ERROR : function no brackets found for case\n");
			Exit(10);
		}

		/* make sure we catch when we havent implemented everything
		   yet.
		   we currently only know about IN and OUT flags
		*/
		if(bi->flags&(~(BI_IN|BI_OUT|BI_POINTER|BI_SIZE_IS|BI_LENGTH_IS))){
			FPRINTF(stderr, "ERROR: function unknown bracket flags encountered : 0x%08x\n",bi->flags);
			Exit(10);
		}
		if(!(bi->flags&(BI_IN|BI_OUT))){
			FPRINTF(stderr, "ERROR : function  parameter is neither in nor out\n");
			Exit(10);
		}

		/* handle the type, verify that we KNOW this type */
		type_item=find_type(ti->str);
		if(!type_item){
			FPRINTF(stderr, "ERROR : function unknown type %s\n",ti->str);
			Exit(10);
		}
		ti=ti->next;
		/* count the levels of pointers */
		for(num_pointers=0;!g_strcmp0(ti->str, "*");ti=ti->next){
			num_pointers++;
		}

		/* now that we know how many real pointer there were we must
		   prepend default pointers to the list so it has the right
		   length.
		*/
		pi=prepend_pointer_list(bi->pointer_list, num_pointers);

		snprintf(hf_index, BASE_BUFFER_SIZE, "hf_%s_%s_%s", ifname, function_name, ti->str);
		/* pass 0  generate subdissectors */
		if(pass==0){
			char filter_name[BASE_BUFFER_SIZE];
			const char *hf;

			snprintf(tmpstr, BASE_BUFFER_SIZE, "%s_dissect_%s_%s", ifname, function_name, ti->str);
			ptmpstr=g_strdup(tmpstr);

			snprintf(filter_name, BASE_BUFFER_SIZE, "%s.%s.%s", ifname, function_name, ti->str);
			hf=register_hf_field(hf_index, ti->str, filter_name, type_item->ft_type, type_item->base_type, type_item->vals, type_item->mask, "");

			FPRINTF(eth_code, "static unsigned\n");
			FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep)\n", ptmpstr);
			FPRINTF(eth_code, "{\n");
			FPRINTF(eth_code, "    uint32_t param=%s;\n",find_dissector_param_value(ptmpstr));
			FPRINTF(eth_code, "    offset=%s(tvb, offset, pinfo, tree, di, drep, %s, param);\n", type_item->dissector, hf);
			FPRINTF(eth_code, "    return offset;\n");
			FPRINTF(eth_code, "}\n");
			FPRINTF(eth_code, "\n");


			/* handle switch_is */
			switch(bi->flags&(BI_SIZE_IS|BI_LENGTH_IS)){
			case 0:
			    break;
			case BI_SIZE_IS|BI_LENGTH_IS:
			    snprintf(tmpstr, BASE_BUFFER_SIZE, "ucvarray_%s", ptmpstr);
			    FPRINTF(eth_code, "static unsigned\n");
			    FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep)\n", tmpstr);
			    FPRINTF(eth_code, "{\n");
			    FPRINTF(eth_code, "    offset=dissect_ndr_ucvarray(tvb, offset, pinfo, tree, di, drep, %s);\n", ptmpstr);
			    FPRINTF(eth_code, "    return offset;\n");
			    FPRINTF(eth_code, "}\n");
			    FPRINTF(eth_code, "\n");
			    ptmpstr=g_strdup(tmpstr);
			    break;
			case BI_SIZE_IS:
			    snprintf(tmpstr, BASE_BUFFER_SIZE, "ucarray_%s", ptmpstr);
			    FPRINTF(eth_code, "static unsigned\n");
			    FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep)\n", tmpstr);
			    FPRINTF(eth_code, "{\n");
			    FPRINTF(eth_code, "    offset=dissect_ndr_ucarray(tvb, offset, pinfo, tree, di, drep, %s);\n", ptmpstr);
			    FPRINTF(eth_code, "    return offset;\n");
			    FPRINTF(eth_code, "}\n");
			    FPRINTF(eth_code, "\n");
			    ptmpstr=g_strdup(tmpstr);
			    break;
			default:
			    FPRINTF(stderr, "ERROR: typedeffunction can not handle this combination of sizeis/lengthis\n");
			    Exit(10);
			}

			/* handle pointers */
			while(num_pointers--){
				pointer_type=pi->type;
				pi=pi->next;
				snprintf(tmpstr, BASE_BUFFER_SIZE, "%s_%s", pointer_type, ptmpstr);
				FPRINTF(eth_code, "static unsigned\n");
				FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep)\n", tmpstr);
				FPRINTF(eth_code, "{\n");
				FPRINTF(eth_code, "    offset=dissect_ndr_toplevel_pointer(tvb, offset, pinfo, tree, di, drep, %s, %s, \"%s\", -1);\n", ptmpstr, ptr_to_define(pointer_type), ti->str);
				FPRINTF(eth_code, "    return offset;\n");
				FPRINTF(eth_code, "}\n");
				FPRINTF(eth_code, "\n");

				ptmpstr=g_strdup(tmpstr);

			}
		}

		if((pass==1)||(pass==2)){
			snprintf(tmpstr, BASE_BUFFER_SIZE, "%s_dissect_%s_%s", ifname, function_name, ti->str);
			ptmpstr=g_strdup(tmpstr);

			switch(bi->flags&(BI_SIZE_IS|BI_LENGTH_IS)){
			case 0:
			    break;
			case BI_SIZE_IS|BI_LENGTH_IS:
			    snprintf(tmpstr, BASE_BUFFER_SIZE, "ucvarray_%s", ptmpstr);
			    ptmpstr=g_strdup(tmpstr);
			    break;
			case BI_SIZE_IS:
			    snprintf(tmpstr, BASE_BUFFER_SIZE, "ucarray_%s", ptmpstr);
			    ptmpstr=g_strdup(tmpstr);
			    break;
			default:
			    FPRINTF(stderr, "ERROR: typedeffunction can not handle this combination of sizeis/lengthis\n");
			    Exit(10);
			}

			/* handle pointers */
			while(num_pointers--){
				pointer_type=pi->type;
				pi=pi->next;
				snprintf(tmpstr, BASE_BUFFER_SIZE, "%s_%s", pointer_type, ptmpstr);
				ptmpstr=g_strdup(tmpstr);
			}

			if((pass==1)&&(bi->flags&BI_IN)){
				FPRINTF(eth_code, " 	   offset=%s(tvb, offset, pinfo, tree, di, drep);\n", ptmpstr);
				FPRINTF(eth_code, " 	   offset=dissect_deferred_pointers(pinfo, tvb, offset, di, drep);\n");
				FPRINTF(eth_code, "\n");
			}
			if((pass==2)&&(bi->flags&BI_OUT)){
				FPRINTF(eth_code, " 	   offset=%s(tvb, offset, pinfo, tree, di, drep);\n", ptmpstr);
				FPRINTF(eth_code, " 	   offset=dissect_deferred_pointers(pinfo, tvb, offset, di, drep);\n");
				FPRINTF(eth_code, "\n");
			}
		}
		ti=ti->next;


		if(!g_strcmp0(ti->str,",")){
			ti=ti->next;
			continue;
		}
	}

	if((pass==1)||(pass==2)){
		if(pass==2){
			FPRINTF(eth_code, "   offset=dissect_ntstatus(tvb, offset, pinfo, tree, di, drep, %s, NULL);\n", hf_status);
			FPRINTF(eth_code, "\n");
		}
		FPRINTF(eth_code, "\n");
		FPRINTF(eth_code, "   return offset;\n");
		FPRINTF(eth_code, "}\n");
	}

	FPRINTF(NULL,"\nEND FUNCTION:%s pass:%d\n-------\n",function_name,pass);

	/* only advance token_list for pass==2
	   ti now points to the ')' token
	*/
	if(pass==2){
		if(!ti || g_strcmp0(ti->str,")")){
			FPRINTF(stderr, "ERROR: function does not end with ')'\n");
			Exit(10);
		}
		ti=ti->next;

		if(!ti || g_strcmp0(ti->str,";")){
			FPRINTF(stderr, "ERROR: function does not end with ';'\n");
			Exit(10);
		}
		ti=ti->next;

		token_list=ti;
	}
}


/* this function will parse a
	   typedef enum {
   or a
	   typedef [ v1_enum ] enum {
   construct and generate the appropriate code.
   the typedef will be g_removed from the token_list once it has been processed
   the function assumes that the typedef is the first object in the token_list
*/
static void parsetypedefenum(void)
{
	token_item_t *ti;
	enum_list_t *enum_list, *el, *lastel;
	char *p;
	long val;
	int eval, enumsize;
	char dissectorname[BASE_BUFFER_SIZE], valsstring[BASE_BUFFER_SIZE];
	char *hfvalsstring;

	enumsize=16;

	ti=token_list;
	if(g_strcmp0(ti->str, "typedef")){
		FPRINTF(stderr, "ERROR: typedefenum  first token is not 'typedef'\n");
		Exit(10);
	}
	ti=ti->next;

	/* this could be a [ v1_enum ] */
	if(!g_strcmp0(ti->str, "[")){
		ti=ti->next;

		if(g_strcmp0(ti->str, "v1_enum")){
			FPRINTF(stderr, "ERROR: typedefenum  not 'v1_enum' inside brackets\n");
			Exit(10);
		}
		ti=ti->next;

		if(g_strcmp0(ti->str, "]")){
			FPRINTF(stderr, "ERROR: typedefenum  'v1_enum' is not followed by ']'\n");
			Exit(10);
		}
		ti=ti->next;

		enumsize=32;
	}


	if(g_strcmp0(ti->str, "enum")){
		FPRINTF(stderr, "ERROR: typedefenum  second token is not 'enum'\n");
		Exit(10);
	}
	ti=ti->next;

	if(g_strcmp0(ti->str, "{")){
		FPRINTF(stderr, "ERROR: typedefenum  third token is not '{'\n");
		Exit(10);
	}
	ti=ti->next;

	/* now parse all values until we find the "}" */
	eval=0;
	enum_list=NULL;
	lastel=NULL;
	while(1){
		/* check for '}' */
		if(!g_strcmp0(ti->str,"}")){
			ti=ti->next;
			break;
		}

		/* handle 4 types of entries:
		 * 1, CONST = value,
		 * 2, CONST,
		 * 3, CONST = value}
		 * 4, CONST}
		 */
		el=g_new0(enum_list_t, 1);
		if (!el) {
			FPRINTF(stderr, "Can't allocate memory. Exit.\n");
			exit(10);
		}
		el->next=NULL;
		if(!enum_list){
			enum_list=el;
		} else {
			lastel->next=el;
		}
		lastel=el;

		/* grab CONST */
		el->name=ti->str;
		ti=ti->next;

		/* grab separator */
		if(!g_strcmp0(ti->str,"=")){
			ti=ti->next;
			/* grab value */
			val=strtol(ti->str,&p,0);
			if (p==ti->str||*p) {
				FPRINTF(stderr, "ERROR: typedefenum value is not a number\n");
				Exit(10);
			}
			el->val=(int)val;
			ti=ti->next;
		} else {
			el->val=eval;
		}
		eval=el->val+1;

		/* check for ',' */
		if(!g_strcmp0(ti->str,",")){
			ti=ti->next;
			continue;
		}

		/* check for '}' */
		if(!g_strcmp0(ti->str,"}")){
			ti=ti->next;
			break;
		}

		FPRINTF(stderr,"ERROR: typedefenum should not be reached\n");
		Exit(10);
	}

	/* verify that it ends with a ';' */
	if(g_strcmp0(ti->next->str,";")){
		FPRINTF(stderr,"ERROR enum terminator is not ';'\n");
		Exit(10);
	}

	snprintf(valsstring, BASE_BUFFER_SIZE, "%s_%s_vals", ifname, ti->str);
	snprintf(dissectorname, DISSECTORNAME_MAXLEN, "%s_dissect_%s", ifname, ti->str);

	FPRINTF(NULL,"\nENUM:%s\n-------\n",ti->str);

	FPRINTF(eth_hdr, "\n");
	for(el=enum_list;el;el=el->next){
		FPRINTF(eth_hdr, "#define %s		%d\n", el->name, el->val);
	}

	FPRINTF(eth_hdr, "\n");
	FPRINTF(eth_hdr, "extern const value_string %s[];\n", valsstring);
	FPRINTF(eth_hdr, "unsigned %s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param);\n", dissectorname);

	FPRINTF(eth_code, "\n");
	FPRINTF(eth_code, "const value_string %s[] = {\n", valsstring);

	for(el=enum_list;el;el=el->next){
		FPRINTF(eth_code, "    { %d	, \"%s\" },\n", el->val, el->name);
	}
	FPRINTF(eth_code, "    { 0	, NULL }\n");
	FPRINTF(eth_code, "};\n");

	FPRINTF(eth_code, "\n");
	FPRINTF(eth_code, "int\n");
	FPRINTF(eth_code, "%s(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, uint32_t param _U_)\n", dissectorname);
	FPRINTF(eth_code, "{\n");
	switch(enumsize){
	case 16:
		FPRINTF(eth_code, "    offset=dissect_ndr_uint16(tvb, offset, pinfo, tree, di, drep, hf_index, NULL);\n");
		break;
	case 32:
		FPRINTF(eth_code, "    offset=dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep, hf_index, NULL);\n");
		break;
	default:
		FPRINTF(stderr,"ERROR enum unknown size\n");
		Exit(10);
	}

	FPRINTF(eth_code, "    return offset;\n");
	FPRINTF(eth_code, "}\n");
	FPRINTF(eth_code, "\n");

	hfvalsstring = g_strdup_printf("VALS(%s)", valsstring);
	switch(enumsize){
	case 16:
		register_new_type(ti->str, dissectorname, "FT_INT16", "BASE_DEC", "0", hfvalsstring, 2);
		break;
	case 32:
		register_new_type(ti->str, dissectorname, "FT_INT32", "BASE_DEC", "0", hfvalsstring, 4);
		break;
	default:
		FPRINTF(stderr,"ERROR enum unknown size\n");
		g_free(hfvalsstring);
		Exit(10);
	}
	g_free(hfvalsstring);

	FPRINTF(NULL,"\n----------\nEND ENUM:%s\n",ti->str);

	/* skip past the name and the ';' */
	token_list=ti->next->next;
}

typedef struct _trimmed_prefixes_t {
	struct _trimmed_prefixes_t *next;
	char *name;
} trimmed_prefixes_t;
static trimmed_prefixes_t *prefixes_to_trim=NULL;

static void preparetrimprefix(char *prefix_name)
{
	trimmed_prefixes_t *new_prefix;
	new_prefix=g_new0(trimmed_prefixes_t, 1);
	if (!new_prefix) {
		FPRINTF(stderr, "Can't allocate memory. Exit.\n");
		exit(10);
	}
	new_prefix->next=prefixes_to_trim;
	prefixes_to_trim=new_prefix;
	new_prefix->name=g_strdup(prefix_name);
}

static void
trimprefix(void)
{
	token_item_t *ti;
	trimmed_prefixes_t *pfx;
	size_t len;

	for(pfx=prefixes_to_trim;pfx;pfx=pfx->next){
		len=strlen(pfx->name);
		for(ti=token_list;ti;ti=ti->next){
			if(!strncmp(ti->str, pfx->name, len)){
				ti->str+=len;
			}
		}
	}
}

static int Exit(int code)
{
	FPRINTF(stderr, "The tokens remaining when aborting:\n");
	printtokenlist(10);

	exit(code);
}

static void usage(void)
{
	FPRINTF(stderr, "Usage: idl2wrs <interface>\n");
}

static void
mergefile(const char *name, FILE *outfile)
{
	FILE *infile;

	FPRINTF(outfile, "\n\n/* INCLUDED FILE : %s */\n", name);
	infile=g_fopen(name, "r");
	while(!feof(infile)){
		int ch;
		ch=fgetc(infile);
		if(ch!=-1){
			fputc(ch, outfile);
		}
	}
	fclose(infile);
	FPRINTF(outfile, "/* END OF INCLUDED FILE : %s */\n\n\n", name);
}



static char *
str_read_string(char *str, char **name)
{
	char tmpstr[BASE_BUFFER_SIZE], *strptr;
	int skip_blanks;
	int quoted_string;

	strptr=tmpstr;
	skip_blanks=1;
	quoted_string=0;
	while(1){
		if(!*str){
			*strptr=0;
			*name=g_strdup(tmpstr);
			return str;
		}
		if(skip_blanks){
			if( (*str==' ') || (*str=='\t') ){
				str++;
				continue;
			}
			if( *str=='"' ){
				str++;
				quoted_string=1;
			}
			skip_blanks=0;
			continue;
		}
		if( (*str==' ') || (*str=='\t') ){
			if(quoted_string){
				*strptr++ = *str++;
				continue;
			}
			*strptr=0;
			*name=g_strdup(tmpstr);
			return str;
		}
		if( (*str=='"') || (*str=='\n') ){
			*strptr=0;
			*name=g_strdup(tmpstr);
			return ++str;
		}
		*strptr++ = *str++;
	}
	return NULL;
}

static void
readcnffile(FILE *fh)
{
	char cnfline[4 * BASE_BUFFER_SIZE];

	FPRINTF(NULL, "Reading conformance file\n=======================\n");
	while(!feof(fh)){
		cnfline[0]=0;
		if(!fgets(cnfline, 4 * BASE_BUFFER_SIZE, fh) || !cnfline[0]){
			continue;
		}
		if(cnfline[0]=='#'){
			/* ignore all comments */
		} else if(!strncmp(cnfline, "NOEMIT", 6)){
			no_emit_item_t *nei;
			char *str, *name;

			str=cnfline+6;
			str_read_string(str, &name);
			nei=g_new0(no_emit_item_t, 1);
			if (!nei) {
				FPRINTF(stderr, "Can't allocate memory. Exit.\n");
				exit(10);
			}
			nei->next=no_emit_list;
			no_emit_list=nei;
			nei->name=name;
			FPRINTF(NULL, "NOEMIT : %s\n", nei->name);
		} else if(!strncmp(cnfline, "TYPE", 4)){
			char *name, *dissectorname, *ft_type, *base_type;
			char *mask, *valsstring, *al;
			char *str;
			int alignment;

			str=cnfline+4;
			str=str_read_string(str, &name);
			str=str_read_string(str, &dissectorname);
			str=str_read_string(str, &ft_type);
			str=str_read_string(str, &base_type);
			str=str_read_string(str, &mask);
			str=str_read_string(str, &valsstring);
			str_read_string(str, &al);
			if (ws_strtoi32(al, NULL, &alignment)) {
				FPRINTF(NULL, "TYPE : X%s,%sX\n", name, dissectorname);
				register_new_type(name, dissectorname, ft_type, base_type, mask, valsstring, alignment);
			}
		} else if(!strncmp(cnfline, "PARAM_VALUE", 11)){
			char *dissectorname, *value;
			char *str;

			str=cnfline+11;
			str=str_read_string(str, &dissectorname);
			str_read_string(str, &value);

			FPRINTF(NULL, "PARAM_VALUE : %s=%s\n", dissectorname,value);
			register_dissector_param_value(dissectorname, value);
		} else if(!strncmp(cnfline, "HF_FIELD", 8)){
			char *hf_index, *title, *filter_name, *ft_type;
			char *base_type, *valsstring, *mask, *blurb;
			char *str;

			str=cnfline+8;
			str=str_read_string(str, &hf_index);
			str=str_read_string(str, &title);
			str=str_read_string(str, &filter_name);
			str=str_read_string(str, &ft_type);
			str=str_read_string(str, &base_type);
			str=str_read_string(str, &valsstring);
			str=str_read_string(str, &mask);
			str_read_string(str, &blurb);
			FPRINTF(NULL, "HF_FIELD: %s \"%s\"\n", hf_index, title);
			register_hf_field(hf_index, title, filter_name, ft_type, base_type, valsstring, mask, blurb);
		} else if(!strncmp(cnfline, "HF_RENAME", 9)){
			char *old_name, *new_name;
			char *str;

			str=cnfline+9;
			str=str_read_string(str, &old_name);
			str_read_string(str, &new_name);
			FPRINTF(NULL, "HF_RENAME: %s -> %s\n", old_name, new_name);
			register_hf_rename(old_name, new_name);
		} else if(!strncmp(cnfline, "UNION_TAG_SIZE", 14)){
			char *union_name, *union_tag;
			int32_t union_tag_size;
			union_tag_size_item_t *utsi;
			char *str;

			str=cnfline+14;
			str=str_read_string(str, &union_name);
			str_read_string(str, &union_tag);
			if (!ws_strtoi32(union_tag, NULL, &union_tag_size)) {
				FPRINTF(NULL, "UNION_TAG_SIZE: invalid string: %s\n", union_tag);
				exit(10);
			}
			FPRINTF(NULL, "UNION_TAG_SIZE: %s == %d\n", union_name, union_tag_size);
			utsi=g_new0(union_tag_size_item_t, 1);
			if (!utsi) {
				FPRINTF(stderr, "Can't allocate memory. Exit.\n");
				exit(10);
			}
			utsi->next=union_tag_size_list;
			union_tag_size_list=utsi;
			utsi->name=g_strdup(union_name);
			utsi->size=union_tag_size;
		} else if(!strncmp(cnfline, "STRIP_PREFIX", 12)){
			char *prefix_name;
			char *str;

			str=cnfline+12;
			str_read_string(str, &prefix_name);
			FPRINTF(NULL, "STRIP_PREFIX: %s\n", prefix_name);
			preparetrimprefix(prefix_name);
		} else {
			FPRINTF(stderr, "ERROR: could not parse cnf directive:%s\n",cnfline);
			exit(10);
		}
	}
}

int main(int argc, const char *argv[])
{
	char idlfile[BASE_BUFFER_SIZE];
	char tmplfile[BASE_BUFFER_SIZE];
	char prefix_str[BASE_BUFFER_SIZE];
	bracket_item_t *bi;
	FILE *fh;

	if(argc!=2){
		usage();
		exit(0);
	}

	eth_code=g_fopen("ETH_CODE", "w");
	eth_hdr=g_fopen("ETH_HDR", "w");
	eth_hfarr=g_fopen("ETH_HFARR", "w");
	eth_hf=g_fopen("ETH_HF", "w");
	eth_ettarr=g_fopen("ETH_ETTARR", "w");
	eth_ett=g_fopen("ETH_ETT", "w");
	eth_ft=g_fopen("ETH_FT", "w");
	eth_handoff=g_fopen("ETH_HANDOFF", "w");

	snprintf(idlfile, BASE_BUFFER_SIZE, "%s.cnf", argv[1]);
	fh=g_fopen(idlfile,"r");
	if(fh){
		readcnffile(fh);
		fclose(fh);
	}

	snprintf(idlfile, BASE_BUFFER_SIZE, "%s.idl", argv[1]);
	fh=g_fopen(idlfile,"r");
	if(!fh){
		FPRINTF(stderr, "ERROR: could not open idl-file:%s\n", idlfile);
		Exit(0);
	}

	lineno=0;
	linepos=0;
	tokenize(fh);
	prune_keyword_parameters("size_is");
	prune_keyword_parameters("length_is");
	rename_tokens("NTSTATUS", "WERROR");
	rename_tokens("unistr_noterm", "unistr");
	rename_tokens("ascstr_noterm", "ascstr");
	rename_tokens("hyper", "uint64");
	FPRINTF(NULL,"\n\nParsing header:\n================\n");
	parseheader();

	/* some idl files prepend a lot of symbols with <ifname>_
	   search through the tokenlist and g_remove all such
	   prefixes
	*/
	snprintf(prefix_str, BASE_BUFFER_SIZE, "%s_", ifname);
	preparetrimprefix(prefix_str);
	trimprefix();

	/* this is the main loop, each iteration it tries to identify what
	   kind of construct is the first entry in the token_list and call
	   the appropriate handler
	*/
	while(1) {
		/* just skip any [ ] that starts a new construct */
		if( !g_strcmp0(token_list->str, "[") ){
			token_list=parsebrackets(token_list, &bi);
			continue;
		}

		/* typedef enum { */
		if( !g_strcmp0(token_list->str,"typedef")
		  &&!g_strcmp0(token_list->next->str,"enum") ){
			parsetypedefenum();
			continue;
		}

		/* typedef [ v1_enum ] enum { */
		if( !g_strcmp0(token_list->str,"typedef")
		  &&!g_strcmp0(token_list->next->str,"[")
		  &&!g_strcmp0(token_list->next->next->str,"v1_enum")
		  &&!g_strcmp0(token_list->next->next->next->str,"]")
		  &&!g_strcmp0(token_list->next->next->next->next->str,"enum") ){
			parsetypedefenum();
			continue;
		}

		/* const */
		if( !g_strcmp0(token_list->str,"const") ){
			parseconst();
			continue;
		}

		/* typedef struct { */
		if( !g_strcmp0(token_list->str,"typedef") ){
			token_item_t *tmpti;

			tmpti=token_list->next;
			if( !g_strcmp0(tmpti->str, "[") ){
				tmpti=parsebrackets(tmpti, &bi);
				/* do some sanity checks here of bi->flags */
			}
			if( !g_strcmp0(tmpti->str, "struct") ){
				parsetypedefstruct(0);
				parsetypedefstruct(1);
				continue;
			}
		}

		/* typedef union { */
		if( !g_strcmp0(token_list->str,"typedef") ){
			token_item_t *tmpti;

			tmpti=token_list->next;
			if( !g_strcmp0(tmpti->str, "[") ){
				tmpti=parsebrackets(tmpti, &bi);
				/* do some sanity checks here of bi->flags */
			}
			if( !g_strcmp0(tmpti->str, "union") ){
				parsetypedefunion(0);
				parsetypedefunion(1);
				continue;
			}
		}

		/* typedef bitmap { */
		if( !g_strcmp0(token_list->str,"typedef") ){
			token_item_t *tmpti;

			tmpti=token_list->next;
			if( !g_strcmp0(tmpti->str, "[") ){
				tmpti=parsebrackets(tmpti, &bi);
				/* do some sanity checks here of bi->flags */
			}
			if( !g_strcmp0(tmpti->str, "bitmap") ){
				parsetypedefbitmap(0);
				parsetypedefbitmap(1);
				continue;
			}
		}

		/* functions:  WERROR function '(' */
		if( !g_strcmp0(token_list->str,"WERROR")
		  &&!g_strcmp0(token_list->next->next->str,"(") ){
			parsefunction(0);
			parsefunction(1);
			parsefunction(2);
			continue;
		}

		/* declare ... ; */
		if( !g_strcmp0(token_list->str,"declare") ){
			skipdeclare();
			continue;
		}


		break;
	};


	fclose(eth_code);
	fclose(eth_hdr);
	fclose(eth_hf);
	fclose(eth_hfarr);
	fclose(eth_ett);
	fclose(eth_ettarr);
	fclose(eth_ft);
	fclose(eth_handoff);

	/* unless the token_list now only contains a single token : '}'
	   we have failed to compile the idl file properly
		*/
	if( g_strcmp0(token_list->str, "}") || token_list->next){
		FPRINTF(stderr, "ERROR: we did not process all tokens. Compiler is incomplete.\n===========================================\n");
		printtokenlist(10);
		exit(10);
	}

	check_hf_rename_refcount();

	/* merge code and template into dissector */
	snprintf(line, 4 * BASE_BUFFER_SIZE, "packet-dcerpc-%s.c", ifname);
	fh=g_fopen(line, "w");
	snprintf(tmplfile, BASE_BUFFER_SIZE, "packet-dcerpc-%s-template.c", argv[1]);
	tfh=g_fopen(tmplfile, "r");
	if(!tfh){
		FPRINTF(stderr, "ERROR: could not find %s\n", tmplfile);
		exit(10);
	}
	while(!feof(tfh)){
		line[0]=0;
		if(!fgets(line, 4 * BASE_BUFFER_SIZE, tfh) || !line[0]){
			continue;
		}
		if(!strncmp(line, "ETH_CODE", 8)){
			mergefile("ETH_CODE",fh);
		} else if(!strncmp(line, "ETH_HDR", 7)){
			mergefile("ETH_HDR",fh);
		} else if(!strncmp(line, "ETH_HFARR", 9)){
			mergefile("ETH_HFARR",fh);
		} else if(!strncmp(line, "ETH_HF", 6)){
			mergefile("ETH_HF",fh);
		} else if(!strncmp(line, "ETH_ETTARR", 10)){
			mergefile("ETH_ETTARR",fh);
		} else if(!strncmp(line, "ETH_ETT", 7)){
			mergefile("ETH_ETT",fh);
		} else if(!strncmp(line, "ETH_FT", 6)){
			mergefile("ETH_FT",fh);
		} else if(!strncmp(line, "ETH_HANDOFF", 11)){
			mergefile("ETH_HANDOFF",fh);
		} else {
			fputs(line, fh);
		}
	}
	fclose(fh);
	fclose(tfh);

	snprintf(line, 4 * BASE_BUFFER_SIZE, "packet-dcerpc-%s.h", ifname);
	fh=g_fopen(line, "w");
	snprintf(tmplfile, BASE_BUFFER_SIZE, "packet-dcerpc-%s-template.h", argv[1]);
	tfh=g_fopen(tmplfile, "r");
	if(!tfh){
		FPRINTF(stderr, "ERROR: could not find %s\n", tmplfile);
		exit(10);
	}
	while(!feof(tfh)){
		line[0]=0;
		if(!fgets(line, 4 * BASE_BUFFER_SIZE, tfh) || !line[0]){
			continue;
		}
		if(!strncmp(line, "ETH_CODE", 8)){
			mergefile("ETH_CODE",fh);
		} else if(!strncmp(line, "ETH_HDR", 7)){
			mergefile("ETH_HDR",fh);
		} else if(!strncmp(line, "ETH_HFARR", 9)){
			mergefile("ETH_HFARR",fh);
		} else if(!strncmp(line, "ETH_HF", 6)){
			mergefile("ETH_HF",fh);
		} else if(!strncmp(line, "ETH_ETTARR", 10)){
			mergefile("ETH_ETTARR",fh);
		} else if(!strncmp(line, "ETH_ETT", 7)){
			mergefile("ETH_ETT",fh);
		} else if(!strncmp(line, "ETH_FT", 6)){
			mergefile("ETH_FT",fh);
		} else if(!strncmp(line, "ETH_HANDOFF", 11)){
			mergefile("ETH_HANDOFF",fh);
		} else {
			fputs(line, fh);
		}
	}

	g_print("%s was successfully compiled\n", ifname);

	fclose(fh);
	fclose(tfh);

	if (g_remove("ETH_CODE") == -1) {
		FPRINTF(stderr, "Can't remove ETH_CODE");
	}
	if (g_remove("ETH_HDR") == -1) {
		FPRINTF(stderr, "Can't remove ETH_CODE");
	}
	if (g_remove("ETH_HFARR") == -1) {
		FPRINTF(stderr, "Can't remove ETH_CODE");
	}
	if (g_remove("ETH_HF") == -1) {
		FPRINTF(stderr, "Can't remove ETH_CODE");
	}
	if (g_remove("ETH_ETTARR") == -1) {
		FPRINTF(stderr, "Can't remove ETH_CODE");
	}
	if (g_remove("ETH_ETT") == -1) {
		FPRINTF(stderr, "Can't remove ETH_CODE");
	}
	if (g_remove("ETH_FT") == -1) {
		FPRINTF(stderr, "Can't remove ETH_CODE");
	}
	if (g_remove("ETH_HANDOFF") == -1) {
		FPRINTF(stderr, "Can't remove ETH_CODE");
	}


	return 0;
}

/*
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
 *
 * Local variables:
 * c-basic-offset: 8
 * tab-width: 8
 * indent-tabs-mode: t
 * End:
 *
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
 * :indentSize=8:tabSize=8:noTabs=false:
 */
