This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
The first big import towards 5.8.1, @18078. Please do NOT
[perl5.git] / ext / List / Util / Util.xs
1 /* Copyright (c) 1997-2000 Graham Barr <gbarr@pobox.com>. All rights reserved.
2  * This program is free software; you can redistribute it and/or
3  * modify it under the same terms as Perl itself.
4  */
5
6 #include <EXTERN.h>
7 #include <perl.h>
8 #include <XSUB.h>
9
10 #ifndef PERL_VERSION
11 #    include "patchlevel.h"
12 #    define PERL_REVISION       5
13 #    define PERL_VERSION        PATCHLEVEL
14 #    define PERL_SUBVERSION     SUBVERSION
15 #endif
16
17 #ifndef aTHX
18 #  define aTHX
19 #  define pTHX
20 #endif
21
22 /* Some platforms have strict exports. And before 5.7.3 cxinc (or Perl_cxinc)
23    was not exported. Therefore platforms like win32, VMS etc have problems
24    so we redefine it here -- GMB
25 */
26 #if PERL_VERSION < 7
27 /* Not in 5.6.1. */
28 #  define SvUOK(sv)           SvIOK_UV(sv)
29 #  ifdef cxinc
30 #    undef cxinc
31 #  endif
32 #  define cxinc() my_cxinc(aTHX)
33 static I32
34 my_cxinc(pTHX)
35 {
36     cxstack_max = cxstack_max * 3 / 2;
37     Renew(cxstack, cxstack_max + 1, struct context);      /* XXX should fix CXINC macro */
38     return cxstack_ix + 1;
39 }
40 #endif
41
42 #if PERL_VERSION < 6
43 #    define NV double
44 #endif
45
46 #ifdef SVf_IVisUV
47 #  define slu_sv_value(sv) (NV)(SvIOK(sv) ? SvIOK_UV(sv) ? SvUVX(sv) : SvIVX(sv) : SvNV(sv))
48 #else
49 #  define slu_sv_value(sv) (NV)(SvIOK(sv) ? SvIVX(sv) : SvNV(sv))
50 #endif
51
52 #ifndef Drand01
53 #    define Drand01()           ((rand() & 0x7FFF) / (double) ((unsigned long)1 << 15))
54 #endif
55
56 #if PERL_VERSION < 5
57 #  ifndef gv_stashpvn
58 #    define gv_stashpvn(n,l,c) gv_stashpv(n,c)
59 #  endif
60 #  ifndef SvTAINTED
61
62 static bool
63 sv_tainted(SV *sv)
64 {
65     if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
66         MAGIC *mg = mg_find(sv, 't');
67         if (mg && ((mg->mg_len & 1) || (mg->mg_len & 2) && mg->mg_obj == sv))
68             return TRUE;
69     }
70     return FALSE;
71 }
72
73 #    define SvTAINTED_on(sv) sv_magic((sv), Nullsv, 't', Nullch, 0)
74 #    define SvTAINTED(sv) (SvMAGICAL(sv) && sv_tainted(sv))
75 #  endif
76 #  define PL_defgv defgv
77 #  define PL_op op
78 #  define PL_curpad curpad
79 #  define CALLRUNOPS runops
80 #  define PL_curpm curpm
81 #  define PL_sv_undef sv_undef
82 #  define PERL_CONTEXT struct context
83 #endif
84 #if (PERL_VERSION < 5) || (PERL_VERSION == 5 && PERL_SUBVERSION <50)
85 #  ifndef PL_tainting
86 #    define PL_tainting tainting
87 #  endif
88 #  ifndef PL_stack_base
89 #    define PL_stack_base stack_base
90 #  endif
91 #  ifndef PL_stack_sp
92 #    define PL_stack_sp stack_sp
93 #  endif
94 #  ifndef PL_ppaddr
95 #    define PL_ppaddr ppaddr
96 #  endif
97 #endif
98
99 #ifndef PTR2IV
100 #  define PTR2IV(ptr) (IV)(ptr)
101 #endif
102
103 MODULE=List::Util       PACKAGE=List::Util
104
105 void
106 min(...)
107 PROTOTYPE: @
108 ALIAS:
109     min = 0
110     max = 1
111 CODE:
112 {
113     int index;
114     NV retval;
115     SV *retsv;
116     if(!items) {
117         XSRETURN_UNDEF;
118     }
119     retsv = ST(0);
120     retval = slu_sv_value(retsv);
121     for(index = 1 ; index < items ; index++) {
122         SV *stacksv = ST(index);
123         NV val = slu_sv_value(stacksv);
124         if(val < retval ? !ix : ix) {
125             retsv = stacksv;
126             retval = val;
127         }
128     }
129     ST(0) = retsv;
130     XSRETURN(1);
131 }
132
133
134
135 NV
136 sum(...)
137 PROTOTYPE: @
138 CODE:
139 {
140     SV *sv;
141     int index;
142     if(!items) {
143         XSRETURN_UNDEF;
144     }
145     sv = ST(0);
146     RETVAL = slu_sv_value(sv);
147     for(index = 1 ; index < items ; index++) {
148         sv = ST(index);
149         RETVAL += slu_sv_value(sv);
150     }
151 }
152 OUTPUT:
153     RETVAL
154
155
156 void
157 minstr(...)
158 PROTOTYPE: @
159 ALIAS:
160     minstr = 2
161     maxstr = 0
162 CODE:
163 {
164     SV *left;
165     int index;
166     if(!items) {
167         XSRETURN_UNDEF;
168     }
169     /*
170       sv_cmp & sv_cmp_locale return 1,0,-1 for gt,eq,lt
171       so we set ix to the value we are looking for
172       xsubpp does not allow -ve values, so we start with 0,2 and subtract 1
173     */
174     ix -= 1;
175     left = ST(0);
176 #ifdef OPpLOCALE
177     if(MAXARG & OPpLOCALE) {
178         for(index = 1 ; index < items ; index++) {
179             SV *right = ST(index);
180             if(sv_cmp_locale(left, right) == ix)
181                 left = right;
182         }
183     }
184     else {
185 #endif
186         for(index = 1 ; index < items ; index++) {
187             SV *right = ST(index);
188             if(sv_cmp(left, right) == ix)
189                 left = right;
190         }
191 #ifdef OPpLOCALE
192     }
193 #endif
194     ST(0) = left;
195     XSRETURN(1);
196 }
197
198
199
200 void
201 reduce(block,...)
202     SV * block
203 PROTOTYPE: &@
204 CODE:
205 {
206     SV *ret;
207     int index;
208     GV *agv,*bgv,*gv;
209     HV *stash;
210     CV *cv;
211     OP *reducecop;
212     PERL_CONTEXT *cx;
213     SV** newsp;
214     I32 gimme = G_SCALAR;
215     I32 hasargs = 0;
216     bool oldcatch = CATCH_GET;
217
218     if(items <= 1) {
219         XSRETURN_UNDEF;
220     }
221     agv = gv_fetchpv("a", TRUE, SVt_PV);
222     bgv = gv_fetchpv("b", TRUE, SVt_PV);
223     SAVESPTR(GvSV(agv));
224     SAVESPTR(GvSV(bgv));
225     cv = sv_2cv(block, &stash, &gv, 0);
226     reducecop = CvSTART(cv);
227     SAVESPTR(CvROOT(cv)->op_ppaddr);
228     CvROOT(cv)->op_ppaddr = PL_ppaddr[OP_NULL];
229     SAVESPTR(PL_curpad);
230     PL_curpad = AvARRAY((AV*)AvARRAY(CvPADLIST(cv))[1]);
231     SAVETMPS;
232     SAVESPTR(PL_op);
233     ret = ST(1);
234     CATCH_SET(TRUE);
235     PUSHBLOCK(cx, CXt_SUB, SP);
236     PUSHSUB(cx);
237     if (!CvDEPTH(cv))
238         (void)SvREFCNT_inc(cv);
239     for(index = 2 ; index < items ; index++) {
240         GvSV(agv) = ret;
241         GvSV(bgv) = ST(index);
242         PL_op = reducecop;
243         CALLRUNOPS(aTHX);
244         ret = *PL_stack_sp;
245     }
246     ST(0) = sv_mortalcopy(ret);
247     POPBLOCK(cx,PL_curpm);
248     CATCH_SET(oldcatch);
249     XSRETURN(1);
250 }
251
252 void
253 first(block,...)
254     SV * block
255 PROTOTYPE: &@
256 CODE:
257 {
258     int index;
259     GV *gv;
260     HV *stash;
261     CV *cv;
262     OP *reducecop;
263     PERL_CONTEXT *cx;
264     SV** newsp;
265     I32 gimme = G_SCALAR;
266     I32 hasargs = 0;
267     bool oldcatch = CATCH_GET;
268
269     if(items <= 1) {
270         XSRETURN_UNDEF;
271     }
272     SAVESPTR(GvSV(PL_defgv));
273     cv = sv_2cv(block, &stash, &gv, 0);
274     reducecop = CvSTART(cv);
275     SAVESPTR(CvROOT(cv)->op_ppaddr);
276     CvROOT(cv)->op_ppaddr = PL_ppaddr[OP_NULL];
277     SAVESPTR(PL_curpad);
278     PL_curpad = AvARRAY((AV*)AvARRAY(CvPADLIST(cv))[1]);
279     SAVETMPS;
280     SAVESPTR(PL_op);
281     CATCH_SET(TRUE);
282     PUSHBLOCK(cx, CXt_SUB, SP);
283     PUSHSUB(cx);
284     if (!CvDEPTH(cv))
285         (void)SvREFCNT_inc(cv);
286
287     for(index = 1 ; index < items ; index++) {
288         GvSV(PL_defgv) = ST(index);
289         PL_op = reducecop;
290         CALLRUNOPS(aTHX);
291         if (SvTRUE(*PL_stack_sp)) {
292           ST(0) = ST(index);
293           POPBLOCK(cx,PL_curpm);
294           CATCH_SET(oldcatch);
295           XSRETURN(1);
296         }
297     }
298     POPBLOCK(cx,PL_curpm);
299     CATCH_SET(oldcatch);
300     XSRETURN_UNDEF;
301 }
302
303 void
304 shuffle(...)
305 PROTOTYPE: @
306 CODE:
307 {
308     int index;
309     struct op dmy_op;
310     struct op *old_op = PL_op;
311     SV *my_pad[2];
312     SV **old_curpad = PL_curpad;
313
314     /* We call pp_rand here so that Drand01 get initialized if rand()
315        or srand() has not already been called
316     */
317     my_pad[1] = sv_newmortal();
318     memzero((char*)(&dmy_op), sizeof(struct op));
319     dmy_op.op_targ = 1;
320     PL_op = &dmy_op;
321     PL_curpad = (SV **)&my_pad;
322     (void)*(PL_ppaddr[OP_RAND])(aTHX);
323     PL_op = old_op;
324     PL_curpad = old_curpad;
325     for (index = items ; index > 1 ; ) {
326         int swap = (int)(Drand01() * (double)(index--));
327         SV *tmp = ST(swap);
328         ST(swap) = ST(index);
329         ST(index) = tmp;
330     }
331     XSRETURN(items);
332 }
333
334
335 MODULE=List::Util       PACKAGE=Scalar::Util
336
337 void
338 dualvar(num,str)
339     SV *        num
340     SV *        str
341 PROTOTYPE: $$
342 CODE:
343 {
344     STRLEN len;
345     char *ptr = SvPV(str,len);
346     ST(0) = sv_newmortal();
347     (void)SvUPGRADE(ST(0),SVt_PVNV);
348     sv_setpvn(ST(0),ptr,len);
349     if(SvNOK(num) || SvPOK(num) || SvMAGICAL(num)) {
350         SvNVX(ST(0)) = SvNV(num);
351         SvNOK_on(ST(0));
352     }
353 #ifdef SVf_IVisUV
354     else if (SvUOK(num)) {
355         SvUVX(ST(0)) = SvUV(num);
356         SvIOK_on(ST(0));
357         SvIsUV_on(ST(0));
358     }
359 #endif
360     else {
361         SvIVX(ST(0)) = SvIV(num);
362         SvIOK_on(ST(0));
363     }
364     if(PL_tainting && (SvTAINTED(num) || SvTAINTED(str)))
365         SvTAINTED_on(ST(0));
366     XSRETURN(1);
367 }
368
369 char *
370 blessed(sv)
371     SV * sv
372 PROTOTYPE: $
373 CODE:
374 {
375     if (SvMAGICAL(sv))
376         mg_get(sv);
377     if(!sv_isobject(sv)) {
378         XSRETURN_UNDEF;
379     }
380     RETVAL = sv_reftype(SvRV(sv),TRUE);
381 }
382 OUTPUT:
383     RETVAL
384
385 char *
386 reftype(sv)
387     SV * sv
388 PROTOTYPE: $
389 CODE:
390 {
391     if (SvMAGICAL(sv))
392         mg_get(sv);
393     if(!SvROK(sv)) {
394         XSRETURN_UNDEF;
395     }
396     RETVAL = sv_reftype(SvRV(sv),FALSE);
397 }
398 OUTPUT:
399     RETVAL
400
401 IV
402 refaddr(sv)
403     SV * sv
404 PROTOTYPE: $
405 CODE:
406 {
407     if(!SvROK(sv)) {
408         XSRETURN_UNDEF;
409     }
410     RETVAL = PTR2IV(SvRV(sv));
411 }
412 OUTPUT:
413     RETVAL
414
415 void
416 weaken(sv)
417         SV *sv
418 PROTOTYPE: $
419 CODE:
420 #ifdef SvWEAKREF
421         sv_rvweaken(sv);
422 #else
423         croak("weak references are not implemented in this release of perl");
424 #endif
425
426 void
427 isweak(sv)
428         SV *sv
429 PROTOTYPE: $
430 CODE:
431 #ifdef SvWEAKREF
432         ST(0) = boolSV(SvROK(sv) && SvWEAKREF(sv));
433         XSRETURN(1);
434 #else
435         croak("weak references are not implemented in this release of perl");
436 #endif
437
438 int
439 readonly(sv)
440         SV *sv
441 PROTOTYPE: $
442 CODE:
443   RETVAL = SvREADONLY(sv);
444 OUTPUT:
445   RETVAL
446
447 int
448 tainted(sv)
449         SV *sv
450 PROTOTYPE: $
451 CODE:
452   RETVAL = SvTAINTED(sv);
453 OUTPUT:
454   RETVAL
455
456 void
457 isvstring(sv)
458        SV *sv
459 PROTOTYPE: $
460 CODE:
461 #ifdef SvVOK
462   ST(0) = boolSV(SvVOK(sv));
463   XSRETURN(1);
464 #else
465         croak("vstrings are not implemented in this release of perl");
466 #endif
467
468
469 BOOT:
470 {
471 #if !defined(SvWEAKREF) || !defined(SvVOK)
472     HV *stash = gv_stashpvn("Scalar::Util", 12, TRUE);
473     GV *vargv = *(GV**)hv_fetch(stash, "EXPORT_FAIL", 11, TRUE);
474     AV *varav;
475     if (SvTYPE(vargv) != SVt_PVGV)
476         gv_init(vargv, stash, "Scalar::Util", 12, TRUE);
477     varav = GvAVn(vargv);
478 #endif
479 #ifndef SvWEAKREF
480     av_push(varav, newSVpv("weaken",6));
481     av_push(varav, newSVpv("isweak",6));
482 #endif
483 #ifndef SvVOK
484     av_push(varav, newSVpv("isvstring",9));
485 #endif
486 }