ftp.nice.ch/pub/next/unix/audio/fugue.s.tar.gz#/fugue/misc/intgen.c

This is intgen.c in view mode; [Download] [Up]

/* intgen.c -- an interface generator for xlisp */
/* Roger B. Dannenberg
 * 12 Feb 1987
 * 13 Apr 1988 -- modified for version 2.0 
 */

/* Summary and Design:
 *    The first command line argument gives the name of
 * the .c file to generate.  All following arguments are
 * .h files to read and use as interface specifications.
 *
 *    The main program opens the output file, calls
 * write_prelude, and then process_file for each input
 * file.  Then call write_postlude and close the file.
 *
 *    process_file opens an input file and reads each line
 * into current_line.
 * If #define is found, save the following identifier as
 *    macro_name.
 * If "LISP:" is found, then see if it is preceded by one
 * or two identifiers and an open paren.
 *    If yes, call routine_call,
 *    else call macro_call.
 *
 *    routine_call gets the first one or two identifiers off the
 * line into type_name and routine_name.  If there is just one id,
 * assign it to routine_name and make type_name = "void". 
 * If the routine_name starts with *, remove the * from 
 * routine_name and append "*" to type_name.
 * Call write_interface with type_name, routine_name, and location
 * of parameter type description after "LISP:".
 *
 *    macro_call gets a type_name from the input line after
 * "LISP:".
 * Then call write_interface with type_name, macro_name, and
 * location of parameter type description.
 *
 *    lisp function names are saved in a table, and an
 * initialization routine is written to install the new
 * SUBRs into the xlisp symbol table, as well as to lookup
 * RSLT_sym, the atom on which results are placed
 *
 * HISTORY
 *
 * 24-Oct-88	Roger Dannenberg at CMU
 *	Changed so that if C routine returns void and has result parameters,
 *	then result parameters are returned by the lisp subr as well as
 *	assigned to *RSLT*.
 *
 * 13-Apr-88	Roger Dannenberg at CMU
 *	Modified for xlisp version 2.0
 *
 * 22-Dec-87    Roger Dannenberg at NeXT
 *	Added FILE type.
 *
 * 21-May-87	Dale Amon at CMU CSD
 *	Included use of NODE *s_true under SCORE_EDITOR conditional. Standard
 *	xlisp code use NODE *true instead.
 *
 * 13-May-87	Dale Amon at CMU CSD
 *	Added conditional compilation switch SCORE_EDITOR so that this
 *	program will work with both standard XLISP sources and with Roger's
 *	(ahem) modified version. Also put in error checking for case where
 *	user does not specifiy an output file so program will exit instead
 *	of coredump.
 *
 */

/* Turn on special handling for Roger's Score Editor if the following #define
 *    is uncommented:
 */
/* #define SCORE_EDITOR	*/

/* Turn on special handling for Chris's Sound Editor if the following #define
 *    is uncommented:
 */
#define SOUND_EDITOR

#define errfile stdout

#define ident_max 100
#define line_max 200
#define subr_max 500

/* prefix for include files not to be included in interface module */
#define no_include_prefix '~'

#define false 0
#define true 1

#include "cext.h"
#include "stdio.h"
#include "ctype.h"
#include "cmdline.h"

static char *sindex();

#define whitep(c) ((c) == ' ' || (c) == '\t')
#define symbolp(c) (isalpha(c) || (c) == '*' || (c) == '_' || (c) == '-' ||\
		    (c) == ':' || isdigit(c) || (c) == '^' || (c) == '*')

