/*******************************************************************************
 * Simplified Wrapper and Interface Generator  (SWIG)
 * 
 * Author : David Beazley
 *
 * Department of Computer Science        
 * University of Chicago
 * 1100 E 58th Street
 * Chicago, IL  60637
 * beazley@cs.uchicago.edu
 *
 * Please read the file LICENSE for the copyright and terms by which SWIG
 * can be used and distributed.
 *******************************************************************************/

/***********************************************************************
 * $Header: /pack/cvsroots/wxwindows/wxWindows/wxPython/wxSWIG/Modules/guile.cxx,v 1.1 2002/04/29 19:56:47 RD Exp $
 *
 * guile.cxx
 *
 * Definitions for adding functions to Guile 3.0
 ***********************************************************************/

#include "swig.h"
#include "guile.h"

static char *guile_usage = "\
Guile Options (available with -guile)\n\
     None available. \n\n";     

// ---------------------------------------------------------------------
// GUILE::parse_args(int argc, char *argv[])
//
// Parse arguments.
// ---------------------------------------------------------------------

void GUILE::parse_args(int argc, char *argv[]) {

  int i;
  
  sprintf(LibDir,"%s",guile_path);

  // Look for certain command line options

  // Look for additional command line options.
  for (i = 1; i < argc; i++) {  
      if (argv[i]) {
          if (strcmp(argv[i],"-help") == 0) {
            fputs(guile_usage,stderr);
            SWIG_exit(0);
          }
      }
  }
  // Add a symbol for this module

  add_symbol("SWIGGUILE",0,0);

  // Set name of typemaps

  typemap_lang = "guile";

}

// --------------------------------------------------------------------
// GUILE::parse()
//
// Parse the input file
// --------------------------------------------------------------------

void GUILE::parse()
{

  printf("Generating wrappers for Guile\n");

  // Print out GUILE specific headers
  
  headers();
  
  // Run the parser
  
  yyparse();

}

// ---------------------------------------------------------------------
// GUILE::set_module(char *mod_name)
//
// Sets the module name.
// Does nothing if it's already set (so it can be overridden as a command
// line option).
//
//----------------------------------------------------------------------

void GUILE::set_module(char *mod_name, char **) {

  if (module) return;
  
  module = new char[strlen(mod_name)+1];
  strcpy(module,mod_name);

}

// ---------------------------------------------------------------------
// GUILE::set_init(char *iname)
//
// Sets the initialization function name.
// Does nothing if it's already set
//
//----------------------------------------------------------------------

void GUILE::set_init(char *iname) {
  set_module(iname,0);
}

// ---------------------------------------------------------------------
// GUILE::headers(void)
//
// Generate the appropriate header files for GUILE interface.
// ----------------------------------------------------------------------

void GUILE::headers(void)
{

  emit_banner(f_header);

  fprintf(f_header,"/* Implementation : GUILE */\n\n");
  fprintf(f_header,"#define SWIGGUILE\n");
  fprintf(f_header,"#include <stdio.h>\n");
  fprintf(f_header,"#include <string.h>\n");
  fprintf(f_header,"#include <stdlib.h>\n");

  // Write out hex conversion functions

  if (!NoInclude) {
      if (insert_file("guile.swg", f_header) == -1) {
          fprintf(stderr,"SWIG : Fatal error.  Unable to locate 'guile.swg' in SWIG library.\n");
          SWIG_exit(1);
      }
      emit_hex(f_header);
  } else {
    fprintf(f_header,"#ifdef __cplusplus\n");
    fprintf(f_header,"extern \"C\" {\n");
    fprintf(f_header,"#endif\n");
    fprintf(f_header,"extern void SWIG_MakePtr(char *, void *, char *);\n");
    fprintf(f_header,"extern void SWIG_RegisterMapping(char *, char *, void *(*)(void *));\n");
    fprintf(f_header,"extern char *SWIG_GetPtr(char *, void **, char *);\n");
    fprintf(f_header,"#ifdef __cplusplus\n");
    fprintf(f_header,"}\n");
    fprintf(f_header,"#endif\n");
  }
}

// --------------------------------------------------------------------
// GUILE::initialize()
//
// Output initialization code that registers functions with the
// interface.
// ---------------------------------------------------------------------
void GUILE::initialize()
{

  int i;
        
  if (!module) {
    module = "swig_init";
    fprintf(stderr,"SWIG : *** Warning. No module name specified.\n");
  }
  
  fprintf(f_header,"#define SWIG_init    %s\n\n", module);
  fprintf(f_init,"void %s() {\n", module);

  if (InitNames) {
    i = 0;
    while (InitNames[i]) {
      fprintf(f_init,"\t %s();\n",InitNames[i]);
      i++;
    }
  }
}

