Commit | Line | Data |
79072805 |
1 | static 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 */ |
30 | int Dl_warn = 1; |
31 | int Dl_errno; |
32 | #define DL_ERRSTR_SIZ 256 |
33 | char Dl_errstr[DL_ERRSTR_SIZ]; |
34 | #define WORD_SIZE (sizeof(int)) |
35 | |
36 | static int userval(); |
37 | static int userset(); |
38 | static int usersub(); |
39 | |
40 | |
41 | /* |
42 | * glue perl subroutines and variables to dlperl functions |
43 | */ |
44 | enum usersubs { |
45 | US_dl_open, |
46 | US_dl_sym, |
47 | US_dl_call, |
48 | US_dl_close, |
49 | }; |
50 | |
51 | enum uservars { |
52 | UV_DL_VERSION, |
53 | UV_DL_WARN, |
54 | UV_dl_errno, |
55 | UV_dl_errstr, |
56 | }; |
57 | |
58 | |
59 | int |
60 | dlperl_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*/ |
94 | static int |
95 | userval(ix, str) |
96 | int ix; |
97 | STR *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 | */ |
122 | static int |
123 | userset(ix, str) |
124 | int ix; |
125 | STR *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 | */ |
142 | static int |
143 | usersub(ix, sp, items) |
144 | int ix; |
145 | register int sp; |
146 | register 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) { |
238 | fatal("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 | } |
1007 | ret_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 | } |