diff options
Diffstat (limited to 'dlperl')
-rw-r--r-- | dlperl/Makefile | 51 | ||||
-rw-r--r-- | dlperl/dlperl.c | 1037 | ||||
-rw-r--r-- | dlperl/dlperl.doc | 264 | ||||
-rw-r--r-- | dlperl/dlperl.man | 219 | ||||
-rw-r--r-- | dlperl/usersub.c | 72 |
5 files changed, 1643 insertions, 0 deletions
diff --git a/dlperl/Makefile b/dlperl/Makefile new file mode 100644 index 0000000000..64cfc76f06 --- /dev/null +++ b/dlperl/Makefile @@ -0,0 +1,51 @@ + +# perl +# - location of uperl.o and include files +PERL = ../perl-lib +# - libraries required by perl - from config.sh +PERL_LIBS = -ldbm -lm -lposix + +UPERL = $(PERL)/uperl4.035.o +UPERL = ../sybperl/uperl2.o + +DP_C = \ + dlperl.c \ + usersub.c + +DP_H = + + +CC = gcc-2.2.2 +CPPFLAGS= -I$(PERL) +#CFLAGS = -g + +ALL = \ + dlperl + + +all: $(ALL) tags + +dlperl: $(UPERL) $(DP_C:.c=.o) + $(LINK.c) -o dlperl $(UPERL) $(DP_C:.c=.o) \ + $(PERL_LIBS) \ + -ldl -lc.1.6 + ld-rules -clobber dlperl + +dlperl.s: dlperl.c + $(COMPILE.c) -S $(OUTPUT_OPTION) dlperl.c + +tags: $(DP_C) $(DP_H) + ctags $(DP_C) $(DP_H) + +lint: + $(LINT.c) $(DP_C) $(LINT_LN) + +clean: + rm -f core *.o + +clobber: clean + rm -f $(ALL) tags + +install: + +.KEEP_STATE: diff --git a/dlperl/dlperl.c b/dlperl/dlperl.c new file mode 100644 index 0000000000..49d48bb197 --- /dev/null +++ b/dlperl/dlperl.c @@ -0,0 +1,1037 @@ +static char sccsid[] = "@(#)dlperl.c 1.2 10/12/92 (DLPERL)"; + +/* + * name: dlperl.c + * synopsis: dlperl - perl interface to dynamically linked usubs + * sccsid: @(#)dlperl.c 1.2 10/12/92 + */ + +/* + * NOTE: this code is *not* portable + * - uses SPARC assembler with gcc asm extensions + * - is SPARC ABI specific + * - uses SunOS 4.x dlopen + * + * NOTE: not all types are currently implemented + * - multiple indirections (pointers to pointers, etc.) + * - structures + * - quad-precison (long double) + */ + +#include <dlfcn.h> +#include <alloca.h> +#include <ctype.h> + +/* perl */ +#include "EXTERN.h" +#include "perl.h" + +/* globals */ +int Dl_warn = 1; +int Dl_errno; +#define DL_ERRSTR_SIZ 256 +char Dl_errstr[DL_ERRSTR_SIZ]; +#define WORD_SIZE (sizeof(int)) + +static int userval(); +static int userset(); +static int usersub(); + + +/* + * glue perl subroutines and variables to dlperl functions + */ +enum usersubs { + US_dl_open, + US_dl_sym, + US_dl_call, + US_dl_close, +}; + +enum uservars { + UV_DL_VERSION, + UV_DL_WARN, + UV_dl_errno, + UV_dl_errstr, +}; + + +int +dlperl_init() +{ + struct ufuncs uf; + char *file = "dlperl.c"; + + uf.uf_val = userval; + uf.uf_set = userset; + +#define MAGICVAR(name, ix) uf.uf_index = ix, magicname(name, &uf, sizeof uf) + + /* subroutines */ + make_usub("dl_open", US_dl_open, usersub, file); + make_usub("dl_sym", US_dl_sym, usersub, file); + make_usub("dl_call", US_dl_call, usersub, file); + make_usub("dl_close", US_dl_close, usersub, file); + + /* variables */ + MAGICVAR("DL_VERSION", (int) UV_DL_VERSION); + MAGICVAR("DL_WARN", (int) UV_DL_WARN); + MAGICVAR("dl_errno", (int) UV_dl_errno); + MAGICVAR("dl_errstr", (int) UV_dl_errstr); + + return 0; +} + + +/* + * USERVAL AND USERSET + */ + +/* + * assign dlperl variables to perl variables + */ +/*ARGSUSED*/ +static int +userval(ix, str) +int ix; +STR *str; +{ + switch(ix) { + case UV_DL_VERSION: + str_set(str, sccsid); + break; + case UV_DL_WARN: + str_numset(str, (double) Dl_warn); + break; + case UV_dl_errno: + str_numset(str, (double) Dl_errno); + break; + case UV_dl_errstr: + str_set(str, Dl_errstr); + break; + default: + fatal("dlperl: unimplemented userval"); + break; + } + return 0; +} + +/* + * assign perl variables to dlperl variables + */ +static int +userset(ix, str) +int ix; +STR *str; +{ + switch(ix) { + case UV_DL_WARN: + Dl_warn = (int) str_gnum(str); + break; + default: + fatal("dlperl: unimplemented userset"); + break; + } + return 0; +} + + +/* + * USERSUBS + */ +static int +usersub(ix, sp, items) +int ix; +register int sp; +register int items; +{ + int oldsp = sp; + STR **st = stack->ary_array + sp; + register STR *Str; /* used in str_get and str_gnum macros */ + + Dl_errno = 0; + *Dl_errstr = '\0'; + + switch(ix) { + case US_dl_open: + { + char *file; + void *dl_so; + + if(items != 1) { + fatal("Usage: $dl_so = &dl_open($file)"); + return oldsp; + } + + file = str_get(st[1]); + dl_so = dlopen(file, 1); + + --sp; + if(dl_so == NULL) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, "&dl_open: %s", dlerror()); + if(Dl_warn) warn(Dl_errstr); + + astore(stack, ++sp, str_mortal(&str_undef)); + } else { + astore(stack, ++sp, str_2mortal(str_make( + (char *) &dl_so, sizeof(void *)))); + } + break; + } + case US_dl_sym: + { + void *dl_so; + char *symbol; + void *dl_func; + + if(items != 2) { + fatal("Usage: $dl_func = &dl_sym($dl_so, $symbol)"); + return oldsp; + } + + dl_so = *(void **) str_get(st[1]); + symbol = str_get(st[2]); + dl_func = dlsym(dl_so, symbol); + + --sp; + if(dl_func == NULL) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, "&dl_sym: %s", dlerror()); + if(Dl_warn) warn(Dl_errstr); + + astore(stack, ++sp, str_mortal(&str_undef)); + } else { + astore(stack, ++sp, str_2mortal(str_make( + (char *) &dl_func, sizeof(void *)))); + } + break; + } + case US_dl_call: + { + void *dl_func; + char *parms_desc, *return_desc; + int nstack, nparm, narr, nlen, nrep; + int f_indirect, f_no_parm, f_result; + char c, *c_p; int c_pn = 0; + unsigned char C, *C_p; int C_pn = 0; + short s, *s_p; int s_pn = 0; + unsigned short S, *S_p; int S_pn = 0; + int i, *i_p; int i_pn = 0; + unsigned int I, *I_p; int I_pn = 0; + long l, *l_p; int l_pn = 0; + unsigned long L, *L_p; int L_pn = 0; + float f, *f_p; int f_pn = 0; + double d, *d_p; int d_pn = 0; + char *a, **a_p; int a_pn = 0; + char *p, **p_p; int p_pn = 0; + unsigned int *stack_base, *stack_p; + unsigned int *xp; + void (*func)(); + unsigned int ret_o; + double ret_fd; + float ret_f; + char *c1; + int n1, n2; + + if(items < 3) { +fatal("Usage: @vals = &dl_call($dl_func, $parms_desc, $return_desc, @parms)"); + return oldsp; + } + dl_func = *(void **) str_get(st[1]); + parms_desc = str_get(st[2]); + return_desc = str_get(st[3]); + + /* determine size of stack and temporaries */ +# define CNT_STK_TMP(PN, SN) \ + n2 = 0; do { \ + if(f_indirect) { \ + PN += narr; \ + ++nstack; \ + if(!f_no_parm) \ + nparm += narr; \ + } else { \ + nstack += SN; \ + if(!f_no_parm) \ + ++nparm; \ + } \ + } while(++n2 < nrep); \ + f_indirect = f_no_parm = narr = nrep = 0; + + nstack = 0; + nparm = 0; + f_indirect = f_no_parm = narr = nrep = 0; + for(c1 = parms_desc;*c1;++c1) { + switch(*c1) { + case ' ': + case '\t': + break; + + case 'c': /* signed char */ + CNT_STK_TMP(c_pn, 1); + break; + case 'C': /* unsigned char */ + CNT_STK_TMP(C_pn, 1); + break; + case 's': /* signed short */ + CNT_STK_TMP(s_pn, 1); + break; + case 'S': /* unsigned short */ + CNT_STK_TMP(S_pn, 1); + break; + case 'i': /* signed int */ + CNT_STK_TMP(i_pn, 1); + break; + case 'I': /* unsigned int */ + CNT_STK_TMP(I_pn, 1); + break; + case 'l': /* signed long */ + CNT_STK_TMP(l_pn, 1); + break; + case 'L': /* unsigned long */ + CNT_STK_TMP(L_pn, 1); + break; + case 'f': /* float */ + CNT_STK_TMP(f_pn, 1); + break; + case 'd': /* double */ + CNT_STK_TMP(d_pn, 2); + break; + case 'a': /* ascii (null-terminated) string */ + CNT_STK_TMP(a_pn, 1); + break; + case 'p': /* pointer to <nlen> buffer */ + CNT_STK_TMP(p_pn, 1); + break; + + case '&': /* pointer = [1] */ + if(f_indirect) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: parms_desc %s: too many indirections, with char %c", + parms_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + f_indirect = 1; + narr = 1; + break; + case '[': /* array */ + if(f_indirect) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: parms_desc %s: too many indirections, with char %c", + parms_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + f_indirect = 1; + ++c1; + while(*c1 == ' ' && *c1 == '\t') + ++c1; + while(isdigit(*c1)) { + narr = narr * 10 + (*c1 - '0'); + ++c1; + } + while(*c1 == ' ' && *c1 == '\t') + ++c1; + if(*c1 != ']') { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: parms_desc %s: bad char %c, expected ]", + parms_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + break; + case '<': /* length */ + ++c1; + while(*c1 == ' ' && *c1 == '\t') + ++c1; + while(isdigit(*c1)) + ++c1; + while(*c1 == ' ' && *c1 == '\t') + ++c1; + if(*c1 != '>') { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: parms_desc %s: bad char %c, expected >", + parms_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + break; + case '+': + break; + case '-': + f_no_parm = 1; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if(nrep) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: too many repeats"); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + while(isdigit(*c1)) { + nrep = nrep * 10 + (*c1 - '0'); + ++c1; + } + --c1; + break; + default: + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: parms_desc %s: bad char %c", + parms_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + } + /* trailing &[]<>+-0-9 is ignored */ + if(nparm != items - 3) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: bad parameter count %d, expected %d", + items - 3, nparm); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + nparm = 4; + + /* allocate temporaries */ + if((c_pn && (c_p = (char *) + alloca(c_pn * sizeof(char))) == NULL) || + (C_pn && (C_p = (unsigned char *) + alloca(C_pn * sizeof(unsigned char))) == NULL) || + (s_pn && (s_p = (short *) + alloca(s_pn * sizeof(short))) == NULL) || + (S_pn && (S_p = (unsigned short *) + alloca(S_pn * sizeof(unsigned short))) == NULL) || + (i_pn && (i_p = (int *) + alloca(i_pn * sizeof(int))) == NULL) || + (I_pn && (I_p = (unsigned int *) + alloca(I_pn * sizeof(unsigned int))) == NULL) || + (l_pn && (l_p = (long *) + alloca(l_pn * sizeof(long))) == NULL) || + (L_pn && (L_p = (unsigned long *) + alloca(L_pn * sizeof(unsigned long))) == NULL) || + (f_pn && (f_p = (float *) + alloca(f_pn * sizeof(float))) == NULL) || + (d_pn && (d_p = (double *) + alloca(d_pn * sizeof(double))) == NULL) || + (a_pn && (a_p = (char **) + alloca(a_pn * sizeof(char *))) == NULL) || + (p_pn && (p_p = (char **) + alloca(p_pn * sizeof(char *))) == NULL)) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, "&dl_call: bad alloca"); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + + /* grow stack - maintains stack alignment (double word) */ + /* NOTE: no functions should be called otherwise the stack */ + /* that is being built will be corrupted */ + /* NOTE: some of the stack is pre-allocated, but is not */ + /* reused here */ + if(alloca(nstack * WORD_SIZE) == NULL) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, "&dl_call: bad alloca"); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + + /* stack base */ +#if !defined(lint) + asm("add %%sp,68,%%o0;st %%o0,%0" : + "=g" (stack_base) : /* input */ : "%%o0"); +#else + stack_base = 0; +#endif + stack_p = stack_base; + + /* layout stack */ +# define LAY_STK_NUM(T, P, PN) \ + n2 = 0; do { \ + if(f_indirect) { \ + *stack_p++ = (unsigned int) &P[PN]; \ + if(f_no_parm) { \ + PN += narr; \ + } else { \ + for(n1 = 0;n1 < narr;++n1) { \ + P[PN++] = (T) \ + str_gnum(st[nparm++]); \ + } \ + } \ + } else { \ + if(f_no_parm) { \ + ++stack_p; \ + } else { \ + *stack_p++ = (T) \ + str_gnum(st[nparm++]); \ + } \ + } \ + } while(++n2 < nrep); \ + f_indirect = f_no_parm = narr = nrep = 0; + +# define LAY_STK_DOUBLE(T, P, PN) \ + n2 = 0; do { \ + if(f_indirect) { \ + *stack_p++ = (unsigned int) &P[PN]; \ + if(f_no_parm) { \ + PN += narr; \ + } else { \ + for(n1 = 0;n1 < narr;++n1) { \ + P[PN++] = (T) \ + str_gnum(st[nparm++]); \ + } \ + } \ + } else { \ + if(f_no_parm) { \ + stack_p += 2; \ + } else { \ + d = (T) str_gnum(st[nparm++]); \ + xp = (unsigned int *) &d; \ + *stack_p++ = *xp++; \ + *stack_p++ = *xp; \ + } \ + } \ + } while(++n2 < nrep); \ + f_indirect = f_no_parm = narr = nrep = 0; + +# define LAY_STK_STR(P, PN) \ + n2 = 0; do { \ + if(f_indirect) { \ + *stack_p++ = (unsigned int) &P[PN]; \ + if(f_no_parm) { \ + PN += narr; \ + } else { \ + for(n1 = 0;n1 < narr;++n1) { \ + P[PN++] = \ + str_get(st[nparm++]); \ + } \ + } \ + } else { \ + if(f_no_parm) { \ + ++stack_p; \ + } else { \ + *stack_p++ = (unsigned int) \ + str_get(st[nparm++]); \ + } \ + } \ + } while(++n2 < nrep); \ + f_indirect = f_no_parm = narr = nrep = 0; + + c_pn = C_pn = s_pn = S_pn = i_pn = I_pn = l_pn = L_pn = 0; + f_pn = d_pn = a_pn = p_pn = 0; + f_indirect = f_no_parm = narr = nrep = 0; + for(c1 = parms_desc;*c1;++c1) { + switch(*c1) { + case ' ': + case '\t': + break; + + case 'c': /* signed char */ + LAY_STK_NUM(char, c_p, c_pn); + break; + case 'C': /* unsigned char */ + LAY_STK_NUM(unsigned char, C_p, C_pn); + break; + case 's': /* signed short */ + LAY_STK_NUM(short, s_p, s_pn); + break; + case 'S': /* unsigned short */ + LAY_STK_NUM(unsigned short, S_p, S_pn); + break; + case 'i': /* signed int */ + LAY_STK_NUM(int, i_p, i_pn); + break; + case 'I': /* unsigned int */ + LAY_STK_NUM(unsigned int, I_p, I_pn); + break; + case 'l': /* signed long */ + LAY_STK_NUM(long, l_p, l_pn); + break; + case 'L': /* unsigned long */ + LAY_STK_NUM(unsigned long, L_p, L_pn); + break; + case 'f': /* float */ + LAY_STK_NUM(float, f_p, f_pn); + break; + case 'd': /* double */ + LAY_STK_DOUBLE(double, d_p, d_pn); + break; + case 'a': /* ascii (null-terminated) string */ + LAY_STK_STR(a_p, a_pn); + break; + case 'p': /* pointer to <nlen> buffer */ + LAY_STK_STR(p_p, p_pn); + break; + + case '&': /* pointer = [1] */ + if(f_indirect) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: parms_desc %s: too many indirections, with char %c", + parms_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + f_indirect = 1; + narr = 1; + break; + case '[': /* array */ + if(f_indirect) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: parms_desc %s: too many indirections, with char %c", + parms_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + f_indirect = 1; + ++c1; + while(*c1 == ' ' && *c1 == '\t') + ++c1; + while(isdigit(*c1)) { + narr = narr * 10 + (*c1 - '0'); + ++c1; + } + while(*c1 == ' ' && *c1 == '\t') + ++c1; + if(*c1 != ']') { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: parms_desc %s: bad char %c, expected ]", + parms_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + break; + case '<': /* length */ + ++c1; + while(*c1 == ' ' && *c1 == '\t') + ++c1; + while(isdigit(*c1)) + ++c1; + while(*c1 == ' ' && *c1 == '\t') + ++c1; + if(*c1 != '>') { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: parms_desc %s: bad char %c, expected >", + parms_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + break; + case '+': + break; + case '-': + f_no_parm = 1; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if(nrep) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: too many repeats"); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + while(isdigit(*c1)) { + nrep = nrep * 10 + (*c1 - '0'); + ++c1; + } + --c1; + break; + default: + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: parms_desc %s: bad char %c", + parms_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + } + /* trailing &[]<>+-0-9 is ignored */ + + /* call function */ + /* NOTE: the first 6 words are passed in registers %o0 - %o5 */ + /* %sp+68 to %sp+92 are vacant, but allocated */ + /* and shadow %o0 - %o5 */ + /* above stack_base starts at %sp+68 and the function */ + /* call below sets up %o0 - %o5 from stack_base */ + func = (void (*)()) dl_func; + (*func)(stack_base[0], stack_base[1], stack_base[2], + stack_base[3], stack_base[4], stack_base[5]); + + /* save return value */ + /* NOTE: return values are either in %o0 or %f0 */ +#if !defined(lint) + asm("st %%o0,%0" : "=g" (ret_o) : /* input */); + asm("std %%f0,%0" : "=g" (ret_fd) : /* input */); + asm("st %%f0,%0" : "=g" (ret_f) : /* input */); +#else + ret_o = 0; ret_fd = 0.0; ret_f = 0.0; +#endif + + /* parameter results */ +# define RES_NUM(P, PN, SN) \ + n2 = 0; do { \ + if(f_indirect) { \ + ++nstack; \ + if(f_result) { \ + for(n1 = 0;n1 < narr;++n1) { \ + astore(stack, ++sp, str_2mortal( \ + str_nmake((double) P[PN++]))); \ + } \ + } else { \ + PN += narr; \ + } \ + } else { \ + nstack += SN; \ + if(f_result) { \ + astore(stack, ++sp, \ + str_mortal(&str_undef));\ + } \ + } \ + } while(++n2 < nrep); \ + f_indirect = f_result = narr = nlen = nrep = 0; + +# define RES_STR(P, PN, L, SN) \ + n2 = 0; do { \ + if(f_indirect) { \ + ++nstack; \ + if(f_result) { \ + for(n1 = 0;n1 < narr;++n1) { \ + astore(stack, ++sp, str_2mortal( \ + str_make(P[PN++], L))); \ + } \ + } else { \ + PN += narr; \ + } \ + } else { \ + if(f_result) { \ + astore(stack, ++sp, str_2mortal(\ + str_make((char *) \ + stack_base[nstack], L))); \ + } \ + nstack += SN; \ + } \ + } while(++n2 < nrep); \ + f_indirect = f_result = narr = nlen = nrep = 0; + + --sp; + nstack = 0; + c_pn = C_pn = s_pn = S_pn = i_pn = I_pn = l_pn = L_pn = 0; + f_pn = d_pn = a_pn = p_pn = 0; + f_indirect = f_result = narr = nlen = nrep = 0; + for(c1 = parms_desc;*c1;++c1) { + switch(*c1) { + case ' ': + case '\t': + break; + + case 'c': /* signed char */ + RES_NUM(c_p, c_pn, 1); + break; + case 'C': /* unsigned char */ + RES_NUM(C_p, C_pn, 1); + break; + case 's': /* signed short */ + RES_NUM(s_p, s_pn, 1); + break; + case 'S': /* unsigned short */ + RES_NUM(S_p, S_pn, 1); + break; + case 'i': /* signed int */ + RES_NUM(i_p, i_pn, 1); + break; + case 'I': /* unsigned int */ + RES_NUM(I_p, I_pn, 1); + break; + case 'l': /* signed long */ + RES_NUM(l_p, l_pn, 1); + break; + case 'L': /* unsigned long */ + RES_NUM(L_p, L_pn, 1); + break; + case 'f': /* float */ + RES_NUM(f_p, f_pn, 1); + break; + case 'd': /* double */ + RES_NUM(d_p, d_pn, 2); + break; + case 'a': /* ascii (null-terminated) string */ + RES_STR(a_p, a_pn, 0, 1); + break; + case 'p': /* pointer to <nlen> buffer */ + RES_STR(p_p, p_pn, nlen, 1); + break; + + case '&': /* pointer = [1] */ + if(f_indirect) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: parms_desc %s: too many indirections, with char %c", + parms_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + f_indirect = 1; + narr = 1; + break; + case '[': /* array */ + if(f_indirect) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: parms_desc %s: too many indirections, with char %c", + parms_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + f_indirect = 1; + ++c1; + while(*c1 == ' ' && *c1 == '\t') + ++c1; + while(isdigit(*c1)) { + narr = narr * 10 + (*c1 - '0'); + ++c1; + } + while(*c1 == ' ' && *c1 == '\t') + ++c1; + if(*c1 != ']') { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: parms_desc %s: bad char %c, expected ]", + parms_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + break; + case '<': /* length */ + ++c1; + while(*c1 == ' ' && *c1 == '\t') + ++c1; + while(isdigit(*c1)) { + nlen = nlen * 10 + (*c1 - '0'); + ++c1; + } + while(*c1 == ' ' && *c1 == '\t') + ++c1; + if(*c1 != '>') { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: parms_desc %s: bad char %c, expected >", + parms_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + break; + case '+': + f_result = 1; + break; + case '-': + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if(nrep) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: too many repeats"); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + while(isdigit(*c1)) { + nrep = nrep * 10 + (*c1 - '0'); + ++c1; + } + --c1; + break; + default: + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: parms_desc %s: bad char %c", + parms_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + } + /* trailing &[]<>+-0-9 is ignored */ + + /* return value */ +# define RET_NUM(T, S, P, R) \ + if(f_indirect) { \ + P = (T *) ret_o; \ + for(n1 = 0;n1 < narr;++n1) { \ + S = *P++; \ + astore(stack, ++sp, str_2mortal( \ + str_nmake((double) S))); \ + } \ + } else { \ + S = (T) R; \ + astore(stack, ++sp, str_2mortal( \ + str_nmake((double) S))); \ + } + +# define RET_STR(S, P, L) \ + if(f_indirect) { \ + P = (char **) ret_o; \ + for(n1 = 0;n1 < narr;++n1) { \ + S = *P++; \ + astore(stack, ++sp, str_2mortal( \ + str_make((char *) S, L))); \ + } \ + } else { \ + S = (char *) ret_o; \ + astore(stack, ++sp, str_2mortal( \ + str_make((char *) S, L))); \ + } + + f_indirect = nlen = narr = 0; + for(c1 = return_desc;*c1;++c1) { + switch(*c1) { + case ' ': + case '\t': + break; + + case 'c': /* signed char */ + RET_NUM(char, c, c_p, ret_o); + goto ret_exit; + case 'C': /* unsigned char */ + RET_NUM(unsigned char, C, C_p, ret_o); + goto ret_exit; + case 's': /* signed short */ + RET_NUM(short, s, s_p, ret_o); + goto ret_exit; + case 'S': /* unsigned short */ + RET_NUM(unsigned short, S, S_p, ret_o); + goto ret_exit; + case 'i': /* signed int */ + RET_NUM(int, i, i_p, ret_o); + goto ret_exit; + case 'I': /* unsigned int */ + RET_NUM(unsigned int, I, I_p, ret_o); + goto ret_exit; + case 'l': /* signed long */ + RET_NUM(long, l, l_p, ret_o); + goto ret_exit; + case 'L': /* unsigned long */ + RET_NUM(unsigned long, L, L_p, ret_o); + goto ret_exit; + case 'f': /* float */ + RET_NUM(float, f, f_p, ret_f); + break; + case 'd': /* double */ + RET_NUM(double, d, d_p, ret_fd); + goto ret_exit; + case 'a': /* ascii (null-terminated) string */ + RET_STR(a, a_p, 0); + goto ret_exit; + case 'p': /* pointer to <nlen> buffer */ + RET_STR(p, p_p, nlen); + goto ret_exit; + + case '&': /* pointer = [1] */ + if(f_indirect) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: return_desc %s: too many indirections, with char %c", + return_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + f_indirect = 1; + narr = 1; + break; + case '[': /* array */ + if(f_indirect) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: return_desc %s: too many indirections, with char %c", + return_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + f_indirect = 1; + ++c1; + while(*c1 == ' ' && *c1 == '\t') + ++c1; + while(isdigit(*c1)) { + narr = narr * 10 + (*c1 - '0'); + ++c1; + } + while(*c1 == ' ' && *c1 == '\t') + ++c1; + if(*c1 != ']') { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: return_desc %s: bad char %c, expected ]", + return_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + break; + case '<': /* length */ + ++c1; + while(*c1 == ' ' && *c1 == '\t') + ++c1; + while(isdigit(*c1)) { + nlen = nlen * 10 + (*c1 - '0'); + ++c1; + } + while(*c1 == ' ' && *c1 == '\t') + ++c1; + if(*c1 != '>') { + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: return_desc %s: bad char %c, expected >", + return_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + break; + default: + Dl_errno = 1; + (void) sprintf(Dl_errstr, + "&dl_call: return_desc %s: bad char %c", + return_desc, *c1); + if(Dl_warn) warn(Dl_errstr); + return oldsp; + } + } +ret_exit: /* anything beyond first [cCsSiIlLdfap] is ignored */ + break; + } + case US_dl_close: + { + void *dl_so; + int dl_err; + + if(items != 1) { + fatal("Usage: $dl_err = &dl_close($dl_so)"); + return oldsp; + } + + dl_so = *(void **) str_get(st[1]); + dl_err = dlclose(dl_so); + + --sp; + if(dl_err) { + Dl_errno = 1; + (void) sprintf(Dl_errstr, "&dl_close: %s", dlerror()); + if(Dl_warn) warn(Dl_errstr); + } + astore(stack, ++sp, str_2mortal(str_nmake((double) dl_err))); + break; + } + default: + fatal("dlperl: unimplemented usersub"); + break; + } + return sp; +} diff --git a/dlperl/dlperl.doc b/dlperl/dlperl.doc new file mode 100644 index 0000000000..7da0dfe1d8 --- /dev/null +++ b/dlperl/dlperl.doc @@ -0,0 +1,264 @@ + + + +DLPERL(1) USER COMMANDS DLPERL(1) + + + +NAME + dlperl - dynamic link-editor subroutines for perl + +SYNOPSIS + $dl_so = &dl_open($file) + $dl_func = &dl_sym($dl_so, $symbol) + @vals = &dl_call($dl_func, $parms_desc, $return_desc, @parms) + $dl_err = &dl_close($dl_so) + + $DL_VERSION + $DL_WARN + $dl_errno + $dl_errstr + +DESCRIPTION + _D_l_p_e_r_l is _p_e_r_l plus user defined subroutines (_u_s_u_b_s) that + interface to the dynamic link-editor and can call most C and + Fortran functions whose object code has been linked into a + shared object file. + + Subroutines + + All _d_l_p_e_r_l subroutines set the two predefined names + $dl_errno and $dl_errstr. Only partial descriptions of + &dl_open, &dl_sym and &dl_close appear below, see _d_l_o_p_e_n(_3_x) + for a complete description. The following subroutines are + defined by _d_l_p_e_r_l: + + &dl_open($file) + Adds the shared object $_f_i_l_e to _d_l_p_e_r_l's address + space. Returns a descriptor that can be used for + later reference to the object in calls to &dl_sym + and &dl_close. When an error occurs an undef value + is returned. + + &dl_sym($dl_so, $symbol) + Obtains an address binding for the function $_s_y_m_b_o_l + as it occurs in the shared object identified by + $_d_l__s_o. When an error occurs an undef value is + returned. + + &dl_call($dl_func, $parms_desc, $return_desc, @parms) + Calls the function identified by $_d_l__f_u_n_c. The + function's entry parameters are described by + $_p_a_r_m_s__d_e_s_c and assigned values from @_p_a_r_m_s. The + function's exit value is described by $_r_e_t_u_r_n__d_e_s_c. + An array is returned that contains the values of any + result parameters and the return value. When an + error occurs because of a problem parsing the + descriptions or because of an incorrect parameter + count no values are returned (although the underly- + ing function may have been called). + + + +Sun Release 4.1 Last change: 10/16/92 1 + + + + + + +DLPERL(1) USER COMMANDS DLPERL(1) + + + + The descriptions are sequences of characters that + give the order and type of parameters: + + c A signed char value. + C An unsigned char value. + s A signed short value. + S An unsigned short value. + i A signed integer value. + I An unsigned integer value. + l A signed long value. + L An unsigned long value. + f A single-precision float. + d A double-precision float. + a An ascii (null-terminated) string. + p A pointer to <length> buffer. + + Each letter may optionally be preceded by a number + that gives a repeat count. An array is specified by + a preceding [_a_r_r_a_y__s_i_z_e] (or & as a shorthand for + [_1]). (Multi-dimension arrays are not currently + supported.) Each scalar or array element is ini- + tialized from @_p_a_r_m_s. A preceding - leaves the + parameter uninitialized. Type _p expects a preceding + <_b_u_f_f_e_r__l_e_n_g_t_h>. A preceding + specifies that after + the function is called that particular parameter's + value is to be returned (multiple values are + returned for array types, a + with a integral type + like _i returns an undef value). The $_r_e_t_u_r_n__d_e_s_c + contains only one letter with no repeat count, - or + +. + + An undef or zero-length $_p_a_r_m__d_e_s_c means the func- + tion has no parameters. An undef or a zero-length + $_r_e_t_u_r_n__d_e_s_c means the function returns void. + Strings or buffers that must be a specific length + (because the values are overwritten) must be pre- + extended. Although type _f is supported, compilers + typically pass floats as doubles. + + &dl_close($dl_so) + Removes the shared object identified by $_d_l__s_o from + _d_l_p_e_r_l's address space. If successful, a value of + zero is returned. When an error occurs a non-zero + value is returned. + + Predefined Names + + The following names have special meaning to _d_l_p_e_r_l. + + $DL_VERSION + The version of _d_l_p_e_r_l. This variable is read-only. + + + + +Sun Release 4.1 Last change: 10/16/92 2 + + + + + + +DLPERL(1) USER COMMANDS DLPERL(1) + + + + $DL_WARN + The current value of the _d_l_p_e_r_l warning flag. + Default is 1. If non-zero, when errors occur warn- + ings are sent to standard error. The warning is the + same information that is stored in $dl_errstr. + + $dl_errno + The error number for the error that occurred. If a + _d_l_p_e_r_l subroutine completes successfully $dl_errno + is set to zero. This variable is read-only. + + $dl_errstr + The error message for the error that occurred. If a + _d_l_p_e_r_l subroutine completes successfully $dl_errstr + is set to a zero length string. This variable is + read-only. + +EXAMPLES + This is an example of calling a simple C function: + + open(OUT, ">example.c"); + print OUT <<'EOC'; + void + example(a1, a2, i1, d1, a3) + char *a1[2]; + char *a2[2]; + int i1; + double *d1; + char *a3[4]; + { + a3[i1 + (int) *d1] = a1[0]; + a3[i1 * (int) *d1] = a1[1]; + a3[(int) *d1 - i1] = a2[0]; + a3[(int) *d1 - 2 * i1] = a2[1]; + } + EOC + close(OUT); + + system("cc -c example.c;ld -o example.so example.o"); + + $dl_so = &dl_open("example.so"); + die "$0: $dl_errstr" if($dl_errno); + + $dl_func = &dl_sym($dl_so, "example"); + die "$0: $dl_errstr" if($dl_errno); + + $dl_func =~ s/(['\\])/\\$1/g; + eval <<EOC; + sub example { + &dl_call('$dl_func', "2[2]a i &d -+[4]a", undef, @_); + } + EOC + + + +Sun Release 4.1 Last change: 10/16/92 3 + + + + + + +DLPERL(1) USER COMMANDS DLPERL(1) + + + + @vals = &example("hacker,", "Perl", "another", "Just", 1, 2); + print "@vals\n"; + + &dl_close($dl_so); + die "$0: $dl_errstr" if($dl_errno); + + unlink('example.c', 'example.o', 'example.so'); + + If a more complicated interface is needed, the dynamically + linked function can define _u_s_u_b_s by calling internal _p_e_r_l + functions. + +AUTHOR + Eric Fifer <egf@sbi.com> + +SEE ALSO + perl(1), dlopen(3X), ld(1) + +BUGS + Additional parameter types should be implemented to support + structures, multi-dimension arrays, pointers to arrays, + pointers to functions, etc. + + Unlike the _p_a_c_k operator, the repeat count precedes the + letter in the $_p_a_r_m__d_e_s_c syntax. The array size preceding + the parameter letter is also unconventional. + + All errors set $dl_errno to 1. + + + + + + + + + + + + + + + + + + + + + + + + + + + +Sun Release 4.1 Last change: 10/16/92 4 + + + diff --git a/dlperl/dlperl.man b/dlperl/dlperl.man new file mode 100644 index 0000000000..8879133ca2 --- /dev/null +++ b/dlperl/dlperl.man @@ -0,0 +1,219 @@ +.\" +.\" name: dlperl.man +.\" synopsis: dlperl man page +.\" sccsid: @(#)dlperl.man 1.4 10/16/92 (DLPERL) +.\" +.ds RP 10/16/92 +.rn '' }` +.de Sh +.br +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp +.if t .sp .5v +.if n .sp +.. +.de Ip +.br +.ie \\n(.$>=3 .ne \\$3 +.el .ne 3 +.IP "\\$1" \\$2 +.. +''' +''' Set up \*(-- to give an unbreakable dash; +''' string Tr holds user defined translation string. +''' Bell System Logo is used as a dummy character. +''' +.tr \(*W-|\(bv\*(Tr +.ie n \{\ +.ds -- \(*W- +.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +.ds L" "" +.ds R" "" +.ds L' ' +.ds R' ' +'br\} +.el\{\ +.ds -- \(em\| +.tr \*(Tr +.ds L" `` +.ds R" '' +.ds L' ` +.ds R' ' +'br\} +.TH DLPERL 1 "\*(RP" +.UC +.SH NAME +dlperl \- dynamic link-editor subroutines for perl +.SH SYNOPSIS +.nf +.ft B +$dl_so = &dl_open($file) +$dl_func = &dl_sym($dl_so, $symbol) +@vals = &dl_call($dl_func, $parms_desc, $return_desc, @parms) +$dl_err = &dl_close($dl_so) +.ft +.fi +.LP +.nf +.ft B +$DL_VERSION +$DL_WARN +$dl_errno +$dl_errstr +.ft +.fi +.SH DESCRIPTION +.I Dlperl +is \fIperl\fP plus user defined subroutines (\fIusubs\fP) that +interface to the dynamic link-editor and can call most C and Fortran +functions whose object code has been linked into a shared object file. +.Sh "Subroutines" +All \fIdlperl\fP subroutines set the two predefined names $dl_errno and +$dl_errstr. Only partial descriptions of &dl_open, &dl_sym and +&dl_close appear below, see \fIdlopen(3x)\fP for a complete +description. The following subroutines are defined by \fIdlperl\fP: +.Ip "&dl_open($file)" 8 2 +Adds the shared object \fI$file\fP to \fIdlperl\fP's address space. +Returns a descriptor that can be used for later reference to the object +in calls to &dl_sym and &dl_close. When an error occurs +an undef value is returned. +.Ip "&dl_sym($dl_so, $symbol)" 8 2 +Obtains an address binding for the function \fI$symbol\fP as it occurs +in the shared object identified by \fI$dl_so\fP. When an error occurs +an undef value is returned. +.Ip "&dl_call($dl_func, $parms_desc, $return_desc, @parms)" 8 2 +Calls the function identified by \fI$dl_func\fP. The function's entry +parameters are described by \fI$parms_desc\fP and assigned values from +\fI@parms\fP. The function's exit value is described by +\fI$return_desc\fP. An array is returned that contains the values of +any result parameters and the return value. When an error occurs +because of a problem parsing the descriptions or because of an +incorrect parameter count no values are returned (although the +underlying function may have been called). +.Sp +The descriptions are sequences of characters that give the order and +type of parameters: +.nf + + c A signed char value. + C An unsigned char value. + s A signed short value. + S An unsigned short value. + i A signed integer value. + I An unsigned integer value. + l A signed long value. + L An unsigned long value. + f A single-precision float. + d A double-precision float. + a An ascii (null-terminated) string. + p A pointer to <length> buffer. + +.fi +Each letter may optionally be preceded by a number that gives a repeat +count. An array is specified by a preceding \fI[array_size\fP] (or +\fI&\fP as a shorthand for \fI[1]\fP). (Multi-dimension arrays are not +currently supported.) Each scalar or array element is initialized from +\fI@parms\fP. A preceding \fI-\fP leaves the parameter uninitialized. +Type \fIp\fP expects a preceding \fI<buffer_length>\fP. A preceding +\fI+\fP specifies that after the function is called that particular +parameter's value is to be returned (multiple values are returned for +array types, a \fI+\fP with a integral type like \fIi\fP returns an +undef value). The \fI$return_desc\fP contains only one letter with no +repeat count, \fI-\fP or \fI+\fP. +.Sp +An undef or zero-length \fI$parm_desc\fP means the function has no +parameters. An undef or a zero-length \fI$return_desc\fP means the +function returns void. Strings or buffers that must be a specific +length (because the values are overwritten) must be pre-extended. +Although type \fIf\fP is supported, compilers typically pass floats as +doubles. +.Ip "&dl_close($dl_so)" 8 2 +Removes the shared object identified by \fI$dl_so\fP from +\fIdlperl\fP's address space. If successful, a value of zero is +returned. When an error occurs a non-zero value is returned. +.Sh "Predefined Names" +The following names have special meaning to \fIdlperl\fP. +.Ip $DL_VERSION 8 +The version of \fIdlperl\fP. This variable is read-only. +.Ip $DL_WARN 8 +The current value of the \fIdlperl\fP warning flag. Default is 1. If +non-zero, when errors occur warnings are sent to standard error. The +warning is the same information that is stored in $dl_errstr. +.Ip $dl_errno 8 +The error number for the error that occurred. If a \fIdlperl\fP +subroutine completes successfully $dl_errno is set to zero. This variable +is read-only. +.Ip $dl_errstr 8 +The error message for the error that occurred. If a \fIdlperl\fP +subroutine completes successfully $dl_errstr is set to a zero length +string. This variable is read-only. +.SH EXAMPLES +This is an example of calling a simple C function: +.Sp +.nf + open(OUT, ">example.c"); + print OUT <<'EOC'; + void + example(a1, a2, i1, d1, a3) + char *a1[2]; + char *a2[2]; + int i1; + double *d1; + char *a3[4]; + { + a3[i1 + (int) *d1] = a1[0]; + a3[i1 * (int) *d1] = a1[1]; + a3[(int) *d1 - i1] = a2[0]; + a3[(int) *d1 - 2 * i1] = a2[1]; + } + EOC + close(OUT); + + system("cc -c example.c;ld -o example.so example.o"); + + $dl_so = &dl_open("example.so"); + die "$0: $dl_errstr" if($dl_errno); + + $dl_func = &dl_sym($dl_so, "example"); + die "$0: $dl_errstr" if($dl_errno); + + $dl_func =~ s/(['\e\e])/\e\e$1/g; + eval <<EOC; + sub example { + &dl_call('$dl_func', "2[2]a i &d -+[4]a", undef, @_); + } + EOC + + @vals = &example("hacker,", "Perl", "another", "Just", 1, 2); + print "@vals\en"; + + &dl_close($dl_so); + die "$0: $dl_errstr" if($dl_errno); + + unlink('example.c', 'example.o', 'example.so'); +.fi +.LP +If a more complicated interface is needed, the dynamically linked +function can define \fIusubs\fP by calling internal \fIperl\fP +functions. +.SH AUTHOR +Eric Fifer <egf@sbi.com> +.SH SEE ALSO +.BR perl (1), +.BR dlopen (3X), +.BR ld (1) +.SH BUGS +Additional parameter types should be implemented to support structures, +multi-dimension arrays, pointers to arrays, pointers to functions, etc. +.LP +Unlike the \fIpack\fP operator, the repeat count precedes the letter in +the \fI$parm_desc\fP syntax. The array size preceding the parameter +letter is also unconventional. +.LP +All errors set $dl_errno to 1. +.rn }` '' diff --git a/dlperl/usersub.c b/dlperl/usersub.c new file mode 100644 index 0000000000..4ba3d6d639 --- /dev/null +++ b/dlperl/usersub.c @@ -0,0 +1,72 @@ +/* $RCSfile: usersub.c,v $$Revision: 4.0.1.1 $$Date: 91/11/05 19:07:24 $ + * + * $Log: usersub.c,v $ + * Revision 4.0.1.1 91/11/05 19:07:24 lwall + * patch11: there are now subroutines for calling back from C into Perl + * + * Revision 4.0 91/03/20 01:56:34 lwall + * 4.0 baseline. + * + * Revision 3.0.1.1 90/08/09 04:06:10 lwall + * patch19: Initial revision + * + */ + +#include "EXTERN.h" +#include "perl.h" + +int +userinit() +{ + dlperl_init(); +} + +/* Be sure to refetch the stack pointer after calling these routines. */ + +int +callback(subname, sp, gimme, hasargs, numargs) +char *subname; +int sp; /* stack pointer after args are pushed */ +int gimme; /* called in array or scalar context */ +int hasargs; /* whether to create a @_ array for routine */ +int numargs; /* how many args are pushed on the stack */ +{ + static ARG myarg[3]; /* fake syntax tree node */ + int arglast[3]; + + arglast[2] = sp; + sp -= numargs; + arglast[1] = sp--; + arglast[0] = sp; + + if (!myarg[0].arg_ptr.arg_str) + myarg[0].arg_ptr.arg_str = str_make("",0); + + myarg[1].arg_type = A_WORD; + myarg[1].arg_ptr.arg_stab = stabent(subname, FALSE); + + myarg[2].arg_type = hasargs ? A_EXPR : A_NULL; + + return do_subr(myarg, gimme, arglast); +} + +int +callv(subname, sp, gimme, argv) +char *subname; +register int sp; /* current stack pointer */ +int gimme; /* called in array or scalar context */ +register char **argv; /* null terminated arg list, NULL for no arglist */ +{ + register int items = 0; + int hasargs = (argv != 0); + + astore(stack, ++sp, Nullstr); /* reserve spot for 1st return arg */ + if (hasargs) { + while (*argv) { + astore(stack, ++sp, str_2mortal(str_make(*argv,0))); + items++; + argv++; + } + } + return callback(subname, sp, gimme, hasargs, items); +} |