/*============================================================================
FILE  writ_ifs.c

MEMBER OF process cmpp

Copyright 1991
Georgia Tech Research Corporation
Atlanta, Georgia 30332
All Rights Reserved

PROJECT A-8503

AUTHORS

    9/12/91  Bill Kuhn

MODIFICATIONS

    <date> <person name> <nature of modifications>

SUMMARY

    This file contains functions used to write out the file "ifspec.c"
    based on information read from "ifspec.ifs", which is now held in
    structure 'ifs_table' passed to write_ifs_c_file().

INTERFACES

    write_ifs_c_file()

REFERENCED FILES

    None.

NON-STANDARD FEATURES

    None.

============================================================================*/


#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include  "cmpp.h"

/* Local function prototypes */

static void  write_comment(FILE *fp, Ifs_Table_t *ifs_table);

static void  write_includes(FILE *fp);

static void  write_mPTable(FILE *fp, Ifs_Table_t *ifs_table);

static void  write_pTable(FILE *fp, Ifs_Table_t *ifs_table);

static void  write_conn_info(FILE *fp, Ifs_Table_t *ifs_table);

static void  write_param_info(FILE *fp, Ifs_Table_t *ifs_table);

static void  write_inst_var_info(FILE *fp, Ifs_Table_t *ifs_table);

static void  write_SPICEdev(FILE *fp, Ifs_Table_t *ifs_table);



static char  *data_type_to_str(Data_Type_t type);

static char  *port_type_to_str(Port_Type_t port);

static char  *dir_to_str(Dir_t dir);

static char  *value_to_str(Data_Type_t type, Value_t value);

static char  *no_value_to_str(void);

static char  *boolean_to_str(Boolean_t value);

static char  *integer_to_str(int value);

static char  *gen_port_type_str(Port_Type_t port);



/* *********************************************************************** */



/*
write_ifs_c_file

Function write_ifs_c_file is a top-level driver function for
creating a C file (ifspec.c) that defines the model Interface
Specification in a form usable by the simulator.  The ifspec.c
output file is opened for writing, and then each of the following
functions is called in order to write the necessary statements
and data structures into the file:

     write_comment
     write_includes
     write_mPTable
     write_conn_info
     write_param_info
     write_inst_var_info
     write_SPICEdev

The output file is then closed.
*/



Status_t write_ifs_c_file(
    const char  *filename,    /* File to write to */
    Ifs_Table_t *ifs_table)   /* Table of Interface Specification data */
{
    FILE     *fp;                     /* File pointer */
    int      int_status;              /* returned status from fclose */


    /* Open the ifspec.c file for write access */

    fp = fopen_cmpp(&filename, "w");

    if(fp == NULL) {
        print_error("ERROR - Can't create file: %s", filename);
        return(ERROR);
    }


    /* Write out a comment section at the top of the file */
    write_comment(fp, ifs_table);

    /* Put in the # includes */
    write_includes(fp);

    /* Write the SPICE3 required XXXmPTable structure */
    write_mPTable(fp, ifs_table);

    /* Write the SPICE3 required XXXpTable structure */
    write_pTable(fp, ifs_table);

    /* Write out the connector table required for the code model element parser */
    write_conn_info(fp, ifs_table);

    /* Write out the parameter table required for the code model element parser */
    write_param_info(fp, ifs_table);

    /* Write out the instance variable table required for the code model element parser */
    write_inst_var_info(fp, ifs_table);

    /* Write out the externally visible structure for this model */
    write_SPICEdev(fp, ifs_table);


    /* Close the ifspec.c file and return */

    int_status = fclose(fp);

    if(int_status == 0)
        return(OK);
    else
        return(ERROR);
}



/* *********************************************************************** */


/*
write_comment

Function write_comment places a comment at the top of the
ifspec.c file warning the user that this file is automatically
generated and should not be edited.
*/


static void  write_comment(
    FILE        *fp,          /* File to write to */
    Ifs_Table_t *ifs_table)   /* Table of Interface Specification data */
{
    fprintf(fp, "\n");
    fprintf(fp, "/*\n");
    fprintf(fp, " * Structures for model: %s\n", ifs_table->name.model_name);
    fprintf(fp, " *\n");
    fprintf(fp, " * Automatically generated by cmpp preprocessor\n");
    fprintf(fp, " *\n");
    fprintf(fp, " * !!! DO NOT EDIT !!!\n");
    fprintf(fp, " *\n");
    fprintf(fp, " */\n");
    fprintf(fp, "\n");
}


/* *********************************************************************** */