/* c and Lisp parameters are encoded in the same table.
 * Field type_id is the string name of the type.
 * For c types (return types of C routines), code is 'C',
 *   convert gives the routine for making a lisp node from
 *   the c datum.
 *   listtype_or_special is "v" for types that should be
 *   returned as LISP NIL (e.g. "void"), "s" for types
 *   that when NULL should be returned as NIL, "r"
 *   for normal types, and "" to raise an error.
 *   ctype is not used and should be NULL.
 * For Lisp types (from parameter specs), code is 'L'.
 *   convert gives the routine that extracts a C value
 *   from a lisp node whose type is given by the field
 *   listtype_or_special.
 *   c_type is the type of the local C variable which is
 *   passed as a parameter to the C routine.
 *   initializer is the initial value for result only parameters
 *
 * End of table is marked by a NULL type_id.
 *
 * Location 0 is reserved to indicate errors.
 * Location 1 MUST BE type ANY
 *
 */

#define any_index 1
struct {
    char *type_id;
    char code;
    char *convert;
    char *getarg_or_special;
    char *ctype;
    char *makenode;
    char *initializer;
} type_table[] = {
	{" ", ' ', NULL, NULL, NULL, NULL, NULL},
	{"ANY", 'L', "", "", "LVAL", "", "NIL"},
	{"ATOM", 'L', "", "xlgasymbol", "LVAL", "", "NIL"},
	{"FILE", 'L', "getfile", "xlgastream", "FILE *", "cvfile", "NULL"},
	{"FIXNUM", 'L', "getfixnum", "xlgafixnum", "int", "cvfixnum", "0"},
	{"FLOAT", 'L', "getflonum", "xlgaflonum", "float", "cvflonum", "0.0"},
	{"FLONUM", 'L', "getflonum", "xlgaflonum", "double", "cvflonum", "0.0"},
	{"STRING", 'L', "getstring", "xlgastring", "unsigned char *", "cvstring", "NULL"},
	{"atom_type", 'C', "", "r", NULL, NULL, NULL},
	{"LVAL", 'C', "", "r", NULL, NULL, "NIL"},

#ifdef SOUND_EDITOR
	/* Extensions for Sound Type: */
	{"SOUND", 'L', "getsound", "xlgasound", "SoundPtr", "cvsound", "NULL"},
	{"SoundPtr", 'C', "cvsound", "r", NULL, NULL, NULL},
#endif

#ifdef SCORE_EDITOR
	{"VALUE",  'L', "getval", "VALUE", "value_type", "cvval", "NULL"},
	{"value_type", 'C', "cvval", "r", NULL, NULL, NULL},
	{"EVENT",  'L', "getevent", "EVENT", "event_type", "cvevent", "NULL"},
	{"event_type", 'C', "cvevent", "r", NULL, NULL, NULL},
	{"score_type", 'C', "cvevent", "r", NULL, NULL, NULL},
#endif
 /* begin DMA entries */
 	{"DEXT", 'L', "getdext", "xlgadext", "ext_type", "cvdext", "NULL"},
 	{"DEXT", 'C', "cvdext", "r", NULL, NULL, NULL},
 	{"SEXT", 'L', "getsext", "xlgasext", "ext_type", "cvsext", "NULL"},
 	{"SEXT", 'C', "cvsext", "r", NULL, NULL, NULL},
 /* end DMA entries */
	{"int", 'C', "cvfixnum", "r", NULL, NULL, NULL},
	{"boolean", 'C', "cvboolean", "r", NULL, NULL, NULL},
	{"float", 'C', "cvflonum", "r", NULL, NULL, NULL},
	{"double", 'C', "cvflonum", "r", NULL, NULL, NULL},
	{"string", 'C', "cvstring", "s", NULL, NULL, NULL},
	{"char*", 'C', "cvstring", "s", NULL, NULL, NULL},
	{"char", 'C', "cvfixnum", "r", NULL, NULL, NULL},
	{"string_type", 'C', "cvstring", "s", NULL, NULL, NULL},
	{"FILE*", 'C', "cvfile", "s", NULL, NULL, NULL},
	{"void", 'C', "", "v", NULL, NULL, NULL},
/*eot*/	{NULL, ' ', NULL, NULL, NULL, NULL, NULL}};