// ---------------------------------------------------------------------
// GUILE::close(void)
//
// Wrap things up.  Close initialization function.
// ---------------------------------------------------------------------

void GUILE::close(void)
{

  emit_ptr_equivalence(f_init);
  fprintf(f_init,"}\n");

}

// ----------------------------------------------------------------------
// GUILE::get_pointer(int parm, DataType *t)
//
// Emits code to get a pointer from a parameter and do type checking.
// parm is the parameter number.   This function is only used
// in create_function().
// ----------------------------------------------------------------------

void GUILE::get_pointer(char *iname, int parm, DataType *t) {

  // Pointers are read as hex-strings with encoded type information
  fprintf(f_wrappers,"\t _tempc = gh_scm2newstr(s_%d, &_len);\n",parm);
  fprintf(f_wrappers,"\t if (SWIG_GetPtr(_tempc, (void **) &_arg%d,",parm);
  if (t->type == T_VOID) fprintf(f_wrappers,"(char *) 0)) {\n");
  else 
    fprintf(f_wrappers,"\"%s\")) {\n", t->print_mangle());

  // Now emit code according to the level of strictness desired

  switch(TypeStrict) {
  case 0: // No type checking
    fprintf(f_wrappers,"\t}\n");
    break;
  case 1: // Warning message only
    fprintf(f_wrappers,
      "\t fprintf(stderr,\"Warning : type mismatch in argument %d of %s. Expected %s, received %%s\\n\", _tempc);\n", parm+1,iname, t->print_mangle());
    fprintf(f_wrappers,"\t }\n");
    break;
  case 2: // Super strict mode.

//    fprintf(f_wrappers,"\t\t gscm_error(\"Type error in argument %d of %s. Expected %s.\", s_%d);\n", parm+1,iname,t->print_mangle(),parm);
    fprintf(f_wrappers,"\t}\n");
    break;

  default :
    fprintf(stderr,"Unknown strictness level\n");
    break;
  }
}

// ----------------------------------------------------------------------
// GUILE::create_function(char *name, char *iname, DataType *d,
//                             ParmList *l)
//
// Create a function declaration and register it with the interpreter.
// ----------------------------------------------------------------------