/*
write_includes

Function write_includes writes the C header files required in
ifspec.c.
*/


static void  write_includes(
    FILE *fp)                /* File to write to */
{
    fprintf(fp, "\n");
	fprintf(fp, "#include \"ngspice/ngspice.h\"\n");
/*  fprintf(fp, "#include \"ngspice/prefix.h\"\n");*/
    fprintf(fp, "#include <stdio.h>\n");
    fprintf(fp, "#include \"ngspice/devdefs.h\"\n");
    fprintf(fp, "#include \"ngspice/ifsim.h\"\n");
    fprintf(fp, "#include \"ngspice/mifdefs.h\"\n");
    fprintf(fp, "#include \"ngspice/mifproto.h\"\n");
    fprintf(fp, "#include \"ngspice/mifparse.h\"\n");
/*  fprintf(fp, "#include \"ngspice/suffix.h\"\n");*/
    fprintf(fp, "\n");
}


/* *********************************************************************** */



/*
write_pTable

Function write_pTable writes the instance parameter information
using SPICE's IFparm structure type.  This table defines the
parameters as output only variables using SPICE's ``OP'' macro. 
These instance parameters are derived from the Interface
Specification file's STATIC_VAR table and define the parameters
that can be queried using the SPICE 3C1 .save feature.
*/


static void  write_pTable(
    FILE        *fp,         /* File to write to */
    Ifs_Table_t *ifs_table)  /* Table of Interface Specification data */
{

    int             i;
    char            str[80];
    Boolean_t       is_array;
    Data_Type_t     type;


    /* Only write the pTable if there is something to put in it.         */
    /* Otherwise, we will put NULL in the SPICEdev structure in its slot */

    if(ifs_table->num_inst_var == 0)
        return;


    /* Write the structure beginning */

    fprintf(fp, "\n");
    fprintf(fp, "static IFparm MIFpTable[] = {\n");


    /* Write out an entry for each instance variable in the table       */

    /* Use the index of the element in the instance variable info array */
    /* ADDED TO the number of parameters as the SPICE3 integer tag.  */

    for(i = 0; i < ifs_table->num_inst_var; i++) {

        /* Use the SPICE3 OP macro since instance vars are output-only */

        fprintf(fp, "    OP(");

        /* Put in the name of the parameter and the integer tag */

        fprintf(fp, "\"%s\", ", ifs_table->inst_var[i].name);
        fprintf(fp, "%d, ", i + ifs_table->num_param);

        /* Format SPICE3 type according to parameter type field */

        type = ifs_table->inst_var[i].type;
        is_array = ifs_table->inst_var[i].is_array;

        strcpy(str,"");

        if(is_array == TRUE) {
            strcat(str,"(");
        }

        if(type == BOOLEAN) {
            strcat(str,"IF_FLAG");   /* There is no BOOLEAN in SPICE3 */
        }
        else if(type == INTEGER) {
            strcat(str,"IF_INTEGER");
        }
        else if(type == REAL) {
            strcat(str,"IF_REAL");        
        }
        else if(type == COMPLEX) {
            strcat(str,"IF_COMPLEX");        
        }
        else if(type == STRING) {
            strcat(str,"IF_STRING");        
        }
        else if(type == POINTER) {
            strcat(str,"IF_STRING"); 
        }
        else {
            print_error("INTERNAL ERROR - write_pTable() - Impossible data type.");
        }

        if(is_array == TRUE) {
            strcat(str,"|IF_VECTOR)");
        }

        fprintf(fp, "%s, ", str);

        /* Put in the description string and finish this line off */

        fprintf(fp, "\"%s\"", ifs_table->inst_var[i].description);
        fprintf(fp, "),\n");

    }

    /* Finish off the structure */

    fprintf(fp, "};\n");
    fprintf(fp, "\n");
}


/* *********************************************************************** */


/*
write_mPTable

Function write_mPTable writes the model parameter information
using SPICE's IFparm structure type.  This table defines the
parameters to be input/output variables using SPICE's ``IOP'' macro
so that these variables can be set or queried from SPICE.  These
model parameters are derived from the Interface Specification's
PARAMETER table.
*/