/* subr names get saved here: */
char subr_table[subr_max][ident_max];
int subr_table_x;

#define get_c_special(i) type_table[(i)].getarg_or_special[0]
#define get_c_conversion(i) type_table[(i)].convert
#define get_lisp_extract(i) type_table[(i)].convert
#define get_lisp_getarg(i) type_table[(i)].getarg_or_special
#define get_lisp_ctype(i) type_table[(i)].ctype
#define get_lisp_makenode(i) type_table[(i)].makenode
#define get_lisp_initializer(i) type_table[(i)].initializer

static void lisp_code();
static int lookup();
static void process_file();
static void routine_call();
static void write_interface();
static void write_postlude();
static void write_prelude();
static void write_ptrfile();

char source_file[ident_max];	/* source file */
char current_line[4 * line_max];    /* current line in source file */
char out_file[ident_max];	/* output file name */
char ptr_file[ident_max];	/* ptr.h file name */
char def_file[ident_max];	/* def.h file name */

FILE *lispout = NULL;		/* output for lisp source code (if any) */


/* getarg -- get an identifier from a string */
/**/
int getarg(start, result, pos)
    char *start;	/* where to start scanning */
    char *result;	/* where to put the identifier */
    char **pos;		/* ptr to char after identifier in source */
{
    *result = NULL;
    while (whitep(*start) && *start != NULL) start++;
    if (*start == NULL) return false;
    if (!symbolp(*start)) return false;
    while (symbolp(*start) && *start != NULL) {
	*result = *start;
	result++;
	start++;
    }
    *result = NULL;
    *pos = start;
    return true;
}


/* error() -- print source file and line */
/**/
error()
{
    fprintf(errfile, "\n%s: |%s|\n", source_file, current_line);
}


/* lisp_code -- write lisp code to file */
/*
 * read from inp if necessary until close comment found
 */
static void lisp_code(inp, s)
  FILE *inp;
  char *s;
{
    char lisp[line_max];
    char *endcomment;
    char *inputline;   /* for end of file detection */

    if (lispout == NULL) {
	char lisp_file_name[ident_max];
	char *extension;
	strcpy(lisp_file_name, out_file);
	extension = sindex(lisp_file_name, ".c");
	strcpy(extension, ".lsp"); /* overwrite .c with .lsp */
	lispout = fopen(lisp_file_name, "w");
	if (lispout == NULL) {
	    fprintf(stdout, "Error: couldn't open %s\n", lisp_file_name);
	    exit(1);
	}
	printf("writing %s ...\n", lisp_file_name);
    }

    strcpy(lisp, s);	/* don't modify s */
    inputline = lisp;
    while (inputline != NULL &&
	   (endcomment = sindex(lisp, "*/")) == NULL) {
	fputs(lisp, lispout);
	inputline = fgets(lisp, line_max, inp);
    }
    strcpy(endcomment, "\n\n");
    fputs(lisp, lispout);
}


/* lookup -- find type data */
/**/
static int lookup(s, t)
    char *s;
    char t;
{
    int i = 1;
    while (type_table[i].type_id != NULL) {
	if (type_table[i].code == t &&
	    strcmp(type_table[i].type_id, s) == 0)
	    return i;
        i++;
    }
    return 0;
}

/* macro_call -- generate xlisp interface for C routine */
/**/
void macro_call(in, out, curline, macro_name, arg_loc)
    FILE *in;		/* input file */
    FILE *out;		/* output file */
    char *curline;	/* input line */
    char *macro_name;	/* name of the macro to call */
    char *arg_loc;	/* location after "LISP:" */
{
    char type_name[ident_max];
    if (!getarg(arg_loc, type_name, &arg_loc)) {
	error();
	fprintf(errfile, "no type given for macro.\n");
    } else {
	write_interface(in, out, type_name, macro_name, arg_loc, true);
    }
}



