// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
// Author(s): Jonathan Berry

// This software is copyrighted by the DIMACS Center at Rutgers, The State
// University of New Jersey.  IT IS PROVIDED AS IS, AND THE AUTHORS, DIMACS, AND
// RUTGERS, THE STATE UNIVERSITY OF NEW JERSEY  DISCLAIM
// ALL LIABILITY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
// DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
// IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
// NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
// MODIFICATIONS.

// The authors hereby grant permission to use, copy, modify, distribute,
// and license this software and its documentation for any purpose, provided
// that existing copyright notices are retained in all copies and that this
// notice is included verbatim in any distributions. No written agreement,
// license, or royalty fee is required for any of the authorized uses.
// Modifications to this software may be copyrighted by their authors
// and need not follow the licensing terms described here, provided that
// the new terms are clearly indicated on the first page of each file where
// they apply.

// Last File Update: 7-Aug-199
// 

// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
// Author: Jonathan Berry

//This software is copyrighted by the DIMACS Center at Rutgers, The State
//University of New Jersey.  IT IS PROVIDED AS IS, AND THE AUTHORS, DIMACS, AND
//RUTGERS, THE STATE UNIVERSITY OF NEW JERSEY  DISCLAIM
//ALL LIABILITY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
//DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
//DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
//POSSIBILITY OF SUCH DAMAGE.

//The authors hereby grant permission to use, copy, modify, and distribute
//this software for any purpose.  However, fees for distribution or use of this
//software or derived works may not be charged without the written
//permission of the copyright holder.
// Last File Update: 7-Aug-199
// 

#include <stdio.h>
#include <stdlib.h>
#include <iostream.h>
#include <fstream.h>
#include <strstream.h>
#include <ctype.h>

#define MAX_INCLUDES	10
#define FOR_CXX		0
#define FOR_STK		1
#define STK_INIT	0
#define USER_METHODS	1
#define INDEP_NAME	1
#define WRAP_ARG	0
#define DONT_WRAP_ARG	1

static char *CompoundName=0;
static char *CompoundName2=0;	// e.g. SetBase<T, DEFAULT_SET_IMPL<T> >
static char *StrippedName=0;
static char *StrippedSTkName=0;
static char *STkObjName=0;
static char *StrippedObjName=0;
static char *HolderClassname=0;
static char *ParentHolderClassname=0;

static ostream *out;

void genHeaderComment(int argc, char *argv[])
{
	char *s;
	ostrstream oss;
	int i;

	oss << argv[0] << " ";
	for (i=1; i<argc; i++)
		oss << "\"" << argv[i] << "\" ";
	oss << ends;
	char *buffer = oss.str();
	*out << "//" << buffer << endl;
	delete buffer;
}

char *newString(char *src)
{
	char *dest = new char[strlen(src)+1];
	strcpy(dest, src);
	return dest;
}

int wrappedHolder(char *hname)
{
	if (hname && ((strcmp(hname,"Collection")==0) ||
	             (strcmp(hname,"List")==0) ||
	             (strcmp(hname,"Matrix")==0) ||
	             (strcmp(hname,"Array")==0)))
		return 1;
	return 0;
}

int wrappedHolderRelative(char *hname)
{
	if (hname &&  (wrappedHolder(hname) || 
	                          (strcmp(hname,"MSet")==0) ||
	                          (strcmp(hname,"Set")==0) ||
	                          (strcmp(hname,"Sequence")==0) ||
	                          (strcmp(hname,"SortedList")==0) ||
	                          (strcmp(hname,"SortedArray")==0)))
		return 1;
	return 0;
}

char *findParent(char *hname)
{
	if (!hname || !wrappedHolderRelative(hname))
		return 0;

	if ((strcmp(hname,"Collection")==0) ||
	    (strcmp(hname,"MSet")==0) ||
	    (strcmp(hname,"Set")==0) ||
	    (strcmp(hname,"Sequence")==0))
		return newString("Collection");
	if ((strcmp(hname,"List")==0) ||
	    (strcmp(hname,"SortedList")==0))
		return newString("List");
	if ((strcmp(hname,"Array")==0) ||
	    (strcmp(hname,"SortedArray")==0))
		return newString("Array");
	if (strcmp(hname,"Matrix")==0)
		return newString("Matrix");
	return 0;
}

void genHeader()
{
	//*out << "#ifdef STK_INTERFACE" << endl;
	*out << "#include <stk.h>" << endl;
	*out << "#include <LINK/stkWrapper/LINK_STk.h>" << endl;
	*out << endl;
}

void genTrailer()
{
	//*out << "#endif " << endl;
}

void genObjectIncludes(char *full_include_file_path)
{
	*out << "#include <" << full_include_file_path <<  ">" << endl;
	*out << "" << endl;
}

void genIncludes(char *obj_incls[], int obj_incl_count)
{
        int i;
        for (i=0; i<obj_incl_count; i++)
                genObjectIncludes(obj_incls[i]);

	*out << "#include <LINK/stkWrapper/Wrapper.h>" << endl;
	*out << "#include <LINK/stkWrapper/Register.h>" << endl;
	if (ParentHolderClassname)
		*out << "#include <LINK/stkWrapper/" << 
			ParentHolderClassname << "Wrapper.h>" << endl;
	*out << endl;
}

void genGCPrototypes(char *hname, char *display_fct, 
		     char *mark_fct, char *sweep_fct)
{
	//if (hname && (display_fct || mark_fct || sweep_fct)) {
	//	cerr << "error: " << hname << " already has display, ";
	//	cerr << "mark, and sweep functions" << endl;
	//	exit(1);
	//} else if (hname)
	//	return;

	if (display_fct)
	   *out << "void " << display_fct << "(SCM, SCM, int);" << endl;
	if (mark_fct)
	   *out << "void " << mark_fct << "(SCM);" << endl;
	if (sweep_fct)
	   *out << "void " << sweep_fct << "(SCM);" << endl;
	*out << endl;
}

void genMacros(char *fullName)
{
	*out << endl;
	*out << "#define "
		<< StrippedName <<"DATA(x) ((" << fullName 
				<< "*) (EXTDATA(x)))" << endl;
	*out << "#define "
		<< StrippedName << "IS_DATA(x) (TYPEP(x, tc_CXXwrapper) && \\" 
							<< endl;
	*out << "\t\tTYPEP(STk_slot_ref(x,val_scm), tc_CXXwrapper) && \\"<<endl;
	*out << "\t\t(EXTID(STk_slot_ref(x,val_scm)) == Wrapper<";
	*out << fullName << " >::type))" << endl;
	*out << "#define "
		<< StrippedName << "ISNT_DATA(x) (!" 
				<< StrippedName << "IS_DATA(x))" << endl;
	*out << endl;

	*out << "#define "
		<< StrippedName << "CXX_DATA(x) (*(" << fullName 
					<< "*) (EXTDATA(VAL(x))))" << endl;
	*out << "#define "
		<< StrippedName << "CXX_IS_DATA(x) (INSTANCEP(x) && \\" << endl;
	*out << "\t\tTYPEP(STk_slot_ref(x,val_scm), tc_CXXwrapper) && \\"<<endl;
	*out << "\t\t(EXTID(STk_slot_ref(x,val_scm)) == Wrapper<";
	*out << fullName << " >::type))" << endl;
	*out << "#define "
		<< StrippedName << "CXX_ISNT_DATA(x) (!"
				<< StrippedName << "CXX_IS_DATA(x))" << endl;
	*out << endl;
}