static void  write_mPTable(
    FILE        *fp,         /* File to write to */
    Ifs_Table_t *ifs_table)  /* Table of Interface Specification data */
{

    int             i;
    char            str[80];
    Boolean_t       is_array;
    Data_Type_t     type;


    /* Only write the mPTable if there is something to put in it.         */
    /* Otherwise, we will put NULL in the SPICEdev structure in its slot */

    if(ifs_table->num_param == 0)
        return;


    /* Write the structure beginning */

    fprintf(fp, "\n");
    fprintf(fp, "static IFparm MIFmPTable[] = {\n");


    /* Write out an entry for each parameter in the table               */

    /* Use the index of the element in the parameter info array */
    /* as the SPICE3 integer tag.                                       */

    for(i = 0; i < ifs_table->num_param; i++) {

        /* Use the SPICE3 IOP macro since model parameters are input/output */

        fprintf(fp, "    IOP(");

        /* Put in the name of the parameter and the integer tag */

        fprintf(fp, "\"%s\", ", ifs_table->param[i].name);
        fprintf(fp, "%d, ", i);

        /* Format SPICE3 type according to parameter type field */

        type = ifs_table->param[i].type;
        is_array = ifs_table->param[i].is_array;

        strcpy(str,"");

        if(is_array == TRUE) {
            strcat(str,"(");
        }

        if(type == BOOLEAN) {
            strcat(str,"IF_FLAG");   /* There is no BOOLEAN in SPICE3 */
        }
        else if(type == INTEGER) {
            strcat(str,"IF_INTEGER");
        }
        else if(type == REAL) {
            strcat(str,"IF_REAL");        
        }
        else if(type == COMPLEX) {
            strcat(str,"IF_COMPLEX");        
        }
        else if(type == STRING) {
            strcat(str,"IF_STRING");        
        }
        else {
            print_error("INTERNAL ERROR - write_mPTable() - Impossible data type.");
        }

        if(is_array == TRUE) {
            strcat(str,"|IF_VECTOR)");
        }

        fprintf(fp, "%s, ", str);

        /* Put in the description string and finish this line off */

        fprintf(fp, "\"%s\"", ifs_table->param[i].description);
        fprintf(fp, "),\n");

    }

    /* Finish off the structure */

    fprintf(fp, "};\n");
    fprintf(fp, "\n");

}


/* *********************************************************************** */


/*
write_conn_info

Function write_conn_info writes information used by the
Simulator's new MIF package to interpret and error check a
model's connection list in a SPICE deck.  This information is
derived from the Interface Specification file's PORT table.
*/



static void  write_conn_info(
    FILE        *fp,          /* File to write to */
    Ifs_Table_t *ifs_table)   /* Table of Interface Specification data */
{

    int             i;
    int             j;
    char            *str;

    /* Only write the connTable if there is something to put in it.      */
    /* Otherwise, we will put NULL in the SPICEdev structure in its slot */

    if(ifs_table->num_conn == 0)  /* An unlikely condition for sure ... */
        return;

    /* First, we must define arrays of port types */

    /* Note that there should be always at least one allowed port type */
    /* so we don't have to worry about arrays with no elements         */

    for(i = 0; i < ifs_table->num_conn; i++) {

        fprintf(fp, "\n");
        fprintf(fp, "static Mif_Port_Type_t MIFportEnum%d[] = {\n", i);

        if(ifs_table->conn[i].num_allowed_types < 1)
            print_error("ERROR - write_conn_info() - Number of allowed types cannot be zero");

        for(j = 0; j < ifs_table->conn[i].num_allowed_types; j++) {

            str = port_type_to_str(ifs_table->conn[i].allowed_port_type[j]);
            fprintf(fp, "\t%s,\n", str);

        }  /* for number of allowed types */

        fprintf(fp, "};\n");
        fprintf(fp, "\n");


        fprintf(fp, "\n");
        fprintf(fp, "static char *MIFportStr%d[] = {\n", i);

        for(j = 0; j < ifs_table->conn[i].num_allowed_types; j++) {
            if(ifs_table->conn[i].allowed_port_type[j] == USER_DEFINED)
                fprintf(fp, "\t\"%s\",\n", ifs_table->conn[i].allowed_type[j]);
            else {
                str = gen_port_type_str(ifs_table->conn[i].allowed_port_type[j]);
                fprintf(fp, "\t\"%s\",\n", str);
            }
        }  /* for number of allowed types */

        fprintf(fp, "};\n");
        fprintf(fp, "\n");

    }  /* for number of connections */



    /* Now write the structure */

    fprintf(fp, "\n");
    fprintf(fp, "static Mif_Conn_Info_t MIFconnTable[] = {\n");


    /* Write out an entry for each parameter in the table               */

    for(i = 0; i < ifs_table->num_conn; i++) {

        fprintf(fp, "  {\n");
        fprintf(fp, "    \"%s\",\n",ifs_table->conn[i].name);
        fprintf(fp, "    \"%s\",\n",ifs_table->conn[i].description);

        str = dir_to_str(ifs_table->conn[i].direction);
        fprintf(fp, "    %s,\n", str);

        str = port_type_to_str(ifs_table->conn[i].default_port_type);
        fprintf(fp, "    %s,\n", str);

        fprintf(fp, "    \"%s\",\n",
		(ifs_table->conn[i].default_port_type == USER_DEFINED)
		? ifs_table->conn[i].default_type
		: gen_port_type_str (ifs_table->conn[i].default_port_type));

        fprintf(fp,"    %d,\n",ifs_table->conn[i].num_allowed_types);
	
        fprintf(fp, "    MIFportEnum%d,\n", i);
        fprintf(fp, "    MIFportStr%d,\n", i);


        str = boolean_to_str(ifs_table->conn[i].is_array);
        fprintf(fp, "    %s,\n", str);

        if(ifs_table->conn[i].is_array == FALSE) {

            str = boolean_to_str(FALSE);    /* has_lower_bound */
            fprintf(fp, "    %s,\n", str);

            str = integer_to_str(0);        /* lower_bound */
            fprintf(fp, "    %s,\n", str);

            str = boolean_to_str(FALSE);    /* has_upper_bound */
            fprintf(fp, "    %s,\n", str);

            str = integer_to_str(0);        /* upper_bound */
            fprintf(fp, "    %s,\n", str);
        }
        else {  /* is_array == TRUE */

            str = boolean_to_str(ifs_table->conn[i].has_lower_bound);
            fprintf(fp, "    %s,\n", str);

            if(ifs_table->conn[i].has_lower_bound == TRUE)
                str = integer_to_str(ifs_table->conn[i].lower_bound);
            else
                str = integer_to_str(0);
            fprintf(fp, "    %s,\n", str);

            str = boolean_to_str(ifs_table->conn[i].has_upper_bound);
            fprintf(fp, "    %s,\n", str);

            if(ifs_table->conn[i].has_upper_bound == TRUE)
                str = integer_to_str(ifs_table->conn[i].upper_bound);
            else
                str = integer_to_str(0);
            fprintf(fp, "    %s,\n", str);

        }  /* if is_array */
    
        str = boolean_to_str(ifs_table->conn[i].null_allowed);
        fprintf(fp, "    %s,\n", str);

        fprintf(fp, "  },\n");

    } /* for number of parameters */


    /* Finish off the structure */

    fprintf(fp, "};\n");
    fprintf(fp, "\n");
}