/* main -- generate an xlisp to c interface file */
/**/
void main(argc, argv)
    int argc;
    char *argv[];
{
    char *s;
    FILE *out;
    FILE *ptrfile;
    FILE *deffile;
    int n;

    for (n = 0; n < subr_max; n++) subr_table[subr_max][0] = NULL;
    subr_table_x = 0;

    cl_init(NULL, 0, NULL, 0, argv, argc);
    if ((s = cl_arg(1)) != NULL) {
  	   strcpy(out_file, s);
	   if (sindex(out_file, ".") == 0) 
	       strcat(out_file, ".c");
	   else fprintf(stderr, 
	       "1st command line argument should be a legal c identifier\n");
	   out = fopen(out_file, "w");
           if (out == NULL) {
	       fprintf(stdout, "Error: couldn't open %s\n", out_file);
	       exit(1);
           }
  	   strcpy(ptr_file, s);
	   strcat(ptr_file, "ptrs.h");
	   ptrfile = fopen(ptr_file, "w");
           if (ptrfile == NULL) {
	       fprintf(stdout, "Error: couldn't open %s\n", ptr_file);
	       exit(1);
           }
  	   strcpy(def_file, s);
	   strcat(def_file, "defs.h");
	   deffile = fopen(def_file, "w");
           if (deffile == NULL) {
	       fprintf(stdout, "Error: couldn't open %s\n", def_file);
	       exit(1);
           }
    } else {
	   fprintf(stdout, "Error: no output file specified\n");
	   exit(1);
    }

    printf("writing %s ...\n", out_file);
    
    write_prelude(out, out_file);
    n = 2;
    while ((s = cl_arg(n)) != NULL) {
	printf("  %s\n", s);
        process_file(s, out);
	n++;
    }
    write_postlude(out);
    fclose(out);
    write_ptrfile(ptrfile, deffile);
    fclose(ptrfile);
    fclose(deffile);
    if (lispout != NULL) fclose(lispout);
}


static void process_file(fname, out)
    char *fname;
    FILE *out;
{
    FILE *in;
    char *cp;
    char *pos;
    char type_name[ident_max];		/* the type of the routine */
    char routine_name[ident_max];	/* the name of the routine or macro */
    int routine_is_macro = false;	/* true if last def was macro */
    int j;
    char flag = fname[0];

    if (flag == no_include_prefix) fname++;

    strcpy(source_file, fname);	/* for error reporting */
    in = fopen(fname, "r");
    if (in == NULL) {
	fprintf(errfile, "couldn't open %s\n", fname);
	return;
    }

    if (flag != no_include_prefix) fprintf(out, "#include \"%s\"\n\n", fname);

    while (fgets(current_line, line_max, in) != NULL) {
        cp = sindex(current_line, "#define");
        if (cp != NULL) {
	    cp += strlen("#define");
	    if (!getarg(cp, routine_name, &cp)) {
	        error();
	        fprintf(errfile, "#define not followed by identifier\n");
	    }
	    /* watch out for multi-line macros: */
	    while (sindex(current_line, "\\\n")) {
		if (fgets(current_line, line_max, in) == NULL) return;
	    }
        } else if ((cp = sindex(current_line, "LISP:")) != NULL) {
	    char type_str[ident_max];
	    char routine_str[ident_max];
	    if (getarg(current_line, type_str, &pos) &&
	        getarg(pos, routine_str, &pos) &&
	        pos < cp) {
	        routine_call(in, out, current_line, type_str, routine_str,
		     cp + strlen("LISP:"));
	    } else if (getarg(cp + strlen("LISP:"), type_str, &pos)) {
	        macro_call(in, out, current_line, routine_name,
			   cp + strlen("LISP:"));
	    } else routine_call(in, out, current_line, type_name, routine_name,
		     cp + strlen("LISP:"));
	} else if ((cp = sindex(current_line, "LISP-SRC:")) != NULL) {
	    lisp_code(in, cp + strlen("LISP-SRC:"));
	} else if (getarg(current_line, type_name, &pos) &&
		   getarg(pos, routine_name, &pos)) {
/*	    printf("saw %s %s\n", type_name, routine_name);*/
	} else {  /* wipe out names for safety: */
	    type_name[0] = NULL;
	    routine_name[0] = NULL;
	}
    }

    fclose(in);
}


