/* ** To run the program: ** ** gencbind OPTIONS ** ** where OPTIONS are one or more of ** -f ** -c ** -d Default values for the options are: ** master file name: stdin ** code generation option: c ** spp source code directory: ./ ** Alternative values for the code generation option are c++ and idl. ** (However, idl doesn't do anything; it is equivalent to c.) ** ** Original code written by Allen Farris. ** M.D. De La Pena 24 February 1998 -- Modified C-binding generation code ** to map IRAF long ints to C ints. In IRAF, long ints and ints have the ** same number of bits. ** M.D. De La Pena 13 January 1999 - Modified code such that parameters which ** are multidimensional arrays and are NOT char, resolve to TYPE *. */ # include # include # include # include /* These constants are the maximum size of a line, including any */ /* continuations, the maximum size of a name, and the maximum */ /* number of parms in a procedure. */ #define maxlinesize 1024 #define maxnamesize 63 #define maxparms 64 enum spp_type { NONE, INT, CHAR, REAL, DOUBLE, POINTER, LONG, SHORT, BOOL, COMPLEX, VOID }; const int SPP_SIZE[11] = { /* sizes of SPP data types in bytes */ 0, 4, 2, 4, 8, 4, 4, 2, 4, 8, 0 }; enum io_option { BOTH, INPUT_ONLY, OUTPUT_ONLY }; enum decl_obj { SCALAR, ARRAY, PROCEDURE }; enum code_generation_option { ANSI_C, C_PLUS_PLUS, IDL }; typedef enum spp_type SPP_TYPE; typedef enum io_option IO_OPT; typedef enum decl_obj DECL_OBJ; typedef enum code_generation_option CODE_GEN_OPT; /* Data structure for holding information about SPP procedures. */ /* This data structure is used to capture data from the master file */ /* and the SPP text file and is used to drive the code generation process. */ typedef struct { char *source_code_name; /* SPP source code filename */ SPP_TYPE rtn_type; /* return type of SPP procedure */ SPP_TYPE rtn_conv; /* optional return conversion type */ char *spp_name; /* SPP procedure name */ char *extern_spp; /* external name of SPP procedure */ char *c_name; /* C function name */ int no_parms; /* number of parms */ char *sppparm[maxparms]; /* the SPP parm name */ char *cparm[maxparms]; /* the C parm name */ IO_OPT option[maxparms]; /* I/O attributes of parms */ SPP_TYPE parm_conv[maxparms]; /* optional parm conversion type */ SPP_TYPE parm_type[maxparms]; /* data type of parm */ char *parm_size[maxparms]; /* size of output char arrays */ DECL_OBJ parm_arrayid[maxparms];/* array indicator of parm */ int no_dims[maxparms]; /* # dimensions if parm is an array */ } ProcInfo; /* a very unintelligent error termination procedure */ void err(char *s) { printf("%s\n",s); exit(0); } /* convert an SPP_TYPE to a printable string */ char * pr_SPP_TYPE(SPP_TYPE t) { char *o; switch (t) { case NONE: o = "none"; break; case INT: o = "int"; break; case CHAR: o = "char"; break; case REAL: o = "real"; break; case DOUBLE: o = "double"; break; case POINTER: o = "pointer"; break; case LONG: o = "long"; break; case SHORT: o = "short"; break; case BOOL: o = "bool"; break; case COMPLEX: o = "complex"; break; case VOID: o = "void"; break; } return o; } /* Given an SPP_TYPE, return a string that is the C data type */ const char *c_type(SPP_TYPE t) { switch (t) { case NONE: return "****"; case INT: return "int"; case CHAR: return "char"; case REAL: return "float"; case DOUBLE: return "double"; case POINTER: return "IRAFPointer"; /*MDD case LONG: return "long"; */ case LONG: return "int"; case SHORT: return "short"; case BOOL: return "Bool"; case COMPLEX: return "Complex"; case VOID: return "void"; } } /* a useful debugging tool */ void prProcInfo(ProcInfo *proc) { int i; printf("%s%s%s%s<%s>%s%s%s%s\n", "ProcInfo: ------------- \nproc.source_code_name = ", proc->source_code_name, "\nproc.rtn_type = ", pr_SPP_TYPE(proc->rtn_type), pr_SPP_TYPE(proc->rtn_conv), " proc->spp_name = ", proc->spp_name, " proc.c_name = ", proc->c_name); for (i = 0; i < proc->no_parms; ++i) { printf("%d: %s<%s> [%s] %s(%s) ", i, pr_SPP_TYPE(proc->parm_type[i]), pr_SPP_TYPE(proc->parm_conv[i]), (proc->parm_size[i] == 0 ? "0" : proc->parm_size[i]), proc->sppparm[i], proc->cparm[i]); switch(proc->parm_arrayid[i]) { case SCALAR: printf("scalar "); break; case ARRAY: printf("array %d",proc->no_dims[i]); break; case PROCEDURE: printf("procedure "); break; } switch(proc->option[i]) { case BOTH: printf("both "); break; case INPUT_ONLY: printf("input only "); break; case OUTPUT_ONLY: printf("output only "); break; } printf("\n"); } } /* Given a string representing an SPP type, */ /* Return the SPP_TYPE */ SPP_TYPE isa_type(char *s) { if (strcmp(s,"int") == 0) return INT; if (strcmp(s,"char") == 0) return CHAR; if (strcmp(s,"real") == 0) return REAL; if (strcmp(s,"double") == 0) return DOUBLE; if (strcmp(s,"pointer") == 0) return POINTER; if (strcmp(s,"long") == 0) return LONG; if (strcmp(s,"short") == 0) return SHORT; if (strcmp(s,"bool") == 0) return BOOL; if (strcmp(s,"complex") == 0) return COMPLEX; if (strcmp(s,"void") == 0) return VOID; return NONE; } /* Given a string representing a type to convert an SPP type to, */ /* Note: This allows conversion to void, which should rarely be used */ /* and can generate bad code. In particular IRAF pointers should not */ /* be converted to type void because you must do arithmetic on them. */ /* Return the SPP_TYPE */ SPP_TYPE isa_conv(char *s) { if (strcmp(s,"i") == 0) return INT; if (strcmp(s,"c") == 0) return CHAR; if (strcmp(s,"r") == 0) return REAL; if (strcmp(s,"f") == 0) return REAL; if (strcmp(s,"d") == 0) return DOUBLE; if (strcmp(s,"p") == 0) return POINTER; if (strcmp(s,"l") == 0) return LONG; if (strcmp(s,"s") == 0) return SHORT; if (strcmp(s,"b") == 0) return BOOL; if (strcmp(s,"x") == 0) return COMPLEX; if (strcmp(s,"v") == 0) return VOID; if (strcmp(s,"int") == 0) return INT; if (strcmp(s,"char") == 0) return CHAR; if (strcmp(s,"real") == 0) return REAL; if (strcmp(s,"float") == 0) return REAL; if (strcmp(s,"double") == 0) return DOUBLE; if (strcmp(s,"pointer") == 0) return POINTER; if (strcmp(s,"long") == 0) return LONG; if (strcmp(s,"short") == 0) return SHORT; if (strcmp(s,"bool") == 0) return BOOL; if (strcmp(s,"complex") == 0) return COMPLEX; if (strcmp(s,"void") == 0) return VOID; return NONE; } /* Return the number of valid characters in a name. */ /* A valid name is a sequence of alphanumeric chars or '_', */ /* the first one of which is an alphabetic char. */ int get_name(char *s) { int n = 0; if (!isalpha(*s)) return 0; while (isalnum(*s) || *s == '_') { ++n; ++s; } return n; } /* ** MAIN program ** */ int main(int argc, char **argv) { char line[maxlinesize]; char cline[maxlinesize]; int n; char *s; FILE *ifile; /* the input master file to be read */ FILE *hfile; /* the .h file to be created */ FILE *cfile; /* the .c file to be created */ char *ofilename; ProcInfo proc; /* structure to capture parse results about a proc */ void parse_proc_line(ProcInfo *, char *); void process_text(ProcInfo *, FILE *, FILE *, CODE_GEN_OPT, char *); CODE_GEN_OPT code_gen_opt; char *mastername; char *spp_directory; /* Set the default options */ ifile = stdin; /* the default input master file */ mastername = "stdin"; code_gen_opt = ANSI_C; spp_directory = "./"; for (n = 1; n < argc; ++n) { s = argv[n]; if (*s == '-') ++s; if (*s == 'f') { ++s; if (*s == '\0') { ++n; s = argv[n]; } mastername = s; ifile = fopen(s,"r"); /* open the master file */ if (ifile == NULL) err("Could not open master file"); } else if (*s == 'c') { ++s; if (*s == '\0') { ++n; s = argv[n]; } if (strcmp(s,"C") == 0 || strcmp(s,"c") == 0) code_gen_opt = ANSI_C; else if (strcmp(s,"C++") == 0 || strcmp(s,"c++") == 0) code_gen_opt = C_PLUS_PLUS; else if (strcmp(s,"IDL") == 0 || strcmp(s,"idl") == 0) code_gen_opt = IDL; else err("Invalid option"); } else if (*s == 'd') { ++s; if (*s == '\0') { ++n; s = argv[n]; } spp_directory = s; } else err("Invalid syntax: cvos -f -c