/* *********************************************************************** */


/*
write_param_info

Function write_param_info writes information used by the
Simulator's new MIF package to interpret and error check a
model's parameter list in an XSPICE deck.  This information is
derived from the Interface Specification file's PARAMETER table. 
It is essentially a superset of the IFparm information written by
write_mPTable().  The IFparm information written by
write_mPTable() is required to work with SPICE's device set and
query functions.  The information written by write_param_info is
more extensive and is required to parse and error check the XSPICE
input deck.
*/



static void  write_param_info(
    FILE        *fp,           /* File to write to */
    Ifs_Table_t *ifs_table)    /* Table of Interface Specification data */
{

    int             i;
    char            *str;


    /* Only write the paramTable if there is something to put in it.      */
    /* Otherwise, we will put NULL in the SPICEdev structure in its slot */

    if(ifs_table->num_param == 0)
        return;


    /* Write the structure beginning */

    fprintf(fp, "\n");
    fprintf(fp, "static Mif_Param_Info_t MIFparamTable[] = {\n");


    /* Write out an entry for each parameter in the table               */

    for(i = 0; i < ifs_table->num_param; i++) {

        fprintf(fp, "  {\n");
        fprintf(fp, "    \"%s\",\n",ifs_table->param[i].name);
        fprintf(fp, "    \"%s\",\n",ifs_table->param[i].description);

        str = data_type_to_str(ifs_table->param[i].type);
        fprintf(fp, "    %s,\n", str);

        str = boolean_to_str(ifs_table->param[i].has_default);
        fprintf(fp, "    %s,\n", str);

        if(ifs_table->param[i].has_default == TRUE)
            str = value_to_str(ifs_table->param[i].type, ifs_table->param[i].default_value);
        else
            str = no_value_to_str();
        fprintf(fp, "    %s,\n", str);

        str = boolean_to_str(ifs_table->param[i].has_lower_limit);
        fprintf(fp, "    %s,\n", str);

        if(ifs_table->param[i].has_lower_limit == TRUE)
            str = value_to_str(ifs_table->param[i].type, ifs_table->param[i].lower_limit);
        else
            str = no_value_to_str();
        fprintf(fp, "    %s,\n", str);

        str = boolean_to_str(ifs_table->param[i].has_upper_limit);
        fprintf(fp, "    %s,\n", str);

        if(ifs_table->param[i].has_upper_limit == TRUE)
            str = value_to_str(ifs_table->param[i].type, ifs_table->param[i].upper_limit);
        else
            str = no_value_to_str();
        fprintf(fp, "    %s,\n", str);

        str = boolean_to_str(ifs_table->param[i].is_array);
        fprintf(fp, "    %s,\n", str);

        if(ifs_table->param[i].is_array == FALSE) {

            str = boolean_to_str(FALSE);    /* has_conn_ref */
            fprintf(fp, "    %s,\n", str);

            str = integer_to_str(0);        /* conn_ref */
            fprintf(fp, "    %s,\n", str);

            str = boolean_to_str(FALSE);    /* has_lower_bound */
            fprintf(fp, "    %s,\n", str);

            str = integer_to_str(0);        /* lower_bound */
            fprintf(fp, "    %s,\n", str);

            str = boolean_to_str(FALSE);    /* has_upper_bound */
            fprintf(fp, "    %s,\n", str);

            str = integer_to_str(0);        /* upper_bound */
            fprintf(fp, "    %s,\n", str);
        }
        else {  /* is_array == TRUE */

            str = boolean_to_str(ifs_table->param[i].has_conn_ref);
            fprintf(fp, "    %s,\n", str);

            if(ifs_table->param[i].has_conn_ref == TRUE) {

                str = integer_to_str(ifs_table->param[i].conn_ref);
                fprintf(fp, "    %s,\n", str);

                str = boolean_to_str(FALSE);    /* has_lower_bound */
                fprintf(fp, "    %s,\n", str);

                str = integer_to_str(0);        /* lower_bound */
                fprintf(fp, "    %s,\n", str);

                str = boolean_to_str(FALSE);    /* has_upper_bound */
                fprintf(fp, "    %s,\n", str);

                str = integer_to_str(0);        /* upper_bound */
                fprintf(fp, "    %s,\n", str);
            }
            else {  /* has_conn_ref == FALSE */

                str = integer_to_str(0);        /* conn_ref */
                fprintf(fp, "    %s,\n", str);

                str = boolean_to_str(ifs_table->param[i].has_lower_bound);
                fprintf(fp, "    %s,\n", str);

                if(ifs_table->param[i].has_lower_bound == TRUE)
                    str = integer_to_str(ifs_table->param[i].lower_bound);
                else
                    str = integer_to_str(0);
                fprintf(fp, "    %s,\n", str);

                str = boolean_to_str(ifs_table->param[i].has_upper_bound);
                fprintf(fp, "    %s,\n", str);

                if(ifs_table->param[i].has_upper_bound == TRUE)
                    str = integer_to_str(ifs_table->param[i].upper_bound);
                else
                    str = integer_to_str(0);
                fprintf(fp, "    %s,\n", str);

            }  /* if has_conn_ref */

        }  /* if is_array */
    
        str = boolean_to_str(ifs_table->param[i].null_allowed);
        fprintf(fp, "    %s,\n", str);

        fprintf(fp, "  },\n");

    } /* for number of parameters */


    /* Finish off the structure */

    fprintf(fp, "};\n");
    fprintf(fp, "\n");

}