/* routine_call -- generate xlisp interface for C routine */
/**/
static void routine_call(in, out, curline, type_name, routine_name, arg_loc)
    FILE *in;		/* input file */
    FILE *out;		/* output file */
    char *curline;	/* input line */
    char *type_name;	/* type id */
    char *routine_name;	/* routine id */
    char *arg_loc;	/* location after "LISP:" */
{

    if (*routine_name == NULL) {
	routine_name = type_name;
	type_name = "void";
    }
    if (*routine_name == '*') {
	char *r = routine_name;
	while (*r != NULL) {   /* shift left */
	    *r = *(r+1);
	    r++;
 	}
        strcat(type_name, "*");
    }
    write_interface(in, out, type_name, routine_name, arg_loc, false);
}


/* sindex -- find substring */
/**/
static char *sindex(sup, sub)
  char *sup;	/* the containing string */
  char *sub;	/* the substring */
{
    int i;
    for ( ; *sup != NULL; sup++) {
	for (i = 0; true; i++) {
	    if (*(sub+i) == NULL) return sup;
	    if (*(sup+i) != *(sub+i)) break;
	}
    }
    return NULL;
}


/* write_interface -- write SUBR for xlisp */
/*
 * NOTE: if is_macro and there are no arguments, then
 *    do not write parens: e.g. "foo" instead of "foo()"
 */