void GUILE::create_function(char *name, char *iname, DataType *d, ParmList *l)
{

  Parm *p;
  int   pcount;
  char  wname[256];
  char  source[64];
  char  target[64];
  char  *tm;
  String cleanup;
  int need_len = 0;
  int need_tempc = 0;

  // Make a wrapper name for this

  strcpy(wname,iname);
  make_wrap_name(wname);

  // Now write the wrapper function itself....this is pretty ugly

  fprintf(f_wrappers,"SCM _wrap_gscm_%s(",wname);

  int i = 0;
  p = l->get_first();
  while (p != 0) {
    if (p->t->is_pointer)
      need_len = 1;
    if ((p->t->type != T_CHAR) && (p->t->is_pointer))
      need_tempc = 1;

    if ((p->t->type != T_VOID) || (p->t->is_pointer))
      fprintf(f_wrappers,"SCM s_%d", i);
    if ((p = l->get_next()))
       fprintf(f_wrappers,", ");
    i++;
  }
  fprintf(f_wrappers,")\n{\n");

  // Declare return variable and arguments

  pcount = emit_args(d,l,f_wrappers);
  
  // Now declare a few helper variables here
  if (d->is_pointer && (d->type != T_CHAR) && 
      !typemap_lookup("out","guile",d,name,"_result","scmresult"))
    fprintf(f_wrappers,"  char _ptemp[128];\n");
  if (need_tempc)
    fprintf(f_wrappers,"  char *_tempc;\n");
  if (need_len)
    fprintf(f_wrappers,"  int _len;\n");
  fprintf(f_wrappers,"  SCM scmresult;  /* fun1 */\n");

  // Now write code to extract the parameters(this is super ugly)

  i = 0;
  p = l->get_first();
  while (p != 0) {
    // Produce names of source and target
    sprintf(source,"s_%d",i);
    sprintf(target,"_arg%d",i);

    if ((tm = typemap_lookup("in","guile",p->t,p->name,source,target))) {
      // Yep.  Use it instead of the default
      fprintf(f_wrappers,"%s\n", tm);
    } else {
      if (!p->t->is_pointer) {
        switch(p->t->type) {

          // Signed Integers
          
        case T_INT :
        case T_SINT :
        case T_SHORT:
        case T_SSHORT:
        case T_LONG:
        case T_SLONG:
        case T_SCHAR:
          fprintf(f_wrappers,"\t _arg%d = %s gh_scm2long(s_%d);\n",i, p->t->print_cast(), i);
          break;
          
          // Unsigned Integers
          
        case T_UINT:
        case T_USHORT:
        case T_ULONG:
        case T_UCHAR:
          fprintf(f_wrappers,"\t _arg%d = %s gh_scm2ulong(s_%d);\n", i, p->t->print_cast(), i);
          break;
          
          // A single character
          
        case T_CHAR :
          fprintf(f_wrappers,"\t _arg%d = %s gh_scm2char(s_%d);\n", i, p->t->print_cast(), i);
          break;
          
          // Floating point
          
        case T_DOUBLE :
        case T_FLOAT:
          fprintf(f_wrappers,"\t _arg%d = %s gh_scm2double(s_%d);\n", i, p->t->print_cast(), i);
          break;
          
          // Void.. Do nothing.
          
        case T_VOID :
          break;
          
          // This is some sort of user-defined call by value type.   We're
          // going to try and wing it here....
          
        case T_USER:
          
          // User defined type not allowed by value.
          
        default :
          fprintf(stderr,"%s : Line %d. Unable to use type %s as a function argument.\n",
                  input_file, line_number, p->t->print_type());
          break;
        }
      } else {
        
        // Argument is a pointer type.   Special case is for char *
        // since that is usually a string.
        
        if ((p->t->type == T_CHAR) && (p->t->is_pointer == 1)) {
          fprintf(f_wrappers,"\t _arg%d = gh_scm2newstr(s_%d, &_len);\n",i,i);
        } else {
          
          // Have a generic pointer type here.    
          
          get_pointer(iname, i, p->t);
        }
      }
    }
    if ((tm = typemap_lookup("check","guile",p->t,p->name,source,target))) {
      // Yep.  Use it instead of the default
      fprintf(f_wrappers,"%s\n",tm);
    }
    if ((tm = typemap_lookup("freearg","guile",p->t,p->name,target,"scmresult"))) {
      // Yep.  Use it instead of the default
      cleanup << tm << "\n";
    }
    p = l->get_next();
    i++;
  }

  // Now write code to make the function call

  fprintf(f_wrappers,"\t SCM_DEFER_INTS;\n");
  emit_func_call(name,d,l,f_wrappers);

  fprintf(f_wrappers,"\t SCM_ALLOW_INTS;\n");
  // Now have return value, figure out what to do with it.

  if ((d->type != T_VOID) || (d->is_pointer)) {
    if ((tm = typemap_lookup("out","guile",d,name,"_result","scmresult"))) {
      // Yep.  Use it instead of the default
      fprintf(f_wrappers,"%s\n",tm);
    } else {
      if (!d->is_pointer) {
        switch(d->type) {
        case T_INT:  case T_SINT:
        case T_SHORT: case T_SSHORT:
        case T_LONG: case T_SLONG:
        case T_SCHAR:
          fprintf(f_wrappers,"\t scmresult = gh_long2scm((long) _result);\n");
          break;
        case T_UINT:
        case T_USHORT:
        case T_ULONG:
        case T_UCHAR:
          fprintf(f_wrappers,"\t scmresult = gh_ulong2scm((unsigned long) _result);\n");
          break;
        case T_DOUBLE :
        case T_FLOAT:
          fprintf(f_wrappers,"\t scmresult = gh_double2scm((double) _result);\n");
          break;
        case T_CHAR :
          fprintf(f_wrappers,"\t scmresult = gh_char2scm(_result);\n");
          break;
        default:
          fprintf(stderr,"%s : Line %d: Unable to use return type %s in function %s.\n",
                  input_file, line_number, d->print_type(), name);
          break;
        }
      } else {
        
        // Is a pointer return type
        
        if ((d->type == T_CHAR) && (d->is_pointer == 1)) {
          fprintf(f_wrappers,"\t scmresult = gh_str02scm(_result);\n");
        } else {
          
          // Is an ordinary pointer type.
          
          fprintf(f_wrappers,"\t  SWIG_MakePtr(_ptemp, _result,\"%s\");\n",
                  d->print_mangle());
          fprintf(f_wrappers,"\t scmresult = gh_str02scm(_ptemp);\n");
        }
      }
    }
  } else {
    /* Some void type.   Need to return something.  I'll return 1 */
    fprintf(f_wrappers,"\t scmresult = gh_int2scm(1);\n");
  }

  // Dump the argument cleanup code
  fprintf(f_wrappers,"%s\n",cleanup.get());

  // Look for any remaining cleanup

  if (NewObject) {
    if ((tm = typemap_lookup("newfree","guile",d,iname,"_result",""))) {
      fprintf(f_wrappers,"%s\n",tm);
    }
  }

  if ((tm = typemap_lookup("ret","guile",d,name,"_result",""))) {
    // Yep.  Use it instead of the default
    fprintf(f_wrappers,"%s\n",tm);
  }
  
  // Wrap things up (in a manner of speaking)
  
  fprintf(f_wrappers,"\t return scmresult;\n");
  fprintf(f_wrappers,"}\n");

  // Now register the function
  fprintf(f_init,"\t gh_new_procedure(\"%s\", _wrap_gscm_%s, %d, 0, 0);\n", 
          iname, wname, pcount);

  // Make a documentation entry for this

  if (doc_entry) {
    static DocEntry *last_doc_entry = 0;
    char *usage = 0;
    usage_func(iname,d,l,&usage);
    doc_entry->usage << usage;
    if (last_doc_entry != doc_entry) {
      doc_entry->cinfo << "returns " << d->print_type();
      last_doc_entry = doc_entry;
    }
    delete usage;
  }
}