/* *********************************************************************** */


/*
write_inst_var_info

Function write_inst_var_info writes information used by the
Simulator's new MIF package to allocate space for and to output
(using SPICE's .save feature) variables defined in the Interface
Specification file's STATIC_VAR table.  It is essentially a
superset of the IFparm information written by write_mPTable(). 
The IFparm information written by write_pTable() is required to
work with SPICE's device query functions.  The information
written by write_inst_var_info is more extensive.
*/



static void  write_inst_var_info(
    FILE        *fp,         /* File to write to */
    Ifs_Table_t *ifs_table)  /* Table of Interface Specification data */
{

    int             i;
    char            *str;

    /* Only write the inst_varTable if there is something to put in it.  */
    /* Otherwise, we will put NULL in the SPICEdev structure in its slot */

    if(ifs_table->num_inst_var == 0)
        return;


    /* Write the structure beginning */

    fprintf(fp, "\n");
    fprintf(fp, "static Mif_Inst_Var_Info_t MIFinst_varTable[] = {\n");


    /* Write out an entry for each parameter in the table               */

    for(i = 0; i < ifs_table->num_inst_var; i++) {

        fprintf(fp, "  {\n");
        fprintf(fp, "    \"%s\",\n",ifs_table->inst_var[i].name);
        fprintf(fp, "    \"%s\",\n",ifs_table->inst_var[i].description);

        str = data_type_to_str(ifs_table->inst_var[i].type);
        fprintf(fp, "    %s,\n", str);

        str = boolean_to_str(ifs_table->inst_var[i].is_array);
        fprintf(fp, "    %s,\n", str);

        fprintf(fp, "  },\n");

    } /* for number of parameters */


    /* Finish off the structure */

    fprintf(fp, "};\n");
    fprintf(fp, "\n");

}