static void write_interface(in, out, type_name, fn_name, arg_loc, is_macro)
    FILE *in;		/* input file */
    FILE *out;		/* output file */
    char *type_name;	/* c type for return value */
    char *fn_name;	/* c function to be called */
    char *arg_loc;	/* LISP arg type are described here */
    int is_macro;	/* true if this is a macro */
{
    char lispfn[ident_max];	/* lisp fn name */
    char *cp;		/* a temporary */
    int len;		/* a string length */
#define args_max 20
    struct {
	int index;	/* table location for this type */
	int res_flag;	/* is a result returned? */
    } args[args_max];
    char arg_type[ident_max];	/* the original type spec */
    char *c_type;	/* c type for an argument */
    char *c_str;	/* temp for a c code line */
    int argcnt = 0;	/* counts arguments */
    int i;		/* argument index */
    int result_flag = false;	/* true if there are result parameters */
    int result_x;	/* index of result type */
    char newline[line_max];	/* place to read continuation lines */


/*    printf("write_interface: %s %s %s", type_name, fn_name, arg_loc);*/
    if (*type_name == NULL || *fn_name == NULL) {
	error();
	fprintf(errfile, "Error: bad syntax, maybe missing type\n");
	return;
    }

    while (*arg_loc != '(' && *arg_loc != NULL) arg_loc++;
    if (*arg_loc == NULL) {
	error();
	fprintf(errfile, "Error: '(' expected after 'LISP:'\n");
	return;
    } else arg_loc++;
    if (!getarg(arg_loc, lispfn, &arg_loc)) {
	error();
	fprintf(stdout, "Error: lisp function name expected\n");
	return;
    }
    /* make it upper case: */
    for (cp = lispfn; *cp != NULL; cp++) {
	if (islower(*cp)) *cp = toupper(*cp);
    }

    /* save SUBR name */
    strcpy(subr_table[subr_table_x], lispfn);
    subr_table_x++;

    /* make lispfn lower case, dash, colon -> underscore: */
    for (cp = lispfn; *cp != NULL; cp++) {
	if (isupper(*cp)) *cp = tolower(*cp);
	if (*cp == '-' || *cp == ':') *cp = '_';
    }
    
    /* append continuation lines to arg_loc to handle multi-line specs */
    while (sindex(arg_loc, "*/") == NULL) {
	/* remove newline */
	if (strlen(arg_loc) > 0) 
	    arg_loc[strlen(arg_loc) - 1] = NULL;
	if (fgets(newline, line_max, in) == NULL) {
	    error();
	    fprintf(stdout, "Error: end of file unexpected\n");
	    exit(1);
	}
	if ((strlen(arg_loc) + strlen(newline)) > (3 * line_max)) {
	    error();
	    fprintf(stdout, 
		"Error: specification too long or missing end of comment.\n");
	    exit(1);
	}
	strcat(arg_loc, newline);
    }

    fprintf(out, "/%c xlc_%s -- interface to C routine %s */\n/**/\n",
	'*', lispfn, fn_name);

    fprintf(out, "LVAL xlc_%s()\n{\n", lispfn);
    while (getarg(arg_loc, arg_type, &arg_loc)) {
        int result_only_flag = false;

	if (argcnt >= args_max) {
	    error();
	    fprintf(errfile, 
		"Internal error: too many args, increase args_max\n");
	}
	len = strlen(arg_type);
	if (arg_type[len-1] == '*') {
	    arg_type[len-1] = NULL;
	    args[argcnt].res_flag = true;
	    result_flag = true;
	} else if (arg_type[len-1] == '^') {
	    arg_type[len-1] = NULL;
	    args[argcnt].res_flag = true;
	    result_flag = true;
	    result_only_flag = true;
	} else args[argcnt].res_flag = false;
	
	args[argcnt].index = lookup(arg_type, 'L');
	c_type = get_lisp_ctype(args[argcnt].index);
	if (c_type == NULL) {
	    error();
	    fprintf(errfile, "Error: %s undefined, using int.\n",
		arg_type);
	    c_type = "int";
	    args[argcnt].index = lookup("FIXNUM", 'L');
	}
	fprintf(out, "    %s arg%d = ", c_type,	argcnt+1);
	if (result_only_flag) {
	    fprintf(out, "%s;\n",
		    get_lisp_initializer(args[argcnt].index));
 	} else if (args[argcnt].index == any_index) {
	    fprintf(out, "xlgetarg();\n");
	} else {
	    c_str = "%s(%s());\n";
	    fprintf(out,c_str,
		    get_lisp_extract(args[argcnt].index),
		    get_lisp_getarg(args[argcnt].index));
	}
	argcnt++;
    }

    /* check for close paren and close comment: */
    cp = sindex(arg_loc, ")");
    if (cp == NULL || sindex(cp+1, "*/") == NULL) {
	error();
	fprintf(errfile, "Warning: close paren and close comment expected\n");
    }

    /* lookup result type */
    result_x = lookup(type_name, 'C');
    if (result_x == 0) {
	fprintf(errfile, "Error: unknown type: %s, assuming void\n", 
	    type_name);
	result_x = lookup("void", 'C');
    }

    /* if there are result parameters then return them rather than NIL
     * when the type is void
     */
    if (get_c_special(result_x) == 'v' && result_flag) {
	fprintf(out, "    LVAL result;\n");
    }

    if (get_c_special(result_x) != 'v') {
	/* declare result: */
        fprintf(out, "    %s result;\n", type_name);
    }

    /* check for end of argument list: */
    fprintf(out, "\n    xllastarg();\n");

    /* call the c routine */
    if (get_c_special(result_x) != 'v') {
	fprintf(out, "    result = ");
    } else fprintf(out, "    ");
    fprintf(out, "%s", fn_name);
    if (!is_macro || argcnt > 0) fprintf(out, "(");

    /* pass arguments: */
    for (i = 0; i < argcnt; i++) {
	if (i > 0) fprintf(out, ", ");
	if (args[i].res_flag) fprintf(out, "&");
        fprintf(out, "arg%d", i+1);
    }
    if (!is_macro || argcnt > 0) fprintf(out, ")");
    fprintf(out, ";\n");

    /* put results (if any) on *RSLT* */
    if (result_flag) {
	int wrote_one_flag = false;
	fprintf(out, "    {\tLVAL *next = &getvalue(RSLT_sym);\n");
	for (i = 0; i < argcnt; i++) {
	    if (args[i].res_flag) {
		if (wrote_one_flag)
		    fprintf(out, "\tnext = &cdr(*next);\n");
		wrote_one_flag = true;
		fprintf(out, "\t*next = cons(NIL, NIL);\n");
		fprintf(out, "\tcar(*next) = %s(arg%d);",
		    get_lisp_makenode(args[i].index), i+1);
	    }
	}
	fprintf(out, "\n    }\n");

	/* copy *RSLT* to result if appropriate */
	if (get_c_special(result_x) == 'v') {
	    fprintf(out, "    result = getvalue(RSLT_sym);\n");
	}
    }

    /* now return actual return value */
    if (get_c_special(result_x) == NULL) {
	error();
	fprintf(errfile, "Warning: unknown type from C, coercing to int.\n");
	fprintf(out, "    return cvfixnum((int) result);\n");
    } else if (get_c_special(result_x) == 'v' && !result_flag) {
	fprintf(out, "    return NIL;\n");
    } else if (get_c_special(result_x) == 'v' && result_flag) {
	fprintf(out, "    return result;\n");
    } else if (get_c_special(result_x) == 's') {
	fprintf(out, "    if (result == NULL) return NIL;\n");
	fprintf(out, "    else return %s(result);\n",
	    get_c_conversion(result_x));
    } else {
	fprintf(out, "    return %s(result);\n",
	    get_c_conversion(result_x));
    }
    fprintf(out, "}\n\n\n");
}