// -----------------------------------------------------------------------
// GUILE::link_variable(char *name, char *iname, DataType *d)
//
// Create a link to a C variable.
// This creates a single function _wrap_gscm_var_varname().
// This function takes a single optional argument.   If supplied, it means
// we are setting this variable to some value.  If ommitted, it means we are
// simply evaluating this variable.  Either way, we return the variables
// value.
// -----------------------------------------------------------------------

void GUILE::link_variable(char *name, char *iname, DataType *t)
{

  char  var_name[256];
  char  *tm;
  char  *tm2 = typemap_lookup("varout","guile",t,name,name,"scmresult");

  // evaluation function names

  sprintf(var_name,"_wrap_gscm_var_%s",iname);

  if ((t->type != T_USER) || (t->is_pointer)) {

    fprintf(f_wrappers,"SCM %s(SCM s_0) {\n", var_name);

    if (!(Status & STAT_READONLY) && (t->is_pointer)) {
      fprintf(f_wrappers,"\t char *_temp;\n");
      fprintf(f_wrappers,"\t int  _len;\n");
    }

    if (tm2) {
      fprintf(f_wrappers,"\t char _ptemp[128];\n");
    }
    fprintf(f_wrappers,"\t SCM scmresult; /* fun2 */\n");

    // Check for a setting of the variable value

    fprintf(f_wrappers,"\t if (s_0 != GH_NOT_PASSED) {\n");
    
    // Yup. Extract the type from s_0 and set variable value 
    if (Status & STAT_READONLY) {
//      fprintf(f_wrappers,"\t\t gscm_error(\"Unable to set %s. Variable is read only.\", s_0);\n", iname);
    } else {
      if ((tm = typemap_lookup("varin","guile",t,name,"s_0",name))) {
        // Yep.  Use it instead of the default
        fprintf(f_wrappers,"%s\n",tm);
      } else {
        if (!t->is_pointer) {

          switch(t->type) {
            // Signed Integer
            
          case T_INT:  case T_SINT:
          case T_SHORT: case T_SSHORT:
          case T_LONG: case T_SLONG:
          case T_SCHAR:
            fprintf(f_wrappers,"\t\t %s = %s gh_scm2long(s_0);\n",name, t->print_cast());
            break;
            
            // Unsigned integer
            
          case T_UINT:
          case T_USHORT:
          case T_ULONG:
          case T_UCHAR:
            fprintf(f_wrappers,"\t\t %s = %s gh_scm2ulong(s_0);\n",name, t->print_cast());
            break;
            
            // Floating point
            
          case T_FLOAT:
          case T_DOUBLE:
            fprintf(f_wrappers,"\t\t %s = %s gh_scm2double(s_0);\n",name, t->print_cast());
            break;
            
            // Character value
            
          case T_CHAR:
            fprintf(f_wrappers,"\t\t %s = gh_scm2char(s_0);\n", name);
            break;
            
            // Unknown value 
            
          default:
            fprintf(stderr,"Line %d.  Error, unsupported data-type.\n", line_number);
            break;
          }
        } else {
          
          // Have some sort of pointer type here, Process it differently
          
          if ((t->type == T_CHAR) && (t->is_pointer == 1)) {
            fprintf(f_wrappers,"\t\t _temp = gh_scm2newstr(s_0, &_len);\n");
            fprintf(f_wrappers,"\t\t if (%s) { free(%s);}\n", name,name);
            fprintf(f_wrappers,"\t\t %s = (char *) malloc((_len+1)*sizeof(char));\n",name);
            fprintf(f_wrappers,"\t\t strncpy(%s,_temp,_len);\n",name);
            fprintf(f_wrappers,"\t\t %s[_len] = 0;\n", name);
          } else {
            // Set the value of a pointer
            fprintf(f_wrappers,"\t\t _temp = gh_scm2newstr(s_0,&_len);\n");
            fprintf(f_wrappers,"\t if (SWIG_GetPtr(_temp, (void **) &%s,",name);
            if (t->type == T_VOID) fprintf(f_wrappers,"(char *) 0)) {\n");
            else 
              fprintf(f_wrappers,"\"%s\")) {\n", t->print_mangle());
            
            // Now emit code according to the level of strictness desired
            
            switch(TypeStrict) {
            case 0: // No type checking
              fprintf(f_wrappers,"\t}\n");
              break;
            case 1: // Warning message only
              fprintf(f_wrappers,
                      "\t fprintf(stderr,\"Warning : type mismatch in variable %s. Expected %s, received %%s\\n\", _temp);\n", name, t->print_mangle());
              fprintf(f_wrappers,"\t }\n");
              break;
            case 2: // Super strict mode.
              
//            fprintf(f_wrappers,"\t\t gscm_error(\"Type error in variable %s. Expected %s.\", s_0);\n", name,t->print_mangle());
              fprintf(f_wrappers,"\t}\n");
              break;
              
            default :
              fprintf(stderr,"Unknown strictness level\n");
              break;
            }
          }
        }
      }
    }
    fprintf(f_wrappers,"\t}\n");

    // Now return the value of the variable (regardless of evaluating or setting)

    if (tm2) {
      // Yep.  Use it instead of the default
      fprintf(f_wrappers,"%s\n",tm);
    } else {
      if (!t->is_pointer) {
        /* Return variable by value */
        
        switch(t->type) {
          
          // Signed Integer
          
        case T_INT: case T_SINT:
        case T_SHORT: case T_SSHORT:
        case T_LONG: case T_SLONG:
        case T_SCHAR:
          fprintf(f_wrappers,"\t scmresult = gh_long2scm((long) %s);\n", name);
          break;
          
          // Unsigned integer
          
        case T_UINT:
        case T_USHORT:
        case T_ULONG:
        case T_UCHAR:
          fprintf(f_wrappers,"\t scmresult = gh_ulong2scm((unsigned long) %s);\n",name);
          break;
          
          // Floats
          
        case T_DOUBLE:
        case T_FLOAT:
          fprintf(f_wrappers,"\t scmresult = gh_double2scm((double) %s);\n", name);
          break;
        case T_CHAR:
          fprintf(f_wrappers,"\t scmresult = gh_char2scm(%s);\n",name);
          break;
        default :
          /* Unknown type */
          break;
        }
      } else {
        
        // Is a pointer return type
        
        if ((t->type == T_CHAR) && (t->is_pointer == 1)) {
          fprintf(f_wrappers,"\t scmresult = gh_str02scm(%s);\n",name);
        } else {
          // Is an ordinary pointer type.
          fprintf(f_wrappers,"\t  SWIG_MakePtr(_ptemp, %s,\"%s\");\n",name,
                  t->print_mangle());
          fprintf(f_wrappers,"\t scmresult = gh_str02scm(_ptemp);\n");
        }
      }
    }
    fprintf(f_wrappers,"\t return scmresult;\n");
    fprintf(f_wrappers,"}\n");
    
    // Now add symbol to the Guile interpreter
    
    fprintf(f_init,"\t gh_new_procedure(\"%s\", %s, 0, 1, 0);\n",iname, var_name);
    
  } else {
    fprintf(stderr,"%s : Line %d. ** Warning. Unable to link with type %s (ignored).\n",
            input_file, line_number, t->print_type());
  }

  // Add a documentation entry
  
  if (doc_entry) {
    char *usage = 0; 
    usage_var(iname,t,&usage);
    doc_entry->usage << usage;
    doc_entry->cinfo << "Global : " << t->print_type() << " " << name;
    delete usage;
  }

}