/* *********************************************************************** */


/*
write_SPICEdev

Function write_SPICEdev writes the global XXX_info structure used
by SPICE to define a model.  Here ``XXX'' is the name of the code
model.  This structure contains the name of the
model, a pointer to the C function that implements the model, and
pointers to all of the above data structures.
*/



static void  write_SPICEdev(
    FILE        *fp,         /* File to write to */
    Ifs_Table_t *ifs_table)  /* Table of Interface Specification data */
{
	
    /* Extern the code model function name */
    fprintf(fp, "\n");
    fprintf(fp, "extern void %s(Mif_Private_t *);\n",
                 ifs_table->name.c_fcn_name);

	/* SPICE now needs these static integers */
	fprintf(fp, "\n");
	fprintf(fp, "static int val_terms             = 0;\n");
	fprintf(fp, "static int val_numNames          = 0;\n");
	fprintf(fp, "static int val_numInstanceParms  = %d;\n",ifs_table->num_inst_var);
	fprintf(fp, "static int val_numModelParms     = %d;\n",ifs_table->num_param);
	fprintf(fp, "static int val_sizeofMIFinstance = sizeof(MIFinstance);\n");
	fprintf(fp, "static int val_sizeofMIFmodel    = sizeof(MIFmodel);\n");

    /* Write out the structure beginning */

    /* Use the c function external identifier appended with _info as the */
    /* external identifier for the structure.                            */

    fprintf(fp, "\n");
    fprintf(fp, "SPICEdev %s_info = {\n", ifs_table->name.c_fcn_name);

    /* Write the IFdevice structure */

    fprintf(fp, "    .DEVpublic = {\n");
    fprintf(fp, "        .name = \"%s\",\n", ifs_table->name.model_name);
    fprintf(fp, "        .description = \"%s\",\n", ifs_table->name.description);
    fprintf(fp, "        .terms = &val_terms,\n");
    fprintf(fp, "        .numNames = &val_numNames,\n");
    fprintf(fp, "        .termNames = NULL,\n");

    fprintf(fp, "        .numInstanceParms = &val_numInstanceParms,\n");
    if(ifs_table->num_inst_var > 0)
        fprintf(fp, "        .instanceParms = MIFpTable,\n");
    else
        fprintf(fp, "        .instanceParms = NULL,\n");

    fprintf(fp, "        .numModelParms = &val_numModelParms,\n");
    if(ifs_table->num_param > 0)
        fprintf(fp, "        .modelParms = MIFmPTable,\n");
    else
        fprintf(fp, "        .modelParms = NULL,\n");
    fprintf(fp, "        .flags = 0,\n\n");

    fprintf(fp, "        .cm_func = %s,\n", ifs_table->name.c_fcn_name);

    fprintf(fp, "        .num_conn = %d,\n", ifs_table->num_conn);
    if(ifs_table->num_conn > 0)
        fprintf(fp, "        .conn = MIFconnTable,\n");
    else
        fprintf(fp, "        .conn = NULL,\n");

    fprintf(fp, "        .num_param = %d,\n", ifs_table->num_param);
    if(ifs_table->num_param > 0)
        fprintf(fp, "        .param = MIFparamTable,\n");
    else
        fprintf(fp, "        .param = NULL,\n");

    fprintf(fp, "        .num_inst_var = %d,\n", ifs_table->num_inst_var);
    if(ifs_table->num_inst_var > 0)
        fprintf(fp, "        .inst_var = MIFinst_varTable,\n");
    else
        fprintf(fp, "        .inst_var = NULL,\n");

    fprintf(fp, "    },\n\n");

    /* Write the names of the generic code model functions */

    fprintf(fp, "    .DEVparam = NULL,\n");
    fprintf(fp, "    .DEVmodParam = MIFmParam,\n");
    fprintf(fp, "    .DEVload = MIFload,\n");
    fprintf(fp, "    .DEVsetup = MIFsetup,\n");
    fprintf(fp, "    .DEVunsetup = MIFunsetup,\n");
    fprintf(fp, "    .DEVpzSetup = NULL,\n");
    fprintf(fp, "    .DEVtemperature = NULL,\n");
    fprintf(fp, "    .DEVtrunc = MIFtrunc,\n");
    fprintf(fp, "    .DEVfindBranch = NULL,\n");
    fprintf(fp, "    .DEVacLoad = MIFload,\n");
    fprintf(fp, "    .DEVaccept = NULL,\n");
    fprintf(fp, "    .DEVdestroy = MIFdestroy,\n");
    fprintf(fp, "    .DEVmodDelete = MIFmDelete,\n");
    fprintf(fp, "    .DEVdelete = MIFdelete,\n");
    fprintf(fp, "    .DEVsetic = NULL,\n");
    fprintf(fp, "    .DEVask = MIFask,\n");
    fprintf(fp, "    .DEVmodAsk = MIFmAsk,\n");
    fprintf(fp, "    .DEVpzLoad = NULL,\n");
    fprintf(fp, "    .DEVconvTest = MIFconvTest,\n");
    fprintf(fp, "    .DEVsenSetup = NULL,\n");
    fprintf(fp, "    .DEVsenLoad = NULL,\n");
    fprintf(fp, "    .DEVsenUpdate = NULL,\n");
    fprintf(fp, "    .DEVsenAcLoad = NULL,\n");
    fprintf(fp, "    .DEVsenPrint = NULL,\n");
    fprintf(fp, "    .DEVsenTrunc = NULL,\n");
    fprintf(fp, "    .DEVdisto = NULL,\n");
    fprintf(fp, "    .DEVnoise = NULL,\n");
    fprintf(fp, "    .DEVsoaCheck = NULL,\n");
    fprintf(fp, "    .DEVinstSize = &val_sizeofMIFinstance,\n");
    fprintf(fp, "    .DEVmodSize = &val_sizeofMIFmodel,\n");
    fprintf(fp, "\n");
    fprintf(fp, "#ifdef CIDER\n");
    fprintf(fp, "    .DEVdump = NULL,\n");
    fprintf(fp, "    .DEVacct = NULL,\n");
    fprintf(fp, "#endif\n");
    fprintf(fp, "};\n");
    fprintf(fp, "\n");
}