void genTypePredicate(char *stripped_name)
{
	*out << "static SCM is" << stripped_name << "(SCM i)" << endl;
	*out << "{" << endl;
	*out << "	if (" << stripped_name << "CXX_IS_DATA(i))" << endl;
	*out << "		return Truth;" << endl;
	*out << "	return Ntruth;" << endl;
	*out << "}" << endl;
	*out << endl;
}

void wrapTypePredicate(char *stripped_stk_name, char *stripped_name)
{
	*out << "\tSTk_add_new_cpp_primitive(\"" << stripped_stk_name ;
	*out << "?\", tc_subr_1," << endl;
        *out << "\t(PRIMITIVE (*)(...))  is" << stripped_name << ");" << endl;
}

	
char *validCname(char *s, int flag)
{
	char *result, *d; 
	char c = (flag==FOR_CXX) ? '_' : '-';

	if (flag==FOR_CXX) {
 		result = new char[strlen(s)+2];
		d = result;
		*d++ = c;
	} else {
 		result = new char[strlen(s)+1];
		d = result;
	}
	while (*s) {
		if (isalnum(*s))
			*d++ = *s;
		else if ((*s!=' ') && !((*s == '*') && (flag==FOR_STK)))
			*d++ = c;
		s++;
	}
	*d = '\0';

	if (flag == FOR_STK) {
		int j = strlen(result);	   // this to avoid List-List-int---
		while ( (--j>=0) && (result[j] == c))
			result[j] = '\0';
	}
	return result;
}

int genTypedefs(int holder_ptr, char *objName)
{
	if (HolderClassname) {
		ostrstream oss2;
		oss2 << HolderClassname << "<" << objName << " >";
		if (holder_ptr)
			oss2 << "*";
		oss2 << ends;
		CompoundName = oss2.str();
		if ((strcmp(HolderClassname, "Set") == 0) ||
		    (strcmp(HolderClassname, "MSet") == 0)) {
			ostrstream oss;
			oss << HolderClassname << "Base<" << objName << 
				", DEFAULT_SET_IMPL<" << objName << " > >";
			if (holder_ptr)
				oss << "*";
			oss << ends;
			CompoundName2 = oss.str();
		} else if (strcmp(HolderClassname, "Sequence") == 0) {
			ostrstream oss;
			oss << HolderClassname << "Base<" << objName << 
				", DEFAULT_SEQ_IMPL<" << objName << " > >";
			if (holder_ptr)
				oss << "*";
			oss << ends;
			CompoundName2 = oss.str();
		} else if (strcmp(HolderClassname, "Array") == 0) {
			ostrstream oss;
			oss << "Vector<" << objName << " >";
			if (holder_ptr)
				oss << "*";
			oss << ends;
			CompoundName2 = oss.str();
		}
	} else
		CompoundName = objName;

	StrippedName = validCname(CompoundName, FOR_CXX);
	if (HolderClassname && (strcmp(HolderClassname, "Array")==0))
		StrippedSTkName = validCname(CompoundName2, FOR_STK);
	else
		StrippedSTkName = validCname(CompoundName, FOR_STK);
	STkObjName = validCname(objName, FOR_STK);
	StrippedObjName = validCname(objName, FOR_CXX);

        *out << "typedef " <<objName << " " << StrippedObjName <<  ";" << endl;
        if (HolderClassname) {
                *out << "typedef " << CompoundName << " "
                                        << StrippedName<< ";" << endl;
                // The following statement placates VC++5.0.  When the
                // latter is fixed, the statement can be removed.	       
                if ((strcmp(HolderClassname,"Collection")!=0) &&
		    (strcmp(HolderClassname, "Container")!=0))
		      *out << "static " << CompoundName << " s_" 
		           << StrippedName << ";" << endl;
        }


	int is_ptr = (CompoundName[strlen(CompoundName)-1] == '*');
	return is_ptr;
}

void genPrimitive(char *hname, char *method_name, char *fct_type, 
			 char *stripped_name, char *cxx_method_name,
			 char *base_name=0)
{
	
	*out << "\tSTk_add_new_cpp_primitive(\"" ;;  
	if (stripped_name && (strcmp(stripped_name, "") != 0))
		*out << stripped_name << "-"<< method_name << "\", ";
	else
		*out << stripped_name << method_name << "\", ";
	*out << fct_type << ", ";
        *out << "\n\t(PRIMITIVE (*)(...))  " << hname;
	if (base_name)
		*out << "<" << base_name <<" >::" 
					<< cxx_method_name << ");" << endl;
	else
		*out << "<" << StrippedObjName << ">::" 
				<< cxx_method_name << ");" << endl;
}

void genOneArgMethod(char *method, char *arg1_type, char *stripped_name,
		     char *ovl_flag, int dont_wrap_arg=0, 
		     int indep_name=0)
{
	*out << "\taddOneArgMethod(\"" << method << "\"," << endl;
	if (!dont_wrap_arg)
		*out <<  "\t\tWrapper<" << arg1_type << " >::name, " << endl;
	else
		*out <<  "\t\t" << arg1_type << "," << endl;
	if (!indep_name)
		*out << "\t\t\"" << 
			stripped_name <<"-"<< method << "\", " << ovl_flag;
	else
		*out << "\t\t\"" << stripped_name << "\", " << ovl_flag;
	*out << ");" << endl;
}

void genTwoArgMethod(char *method, char *arg1_type, char *arg2_type, 
		     char *stripped_name, char *ovl_flag, 
		     int dont_wrap_arg1=0, int dont_wrap_arg2=0,
		     int indep_name=0)
{
	*out << "\taddTwoArgMethod(\"" << method << "\"," << endl;
	if (!dont_wrap_arg1)
		*out <<  "\t\tWrapper<" << arg1_type << " >::name, " << endl;
	else
		*out <<  "\t\t" << arg1_type << "," << endl;
	if (!dont_wrap_arg2)
		*out <<  "\t\tWrapper<" << arg2_type << " >::name, " << endl;
	else
		*out <<  "\t\t" << arg2_type << "," << endl;
	if (!indep_name)
		*out << "\t\t\"" << 
			stripped_name <<"-"<< method << "\", " << ovl_flag;
	else
		*out << "\t\t\"" << stripped_name << "\", " << ovl_flag;
	*out << ");" << endl;
}