// -----------------------------------------------------------------------
// GUILE::declare_const(char *name, char *iname, DataType *type, char *value)
//
// Makes a constant.   Not sure how this is really supposed to work.
// I'm going to fake out SWIG and create a variable instead.
// ------------------------------------------------------------------------

void GUILE::declare_const(char *name, char *, DataType *type, char *value) {

  int OldStatus = Status;      // Save old status flags
  char   var_name[256];

  Status = STAT_READONLY;      // Enable readonly mode.

  // Make a static variable;

  sprintf(var_name,"_wrap_const_%s",name);

  if ((type->type == T_USER) && (!type->is_pointer)) {
    fprintf(stderr,"%s : Line %d.  Unsupported constant value.\n", input_file, line_number);
    return;
  }

  // Create variable and assign it a value

  fprintf(f_header,"static %s %s = ", type->print_type(), var_name);
  if ((type->type == T_CHAR) && (type->is_pointer <= 1)) {
    fprintf(f_header,"\"%s\";\n", value);
  } else {
    fprintf(f_header,"%s;\n", value);
  }

  // Now create a variable declaration

  link_variable(var_name, name, type);
  Status = OldStatus;

  if (doc_entry) {
    char *usage = 0;
    usage_const(name,type,value,&usage);
    doc_entry->usage = "";
    doc_entry->usage << usage;
    doc_entry->cinfo = "";
    doc_entry->cinfo << "Constant: " << type->print_type();
    delete usage;
  }

}