/* *********************************************************************** */


/*
The following functions are utility routines used to convert internal
enums and data to ASCII form for placing into the .c file
being created.
*/


#define BASE_STR_LEN  80


static char  *data_type_to_str(Data_Type_t type)
{
    static char *str = NULL;

    if(str == NULL)
        str = (char *) malloc(BASE_STR_LEN+1);

    switch(type) {

        case BOOLEAN:
            strcpy(str,"MIF_BOOLEAN");
            break;

        case INTEGER:
            strcpy(str,"MIF_INTEGER");
            break;

        case REAL:
            strcpy(str,"MIF_REAL");
            break;

        case COMPLEX:
            strcpy(str,"MIF_COMPLEX");
            break;

        case STRING:
            strcpy(str,"MIF_STRING");
            break;

	case POINTER:
            strcpy(str,"MIF_STRING");
            break;

        default:
            print_error("INTERNAL ERROR - data_type_to_str() - Impossible data type.");
    }

    return(str);
}


/* *********************************************************************** */

static char  *port_type_to_str(Port_Type_t port)
{
    static char *str = NULL;

    if(str == NULL)
        str = (char *) malloc(BASE_STR_LEN+1);

    switch(port) {

        case VOLTAGE:
            strcpy(str,"MIF_VOLTAGE");
            break;

        case DIFF_VOLTAGE:
            strcpy(str,"MIF_DIFF_VOLTAGE");
            break;

        case CURRENT:
            strcpy(str,"MIF_CURRENT");
            break;

        case DIFF_CURRENT:
            strcpy(str,"MIF_DIFF_CURRENT");
            break;

        case VSOURCE_CURRENT:
            strcpy(str,"MIF_VSOURCE_CURRENT");
            break;

        case CONDUCTANCE:
            strcpy(str,"MIF_CONDUCTANCE");
            break;

        case DIFF_CONDUCTANCE:
            strcpy(str,"MIF_DIFF_CONDUCTANCE");
            break;

        case RESISTANCE:
            strcpy(str,"MIF_RESISTANCE");
            break;

        case DIFF_RESISTANCE:
            strcpy(str,"MIF_DIFF_RESISTANCE");
            break;

        case DIGITAL:
            strcpy(str,"MIF_DIGITAL");
            break;

        case USER_DEFINED:
            strcpy(str,"MIF_USER_DEFINED");
            break;

        default:
            print_error("INTERNAL ERROR - port_type_to_str() - Impossible port type.");
    }

    return(str);

}