void genThreeArgMethod(char *method, char *arg1_type, char *arg2_type, 
	       char *arg3_type, char *stripped_name, char *ovl_flag,
		     int dont_wrap_arg1=0, int dont_wrap_arg2=0,
		     int dont_wrap_arg3=0, int indep_name=0)
{
	*out << "\taddThreeArgMethod(\"" << method << "\"," << endl;
	if (!dont_wrap_arg1)
		*out <<  "\t\tWrapper<" << arg1_type << " >::name, " << endl;
	else
		*out <<  "\t\t" << arg1_type << "," << endl;
	if (!dont_wrap_arg2)
		*out <<  "\t\tWrapper<" << arg2_type << " >::name, " << endl;
	else
		*out <<  "\t\t" << arg2_type << "," << endl;
	if (!dont_wrap_arg3)
		*out <<  "\t\tWrapper<" << arg3_type << " >::name, " << endl;
	else
		*out <<  "\t\t" << arg3_type << "," << endl;
	if (!indep_name)
		*out << "\t\t\"" << 
			stripped_name <<"-"<< method << "\", " << ovl_flag;
	else
		*out << "\t\t\"" << stripped_name << "\", " << ovl_flag;
	*out << ");" << endl;
}

void genFourArgMethod(char *method, char *arg1_type, char *arg2_type, 
	        char *arg3_type, char *arg4_type,
		char *stripped_name, char *ovl_flag,
		     int dont_wrap_arg1=0, int dont_wrap_arg2=0,
		     int dont_wrap_arg3=0, int dont_wrap_arg4=0,
		     int indep_name=0)
{
	*out << "\taddFourArgMethod(\"" << method << "\"," << endl;
	if (!dont_wrap_arg1)
		*out <<  "\t\tWrapper<" << arg1_type << " >::name, " << endl;
	else
		*out <<  "\t\t" << arg1_type << "," << endl;
	if (!dont_wrap_arg2)
		*out <<  "\t\tWrapper<" << arg2_type << " >::name, " << endl;
	else
		*out <<  "\t\t" << arg2_type << "," << endl;
	if (!dont_wrap_arg3)
		*out <<  "\t\tWrapper<" << arg3_type << " >::name, " << endl;
	else
		*out <<  "\t\t" << arg3_type << "," << endl;
	if (!dont_wrap_arg4)
		*out <<  "\t\tWrapper<" << arg4_type << " >::name, " << endl;
	else
		*out <<  "\t\t" << arg4_type << "," << endl;
	if (!indep_name)
		*out << "\t\t\"" << 
			stripped_name <<"-"<< method << "\", " << ovl_flag;
	else
		*out << "\t\t\"" << stripped_name << "\", " << ovl_flag;
	*out << ");" << endl;
}

void genBuildMethod(char *method, char *arg_type, 
		     char *stripped_name, char *ovl_flag, int dont_wrap_arg=0,
		     int indep_name=0)
{
	*out << "\taddArbMethod(\"" << method << "\"," << endl;
	if (!dont_wrap_arg)
		*out <<  "\t\tWrapper<" << arg_type << " >::name, " << endl;
	else
		*out <<  "\t\t" << arg_type << "," << endl;
	if (!indep_name)
		*out << "\t\t\"" << 
			stripped_name <<"-"<< method << "\", " << ovl_flag;
	else
		*out << "\t\t\"" << stripped_name << "\", " << ovl_flag;
	*out << ");" << endl;
}

void genArbMethod(char *method, char *arg_type, 
		     char *stripped_name, char *ovl_flag, int dont_wrap_arg=0,
		     int indep_name=0)
{
	*out << "\taddArbMethod(\"" << method << "\"," << endl;
	if (!dont_wrap_arg)
		*out <<  "\t\tWrapper<" << arg_type << " >::name, " << endl;
	else
		*out <<  "\t\t" << arg_type << "," << endl;
	if (!indep_name)
		*out << "\t\t\"" << 
			stripped_name <<"-"<< method << "\", " << ovl_flag;
	else
		*out << "\t\t\"" << stripped_name << "\", " << ovl_flag;
	*out << ");" << endl;
}

void genListMethod(char *method,  
		     char *stripped_name, char* ovl_flag, int dont_wrap_arg=0,
		     int indep_name=0)
{
	*out << "\taddListMethod(\"" << method << "\"," << endl;
	/*
	if (!dont_wrap_arg)
		*out <<  "\t\tWrapper<" << arg_type << " >::name, " << endl;
	else
		*out <<  "\t\t" << arg_type << "," << endl;
	*/
	if (!indep_name)
		*out << "\t\t\"" << 
			stripped_name <<"-"<< method << "\", " << ovl_flag;
	else
		*out << "\t\t\"" << stripped_name << "\", " << ovl_flag;
	*out << ");" << endl;
}

void genBooleanMethod(char *method, char *arg_type, 
		     char *stripped_name, char *ovl_flag, int dont_wrap_arg=0,
		     int indep_name=0)
{
	*out << "\taddBooleanMethod(\"" << method << "\"," << endl;
	if (!dont_wrap_arg)
		*out <<  "\t\tWrapper<" << arg_type << " >::name, " << endl;
	else
		*out <<  "\t\t" << arg_type << "," << endl;
	if (!indep_name)
		*out << "\t\t\"" << 
			stripped_name <<"-"<< method << "\", " << ovl_flag;
	else
		*out << "\t\t\"" << stripped_name << "\", " << ovl_flag;
	*out << ");" << endl;
}

