perl 5.0 alpha 8
[p5sagit/p5-mst-13.2.git] / dlperl / dlperl.c
CommitLineData
79072805 1static char sccsid[] = "@(#)dlperl.c 1.2 10/12/92 (DLPERL)";
2
3/*
4 * name: dlperl.c
5 * synopsis: dlperl - perl interface to dynamically linked usubs
6 * sccsid: @(#)dlperl.c 1.2 10/12/92
7 */
8
9/*
10 * NOTE: this code is *not* portable
11 * - uses SPARC assembler with gcc asm extensions
12 * - is SPARC ABI specific
13 * - uses SunOS 4.x dlopen
14 *
15 * NOTE: not all types are currently implemented
16 * - multiple indirections (pointers to pointers, etc.)
17 * - structures
18 * - quad-precison (long double)
19 */
20
21#include <dlfcn.h>
22#include <alloca.h>
23#include <ctype.h>
24
25/* perl */
26#include "EXTERN.h"
27#include "perl.h"
28
29/* globals */
30int Dl_warn = 1;
31int Dl_errno;
32#define DL_ERRSTR_SIZ 256
33char Dl_errstr[DL_ERRSTR_SIZ];
34#define WORD_SIZE (sizeof(int))
35
36static int userval();
37static int userset();
38static int usersub();
39
40
41/*
42 * glue perl subroutines and variables to dlperl functions
43 */
44enum usersubs {
45 US_dl_open,
46 US_dl_sym,
47 US_dl_call,
48 US_dl_close,
49};
50
51enum uservars {
52 UV_DL_VERSION,
53 UV_DL_WARN,
54 UV_dl_errno,
55 UV_dl_errstr,
56};
57
58
59int
60dlperl_init()
61{
62 struct ufuncs uf;
63 char *file = "dlperl.c";
64
65 uf.uf_val = userval;
66 uf.uf_set = userset;
67
68#define MAGICVAR(name, ix) uf.uf_index = ix, magicname(name, &uf, sizeof uf)
69
70 /* subroutines */
71 make_usub("dl_open", US_dl_open, usersub, file);
72 make_usub("dl_sym", US_dl_sym, usersub, file);
73 make_usub("dl_call", US_dl_call, usersub, file);
74 make_usub("dl_close", US_dl_close, usersub, file);
75
76 /* variables */
77 MAGICVAR("DL_VERSION", (int) UV_DL_VERSION);
78 MAGICVAR("DL_WARN", (int) UV_DL_WARN);
79 MAGICVAR("dl_errno", (int) UV_dl_errno);
80 MAGICVAR("dl_errstr", (int) UV_dl_errstr);
81
82 return 0;
83}
84
85
86/*
87 * USERVAL AND USERSET
88 */
89
90/*
91 * assign dlperl variables to perl variables
92 */
93/*ARGSUSED*/
94static int
95userval(ix, str)
96int ix;
97STR *str;
98{
99 switch(ix) {
100 case UV_DL_VERSION:
101 str_set(str, sccsid);
102 break;
103 case UV_DL_WARN:
104 str_numset(str, (double) Dl_warn);
105 break;
106 case UV_dl_errno:
107 str_numset(str, (double) Dl_errno);
108 break;
109 case UV_dl_errstr:
110 str_set(str, Dl_errstr);
111 break;
112 default:
113 fatal("dlperl: unimplemented userval");
114 break;
115 }
116 return 0;
117}
118
119/*
120 * assign perl variables to dlperl variables
121 */
122static int
123userset(ix, str)
124int ix;
125STR *str;
126{
127 switch(ix) {
128 case UV_DL_WARN:
129 Dl_warn = (int) str_gnum(str);
130 break;
131 default:
132 fatal("dlperl: unimplemented userset");
133 break;
134 }
135 return 0;
136}
137
138
139/*
140 * USERSUBS
141 */
142static int
143usersub(ix, sp, items)
144int ix;
145register int sp;
146register int items;
147{
148 int oldsp = sp;
149 STR **st = stack->ary_array + sp;
150 register STR *Str; /* used in str_get and str_gnum macros */
151
152 Dl_errno = 0;
153 *Dl_errstr = '\0';
154
155 switch(ix) {
156 case US_dl_open:
157 {
158 char *file;
159 void *dl_so;
160
161 if(items != 1) {
162 fatal("Usage: $dl_so = &dl_open($file)");
163 return oldsp;
164 }
165
166 file = str_get(st[1]);
167 dl_so = dlopen(file, 1);
168
169 --sp;
170 if(dl_so == NULL) {
171 Dl_errno = 1;
172 (void) sprintf(Dl_errstr, "&dl_open: %s", dlerror());
173 if(Dl_warn) warn(Dl_errstr);
174
175 astore(stack, ++sp, str_mortal(&str_undef));
176 } else {
177 astore(stack, ++sp, str_2mortal(str_make(
178 (char *) &dl_so, sizeof(void *))));
179 }
180 break;
181 }
182 case US_dl_sym:
183 {
184 void *dl_so;
185 char *symbol;
186 void *dl_func;
187
188 if(items != 2) {
189 fatal("Usage: $dl_func = &dl_sym($dl_so, $symbol)");
190 return oldsp;
191 }
192
193 dl_so = *(void **) str_get(st[1]);
194 symbol = str_get(st[2]);
195 dl_func = dlsym(dl_so, symbol);
196
197 --sp;
198 if(dl_func == NULL) {
199 Dl_errno = 1;
200 (void) sprintf(Dl_errstr, "&dl_sym: %s", dlerror());
201 if(Dl_warn) warn(Dl_errstr);
202
203 astore(stack, ++sp, str_mortal(&str_undef));
204 } else {
205 astore(stack, ++sp, str_2mortal(str_make(
206 (char *) &dl_func, sizeof(void *))));
207 }
208 break;
209 }
210 case US_dl_call:
211 {
212 void *dl_func;
213 char *parms_desc, *return_desc;
214 int nstack, nparm, narr, nlen, nrep;
215 int f_indirect, f_no_parm, f_result;
216 char c, *c_p; int c_pn = 0;
217 unsigned char C, *C_p; int C_pn = 0;
218 short s, *s_p; int s_pn = 0;
219 unsigned short S, *S_p; int S_pn = 0;
220 int i, *i_p; int i_pn = 0;
221 unsigned int I, *I_p; int I_pn = 0;
222 long l, *l_p; int l_pn = 0;
223 unsigned long L, *L_p; int L_pn = 0;
224 float f, *f_p; int f_pn = 0;
225 double d, *d_p; int d_pn = 0;
226 char *a, **a_p; int a_pn = 0;
227 char *p, **p_p; int p_pn = 0;
228 unsigned int *stack_base, *stack_p;
229 unsigned int *xp;
230 void (*func)();
231 unsigned int ret_o;
232 double ret_fd;
233 float ret_f;
234 char *c1;
235 int n1, n2;
236
237 if(items < 3) {
238fatal("Usage: @vals = &dl_call($dl_func, $parms_desc, $return_desc, @parms)");
239 return oldsp;
240 }
241 dl_func = *(void **) str_get(st[1]);
242 parms_desc = str_get(st[2]);
243 return_desc = str_get(st[3]);
244
245 /* determine size of stack and temporaries */
246# define CNT_STK_TMP(PN, SN) \
247 n2 = 0; do { \
248 if(f_indirect) { \
249 PN += narr; \
250 ++nstack; \
251 if(!f_no_parm) \
252 nparm += narr; \
253 } else { \
254 nstack += SN; \
255 if(!f_no_parm) \
256 ++nparm; \
257 } \
258 } while(++n2 < nrep); \
259 f_indirect = f_no_parm = narr = nrep = 0;
260
261 nstack = 0;
262 nparm = 0;
263 f_indirect = f_no_parm = narr = nrep = 0;
264 for(c1 = parms_desc;*c1;++c1) {
265 switch(*c1) {
266 case ' ':
267 case '\t':
268 break;
269
270 case 'c': /* signed char */
271 CNT_STK_TMP(c_pn, 1);
272 break;
273 case 'C': /* unsigned char */
274 CNT_STK_TMP(C_pn, 1);
275 break;
276 case 's': /* signed short */
277 CNT_STK_TMP(s_pn, 1);
278 break;
279 case 'S': /* unsigned short */
280 CNT_STK_TMP(S_pn, 1);
281 break;
282 case 'i': /* signed int */
283 CNT_STK_TMP(i_pn, 1);
284 break;
285 case 'I': /* unsigned int */
286 CNT_STK_TMP(I_pn, 1);
287 break;
288 case 'l': /* signed long */
289 CNT_STK_TMP(l_pn, 1);
290 break;
291 case 'L': /* unsigned long */
292 CNT_STK_TMP(L_pn, 1);
293 break;
294 case 'f': /* float */
295 CNT_STK_TMP(f_pn, 1);
296 break;
297 case 'd': /* double */
298 CNT_STK_TMP(d_pn, 2);
299 break;
300 case 'a': /* ascii (null-terminated) string */
301 CNT_STK_TMP(a_pn, 1);
302 break;
303 case 'p': /* pointer to <nlen> buffer */
304 CNT_STK_TMP(p_pn, 1);
305 break;
306
307 case '&': /* pointer = [1] */
308 if(f_indirect) {
309 Dl_errno = 1;
310 (void) sprintf(Dl_errstr,
311 "&dl_call: parms_desc %s: too many indirections, with char %c",
312 parms_desc, *c1);
313 if(Dl_warn) warn(Dl_errstr);
314 return oldsp;
315 }
316 f_indirect = 1;
317 narr = 1;
318 break;
319 case '[': /* array */
320 if(f_indirect) {
321 Dl_errno = 1;
322 (void) sprintf(Dl_errstr,
323 "&dl_call: parms_desc %s: too many indirections, with char %c",
324 parms_desc, *c1);
325 if(Dl_warn) warn(Dl_errstr);
326 return oldsp;
327 }
328 f_indirect = 1;
329 ++c1;
330 while(*c1 == ' ' && *c1 == '\t')
331 ++c1;
332 while(isdigit(*c1)) {
333 narr = narr * 10 + (*c1 - '0');
334 ++c1;
335 }
336 while(*c1 == ' ' && *c1 == '\t')
337 ++c1;
338 if(*c1 != ']') {
339 Dl_errno = 1;
340 (void) sprintf(Dl_errstr,
341 "&dl_call: parms_desc %s: bad char %c, expected ]",
342 parms_desc, *c1);
343 if(Dl_warn) warn(Dl_errstr);
344 return oldsp;
345 }
346 break;
347 case '<': /* length */
348 ++c1;
349 while(*c1 == ' ' && *c1 == '\t')
350 ++c1;
351 while(isdigit(*c1))
352 ++c1;
353 while(*c1 == ' ' && *c1 == '\t')
354 ++c1;
355 if(*c1 != '>') {
356 Dl_errno = 1;
357 (void) sprintf(Dl_errstr,
358 "&dl_call: parms_desc %s: bad char %c, expected >",
359 parms_desc, *c1);
360 if(Dl_warn) warn(Dl_errstr);
361 return oldsp;
362 }
363 break;
364 case '+':
365 break;
366 case '-':
367 f_no_parm = 1;
368 break;
369 case '0': case '1': case '2': case '3': case '4':
370 case '5': case '6': case '7': case '8': case '9':
371 if(nrep) {
372 Dl_errno = 1;
373 (void) sprintf(Dl_errstr,
374 "&dl_call: too many repeats");
375 if(Dl_warn) warn(Dl_errstr);
376 return oldsp;
377 }
378 while(isdigit(*c1)) {
379 nrep = nrep * 10 + (*c1 - '0');
380 ++c1;
381 }
382 --c1;
383 break;
384 default:
385 Dl_errno = 1;
386 (void) sprintf(Dl_errstr,
387 "&dl_call: parms_desc %s: bad char %c",
388 parms_desc, *c1);
389 if(Dl_warn) warn(Dl_errstr);
390 return oldsp;
391 }
392 }
393 /* trailing &[]<>+-0-9 is ignored */
394 if(nparm != items - 3) {
395 Dl_errno = 1;
396 (void) sprintf(Dl_errstr,
397 "&dl_call: bad parameter count %d, expected %d",
398 items - 3, nparm);
399 if(Dl_warn) warn(Dl_errstr);
400 return oldsp;
401 }
402 nparm = 4;
403
404 /* allocate temporaries */
405 if((c_pn && (c_p = (char *)
406 alloca(c_pn * sizeof(char))) == NULL) ||
407 (C_pn && (C_p = (unsigned char *)
408 alloca(C_pn * sizeof(unsigned char))) == NULL) ||
409 (s_pn && (s_p = (short *)
410 alloca(s_pn * sizeof(short))) == NULL) ||
411 (S_pn && (S_p = (unsigned short *)
412 alloca(S_pn * sizeof(unsigned short))) == NULL) ||
413 (i_pn && (i_p = (int *)
414 alloca(i_pn * sizeof(int))) == NULL) ||
415 (I_pn && (I_p = (unsigned int *)
416 alloca(I_pn * sizeof(unsigned int))) == NULL) ||
417 (l_pn && (l_p = (long *)
418 alloca(l_pn * sizeof(long))) == NULL) ||
419 (L_pn && (L_p = (unsigned long *)
420 alloca(L_pn * sizeof(unsigned long))) == NULL) ||
421 (f_pn && (f_p = (float *)
422 alloca(f_pn * sizeof(float))) == NULL) ||
423 (d_pn && (d_p = (double *)
424 alloca(d_pn * sizeof(double))) == NULL) ||
425 (a_pn && (a_p = (char **)
426 alloca(a_pn * sizeof(char *))) == NULL) ||
427 (p_pn && (p_p = (char **)
428 alloca(p_pn * sizeof(char *))) == NULL)) {
429 Dl_errno = 1;
430 (void) sprintf(Dl_errstr, "&dl_call: bad alloca");
431 if(Dl_warn) warn(Dl_errstr);
432 return oldsp;
433 }
434
435 /* grow stack - maintains stack alignment (double word) */
436 /* NOTE: no functions should be called otherwise the stack */
437 /* that is being built will be corrupted */
438 /* NOTE: some of the stack is pre-allocated, but is not */
439 /* reused here */
440 if(alloca(nstack * WORD_SIZE) == NULL) {
441 Dl_errno = 1;
442 (void) sprintf(Dl_errstr, "&dl_call: bad alloca");
443 if(Dl_warn) warn(Dl_errstr);
444 return oldsp;
445 }
446
447 /* stack base */
448#if !defined(lint)
449 asm("add %%sp,68,%%o0;st %%o0,%0" :
450 "=g" (stack_base) : /* input */ : "%%o0");
451#else
452 stack_base = 0;
453#endif
454 stack_p = stack_base;
455
456 /* layout stack */
457# define LAY_STK_NUM(T, P, PN) \
458 n2 = 0; do { \
459 if(f_indirect) { \
460 *stack_p++ = (unsigned int) &P[PN]; \
461 if(f_no_parm) { \
462 PN += narr; \
463 } else { \
464 for(n1 = 0;n1 < narr;++n1) { \
465 P[PN++] = (T) \
466 str_gnum(st[nparm++]); \
467 } \
468 } \
469 } else { \
470 if(f_no_parm) { \
471 ++stack_p; \
472 } else { \
473 *stack_p++ = (T) \
474 str_gnum(st[nparm++]); \
475 } \
476 } \
477 } while(++n2 < nrep); \
478 f_indirect = f_no_parm = narr = nrep = 0;
479
480# define LAY_STK_DOUBLE(T, P, PN) \
481 n2 = 0; do { \
482 if(f_indirect) { \
483 *stack_p++ = (unsigned int) &P[PN]; \
484 if(f_no_parm) { \
485 PN += narr; \
486 } else { \
487 for(n1 = 0;n1 < narr;++n1) { \
488 P[PN++] = (T) \
489 str_gnum(st[nparm++]); \
490 } \
491 } \
492 } else { \
493 if(f_no_parm) { \
494 stack_p += 2; \
495 } else { \
496 d = (T) str_gnum(st[nparm++]); \
497 xp = (unsigned int *) &d; \
498 *stack_p++ = *xp++; \
499 *stack_p++ = *xp; \
500 } \
501 } \
502 } while(++n2 < nrep); \
503 f_indirect = f_no_parm = narr = nrep = 0;
504
505# define LAY_STK_STR(P, PN) \
506 n2 = 0; do { \
507 if(f_indirect) { \
508 *stack_p++ = (unsigned int) &P[PN]; \
509 if(f_no_parm) { \
510 PN += narr; \
511 } else { \
512 for(n1 = 0;n1 < narr;++n1) { \
513 P[PN++] = \
514 str_get(st[nparm++]); \
515 } \
516 } \
517 } else { \
518 if(f_no_parm) { \
519 ++stack_p; \
520 } else { \
521 *stack_p++ = (unsigned int) \
522 str_get(st[nparm++]); \
523 } \
524 } \
525 } while(++n2 < nrep); \
526 f_indirect = f_no_parm = narr = nrep = 0;
527
528 c_pn = C_pn = s_pn = S_pn = i_pn = I_pn = l_pn = L_pn = 0;
529 f_pn = d_pn = a_pn = p_pn = 0;
530 f_indirect = f_no_parm = narr = nrep = 0;
531 for(c1 = parms_desc;*c1;++c1) {
532 switch(*c1) {
533 case ' ':
534 case '\t':
535 break;
536
537 case 'c': /* signed char */
538 LAY_STK_NUM(char, c_p, c_pn);
539 break;
540 case 'C': /* unsigned char */
541 LAY_STK_NUM(unsigned char, C_p, C_pn);
542 break;
543 case 's': /* signed short */
544 LAY_STK_NUM(short, s_p, s_pn);
545 break;
546 case 'S': /* unsigned short */
547 LAY_STK_NUM(unsigned short, S_p, S_pn);
548 break;
549 case 'i': /* signed int */
550 LAY_STK_NUM(int, i_p, i_pn);
551 break;
552 case 'I': /* unsigned int */
553 LAY_STK_NUM(unsigned int, I_p, I_pn);
554 break;
555 case 'l': /* signed long */
556 LAY_STK_NUM(long, l_p, l_pn);
557 break;
558 case 'L': /* unsigned long */
559 LAY_STK_NUM(unsigned long, L_p, L_pn);
560 break;
561 case 'f': /* float */
562 LAY_STK_NUM(float, f_p, f_pn);
563 break;
564 case 'd': /* double */
565 LAY_STK_DOUBLE(double, d_p, d_pn);
566 break;
567 case 'a': /* ascii (null-terminated) string */
568 LAY_STK_STR(a_p, a_pn);
569 break;
570 case 'p': /* pointer to <nlen> buffer */
571 LAY_STK_STR(p_p, p_pn);
572 break;
573
574 case '&': /* pointer = [1] */
575 if(f_indirect) {
576 Dl_errno = 1;
577 (void) sprintf(Dl_errstr,
578 "&dl_call: parms_desc %s: too many indirections, with char %c",
579 parms_desc, *c1);
580 if(Dl_warn) warn(Dl_errstr);
581 return oldsp;
582 }
583 f_indirect = 1;
584 narr = 1;
585 break;
586 case '[': /* array */
587 if(f_indirect) {
588 Dl_errno = 1;
589 (void) sprintf(Dl_errstr,
590 "&dl_call: parms_desc %s: too many indirections, with char %c",
591 parms_desc, *c1);
592 if(Dl_warn) warn(Dl_errstr);
593 return oldsp;
594 }
595 f_indirect = 1;
596 ++c1;
597 while(*c1 == ' ' && *c1 == '\t')
598 ++c1;
599 while(isdigit(*c1)) {
600 narr = narr * 10 + (*c1 - '0');
601 ++c1;
602 }
603 while(*c1 == ' ' && *c1 == '\t')
604 ++c1;
605 if(*c1 != ']') {
606 Dl_errno = 1;
607 (void) sprintf(Dl_errstr,
608 "&dl_call: parms_desc %s: bad char %c, expected ]",
609 parms_desc, *c1);
610 if(Dl_warn) warn(Dl_errstr);
611 return oldsp;
612 }
613 break;
614 case '<': /* length */
615 ++c1;
616 while(*c1 == ' ' && *c1 == '\t')
617 ++c1;
618 while(isdigit(*c1))
619 ++c1;
620 while(*c1 == ' ' && *c1 == '\t')
621 ++c1;
622 if(*c1 != '>') {
623 Dl_errno = 1;
624 (void) sprintf(Dl_errstr,
625 "&dl_call: parms_desc %s: bad char %c, expected >",
626 parms_desc, *c1);
627 if(Dl_warn) warn(Dl_errstr);
628 return oldsp;
629 }
630 break;
631 case '+':
632 break;
633 case '-':
634 f_no_parm = 1;
635 break;
636 case '0': case '1': case '2': case '3': case '4':
637 case '5': case '6': case '7': case '8': case '9':
638 if(nrep) {
639 Dl_errno = 1;
640 (void) sprintf(Dl_errstr,
641 "&dl_call: too many repeats");
642 if(Dl_warn) warn(Dl_errstr);
643 return oldsp;
644 }
645 while(isdigit(*c1)) {
646 nrep = nrep * 10 + (*c1 - '0');
647 ++c1;
648 }
649 --c1;
650 break;
651 default:
652 Dl_errno = 1;
653 (void) sprintf(Dl_errstr,
654 "&dl_call: parms_desc %s: bad char %c",
655 parms_desc, *c1);
656 if(Dl_warn) warn(Dl_errstr);
657 return oldsp;
658 }
659 }
660 /* trailing &[]<>+-0-9 is ignored */
661
662 /* call function */
663 /* NOTE: the first 6 words are passed in registers %o0 - %o5 */
664 /* %sp+68 to %sp+92 are vacant, but allocated */
665 /* and shadow %o0 - %o5 */
666 /* above stack_base starts at %sp+68 and the function */
667 /* call below sets up %o0 - %o5 from stack_base */
668 func = (void (*)()) dl_func;
669 (*func)(stack_base[0], stack_base[1], stack_base[2],
670 stack_base[3], stack_base[4], stack_base[5]);
671
672 /* save return value */
673 /* NOTE: return values are either in %o0 or %f0 */
674#if !defined(lint)
675 asm("st %%o0,%0" : "=g" (ret_o) : /* input */);
676 asm("std %%f0,%0" : "=g" (ret_fd) : /* input */);
677 asm("st %%f0,%0" : "=g" (ret_f) : /* input */);
678#else
679 ret_o = 0; ret_fd = 0.0; ret_f = 0.0;
680#endif
681
682 /* parameter results */
683# define RES_NUM(P, PN, SN) \
684 n2 = 0; do { \
685 if(f_indirect) { \
686 ++nstack; \
687 if(f_result) { \
688 for(n1 = 0;n1 < narr;++n1) { \
689 astore(stack, ++sp, str_2mortal( \
690 str_nmake((double) P[PN++]))); \
691 } \
692 } else { \
693 PN += narr; \
694 } \
695 } else { \
696 nstack += SN; \
697 if(f_result) { \
698 astore(stack, ++sp, \
699 str_mortal(&str_undef));\
700 } \
701 } \
702 } while(++n2 < nrep); \
703 f_indirect = f_result = narr = nlen = nrep = 0;
704
705# define RES_STR(P, PN, L, SN) \
706 n2 = 0; do { \
707 if(f_indirect) { \
708 ++nstack; \
709 if(f_result) { \
710 for(n1 = 0;n1 < narr;++n1) { \
711 astore(stack, ++sp, str_2mortal( \
712 str_make(P[PN++], L))); \
713 } \
714 } else { \
715 PN += narr; \
716 } \
717 } else { \
718 if(f_result) { \
719 astore(stack, ++sp, str_2mortal(\
720 str_make((char *) \
721 stack_base[nstack], L))); \
722 } \
723 nstack += SN; \
724 } \
725 } while(++n2 < nrep); \
726 f_indirect = f_result = narr = nlen = nrep = 0;
727
728 --sp;
729 nstack = 0;
730 c_pn = C_pn = s_pn = S_pn = i_pn = I_pn = l_pn = L_pn = 0;
731 f_pn = d_pn = a_pn = p_pn = 0;
732 f_indirect = f_result = narr = nlen = nrep = 0;
733 for(c1 = parms_desc;*c1;++c1) {
734 switch(*c1) {
735 case ' ':
736 case '\t':
737 break;
738
739 case 'c': /* signed char */
740 RES_NUM(c_p, c_pn, 1);
741 break;
742 case 'C': /* unsigned char */
743 RES_NUM(C_p, C_pn, 1);
744 break;
745 case 's': /* signed short */
746 RES_NUM(s_p, s_pn, 1);
747 break;
748 case 'S': /* unsigned short */
749 RES_NUM(S_p, S_pn, 1);
750 break;
751 case 'i': /* signed int */
752 RES_NUM(i_p, i_pn, 1);
753 break;
754 case 'I': /* unsigned int */
755 RES_NUM(I_p, I_pn, 1);
756 break;
757 case 'l': /* signed long */
758 RES_NUM(l_p, l_pn, 1);
759 break;
760 case 'L': /* unsigned long */
761 RES_NUM(L_p, L_pn, 1);
762 break;
763 case 'f': /* float */
764 RES_NUM(f_p, f_pn, 1);
765 break;
766 case 'd': /* double */
767 RES_NUM(d_p, d_pn, 2);
768 break;
769 case 'a': /* ascii (null-terminated) string */
770 RES_STR(a_p, a_pn, 0, 1);
771 break;
772 case 'p': /* pointer to <nlen> buffer */
773 RES_STR(p_p, p_pn, nlen, 1);
774 break;
775
776 case '&': /* pointer = [1] */
777 if(f_indirect) {
778 Dl_errno = 1;
779 (void) sprintf(Dl_errstr,
780 "&dl_call: parms_desc %s: too many indirections, with char %c",
781 parms_desc, *c1);
782 if(Dl_warn) warn(Dl_errstr);
783 return oldsp;
784 }
785 f_indirect = 1;
786 narr = 1;
787 break;
788 case '[': /* array */
789 if(f_indirect) {
790 Dl_errno = 1;
791 (void) sprintf(Dl_errstr,
792 "&dl_call: parms_desc %s: too many indirections, with char %c",
793 parms_desc, *c1);
794 if(Dl_warn) warn(Dl_errstr);
795 return oldsp;
796 }
797 f_indirect = 1;
798 ++c1;
799 while(*c1 == ' ' && *c1 == '\t')
800 ++c1;
801 while(isdigit(*c1)) {
802 narr = narr * 10 + (*c1 - '0');
803 ++c1;
804 }
805 while(*c1 == ' ' && *c1 == '\t')
806 ++c1;
807 if(*c1 != ']') {
808 Dl_errno = 1;
809 (void) sprintf(Dl_errstr,
810 "&dl_call: parms_desc %s: bad char %c, expected ]",
811 parms_desc, *c1);
812 if(Dl_warn) warn(Dl_errstr);
813 return oldsp;
814 }
815 break;
816 case '<': /* length */
817 ++c1;
818 while(*c1 == ' ' && *c1 == '\t')
819 ++c1;
820 while(isdigit(*c1)) {
821 nlen = nlen * 10 + (*c1 - '0');
822 ++c1;
823 }
824 while(*c1 == ' ' && *c1 == '\t')
825 ++c1;
826 if(*c1 != '>') {
827 Dl_errno = 1;
828 (void) sprintf(Dl_errstr,
829 "&dl_call: parms_desc %s: bad char %c, expected >",
830 parms_desc, *c1);
831 if(Dl_warn) warn(Dl_errstr);
832 return oldsp;
833 }
834 break;
835 case '+':
836 f_result = 1;
837 break;
838 case '-':
839 break;
840 case '0': case '1': case '2': case '3': case '4':
841 case '5': case '6': case '7': case '8': case '9':
842 if(nrep) {
843 Dl_errno = 1;
844 (void) sprintf(Dl_errstr,
845 "&dl_call: too many repeats");
846 if(Dl_warn) warn(Dl_errstr);
847 return oldsp;
848 }
849 while(isdigit(*c1)) {
850 nrep = nrep * 10 + (*c1 - '0');
851 ++c1;
852 }
853 --c1;
854 break;
855 default:
856 Dl_errno = 1;
857 (void) sprintf(Dl_errstr,
858 "&dl_call: parms_desc %s: bad char %c",
859 parms_desc, *c1);
860 if(Dl_warn) warn(Dl_errstr);
861 return oldsp;
862 }
863 }
864 /* trailing &[]<>+-0-9 is ignored */
865
866 /* return value */
867# define RET_NUM(T, S, P, R) \
868 if(f_indirect) { \
869 P = (T *) ret_o; \
870 for(n1 = 0;n1 < narr;++n1) { \
871 S = *P++; \
872 astore(stack, ++sp, str_2mortal( \
873 str_nmake((double) S))); \
874 } \
875 } else { \
876 S = (T) R; \
877 astore(stack, ++sp, str_2mortal( \
878 str_nmake((double) S))); \
879 }
880
881# define RET_STR(S, P, L) \
882 if(f_indirect) { \
883 P = (char **) ret_o; \
884 for(n1 = 0;n1 < narr;++n1) { \
885 S = *P++; \
886 astore(stack, ++sp, str_2mortal( \
887 str_make((char *) S, L))); \
888 } \
889 } else { \
890 S = (char *) ret_o; \
891 astore(stack, ++sp, str_2mortal( \
892 str_make((char *) S, L))); \
893 }
894
895 f_indirect = nlen = narr = 0;
896 for(c1 = return_desc;*c1;++c1) {
897 switch(*c1) {
898 case ' ':
899 case '\t':
900 break;
901
902 case 'c': /* signed char */
903 RET_NUM(char, c, c_p, ret_o);
904 goto ret_exit;
905 case 'C': /* unsigned char */
906 RET_NUM(unsigned char, C, C_p, ret_o);
907 goto ret_exit;
908 case 's': /* signed short */
909 RET_NUM(short, s, s_p, ret_o);
910 goto ret_exit;
911 case 'S': /* unsigned short */
912 RET_NUM(unsigned short, S, S_p, ret_o);
913 goto ret_exit;
914 case 'i': /* signed int */
915 RET_NUM(int, i, i_p, ret_o);
916 goto ret_exit;
917 case 'I': /* unsigned int */
918 RET_NUM(unsigned int, I, I_p, ret_o);
919 goto ret_exit;
920 case 'l': /* signed long */
921 RET_NUM(long, l, l_p, ret_o);
922 goto ret_exit;
923 case 'L': /* unsigned long */
924 RET_NUM(unsigned long, L, L_p, ret_o);
925 goto ret_exit;
926 case 'f': /* float */
927 RET_NUM(float, f, f_p, ret_f);
928 break;
929 case 'd': /* double */
930 RET_NUM(double, d, d_p, ret_fd);
931 goto ret_exit;
932 case 'a': /* ascii (null-terminated) string */
933 RET_STR(a, a_p, 0);
934 goto ret_exit;
935 case 'p': /* pointer to <nlen> buffer */
936 RET_STR(p, p_p, nlen);
937 goto ret_exit;
938
939 case '&': /* pointer = [1] */
940 if(f_indirect) {
941 Dl_errno = 1;
942 (void) sprintf(Dl_errstr,
943 "&dl_call: return_desc %s: too many indirections, with char %c",
944 return_desc, *c1);
945 if(Dl_warn) warn(Dl_errstr);
946 return oldsp;
947 }
948 f_indirect = 1;
949 narr = 1;
950 break;
951 case '[': /* array */
952 if(f_indirect) {
953 Dl_errno = 1;
954 (void) sprintf(Dl_errstr,
955 "&dl_call: return_desc %s: too many indirections, with char %c",
956 return_desc, *c1);
957 if(Dl_warn) warn(Dl_errstr);
958 return oldsp;
959 }
960 f_indirect = 1;
961 ++c1;
962 while(*c1 == ' ' && *c1 == '\t')
963 ++c1;
964 while(isdigit(*c1)) {
965 narr = narr * 10 + (*c1 - '0');
966 ++c1;
967 }
968 while(*c1 == ' ' && *c1 == '\t')
969 ++c1;
970 if(*c1 != ']') {
971 Dl_errno = 1;
972 (void) sprintf(Dl_errstr,
973 "&dl_call: return_desc %s: bad char %c, expected ]",
974 return_desc, *c1);
975 if(Dl_warn) warn(Dl_errstr);
976 return oldsp;
977 }
978 break;
979 case '<': /* length */
980 ++c1;
981 while(*c1 == ' ' && *c1 == '\t')
982 ++c1;
983 while(isdigit(*c1)) {
984 nlen = nlen * 10 + (*c1 - '0');
985 ++c1;
986 }
987 while(*c1 == ' ' && *c1 == '\t')
988 ++c1;
989 if(*c1 != '>') {
990 Dl_errno = 1;
991 (void) sprintf(Dl_errstr,
992 "&dl_call: return_desc %s: bad char %c, expected >",
993 return_desc, *c1);
994 if(Dl_warn) warn(Dl_errstr);
995 return oldsp;
996 }
997 break;
998 default:
999 Dl_errno = 1;
1000 (void) sprintf(Dl_errstr,
1001 "&dl_call: return_desc %s: bad char %c",
1002 return_desc, *c1);
1003 if(Dl_warn) warn(Dl_errstr);
1004 return oldsp;
1005 }
1006 }
1007ret_exit: /* anything beyond first [cCsSiIlLdfap] is ignored */
1008 break;
1009 }
1010 case US_dl_close:
1011 {
1012 void *dl_so;
1013 int dl_err;
1014
1015 if(items != 1) {
1016 fatal("Usage: $dl_err = &dl_close($dl_so)");
1017 return oldsp;
1018 }
1019
1020 dl_so = *(void **) str_get(st[1]);
1021 dl_err = dlclose(dl_so);
1022
1023 --sp;
1024 if(dl_err) {
1025 Dl_errno = 1;
1026 (void) sprintf(Dl_errstr, "&dl_close: %s", dlerror());
1027 if(Dl_warn) warn(Dl_errstr);
1028 }
1029 astore(stack, ++sp, str_2mortal(str_nmake((double) dl_err)));
1030 break;
1031 }
1032 default:
1033 fatal("dlperl: unimplemented usersub");
1034 break;
1035 }
1036 return sp;
1037}