/* *********************************************************************** */

static char  *gen_port_type_str(Port_Type_t port)
{
    static char *str = NULL;

    if(str == NULL)
        str = (char *) malloc(BASE_STR_LEN+1);

    switch(port) {

        case VOLTAGE:
            strcpy(str,"v");
            break;

        case DIFF_VOLTAGE:
            strcpy(str,"vd");
            break;

        case CURRENT:
            strcpy(str,"i");
            break;

        case DIFF_CURRENT:
            strcpy(str,"id");
            break;

        case VSOURCE_CURRENT:
            strcpy(str,"vnam");
            break;

        case CONDUCTANCE:
            strcpy(str,"g");
            break;

        case DIFF_CONDUCTANCE:
            strcpy(str,"gd");
            break;

        case RESISTANCE:
            strcpy(str,"h");
            break;

        case DIFF_RESISTANCE:
            strcpy(str,"hd");
            break;

        case DIGITAL:
            strcpy(str,"d");
            break;

        case USER_DEFINED:
            strcpy(str,"");
            break;

        default:
            print_error("INTERNAL ERROR - gen_port_type_str() - Impossible port type.");
    }

    return(str);

}


/* *********************************************************************** */

static char  *dir_to_str(Dir_t dir)
{
    static char *str = NULL;

    if(str == NULL)
        str = (char *) malloc(BASE_STR_LEN+1);

    switch(dir) {

        case IN:
            strcpy(str,"MIF_IN");
            break;

        case OUT:
            strcpy(str,"MIF_OUT");
            break;

        case INOUT:
            strcpy(str,"MIF_INOUT");
            break;

        default:
            print_error("INTERNAL ERROR - dir_to_str() - Impossible direction type.");
    }

    return(str);
}



/* *********************************************************************** */

static char  *value_to_str(Data_Type_t type, Value_t value)
{
    static char *str = NULL;
    static int  max_len = 0;

    char *bool_str;
    int  str_len;


    if(str == NULL) {
        str = (char *) malloc(2 * BASE_STR_LEN + 1);
        max_len = 2 * BASE_STR_LEN;
    }

    switch(type) {

        case BOOLEAN:
            bool_str = boolean_to_str(value.bvalue);
            sprintf(str, "{%s, 0, 0.0, {0.0, 0.0}, NULL}", bool_str);
            break;

        case INTEGER:
            sprintf(str, "{MIF_FALSE, %d, 0.0, {0.0, 0.0}, NULL}", value.ivalue);
            break;

        case REAL:
            sprintf(str, "{MIF_FALSE, 0, %e, {0.0, 0.0}, NULL}", value.rvalue);
            break;

        case COMPLEX:
            sprintf(str, "{MIF_FALSE, 0, 0.0, {%e, %e}, NULL}",
                                      value.cvalue.real, value.cvalue.imag);
            break;

        case STRING:
            /* be careful, the string could conceivably be very long... */
            str_len = (int) strlen(value.svalue);
            if((str_len + BASE_STR_LEN) > max_len) {
                str = (char *) realloc(str, (size_t) (max_len + str_len + 1));
                max_len += str_len;
            }
            sprintf(str, "{MIF_FALSE, 0, 0.0, {0.0, 0.0}, \"%s\"}", value.svalue);
            break;

        default:
            print_error("INTERNAL ERROR - value_to_str() - Impossible data type.");

    }

    return(str);
}


/* *********************************************************************** */

static char  *boolean_to_str(Boolean_t value)
{
    static char *str = NULL;

    if(str == NULL)
        str = (char *) malloc(BASE_STR_LEN+1);

    switch(value) {

        case TRUE:
            strcpy(str,"MIF_TRUE");
            break;

        case FALSE:
            strcpy(str,"MIF_FALSE");
            break;

        default:
            print_error("INTERNAL ERROR - boolean_to_str() - Impossible boolean value.");

    }

    return(str);
}


/* *********************************************************************** */

static char  *integer_to_str(int value)
{
    static char *str = NULL;

    if(str == NULL) {
        str = (char *) malloc(BASE_STR_LEN + 1);
    }

    sprintf(str, "%d", value);

    return(str);
}


/* *********************************************************************** */

static char  *no_value_to_str(void)
{
    static char *str = NULL;

    if(str == NULL) {
        str = (char *) malloc(BASE_STR_LEN + 1);
    }

    sprintf(str, "{MIF_FALSE, 0, 0.0, {0.0, 0.0}, NULL}");

    return(str);
}