void genSTkArrayMethods()
{
	*out << endl;
/*
	{
	ostrstream oss, oss2;
   	oss << "vector-" << STkObjName <<  ends;
   	oss2 << "vector-" << STkObjName << "1" << ends;
	char *stk_meth = oss.str();
	char *stk_prim = oss2.str();
	genListMethod(stk_meth, stk_prim, "LINK_NEW",
						WRAP_ARG, INDEP_NAME);
	delete stk_meth;
	delete stk_prim;
	}
	{
	ostrstream oss, oss2;
   	oss << "vector-" << STkObjName << ends;
   	oss2 << "list->" << "vector-" << STkObjName << ends;
	char *stk_meth = oss.str();
	char *stk_prim = oss2.str();
	genOneArgMethod(stk_meth, "\"<pair>\"", stk_prim, "LINK_NEW",
						DONT_WRAP_ARG, 
							INDEP_NAME);
	delete stk_prim;
	delete stk_meth;
	}
*/
	genOneArgMethod("vector-copy", StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genOneArgMethod("vector->list", StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genOneArgMethod("vector-length", StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genTwoArgMethod("vector-ref", StrippedName, 
					"\"<integer>\"",
					StrippedSTkName, "LINK_OVL", 
						WRAP_ARG,DONT_WRAP_ARG);
	genTwoArgMethod("vector-fill!", StrippedName, StrippedObjName,
					StrippedSTkName, "LINK_OVL");
	genTwoArgMethod("vector-resize", StrippedName, "\"<integer>\"",
					StrippedSTkName, "LINK_OVL",
						WRAP_ARG, DONT_WRAP_ARG);
	genThreeArgMethod("vector-set!", StrippedName, "\"<integer>\"",
					StrippedObjName, StrippedSTkName, 
					"LINK_OVL",
						WRAP_ARG, DONT_WRAP_ARG,
						WRAP_ARG);
	genTwoArgMethod("eqv?",StrippedName, StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genBooleanMethod("<",  StrippedName, StrippedSTkName, "LINK_OVL");
	genBooleanMethod("<=", StrippedName, StrippedSTkName, "LINK_OVL");
	genBooleanMethod(">",  StrippedName, StrippedSTkName, "LINK_OVL");
	genBooleanMethod(">=", StrippedName, StrippedSTkName, "LINK_OVL");
}

void genSTkMatrixMethods()
{
	*out << endl;
	genOneArgMethod("matrix-copy", StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genOneArgMethod("matrix->list", StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genOneArgMethod("matrix-rows", StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genOneArgMethod("matrix-cols", StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genThreeArgMethod("matrix-ref", StrippedName, 
					"\"<integer>\"",
					"\"<integer>\"",
					StrippedSTkName, "LINK_OVL", 
						WRAP_ARG,DONT_WRAP_ARG,
						DONT_WRAP_ARG);
	genTwoArgMethod("matrix-fill!", StrippedName, StrippedObjName,
					StrippedSTkName, "LINK_OVL");
	genFourArgMethod("matrix-set!", StrippedName, "\"<integer>\"",
					"\"<integer>\"",
					StrippedObjName, StrippedSTkName, 
					"LINK_OVL",
						WRAP_ARG, DONT_WRAP_ARG,
						DONT_WRAP_ARG, WRAP_ARG);
	genTwoArgMethod("eqv?",StrippedName, StrippedName, 
					StrippedSTkName, "LINK_OVL");
}

void genSTkListMethods()
{
	*out << endl;
	{
	ostrstream oss, oss2;
   	oss << "list-" << STkObjName <<  ends;
   	oss2 << "list-" << STkObjName << "1" << ends;
	char *stk_meth = oss.str();
	char *stk_prim = oss2.str();
	genListMethod(stk_meth, stk_prim, "LINK_NEW",
						WRAP_ARG, INDEP_NAME);
	delete stk_meth;
	delete stk_prim;
	}
/*
	{
	ostrstream oss, oss2;
   	oss << "list-" << STkObjName << ends;
   	oss2 << "list->" << "list-" << STkObjName << ends;
	char *stk_meth = oss.str();
	char *stk_prim = oss2.str();
	genOneArgMethod(stk_meth, "\"<pair>\"", stk_prim, "LINK_NEW",
						DONT_WRAP_ARG, 
							INDEP_NAME);
	delete stk_prim;
	delete stk_meth;
	}
*/
	genOneArgMethod("null?", StrippedName, StrippedSTkName, "LINK_OVL");
	genOneArgMethod("length", StrippedName, StrippedSTkName, "LINK_OVL");
/*
	genTwoArgMethod("list-ref", StrippedName, 
					StrippedSTkName, "LINK_OVL",
					"\"<integer>\"", 
						WRAP_ARG, DONT_WRAP_ARG);
	genTwoArgMethod("list-tail", StrippedName, "\"<integer>\"", 
					StrippedSTkName, "LINK_OVL",
						WRAP_ARG, DONT_WRAP_ARG);
	genOneArgMethod("car", StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genOneArgMethod("cdr", StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genTwoArgMethod("cons", StrippedName, StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genTwoArgMethod("set-car!", StrippedName, StrippedObjName, 
					StrippedSTkName, "LINK_OVL");
	genTwoArgMethod("set-cdr!", StrippedName, StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genTwoArgMethod("memq", StrippedObjName, StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genTwoArgMethod("memv", StrippedObjName, StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genTwoArgMethod("member", StrippedObjName, StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genArbMethod("append",StrippedName, StrippedSTkName, "LINK_OVL");
*/
	genTwoArgMethod("eqv?",StrippedName, StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genBooleanMethod("<",  StrippedName, StrippedSTkName, "LINK_OVL");
	genBooleanMethod("<=", StrippedName, StrippedSTkName, "LINK_OVL");
	genBooleanMethod(">",  StrippedName, StrippedSTkName, "LINK_OVL");
	genBooleanMethod(">=", StrippedName, StrippedSTkName, "LINK_OVL");
}

void genSTkCollectionMethods(int gen_choose)
{
	*out << endl;
	{
	ostrstream oss, oss2;
   	oss << "mset-" << STkObjName <<  ends;
   	oss2 << "mset-" << STkObjName << "1" << ends;
	char *stk_meth = oss.str();
	char *stk_prim = oss2.str();
	genListMethod(stk_meth, stk_prim, "LINK_NEW",
						WRAP_ARG, INDEP_NAME);
	delete stk_meth;
	delete stk_prim;
	}
	{
	ostrstream oss, oss2;
   	oss << "set-" << STkObjName << ends;
   	oss2 << "set-" << STkObjName << "1" << ends;
	char *stk_meth = oss.str();
	char *stk_prim = oss2.str();
	genListMethod(stk_meth, stk_prim, "LINK_NEW",
						WRAP_ARG, INDEP_NAME);
	delete stk_prim;
	delete stk_meth;
	}
	{
	ostrstream oss, oss2;
   	oss << "sequence-" << STkObjName << ends;
   	oss2 << "sequence-" << STkObjName << "1" << ends;
	char *stk_meth = oss.str();
	char *stk_prim = oss2.str();
	genListMethod(stk_meth, stk_prim, "LINK_NEW",
						WRAP_ARG, INDEP_NAME);
	delete stk_prim;
	delete stk_meth;
	}
	//genOneArgMethod("sorted?", StrippedName, StrippedSTkName, "LINK_NEW");
	genOneArgMethod("null?", StrippedName, StrippedSTkName, "LINK_OVL");
	genOneArgMethod("size", StrippedName, StrippedSTkName, "LINK_NEW");
	genTwoArgMethod("eqv?",StrippedName, StrippedName, 
					StrippedSTkName, "LINK_OVL");
	genBooleanMethod("<",  StrippedName, StrippedSTkName, "LINK_OVL");
	genBooleanMethod("<=", StrippedName, StrippedSTkName, "LINK_OVL");
	genBooleanMethod(">",  StrippedName, StrippedSTkName, "LINK_OVL");
	genBooleanMethod(">=", StrippedName, StrippedSTkName, "LINK_OVL");
	genTwoArgMethod("member", StrippedObjName, StrippedName, 
					StrippedSTkName, "LINK_OVL");
	//genTwoArgMethod("occurrences", StrippedName, StrippedObjName, 
	//				StrippedSTkName, "LINK_NEW");
	//genTwoArgMethod("rank",         StrippedName, StrippedObjName, 
	//				StrippedSTkName, "LINK_NEW");
	genTwoArgMethod("ref", 		
					StrippedName,
					"\"<integer>\"", 
					StrippedSTkName, "LINK_NEW",
						WRAP_ARG, DONT_WRAP_ARG);
	genOneArgMethod("clear!", StrippedName, StrippedSTkName, "LINK_NEW");
	genTwoArgMethod("insert!", StrippedObjName, StrippedName, 
					StrippedSTkName, "LINK_NEW");
	genTwoArgMethod("append!", StrippedObjName, StrippedName, 
					StrippedSTkName, "LINK_NEW");
	genTwoArgMethod("remove!", StrippedObjName, StrippedName, 
					StrippedSTkName, "LINK_NEW");
	genArbMethod("+",StrippedName, StrippedSTkName, "LINK_OVL");
	genArbMethod("^",StrippedName, StrippedSTkName, "LINK_NEW");
	genArbMethod("-",StrippedName, StrippedSTkName, "LINK_OVL");
	//genBooleanMethod("subset", StrippedName, StrippedSTkName, "LINK_NEW");
	//genBooleanMethod("proper-subset", StrippedName, StrippedSTkName, 
	//				"LINK_NEW");
	if (gen_choose)
	{
		genTwoArgMethod("cartesian-product", 
					StrippedObjName, 
					StrippedObjName, 
					StrippedSTkName, "LINK_NEW");
		genTwoArgMethod("choose", StrippedObjName, "\"<integer>\"",
					StrippedSTkName, "LINK_NEW",
						WRAP_ARG, DONT_WRAP_ARG);
		genOneArgMethod("power-set", StrippedObjName, 
					StrippedSTkName, "LINK_NEW");
		genOneArgMethod("permutations", StrippedObjName, 
					StrippedSTkName, "LINK_NEW");
	}
}

void genSTkMatrixPrimitives()
{
   char *buffer;

   genPrimitive("MatrixWrapper", "make", "tc_subr_2", 
				StrippedSTkName, "makeLinkMatrix");
   genPrimitive("MatrixWrapper", "make2", "tc_subr_3", 
				StrippedSTkName, "makeFilledLinkMatrix");
   genPrimitive("MatrixWrapper", "matrix-ref", "tc_subr_3", 
				StrippedSTkName, "refLinkMatrix");
   {
   ostrstream oss;
   oss << StrippedSTkName << "?" << ends;
   buffer = oss.str();
   genPrimitive("MatrixWrapper",buffer, "tc_subr_1", "", "linkMatrixP");
   delete buffer;
   }
   {
   ostrstream oss;
   oss << "matrix-" << STkObjName  << ends;
   buffer = oss.str();
   genPrimitive("MatrixWrapper",buffer, "tc_subr_2", "", "makeLinkMatrix");
   delete buffer;
   }
   genPrimitive("MatrixWrapper", "matrix-fill!", "tc_subr_2", 
				StrippedSTkName, "fillLinkMatrix");
   genPrimitive("MatrixWrapper", "matrix-copy", "tc_subr_1", 
				StrippedSTkName, "copyLinkMatrix");
   genPrimitive("MatrixWrapper", "matrix-set!", "tc_lsubr", 
				StrippedSTkName, "setLinkMatrix");
   genPrimitive("MatrixWrapper", "matrix-rows", "tc_subr_1", 
				StrippedSTkName, "numRowsLinkMatrix");
   genPrimitive("MatrixWrapper", "matrix-cols", "tc_subr_1", 
				StrippedSTkName, "numColsLinkMatrix");
   genPrimitive("MatrixWrapper", "eqv?", "tc_subr_2", 
				StrippedSTkName, "eqvLinkMatrix");
   {
   ostrstream oss;
   oss << "list->" << StrippedSTkName << ends;
   buffer = oss.str();
   genPrimitive("MatrixWrapper",buffer, "tc_subr_1", "", "stkList2LinkMatrix");
   delete buffer;
   }
   {
   ostrstream oss;
   oss << StrippedSTkName << "->list" << ends;
   buffer = oss.str();
   genPrimitive("MatrixWrapper",buffer, "tc_subr_1", "", "linkMatrix2STkList");
   delete buffer;
   }
}

void genSTkArrayPrimitives()
{
   char *buffer;

   genPrimitive("ArrayWrapper", "make", "tc_subr_1", 
				StrippedSTkName, "makeLinkArray");
   genPrimitive("ArrayWrapper", "make2", "tc_subr_2", 
				StrippedSTkName, "makeFilledLinkArray");
   genPrimitive("ArrayWrapper", "vector-ref", "tc_subr_2", 
				StrippedSTkName, "refLinkArray");
   {
   ostrstream oss;
   oss << StrippedSTkName << "?" << ends;
   buffer = oss.str();
   genPrimitive("ArrayWrapper",buffer, "tc_subr_1", "", "linkArrayP");
   delete buffer;
   }
   /*
   genPrimitive("ArrayWrapper", StrippedSTkName, "tc_subr_1", 
				"", "buildLinkArray");
   */
   {
   ostrstream oss;
   oss << "vector-" << STkObjName  << ends;
   buffer = oss.str();
   genPrimitive("ArrayWrapper",buffer, "tc_subr_1", "", "buildLinkArray");
   delete buffer;
   }
   genPrimitive("ArrayWrapper", "vector-fill!", "tc_subr_2", 
				StrippedSTkName, "fillLinkArray");
   genPrimitive("ArrayWrapper", "vector-copy", "tc_subr_1", 
				StrippedSTkName, "copyLinkArray");
   genPrimitive("ArrayWrapper", "vector-set!", "tc_subr_3", 
				StrippedSTkName, "setLinkArray");
   genPrimitive("ArrayWrapper", "vector-length", "tc_subr_1", 
				StrippedSTkName, "lengthLinkArray");
   genPrimitive("ArrayWrapper", "eqv?", "tc_subr_2", 
				StrippedSTkName, "eqvLinkArray");
   genPrimitive("ArrayWrapper", "<", "tc_subr_2", 
				StrippedSTkName, "lthLinkArray");
   genPrimitive("ArrayWrapper", "<=", "tc_subr_2", 
				StrippedSTkName, "leLinkArray");
   genPrimitive("ArrayWrapper", ">", "tc_subr_2", 
				StrippedSTkName, "grLinkArray");
   genPrimitive("ArrayWrapper", ">=", "tc_subr_2", 
				StrippedSTkName, "geLinkArray");
   genPrimitive("ArrayWrapper", "vector-resize", "tc_subr_2", 
				StrippedSTkName, "resizeLinkArray");
   {
   ostrstream oss;
   oss << "list->" << StrippedSTkName << ends;
   buffer = oss.str();
   genPrimitive("ArrayWrapper",buffer, "tc_subr_1", "", "stkList2LinkArray");
   delete buffer;
   }
   {
   ostrstream oss;
   oss << StrippedSTkName << "->list" << ends;
   buffer = oss.str();
   genPrimitive("ArrayWrapper",buffer, "tc_subr_1", "", "linkArray2STkList");
   delete buffer;
   }
}

void genSTkListPrimitives()
{
   char *buffer;
   genPrimitive("ListWrapper", "make", "tc_subr_0", 
				StrippedSTkName,"makeLinkList");
   {
   ostrstream oss;
   oss << StrippedSTkName << "?" << ends;
   buffer = oss.str();
   genPrimitive("ListWrapper",buffer, "tc_subr_1", "", "linkListP");
   delete buffer;
   }
/*
   genPrimitive("ListWrapper","cons", "tc_subr_2", 
				StrippedSTkName, "consLinkList");
   genPrimitive("ListWrapper","set-car!","tc_subr_2",StrippedSTkName,
					"setCarLinkList");
   genPrimitive("ListWrapper","set-cdr!","tc_subr_2",StrippedSTkName,
							"setCdrLinkList");
   genPrimitive("ListWrapper","list-tail", "tc_subr_2", 
					StrippedSTkName, "tailLinkList");
   genPrimitive("ListWrapper","list-ref", "tc_subr_2", 
					StrippedSTkName, "refLinkList");
   genPrimitive("ListWrapper","car", "tc_subr_1", 
				StrippedSTkName, "carLinkList");
   genPrimitive("ListWrapper","cdr", "tc_subr_1", 
				StrippedSTkName, "cdrLinkList");
   genPrimitive("ListWrapper","null?", "tc_subr_1", StrippedSTkName, 
					"nullpLinkList");

   genPrimitive("ListWrapper",StrippedSTkName, "tc_subr_1","", "buildLinkList");
   {
   ostrstream oss;
   oss << "list-" << STkObjName << "1" << ends;
   buffer = oss.str();
   genPrimitive("ListWrapper",buffer, "tc_subr_1", "", "buildLinkList");
   delete buffer;
   }
   genPrimitive("ListWrapper","length", "tc_subr_1",StrippedSTkName,
					"lengthLinkList");

   genPrimitive("ListWrapper","append", "tc_lsubr", StrippedSTkName, 
					"appendLinkList");
   genPrimitive("ListWrapper","memq", "tc_subr_2", 
				StrippedSTkName, "memqLinkList");
   genPrimitive("ListWrapper","memv", "tc_subr_2", 
				StrippedSTkName, "memvLinkList");

   genPrimitive("ListWrapper","eqv?", "tc_subr_2", 
				StrippedSTkName, "eqvLinkList");
   genPrimitive("ListWrapper","<", "tc_subr_2", StrippedSTkName, "lthLinkList");
   genPrimitive("ListWrapper","<=", "tc_subr_2", StrippedSTkName, "leLinkList");
   genPrimitive("ListWrapper",">", "tc_subr_2", StrippedSTkName, "grLinkList");
   genPrimitive("ListWrapper",">=", "tc_subr_2", StrippedSTkName, "geLinkList");

   genPrimitive("ListWrapper","member", "tc_subr_2",StrippedSTkName,
					"memberLinkList");
*/
   {
   ostrstream oss;
   oss << "list->" << StrippedSTkName << ends;
   buffer = oss.str();
   genPrimitive("ListWrapper",buffer, "tc_subr_1", "", "stkList2LinkList");
   delete buffer;
   }
   {
   ostrstream oss;
   oss << StrippedSTkName << "->list" << ends;
   buffer = oss.str();
   genPrimitive("ListWrapper",buffer, "tc_subr_1", "", "linkList2STkList");
   delete buffer;
   }
}

void genSTkCollectionPrimitives(int gen_choose, char *base_obj_name)
{
   char *buffer;
   {
   ostrstream oss;
   oss << "collection-" << STkObjName << "?" << ends;
   buffer = oss.str();
   genPrimitive("CollectionWrapper",buffer, "tc_subr_1", "", "collectionP");
   delete buffer;
   }
   {
   ostrstream oss;
   oss << "mset-" << STkObjName << "1" << ends;
   buffer = oss.str();
   genPrimitive("CollectionWrapper",buffer, "tc_subr_1", "", "buildMSet");
   delete buffer;
   }
   {
   ostrstream oss;
   oss << "set-" << STkObjName << "1" << ends;
   buffer = oss.str();
   genPrimitive("CollectionWrapper",buffer, "tc_subr_1", "", "buildSet");
   delete buffer;
   }
   {
   ostrstream oss;
   oss << "sequence-" << STkObjName << "1" << ends;
   buffer = oss.str();
   genPrimitive("CollectionWrapper",buffer, "tc_subr_1", "", "buildSequence");
   delete buffer;
   }
   genPrimitive("CollectionWrapper","sorted?", "tc_subr_1", StrippedSTkName,
                                                "sortedLinkCollection");
   genPrimitive("CollectionWrapper","size", "tc_subr_1", StrippedSTkName, 
						"sizeLinkCollection");
   genPrimitive("CollectionWrapper","null?", "tc_subr_1", StrippedSTkName, 
						"nullLinkCollection");
   genPrimitive("CollectionWrapper", "eqv?", "tc_subr_2", StrippedSTkName,
						"eqvLinkCollection");
   genPrimitive("CollectionWrapper", "<", "tc_subr_2", StrippedSTkName,
						"lthLinkCollection");
   genPrimitive("CollectionWrapper", "<=", "tc_subr_2", StrippedSTkName,
						"leLinkCollection");
   genPrimitive("CollectionWrapper", ">", "tc_subr_2", StrippedSTkName,
						"grLinkCollection");
   genPrimitive("CollectionWrapper", ">=", "tc_subr_2", StrippedSTkName,
						"geLinkCollection");
   genPrimitive("CollectionWrapper", "member", "tc_subr_2", StrippedSTkName,
						"memberLinkCollection");
   genPrimitive("CollectionWrapper", "clear!", "tc_subr_1", StrippedSTkName,
						"clearLinkCollection");
   genPrimitive("CollectionWrapper", "insert!", "tc_subr_2", StrippedSTkName,
						"insertLinkCollection");
   genPrimitive("CollectionWrapper", "append!", "tc_subr_2", StrippedSTkName,
						"appendLinkCollection");
   genPrimitive("CollectionWrapper", "remove!", "tc_subr_2", StrippedSTkName,
						"removeLinkCollection");
   genPrimitive("CollectionWrapper", "occurrences", "tc_subr_2", 
				StrippedSTkName, "occurrencesLinkCollection");
   genPrimitive("CollectionWrapper", "ref", "tc_subr_2", 
				StrippedSTkName, "refLinkCollection");
   genPrimitive("CollectionWrapper", "rank", "tc_subr_2", 
				StrippedSTkName, "rankLinkCollection");
   genPrimitive("CollectionWrapper", "+", "tc_subr_1_or_2", StrippedSTkName,
						"unionLinkCollection");
   genPrimitive("CollectionWrapper", "^", "tc_subr_1_or_2", StrippedSTkName,
						"intersectionLinkCollection");
   genPrimitive("CollectionWrapper", "-", "tc_subr_1_or_2", StrippedSTkName,
						"differenceLinkCollection");
   genPrimitive("CollectionWrapper", "subset", "tc_subr_2", StrippedSTkName,
						"subsetLinkCollection");
   genPrimitive("CollectionWrapper", "proper-subset", "tc_subr_2",
				StrippedSTkName, "properSubsetLinkCollection");
   {
   ostrstream oss;
   oss << "list->mset-" << STkObjName << ends;
   buffer = oss.str();
   genPrimitive("CollectionWrapper",buffer, "tc_subr_1", "", 
					"stkList2LinkMSet");
   delete buffer;
   }
   {
   ostrstream oss;
   oss << "list->set-" << STkObjName << ends;
   buffer = oss.str();
   genPrimitive("CollectionWrapper",buffer, "tc_subr_1", "", "stkList2LinkSet");
   delete buffer;
   }
   {
   ostrstream oss;
   oss << "list->sequence-" << STkObjName << ends;
   buffer = oss.str();
   genPrimitive("CollectionWrapper",buffer, "tc_subr_1", "",
					"stkList2LinkSequence");
   delete buffer;
   }
   {
   ostrstream oss;
   oss << "mset-" << STkObjName << "->list" << ends;
   buffer = oss.str();
   genPrimitive("CollectionWrapper",buffer, "tc_subr_1", "", 
					"collection2STkList");
   delete buffer;
   }
   {
   ostrstream oss;
   oss << "set-" << STkObjName << "->list" << ends;
   buffer = oss.str();
   genPrimitive("CollectionWrapper",buffer, "tc_subr_1", "", 
					"collection2STkList");
   delete buffer;
   }
   {
   ostrstream oss;
   oss << "sequence-" << STkObjName << "->list" << ends;
   buffer = oss.str();
   genPrimitive("CollectionWrapper",buffer, "tc_subr_1", "", 
					"collection2STkList");
   delete buffer;
   }
   if (gen_choose) {
        genPrimitive("SetFuncsWrapper", "cartesian-product" , "tc_subr_2",
                                        StrippedSTkName, "cartesianProduct",
                                        base_obj_name);
   	genPrimitive("SetFuncsWrapper", "choose" , "tc_subr_2", 
					StrippedSTkName, "choose", 
					base_obj_name);
   	genPrimitive("SetFuncsWrapper", "power-set" , "tc_subr_1", 
					StrippedSTkName, "powerSet",
					base_obj_name);
   	genPrimitive("SetFuncsWrapper", "permutations" , "tc_subr_1", 
					StrippedSTkName, "permutations",
					base_obj_name);
   }
}

char *assignGCName(char *hname, char *gc_name)
{
	ostrstream oss;
	oss<<hname<<"Wrapper<"
			<< StrippedObjName << ">::"<< gc_name << "Typed" << hname << ends;
	return oss.str();
}

void genSTkInitRoutine( int is_ptr, char *holderName, 
			char *file_root,
			char *objName, 
			char *parentName,
			char *displayFctName,
			char *markFctName,
			char *sweepFctName,
			int gen_methods)
{
	*out << "PRIMITIVE STk_init_" << file_root << "()" << endl;
	*out << "{" << endl;
	*out << "\tWrapper<"
			<< StrippedName << ">::type = STk_new_CXXwrapper_id("
								 << endl;
	*out << "\t\t\tWrapper<" << StrippedName << ">::name, "<<endl;
	if (!parentName || (strcmp(parentName,"")==0))
		*out << "\t\t\t\"\"," << endl;
	else
		*out << "\t\t\tWrapper<" << parentName 
						<< " >::name," << endl;

	if (ParentHolderClassname) {
		displayFctName = assignGCName(ParentHolderClassname, "display");
		markFctName    = assignGCName(ParentHolderClassname, "mark");
		sweepFctName   = assignGCName(ParentHolderClassname, "free");
	}

	if (displayFctName)
		*out << "\t\t\t(void (*)(SCM x, SCM port, int mode))\n\t\t\t" 
						<< displayFctName<< "," << endl;
	else
		*out << "\t\t\t(void (*)(SCM x, SCM port, int mode))0,"<< endl;
	if (markFctName)
		*out << "\t\t\t(void (*)(SCM x))" << markFctName << "," << endl;
	else
		*out << "\t\t\t(void (*)(SCM x))0," << endl;
	if (sweepFctName)
		*out << "\t\t\t(void (*)(SCM x))" << sweepFctName <<");"<<endl;
	else
		*out << "\t\t\t(void (*)(SCM x))0);"<<endl;

	*out << "\tTcl_InitHashTable(&Register<"
				<< StrippedName << ">::objTable, ";
	*out << "TCL_ONE_WORD_KEYS);" << endl;
	if (is_ptr)
		wrapTypePredicate(StrippedSTkName, StrippedName);
	*out << "\treturn UNDEFINED;" << endl;
	*out << "}" << endl;
}

void genSTkInitMethods( int is_ptr, char *holderName, 
			char *file_root,
			char *base_obj_name, 
			char *objName, 
			char *parentName,
			char *displayFctName,
			char *markFctName,
			char *sweepFctName,
			int gen_choose,
			int gen_methods)
{
	*out << endl;
	ostrstream oss;
	if (file_root)
		oss << file_root << ends;
	else {
		oss << StrippedName << ends;
	}
	char *missing = oss.str();

	*out << "void genExtra" << missing << "Methods(void);" << endl;
	*out << endl;
	*out << "PRIMITIVE STk_init_methods_" << missing << "()" << endl;
	*out << "{" << endl;

	if (gen_methods && holderName) {
		if  (strcmp(holderName,"List")==0) {
			genSTkListPrimitives();
			//genSTkListMethods();
		} else if  (strcmp(holderName,"Collection")==0) {
			genSTkCollectionPrimitives(gen_choose, base_obj_name);
			genSTkCollectionMethods(gen_choose);
		} else if  (strcmp(holderName,"Array")==0) {
			genSTkArrayPrimitives();
			genSTkArrayMethods();
		} else if  (strcmp(holderName,"Matrix")==0) {
			genSTkMatrixPrimitives();
			genSTkMatrixMethods();
		}
	}
	*out << "\tgenExtra" << missing << "Methods";
	*out << "();" << endl;
	*out << "	return UNDEFINED;" << endl;
	*out << "}" << endl;
}

void genExtraMethodsShell(char *StrippedName, char *file_root)
{
	*out << endl;
	*out << "// define your new methods above " << endl;
	*out << "// and register them using STk_add_new_cpp_primitive() below" 
					<< endl;
	*out << endl;
	if (file_root)
 	  *out << "void genExtra" << file_root << "Methods() {}" << endl;
	else
 	  *out << "void genExtra" << StrippedName << "Methods() {}" << endl;
}

int genPreliminaries(int holder_ptr, char *base_obj_name, char *obj_name, 
		    char *parent_name, 
		    char *display_fct, char *mark_fct, char *sweep_fct,
		    int gen_choose, int gen_methods, char *obj_incls[], 
		    int obj_incl_count)
{
	genIncludes(obj_incls, obj_incl_count);
	genGCPrototypes(HolderClassname, display_fct, mark_fct, sweep_fct);
	int is_ptr = genTypedefs(holder_ptr, obj_name);
	genMacros(CompoundName);
	*out << ends;
	return is_ptr;
}

ostream *openFile(int file_type, char *file_root, char *dir_name)
{
	char *link_path;
	char *file_path;

	if ((link_path=getenv("LINK_BASE")) == 0) {
		cerr << "error: LINK_BASE environment variable must be set"
				<< endl;
		exit(2);
	}
	ostrstream oss;

	if (file_type == STK_INIT) {
		oss<<link_path<<"/src/"<<dir_name << "/autogenSTkMethods/";
		oss << file_root << "STkInit.cpp" << ends;
	} else {
		oss << link_path<<"/src/"<<dir_name << "/manualSTkMethods/";
		oss << dir_name << file_root << "Methods.cpp" << ends;
	}
	file_path = oss.str();

	if (file_type == USER_METHODS) {
		ifstream file_is_there(file_path, ios::in);
		if (file_is_there) {
			cerr << "warning: "<< file_path<< " exists. not written"
						 << endl;
			return 0;
		}
	}
	ostream *out = new ofstream(file_path, ios::out);
	if (!(*out)) {
		cerr << "error: cannot open "<< file_path <<" for output"<<endl;
		exit(1);
	}
	delete file_path;
	return out;
}

typedef char *charptr;
typedef ostream *ostreamptr;
typedef char *charptrarray[MAX_INCLUDES];

void processArgs(int argc, 
		 char *argv[],
                 charptr& HolderClassname,
                 charptr& ParentHolderClassname,
                 int &gen_choose,
                 int &gen_methods,
                 int &holder_ptr,
                 charptr& dir_name,
                 charptr& file_name,
                 charptr& base_obj_name,
                 charptr& obj_name,
		 charptr& parent_name,
                 int &object_incl_count,
                 charptrarray& object_includes,
		 charptr& display_fct,
		 charptr& mark_fct,
		 charptr& sweep_fct)
{
	char *s; 

	while(--argc > 0 && (*++argv)[0] == '-') {
	   for(s=argv[0]+1; *s != '\0'; s++)
		switch(*s) {
			case 'h' :  
                                if (*(s+1) == 'p') {
					holder_ptr = 1;
					s++;
				}
				--argc;
				HolderClassname = newString((++argv)[0]);
				ParentHolderClassname = 
					findParent(HolderClassname);
				break;
			case 'g' :  
				gen_methods = 1;
				break;
			case 'c' :  
				gen_choose = 1;
				--argc;
				base_obj_name = newString((++argv)[0]);
				break;
			case 'p' :  
				holder_ptr = 1;
				break;
			case 't' :  
				--argc;
				obj_name = newString((++argv)[0]);
				break;
			case 'd' :  
				--argc;
				dir_name = newString((++argv)[0]);
				break;
			case 'f' :  
				--argc;
				file_name = newString((++argv)[0]);
				break;
			case 'r' :  
				--argc;
				parent_name = newString((++argv)[0]);
				break;
			case 'I' :  
				--argc;
                                object_includes[object_incl_count++] =
                                               newString((++argv)[0]);

				break;
			case 'y' :  
				--argc;
				display_fct = newString((++argv)[0]);
				break;
			case 'm' :  
				--argc;
				mark_fct = newString((++argv)[0]);
				break;
			case 'w' :  
				--argc;
				sweep_fct = newString((++argv)[0]);
				break;
			default :
                                *out << "Illegal option: -" << *s << endl;
                                exit(1);
		}
	}
}

void usageMsg(int argc, char *obj_name)
{
	if ((argc <3) || !obj_name) {
	    cout << "usage: genMethods [-gp] -t <element type name> " 
								<< endl;
	    cout << "	    [-d <LINK src directory name>]" << endl;
	    cout << "	    [-f <file root>]" << endl;
	    cout << "	    [-g]" << endl;
	    cout << "	    [-c <base type name>]" << endl;
	    cout << "	    [-p]  " << endl;
	    cout << "	    [-r <parent type name>]  " << endl;
	    cout << "	    [-h <holder class name (e.g. List)>]  " << endl;
	    cout << "	    [-I <full include path of .h>]" << endl;
	    cout << "	    [-y <display fct name>]" << endl;
	    cout << "	    [-m <mark    fct name>]" << endl;
	    cout << "	    [-w <sweep   fct name>]" << endl;
	    cout << "ex: genMethods -g -t \"Vertex*\" -h SortedList "
		    "-r \"List<Vertex*>\" "
		    "-I \"LINK/graph/Vertex.h\" -I \"LINK/basic/List.h\""<<endl;
	    cout << endl;
	    cout << "ex: genMethods -g -t \"Vertex*\" -h List "
		    "-I \"LINK/graph/Vertex.h\" -I \"LINK/basic/List.h\""<<endl;
	    exit(1);
	}
}


void deleteDyn()
{
	if (CompoundName)    delete CompoundName;
	if (CompoundName2)   delete CompoundName2;	
	if (StrippedName)    delete StrippedName;
	if (StrippedSTkName) delete StrippedSTkName;
	if (StrippedObjName) delete StrippedObjName;
	if (STkObjName)      delete STkObjName;
	if (HolderClassname) delete HolderClassname;
	if (ParentHolderClassname) delete ParentHolderClassname;
}

main(int argc, char *argv[])
{
	char *s, *object_includes[MAX_INCLUDES];
	int holder_ptr=0, gen_choose=0, gen_methods=0, is_ptr;
	char *dir_name=0, *base_obj_name=0, *obj_name=0, *parent_name=0;
	char *file_name=0;
	char *display_fct=0, *mark_fct=0, *sweep_fct=0;
	int object_incl_count=0;
	char **save_argv = argv;
	int  save_argc = argc;
	
	dir_name=0;
	ostrstream preliminaries;
	out = &preliminaries;

	processArgs(argc, argv, HolderClassname, ParentHolderClassname,
                 gen_choose, gen_methods, holder_ptr, dir_name, file_name,
		 base_obj_name,
		 obj_name, parent_name, object_incl_count, object_includes,
		 display_fct, mark_fct, sweep_fct);
	usageMsg(argc, obj_name);
	genHeaderComment(save_argc, save_argv);
	genHeader();
	is_ptr = genPreliminaries( holder_ptr, base_obj_name, obj_name, 
			parent_name, display_fct, mark_fct, sweep_fct, 
			gen_choose, gen_methods, object_includes, 
			object_incl_count);

	char *preliminary_string = preliminaries.str();

	if (dir_name) {
		char *init_name=0;
		if (file_name) {
			out = openFile(STK_INIT, file_name, dir_name);
			init_name = file_name;
		} else {
			out = openFile(STK_INIT, StrippedName, dir_name);
			init_name = StrippedName;
		}
		*out << preliminary_string << endl;
		if (is_ptr)
			genTypePredicate(StrippedName);

		genSTkInitRoutine(is_ptr, HolderClassname, init_name,obj_name, 
				  parent_name, display_fct, mark_fct, 
				  sweep_fct, gen_methods);
		genSTkInitMethods(is_ptr, HolderClassname, init_name,
				  base_obj_name, obj_name, 
				  parent_name, display_fct, mark_fct, 
				  sweep_fct, gen_choose, gen_methods);
		genTrailer();
		((ofstream*)out)->close();

		if (file_name)
			out = openFile(USER_METHODS, file_name, dir_name);
		else
			out = openFile(USER_METHODS, StrippedName, dir_name);
		if (out) {
			*out << preliminary_string << endl;
			genExtraMethodsShell(StrippedName, init_name);
			genTrailer();
			//(*out).close();
		}
	} else {
		out = &cout;
		*out << preliminary_string << endl;
		genSTkInitRoutine(is_ptr, HolderClassname, StrippedName, 
				  obj_name, 
				  parent_name, display_fct, mark_fct, 
				  sweep_fct, gen_methods);
		genSTkInitMethods(is_ptr, HolderClassname, StrippedName,
				  base_obj_name, obj_name, 
				  parent_name, display_fct, mark_fct, 
				  sweep_fct, gen_choose, gen_methods);
		genTrailer();
	}
	deleteDyn();
}
