Fix a remaining B::Lint bug.
[p5sagit/p5-mst-13.2.git] / ext / PerlIO / Via / Via.xs
CommitLineData
e7a1fdd7 1#define PERL_NO_GET_CONTEXT
2#include "EXTERN.h"
3#include "perl.h"
4#include "XSUB.h"
5#ifdef PERLIO_LAYERS
6
7#include "perliol.h"
8
9typedef struct
10{
11 struct _PerlIO base; /* Base "class" info */
12 HV * stash;
13 SV * obj;
14 SV * var;
15 SSize_t cnt;
e7a1fdd7 16 IO * io;
17 SV * fh;
18 CV *PUSHED;
19 CV *POPPED;
20 CV *OPEN;
21 CV *FDOPEN;
22 CV *SYSOPEN;
23 CV *GETARG;
24 CV *FILENO;
25 CV *READ;
26 CV *WRITE;
27 CV *FILL;
28 CV *CLOSE;
29 CV *SEEK;
30 CV *TELL;
31 CV *UNREAD;
32 CV *FLUSH;
33 CV *SETLINEBUF;
34 CV *CLEARERR;
c7997937 35 CV *mERROR;
e7a1fdd7 36 CV *mEOF;
37} PerlIOVia;
38
39#define MYMethod(x) #x,&s->x
40
41CV *
42PerlIOVia_fetchmethod(pTHX_ PerlIOVia *s,char *method,CV **save)
43{
44 GV *gv = gv_fetchmeth(s->stash,method,strlen(method),0);
45#if 0
46 Perl_warn(aTHX_ "Lookup %s::%s => %p",HvNAME(s->stash),method,gv);
47#endif
48 if (gv)
49 {
50 return *save = GvCV(gv);
51 }
52 else
53 {
54 return *save = (CV *) -1;
55 }
e7a1fdd7 56}
57
d9dac8cd 58/*
59 * Try and call method, possibly via cached lookup.
60 * If method does not exist return Nullsv (caller may fallback to another approach
61 * If method does exist call it with flags passing variable number of args
62 * Last arg is a "filehandle" to layer below (if present)
63 * Returns scalar returned by method (if any) otherwise sv_undef
64 */
65
e7a1fdd7 66SV *
67PerlIOVia_method(pTHX_ PerlIO *f,char *method,CV **save,int flags,...)
68{
69 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
70 CV *cv = (*save) ? *save : PerlIOVia_fetchmethod(aTHX_ s,method,save);
71 SV *result = Nullsv;
72 va_list ap;
73 va_start(ap,flags);
74 if (cv != (CV *)-1)
75 {
76 IV count;
77 dSP;
78 SV *arg;
24f59afc 79 PUSHSTACKi(PERLSI_MAGIC);
e7a1fdd7 80 ENTER;
24f59afc 81 SPAGAIN;
e7a1fdd7 82 PUSHMARK(sp);
83 XPUSHs(s->obj);
84 while ((arg = va_arg(ap,SV *)))
85 {
86 XPUSHs(arg);
87 }
88 if (*PerlIONext(f))
89 {
90 if (!s->fh)
91 {
92 GV *gv = newGVgen(HvNAME(s->stash));
93 GvIOp(gv) = newIO();
94 s->fh = newRV_noinc((SV *)gv);
95 s->io = GvIOp(gv);
96 }
97 IoIFP(s->io) = PerlIONext(f);
98 IoOFP(s->io) = PerlIONext(f);
99 XPUSHs(s->fh);
100 }
d9dac8cd 101 else
102 {
103 PerlIO_debug("No next\n");
104 }
e7a1fdd7 105 PUTBACK;
106 count = call_sv((SV *)cv,flags);
107 if (count)
108 {
109 SPAGAIN;
110 result = POPs;
111 PUTBACK;
112 }
113 else
114 {
115 result = &PL_sv_undef;
116 }
117 LEAVE;
24f59afc 118 POPSTACK;
e7a1fdd7 119 }
120 va_end(ap);
121 return result;
122}
123
124IV
f62ce20a 125PerlIOVia_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg)
e7a1fdd7 126{
f62ce20a 127 IV code = PerlIOBase_pushed(aTHX_ f,mode,Nullsv);
e7a1fdd7 128 if (code == 0)
129 {
e7a1fdd7 130 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
131 if (!arg)
132 {
99ef548b 133 if (ckWARN(WARN_LAYER))
134 Perl_warner(aTHX_ packWARN(WARN_LAYER), "No package specified");
d9dac8cd 135 errno = EINVAL;
e7a1fdd7 136 code = -1;
137 }
138 else
139 {
140 STRLEN pkglen = 0;
141 char *pkg = SvPV(arg,pkglen);
267cbce7 142 s->obj = SvREFCNT_inc(arg);
e7a1fdd7 143 s->stash = gv_stashpvn(pkg, pkglen, FALSE);
144 if (s->stash)
145 {
146 SV *modesv = (mode) ? sv_2mortal(newSVpvn(mode,strlen(mode))) : Nullsv;
147 SV *result = PerlIOVia_method(aTHX_ f,MYMethod(PUSHED),G_SCALAR,modesv,Nullsv);
148 if (result)
149 {
150 if (sv_isobject(result))
267cbce7 151 {
152 s->obj = SvREFCNT_inc(result);
153 SvREFCNT_dec(arg);
154 }
e7a1fdd7 155 else if (SvIV(result) != 0)
156 return SvIV(result);
157 }
158 if (PerlIOVia_fetchmethod(aTHX_ s,MYMethod(FILL)) == (CV *) -1)
159 PerlIOBase(f)->flags &= ~PERLIO_F_FASTGETS;
160 else
161 PerlIOBase(f)->flags |= PERLIO_F_FASTGETS;
162 }
163 else
164 {
99ef548b 165 if (ckWARN(WARN_LAYER))
166 Perl_warner(aTHX_ packWARN(WARN_LAYER), "Cannot find package '%.*s'",(int) pkglen,pkg);
267cbce7 167#ifdef ENOSYS
168 errno = ENOSYS;
169#else
170#ifdef ENOENT
171 errno = ENOENT;
172#endif
173#endif
e7a1fdd7 174 code = -1;
175 }
176 }
177 }
178 return code;
179}
180
181PerlIO *
d9dac8cd 182PerlIOVia_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, IV n,
183 const char *mode, int fd, int imode, int perm,
184 PerlIO *f, int narg, SV **args)
e7a1fdd7 185{
186 if (!f)
187 {
188 f = PerlIO_push(aTHX_ PerlIO_allocate(aTHX),self,mode,PerlIOArg);
189 }
190 else
191 {
d9dac8cd 192 /* Reopen */
e7a1fdd7 193 if (!PerlIO_push(aTHX_ f,self,mode,PerlIOArg))
194 return NULL;
195 }
196 if (f)
197 {
198 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
199 SV *result = Nullsv;
200 if (fd >= 0)
201 {
202 SV *fdsv = sv_2mortal(newSViv(fd));
203 result = PerlIOVia_method(aTHX_ f,MYMethod(FDOPEN),G_SCALAR,fdsv,Nullsv);
204 }
205 else if (narg > 0)
206 {
207 if (*mode == '#')
208 {
209 SV *imodesv = sv_2mortal(newSViv(imode));
210 SV *permsv = sv_2mortal(newSViv(perm));
211 result = PerlIOVia_method(aTHX_ f,MYMethod(SYSOPEN),G_SCALAR,*args,imodesv,permsv,Nullsv);
212 }
213 else
214 {
215 result = PerlIOVia_method(aTHX_ f,MYMethod(OPEN),G_SCALAR,*args,Nullsv);
216 }
217 }
218 if (result)
219 {
220 if (sv_isobject(result))
221 s->obj = SvREFCNT_inc(result);
222 else if (!SvTRUE(result))
223 {
224 return NULL;
225 }
226 }
227 else
d9dac8cd 228 {
229 /* Required open method not present */
230 PerlIO_funcs *tab = NULL;
231 IV m = n-1;
232 while (m >= 0) {
233 PerlIO_funcs *t = PerlIO_layer_fetch(aTHX_ layers, m, NULL);
234 if (t && t->Open) {
235 tab = t;
236 break;
237 }
238 n--;
239 }
240 if (tab) {
241 if ((*tab->Open) (aTHX_ tab, layers, m, mode, fd, imode, perm,
242 PerlIONext(f), narg, args)) {
243 PerlIO_debug("Opened with %s => %p->%p\n",tab->name,PerlIONext(f),*PerlIONext(f));
244 if (m + 1 < n) {
245 /*
246 * More layers above the one that we used to open -
247 * apply them now
248 */
249 if (PerlIO_apply_layera(aTHX_ PerlIONext(f), mode, layers, m+1, n) != 0) {
250 /* If pushing layers fails close the file */
251 PerlIO_close(f);
252 f = NULL;
253 }
254 }
255 return f;
256 }
257 else {
258 /* Sub-layer open failed */
259 }
260 }
261 else {
262 /* Nothing to do the open */
263 }
264 return NULL;
265 }
e7a1fdd7 266 }
267 return f;
268}
269
270IV
f62ce20a 271PerlIOVia_popped(pTHX_ PerlIO *f)
e7a1fdd7 272{
e7a1fdd7 273 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
274 PerlIOVia_method(aTHX_ f,MYMethod(POPPED),G_VOID,Nullsv);
275 if (s->var)
276 {
277 SvREFCNT_dec(s->var);
278 s->var = Nullsv;
279 }
280
281 if (s->io)
282 {
283 IoIFP(s->io) = NULL;
284 IoOFP(s->io) = NULL;
285 }
286 if (s->fh)
287 {
288 SvREFCNT_dec(s->fh);
289 s->fh = Nullsv;
290 s->io = NULL;
291 }
292 if (s->obj)
293 {
294 SvREFCNT_dec(s->obj);
295 s->obj = Nullsv;
296 }
297 return 0;
298}
299
300IV
f62ce20a 301PerlIOVia_close(pTHX_ PerlIO *f)
e7a1fdd7 302{
e7a1fdd7 303 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
f62ce20a 304 IV code = PerlIOBase_close(aTHX_ f);
e7a1fdd7 305 SV *result = PerlIOVia_method(aTHX_ f,MYMethod(CLOSE),G_SCALAR,Nullsv);
306 if (result && SvIV(result) != 0)
307 code = SvIV(result);
308 PerlIOBase(f)->flags &= ~(PERLIO_F_RDBUF|PERLIO_F_WRBUF);
309 return code;
310}
311
312IV
f62ce20a 313PerlIOVia_fileno(pTHX_ PerlIO *f)
e7a1fdd7 314{
e7a1fdd7 315 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
316 SV *result = PerlIOVia_method(aTHX_ f,MYMethod(FILENO),G_SCALAR,Nullsv);
317 return (result) ? SvIV(result) : PerlIO_fileno(PerlIONext(f));
318}
319
320IV
f62ce20a 321PerlIOVia_seek(pTHX_ PerlIO *f, Off_t offset, int whence)
e7a1fdd7 322{
e7a1fdd7 323 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
324 SV *offsv = sv_2mortal(newSViv(offset));
9f16d962 325 SV *whsv = sv_2mortal(newSViv(whence));
e7a1fdd7 326 SV *result = PerlIOVia_method(aTHX_ f,MYMethod(SEEK),G_SCALAR,offsv,whsv,Nullsv);
327 return (result) ? SvIV(result) : -1;
328}
329
330Off_t
f62ce20a 331PerlIOVia_tell(pTHX_ PerlIO *f)
e7a1fdd7 332{
e7a1fdd7 333 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
334 SV *result = PerlIOVia_method(aTHX_ f,MYMethod(TELL),G_SCALAR,Nullsv);
9f16d962 335 return (result) ? (Off_t) SvIV(result) : (Off_t) -1;
e7a1fdd7 336}
337
338SSize_t
f62ce20a 339PerlIOVia_unread(pTHX_ PerlIO *f, const void *vbuf, Size_t count)
e7a1fdd7 340{
e7a1fdd7 341 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
342 SV *buf = sv_2mortal(newSVpvn((char *)vbuf,count));
343 SV *result = PerlIOVia_method(aTHX_ f,MYMethod(UNREAD),G_SCALAR,buf,Nullsv);
344 if (result)
345 return (SSize_t) SvIV(result);
346 else
347 {
f62ce20a 348 return PerlIOBase_unread(aTHX_ f,vbuf,count);
e7a1fdd7 349 }
350}
351
352SSize_t
f62ce20a 353PerlIOVia_read(pTHX_ PerlIO *f, void *vbuf, Size_t count)
e7a1fdd7 354{
355 SSize_t rd = 0;
356 if (PerlIOBase(f)->flags & PERLIO_F_CANREAD)
357 {
358 if (PerlIOBase(f)->flags & PERLIO_F_FASTGETS)
359 {
f62ce20a 360 rd = PerlIOBase_read(aTHX_ f,vbuf,count);
e7a1fdd7 361 }
362 else
363 {
e7a1fdd7 364 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
365 SV *buf = sv_2mortal(newSV(count));
366 SV *n = sv_2mortal(newSViv(count));
367 SV *result = PerlIOVia_method(aTHX_ f,MYMethod(READ),G_SCALAR,buf,n,Nullsv);
368 if (result)
369 {
370 rd = (SSize_t) SvIV(result);
371 Move(SvPVX(buf),vbuf,rd,char);
372 return rd;
373 }
374 }
375 }
376 return rd;
377}
378
379SSize_t
f62ce20a 380PerlIOVia_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count)
e7a1fdd7 381{
382 if (PerlIOBase(f)->flags & PERLIO_F_CANWRITE)
383 {
e7a1fdd7 384 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
385 SV *buf = newSVpvn((char *)vbuf,count);
386 SV *result = PerlIOVia_method(aTHX_ f,MYMethod(WRITE),G_SCALAR,buf,Nullsv);
387 SvREFCNT_dec(buf);
388 if (result)
389 return (SSize_t) SvIV(result);
390 return -1;
391 }
392 return 0;
393}
394
395IV
f62ce20a 396PerlIOVia_fill(pTHX_ PerlIO *f)
e7a1fdd7 397{
398 if (PerlIOBase(f)->flags & PERLIO_F_CANREAD)
399 {
e7a1fdd7 400 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
401 SV *result = PerlIOVia_method(aTHX_ f,MYMethod(FILL),G_SCALAR,Nullsv);
402 if (s->var)
403 {
404 SvREFCNT_dec(s->var);
405 s->var = Nullsv;
406 }
407 if (result && SvOK(result))
408 {
409 STRLEN len = 0;
410 char *p = SvPV(result,len);
411 s->var = newSVpvn(p,len);
412 s->cnt = SvCUR(s->var);
413 return 0;
414 }
415 else
416 PerlIOBase(f)->flags |= PERLIO_F_EOF;
417 }
418 return -1;
419}
420
421IV
f62ce20a 422PerlIOVia_flush(pTHX_ PerlIO *f)
e7a1fdd7 423{
e7a1fdd7 424 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
425 SV *result = PerlIOVia_method(aTHX_ f,MYMethod(FLUSH),G_SCALAR,Nullsv);
426 if (s->var && s->cnt > 0)
427 {
428 SvREFCNT_dec(s->var);
429 s->var = Nullsv;
430 }
431 return (result) ? SvIV(result) : 0;
432}
433
434STDCHAR *
f62ce20a 435PerlIOVia_get_base(pTHX_ PerlIO *f)
e7a1fdd7 436{
437 if (PerlIOBase(f)->flags & PERLIO_F_CANREAD)
438 {
e7a1fdd7 439 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
440 if (s->var)
441 {
442 return (STDCHAR *)SvPVX(s->var);
443 }
444 }
445 return (STDCHAR *) Nullch;
446}
447
448STDCHAR *
f62ce20a 449PerlIOVia_get_ptr(pTHX_ PerlIO *f)
e7a1fdd7 450{
451 if (PerlIOBase(f)->flags & PERLIO_F_CANREAD)
452 {
453 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
454 if (s->var)
455 {
e7a1fdd7 456 STDCHAR *p = (STDCHAR *)(SvEND(s->var) - s->cnt);
457 return p;
458 }
459 }
460 return (STDCHAR *) Nullch;
461}
462
463SSize_t
f62ce20a 464PerlIOVia_get_cnt(pTHX_ PerlIO *f)
e7a1fdd7 465{
466 if (PerlIOBase(f)->flags & PERLIO_F_CANREAD)
467 {
468 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
469 if (s->var)
470 {
471 return s->cnt;
472 }
473 }
474 return 0;
475}
476
477Size_t
f62ce20a 478PerlIOVia_bufsiz(pTHX_ PerlIO *f)
e7a1fdd7 479{
480 if (PerlIOBase(f)->flags & PERLIO_F_CANREAD)
481 {
482 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
483 if (s->var)
484 return SvCUR(s->var);
485 }
486 return 0;
487}
488
489void
f62ce20a 490PerlIOVia_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR *ptr, SSize_t cnt)
e7a1fdd7 491{
492 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
493 s->cnt = cnt;
494}
495
496void
f62ce20a 497PerlIOVia_setlinebuf(pTHX_ PerlIO *f)
e7a1fdd7 498{
e7a1fdd7 499 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
500 PerlIOVia_method(aTHX_ f,MYMethod(SETLINEBUF),G_VOID,Nullsv);
f62ce20a 501 PerlIOBase_setlinebuf(aTHX_ f);
e7a1fdd7 502}
503
504void
f62ce20a 505PerlIOVia_clearerr(pTHX_ PerlIO *f)
e7a1fdd7 506{
e7a1fdd7 507 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
508 PerlIOVia_method(aTHX_ f,MYMethod(CLEARERR),G_VOID,Nullsv);
f62ce20a 509 PerlIOBase_clearerr(aTHX_ f);
e7a1fdd7 510}
511
c7997937 512IV
f62ce20a 513PerlIOVia_error(pTHX_ PerlIO *f)
e7a1fdd7 514{
e7a1fdd7 515 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
c7997937 516 SV *result = PerlIOVia_method(aTHX_ f,"ERROR",&s->mERROR,G_SCALAR,Nullsv);
f62ce20a 517 return (result) ? SvIV(result) : PerlIOBase_error(aTHX_ f);
e7a1fdd7 518}
519
520IV
f62ce20a 521PerlIOVia_eof(pTHX_ PerlIO *f)
e7a1fdd7 522{
e7a1fdd7 523 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
524 SV *result = PerlIOVia_method(aTHX_ f,"EOF",&s->mEOF,G_SCALAR,Nullsv);
f62ce20a 525 return (result) ? SvIV(result) : PerlIOBase_eof(aTHX_ f);
e7a1fdd7 526}
527
ecdeb87c 528SV *
529PerlIOVia_getarg(pTHX_ PerlIO *f, CLONE_PARAMS *param, int flags)
530{
531 PerlIOVia *s = PerlIOSelf(f,PerlIOVia);
532 return PerlIOVia_method(aTHX_ f,MYMethod(GETARG),G_SCALAR,Nullsv);
533}
534
8cf8f3d1 535PerlIO *
ecdeb87c 536PerlIOVia_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int flags)
8cf8f3d1 537{
ecdeb87c 538 if ((f = PerlIOBase_dup(aTHX_ f, o, param, flags)))
9f16d962 539 {
ecdeb87c 540 /* Most of the fields will lazily set themselves up as needed
9f16d962 541 stash and obj have been set up by the implied push
542 */
543 }
544 return f;
8cf8f3d1 545}
546
e7a1fdd7 547PerlIO_funcs PerlIO_object = {
548 "Via",
549 sizeof(PerlIOVia),
550 PERLIO_K_BUFFERED|PERLIO_K_DESTRUCT,
551 PerlIOVia_pushed,
552 PerlIOVia_popped,
d9dac8cd 553 PerlIOVia_open, /* NULL, */
e7a1fdd7 554 PerlIOVia_getarg,
555 PerlIOVia_fileno,
8cf8f3d1 556 PerlIOVia_dup,
e7a1fdd7 557 PerlIOVia_read,
558 PerlIOVia_unread,
559 PerlIOVia_write,
560 PerlIOVia_seek,
561 PerlIOVia_tell,
562 PerlIOVia_close,
563 PerlIOVia_flush,
564 PerlIOVia_fill,
565 PerlIOVia_eof,
566 PerlIOVia_error,
567 PerlIOVia_clearerr,
568 PerlIOVia_setlinebuf,
569 PerlIOVia_get_base,
570 PerlIOVia_bufsiz,
571 PerlIOVia_get_ptr,
572 PerlIOVia_get_cnt,
573 PerlIOVia_set_ptrcnt,
574};
575
576
577#endif /* Layers available */
578
579MODULE = PerlIO::Via PACKAGE = PerlIO::Via
580PROTOTYPES: ENABLE;
581
582BOOT:
583{
584#ifdef PERLIO_LAYERS
585 PerlIO_define_layer(aTHX_ &PerlIO_object);
586#endif
587}
588