#ifdef PERL_IMPLICIT_SYS
# define dSYS dTHX
#else
# define dSYS dNOOP
#endif
#define PERLIO_NOT_STDIO 0
#include "EXTERN.h"
#define PERL_IN_PERLIO_C
#include "perl.h"
#ifdef MULTIPLICITY
# undef dSYS
# define dSYS dTHX
#endif
#include "XSUB.h"
#ifdef VMS
# include <rms.h>
#endif
#define PerlIO_lockcnt(f) (((PerlIOl*)(void*)(f))->head->flags)
#define Perl_PerlIO_or_Base(f, callback, base, failure, args) \
if
(PerlIOValid(f)) { \
const
PerlIO_funcs *
const
tab = PerlIOBase(f)->tab;\
if
(tab && tab->callback) \
return
(*tab->callback) args; \
else
\
return
PerlIOBase_ ## base args; \
} \
else
\
SETERRNO(EBADF, SS_IVCHAN); \
return
failure
#define Perl_PerlIO_or_fail(f, callback, failure, args) \
if
(PerlIOValid(f)) { \
const
PerlIO_funcs *
const
tab = PerlIOBase(f)->tab;\
if
(tab && tab->callback) \
return
(*tab->callback) args; \
SETERRNO(EINVAL, LIB_INVARG); \
} \
else
\
SETERRNO(EBADF, SS_IVCHAN); \
return
failure
#define Perl_PerlIO_or_Base_void(f, callback, base, args) \
if
(PerlIOValid(f)) { \
const
PerlIO_funcs *
const
tab = PerlIOBase(f)->tab;\
if
(tab && tab->callback) \
(*tab->callback) args; \
else
\
PerlIOBase_ ## base args; \
} \
else
\
SETERRNO(EBADF, SS_IVCHAN)
#define Perl_PerlIO_or_fail_void(f, callback, args) \
if
(PerlIOValid(f)) { \
const
PerlIO_funcs *
const
tab = PerlIOBase(f)->tab;\
if
(tab && tab->callback) \
(*tab->callback) args; \
else
\
SETERRNO(EINVAL, LIB_INVARG); \
} \
else
\
SETERRNO(EBADF, SS_IVCHAN)
#if defined(__osf__) && _XOPEN_SOURCE < 500
extern
int
fseeko(
FILE
*, off_t,
int
);
extern
off_t ftello(
FILE
*);
#endif
#define NATIVE_0xd CR_NATIVE
#define NATIVE_0xa LF_NATIVE
EXTERN_C
int
perlsio_binmode(
FILE
*fp,
int
iotype,
int
mode);
int
perlsio_binmode(
FILE
*fp,
int
iotype,
int
mode)
{
#ifdef DOSISH
dTHX;
PERL_UNUSED_ARG(iotype);
if
(PerlLIO_setmode(fileno(fp), mode) != -1) {
return
1;
}
else
return
0;
#else
# if defined(USEMYBINMODE)
dTHX;
# if defined(__CYGWIN__)
PERL_UNUSED_ARG(iotype);
# endif
if
(my_binmode(fp, iotype, mode) != FALSE)
return
1;
else
return
0;
# else
PERL_UNUSED_ARG(fp);
PERL_UNUSED_ARG(iotype);
PERL_UNUSED_ARG(mode);
return
1;
# endif
#endif
}
#ifndef O_ACCMODE
# define O_ACCMODE 3 /* Assume traditional implementation */
#endif
int
PerlIO_intmode2str(
int
rawmode,
char
*mode,
int
*writing)
{
const
int
result = rawmode & O_ACCMODE;
int
ix = 0;
int
ptype;
switch
(result) {
case
O_RDONLY:
ptype = IoTYPE_RDONLY;
break
;
case
O_WRONLY:
ptype = IoTYPE_WRONLY;
break
;
case
O_RDWR:
default
:
ptype = IoTYPE_RDWR;
break
;
}
if
(writing)
*writing = (result != O_RDONLY);
if
(result == O_RDONLY) {
mode[ix++] =
'r'
;
}
#ifdef O_APPEND
else
if
(rawmode & O_APPEND) {
mode[ix++] =
'a'
;
if
(result != O_WRONLY)
mode[ix++] =
'+'
;
}
#endif
else
{
if
(result == O_WRONLY)
mode[ix++] =
'w'
;
else
{
mode[ix++] =
'r'
;
mode[ix++] =
'+'
;
}
}
#if O_BINARY != 0
if
(rawmode & O_BINARY)
mode[ix++] =
'b'
;
#endif
mode[ix] =
'\0'
;
return
ptype;
}
#ifndef PERLIO_LAYERS
int
PerlIO_apply_layers(pTHX_ PerlIO *f,
const
char
*mode,
const
char
*names)
{
if
(!names || !*names
|| strEQ(names,
":crlf"
)
|| strEQ(names,
":raw"
)
|| strEQ(names,
":bytes"
)
) {
return
0;
}
Perl_croak(aTHX_
"Cannot apply \"%s\" in non-PerlIO perl"
, names);
return
-1;
}
void
PerlIO_destruct(pTHX)
{
}
int
PerlIO_binmode(pTHX_ PerlIO *fp,
int
iotype,
int
mode,
const
char
*names)
{
return
perlsio_binmode(fp, iotype, mode);
}
PerlIO *
PerlIO_fdupopen(pTHX_ PerlIO *f, CLONE_PARAMS *param,
int
flags)
{
#if defined(PERL_IMPLICIT_SYS)
return
PerlSIO_fdupopen(f);
#else
# ifdef WIN32
return
win32_fdupopen(f);
# else
if
(f) {
const
int
fd = PerlLIO_dup_cloexec(PerlIO_fileno(f));
if
(fd >= 0) {
char
mode[8];
const
int
omode = fcntl(fd, F_GETFL);
PerlIO_intmode2str(omode,mode,NULL);
return
PerlIO_fdopen(fd, mode);
}
return
NULL;
}
else
{
SETERRNO(EBADF, SS_IVCHAN);
}
# endif
return
NULL;
#endif
}
PerlIO *
PerlIO_openn(pTHX_
const
char
*layers,
const
char
*mode,
int
fd,
int
imode,
int
perm, PerlIO *old,
int
narg, SV **args)
{
if
(narg) {
if
(narg > 1) {
Perl_croak(aTHX_
"More than one argument to open"
);
}
if
(*args == &PL_sv_undef)
return
PerlIO_tmpfile();
else
{
STRLEN len;
const
char
*name = SvPV_const(*args, len);
if
(!IS_SAFE_PATHNAME(name, len,
"open"
))
return
NULL;
if
(*mode == IoTYPE_NUMERIC) {
fd = PerlLIO_open3_cloexec(name, imode, perm);
if
(fd >= 0)
return
PerlIO_fdopen(fd, mode + 1);
}
else
if
(old) {
return
PerlIO_reopen(name, mode, old);
}
else
{
return
PerlIO_open(name, mode);
}
}
}
else
{
return
PerlIO_fdopen(fd, mode);
}
return
NULL;
}
XS(XS_PerlIO__Layer__find);
XS(XS_PerlIO__Layer__find)
{
dXSARGS;
if
(items < 2)
Perl_croak(aTHX_
"Usage class->find(name[,load])"
);
else
{
const
char
*
const
name = SvPV_nolen_const(ST(1));
ST(0) = (strEQ(name,
"crlf"
)
|| strEQ(name,
"raw"
)) ? &PL_sv_yes : &PL_sv_undef;
XSRETURN(1);
}
}
void
Perl_boot_core_PerlIO(pTHX)
{
newXS(
"PerlIO::Layer::find"
, XS_PerlIO__Layer__find, __FILE__);
}
#endif
#include "perliol.h"
void
PerlIO_debug(
const
char
*fmt, ...)
{
va_list
ap;
dSYS;
if
(!DEBUG_i_TEST)
return
;
va_start
(ap, fmt);
if
(!PL_perlio_debug_fd) {
if
(!TAINTING_get &&
PerlProc_getuid() == PerlProc_geteuid() &&
PerlProc_getgid() == PerlProc_getegid()) {
const
char
*
const
s = PerlEnv_getenv(
"PERLIO_DEBUG"
);
if
(s && *s)
PL_perlio_debug_fd = PerlLIO_open3_cloexec(s,
O_WRONLY | O_CREAT | O_APPEND, 0666);
else
PL_perlio_debug_fd = PerlLIO_dup_cloexec(2);
}
else
{
PL_perlio_debug_fd = PerlLIO_dup_cloexec(2);
}
}
if
(PL_perlio_debug_fd > 0) {
#ifdef USE_ITHREADS
const
char
*
const
s = CopFILE(PL_curcop);
char
buffer[1024];
const
STRLEN len1 = my_snprintf(buffer,
sizeof
(buffer),
"%.40s:%"
LINE_Tf
" "
, s ? s :
"(none)"
, CopLINE(PL_curcop));
# ifdef USE_QUADMATH
# ifdef HAS_VSNPRINTF
DECLARATION_FOR_LC_NUMERIC_MANIPULATION;
STORE_LC_NUMERIC_SET_TO_NEEDED();
const
STRLEN len2 = vsnprintf(buffer + len1,
sizeof
(buffer) - len1, fmt, ap);
RESTORE_LC_NUMERIC();
# else
STATIC_ASSERT_STMT(0);
# endif
# else
const
STRLEN len2 = my_vsnprintf(buffer + len1,
sizeof
(buffer) - len1, fmt, ap);
# endif
PERL_UNUSED_RESULT(PerlLIO_write(PL_perlio_debug_fd, buffer, len1 + len2));
#else
const
char
*s = CopFILE(PL_curcop);
STRLEN len;
SV *
const
sv = Perl_newSVpvf(aTHX_
"%s:%"
LINE_Tf
" "
,
s ? s :
"(none)"
, CopLINE(PL_curcop));
Perl_sv_vcatpvf(aTHX_ sv, fmt, &ap);
s = SvPV_const(sv, len);
PERL_UNUSED_RESULT(PerlLIO_write(PL_perlio_debug_fd, s, len));
SvREFCNT_dec(sv);
#endif
}
va_end
(ap);
}
#ifdef DEBUGGING
# define VERIFY_HEAD(f) PerlIO_verify_head(aTHX_ f)
static
void
PerlIO_verify_head(pTHX_ PerlIO *f)
{
PerlIOl *head, *p;
int
seen = 0;
# ifndef PERL_IMPLICIT_SYS
PERL_UNUSED_CONTEXT;
# endif
if
(!PerlIOValid(f))
return
;
p = head = PerlIOBase(f)->head;
assert
(p);
do
{
assert
(p->head == head);
if
(&p->next == f)
seen = 1;
p = p->next;
}
while
(p);
assert
(seen);
}
#else
# define VERIFY_HEAD(f)
#endif
#define PERLIO_TABLE_SIZE 64
static
void
PerlIO_init_table(pTHX)
{
if
(PL_perlio)
return
;
Newxz(PL_perlio, PERLIO_TABLE_SIZE, PerlIOl);
}
PerlIO *
PerlIO_allocate(pTHX)
{
PerlIOl **last;
PerlIOl *f;
last = &PL_perlio;
while
((f = *last)) {
int
i;
last = &f->next;
for
(i = 1; i < PERLIO_TABLE_SIZE; i++) {
if
(!((++f)->next)) {
goto
good_exit;
}
}
}
Newxz(f,PERLIO_TABLE_SIZE,PerlIOl);
if
(!f) {
return
NULL;
}
*last = f++;
good_exit:
f->flags = 0;
f->tab = NULL;
f->head = f;
return
&f->next;
}
#undef PerlIO_fdupopen
PerlIO *
PerlIO_fdupopen(pTHX_ PerlIO *f, CLONE_PARAMS *param,
int
flags)
{
if
(PerlIOValid(f)) {
const
PerlIO_funcs *
const
tab = PerlIOBase(f)->tab;
DEBUG_i( PerlIO_debug(
"fdupopen f=%p param=%p\n"
,(
void
*)f,(
void
*)param) );
if
(tab && tab->Dup)
return
(*tab->Dup)(aTHX_ PerlIO_allocate(aTHX), f, param, flags);
else
{
return
PerlIOBase_dup(aTHX_ PerlIO_allocate(aTHX), f, param, flags);
}
}
else
SETERRNO(EBADF, SS_IVCHAN);
return
NULL;
}
void
PerlIO_cleantable(pTHX_ PerlIOl **tablep)
{
PerlIOl *
const
table = *tablep;
if
(table) {
int
i;
PerlIO_cleantable(aTHX_ &table[0].next);
for
(i = PERLIO_TABLE_SIZE - 1; i > 0; i--) {
PerlIOl *
const
f = table + i;
if
(f->next) {
PerlIO_close(&(f->next));
}
}
Safefree(table);
*tablep = NULL;
}
}
PerlIO_list_t *
PerlIO_list_alloc(pTHX)
{
PerlIO_list_t *list;
PERL_UNUSED_CONTEXT;
Newxz(list, 1, PerlIO_list_t);
list->refcnt = 1;
return
list;
}
void
PerlIO_list_free(pTHX_ PerlIO_list_t *list)
{
if
(list) {
if
(--list->refcnt == 0) {
if
(list->array) {
IV i;
for
(i = 0; i < list->cur; i++)
SvREFCNT_dec(list->array[i].arg);
Safefree(list->array);
}
Safefree(list);
}
}
}
void
PerlIO_list_push(pTHX_ PerlIO_list_t *list, PerlIO_funcs *funcs, SV *arg)
{
PerlIO_pair_t *p;
PERL_UNUSED_CONTEXT;
if
(list->cur >= list->len) {
const
IV new_len = list->len + 8;
if
(list->array)
Renew(list->array, new_len, PerlIO_pair_t);
else
Newx(list->array, new_len, PerlIO_pair_t);
list->len = new_len;
}
p = &(list->array[list->cur++]);
p->funcs = funcs;
if
((p->arg = arg)) {
SvREFCNT_inc_simple_void_NN(arg);
}
}
PerlIO_list_t *
PerlIO_clone_list(pTHX_ PerlIO_list_t *proto, CLONE_PARAMS *param)
{
PerlIO_list_t *list = NULL;
if
(proto) {
int
i;
list = PerlIO_list_alloc(aTHX);
for
(i=0; i < proto->cur; i++) {
SV *arg = proto->array[i].arg;
#ifdef USE_ITHREADS
if
(arg && param)
arg = sv_dup(arg, param);
#else
PERL_UNUSED_ARG(param);
#endif
PerlIO_list_push(aTHX_ list, proto->array[i].funcs, arg);
}
}
return
list;
}
void
PerlIO_clone(pTHX_ PerlInterpreter *proto, CLONE_PARAMS *param)
{
#ifdef USE_ITHREADS
PerlIOl **table = &proto->Iperlio;
PerlIOl *f;
PL_perlio = NULL;
PL_known_layers = PerlIO_clone_list(aTHX_ proto->Iknown_layers, param);
PL_def_layerlist = PerlIO_clone_list(aTHX_ proto->Idef_layerlist, param);
PerlIO_init_table(aTHX);
DEBUG_i( PerlIO_debug(
"Clone %p from %p\n"
,(
void
*)aTHX,(
void
*)proto) );
while
((f = *table)) {
int
i;
table = &f->next;
f++;
for
(i = 1; i < PERLIO_TABLE_SIZE; i++) {
if
(f->next) {
(
void
) fp_dup(&(f->next), 0, param);
}
f++;
}
}
#else
PERL_UNUSED_CONTEXT;
PERL_UNUSED_ARG(proto);
PERL_UNUSED_ARG(param);
#endif
}
void
PerlIO_destruct(pTHX)
{
PerlIOl **table = &PL_perlio;
PerlIOl *f;
#ifdef USE_ITHREADS
DEBUG_i( PerlIO_debug(
"Destruct %p\n"
,(
void
*)aTHX) );
#endif
while
((f = *table)) {
int
i;
table = &f->next;
f++;
for
(i = 1; i < PERLIO_TABLE_SIZE; i++) {
PerlIO *x = &(f->next);
const
PerlIOl *l;
while
((l = *x)) {
if
(l->tab && l->tab->kind & PERLIO_K_DESTRUCT) {
DEBUG_i( PerlIO_debug(
"Destruct popping %s\n"
, l->tab->name) );
PerlIO_flush(x);
PerlIO_pop(aTHX_ x);
}
else
{
x = PerlIONext(x);
}
}
f++;
}
}
}
void
PerlIO_pop(pTHX_ PerlIO *f)
{
const
PerlIOl *l = *f;
VERIFY_HEAD(f);
if
(l) {
DEBUG_i( PerlIO_debug(
"PerlIO_pop f=%p %s\n"
, (
void
*)f,
l->tab ? l->tab->name :
"(Null)"
) );
if
(l->tab && l->tab->Popped) {
if
((*l->tab->Popped) (aTHX_ f) != 0)
return
;
}
if
(PerlIO_lockcnt(f)) {
PerlIOBase(f)->flags = PERLIO_F_CLEARED;
PerlIOBase(f)->tab = NULL;
}
else
{
*f = l->next;
Safefree(l);
}
}
}
AV *
PerlIO_get_layers(pTHX_ PerlIO *f)
{
AV *
const
av = newAV();
if
(PerlIOValid(f)) {
PerlIOl *l = PerlIOBase(f);
while
(l) {
SV *
const
name = l->tab && l->tab->name ?
newSVpv(l->tab->name, 0) : &PL_sv_undef;
SV *
const
arg = l->tab && l->tab->Getarg ?
(*l->tab->Getarg)(aTHX_ &l, 0, 0) : &PL_sv_undef;
av_push_simple(av, name);
av_push_simple(av, arg);
av_push_simple(av, newSViv((IV)l->flags));
l = l->next;
}
}
return
av;
}
PerlIO_funcs *
PerlIO_find_layer(pTHX_
const
char
*name, STRLEN len,
int
load)
{
IV i;
if
((SSize_t) len <= 0)
len =
strlen
(name);
for
(i = 0; i < PL_known_layers->cur; i++) {
PerlIO_funcs *
const
f = PL_known_layers->array[i].funcs;
const
STRLEN this_len =
strlen
(f->name);
if
(this_len == len && memEQ(f->name, name, len)) {
DEBUG_i( PerlIO_debug(
"%.*s => %p\n"
, (
int
) len, name, (
void
*)f) );
return
f;
}
}
if
(load && PL_subname && PL_def_layerlist
&& PL_def_layerlist->cur >= 2) {
if
(PL_in_load_module) {
Perl_croak(aTHX_
"Recursive call to Perl_load_module in PerlIO_find_layer"
);
return
NULL;
}
else
{
SV *
const
pkgsv = newSVpvs(
"PerlIO"
);
SV *
const
layer = newSVpvn(name, len);
CV *
const
cv = get_cvs(
"PerlIO::Layer::NoWarnings"
, 0);
ENTER;
SAVEBOOL(PL_in_load_module);
if
(cv) {
SAVEGENERICSV(PL_warnhook);
PL_warnhook = MUTABLE_SV((SvREFCNT_inc_simple_NN(cv)));
}
PL_in_load_module = TRUE;
Perl_load_module(aTHX_ 0, pkgsv, NULL, layer, NULL);
LEAVE;
return
PerlIO_find_layer(aTHX_ name, len, 0);
}
}
DEBUG_i( PerlIO_debug(
"Cannot find %.*s\n"
, (
int
) len, name) );
return
NULL;
}
#ifdef USE_ATTRIBUTES_FOR_PERLIO
static
int
perlio_mg_set(pTHX_ SV *sv, MAGIC *mg)
{
if
(SvROK(sv)) {
IO *
const
io = GvIOn(MUTABLE_GV(SvRV(sv)));
PerlIO *
const
ifp = IoIFP(io);
PerlIO *
const
ofp = IoOFP(io);
Perl_warn(aTHX_
"set %"
SVf
" %p %p %p"
,
SVfARG(sv), (
void
*)io, (
void
*)ifp, (
void
*)ofp);
}
return
0;
}
static
int
perlio_mg_get(pTHX_ SV *sv, MAGIC *mg)
{
if
(SvROK(sv)) {
IO *
const
io = GvIOn(MUTABLE_GV(SvRV(sv)));
PerlIO *
const
ifp = IoIFP(io);
PerlIO *
const
ofp = IoOFP(io);
Perl_warn(aTHX_
"get %"
SVf
" %p %p %p"
,
SVfARG(sv), (
void
*)io, (
void
*)ifp, (
void
*)ofp);
}
return
0;
}
static
int
perlio_mg_clear(pTHX_ SV *sv, MAGIC *mg)
{
Perl_warn(aTHX_
"clear %"
SVf, SVfARG(sv));
return
0;
}
static
int
perlio_mg_free(pTHX_ SV *sv, MAGIC *mg)
{
Perl_warn(aTHX_
"free %"
SVf, SVfARG(sv));
return
0;
}
MGVTBL perlio_vtab = {
perlio_mg_get,
perlio_mg_set,
NULL,
perlio_mg_clear,
perlio_mg_free
};
XS(XS_io_MODIFY_SCALAR_ATTRIBUTES);
XS(XS_io_MODIFY_SCALAR_ATTRIBUTES)
{
dXSARGS;
SV *
const
sv = SvRV(ST(1));
AV *
const
av = newAV();
MAGIC *mg;
int
count = 0;
int
i;
sv_magic(sv, MUTABLE_SV(av), PERL_MAGIC_ext, NULL, 0);
SvRMAGICAL_off(sv);
mg = mg_find(sv, PERL_MAGIC_ext);
mg->mg_virtual = &perlio_vtab;
mg_magical(sv);
Perl_warn(aTHX_
"attrib %"
SVf, SVfARG(sv));
for
(i = 2; i < items; i++) {
STRLEN len;
const
char
*
const
name = SvPV_const(ST(i), len);
SV *
const
layer = PerlIO_find_layer(aTHX_ name, len, 1);
if
(layer) {
av_push_simple(av, SvREFCNT_inc_simple_NN(layer));
}
else
{
ST(count) = ST(i);
count++;
}
}
SvREFCNT_dec(av);
XSRETURN(count);
}
#endif /* USE_ATTRIBUTES_FOR_PERLIO */
SV *
PerlIO_tab_sv(pTHX_ PerlIO_funcs *tab)
{
HV *
const
stash = gv_stashpvs(
"PerlIO::Layer"
, GV_ADD);
SV *
const
sv = sv_bless(newRV_noinc(newSViv(PTR2IV(tab))), stash);
return
sv;
}
XS(XS_PerlIO__Layer__NoWarnings);
XS(XS_PerlIO__Layer__NoWarnings)
{
dXSARGS;
PERL_UNUSED_VAR(items);
DEBUG_i(
if
(items)
PerlIO_debug(
"warning:%s\n"
,SvPV_nolen_const(ST(0))) );
XSRETURN(0);
}
XS(XS_PerlIO__Layer__find);
XS(XS_PerlIO__Layer__find)
{
dXSARGS;
if
(items < 2)
Perl_croak(aTHX_
"Usage class->find(name[,load])"
);
else
{
STRLEN len;
const
char
*
const
name = SvPV_const(ST(1), len);
const
bool
load = (items > 2) ? SvTRUE_NN(ST(2)) : 0;
PerlIO_funcs *
const
layer = PerlIO_find_layer(aTHX_ name, len, load);
ST(0) =
(layer) ? sv_2mortal(PerlIO_tab_sv(aTHX_ layer)) :
&PL_sv_undef;
XSRETURN(1);
}
}
void
PerlIO_define_layer(pTHX_ PerlIO_funcs *tab)
{
if
(!PL_known_layers)
PL_known_layers = PerlIO_list_alloc(aTHX);
PerlIO_list_push(aTHX_ PL_known_layers, tab, NULL);
DEBUG_i( PerlIO_debug(
"define %s %p\n"
, tab->name, (
void
*)tab) );
}
int
PerlIO_parse_layers(pTHX_ PerlIO_list_t *av,
const
char
*names)
{
if
(names) {
const
char
*s = names;
while
(*s) {
while
(isSPACE(*s) || *s ==
':'
)
s++;
if
(*s) {
STRLEN llen = 0;
const
char
*e = s;
const
char
*as = NULL;
STRLEN alen = 0;
if
(!isIDFIRST(*s)) {
const
char
q = ((*s ==
'\''
) ?
'"'
:
'\''
);
Perl_ck_warner(aTHX_ packWARN(WARN_LAYER),
"Invalid separator character %c%c%c in PerlIO layer specification %s"
,
q, *s, q, s);
SETERRNO(EINVAL, LIB_INVARG);
return
-1;
}
do
{
e++;
}
while
(isWORDCHAR(*e));
llen = e - s;
if
(*e ==
'('
) {
int
nesting = 1;
as = ++e;
while
(nesting) {
switch
(*e++) {
case
')'
:
if
(--nesting == 0)
alen = (e - 1) - as;
break
;
case
'('
:
++nesting;
break
;
case
'\\'
:
if
(*e++) {
break
;
}
case
'\0'
:
e--;
Perl_ck_warner(aTHX_ packWARN(WARN_LAYER),
"Argument list not closed for PerlIO layer \"%.*s\""
,
(
int
) (e - s), s);
return
-1;
default
:
break
;
}
}
}
if
(e > s) {
PerlIO_funcs *
const
layer =
PerlIO_find_layer(aTHX_ s, llen, 1);
if
(layer) {
SV *arg = NULL;
if
(as)
arg = newSVpvn(as, alen);
PerlIO_list_push(aTHX_ av, layer,
(arg) ? arg : &PL_sv_undef);
SvREFCNT_dec(arg);
}
else
{
Perl_ck_warner(aTHX_ packWARN(WARN_LAYER),
"Unknown PerlIO layer \"%.*s\""
,
(
int
) llen, s);
return
-1;
}
}
s = e;
}
}
}
return
0;
}
void
PerlIO_default_buffer(pTHX_ PerlIO_list_t *av)
{
PERLIO_FUNCS_DECL(*tab) = &PerlIO_perlio;
#ifdef PERLIO_USING_CRLF
tab = &PerlIO_crlf;
#else
if
(PerlIO_stdio.Set_ptrcnt)
tab = &PerlIO_stdio;
#endif
DEBUG_i( PerlIO_debug(
"Pushing %s\n"
, tab->name) );
PerlIO_list_push(aTHX_ av, (PerlIO_funcs *)tab, &PL_sv_undef);
}
SV *
PerlIO_arg_fetch(PerlIO_list_t *av, IV n)
{
return
av->array[n].arg;
}
PerlIO_funcs *
PerlIO_layer_fetch(pTHX_ PerlIO_list_t *av, IV n, PerlIO_funcs *def)
{
if
(n >= 0 && n < av->cur) {
DEBUG_i( PerlIO_debug(
"Layer %"
IVdf
" is %s\n"
, n,
av->array[n].funcs->name) );
return
av->array[n].funcs;
}
if
(!def)
Perl_croak(aTHX_
"panic: PerlIO layer array corrupt"
);
return
def;
}
IV
PerlIOPop_pushed(pTHX_ PerlIO *f,
const
char
*mode, SV *arg, PerlIO_funcs *tab)
{
PERL_UNUSED_ARG(mode);
PERL_UNUSED_ARG(arg);
PERL_UNUSED_ARG(tab);
if
(PerlIOValid(f)) {
PerlIO_flush(f);
PerlIO_pop(aTHX_ f);
return
0;
}
return
-1;
}
PERLIO_FUNCS_DECL(PerlIO_remove) = {
sizeof
(PerlIO_funcs),
"pop"
,
0,
PERLIO_K_DUMMY | PERLIO_K_UTF8,
PerlIOPop_pushed,
NULL,
PerlIOBase_open,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
static
const
char
code_point_warning[] =
"Strings with code points over 0xFF may not be mapped into in-memory file handles\n"
;
typedef
struct
{
struct
_PerlIO base;
SV *var;
Off_t posn;
} PerlIOScalar;
IV
PerlIOScalar_eof(pTHX_ PerlIO * f)
{
if
(PerlIOBase(f)->flags & PERLIO_F_CANREAD) {
PerlIOScalar *s = PerlIOSelf(f, PerlIOScalar);
STRLEN len;
(
void
)SvPV(s->var, len);
return
len - (STRLEN)(s->posn) <= 0;
}
return
1;
}
static
IV
PerlIOScalar_pushed(pTHX_ PerlIO * f,
const
char
*mode, SV * arg,
PerlIO_funcs * tab)
{
IV code;
PerlIOScalar *s = PerlIOSelf(f, PerlIOScalar);
if
(arg && SvOK(arg)) {
if
(SvROK(arg)) {
if
(SvREADONLY(SvRV(arg)) && !SvIsCOW(SvRV(arg))
&& mode && *mode !=
'r'
) {
if
(ckWARN(WARN_LAYER))
Perl_warner(aTHX_ packWARN(WARN_LAYER),
"%s"
, PL_no_modify);
SETERRNO(EACCES, RMS_PRV);
return
-1;
}
s->var = SvREFCNT_inc(SvRV(arg));
SvGETMAGIC(s->var);
if
(!SvPOK(s->var) && SvOK(s->var))
(
void
)SvPV_nomg_const_nolen(s->var);
}
else
{
s->var =
SvREFCNT_inc(get_sv
(SvPV_nolen(arg), GV_ADD | GV_ADDMULTI));
}
SvUPGRADE(s->var, SVt_PV);
}
else
{
s->var = newSVpvs(
""
);
}
code = PerlIOBase_pushed(aTHX_ f, mode, NULL, tab);
if
(!SvOK(s->var) || (PerlIOBase(f)->flags) & PERLIO_F_TRUNCATE)
{
sv_force_normal(s->var);
SvCUR_set(s->var, 0);
if
(SvPOK(s->var)) *SvPVX(s->var) = 0;
}
if
(SvUTF8(s->var) && !sv_utf8_downgrade(s->var, TRUE)) {
if
(ckWARN(WARN_UTF8))
Perl_warner(aTHX_ packWARN(WARN_UTF8), code_point_warning);
SETERRNO(EINVAL, SS_IVCHAN);
SvREFCNT_dec(s->var);
s->var = NULL;
return
-1;
}
if
((PerlIOBase(f)->flags) & PERLIO_F_APPEND)
s->posn = SvOK(s->var) ? sv_len(s->var) : 0;
else
s->posn = 0;
SvSETMAGIC(s->var);
return
code;
}
static
IV
PerlIOScalar_popped(pTHX_ PerlIO * f)
{
PerlIOScalar *s = PerlIOSelf(f, PerlIOScalar);
if
(s->var) {
SvREFCNT_dec(s->var);
s->var = NULL;
}
return
0;
}
static
IV
PerlIOScalar_close(pTHX_ PerlIO * f)
{
IV code = PerlIOBase_close(aTHX_ f);
PerlIOBase(f)->flags &= ~(PERLIO_F_RDBUF | PERLIO_F_WRBUF);
return
code;
}
static
IV
PerlIOScalar_fileno(pTHX_ PerlIO * f)
{
PERL_UNUSED_ARG(f);
return
-1;
}
static
IV
PerlIOScalar_seek(pTHX_ PerlIO * f, Off_t offset,
int
whence)
{
PerlIOScalar *s = PerlIOSelf(f, PerlIOScalar);
Off_t new_posn;
switch
(whence) {
case
SEEK_SET:
new_posn = offset;
break
;
case
SEEK_CUR:
new_posn = offset + s->posn;
break
;
case
SEEK_END:
{
STRLEN oldcur;
(
void
)SvPV(s->var, oldcur);
new_posn = offset + oldcur;
break
;
}
default
:
SETERRNO(EINVAL, SS_IVCHAN);
return
-1;
}
if
(new_posn < 0) {
if
(ckWARN(WARN_LAYER))
Perl_warner(aTHX_ packWARN(WARN_LAYER),
"Offset outside string"
);
SETERRNO(EINVAL, SS_IVCHAN);
return
-1;
}
s->posn = new_posn;
return
0;
}
static
Off_t
PerlIOScalar_tell(pTHX_ PerlIO * f)
{
PerlIOScalar *s = PerlIOSelf(f, PerlIOScalar);
return
s->posn;
}
static
SSize_t
PerlIOScalar_read(pTHX_ PerlIO *f,
void
*vbuf, Size_t count)
{
if
(!f)
return
0;
if
(!(PerlIOBase(f)->flags & PERLIO_F_CANREAD)) {
PerlIOBase(f)->flags |= PERLIO_F_ERROR;
SETERRNO(EBADF, SS_IVCHAN);
Perl_PerlIO_save_errno(aTHX_ f);
return
0;
}
{
PerlIOScalar *s = PerlIOSelf(f, PerlIOScalar);
SV *sv = s->var;
char
*p;
STRLEN len;
STRLEN got;
p = SvPV(sv, len);
if
(SvUTF8(sv)) {
if
(sv_utf8_downgrade(sv, TRUE)) {
p = SvPV_nomg(sv, len);
}
else
{
if
(ckWARN(WARN_UTF8))
Perl_warner(aTHX_ packWARN(WARN_UTF8), code_point_warning);
SETERRNO(EINVAL, SS_IVCHAN);
return
-1;
}
}
#if Off_t_size >= Size_t_size
assert
(len < ((~(STRLEN)0) >> 1));
if
((Off_t)len <= s->posn)
return
0;
#else
if
(len <= (STRLEN)s->posn)
return
0;
#endif
got = len - (STRLEN)(s->posn);
if
((STRLEN)got > (STRLEN)count)
got = (STRLEN)count;
Copy(p + (STRLEN)(s->posn), vbuf, got, STDCHAR);
s->posn += (Off_t)got;
return
(SSize_t)got;
}
}
static
SSize_t
PerlIOScalar_write(pTHX_ PerlIO * f,
const
void
*vbuf, Size_t count)
{
if
(PerlIOBase(f)->flags & PERLIO_F_CANWRITE) {
Off_t offset;
PerlIOScalar *s = PerlIOSelf(f, PerlIOScalar);
SV *sv = s->var;
char
*dst;
SvGETMAGIC(sv);
if
(!SvROK(sv)) sv_force_normal(sv);
if
(SvOK(sv)) SvPV_force_nomg_nolen(sv);
if
(SvUTF8(sv) && !sv_utf8_downgrade(sv, TRUE)) {
if
(ckWARN(WARN_UTF8))
Perl_warner(aTHX_ packWARN(WARN_UTF8), code_point_warning);
SETERRNO(EINVAL, SS_IVCHAN);
return
0;
}
if
((PerlIOBase(f)->flags) & PERLIO_F_APPEND) {
dst = SvGROW(sv, SvCUR(sv) + count + 1);
offset = SvCUR(sv);
s->posn = offset + count;
}
else
{
STRLEN
const
cur = SvCUR(sv);
#if Size_t_size < Off_t_size
if
(s->posn > SSize_t_MAX) {
#ifdef EFBIG
SETERRNO(EFBIG, SS_BUFFEROVF);
#else
SETERRNO(ENOSPC, SS_BUFFEROVF);
#endif
return
0;
}
#endif
if
((STRLEN)s->posn > cur) {
dst = SvGROW(sv, (STRLEN)s->posn + count + 1);
Zero(SvPVX(sv) + cur, (STRLEN)s->posn - cur,
char
);
}
else
if
((s->posn + count) >= cur)
dst = SvGROW(sv, (STRLEN)s->posn + count + 1);
else
dst = SvPVX(sv);
offset = s->posn;
s->posn += count;
}
Move(vbuf, dst + offset, count,
char
);
if
((STRLEN) s->posn > SvCUR(sv)) {
SvCUR_set(sv, (STRLEN)s->posn);
dst[(STRLEN) s->posn] = 0;
}
SvPOK_on(sv);
SvSETMAGIC(sv);
return
count;
}
else
return
0;
}
static
IV
PerlIOScalar_fill(pTHX_ PerlIO * f)
{
PERL_UNUSED_ARG(f);
return
-1;
}
static
IV
PerlIOScalar_flush(pTHX_ PerlIO * f)
{
PERL_UNUSED_ARG(f);
return
0;
}
static
STDCHAR *
PerlIOScalar_get_base(pTHX_ PerlIO * f)
{
PerlIOScalar *s = PerlIOSelf(f, PerlIOScalar);
if
(PerlIOBase(f)->flags & PERLIO_F_CANREAD) {
SvGETMAGIC(s->var);
return
(STDCHAR *) SvPV_nolen(s->var);
}
return
(STDCHAR *) NULL;
}
static
STDCHAR *
PerlIOScalar_get_ptr(pTHX_ PerlIO * f)
{
if
(PerlIOBase(f)->flags & PERLIO_F_CANREAD) {
PerlIOScalar *s = PerlIOSelf(f, PerlIOScalar);
return
PerlIOScalar_get_base(aTHX_ f) + s->posn;
}
return
(STDCHAR *) NULL;
}
static
SSize_t
PerlIOScalar_get_cnt(pTHX_ PerlIO * f)
{
if
(PerlIOBase(f)->flags & PERLIO_F_CANREAD) {
PerlIOScalar *s = PerlIOSelf(f, PerlIOScalar);
STRLEN len;
(
void
)SvPV(s->var,len);
if
((Off_t)len > s->posn)
return
len - (STRLEN)s->posn;
else
return
0;
}
return
0;
}
static
Size_t
PerlIOScalar_bufsiz(pTHX_ PerlIO * f)
{
if
(PerlIOBase(f)->flags & PERLIO_F_CANREAD) {
PerlIOScalar *s = PerlIOSelf(f, PerlIOScalar);
SvGETMAGIC(s->var);
return
SvCUR(s->var);
}
return
0;
}
static
void
PerlIOScalar_set_ptrcnt(pTHX_ PerlIO * f, STDCHAR * ptr, SSize_t cnt)
{
PerlIOScalar *s = PerlIOSelf(f, PerlIOScalar);
STRLEN len;
PERL_UNUSED_ARG(ptr);
(
void
)SvPV(s->var,len);
s->posn = len - cnt;
}
static
PerlIO *
PerlIOScalar_open(pTHX_ PerlIO_funcs * self, PerlIO_list_t * layers, IV n,
const
char
*mode,
int
fd,
int
imode,
int
perm,
PerlIO * f,
int
narg, SV ** args)
{
SV *arg = (narg > 0) ? *args : PerlIOArg;
PERL_UNUSED_ARG(fd);
PERL_UNUSED_ARG(imode);
PERL_UNUSED_ARG(perm);
if
(SvROK(arg) || SvPOK(arg)) {
if
(!f) {
f = PerlIO_allocate(aTHX);
}
if
( (f = PerlIO_push(aTHX_ f, self, mode, arg)) ) {
PerlIOBase(f)->flags |= PERLIO_F_OPEN;
}
return
f;
}
return
NULL;
}
static
SV *
PerlIOScalar_arg(pTHX_ PerlIO * f, CLONE_PARAMS * param,
int
flags)
{
PerlIOScalar *s = PerlIOSelf(f, PerlIOScalar);
SV *var = s->var;
if
(flags & PERLIO_DUP_CLONE)
var = PerlIO_sv_dup(aTHX_ var, param);
else
if
(flags & PERLIO_DUP_FD) {
var = newSVsv(var);
}
else
{
var = SvREFCNT_inc(var);
}
return
newRV_noinc(var);
}
static
PerlIO *
PerlIOScalar_dup(pTHX_ PerlIO * f, PerlIO * o, CLONE_PARAMS * param,
int
flags)
{
PerlIOScalar *
const
os = PerlIOSelf(o, PerlIOScalar);
PerlIOScalar *fs = NULL;
SV *
const
var = os->var;
os->var = newSVpvs(
""
);
if
((f = PerlIOBase_dup(aTHX_ f, o, param, flags))) {
fs = PerlIOSelf(f, PerlIOScalar);
SvREFCNT_dec(fs->var);
}
SvREFCNT_dec(os->var);
os->var = var;
if
(f) {
SV *
const
rv = PerlIOScalar_arg(aTHX_ o, param, flags);
fs->var = SvREFCNT_inc(SvRV(rv));
SvREFCNT_dec(rv);
fs->posn = os->posn;
}
return
f;
}
static
PERLIO_FUNCS_DECL(PerlIO_scalar) = {
sizeof
(PerlIO_funcs),
"scalar"
,
sizeof
(PerlIOScalar),
PERLIO_K_BUFFERED | PERLIO_K_RAW,
PerlIOScalar_pushed,
PerlIOScalar_popped,
PerlIOScalar_open,
PerlIOBase_binmode,
PerlIOScalar_arg,
PerlIOScalar_fileno,
PerlIOScalar_dup,
PerlIOScalar_read,
NULL,
PerlIOScalar_write,
PerlIOScalar_seek,
PerlIOScalar_tell,
PerlIOScalar_close,
PerlIOScalar_flush,
PerlIOScalar_fill,
PerlIOScalar_eof,
PerlIOBase_error,
PerlIOBase_clearerr,
PerlIOBase_setlinebuf,
PerlIOScalar_get_base,
PerlIOScalar_bufsiz,
PerlIOScalar_get_ptr,
PerlIOScalar_get_cnt,
PerlIOScalar_set_ptrcnt,
};
PerlIO_list_t *
PerlIO_default_layers(pTHX)
{
if
(!PL_def_layerlist) {
const
char
*
const
s = TAINTING_get ? NULL : PerlEnv_getenv(
"PERLIO"
);
PERLIO_FUNCS_DECL(*osLayer) = &PerlIO_unix;
PL_def_layerlist = PerlIO_list_alloc(aTHX);
PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_unix));
PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_raw));
PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_perlio));
PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_stdio));
PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_crlf));
PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_utf8));
PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_remove));
PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_byte));
PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_scalar));
PerlIO_list_push(aTHX_ PL_def_layerlist, (PerlIO_funcs *)osLayer,
&PL_sv_undef);
if
(s) {
PerlIO_parse_layers(aTHX_ PL_def_layerlist, s);
}
else
{
PerlIO_default_buffer(aTHX_ PL_def_layerlist);
}
}
if
(PL_def_layerlist->cur < 2) {
PerlIO_default_buffer(aTHX_ PL_def_layerlist);
}
return
PL_def_layerlist;
}
void
Perl_boot_core_PerlIO(pTHX)
{
#ifdef USE_ATTRIBUTES_FOR_PERLIO
newXS(
"io::MODIFY_SCALAR_ATTRIBUTES"
, XS_io_MODIFY_SCALAR_ATTRIBUTES,
__FILE__);
#endif
newXS(
"PerlIO::Layer::find"
, XS_PerlIO__Layer__find, __FILE__);
newXS(
"PerlIO::Layer::NoWarnings"
, XS_PerlIO__Layer__NoWarnings, __FILE__);
}
PerlIO_funcs *
PerlIO_default_layer(pTHX_ I32 n)
{
PerlIO_list_t *
const
av = PerlIO_default_layers(aTHX);
if
(n < 0)
n += av->cur;
return
PerlIO_layer_fetch(aTHX_ av, n, PERLIO_FUNCS_CAST(&PerlIO_stdio));
}
#define PerlIO_default_top() PerlIO_default_layer(aTHX_ -1)
#define PerlIO_default_btm() PerlIO_default_layer(aTHX_ 0)
void
PerlIO_stdstreams(pTHX)
{
if
(!PL_perlio) {
PerlIO_init_table(aTHX);
PerlIO_fdopen(0,
"Ir"
PERLIO_STDTEXT);
PerlIO_fdopen(1,
"Iw"
PERLIO_STDTEXT);
PerlIO_fdopen(2,
"Iw"
PERLIO_STDTEXT);
}
}
PerlIO *
PerlIO_push(pTHX_ PerlIO *f, PERLIO_FUNCS_DECL(*tab),
const
char
*mode, SV *arg)
{
VERIFY_HEAD(f);
if
(tab->fsize !=
sizeof
(PerlIO_funcs)) {
Perl_croak( aTHX_
"%s (%"
UVuf
") does not match %s (%"
UVuf
")"
,
"PerlIO layer function table size"
, (UV)tab->fsize,
"size expected by this perl"
, (UV)
sizeof
(PerlIO_funcs) );
}
if
(tab->size) {
PerlIOl *l;
if
(tab->size <
sizeof
(PerlIOl)) {
Perl_croak( aTHX_
"%s (%"
UVuf
") smaller than %s (%"
UVuf
")"
,
"PerlIO layer instance size"
, (UV)tab->size,
"size expected by this perl"
, (UV)
sizeof
(PerlIOl) );
}
if
(f) {
char
*temp;
Newxz(temp, tab->size,
char
);
l = (PerlIOl*)temp;
if
(l) {
l->next = *f;
l->tab = (PerlIO_funcs*) tab;
l->head = ((PerlIOl*)f)->head;
*f = l;
DEBUG_i( PerlIO_debug(
"PerlIO_push f=%p %s %s %p\n"
,
(
void
*)f, tab->name,
(mode) ? mode :
"(Null)"
, (
void
*)arg) );
if
(*l->tab->Pushed &&
(*l->tab->Pushed)
(aTHX_ f, mode, arg, (PerlIO_funcs*) tab) != 0) {
PerlIO_pop(aTHX_ f);
return
NULL;
}
}
else
return
NULL;
}
}
else
if
(f) {
DEBUG_i( PerlIO_debug(
"PerlIO_push f=%p %s %s %p\n"
, (
void
*)f, tab->name,
(mode) ? mode :
"(Null)"
, (
void
*)arg) );
if
(tab->Pushed &&
(*tab->Pushed) (aTHX_ f, mode, arg, (PerlIO_funcs*) tab) != 0) {
return
NULL;
}
}
return
f;
}
PerlIO *
PerlIOBase_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers,
IV n,
const
char
*mode,
int
fd,
int
imode,
int
perm,
PerlIO *old,
int
narg, SV **args)
{
PerlIO_funcs *
const
tab = PerlIO_layer_fetch(aTHX_ layers, n - 1, PerlIO_default_layer(aTHX_ 0));
if
(tab && tab->Open) {
PerlIO* ret = (*tab->Open)(aTHX_ tab, layers, n - 1, mode, fd, imode, perm, old, narg, args);
if
(ret && PerlIO_push(aTHX_ ret, self, mode, PerlIOArg) == NULL) {
PerlIO_close(ret);
return
NULL;
}
return
ret;
}
SETERRNO(EINVAL, LIB_INVARG);
return
NULL;
}
IV
PerlIOBase_binmode(pTHX_ PerlIO *f)
{
if
(PerlIOValid(f)) {
if
(PerlIOBase(f)->tab && PerlIOBase(f)->tab->kind & PERLIO_K_RAW) {
PerlIOBase(f)->flags &= ~PERLIO_F_UTF8;
}
else
{
PerlIO_pop(aTHX_ f);
}
return
0;
}
return
-1;
}
IV
PerlIORaw_pushed(pTHX_ PerlIO *f,
const
char
*mode, SV *arg, PerlIO_funcs *tab)
{
PERL_UNUSED_ARG(mode);
PERL_UNUSED_ARG(arg);
PERL_UNUSED_ARG(tab);
if
(PerlIOValid(f)) {
PerlIO *t;
const
PerlIOl *l;
PerlIO_flush(f);
t = f;
while
(t && (l = *t)) {
if
(l->tab && l->tab->Binmode) {
if
((*l->tab->Binmode)(aTHX_ t) == 0) {
if
(*t == l) {
t = PerlIONext(t);
}
}
else
{
return
-1;
}
}
else
{
PerlIO_pop(aTHX_ t);
}
}
if
(PerlIOValid(f)) {
DEBUG_i( PerlIO_debug(
":raw f=%p :%s\n"
, (
void
*)f,
PerlIOBase(f)->tab ? PerlIOBase(f)->tab->name :
"(Null)"
) );
return
0;
}
}
return
-1;
}
int
PerlIO_apply_layera(pTHX_ PerlIO *f,
const
char
*mode,
PerlIO_list_t *layers, IV n, IV max)
{
int
code = 0;
while
(n < max) {
PerlIO_funcs *
const
tab = PerlIO_layer_fetch(aTHX_ layers, n, NULL);
if
(tab) {
if
(!PerlIO_push(aTHX_ f, tab, mode, PerlIOArg)) {
code = -1;
break
;
}
}
n++;
}
return
code;
}
int
PerlIO_apply_layers(pTHX_ PerlIO *f,
const
char
*mode,
const
char
*names)
{
int
code = 0;
ENTER;
save_scalar(PL_errgv);
if
(f && names) {
PerlIO_list_t *
const
layers = PerlIO_list_alloc(aTHX);
code = PerlIO_parse_layers(aTHX_ layers, names);
if
(code == 0) {
code = PerlIO_apply_layera(aTHX_ f, mode, layers, 0, layers->cur);
}
PerlIO_list_free(aTHX_ layers);
}
LEAVE;
return
code;
}
int
PerlIO_binmode(pTHX_ PerlIO *f,
int
iotype,
int
mode,
const
char
*names)
{
PERL_UNUSED_ARG(iotype);
PERL_UNUSED_ARG(mode);
DEBUG_i(
PerlIO_debug(
"PerlIO_binmode f=%p %s %c %x %s\n"
, (
void
*)f,
(PerlIOBase(f) && PerlIOBase(f)->tab) ?
PerlIOBase(f)->tab->name :
"(Null)"
,
iotype, mode, (names) ? names :
"(Null)"
) );
if
(names) {
return
cBOOL(PerlIO_apply_layers(aTHX_ f, NULL, names) == 0);
}
else
{
#ifdef PERLIO_USING_CRLF
if
(!(mode & O_BINARY)) {
while
(*f) {
if
(PerlIOBase(f)->tab &&
PerlIOBase(f)->tab->kind & PERLIO_K_CANCRLF)
{
if
(!(PerlIOBase(f)->flags & PERLIO_F_CRLF)) {
PerlIO_flush(f);
PerlIOBase(f)->flags |= PERLIO_F_CRLF;
}
return
TRUE;
}
f = PerlIONext(f);
}
return
FALSE;
}
#endif
return
cBOOL(PerlIO_push(aTHX_ f, PERLIO_FUNCS_CAST(&PerlIO_raw), NULL, NULL));
}
}
int
PerlIO__close(pTHX_ PerlIO *f)
{
if
(PerlIOValid(f)) {
PerlIO_funcs *
const
tab = PerlIOBase(f)->tab;
if
(tab && tab->Close)
return
(*tab->Close)(aTHX_ f);
else
return
PerlIOBase_close(aTHX_ f);
}
else
{
SETERRNO(EBADF, SS_IVCHAN);
return
-1;
}
}
int
Perl_PerlIO_close(pTHX_ PerlIO *f)
{
const
int
code = PerlIO__close(aTHX_ f);
while
(PerlIOValid(f)) {
PerlIO_pop(aTHX_ f);
if
(PerlIO_lockcnt(f))
f = PerlIONext(f);
}
return
code;
}
int
Perl_PerlIO_fileno(pTHX_ PerlIO *f)
{
Perl_PerlIO_or_Base(f, Fileno, fileno, -1, (aTHX_ f));
}
static
PerlIO_funcs *
PerlIO_layer_from_ref(pTHX_ SV *sv)
{
if
(SvTYPE(sv) < SVt_PVAV && (!isGV_with_GP(sv) || SvFAKE(sv)))
return
(PerlIO_funcs*) &PerlIO_scalar;
switch
(SvTYPE(sv)) {
case
SVt_PVAV:
return
PerlIO_find_layer(aTHX_ STR_WITH_LEN(
"Array"
), 0);
case
SVt_PVHV:
return
PerlIO_find_layer(aTHX_ STR_WITH_LEN(
"Hash"
), 0);
case
SVt_PVCV:
return
PerlIO_find_layer(aTHX_ STR_WITH_LEN(
"Code"
), 0);
case
SVt_PVGV:
return
PerlIO_find_layer(aTHX_ STR_WITH_LEN(
"Glob"
), 0);
default
:
return
NULL;
}
}
PerlIO_list_t *
PerlIO_resolve_layers(pTHX_
const
char
*layers,
const
char
*mode,
int
narg, SV **args)
{
PerlIO_list_t *def = PerlIO_default_layers(aTHX);
int
incdef = 1;
if
(!PL_perlio)
PerlIO_stdstreams(aTHX);
if
(narg) {
SV *
const
arg = *args;
if
(SvROK(arg) && !SvOBJECT(SvRV(arg))) {
PerlIO_funcs *
const
handler = PerlIO_layer_from_ref(aTHX_ SvRV(arg));
if
(handler) {
def = PerlIO_list_alloc(aTHX);
PerlIO_list_push(aTHX_ def, handler, &PL_sv_undef);
incdef = 0;
}
}
}
if
(!layers || !*layers)
layers = Perl_PerlIO_context_layers(aTHX_ mode);
if
(layers && *layers) {
PerlIO_list_t *av;
if
(incdef) {
av = PerlIO_clone_list(aTHX_ def, NULL);
}
else
{
av = def;
}
if
(PerlIO_parse_layers(aTHX_ av, layers) == 0) {
return
av;
}
else
{
PerlIO_list_free(aTHX_ av);
return
NULL;
}
}
else
{
if
(incdef)
def->refcnt++;
return
def;
}
}
PerlIO *
PerlIO_openn(pTHX_
const
char
*layers,
const
char
*mode,
int
fd,
int
imode,
int
perm, PerlIO *f,
int
narg, SV **args)
{
if
(!f && narg == 1 && *args == &PL_sv_undef) {
imode = PerlIOUnix_oflags(mode);
if
(imode != -1 && (f = PerlIO_tmpfile_flags(imode))) {
if
(!layers || !*layers)
layers = Perl_PerlIO_context_layers(aTHX_ mode);
if
(layers && *layers)
PerlIO_apply_layers(aTHX_ f, mode, layers);
}
}
else
{
PerlIO_list_t *layera;
IV n;
PerlIO_funcs *tab = NULL;
if
(PerlIOValid(f)) {
PerlIOl *l = *f;
layera = PerlIO_list_alloc(aTHX);
while
(l) {
SV *arg = NULL;
if
(l->tab && l->tab->Getarg)
arg = (*l->tab->Getarg) (aTHX_ &l, NULL, 0);
PerlIO_list_push(aTHX_ layera, l->tab,
(arg) ? arg : &PL_sv_undef);
SvREFCNT_dec(arg);
l = *PerlIONext(&l);
}
}
else
{
layera = PerlIO_resolve_layers(aTHX_ layers, mode, narg, args);
if
(!layera) {
return
NULL;
}
}
n = layera->cur - 1;
while
(n >= 0) {
PerlIO_funcs *
const
t = PerlIO_layer_fetch(aTHX_ layera, n, NULL);
if
(t && t->Open) {
tab = t;
break
;
}
n--;
}
if
(tab) {
if
(narg > 1 && !(tab->kind & PERLIO_K_MULTIARG)) {
Perl_croak(aTHX_
"More than one argument to open(,':%s')"
,tab->name);
}
DEBUG_i( PerlIO_debug(
"openn(%s,'%s','%s',%d,%x,%o,%p,%d,%p)\n"
,
tab->name, layers ? layers :
"(Null)"
, mode, fd,
imode, perm, (
void
*)f, narg, (
void
*)args) );
if
(tab->Open)
f = (*tab->Open) (aTHX_ tab, layera, n, mode, fd, imode, perm,
f, narg, args);
else
{
SETERRNO(EINVAL, LIB_INVARG);
f = NULL;
}
if
(f) {
if
(n + 1 < layera->cur) {
if
(PerlIO_apply_layera(aTHX_ f, mode, layera, n + 1, layera->cur) != 0) {
PerlIO_close(f);
f = NULL;
}
}
}
}
PerlIO_list_free(aTHX_ layera);
}
return
f;
}
SSize_t
Perl_PerlIO_read(pTHX_ PerlIO *f,
void
*vbuf, Size_t count)
{
PERL_ARGS_ASSERT_PERLIO_READ;
Perl_PerlIO_or_Base(f, Read, read, -1, (aTHX_ f, vbuf, count));
}
SSize_t
Perl_PerlIO_unread(pTHX_ PerlIO *f,
const
void
*vbuf, Size_t count)
{
PERL_ARGS_ASSERT_PERLIO_UNREAD;
Perl_PerlIO_or_Base(f, Unread, unread, -1, (aTHX_ f, vbuf, count));
}
SSize_t
Perl_PerlIO_write(pTHX_ PerlIO *f,
const
void
*vbuf, Size_t count)
{
PERL_ARGS_ASSERT_PERLIO_WRITE;
Perl_PerlIO_or_fail(f, Write, -1, (aTHX_ f, vbuf, count));
}
int
Perl_PerlIO_seek(pTHX_ PerlIO *f, Off_t offset,
int
whence)
{
Perl_PerlIO_or_fail(f, Seek, -1, (aTHX_ f, offset, whence));
}
Off_t
Perl_PerlIO_tell(pTHX_ PerlIO *f)
{
Perl_PerlIO_or_fail(f, Tell, -1, (aTHX_ f));
}
int
Perl_PerlIO_flush(pTHX_ PerlIO *f)
{
if
(f) {
if
(*f) {
const
PerlIO_funcs *tab = PerlIOBase(f)->tab;
if
(tab && tab->Flush)
return
(*tab->Flush) (aTHX_ f);
else
return
0;
}
else
{
DEBUG_i( PerlIO_debug(
"Cannot flush f=%p\n"
, (
void
*)f) );
SETERRNO(EBADF, SS_IVCHAN);
return
-1;
}
}
else
{
PerlIOl **table = &PL_perlio;
PerlIOl *ff;
int
code = 0;
while
((ff = *table)) {
int
i;
table = &ff->next;
ff++;
for
(i = 1; i < PERLIO_TABLE_SIZE; i++) {
if
(ff->next && PerlIO_flush(&(ff->next)) != 0)
code = -1;
ff++;
}
}
return
code;
}
}
void
PerlIOBase_flush_linebuf(pTHX)
{
PerlIOl **table = &PL_perlio;
PerlIOl *f;
while
((f = *table)) {
int
i;
table = &f->next;
f++;
for
(i = 1; i < PERLIO_TABLE_SIZE; i++) {
if
(f->next
&& (PerlIOBase(&(f->next))->
flags & (PERLIO_F_LINEBUF | PERLIO_F_CANWRITE))
== (PERLIO_F_LINEBUF | PERLIO_F_CANWRITE))
PerlIO_flush(&(f->next));
f++;
}
}
}
int
Perl_PerlIO_fill(pTHX_ PerlIO *f)
{
Perl_PerlIO_or_fail(f, Fill, -1, (aTHX_ f));
}
int
PerlIO_isutf8(PerlIO *f)
{
if
(PerlIOValid(f))
return
(PerlIOBase(f)->flags & PERLIO_F_UTF8) != 0;
else
SETERRNO(EBADF, SS_IVCHAN);
return
-1;
}
int
Perl_PerlIO_eof(pTHX_ PerlIO *f)
{
Perl_PerlIO_or_Base(f, Eof, eof, -1, (aTHX_ f));
}
int
Perl_PerlIO_error(pTHX_ PerlIO *f)
{
Perl_PerlIO_or_Base(f, Error, error, -1, (aTHX_ f));
}
void
Perl_PerlIO_clearerr(pTHX_ PerlIO *f)
{
Perl_PerlIO_or_Base_void(f, Clearerr,
clearerr
, (aTHX_ f));
}
void
Perl_PerlIO_setlinebuf(pTHX_ PerlIO *f)
{
Perl_PerlIO_or_Base_void(f, Setlinebuf, setlinebuf, (aTHX_ f));
}
int
PerlIO_has_base(PerlIO *f)
{
if
(PerlIOValid(f)) {
const
PerlIO_funcs *
const
tab = PerlIOBase(f)->tab;
if
(tab)
return
(tab->Get_base != NULL);
}
return
0;
}
int
PerlIO_fast_gets(PerlIO *f)
{
if
(PerlIOValid(f)) {
if
(PerlIOBase(f)->flags & PERLIO_F_FASTGETS) {
const
PerlIO_funcs *
const
tab = PerlIOBase(f)->tab;
if
(tab)
return
(tab->Set_ptrcnt != NULL);
}
}
return
0;
}
int
PerlIO_has_cntptr(PerlIO *f)
{
if
(PerlIOValid(f)) {
const
PerlIO_funcs *
const
tab = PerlIOBase(f)->tab;
if
(tab)
return
(tab->Get_ptr != NULL && tab->Get_cnt != NULL);
}
return
0;
}
int
PerlIO_canset_cnt(PerlIO *f)
{
if
(PerlIOValid(f)) {
const
PerlIO_funcs *
const
tab = PerlIOBase(f)->tab;
if
(tab)
return
(tab->Set_ptrcnt != NULL);
}
return
0;
}
STDCHAR *
Perl_PerlIO_get_base(pTHX_ PerlIO *f)
{
Perl_PerlIO_or_fail(f, Get_base, NULL, (aTHX_ f));
}
SSize_t
Perl_PerlIO_get_bufsiz(pTHX_ PerlIO *f)
{
Perl_PerlIO_or_fail(f, Get_bufsiz, -1, (aTHX_ f));
}
STDCHAR *
Perl_PerlIO_get_ptr(pTHX_ PerlIO *f)
{
Perl_PerlIO_or_fail(f, Get_ptr, NULL, (aTHX_ f));
}
SSize_t
Perl_PerlIO_get_cnt(pTHX_ PerlIO *f)
{
Perl_PerlIO_or_fail(f, Get_cnt, -1, (aTHX_ f));
}
void
Perl_PerlIO_set_cnt(pTHX_ PerlIO *f, SSize_t cnt)
{
Perl_PerlIO_or_fail_void(f, Set_ptrcnt, (aTHX_ f, NULL, cnt));
}
void
Perl_PerlIO_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt)
{
Perl_PerlIO_or_fail_void(f, Set_ptrcnt, (aTHX_ f, ptr, cnt));
}
IV
PerlIOUtf8_pushed(pTHX_ PerlIO *f,
const
char
*mode, SV *arg, PerlIO_funcs *tab)
{
PERL_UNUSED_CONTEXT;
PERL_UNUSED_ARG(mode);
PERL_UNUSED_ARG(arg);
if
(PerlIOValid(f)) {
if
(tab && tab->kind & PERLIO_K_UTF8)
PerlIOBase(f)->flags |= PERLIO_F_UTF8;
else
PerlIOBase(f)->flags &= ~PERLIO_F_UTF8;
return
0;
}
return
-1;
}
PERLIO_FUNCS_DECL(PerlIO_utf8) = {
sizeof
(PerlIO_funcs),
"utf8"
,
0,
PERLIO_K_DUMMY | PERLIO_K_UTF8 | PERLIO_K_MULTIARG,
PerlIOUtf8_pushed,
NULL,
PerlIOBase_open,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
PERLIO_FUNCS_DECL(PerlIO_byte) = {
sizeof
(PerlIO_funcs),
"bytes"
,
0,
PERLIO_K_DUMMY | PERLIO_K_MULTIARG,
PerlIOUtf8_pushed,
NULL,
PerlIOBase_open,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
PERLIO_FUNCS_DECL(PerlIO_raw) = {
sizeof
(PerlIO_funcs),
"raw"
,
0,
PERLIO_K_DUMMY,
PerlIORaw_pushed,
PerlIOBase_popped,
PerlIOBase_open,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
IV
PerlIOBase_fileno(pTHX_ PerlIO *f)
{
return
PerlIOValid(f) ? PerlIO_fileno(PerlIONext(f)) : -1;
}
char
*
PerlIO_modestr(PerlIO * f,
char
*buf)
{
char
*s = buf;
if
(PerlIOValid(f)) {
const
IV flags = PerlIOBase(f)->flags;
if
(flags & PERLIO_F_APPEND) {
*s++ =
'a'
;
if
(flags & PERLIO_F_CANREAD) {
*s++ =
'+'
;
}
}
else
if
(flags & PERLIO_F_CANREAD) {
*s++ =
'r'
;
if
(flags & PERLIO_F_CANWRITE)
*s++ =
'+'
;
}
else
if
(flags & PERLIO_F_CANWRITE) {
*s++ =
'w'
;
if
(flags & PERLIO_F_CANREAD) {
*s++ =
'+'
;
}
}
#ifdef PERLIO_USING_CRLF
if
(!(flags & PERLIO_F_CRLF))
*s++ =
'b'
;
#endif
}
*s =
'\0'
;
return
buf;
}
IV
PerlIOBase_pushed(pTHX_ PerlIO *f,
const
char
*mode, SV *arg, PerlIO_funcs *tab)
{
PerlIOl *
const
l = PerlIOBase(f);
PERL_UNUSED_CONTEXT;
PERL_UNUSED_ARG(arg);
l->flags &= ~(PERLIO_F_CANREAD | PERLIO_F_CANWRITE |
PERLIO_F_TRUNCATE | PERLIO_F_APPEND);
if
(tab && tab->Set_ptrcnt != NULL)
l->flags |= PERLIO_F_FASTGETS;
if
(mode) {
if
(*mode == IoTYPE_NUMERIC || *mode == IoTYPE_IMPLICIT)
mode++;
switch
(*mode++) {
case
'r'
:
l->flags |= PERLIO_F_CANREAD;
break
;
case
'a'
:
l->flags |= PERLIO_F_APPEND | PERLIO_F_CANWRITE;
break
;
case
'w'
:
l->flags |= PERLIO_F_TRUNCATE | PERLIO_F_CANWRITE;
break
;
default
:
SETERRNO(EINVAL, LIB_INVARG);
return
-1;
}
#ifdef __MVS__ /* XXX Perhaps should be be OEMVS instead of __MVS__ */
{
int
comma = 0;
while
(*mode) {
switch
(*mode++) {
case
'+'
:
if
(!comma)
l->flags |= PERLIO_F_CANREAD | PERLIO_F_CANWRITE;
break
;
case
'b'
:
if
(!comma)
l->flags &= ~PERLIO_F_CRLF;
break
;
case
't'
:
if
(!comma)
l->flags |= PERLIO_F_CRLF;
break
;
case
','
:
comma = 1;
break
;
default
:
break
;
}
}
}
#else
while
(*mode) {
switch
(*mode++) {
case
'+'
:
l->flags |= PERLIO_F_CANREAD | PERLIO_F_CANWRITE;
break
;
case
'b'
:
l->flags &= ~PERLIO_F_CRLF;
break
;
case
't'
:
l->flags |= PERLIO_F_CRLF;
break
;
default
:
SETERRNO(EINVAL, LIB_INVARG);
return
-1;
}
}
#endif
}
else
{
if
(l->next) {
l->flags |= l->next->flags &
(PERLIO_F_CANREAD | PERLIO_F_CANWRITE | PERLIO_F_TRUNCATE |
PERLIO_F_APPEND);
}
}
#if 0
DEBUG_i(
PerlIO_debug(
"PerlIOBase_pushed f=%p %s %s fl=%08"
UVxf
" (%s)\n"
,
(
void
*)f, PerlIOBase(f)->tab->name, (omode) ? omode :
"(Null)"
,
l->flags, PerlIO_modestr(f, temp));
);
#endif
return
0;
}
IV
PerlIOBase_popped(pTHX_ PerlIO *f)
{
PERL_UNUSED_CONTEXT;
PERL_UNUSED_ARG(f);
return
0;
}
SSize_t
PerlIOBase_unread(pTHX_ PerlIO *f,
const
void
*vbuf, Size_t count)
{
const
Off_t old = PerlIO_tell(f);
PerlIO_push(aTHX_ f, PERLIO_FUNCS_CAST(&PerlIO_pending),
"r"
, NULL);
PerlIOSelf(f, PerlIOBuf)->posn = old;
return
PerlIOBuf_unread(aTHX_ f, vbuf, count);
}
SSize_t
PerlIOBase_read(pTHX_ PerlIO *f,
void
*vbuf, Size_t count)
{
STDCHAR *buf = (STDCHAR *) vbuf;
if
(f) {
if
(!(PerlIOBase(f)->flags & PERLIO_F_CANREAD)) {
PerlIOBase(f)->flags |= PERLIO_F_ERROR;
SETERRNO(EBADF, SS_IVCHAN);
PerlIO_save_errno(f);
return
0;
}
while
(count > 0) {
get_cnt:
{
SSize_t avail = PerlIO_get_cnt(f);
SSize_t take = 0;
if
(avail > 0)
take = (((SSize_t) count >= 0) && ((SSize_t)count < avail)) ? (SSize_t)count : avail;
if
(take > 0) {
STDCHAR *ptr = PerlIO_get_ptr(f);
Copy(ptr, buf, take, STDCHAR);
PerlIO_set_ptrcnt(f, ptr + take, (avail -= take));
count -= take;
buf += take;
if
(avail == 0)
goto
get_cnt;
}
if
(count > 0 && avail <= 0) {
if
(PerlIO_fill(f) != 0)
break
;
}
}
}
return
(buf - (STDCHAR *) vbuf);
}
return
0;
}
IV
PerlIOBase_noop_ok(pTHX_ PerlIO *f)
{
PERL_UNUSED_CONTEXT;
PERL_UNUSED_ARG(f);
return
0;
}
IV
PerlIOBase_noop_fail(pTHX_ PerlIO *f)
{
PERL_UNUSED_CONTEXT;
PERL_UNUSED_ARG(f);
return
-1;
}
IV
PerlIOBase_close(pTHX_ PerlIO *f)
{
IV code = -1;
if
(PerlIOValid(f)) {
PerlIO *n = PerlIONext(f);
code = PerlIO_flush(f);
PerlIOBase(f)->flags &=
~(PERLIO_F_CANREAD | PERLIO_F_CANWRITE | PERLIO_F_OPEN);
while
(PerlIOValid(n)) {
const
PerlIO_funcs *
const
tab = PerlIOBase(n)->tab;
if
(tab && tab->Close) {
if
((*tab->Close)(aTHX_ n) != 0)
code = -1;
break
;
}
else
{
PerlIOBase(n)->flags &=
~(PERLIO_F_CANREAD | PERLIO_F_CANWRITE | PERLIO_F_OPEN);
}
n = PerlIONext(n);
}
}
else
{
SETERRNO(EBADF, SS_IVCHAN);
}
return
code;
}
IV
PerlIOBase_eof(pTHX_ PerlIO *f)
{
PERL_UNUSED_CONTEXT;
if
(PerlIOValid(f)) {
return
(PerlIOBase(f)->flags & PERLIO_F_EOF) != 0;
}
return
1;
}
IV
PerlIOBase_error(pTHX_ PerlIO *f)
{
PERL_UNUSED_CONTEXT;
if
(PerlIOValid(f)) {
return
(PerlIOBase(f)->flags & PERLIO_F_ERROR) != 0;
}
return
1;
}
void
PerlIOBase_clearerr(pTHX_ PerlIO *f)
{
if
(PerlIOValid(f)) {
PerlIO *
const
n = PerlIONext(f);
PerlIOBase(f)->flags &= ~(PERLIO_F_ERROR | PERLIO_F_EOF);
if
(PerlIOValid(n))
PerlIO_clearerr(n);
}
}
void
PerlIOBase_setlinebuf(pTHX_ PerlIO *f)
{
PERL_UNUSED_CONTEXT;
if
(PerlIOValid(f)) {
PerlIOBase(f)->flags |= PERLIO_F_LINEBUF;
}
}
SV *
PerlIO_sv_dup(pTHX_ SV *arg, CLONE_PARAMS *param)
{
if
(!arg)
return
NULL;
#ifdef USE_ITHREADS
if
(param) {
arg = sv_dup(arg, param);
SvREFCNT_inc_simple_void_NN(arg);
return
arg;
}
else
{
return
newSVsv(arg);
}
#else
PERL_UNUSED_ARG(param);
return
newSVsv(arg);
#endif
}
PerlIO *
PerlIOBase_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param,
int
flags)
{
PerlIO *
const
nexto = PerlIONext(o);
if
(PerlIOValid(nexto)) {
const
PerlIO_funcs *
const
tab = PerlIOBase(nexto)->tab;
if
(tab && tab->Dup)
f = (*tab->Dup)(aTHX_ f, nexto, param, flags);
else
f = PerlIOBase_dup(aTHX_ f, nexto, param, flags);
}
if
(f) {
PerlIO_funcs *
const
self = PerlIOBase(o)->tab;
SV *arg = NULL;
char
buf[8];
assert
(self);
DEBUG_i(PerlIO_debug(
"PerlIOBase_dup %s f=%p o=%p param=%p\n"
,
self->name,
(
void
*)f, (
void
*)o, (
void
*)param) );
if
(self->Getarg)
arg = (*self->Getarg)(aTHX_ o, param, flags);
f = PerlIO_push(aTHX_ f, self, PerlIO_modestr(o,buf), arg);
if
(f && PerlIOBase(o)->flags & PERLIO_F_UTF8)
PerlIOBase(f)->flags |= PERLIO_F_UTF8;
SvREFCNT_dec(arg);
}
return
f;
}
static
void
S_more_refcounted_fds(pTHX_
const
int
new_fd)
PERL_TSA_REQUIRES(PL_perlio_mutex)
{
const
int
old_max = PL_perlio_fd_refcnt_size;
const
int
new_max = 16 + (new_fd & ~15);
int
*new_array;
#ifndef PERL_IMPLICIT_SYS
PERL_UNUSED_CONTEXT;
#endif
DEBUG_i( PerlIO_debug(
"More fds - old=%d, need %d, new=%d\n"
,
old_max, new_fd, new_max) );
if
(new_fd < old_max) {
return
;
}
assert
(new_max > new_fd);
new_array = (
int
*)
realloc
(PL_perlio_fd_refcnt, new_max *
sizeof
(
int
));
if
(!new_array) {
MUTEX_UNLOCK(&PL_perlio_mutex);
croak_no_mem_ext(STR_WITH_LEN(
"perlio:more_refcounted_fds"
));
}
PL_perlio_fd_refcnt_size = new_max;
PL_perlio_fd_refcnt = new_array;
DEBUG_i( PerlIO_debug(
"Zeroing %p, %d\n"
,
(
void
*)(new_array + old_max),
new_max - old_max) );
Zero(new_array + old_max, new_max - old_max,
int
);
}
void
PerlIO_init(pTHX)
{
PERL_UNUSED_CONTEXT;
}
void
PerlIOUnix_refcnt_inc(
int
fd)
{
dTHX;
if
(fd >= 0) {
MUTEX_LOCK(&PL_perlio_mutex);
if
(fd >= PL_perlio_fd_refcnt_size)
S_more_refcounted_fds(aTHX_ fd);
PL_perlio_fd_refcnt[fd]++;
if
(PL_perlio_fd_refcnt[fd] <= 0) {
Perl_croak(aTHX_
"refcnt_inc: fd %d: %d <= 0\n"
,
fd, PL_perlio_fd_refcnt[fd]);
}
DEBUG_i( PerlIO_debug(
"refcnt_inc: fd %d refcnt=%d\n"
,
fd, PL_perlio_fd_refcnt[fd]) );
MUTEX_UNLOCK(&PL_perlio_mutex);
}
else
{
Perl_croak(aTHX_
"refcnt_inc: fd %d < 0\n"
, fd);
}
}
int
PerlIOUnix_refcnt_dec(
int
fd)
{
int
cnt = 0;
if
(fd >= 0) {
#ifdef DEBUGGING
dTHX;
#endif
MUTEX_LOCK(&PL_perlio_mutex);
if
(fd >= PL_perlio_fd_refcnt_size) {
Perl_croak_nocontext(
"refcnt_dec: fd %d >= refcnt_size %d\n"
,
fd, PL_perlio_fd_refcnt_size);
}
if
(PL_perlio_fd_refcnt[fd] <= 0) {
Perl_croak_nocontext(
"refcnt_dec: fd %d: %d <= 0\n"
,
fd, PL_perlio_fd_refcnt[fd]);
}
cnt = --PL_perlio_fd_refcnt[fd];
DEBUG_i( PerlIO_debug(
"refcnt_dec: fd %d refcnt=%d\n"
, fd, cnt) );
MUTEX_UNLOCK(&PL_perlio_mutex);
}
else
{
Perl_croak_nocontext(
"refcnt_dec: fd %d < 0\n"
, fd);
}
return
cnt;
}
int
PerlIOUnix_refcnt(
int
fd)
{
dTHX;
int
cnt = 0;
if
(fd >= 0) {
MUTEX_LOCK(&PL_perlio_mutex);
if
(fd >= PL_perlio_fd_refcnt_size) {
Perl_croak(aTHX_
"refcnt: fd %d >= refcnt_size %d\n"
,
fd, PL_perlio_fd_refcnt_size);
}
if
(PL_perlio_fd_refcnt[fd] <= 0) {
Perl_croak(aTHX_
"refcnt: fd %d: %d <= 0\n"
,
fd, PL_perlio_fd_refcnt[fd]);
}
cnt = PL_perlio_fd_refcnt[fd];
MUTEX_UNLOCK(&PL_perlio_mutex);
}
else
{
Perl_croak(aTHX_
"refcnt: fd %d < 0\n"
, fd);
}
return
cnt;
}
void
PerlIO_cleanup(pTHX)
{
int
i;
#ifdef USE_ITHREADS
DEBUG_i( PerlIO_debug(
"Cleanup layers for %p\n"
,(
void
*)aTHX) );
#else
DEBUG_i( PerlIO_debug(
"Cleanup layers\n"
) );
#endif
for
(i=0; i < 3; i++)
PerlIOUnix_refcnt_inc(i);
PerlIO_cleantable(aTHX_ &PL_perlio);
for
(i=0; i < 3; i++)
PerlIOUnix_refcnt_dec(i);
if
(PL_known_layers) {
PerlIO_list_free(aTHX_ PL_known_layers);
PL_known_layers = NULL;
}
if
(PL_def_layerlist) {
PerlIO_list_free(aTHX_ PL_def_layerlist);
PL_def_layerlist = NULL;
}
}
void
PerlIO_teardown(
void
)
{
#if 0
# ifdef DEBUGGING
{
#define PERLIO_TEARDOWN_MESSAGE_BUF_SIZE 64
#define PERLIO_TEARDOWN_MESSAGE_FD 2
char
buf[PERLIO_TEARDOWN_MESSAGE_BUF_SIZE];
int
i;
for
(i = 3; i < PL_perlio_fd_refcnt_size; i++) {
if
(PL_perlio_fd_refcnt[i]) {
const
STRLEN len =
my_snprintf(buf,
sizeof
(buf),
"PerlIO_teardown: fd %d refcnt=%d\n"
,
i, PL_perlio_fd_refcnt[i]);
PerlLIO_write(PERLIO_TEARDOWN_MESSAGE_FD, buf, len);
}
}
}
# endif
#endif
if
(PL_perlio_fd_refcnt_size
&& PL_perlio_fd_refcnt) {
free
(PL_perlio_fd_refcnt);
PL_perlio_fd_refcnt = NULL;
PL_perlio_fd_refcnt_size = 0;
}
}
typedef
struct
{
struct
_PerlIO base;
int
fd;
int
oflags;
} PerlIOUnix;
static
void
S_lockcnt_dec(pTHX_
const
void
* f)
{
#ifndef PERL_IMPLICIT_SYS
PERL_UNUSED_CONTEXT;
#endif
PerlIO_lockcnt((PerlIO*)f)--;
}
static
bool
S_perlio_async_run(pTHX_ PerlIO* f) {
ENTER;
SAVEDESTRUCTOR_X(S_lockcnt_dec, (
void
*)f);
PerlIO_lockcnt(f)++;
PERL_ASYNC_CHECK();
if
( !(PerlIOBase(f)->flags & PERLIO_F_CLEARED) ) {
LEAVE;
return
0;
}
while
(PerlIOValid(f) &&
(PerlIOBase(f)->flags & PERLIO_F_CLEARED))
{
const
PerlIOl *l = *f;
*f = l->next;
Safefree(l);
}
LEAVE;
return
1;
}
int
PerlIOUnix_oflags(
const
char
*mode)
{
int
oflags = -1;
if
(*mode == IoTYPE_IMPLICIT || *mode == IoTYPE_NUMERIC)
mode++;
switch
(*mode) {
case
'r'
:
oflags = O_RDONLY;
if
(*++mode ==
'+'
) {
oflags = O_RDWR;
mode++;
}
break
;
case
'w'
:
oflags = O_CREAT | O_TRUNC;
if
(*++mode ==
'+'
) {
oflags |= O_RDWR;
mode++;
}
else
oflags |= O_WRONLY;
break
;
case
'a'
:
oflags = O_CREAT | O_APPEND;
if
(*++mode ==
'+'
) {
oflags |= O_RDWR;
mode++;
}
else
oflags |= O_WRONLY;
break
;
}
switch
(*mode) {
case
'b'
:
#if O_TEXT != O_BINARY
oflags |= O_BINARY;
oflags &= ~O_TEXT;
#endif
mode++;
break
;
case
't'
:
#if O_TEXT != O_BINARY
oflags |= O_TEXT;
oflags &= ~O_BINARY;
#endif
mode++;
break
;
default
:
#if O_BINARY != 0
oflags |= O_BINARY;
#endif
break
;
}
if
(*mode || oflags == -1) {
SETERRNO(EINVAL, LIB_INVARG);
oflags = -1;
}
return
oflags;
}
IV
PerlIOUnix_fileno(pTHX_ PerlIO *f)
{
PERL_UNUSED_CONTEXT;
return
PerlIOSelf(f, PerlIOUnix)->fd;
}
static
void
PerlIOUnix_setfd(pTHX_ PerlIO *f,
int
fd,
int
imode)
{
PerlIOUnix *
const
s = PerlIOSelf(f, PerlIOUnix);
#if defined(WIN32)
Stat_t st;
if
(PerlLIO_fstat(fd, &st) == 0) {
if
(!S_ISREG(st.st_mode)) {
DEBUG_i( PerlIO_debug(
"%d is not regular file\n"
,fd) );
PerlIOBase(f)->flags |= PERLIO_F_NOTREG;
}
else
{
DEBUG_i( PerlIO_debug(
"%d _is_ a regular file\n"
,fd) );
}
}
#endif
s->fd = fd;
s->oflags = imode;
PerlIOUnix_refcnt_inc(fd);
PERL_UNUSED_CONTEXT;
}
IV
PerlIOUnix_pushed(pTHX_ PerlIO *f,
const
char
*mode, SV *arg, PerlIO_funcs *tab)
{
IV code = PerlIOBase_pushed(aTHX_ f, mode, arg, tab);
if
(*PerlIONext(f)) {
PerlIO_flush(PerlIONext(f));
PerlIOUnix_setfd(aTHX_ f, PerlIO_fileno(PerlIONext(f)),
mode ? PerlIOUnix_oflags(mode) : -1);
}
PerlIOBase(f)->flags |= PERLIO_F_OPEN;
return
code;
}
IV
PerlIOUnix_seek(pTHX_ PerlIO *f, Off_t offset,
int
whence)
{
const
int
fd = PerlIOSelf(f, PerlIOUnix)->fd;
Off_t new_loc;
PERL_UNUSED_CONTEXT;
if
(PerlIOBase(f)->flags & PERLIO_F_NOTREG) {
#ifdef ESPIPE
SETERRNO(ESPIPE, LIB_INVARG);
#else
SETERRNO(EINVAL, LIB_INVARG);
#endif
return
-1;
}
new_loc = PerlLIO_lseek(fd, offset, whence);
if
(new_loc == (Off_t) - 1)
return
-1;
PerlIOBase(f)->flags &= ~PERLIO_F_EOF;
return
0;
}
PerlIO *
PerlIOUnix_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers,
IV n,
const
char
*mode,
int
fd,
int
imode,
int
perm, PerlIO *f,
int
narg, SV **args)
{
bool
known_cloexec = 0;
if
(PerlIOValid(f)) {
if
(PerlIOBase(f)->tab && PerlIOBase(f)->flags & PERLIO_F_OPEN)
(*PerlIOBase(f)->tab->Close)(aTHX_ f);
}
if
(narg > 0) {
if
(*mode == IoTYPE_NUMERIC)
mode++;
else
{
imode = PerlIOUnix_oflags(mode);
#ifdef VMS
perm = 0777;
#else
perm = 0666;
#endif
}
if
(imode != -1) {
STRLEN len;
const
char
*path = SvPV_const(*args, len);
if
(!IS_SAFE_PATHNAME(path, len,
"open"
))
return
NULL;
fd = PerlLIO_open3_cloexec(path, imode, perm);
known_cloexec = 1;
}
}
if
(fd >= 0) {
if
(known_cloexec)
setfd_inhexec_for_sysfd(fd);
else
setfd_cloexec_or_inhexec_by_sysfdness(fd);
if
(*mode == IoTYPE_IMPLICIT)
mode++;
if
(!f) {
f = PerlIO_allocate(aTHX);
}
if
(!PerlIOValid(f)) {
if
(!(f = PerlIO_push(aTHX_ f, self, mode, PerlIOArg))) {
PerlLIO_close(fd);
return
NULL;
}
}
PerlIOUnix_setfd(aTHX_ f, fd, imode);
PerlIOBase(f)->flags |= PERLIO_F_OPEN;
if
(*mode == IoTYPE_APPEND)
PerlIOUnix_seek(aTHX_ f, 0, SEEK_END);
return
f;
}
else
{
if
(f) {
NOOP;
}
return
NULL;
}
}
PerlIO *
PerlIOUnix_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param,
int
flags)
{
const
PerlIOUnix *
const
os = PerlIOSelf(o, PerlIOUnix);
int
fd = os->fd;
if
(flags & PERLIO_DUP_FD) {
fd = PerlLIO_dup_cloexec(fd);
if
(fd >= 0)
setfd_inhexec_for_sysfd(fd);
}
if
(fd >= 0) {
f = PerlIOBase_dup(aTHX_ f, o, param, flags);
if
(f) {
PerlIOUnix_setfd(aTHX_ f, fd, os->oflags);
return
f;
}
PerlLIO_close(fd);
}
return
NULL;
}
SSize_t
PerlIOUnix_read(pTHX_ PerlIO *f,
void
*vbuf, Size_t count)
{
int
fd;
if
(PerlIO_lockcnt(f))
return
-1;
fd = PerlIOSelf(f, PerlIOUnix)->fd;
if
(!(PerlIOBase(f)->flags & PERLIO_F_CANREAD) ||
PerlIOBase(f)->flags & (PERLIO_F_EOF|PERLIO_F_ERROR)) {
return
0;
}
while
(1) {
const
SSize_t len = PerlLIO_read(fd, vbuf, count);
if
(len >= 0 ||
errno
!= EINTR) {
if
(len < 0) {
if
(
errno
!= EAGAIN) {
PerlIOBase(f)->flags |= PERLIO_F_ERROR;
PerlIO_save_errno(f);
}
}
else
if
(len == 0 && count != 0) {
PerlIOBase(f)->flags |= PERLIO_F_EOF;
SETERRNO(0,0);
}
return
len;
}
if
(PL_sig_pending && S_perlio_async_run(aTHX_ f))
return
-1;
}
NOT_REACHED;
}
SSize_t
PerlIOUnix_write(pTHX_ PerlIO *f,
const
void
*vbuf, Size_t count)
{
int
fd;
if
(PerlIO_lockcnt(f))
return
-1;
fd = PerlIOSelf(f, PerlIOUnix)->fd;
while
(1) {
const
SSize_t len = PerlLIO_write(fd, vbuf, count);
if
(len >= 0 ||
errno
!= EINTR) {
if
(len < 0) {
if
(
errno
!= EAGAIN) {
PerlIOBase(f)->flags |= PERLIO_F_ERROR;
PerlIO_save_errno(f);
}
}
return
len;
}
if
(PL_sig_pending && S_perlio_async_run(aTHX_ f))
return
-1;
}
NOT_REACHED;
}
Off_t
PerlIOUnix_tell(pTHX_ PerlIO *f)
{
PERL_UNUSED_CONTEXT;
return
PerlLIO_lseek(PerlIOSelf(f, PerlIOUnix)->fd, 0, SEEK_CUR);
}
IV
PerlIOUnix_close(pTHX_ PerlIO *f)
{
const
int
fd = PerlIOSelf(f, PerlIOUnix)->fd;
int
code = 0;
if
(PerlIOBase(f)->flags & PERLIO_F_OPEN) {
code = PerlIOBase_close(aTHX_ f);
if
(PerlIOUnix_refcnt_dec(fd) > 0) {
PerlIOBase(f)->flags &= ~PERLIO_F_OPEN;
return
0;
}
}
else
{
SETERRNO(EBADF,SS_IVCHAN);
return
-1;
}
while
(PerlLIO_close(fd) != 0) {
if
(
errno
!= EINTR) {
code = -1;
break
;
}
if
(PL_sig_pending && S_perlio_async_run(aTHX_ f))
return
-1;
}
if
(code == 0) {
PerlIOBase(f)->flags &= ~PERLIO_F_OPEN;
}
return
code;
}
PERLIO_FUNCS_DECL(PerlIO_unix) = {
sizeof
(PerlIO_funcs),
"unix"
,
sizeof
(PerlIOUnix),
PERLIO_K_RAW,
PerlIOUnix_pushed,
PerlIOBase_popped,
PerlIOUnix_open,
PerlIOBase_binmode,
NULL,
PerlIOUnix_fileno,
PerlIOUnix_dup,
PerlIOUnix_read,
PerlIOBase_unread,
PerlIOUnix_write,
PerlIOUnix_seek,
PerlIOUnix_tell,
PerlIOUnix_close,
PerlIOBase_noop_ok,
PerlIOBase_noop_fail,
PerlIOBase_eof,
PerlIOBase_error,
PerlIOBase_clearerr,
PerlIOBase_setlinebuf,
NULL,
NULL,
NULL,
NULL,
NULL,
};
#if defined(VMS) && !defined(STDIO_BUFFER_WRITABLE)
# define STDIO_BUFFER_WRITABLE
#endif
typedef
struct
{
struct
_PerlIO base;
FILE
*stdio;
} PerlIOStdio;
IV
PerlIOStdio_fileno(pTHX_ PerlIO *f)
{
PERL_UNUSED_CONTEXT;
if
(PerlIOValid(f)) {
FILE
*
const
s = PerlIOSelf(f, PerlIOStdio)->stdio;
if
(s)
return
PerlSIO_fileno(s);
}
errno
= EBADF;
return
-1;
}
char
*
PerlIOStdio_mode(
const
char
*mode,
char
*tmode)
{
char
*
const
ret = tmode;
if
(mode) {
while
(*mode) {
*tmode++ = *mode++;
}
}
#if defined(PERLIO_USING_CRLF) || defined(__CYGWIN__)
*tmode++ =
'b'
;
#endif
*tmode =
'\0'
;
return
ret;
}
IV
PerlIOStdio_pushed(pTHX_ PerlIO *f,
const
char
*mode, SV *arg, PerlIO_funcs *tab)
{
PerlIO *n;
if
(PerlIOValid(f) && PerlIOValid(n = PerlIONext(f))) {
PerlIO_funcs *
const
toptab = PerlIOBase(n)->tab;
if
(toptab == tab) {
PerlIO_pop(aTHX_ f);
return
0;
}
else
{
const
int
fd = PerlIO_fileno(n);
char
tmode[8];
FILE
*stdio;
if
(fd >= 0 && (stdio = PerlSIO_fdopen(fd,
mode = PerlIOStdio_mode(mode, tmode)))) {
PerlIOSelf(f, PerlIOStdio)->stdio = stdio;
PerlIO_flush(PerlIONext(f));
return
PerlIOBase_pushed(aTHX_ f, mode, arg, tab);
}
else
{
return
-1;
}
}
}
return
PerlIOBase_pushed(aTHX_ f, mode, arg, tab);
}
PerlIO *
PerlIO_importFILE(
FILE
*stdio,
const
char
*mode)
{
dTHX;
PerlIO *f = NULL;
#ifdef __MVS__
int
rc;
char
filename[FILENAME_MAX];
fldata_t fileinfo;
#endif
if
(stdio) {
PerlIOStdio *s;
int
fd0 = fileno(stdio);
if
(fd0 < 0) {
#ifdef __MVS__
rc = fldata(stdio,filename,&fileinfo);
if
(rc != 0){
return
NULL;
}
if
(fileinfo.__dsorgHFS){
return
NULL;
}
#else
return
NULL;
#endif
}
if
(!mode || !*mode) {
const
int
fd = PerlLIO_dup_cloexec(fd0);
FILE
*f2;
if
(fd < 0) {
return
f;
}
f2 = PerlSIO_fdopen(fd, (mode =
"r+"
));
if
(!f2) {
f2 = PerlSIO_fdopen(fd, (mode =
"w"
));
}
if
(!f2) {
f2 = PerlSIO_fdopen(fd, (mode =
"r"
));
}
if
(!f2) {
PerlLIO_close(fd);
return
f;
}
fclose
(f2);
}
if
((f = PerlIO_push(aTHX_(PerlIO_allocate(aTHX)), PERLIO_FUNCS_CAST(&PerlIO_stdio), mode, NULL))) {
s = PerlIOSelf(f, PerlIOStdio);
s->stdio = stdio;
fd0 = fileno(stdio);
if
(fd0 != -1){
PerlIOUnix_refcnt_inc(fd0);
setfd_cloexec_or_inhexec_by_sysfdness(fd0);
}
#ifdef __MVS__
else
{
rc = fldata(stdio,filename,&fileinfo);
if
(rc != 0){
PerlIOUnix_refcnt_inc(fd0);
}
if
(fileinfo.__dsorgHFS){
PerlIOUnix_refcnt_inc(fd0);
}
}
#endif
}
}
return
f;
}
PerlIO *
PerlIOStdio_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers,
IV n,
const
char
*mode,
int
fd,
int
imode,
int
perm, PerlIO *f,
int
narg, SV **args)
{
char
tmode[8];
if
(PerlIOValid(f)) {
STRLEN len;
const
char
*
const
path = SvPV_const(*args, len);
PerlIOStdio *
const
s = PerlIOSelf(f, PerlIOStdio);
FILE
*stdio;
if
(!IS_SAFE_PATHNAME(path, len,
"open"
))
return
NULL;
PerlIOUnix_refcnt_dec(fileno(s->stdio));
stdio = PerlSIO_freopen(path, PerlIOStdio_mode(mode, tmode),
s->stdio);
if
(!s->stdio)
return
NULL;
s->stdio = stdio;
fd = fileno(stdio);
PerlIOUnix_refcnt_inc(fd);
setfd_cloexec_or_inhexec_by_sysfdness(fd);
return
f;
}
else
{
if
(narg > 0) {
STRLEN len;
const
char
*
const
path = SvPV_const(*args, len);
if
(!IS_SAFE_PATHNAME(path, len,
"open"
))
return
NULL;
if
(*mode == IoTYPE_NUMERIC) {
mode++;
fd = PerlLIO_open3_cloexec(path, imode, perm);
}
else
{
FILE
*stdio;
bool
appended = FALSE;
#ifdef __CYGWIN__
appended = TRUE;
mode = PerlIOStdio_mode(mode, tmode);
#endif
stdio = PerlSIO_fopen(path, mode);
if
(stdio) {
if
(!f) {
f = PerlIO_allocate(aTHX);
}
if
(!appended)
mode = PerlIOStdio_mode(mode, tmode);
f = PerlIO_push(aTHX_ f, self, mode, PerlIOArg);
if
(f) {
PerlIOSelf(f, PerlIOStdio)->stdio = stdio;
fd = fileno(stdio);
PerlIOUnix_refcnt_inc(fd);
setfd_cloexec_or_inhexec_by_sysfdness(fd);
}
else
{
PerlSIO_fclose(stdio);
}
return
f;
}
else
{
return
NULL;
}
}
}
if
(fd >= 0) {
FILE
*stdio = NULL;
int
init = 0;
if
(*mode == IoTYPE_IMPLICIT) {
init = 1;
mode++;
}
if
(init) {
switch
(fd) {
case
0:
stdio = PerlSIO_stdin;
break
;
case
1:
stdio = PerlSIO_stdout;
break
;
case
2:
stdio = PerlSIO_stderr;
break
;
}
}
else
{
stdio = PerlSIO_fdopen(fd, mode =
PerlIOStdio_mode(mode, tmode));
}
if
(stdio) {
if
(!f) {
f = PerlIO_allocate(aTHX);
}
if
((f = PerlIO_push(aTHX_ f, self, mode, PerlIOArg))) {
PerlIOSelf(f, PerlIOStdio)->stdio = stdio;
fd = fileno(stdio);
PerlIOUnix_refcnt_inc(fd);
setfd_cloexec_or_inhexec_by_sysfdness(fd);
}
return
f;
}
PerlLIO_close(fd);
}
}
return
NULL;
}
PerlIO *
PerlIOStdio_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param,
int
flags)
{
if
((f = PerlIOBase_dup(aTHX_ f, o, param, flags))) {
FILE
*stdio = PerlIOSelf(o, PerlIOStdio)->stdio;
const
int
fd = fileno(stdio);
char
mode[8];
if
(flags & PERLIO_DUP_FD) {
const
int
dfd = PerlLIO_dup_cloexec(fileno(stdio));
if
(dfd >= 0) {
stdio = PerlSIO_fdopen(dfd, PerlIO_modestr(o,mode));
goto
set_this;
}
else
{
NOOP;
}
}
stdio = PerlSIO_fdopen(fd, PerlIO_modestr(o,mode));
set_this:
PerlIOSelf(f, PerlIOStdio)->stdio = stdio;
if
(stdio) {
int
fd = fileno(stdio);
PerlIOUnix_refcnt_inc(fd);
setfd_cloexec_or_inhexec_by_sysfdness(fd);
}
}
return
f;
}
static
int
PerlIOStdio_invalidate_fileno(pTHX_
FILE
*f)
{
PERL_UNUSED_CONTEXT;
#if defined(HAS_FDCLOSE)
return
fdclose(f, NULL) == 0 ? 1 : 0;
#elif defined(__UCLIBC__)
f->__filedes = -1;
return
1;
#elif defined(__GLIBC__)
f->_fileno = -1;
return
1;
#elif defined(__sun)
PERL_UNUSED_ARG(f);
return
0;
#elif defined(__hpux)
f->__fileH = 0xff;
f->__fileL = 0xff;
return
1;
#elif defined(_AIX) || defined(__osf__) || defined(__irix__)
f->_file = -1;
return
1;
#elif defined(__FreeBSD__)
f->_file = -1;
return
1;
#elif defined(__OpenBSD__)
f->_file = -1;
return
1;
#elif defined(__EMX__)
f->_handle = -1;
return
1;
#elif defined(__CYGWIN__)
f->_file = -1;
return
1;
#elif defined(WIN32)
PERLIO_FILE_file(f) = -1;
return
1;
#else
# if 0
# error "Don't know how to set FILE.fileno on your platform"
# endif
PERL_UNUSED_ARG(f);
return
0;
#endif
}
IV
PerlIOStdio_close(pTHX_ PerlIO *f)
{
FILE
*
const
stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
if
(!stdio) {
errno
= EBADF;
return
-1;
}
else
{
const
int
fd = fileno(stdio);
int
invalidate = 0;
IV result = 0;
int
dupfd = -1;
dSAVEDERRNO;
#ifdef SOCKS5_VERSION_NAME
int
optval;
Sock_size_t optlen =
sizeof
(
int
);
if
(getsockopt(fd, SOL_SOCKET, SO_TYPE, (
void
*) &optval, &optlen) == 0)
invalidate = 1;
#endif
if
(fd != -1 && PerlIOUnix_refcnt_dec(fd) > 0) {
invalidate = 1;
}
if
(invalidate) {
if
(stdio == stdin)
return
0;
if
(stdio == stdout || stdio == stderr)
return
PerlIO_flush(f);
}
MUTEX_LOCK(&PL_perlio_mutex);
if
(invalidate) {
result = PerlIO_flush(f);
SAVE_ERRNO;
invalidate = PerlIOStdio_invalidate_fileno(aTHX_ stdio);
if
(!invalidate) {
dupfd = PerlLIO_dup_cloexec(fd);
#ifdef USE_ITHREADS
if
(dupfd < 0) {
}
#endif
}
}
else
{
SAVE_ERRNO;
}
result = PerlSIO_fclose(stdio);
if
(invalidate && result != 0) {
RESTORE_ERRNO;
result = 0;
}
#ifdef SOCKS5_VERSION_NAME
result = close(fd);
#endif
if
(dupfd >= 0) {
PerlLIO_dup2_cloexec(dupfd, fd);
setfd_inhexec_for_sysfd(fd);
PerlLIO_close(dupfd);
}
MUTEX_UNLOCK(&PL_perlio_mutex);
return
result;
}
}
SSize_t
PerlIOStdio_read(pTHX_ PerlIO *f,
void
*vbuf, Size_t count)
{
FILE
* s;
SSize_t got = 0;
if
(PerlIO_lockcnt(f))
return
-1;
s = PerlIOSelf(f, PerlIOStdio)->stdio;
for
(;;) {
if
(count == 1) {
STDCHAR *buf = (STDCHAR *) vbuf;
const
int
ch = PerlSIO_fgetc(s);
if
(ch != EOF) {
*buf = ch;
got = 1;
}
}
else
got = PerlSIO_fread(vbuf, 1, count, s);
if
(got == 0 && PerlSIO_ferror(s))
got = -1;
if
(got >= 0 ||
errno
!= EINTR)
break
;
if
(PL_sig_pending && S_perlio_async_run(aTHX_ f))
return
-1;
SETERRNO(0,0);
}
#ifdef __sgi
if
(
errno
== ENOENT) SETERRNO(0,0);
#endif
return
got;
}
SSize_t
PerlIOStdio_unread(pTHX_ PerlIO *f,
const
void
*vbuf, Size_t count)
{
SSize_t unread = 0;
FILE
*
const
s = PerlIOSelf(f, PerlIOStdio)->stdio;
#ifdef STDIO_BUFFER_WRITABLE
if
(PerlIO_fast_gets(f) && PerlIO_has_base(f)) {
STDCHAR *buf = ((STDCHAR *) vbuf) + count;
STDCHAR *base = PerlIO_get_base(f);
SSize_t cnt = PerlIO_get_cnt(f);
STDCHAR *ptr = PerlIO_get_ptr(f);
SSize_t avail = ptr - base;
if
(avail > 0) {
if
(avail > count) {
avail = count;
}
ptr -= avail;
Move(buf-avail,ptr,avail,STDCHAR);
count -= avail;
unread += avail;
PerlIO_set_ptrcnt(f,ptr,cnt+avail);
if
(PerlSIO_feof(s) && unread >= 0)
PerlSIO_clearerr(s);
}
}
else
#endif
if
(PerlIO_has_cntptr(f)) {
STDCHAR *eptr = (STDCHAR*)PerlSIO_get_ptr(s);
STDCHAR *buf = ((STDCHAR *) vbuf) + count;
while
(count > 0) {
const
int
ch = (U8) *--buf;
if
(
ungetc
(ch,s) != ch) {
break
;
}
if
((STDCHAR*)PerlSIO_get_ptr(s) != --eptr || (((U8) *eptr) != ch)) {
if
(
fgetc
(s) != EOF)
break
;
}
count--;
unread++;
}
}
if
(count > 0) {
unread += PerlIOBase_unread(aTHX_ f, vbuf, count);
}
return
unread;
}
SSize_t
PerlIOStdio_write(pTHX_ PerlIO *f,
const
void
*vbuf, Size_t count)
{
SSize_t got;
if
(PerlIO_lockcnt(f))
return
-1;
for
(;;) {
got = PerlSIO_fwrite(vbuf, 1, count,
PerlIOSelf(f, PerlIOStdio)->stdio);
if
(got >= 0 ||
errno
!= EINTR)
break
;
if
(PL_sig_pending && S_perlio_async_run(aTHX_ f))
return
-1;
SETERRNO(0,0);
}
return
got;
}
IV
PerlIOStdio_seek(pTHX_ PerlIO *f, Off_t offset,
int
whence)
{
FILE
*
const
stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
PERL_UNUSED_CONTEXT;
return
PerlSIO_fseek(stdio, offset, whence);
}
Off_t
PerlIOStdio_tell(pTHX_ PerlIO *f)
{
FILE
*
const
stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
PERL_UNUSED_CONTEXT;
return
PerlSIO_ftell(stdio);
}
IV
PerlIOStdio_flush(pTHX_ PerlIO *f)
{
FILE
*
const
stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
PERL_UNUSED_CONTEXT;
if
(PerlIOBase(f)->flags & PERLIO_F_CANWRITE) {
return
PerlSIO_fflush(stdio);
}
else
{
NOOP;
#if 0
dSAVE_ERRNO;
if
(PerlSIO_fseek(stdio, (Off_t) 0, SEEK_CUR) != 0)
RESTORE_ERRNO;
#endif
}
return
0;
}
IV
PerlIOStdio_eof(pTHX_ PerlIO *f)
{
PERL_UNUSED_CONTEXT;
return
PerlSIO_feof(PerlIOSelf(f, PerlIOStdio)->stdio);
}
IV
PerlIOStdio_error(pTHX_ PerlIO *f)
{
PERL_UNUSED_CONTEXT;
return
PerlSIO_ferror(PerlIOSelf(f, PerlIOStdio)->stdio);
}
void
PerlIOStdio_clearerr(pTHX_ PerlIO *f)
{
PERL_UNUSED_CONTEXT;
PerlSIO_clearerr(PerlIOSelf(f, PerlIOStdio)->stdio);
}
void
PerlIOStdio_setlinebuf(pTHX_ PerlIO *f)
{
PERL_UNUSED_CONTEXT;
#ifdef HAS_SETLINEBUF
PerlSIO_setlinebuf(PerlIOSelf(f, PerlIOStdio)->stdio);
#else
PerlSIO_setvbuf(PerlIOSelf(f, PerlIOStdio)->stdio, NULL, _IOLBF, 0);
#endif
}
#ifdef FILE_base
STDCHAR *
PerlIOStdio_get_base(pTHX_ PerlIO *f)
{
FILE
*
const
stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
PERL_UNUSED_CONTEXT;
return
(STDCHAR*)PerlSIO_get_base(stdio);
}
Size_t
PerlIOStdio_get_bufsiz(pTHX_ PerlIO *f)
{
FILE
*
const
stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
PERL_UNUSED_CONTEXT;
return
PerlSIO_get_bufsiz(stdio);
}
#endif
#ifdef USE_STDIO_PTR
STDCHAR *
PerlIOStdio_get_ptr(pTHX_ PerlIO *f)
{
FILE
*
const
stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
PERL_UNUSED_CONTEXT;
return
(STDCHAR*)PerlSIO_get_ptr(stdio);
}
SSize_t
PerlIOStdio_get_cnt(pTHX_ PerlIO *f)
{
FILE
*
const
stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
PERL_UNUSED_CONTEXT;
return
PerlSIO_get_cnt(stdio);
}
void
PerlIOStdio_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt)
{
FILE
*
const
stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
PERL_UNUSED_CONTEXT;
if
(ptr != NULL) {
# ifdef STDIO_PTR_LVALUE
GCC_DIAG_IGNORE_STMT(-Wpointer-sign);
PerlSIO_set_ptr(stdio, ptr);
GCC_DIAG_RESTORE_STMT;
# ifdef STDIO_PTR_LVAL_SETS_CNT
assert
(PerlSIO_get_cnt(stdio) == (cnt));
# endif
# if (!defined(STDIO_PTR_LVAL_NOCHANGE_CNT))
return
;
# endif
# else /* STDIO_PTR_LVALUE */
PerlProc_abort();
# endif /* STDIO_PTR_LVALUE */
}
# ifdef STDIO_CNT_LVALUE
PerlSIO_set_cnt(stdio, cnt);
# elif (defined(STDIO_PTR_LVALUE) && defined(STDIO_PTR_LVAL_SETS_CNT))
PerlSIO_set_ptr(stdio,
PerlSIO_get_ptr(stdio) + (PerlSIO_get_cnt(stdio) -
cnt));
# else /* STDIO_PTR_LVAL_SETS_CNT */
PerlProc_abort();
# endif /* STDIO_CNT_LVALUE */
}
#endif
IV
PerlIOStdio_fill(pTHX_ PerlIO *f)
{
FILE
* stdio;
int
c;
PERL_UNUSED_CONTEXT;
if
(PerlIO_lockcnt(f))
return
-1;
stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
if
((PerlIOBase(f)->flags & PERLIO_F_CANWRITE)) {
if
(PerlSIO_fflush(stdio) != 0)
return
EOF;
}
for
(;;) {
c = PerlSIO_fgetc(stdio);
if
(c != EOF)
break
;
if
(! PerlSIO_ferror(stdio) ||
errno
!= EINTR)
return
EOF;
if
(PL_sig_pending && S_perlio_async_run(aTHX_ f))
return
-1;
SETERRNO(0,0);
}
#if (defined(STDIO_PTR_LVALUE) && (defined(STDIO_CNT_LVALUE) || defined(STDIO_PTR_LVAL_SETS_CNT)))
# ifdef STDIO_BUFFER_WRITABLE
if
(PerlIO_fast_gets(f) && PerlIO_has_base(f)) {
STDCHAR *base = (STDCHAR*)PerlSIO_get_base(stdio);
SSize_t cnt = PerlSIO_get_cnt(stdio);
STDCHAR *ptr = (STDCHAR*)PerlSIO_get_ptr(stdio);
if
(ptr == base+1) {
*--ptr = (STDCHAR) c;
PerlIOStdio_set_ptrcnt(aTHX_ f,ptr,cnt+1);
if
(PerlSIO_feof(stdio))
PerlSIO_clearerr(stdio);
return
0;
}
}
else
# endif
if
(PerlIO_has_cntptr(f)) {
STDCHAR ch = c;
if
(PerlIOStdio_unread(aTHX_ f,&ch,1) == 1) {
return
0;
}
}
#endif
if
(PerlSIO_ungetc(c, stdio) != c)
return
EOF;
return
0;
}
PERLIO_FUNCS_DECL(PerlIO_stdio) = {
sizeof
(PerlIO_funcs),
"stdio"
,
sizeof
(PerlIOStdio),
PERLIO_K_BUFFERED|PERLIO_K_RAW,
PerlIOStdio_pushed,
PerlIOBase_popped,
PerlIOStdio_open,
PerlIOBase_binmode,
NULL,
PerlIOStdio_fileno,
PerlIOStdio_dup,
PerlIOStdio_read,
PerlIOStdio_unread,
PerlIOStdio_write,
PerlIOStdio_seek,
PerlIOStdio_tell,
PerlIOStdio_close,
PerlIOStdio_flush,
PerlIOStdio_fill,
PerlIOStdio_eof,
PerlIOStdio_error,
PerlIOStdio_clearerr,
PerlIOStdio_setlinebuf,
#ifdef FILE_base
PerlIOStdio_get_base,
PerlIOStdio_get_bufsiz,
#else
NULL,
NULL,
#endif
#ifdef USE_STDIO_PTR
PerlIOStdio_get_ptr,
PerlIOStdio_get_cnt,
# if defined(HAS_FAST_STDIO) && defined(USE_FAST_STDIO)
PerlIOStdio_set_ptrcnt,
# else
NULL,
# endif /* HAS_FAST_STDIO && USE_FAST_STDIO */
#else
NULL,
NULL,
NULL,
#endif /* USE_STDIO_PTR */
};
FILE
*
PerlIO_exportFILE(PerlIO * f,
const
char
*mode)
{
dTHX;
FILE
*stdio = NULL;
if
(PerlIOValid(f)) {
char
buf[8];
int
fd = PerlIO_fileno(f);
if
(fd < 0) {
return
NULL;
}
PerlIO_flush(f);
if
(!mode || !*mode) {
mode = PerlIO_modestr(f, buf);
}
stdio = PerlSIO_fdopen(PerlIO_fileno(f), mode);
if
(stdio) {
PerlIOl *l = *f;
PerlIO *f2;
*f = NULL;
if
((f2 = PerlIO_push(aTHX_ f, PERLIO_FUNCS_CAST(&PerlIO_stdio), buf, NULL))) {
PerlIOStdio *s = PerlIOSelf((f = f2), PerlIOStdio);
s->stdio = stdio;
PerlIOUnix_refcnt_inc(fileno(stdio));
*PerlIONext(f) = l;
}
else
{
*f = l;
}
}
}
return
stdio;
}
FILE
*
PerlIO_findFILE(PerlIO *f)
{
PerlIOl *l = *f;
FILE
*stdio;
while
(l) {
if
(l->tab == &PerlIO_stdio) {
PerlIOStdio *s = PerlIOSelf(&l, PerlIOStdio);
return
s->stdio;
}
l = *PerlIONext(&l);
}
stdio = PerlIO_exportFILE(f, NULL);
if
(stdio) {
const
int
fd = fileno(stdio);
if
(fd >= 0)
PerlIOUnix_refcnt_dec(fd);
}
return
stdio;
}
void
PerlIO_releaseFILE(PerlIO *p,
FILE
*f)
{
PerlIOl *l;
while
((l = *p)) {
if
(l->tab == &PerlIO_stdio) {
PerlIOStdio *s = PerlIOSelf(&l, PerlIOStdio);
if
(s->stdio == f) {
const
int
fd = fileno(f);
if
(fd >= 0)
PerlIOUnix_refcnt_dec(fd);
{
dTHX;
PerlIO_pop(aTHX_ p);
}
return
;
}
}
p = PerlIONext(p);
}
return
;
}
IV
PerlIOBuf_pushed(pTHX_ PerlIO *f,
const
char
*mode, SV *arg, PerlIO_funcs *tab)
{
PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf);
const
int
fd = PerlIO_fileno(f);
if
(fd >= 0 && PerlLIO_isatty(fd)) {
PerlIOBase(f)->flags |= PERLIO_F_LINEBUF | PERLIO_F_TTY;
}
if
(*PerlIONext(f)) {
const
Off_t posn = PerlIO_tell(PerlIONext(f));
if
(posn != (Off_t) - 1) {
b->posn = posn;
}
}
return
PerlIOBase_pushed(aTHX_ f, mode, arg, tab);
}
PerlIO *
PerlIOBuf_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers,
IV n,
const
char
*mode,
int
fd,
int
imode,
int
perm,
PerlIO *f,
int
narg, SV **args)
{
if
(PerlIOValid(f)) {
PerlIO *next = PerlIONext(f);
PerlIO_funcs *tab =
PerlIO_layer_fetch(aTHX_ layers, n - 1, PerlIOBase(next)->tab);
if
(tab && tab->Open)
next =
(*tab->Open)(aTHX_ tab, layers, n - 1, mode, fd, imode, perm,
next, narg, args);
if
(!next || (*PerlIOBase(f)->tab->Pushed) (aTHX_ f, mode, PerlIOArg, self) != 0) {
return
NULL;
}
}
else
{
PerlIO_funcs *tab = PerlIO_layer_fetch(aTHX_ layers, n - 1, PerlIO_default_btm());
int
init = 0;
if
(*mode == IoTYPE_IMPLICIT) {
init = 1;
}
if
(tab && tab->Open)
f = (*tab->Open)(aTHX_ tab, layers, n - 1, mode, fd, imode, perm,
f, narg, args);
else
SETERRNO(EINVAL, LIB_INVARG);
if
(f) {
if
(PerlIO_push(aTHX_ f, self, mode, PerlIOArg) == 0) {
PerlIO_close (f);
return
NULL;
}
else
{
fd = PerlIO_fileno(f);
if
(init && fd == 2) {
PerlIOBase(f)->flags |= PERLIO_F_UNBUF;
}
#ifdef PERLIO_USING_CRLF
# ifdef PERLIO_IS_BINMODE_FD
if
(PERLIO_IS_BINMODE_FD(fd))
PerlIO_binmode(aTHX_ f,
'<'
, O_BINARY, NULL);
else
# endif
PerlLIO_setmode(fd, O_BINARY);
#endif
#ifdef VMS
if
(PerlIOBase(f)->flags & PERLIO_F_CANWRITE) {
Stat_t st;
if
(PerlLIO_fstat(fd, &st) == 0
&& S_ISREG(st.st_mode)
&& (st.st_fab_rfm == FAB$C_VAR
|| st.st_fab_rfm == FAB$C_VFC)) {
PerlIOBase(f)->flags |= PERLIO_F_LINEBUF;
}
}
#endif
}
}
}
return
f;
}
IV
PerlIOBuf_flush(pTHX_ PerlIO *f)
{
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
int
code = 0;
PerlIO *n = PerlIONext(f);
if
(PerlIOBase(f)->flags & PERLIO_F_WRBUF) {
const
STDCHAR *buf = b->buf;
const
STDCHAR *p = buf;
while
(p < b->ptr) {
SSize_t count = PerlIO_write(n, p, b->ptr - p);
if
(count > 0) {
p += count;
}
else
if
(count < 0 || PerlIO_error(n)) {
PerlIOBase(f)->flags |= PERLIO_F_ERROR;
PerlIO_save_errno(f);
code = -1;
break
;
}
}
b->posn += (p - buf);
}
else
if
(PerlIOBase(f)->flags & PERLIO_F_RDBUF) {
STDCHAR *buf = PerlIO_get_base(f);
b->posn += (b->ptr - buf);
if
(b->ptr < b->end) {
if
(PerlIOValid(n) && PerlIO_seek(n, b->posn, SEEK_SET) == 0) {
b->posn = PerlIO_tell(n = PerlIONext(f));
}
else
{
b->posn -= (b->ptr - buf);
return
code;
}
}
}
b->ptr = b->end = b->buf;
PerlIOBase(f)->flags &= ~(PERLIO_F_RDBUF | PERLIO_F_WRBUF);
if
(PerlIOValid(n) && PerlIO_flush(n) != 0)
code = -1;
return
code;
}
IV
PerlIOBuf_fill(pTHX_ PerlIO *f)
{
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
PerlIO *n = PerlIONext(f);
SSize_t avail;
if
(PerlIO_flush(f) != 0)
return
-1;
if
(PerlIOBase(f)->flags & PERLIO_F_TTY)
PerlIOBase_flush_linebuf(aTHX);
if
(!b->buf)
PerlIO_get_base(f);
assert
(b->buf);
b->ptr = b->end = b->buf;
if
(!PerlIOValid(n)) {
PerlIOBase(f)->flags |= PERLIO_F_EOF;
return
-1;
}
if
(PerlIO_fast_gets(n)) {
avail = PerlIO_get_cnt(n);
if
(avail <= 0) {
avail = PerlIO_fill(n);
if
(avail == 0)
avail = PerlIO_get_cnt(n);
else
{
if
(!PerlIO_error(n) && PerlIO_eof(n))
avail = 0;
}
}
if
(avail > 0) {
STDCHAR *ptr = PerlIO_get_ptr(n);
const
SSize_t cnt = avail;
if
(avail > (SSize_t)b->bufsiz)
avail = b->bufsiz;
Copy(ptr, b->buf, avail, STDCHAR);
PerlIO_set_ptrcnt(n, ptr + avail, cnt - avail);
}
}
else
{
avail = PerlIO_read(n, b->ptr, b->bufsiz);
}
if
(avail <= 0) {
if
(avail == 0)
PerlIOBase(f)->flags |= PERLIO_F_EOF;
else
{
PerlIOBase(f)->flags |= PERLIO_F_ERROR;
PerlIO_save_errno(f);
}
return
-1;
}
b->end = b->buf + avail;
PerlIOBase(f)->flags |= PERLIO_F_RDBUF;
return
0;
}
SSize_t
PerlIOBuf_read(pTHX_ PerlIO *f,
void
*vbuf, Size_t count)
{
if
(PerlIOValid(f)) {
const
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
if
(!b->ptr)
PerlIO_get_base(f);
return
PerlIOBase_read(aTHX_ f, vbuf, count);
}
return
0;
}
SSize_t
PerlIOBuf_unread(pTHX_ PerlIO *f,
const
void
*vbuf, Size_t count)
{
const
STDCHAR *buf = (
const
STDCHAR *) vbuf + count;
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
SSize_t unread = 0;
SSize_t avail;
if
(PerlIOBase(f)->flags & PERLIO_F_WRBUF)
PerlIO_flush(f);
if
(!b->buf)
PerlIO_get_base(f);
if
(b->buf) {
if
(PerlIOBase(f)->flags & PERLIO_F_RDBUF) {
avail = (b->ptr - b->buf);
}
else
{
avail = b->bufsiz;
b->end = b->buf + avail;
b->ptr = b->end;
PerlIOBase(f)->flags |= PERLIO_F_RDBUF;
b->posn -= b->bufsiz;
}
if
((SSize_t) count >= 0 && avail > (SSize_t) count) {
avail = count;
}
if
(avail > 0) {
b->ptr -= avail;
buf -= avail;
if
(buf != b->ptr) {
Copy(buf, b->ptr, avail, STDCHAR);
}
count -= avail;
unread += avail;
PerlIOBase(f)->flags &= ~PERLIO_F_EOF;
}
}
if
(count > 0) {
unread += PerlIOBase_unread(aTHX_ f, vbuf, count);
}
return
unread;
}
SSize_t
PerlIOBuf_write(pTHX_ PerlIO *f,
const
void
*vbuf, Size_t count)
{
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
const
STDCHAR *buf = (
const
STDCHAR *) vbuf;
const
STDCHAR *flushptr = buf;
Size_t written = 0;
if
(!b->buf)
PerlIO_get_base(f);
if
(!(PerlIOBase(f)->flags & PERLIO_F_CANWRITE))
return
0;
if
(PerlIOBase(f)->flags & PERLIO_F_RDBUF) {
if
(PerlIO_flush(f) != 0) {
return
0;
}
}
if
(PerlIOBase(f)->flags & PERLIO_F_LINEBUF) {
flushptr = buf + count;
while
(flushptr > buf && *(flushptr - 1) !=
'\n'
)
--flushptr;
}
while
(count > 0) {
SSize_t avail = b->bufsiz - (b->ptr - b->buf);
if
((SSize_t) count >= 0 && (SSize_t) count < avail)
avail = count;
if
(flushptr > buf && flushptr <= buf + avail)
avail = flushptr - buf;
PerlIOBase(f)->flags |= PERLIO_F_WRBUF;
if
(avail) {
Copy(buf, b->ptr, avail, STDCHAR);
count -= avail;
buf += avail;
written += avail;
b->ptr += avail;
if
(buf == flushptr)
PerlIO_flush(f);
}
if
(b->ptr >= (b->buf + b->bufsiz))
if
(PerlIO_flush(f) == -1)
return
-1;
}
if
(PerlIOBase(f)->flags & PERLIO_F_UNBUF)
PerlIO_flush(f);
return
written;
}
IV
PerlIOBuf_seek(pTHX_ PerlIO *f, Off_t offset,
int
whence)
{
IV code;
if
((code = PerlIO_flush(f)) == 0) {
PerlIOBase(f)->flags &= ~PERLIO_F_EOF;
code = PerlIO_seek(PerlIONext(f), offset, whence);
if
(code == 0) {
PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf);
b->posn = PerlIO_tell(PerlIONext(f));
}
}
return
code;
}
Off_t
PerlIOBuf_tell(pTHX_ PerlIO *f)
{
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
Off_t posn = b->posn;
if
((PerlIOBase(f)->flags & PERLIO_F_APPEND) &&
(PerlIOBase(f)->flags & PERLIO_F_WRBUF)) {
#if 1
PerlIO_flush(f);
#else
PerlIO_seek(PerlIONext(f),0, SEEK_END);
#endif
posn = b->posn = PerlIO_tell(PerlIONext(f));
}
if
(b->buf) {
posn += (b->ptr - b->buf);
}
return
posn;
}
IV
PerlIOBuf_popped(pTHX_ PerlIO *f)
{
const
IV code = PerlIOBase_popped(aTHX_ f);
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
if
(b->buf && b->buf != (STDCHAR *) & b->oneword) {
Safefree(b->buf);
}
b->ptr = b->end = b->buf = NULL;
PerlIOBase(f)->flags &= ~(PERLIO_F_RDBUF | PERLIO_F_WRBUF);
return
code;
}
IV
PerlIOBuf_close(pTHX_ PerlIO *f)
{
const
IV code = PerlIOBase_close(aTHX_ f);
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
if
(b->buf && b->buf != (STDCHAR *) & b->oneword) {
Safefree(b->buf);
}
b->ptr = b->end = b->buf = NULL;
PerlIOBase(f)->flags &= ~(PERLIO_F_RDBUF | PERLIO_F_WRBUF);
return
code;
}
STDCHAR *
PerlIOBuf_get_ptr(pTHX_ PerlIO *f)
{
const
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
if
(!b->buf)
PerlIO_get_base(f);
return
b->ptr;
}
SSize_t
PerlIOBuf_get_cnt(pTHX_ PerlIO *f)
{
const
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
if
(!b->buf)
PerlIO_get_base(f);
if
(PerlIOBase(f)->flags & PERLIO_F_RDBUF)
return
(b->end - b->ptr);
return
0;
}
STDCHAR *
PerlIOBuf_get_base(pTHX_ PerlIO *f)
{
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
PERL_UNUSED_CONTEXT;
if
(!b->buf) {
if
(!b->bufsiz)
b->bufsiz = PERLIOBUF_DEFAULT_BUFSIZ;
Newx(b->buf,b->bufsiz, STDCHAR);
if
(!b->buf) {
b->buf = (STDCHAR *) & b->oneword;
b->bufsiz =
sizeof
(b->oneword);
}
b->end = b->ptr = b->buf;
}
return
b->buf;
}
Size_t
PerlIOBuf_bufsiz(pTHX_ PerlIO *f)
{
const
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
if
(!b->buf)
PerlIO_get_base(f);
return
(b->end - b->buf);
}
void
PerlIOBuf_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt)
{
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
#ifndef DEBUGGING
PERL_UNUSED_ARG(cnt);
#endif
if
(!b->buf)
PerlIO_get_base(f);
b->ptr = ptr;
assert
(PerlIO_get_cnt(f) == cnt);
assert
(b->ptr >= b->buf);
PerlIOBase(f)->flags |= PERLIO_F_RDBUF;
}
PerlIO *
PerlIOBuf_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param,
int
flags)
{
return
PerlIOBase_dup(aTHX_ f, o, param, flags);
}
PERLIO_FUNCS_DECL(PerlIO_perlio) = {
sizeof
(PerlIO_funcs),
"perlio"
,
sizeof
(PerlIOBuf),
PERLIO_K_BUFFERED|PERLIO_K_RAW,
PerlIOBuf_pushed,
PerlIOBuf_popped,
PerlIOBuf_open,
PerlIOBase_binmode,
NULL,
PerlIOBase_fileno,
PerlIOBuf_dup,
PerlIOBuf_read,
PerlIOBuf_unread,
PerlIOBuf_write,
PerlIOBuf_seek,
PerlIOBuf_tell,
PerlIOBuf_close,
PerlIOBuf_flush,
PerlIOBuf_fill,
PerlIOBase_eof,
PerlIOBase_error,
PerlIOBase_clearerr,
PerlIOBase_setlinebuf,
PerlIOBuf_get_base,
PerlIOBuf_bufsiz,
PerlIOBuf_get_ptr,
PerlIOBuf_get_cnt,
PerlIOBuf_set_ptrcnt,
};
IV
PerlIOPending_fill(pTHX_ PerlIO *f)
{
PerlIO_flush(f);
return
0;
}
IV
PerlIOPending_close(pTHX_ PerlIO *f)
{
PerlIO_flush(f);
return
PerlIO_close(f);
}
IV
PerlIOPending_seek(pTHX_ PerlIO *f, Off_t offset,
int
whence)
{
PerlIO_flush(f);
return
PerlIO_seek(f, offset, whence);
}
IV
PerlIOPending_flush(pTHX_ PerlIO *f)
{
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
if
(b->buf && b->buf != (STDCHAR *) & b->oneword) {
Safefree(b->buf);
b->buf = NULL;
}
PerlIO_pop(aTHX_ f);
return
0;
}
void
PerlIOPending_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt)
{
if
(cnt <= 0) {
PerlIO_flush(f);
}
else
{
PerlIOBuf_set_ptrcnt(aTHX_ f, ptr, cnt);
}
}
IV
PerlIOPending_pushed(pTHX_ PerlIO *f,
const
char
*mode, SV *arg, PerlIO_funcs *tab)
{
const
IV code = PerlIOBase_pushed(aTHX_ f, mode, arg, tab);
PerlIOl *
const
l = PerlIOBase(f);
l->flags = (l->flags & ~(PERLIO_F_FASTGETS | PERLIO_F_UTF8)) |
(PerlIOBase(PerlIONext(f))->
flags & (PERLIO_F_FASTGETS | PERLIO_F_UTF8));
return
code;
}
SSize_t
PerlIOPending_read(pTHX_ PerlIO *f,
void
*vbuf, Size_t count)
{
SSize_t avail = PerlIO_get_cnt(f);
SSize_t got = 0;
if
((SSize_t) count >= 0 && (SSize_t)count < avail)
avail = count;
if
(avail > 0)
got = PerlIOBuf_read(aTHX_ f, vbuf, avail);
if
(got >= 0 && got < (SSize_t)count) {
const
SSize_t more =
PerlIO_read(f, ((STDCHAR *) vbuf) + got, count - got);
if
(more >= 0 || got == 0)
got += more;
}
return
got;
}
PERLIO_FUNCS_DECL(PerlIO_pending) = {
sizeof
(PerlIO_funcs),
"pending"
,
sizeof
(PerlIOBuf),
PERLIO_K_BUFFERED|PERLIO_K_RAW,
PerlIOPending_pushed,
PerlIOBuf_popped,
NULL,
PerlIOBase_binmode,
NULL,
PerlIOBase_fileno,
PerlIOBuf_dup,
PerlIOPending_read,
PerlIOBuf_unread,
PerlIOBuf_write,
PerlIOPending_seek,
PerlIOBuf_tell,
PerlIOPending_close,
PerlIOPending_flush,
PerlIOPending_fill,
PerlIOBase_eof,
PerlIOBase_error,
PerlIOBase_clearerr,
PerlIOBase_setlinebuf,
PerlIOBuf_get_base,
PerlIOBuf_bufsiz,
PerlIOBuf_get_ptr,
PerlIOBuf_get_cnt,
PerlIOPending_set_ptrcnt,
};
typedef
struct
{
PerlIOBuf base;
STDCHAR *nl;
} PerlIOCrlf;
static
void
S_inherit_utf8_flag(PerlIO *f)
{
PerlIO *g = PerlIONext(f);
if
(PerlIOValid(g)) {
if
(PerlIOBase(g)->flags & PERLIO_F_UTF8) {
PerlIOBase(f)->flags |= PERLIO_F_UTF8;
}
}
}
IV
PerlIOCrlf_pushed(pTHX_ PerlIO *f,
const
char
*mode, SV *arg, PerlIO_funcs *tab)
{
IV code;
PerlIOBase(f)->flags |= PERLIO_F_CRLF;
code = PerlIOBuf_pushed(aTHX_ f, mode, arg, tab);
#if 0
DEBUG_i(
PerlIO_debug(
"PerlIOCrlf_pushed f=%p %s %s fl=%08"
UVxf
"\n"
,
(
void
*)f, PerlIOBase(f)->tab->name, (mode) ? mode :
"(Null)"
,
PerlIOBase(f)->flags);
);
#endif
{
PerlIO *g = PerlIONext(f);
if
(PerlIOValid(g)) {
PerlIOl *b = PerlIOBase(g);
if
(b && b->tab == &PerlIO_crlf) {
if
(!(b->flags & PERLIO_F_CRLF))
b->flags |= PERLIO_F_CRLF;
S_inherit_utf8_flag(g);
PerlIO_pop(aTHX_ f);
return
code;
}
}
}
S_inherit_utf8_flag(f);
return
code;
}
SSize_t
PerlIOCrlf_unread(pTHX_ PerlIO *f,
const
void
*vbuf, Size_t count)
{
PerlIOCrlf *
const
c = PerlIOSelf(f, PerlIOCrlf);
if
(c->nl) {
*(c->nl) = NATIVE_0xd;
c->nl = NULL;
}
if
(!(PerlIOBase(f)->flags & PERLIO_F_CRLF))
return
PerlIOBuf_unread(aTHX_ f, vbuf, count);
else
{
const
STDCHAR *buf = (
const
STDCHAR *) vbuf + count;
PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf);
SSize_t unread = 0;
if
(PerlIOBase(f)->flags & PERLIO_F_WRBUF)
PerlIO_flush(f);
if
(!b->buf)
PerlIO_get_base(f);
if
(b->buf) {
if
(!(PerlIOBase(f)->flags & PERLIO_F_RDBUF)) {
b->end = b->ptr = b->buf + b->bufsiz;
PerlIOBase(f)->flags |= PERLIO_F_RDBUF;
b->posn -= b->bufsiz;
}
while
(count > 0 && b->ptr > b->buf) {
const
int
ch = *--buf;
if
(ch ==
'\n'
) {
if
(b->ptr - 2 >= b->buf) {
*--(b->ptr) = NATIVE_0xa;
*--(b->ptr) = NATIVE_0xd;
unread++;
count--;
}
else
{
*--(b->ptr) = NATIVE_0xa;
unread++;
count--;
}
}
else
{
*--(b->ptr) = ch;
unread++;
count--;
}
}
}
if
(count > 0)
unread += PerlIOBase_unread(aTHX_ f, (
const
STDCHAR *) vbuf + unread, count);
return
unread;
}
}
SSize_t
PerlIOCrlf_get_cnt(pTHX_ PerlIO *f)
{
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
if
(!b->buf)
PerlIO_get_base(f);
if
(PerlIOBase(f)->flags & PERLIO_F_RDBUF) {
PerlIOCrlf *
const
c = PerlIOSelf(f, PerlIOCrlf);
if
((PerlIOBase(f)->flags & PERLIO_F_CRLF) && (!c->nl || *c->nl == NATIVE_0xd)) {
STDCHAR *nl = (c->nl) ? c->nl : b->ptr;
scan:
while
(nl < b->end && *nl != NATIVE_0xd)
nl++;
if
(nl < b->end && *nl == NATIVE_0xd) {
test:
if
(nl + 1 < b->end) {
if
(nl[1] == NATIVE_0xa) {
*nl =
'\n'
;
c->nl = nl;
}
else
{
nl++;
goto
scan;
}
}
else
{
if
(b->ptr < nl) {
c->nl = nl;
return
(nl - b->ptr);
}
else
{
int
code;
b->ptr++;
b->buf++;
b->bufsiz--;
code = PerlIO_fill(f);
b->bufsiz++;
b->buf--;
b->ptr = nl = b->buf;
*nl = NATIVE_0xd;
if
(code == 0)
goto
test;
}
}
}
}
return
(((c->nl) ? (c->nl + 1) : b->end) - b->ptr);
}
return
0;
}
void
PerlIOCrlf_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt)
{
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
PerlIOCrlf *
const
c = PerlIOSelf(f, PerlIOCrlf);
if
(!b->buf)
PerlIO_get_base(f);
if
(!ptr) {
if
(c->nl) {
ptr = c->nl + 1;
if
(ptr == b->end && *c->nl == NATIVE_0xd) {
ptr--;
}
}
else
{
ptr = b->end;
}
ptr -= cnt;
}
else
{
NOOP;
#if 0
IV flags = PerlIOBase(f)->flags;
STDCHAR *chk = (c->nl) ? (c->nl+1) : b->end;
if
(ptr+cnt == c->nl && c->nl+1 == b->end && *c->nl == NATIVE_0xd) {
chk--;
}
chk -= cnt;
if
(ptr != chk ) {
Perl_croak(aTHX_
"ptr wrong %p != %p fl=%08"
UVxf
" nl=%p e=%p for %d"
, (
void
*)ptr, (
void
*)chk,
flags, c->nl, b->end, cnt);
}
#endif
}
if
(c->nl) {
if
(ptr > c->nl) {
*(c->nl) = NATIVE_0xd;
c->nl = NULL;
ptr++;
}
}
b->ptr = ptr;
PerlIOBase(f)->flags |= PERLIO_F_RDBUF;
}
SSize_t
PerlIOCrlf_write(pTHX_ PerlIO *f,
const
void
*vbuf, Size_t count)
{
if
(!(PerlIOBase(f)->flags & PERLIO_F_CRLF))
return
PerlIOBuf_write(aTHX_ f, vbuf, count);
else
{
PerlIOBuf *
const
b = PerlIOSelf(f, PerlIOBuf);
const
STDCHAR *buf = (
const
STDCHAR *) vbuf;
const
STDCHAR *
const
ebuf = buf + count;
if
(!b->buf)
PerlIO_get_base(f);
if
(!(PerlIOBase(f)->flags & PERLIO_F_CANWRITE))
return
0;
while
(buf < ebuf) {
const
STDCHAR *
const
eptr = b->buf + b->bufsiz;
PerlIOBase(f)->flags |= PERLIO_F_WRBUF;
while
(buf < ebuf && b->ptr < eptr) {
if
(*buf ==
'\n'
) {
if
((b->ptr + 2) > eptr) {
PerlIO_flush(f);
break
;
}
else
{
*(b->ptr)++ = NATIVE_0xd;
*(b->ptr)++ = NATIVE_0xa;
buf++;
if
(PerlIOBase(f)->flags & PERLIO_F_LINEBUF) {
PerlIO_flush(f);
break
;
}
}
}
else
{
*(b->ptr)++ = *buf++;
}
if
(b->ptr >= eptr) {
PerlIO_flush(f);
break
;
}
}
}
if
(PerlIOBase(f)->flags & PERLIO_F_UNBUF)
PerlIO_flush(f);
return
(buf - (STDCHAR *) vbuf);
}
}
IV
PerlIOCrlf_flush(pTHX_ PerlIO *f)
{
PerlIOCrlf *
const
c = PerlIOSelf(f, PerlIOCrlf);
if
(c->nl) {
*(c->nl) = NATIVE_0xd;
c->nl = NULL;
}
return
PerlIOBuf_flush(aTHX_ f);
}
IV
PerlIOCrlf_binmode(pTHX_ PerlIO *f)
{
if
((PerlIOBase(f)->flags & PERLIO_F_CRLF)) {
PerlIOBase(f)->flags &= ~PERLIO_F_CRLF;
#ifndef PERLIO_USING_CRLF
PerlIO_pop(aTHX_ f);
#endif
}
return
PerlIOBase_binmode(aTHX_ f);
}
PERLIO_FUNCS_DECL(PerlIO_crlf) = {
sizeof
(PerlIO_funcs),
"crlf"
,
sizeof
(PerlIOCrlf),
PERLIO_K_BUFFERED | PERLIO_K_CANCRLF | PERLIO_K_RAW,
PerlIOCrlf_pushed,
PerlIOBuf_popped,
PerlIOBuf_open,
PerlIOCrlf_binmode,
NULL,
PerlIOBase_fileno,
PerlIOBuf_dup,
PerlIOBuf_read,
PerlIOCrlf_unread,
PerlIOCrlf_write,
PerlIOBuf_seek,
PerlIOBuf_tell,
PerlIOBuf_close,
PerlIOCrlf_flush,
PerlIOBuf_fill,
PerlIOBase_eof,
PerlIOBase_error,
PerlIOBase_clearerr,
PerlIOBase_setlinebuf,
PerlIOBuf_get_base,
PerlIOBuf_bufsiz,
PerlIOBuf_get_ptr,
PerlIOCrlf_get_cnt,
PerlIOCrlf_set_ptrcnt,
};
PerlIO *
Perl_PerlIO_stdin(pTHX)
{
if
(!PL_perlio) {
PerlIO_stdstreams(aTHX);
}
return
&PL_perlio[1].next;
}
PerlIO *
Perl_PerlIO_stdout(pTHX)
{
if
(!PL_perlio) {
PerlIO_stdstreams(aTHX);
}
return
&PL_perlio[2].next;
}
PerlIO *
Perl_PerlIO_stderr(pTHX)
{
if
(!PL_perlio) {
PerlIO_stdstreams(aTHX);
}
return
&PL_perlio[3].next;
}
char
*
PerlIO_getname(PerlIO *f,
char
*buf)
{
#ifdef VMS
dTHX;
char
*name = NULL;
bool
exported = FALSE;
FILE
*stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
if
(!stdio) {
stdio = PerlIO_exportFILE(f,0);
exported = TRUE;
}
if
(stdio) {
name = fgetname(stdio, buf);
if
(exported) PerlIO_releaseFILE(f,stdio);
}
return
name;
#else
PERL_UNUSED_ARG(f);
PERL_UNUSED_ARG(buf);
Perl_croak_nocontext(
"Don't know how to get file name"
);
return
NULL;
#endif
}
#undef PerlIO_fdopen
PerlIO *
PerlIO_fdopen(
int
fd,
const
char
*mode)
{
dTHX;
return
PerlIO_openn(aTHX_ NULL, mode, fd, 0, 0, NULL, 0, NULL);
}
#undef PerlIO_open
PerlIO *
PerlIO_open(
const
char
*path,
const
char
*mode)
{
dTHX;
SV *name = newSVpvn_flags(path, path == NULL ? 0 :
strlen
(path), SVs_TEMP);
return
PerlIO_openn(aTHX_ NULL, mode, -1, 0, 0, NULL, 1, &name);
}
#undef Perlio_reopen
PerlIO *
PerlIO_reopen(
const
char
*path,
const
char
*mode, PerlIO *f)
{
dTHX;
SV *name = newSVpvn_flags(path, path == NULL ? 0 :
strlen
(path), SVs_TEMP);
return
PerlIO_openn(aTHX_ NULL, mode, -1, 0, 0, f, 1, &name);
}
#undef PerlIO_getc
int
PerlIO_getc(PerlIO *f)
{
dTHX;
STDCHAR buf[1];
if
( 1 == PerlIO_read(f, buf, 1) ) {
return
(unsigned
char
) buf[0];
}
return
EOF;
}
#undef PerlIO_ungetc
int
PerlIO_ungetc(PerlIO *f,
int
ch)
{
dTHX;
if
(ch != EOF) {
STDCHAR buf = ch;
if
(PerlIO_unread(f, &buf, 1) == 1)
return
ch;
}
return
EOF;
}
#undef PerlIO_putc
int
PerlIO_putc(PerlIO *f,
int
ch)
{
dTHX;
STDCHAR buf = ch;
return
PerlIO_write(f, &buf, 1);
}
#undef PerlIO_puts
int
PerlIO_puts(PerlIO *f,
const
char
*s)
{
dTHX;
return
PerlIO_write(f, s,
strlen
(s));
}
#undef PerlIO_rewind
void
PerlIO_rewind(PerlIO *f)
{
dTHX;
PerlIO_seek(f, (Off_t) 0, SEEK_SET);
PerlIO_clearerr(f);
}
#undef PerlIO_vprintf
int
PerlIO_vprintf(PerlIO *f,
const
char
*fmt,
va_list
ap)
{
dTHX;
SV * sv;
const
char
*s;
STRLEN len;
SSize_t wrote;
#ifdef NEED_VA_COPY
va_list
apc;
Perl_va_copy(ap, apc);
sv = vnewSVpvf(fmt, &apc);
va_end
(apc);
#else
sv = vnewSVpvf(fmt, &ap);
#endif
s = SvPV_const(sv, len);
wrote = PerlIO_write(f, s, len);
SvREFCNT_dec(sv);
return
wrote;
}
#undef PerlIO_printf
int
PerlIO_printf(PerlIO *f,
const
char
*fmt, ...)
{
va_list
ap;
int
result;
va_start
(ap, fmt);
result = PerlIO_vprintf(f, fmt, ap);
va_end
(ap);
return
result;
}
#undef PerlIO_stdoutf
int
PerlIO_stdoutf(
const
char
*fmt, ...)
{
dTHX;
va_list
ap;
int
result;
va_start
(ap, fmt);
result = PerlIO_vprintf(PerlIO_stdout(), fmt, ap);
va_end
(ap);
return
result;
}
#undef PerlIO_tmpfile
PerlIO *
PerlIO_tmpfile(
void
)
{
return
PerlIO_tmpfile_flags(0);
}
#define MKOSTEMP_MODES ( O_RDWR | O_CREAT | O_EXCL )
#define MKOSTEMP_MODE_MASK ( O_ACCMODE | O_CREAT | O_EXCL | O_TRUNC )
PerlIO *
PerlIO_tmpfile_flags(
int
imode)
{
#ifndef WIN32
dTHX;
#endif
PerlIO *f = NULL;
#ifdef WIN32
const
int
fd = win32_tmpfd_mode(imode);
if
(fd >= 0)
f = PerlIO_fdopen(fd,
"w+b"
);
#elif ! defined(OS2)
int
fd = -1;
char
tempname[] =
"/tmp/PerlIO_XXXXXX"
;
const
char
*
const
tmpdir = TAINTING_get ? NULL : PerlEnv_getenv(
"TMPDIR"
);
SV * sv = NULL;
int
old_umask = umask(0177);
imode &= ~MKOSTEMP_MODE_MASK;
if
(tmpdir && *tmpdir) {
sv = newSVpv(tmpdir, 0);
sv_catpv(sv, tempname + 4);
fd = Perl_my_mkostemp_cloexec(SvPVX(sv), imode | O_VMS_DELETEONCLOSE);
}
if
(fd < 0) {
SvREFCNT_dec(sv);
sv = NULL;
fd = Perl_my_mkostemp_cloexec(tempname, imode | O_VMS_DELETEONCLOSE);
}
if
(fd < 0) {
sv = newSVpvs(
"."
);
sv_catpv(sv, tempname + 4);
fd = Perl_my_mkostemp_cloexec(SvPVX(sv), imode | O_VMS_DELETEONCLOSE);
}
umask(old_umask);
if
(fd >= 0) {
char
mode[8];
int
writing = 1;
(
void
)PerlIO_intmode2str(imode | MKOSTEMP_MODES, mode, &writing);
f = PerlIO_fdopen(fd, mode);
if
(f)
PerlIOBase(f)->flags |= PERLIO_F_TEMP;
# ifndef VMS
PerlLIO_unlink(sv ? SvPVX_const(sv) : tempname);
# endif
}
SvREFCNT_dec(sv);
#else /* !HAS_MKSTEMP, fallback to stdio tmpfile(). */
FILE
*
const
stdio = PerlSIO_tmpfile();
if
(stdio)
f = PerlIO_fdopen(fileno(stdio),
"w+"
);
#endif /* else WIN32 */
return
f;
}
void
Perl_PerlIO_save_errno(pTHX_ PerlIO *f)
{
PERL_UNUSED_CONTEXT;
if
(!PerlIOValid(f))
return
;
PerlIOBase(f)->err =
errno
;
#ifdef VMS
PerlIOBase(f)->os_err = vaxc$
errno
;
#elif defined(OS2)
PerlIOBase(f)->os_err = Perl_rc;
#elif defined(WIN32)
PerlIOBase(f)->os_err = GetLastError();
#endif
}
void
Perl_PerlIO_restore_errno(pTHX_ PerlIO *f)
{
PERL_UNUSED_CONTEXT;
if
(!PerlIOValid(f))
return
;
SETERRNO(PerlIOBase(f)->err, PerlIOBase(f)->os_err);
#ifdef OS2
Perl_rc = PerlIOBase(f)->os_err);
#elif defined(WIN32)
SetLastError(PerlIOBase(f)->os_err);
#endif
}
#undef HAS_FSETPOS
#undef HAS_FGETPOS
const
char
*
Perl_PerlIO_context_layers(pTHX_
const
char
*mode)
{
const
char
*direction = NULL;
SV *layers;
if
(!PL_curcop)
return
NULL;
if
(mode && mode[0] !=
'r'
) {
if
(PL_curcop->cop_hints & HINT_LEXICAL_IO_OUT)
direction =
"open>"
;
}
else
{
if
(PL_curcop->cop_hints & HINT_LEXICAL_IO_IN)
direction =
"open<"
;
}
if
(!direction)
return
NULL;
layers = cop_hints_fetch_pvn(PL_curcop, direction, 5, 0, 0);
assert
(layers);
return
SvOK(layers) ? SvPV_nolen_const(layers) : NULL;
}
#ifndef HAS_FSETPOS
# undef PerlIO_setpos
int
PerlIO_setpos(PerlIO *f, SV *pos)
{
if
(SvOK(pos)) {
if
(f) {
dTHX;
STRLEN len;
const
Off_t *
const
posn = (Off_t *) SvPV(pos, len);
if
(len ==
sizeof
(Off_t))
return
PerlIO_seek(f, *posn, SEEK_SET);
}
}
SETERRNO(EINVAL, SS_IVCHAN);
return
-1;
}
#else
# undef PerlIO_setpos
int
PerlIO_setpos(PerlIO *f, SV *pos)
{
if
(SvOK(pos)) {
if
(f) {
dTHX;
STRLEN len;
Fpos_t *
const
fpos = (Fpos_t *) SvPV(pos, len);
if
(len ==
sizeof
(Fpos_t))
# if defined(USE_64_BIT_STDIO) && defined(USE_FSETPOS64)
return
fsetpos64(f, fpos);
# else
return
fsetpos
(f, fpos);
# endif
}
}
SETERRNO(EINVAL, SS_IVCHAN);
return
-1;
}
#endif
#ifndef HAS_FGETPOS
# undef PerlIO_getpos
int
PerlIO_getpos(PerlIO *f, SV *pos)
{
dTHX;
Off_t posn = PerlIO_tell(f);
sv_setpvn(pos, (
char
*) &posn,
sizeof
(posn));
return
(posn == (Off_t) - 1) ? -1 : 0;
}
#else
# undef PerlIO_getpos
int
PerlIO_getpos(PerlIO *f, SV *pos)
{
dTHX;
Fpos_t fpos;
int
code;
# if defined(USE_64_BIT_STDIO) && defined(USE_FSETPOS64)
code = fgetpos64(f, &fpos);
# else
code =
fgetpos
(f, &fpos);
# endif
sv_setpvn(pos, (
char
*) &fpos,
sizeof
(fpos));
return
code;
}
#endif
void
Perl_noperl_die(
const
char
* pat, ...)
{
va_list
arglist;
PERL_ARGS_ASSERT_NOPERL_DIE;
va_start
(arglist, pat);
vfprintf
(stderr, pat, arglist);
va_end
(arglist);
exit
(1);
}