// ----------------------------------------------------------------------
// GUILE::usage_var(char *iname, DataType *t, char **s)
//
// Produces a usage string for a Guile variable.
// ----------------------------------------------------------------------

void GUILE::usage_var(char *iname, DataType *t, char **s) {

  char temp[1024], *c;

  sprintf(temp,"(%s)", iname);
  c = temp + strlen(temp);

  if (!((t->type != T_USER) || (t->is_pointer))) {
    sprintf(c," - unsupported");
  }

  if (*s == 0) 
    *s = new char[strlen(temp)+1];
  strcpy(*s,temp);
}

// ---------------------------------------------------------------------------
// GUILE::usage_func(char *iname, DataType *t, ParmList *l, char **s)
// 
// Produces a usage string for a function in Guile
// ---------------------------------------------------------------------------

void GUILE::usage_func(char *iname, DataType *, ParmList *l,
                        char **s) {

  char temp[1024];
  char *c;
  int  i;
  Parm  *p;

  sprintf(temp,"(%s ", iname);
  c = temp + strlen(temp);
  
  /* Now go through and print parameters */

  p = l->get_first();
  while (p != 0) {
    
    /* If parameter has been named, use that.   Otherwise, just print a type  */

    if ((p->t->type != T_VOID) || (p->t->is_pointer)) {
      if (strlen(p->name) > 0) {
        sprintf(c,"%s ",p->name);
        c += strlen(p->name)+1;
      }
      else {
        sprintf(c,"%s",p->t->name);
        c += strlen(p->t->name);
        if (p->t->is_pointer) {
          for (i = 0; i < (p->t->is_pointer-p->t->implicit_ptr); i++) {
            sprintf(c,"*");
            c++;
          }
        }
      }
    }
      p = l->get_next();
      if (p != 0) {
        sprintf(c," ");
        c++;
      }
  }
  sprintf(c,")");
  if (*s == 0) 
    *s = new char[strlen(temp)+1];
  strcpy(*s,temp);
}


// ----------------------------------------------------------------------
// GUILE::usage_const(char *iname, DataType *type, char *value, char **s)
//
// Produces a usage string for a Guile constant
// ----------------------------------------------------------------------

void GUILE::usage_const(char *iname, DataType *, char *value, char **s) {

  char temp[1024];

  sprintf(temp,"(%s %s)", iname, value);

  if (*s == 0) 
    *s = new char[strlen(temp)+1];
  strcpy(*s,temp);

}