/* write_postlude -- write stuff at end of file */
/**/
static void write_postlude(out)
    FILE *out;
{
	/* nothing to do for version 2 */
}


/* write_ptrfile -- write function definition table */
/**/
static void write_ptrfile(pf, df)
  FILE *pf;
  FILE *df;
{
    int n;
    char *cp;
    char cname[ident_max];

    for (n = 0; n < subr_table_x; n++) {
	strcpy(cname, subr_table[n]);
        /* make cname lower case, dash,colon -> underscore: */
        for (cp = cname; *cp != NULL; cp++) {
	    if (isupper(*cp)) *cp = tolower(*cp);
	    if (*cp == '-' || *cp == ':') *cp = '_';
        }
	fprintf(df, "extern LVAL xlc_%s();\n", cname);
	fprintf(pf, "  { \"%s\",  S, xlc_%s}, \n", subr_table[n], cname);
    }
    printf("	Add %s to localdefs.h and add %s to localptrs.h\n",
	def_file, ptr_file);
}


/* write_prelude -- write stuff at head of file */
/**/
static void write_prelude(out, out_file)
    FILE *out;
    char *out_file;
{
    int i = 2;
    char *s;
    fprintf(out, "/%c %s -- interface to  ",
	 '*', out_file);
    while ((s = cl_arg(i)) != NULL) {
	if (i > 2) fprintf(out, ", ");
	fprintf(out, "%s", s);
	i++;
    }
    fprintf(out, " */\n\n%cinclude \"xlisp.h\"\n\n", '#');
#ifdef SCORE_EDITOR
    fprintf(out, "extern LVAL s_true;\n");
    fprintf(out, "%cdefine cvboolean(i) ((i) ? s_true : NIL)\n\n", '#');
#else
    fprintf(out, "extern LVAL true;\n");
    fprintf(out, "%cdefine cvboolean(i) ((i) ? true : NIL)\n\n", '#');
#endif
    fprintf(out, "extern LVAL RSLT_sym;\n\n\n");
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.