summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJarkko Hietaniemi <jhi@iki.fi>2000-11-04 22:43:56 +0000
committerJarkko Hietaniemi <jhi@iki.fi>2000-11-04 22:43:56 +0000
commit6ac94dd724117eebd4840593a6c1fc07770a26fb (patch)
tree1de0f49948378469de095e74d9d9099302fa2cd3
parentf83701cd86be3616a770a8d28c295a3f15ac21d0 (diff)
parent5f5aa521de335cf2067dde611355a38216d7287b (diff)
downloadperl-6ac94dd724117eebd4840593a6c1fc07770a26fb.tar.gz
Integrate perlio:
[ 7539] PerlIO infrastructure complete. [ 7538] Type tweaks + less contorted allocation scheme [ 7537] Fix for stdio as default "discipline" - PerlIO_init() was fdopen(2,"w")'ing a fresh FILE * rather than re-using stderr. Which meant PerlIO_stderr() was fully buffered rather than unbuffered (on Solaris, Linux seemed to do something sensible) which lead to some interesting fails. [ 7535] Implement stack of layers - (perlio.c _is_ derived from the old file honest...) - Works on Linux with perlio + unix stdio - Works on Solaris with perlio + unix - Fails ONE test (print to STDIN should fail) on Solaris with stdio. - Fails (hangs in openpid) if you try and stack perlio + stdio - Linux stdio's read() logic is hanging. [ 7492] Change files which are mysteriously different to mainline to be copies of mainline. [ 7491] Perlio fixes discovered on big-endian & very traditional Solaris: - typo in endian code in putc. - Don't allow read of write-only files and vice-versa - and off-by-one in flush-all loop. Remove debug calls as they were using GCC specific features. [ 7484] PerlIO passes all tests. [ 7482] Include <unistd.h> to get correct lseek() prototype etc. (I thought perl.h did that) - down to two fails - comp/require.t (last test) - lib/io_xs.t - possibly import/export of FILE * ? [ 7480] Fixed two bugs: - error code not being set on close (of broken pipe) - append mode was truncating. At least one seek/tell bug remains. [ 7479] Prototype (stdio-like) PerlIO passing basic tests. Checked in in case of accidents. Still several worrying fails, no line disciplines yet. p4raw-link: @7539 on //depot/perlio: f3862f8bcf6d3aa824432654b287f4ebd64db17f p4raw-link: @7538 on //depot/perlio: 05d1247b4b0324742a6edccf90ff347d8905fcdb p4raw-link: @7537 on //depot/perlio: c7fc522f3f7e35723803aaacf8c326dac22dae76 p4raw-link: @7535 on //depot/perlio: 9e353e3b7330a59ca210e75e4484e7762fcd1ce4 p4raw-link: @7492 on //depot/perlio: e9e021e644582e6ca1e9f6b4c1f1a8a7c7e2a58d p4raw-link: @7491 on //depot/perlio: f89522bf4daaf3c639b016283ffbace973e9c323 p4raw-link: @7484 on //depot/perlio: b1ef6e3bd726972447a8b536231f096656903bb3 p4raw-link: @7482 on //depot/perlio: 02f66e2f9235025f08502389e56df70aa71733c0 p4raw-link: @7480 on //depot/perlio: bb9950b796df42e2f824a072ae878c87e977be20 p4raw-link: @7479 on //depot/perlio: 6f9d8c32c6a78a47c6088f50d7051d779f712ee1 p4raw-id: //depot/perl@7547
-rw-r--r--MANIFEST1
-rw-r--r--iperlsys.h49
-rw-r--r--lib/perlio.pm87
-rw-r--r--objXSUB.h2
-rw-r--r--perlapi.c8
-rw-r--r--perlio.c1895
-rw-r--r--pod/perlapi.pod8
-rwxr-xr-xt/lib/b.t1
8 files changed, 1769 insertions, 282 deletions
diff --git a/MANIFEST b/MANIFEST
index 1b4021353d..2b47007729 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -772,6 +772,7 @@ lib/open2.pl Open a two-ended pipe (uses IPC::Open2)
lib/open3.pl Open a three-ended pipe (uses IPC::Open3)
lib/overload.pm Module for overloading perl operators
lib/perl5db.pl Perl debugging routines
+lib/perlio.pm Perl IO interface pragma
lib/pwd.pl Routines to keep track of PWD environment variable
lib/shellwords.pl Perl library to split into words with shell quoting
lib/sigtrap.pm For trapping an abort and giving traceback
diff --git a/iperlsys.h b/iperlsys.h
index 6844801bb4..55471cdbd4 100644
--- a/iperlsys.h
+++ b/iperlsys.h
@@ -78,11 +78,17 @@ extern void PerlIO_init (void);
typedef Signal_t (*Sighandler_t) (int);
#endif
+#ifndef Fpos_t
+#define Fpos_t Off_t
+#endif
+
#if defined(PERL_IMPLICIT_SYS)
#ifndef PerlIO
-typedef struct _PerlIO PerlIO;
-#endif
+typedef struct _PerlIO PerlIOl;
+typedef PerlIOl *PerlIO;
+#define PerlIO PerlIO
+#endif /* No PerlIO */
/* IPerlStdIO */
struct IPerlStdIO;
@@ -120,7 +126,7 @@ typedef void (*LPSetCnt)(struct IPerlStdIO*, PerlIO*, int);
typedef void (*LPSetPtrCnt)(struct IPerlStdIO*, PerlIO*, char*,
int);
typedef void (*LPSetlinebuf)(struct IPerlStdIO*, PerlIO*);
-typedef int (*LPPrintf)(struct IPerlStdIO*, PerlIO*, const char*,
+typedef int (*LPPrintf)(struct IPerlStdIO*, PerlIO*, const char*,
...);
typedef int (*LPVprintf)(struct IPerlStdIO*, PerlIO*, const char*,
va_list);
@@ -134,6 +140,7 @@ typedef int (*LPSetpos)(struct IPerlStdIO*, PerlIO*,
typedef void (*LPInit)(struct IPerlStdIO*);
typedef void (*LPInitOSExtras)(struct IPerlStdIO*);
typedef PerlIO* (*LPFdupopen)(struct IPerlStdIO*, PerlIO*);
+typedef int (*LPIsUtf8)(struct IPerlStdIO*, PerlIO*);
struct IPerlStdIO
{
@@ -176,6 +183,7 @@ struct IPerlStdIO
LPInit pInit;
LPInitOSExtras pInitOSExtras;
LPFdupopen pFdupopen;
+ LPIsUtf8 pIsUtf8;
};
struct IPerlStdIOInfo
@@ -185,19 +193,19 @@ struct IPerlStdIOInfo
};
#ifdef USE_STDIO_PTR
-# define PerlIO_has_cntptr(f) 1
+# define PerlIO_has_cntptr(f) 1
# ifdef STDIO_PTR_LVALUE
# ifdef STDIO_CNT_LVALUE
-# define PerlIO_canset_cnt(f) 1
+# define PerlIO_canset_cnt(f) 1
# ifdef STDIO_PTR_LVAL_NOCHANGE_CNT
-# define PerlIO_fast_gets(f) 1
+# define PerlIO_fast_gets(f) 1
# endif
# else /* STDIO_CNT_LVALUE */
-# define PerlIO_canset_cnt(f) 0
+# define PerlIO_canset_cnt(f) 0
# endif
# else /* STDIO_PTR_LVALUE */
# ifdef STDIO_PTR_LVAL_SETS_CNT
-# define PerlIO_fast_gets(f) 1
+# define PerlIO_fast_gets(f) 1
# endif
# endif
#else /* USE_STDIO_PTR */
@@ -206,7 +214,7 @@ struct IPerlStdIOInfo
#endif /* USE_STDIO_PTR */
#ifndef PerlIO_fast_gets
-#define PerlIO_fast_gets(f) 0
+#define PerlIO_fast_gets(f) 0
#endif
#ifdef FILE_base
@@ -274,7 +282,7 @@ struct IPerlStdIOInfo
#define PerlIO_printf Perl_fprintf_nocontext
#define PerlIO_stdoutf *PL_StdIO->pPrintf
#define PerlIO_vprintf(f,fmt,a) \
- (*PL_StdIO->pVprintf)(PL_StdIO, (f),(fmt),a)
+ (*PL_StdIO->pVprintf)(PL_StdIO, (f),(fmt),a)
#define PerlIO_tell(f) \
(*PL_StdIO->pTell)(PL_StdIO, (f))
#define PerlIO_seek(f,o,w) \
@@ -294,18 +302,22 @@ struct IPerlStdIOInfo
(*PL_StdIO->pInitOSExtras)(PL_StdIO)
#define PerlIO_fdupopen(f) \
(*PL_StdIO->pFdupopen)(PL_StdIO, (f))
+#define PerlIO_isutf8(f) \
+ (*PL_StdIO->pIsUtf8)(PL_StdIO, (f))
#else /* PERL_IMPLICIT_SYS */
#include "perlsdio.h"
#include "perl.h"
#define PerlIO_fdupopen(f) (f)
+#define PerlIO_isutf8(f) 0
#endif /* PERL_IMPLICIT_SYS */
#ifndef PERLIO_IS_STDIO
#ifdef USE_SFIO
#include "perlsfio.h"
+#define PerlIO_isutf8(f) 0
#endif /* USE_SFIO */
#endif /* PERLIO_IS_STDIO */
@@ -331,14 +343,11 @@ struct IPerlStdIOInfo
#endif
#ifndef PerlIO
-struct _PerlIO;
-#define PerlIO struct _PerlIO
+typedef struct _PerlIO PerlIOl;
+typedef PerlIOl *PerlIO;
+#define PerlIO PerlIO
#endif /* No PerlIO */
-#ifndef Fpos_t
-#define Fpos_t long
-#endif
-
#ifndef NEXT30_NO_ATTRIBUTE
#ifndef HASATTRIBUTE /* disable GNU-cc attribute checking? */
#ifdef __attribute__ /* Avoid possible redefinition errors */
@@ -480,7 +489,9 @@ extern int PerlIO_setpos (PerlIO *,const Fpos_t *);
#ifndef PerlIO_fdupopen
extern PerlIO * PerlIO_fdupopen (PerlIO *);
#endif
-
+#ifndef PerlIO_isutf8
+extern int PerlIO_isutf8 (PerlIO *);
+#endif
/*
* Interface for directory functions
@@ -558,7 +569,7 @@ struct IPerlDirInfo
#define PerlDir_mkdir(name, mode) Mkdir((name), (mode))
#ifdef VMS
# define PerlDir_chdir(n) Chdir(((n) && *(n)) ? (n) : "SYS$LOGIN")
-#else
+#else
# define PerlDir_chdir(name) chdir((name))
#endif
#define PerlDir_rmdir(name) rmdir((name))
@@ -1262,7 +1273,7 @@ typedef int (*LPRecvfrom)(struct IPerlSock*, SOCKET, char*, int,
typedef int (*LPSelect)(struct IPerlSock*, int, char*, char*,
char*, const struct timeval*);
typedef int (*LPSend)(struct IPerlSock*, SOCKET, const char*, int,
- int);
+ int);
typedef int (*LPSendto)(struct IPerlSock*, SOCKET, const char*,
int, int, const struct sockaddr*, int);
typedef void (*LPSethostent)(struct IPerlSock*, int);
diff --git a/lib/perlio.pm b/lib/perlio.pm
new file mode 100644
index 0000000000..48acfbbf0b
--- /dev/null
+++ b/lib/perlio.pm
@@ -0,0 +1,87 @@
+package perlio;
+1;
+__END__
+
+=head1 NAME
+
+perlio - perl pragma to configure C level IO
+
+=head1 SYNOPSIS
+
+ Shell:
+ PERLIO=perlio perl ....
+
+ print "Have ",join(',',keys %perlio::layers),"\n";
+ print "Using ",join(',',@perlio::layers),"\n";
+
+
+=head1 DESCRIPTION
+
+Mainly a Place holder for now.
+
+The C<%perlio::layers> hash is a record of the available "layers" that may be pushed
+onto a C<PerlIO> stream.
+
+The C<@perlio::layers> array is the current set of layers that are used when
+a new C<PerlIO> stream is opened. The C code looks are the array each time
+a stream is opened so the "stack" can be manipulated by messing with the array :
+
+ pop(@perlio::layers);
+ push(@perlio::layers,$perlio::layers{'stdio'});
+
+The values if both the hash and the array are perl objects, of class C<perlio::Layer>
+which are created by the C code in C<perlio.c>. As yet there is nothing useful you
+can do with the objects at the perl level.
+
+There are three layers currently defined:
+
+=over 4
+
+=item unix
+
+Low level layer which calls C<read>, C<write> and C<lseek> etc.
+
+=item stdio
+
+Layer which calls C<fread>, C<fwrite> and C<fseek>/C<ftell> etc.
+Note that as this is "real" stdio it will ignore any layers beneath it and
+got straight to the operating system via the C library as usual.
+
+=item perlio
+
+This is a re-implementation of "stdio-like" buffering written as a PerlIO "layer".
+As such it will call whatever layer is below it for its operations.
+
+=back
+
+=head2 Defaults and how to override them
+
+If C<Configure> found out how to do "fast" IO using system's stdio, then
+the default layers are :
+
+ unix stdio
+
+Otherwise the default layers are
+
+ unix perlio
+
+(STDERR will have just unix in this case as that is optimal way to make it
+"unbuffered" - do not add a buffering layer!)
+
+The default may change once perlio has been better tested and tuned.
+
+The default can be overridden by setting the environment variable PERLIO
+to a space separated list of layers (unix is always pushed first).
+This can be used to see the effect of/bugs in the various layers e.g.
+
+ cd .../perl/t
+ PERLIO=stdio ./perl harness
+ PERLIO=perlio ./perl harness
+
+=head1 AUTHOR
+
+Nick Ing-Simmons E<lt>nick@ing-simmons.netE<gt>
+
+=cut
+
+
diff --git a/objXSUB.h b/objXSUB.h
index 4d5ff6b8a5..5827b7225c 100644
--- a/objXSUB.h
+++ b/objXSUB.h
@@ -1901,7 +1901,7 @@
#define Perl_whichsig pPerl->Perl_whichsig
#undef whichsig
#define whichsig Perl_whichsig
-#if defined(USE_PURE_BISON)
+#ifdef USE_PURE_BISON
#else
#endif
#if defined(MYMALLOC)
diff --git a/perlapi.c b/perlapi.c
index efa716410c..a9dd2f070d 100644
--- a/perlapi.c
+++ b/perlapi.c
@@ -2237,21 +2237,21 @@ Perl_init_i18nl14n(pTHXo_ int printwarn)
#undef Perl_new_collate
void
-Perl_new_collate(pTHXo_ const char* newcoll)
+Perl_new_collate(pTHXo_ char* newcoll)
{
((CPerlObj*)pPerl)->Perl_new_collate(newcoll);
}
#undef Perl_new_ctype
void
-Perl_new_ctype(pTHXo_ const char* newctype)
+Perl_new_ctype(pTHXo_ char* newctype)
{
((CPerlObj*)pPerl)->Perl_new_ctype(newctype);
}
#undef Perl_new_numeric
void
-Perl_new_numeric(pTHXo_ const char* newcoll)
+Perl_new_numeric(pTHXo_ char* newcoll)
{
((CPerlObj*)pPerl)->Perl_new_numeric(newcoll);
}
@@ -3439,7 +3439,7 @@ Perl_whichsig(pTHXo_ char* sig)
{
return ((CPerlObj*)pPerl)->Perl_whichsig(sig);
}
-#if defined(USE_PURE_BISON)
+#ifdef USE_PURE_BISON
#else
#endif
#if defined(MYMALLOC)
diff --git a/perlio.c b/perlio.c
index 969b8d1c6d..5d8ecdbb95 100644
--- a/perlio.c
+++ b/perlio.c
@@ -7,7 +7,6 @@
*
*/
-
#define VOIDUSED 1
#ifdef PERL_MICRO
# include "uconfig.h"
@@ -15,14 +14,14 @@
# include "config.h"
#endif
-#define PERLIO_NOT_STDIO 0
+#define PERLIO_NOT_STDIO 0
#if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
-#define PerlIO FILE
+/* #define PerlIO FILE */
#endif
/*
- * This file provides those parts of PerlIO abstraction
+ * This file provides those parts of PerlIO abstraction
* which are not #defined in iperlsys.h.
- * Which these are depends on various Configure #ifdef's
+ * Which these are depends on various Configure #ifdef's
*/
#include "EXTERN.h"
@@ -31,15 +30,15 @@
#if !defined(PERL_IMPLICIT_SYS)
-#ifdef PERLIO_IS_STDIO
+#ifdef PERLIO_IS_STDIO
void
PerlIO_init(void)
{
- /* Does nothing (yet) except force this file to be included
+ /* Does nothing (yet) except force this file to be included
in perl binary. That allows this file to force inclusion
- of other functions that may be required by loadable
- extensions e.g. for FileHandle::tmpfile
+ of other functions that may be required by loadable
+ extensions e.g. for FileHandle::tmpfile
*/
}
@@ -57,7 +56,7 @@ PerlIO_tmpfile(void)
#undef HAS_FSETPOS
#undef HAS_FGETPOS
-/* This section is just to make sure these functions
+/* This section is just to make sure these functions
get pulled in from libsfio.a
*/
@@ -71,368 +70,1770 @@ PerlIO_tmpfile(void)
void
PerlIO_init(void)
{
- /* Force this file to be included in perl binary. Which allows
- * this file to force inclusion of other functions that may be
- * required by loadable extensions e.g. for FileHandle::tmpfile
+ /* Force this file to be included in perl binary. Which allows
+ * this file to force inclusion of other functions that may be
+ * required by loadable extensions e.g. for FileHandle::tmpfile
*/
/* Hack
* sfio does its own 'autoflush' on stdout in common cases.
- * Flush results in a lot of lseek()s to regular files and
+ * Flush results in a lot of lseek()s to regular files and
* lot of small writes to pipes.
*/
sfset(sfstdout,SF_SHARE,0);
}
#else /* USE_SFIO */
+/*======================================================================================*/
+/* Implement all the PerlIO interface ourselves.
+ */
-/* Implement all the PerlIO interface using stdio.
- - this should be only file to include <stdio.h>
-*/
+/* We _MUST_ have <unistd.h> if we are using lseek() and may have large files */
+#ifdef I_UNISTD
+#include <unistd.h>
+#endif
+#include "XSUB.h"
+
+#undef printf
+void PerlIO_debug(char *fmt,...) __attribute__((format(printf,1,2)));
+
+void
+PerlIO_debug(char *fmt,...)
+{
+ static int dbg = 0;
+ if (!dbg)
+ {
+ char *s = getenv("PERLIO_DEBUG");
+ if (s && *s)
+ dbg = open(s,O_WRONLY|O_CREAT|O_APPEND,0666);
+ else
+ dbg = -1;
+ }
+ if (dbg > 0)
+ {
+ dTHX;
+ va_list ap;
+ SV *sv = newSVpvn("",0);
+ char *s;
+ STRLEN len;
+ va_start(ap,fmt);
+ s = CopFILE(PL_curcop);
+ if (!s)
+ s = "(none)";
+ Perl_sv_catpvf(aTHX_ sv, "%s:%"IVdf" ", s, (IV)CopLINE(PL_curcop));
+ Perl_sv_vcatpvf(aTHX_ sv, fmt, &ap);
+
+ s = SvPV(sv,len);
+ write(dbg,s,len);
+ va_end(ap);
+ SvREFCNT_dec(sv);
+ }
+}
+
+/*--------------------------------------------------------------------------------------*/
+
+typedef struct
+{
+ char * name;
+ Size_t size;
+ IV kind;
+ IV (*Fileno)(PerlIO *f);
+ PerlIO * (*Fdopen)(int fd, const char *mode);
+ PerlIO * (*Open)(const char *path, const char *mode);
+ int (*Reopen)(const char *path, const char *mode, PerlIO *f);
+ /* Unix-like functions - cf sfio line disciplines */
+ SSize_t (*Read)(PerlIO *f, void *vbuf, Size_t count);
+ SSize_t (*Unread)(PerlIO *f, const void *vbuf, Size_t count);
+ SSize_t (*Write)(PerlIO *f, const void *vbuf, Size_t count);
+ IV (*Seek)(PerlIO *f, Off_t offset, int whence);
+ Off_t (*Tell)(PerlIO *f);
+ IV (*Close)(PerlIO *f);
+ /* Stdio-like buffered IO functions */
+ IV (*Flush)(PerlIO *f);
+ IV (*Eof)(PerlIO *f);
+ IV (*Error)(PerlIO *f);
+ void (*Clearerr)(PerlIO *f);
+ void (*Setlinebuf)(PerlIO *f);
+ /* Perl's snooping functions */
+ STDCHAR * (*Get_base)(PerlIO *f);
+ Size_t (*Get_bufsiz)(PerlIO *f);
+ STDCHAR * (*Get_ptr)(PerlIO *f);
+ SSize_t (*Get_cnt)(PerlIO *f);
+ void (*Set_ptrcnt)(PerlIO *f,STDCHAR *ptr,SSize_t cnt);
+} PerlIO_funcs;
+
+
+struct _PerlIO
+{
+ PerlIOl * next; /* Lower layer */
+ PerlIO_funcs * tab; /* Functions for this layer */
+ IV flags; /* Various flags for state */
+};
+
+/*--------------------------------------------------------------------------------------*/
+
+/* Flag values */
+#define PERLIO_F_EOF 0x00010000
+#define PERLIO_F_CANWRITE 0x00020000
+#define PERLIO_F_CANREAD 0x00040000
+#define PERLIO_F_ERROR 0x00080000
+#define PERLIO_F_TRUNCATE 0x00100000
+#define PERLIO_F_APPEND 0x00200000
+#define PERLIO_F_BINARY 0x00400000
+#define PERLIO_F_UTF8 0x00800000
+#define PERLIO_F_LINEBUF 0x01000000
+#define PERLIO_F_WRBUF 0x02000000
+#define PERLIO_F_RDBUF 0x04000000
+#define PERLIO_F_TEMP 0x08000000
+#define PERLIO_F_OPEN 0x10000000
+
+#define PerlIOBase(f) (*(f))
+#define PerlIOSelf(f,type) ((type *)PerlIOBase(f))
+#define PerlIONext(f) (&(PerlIOBase(f)->next))
+
+/*--------------------------------------------------------------------------------------*/
+/* Inner level routines */
+
+/* Table of pointers to the PerlIO structs (malloc'ed) */
+PerlIO *_perlio = NULL;
+#define PERLIO_TABLE_SIZE 64
-#undef PerlIO_stderr
PerlIO *
-PerlIO_stderr(void)
+PerlIO_allocate(void)
{
- return (PerlIO *) stderr;
+ /* Find a free slot in the table, allocating new table as necessary */
+ PerlIO **last = &_perlio;
+ PerlIO *f;
+ while ((f = *last))
+ {
+ int i;
+ last = (PerlIO **)(f);
+ for (i=1; i < PERLIO_TABLE_SIZE; i++)
+ {
+ if (!*++f)
+ {
+ return f;
+ }
+ }
+ }
+ Newz('I',f,PERLIO_TABLE_SIZE,PerlIO);
+ if (!f)
+ return NULL;
+ *last = f;
+ return f+1;
}
-#undef PerlIO_stdin
+void
+PerlIO_cleantable(PerlIO **tablep)
+{
+ PerlIO *table = *tablep;
+ if (table)
+ {
+ int i;
+ PerlIO_cleantable((PerlIO **) &(table[0]));
+ for (i=PERLIO_TABLE_SIZE-1; i > 0; i--)
+ {
+ PerlIO *f = table+i;
+ if (*f)
+ PerlIO_close(f);
+ }
+ Safefree(table);
+ *tablep = NULL;
+ }
+}
+
+void
+PerlIO_cleanup(void)
+{
+ PerlIO_cleantable(&_perlio);
+}
+
+void
+PerlIO_pop(PerlIO *f)
+{
+ PerlIOl *l = *f;
+ if (l)
+ {
+ *f = l->next;
+ Safefree(l);
+ }
+}
+
+#undef PerlIO_close
+int
+PerlIO_close(PerlIO *f)
+{
+ int code = (*PerlIOBase(f)->tab->Close)(f);
+ while (*f)
+ {
+ PerlIO_pop(f);
+ }
+ return code;
+}
+
+
+/*--------------------------------------------------------------------------------------*/
+/* Given the abstraction above the public API functions */
+
+#undef PerlIO_fileno
+int
+PerlIO_fileno(PerlIO *f)
+{
+ return (*PerlIOBase(f)->tab->Fileno)(f);
+}
+
+
+extern PerlIO_funcs PerlIO_unix;
+extern PerlIO_funcs PerlIO_perlio;
+extern PerlIO_funcs PerlIO_stdio;
+
+XS(XS_perlio_import)
+{
+ dXSARGS;
+ GV *gv = CvGV(cv);
+ char *s = GvNAME(gv);
+ STRLEN l = GvNAMELEN(gv);
+ PerlIO_debug("%.*s\n",(int) l,s);
+ XSRETURN_EMPTY;
+}
+
+XS(XS_perlio_unimport)
+{
+ dXSARGS;
+ GV *gv = CvGV(cv);
+ char *s = GvNAME(gv);
+ STRLEN l = GvNAMELEN(gv);
+ PerlIO_debug("%.*s\n",(int) l,s);
+ XSRETURN_EMPTY;
+}
+
+HV *PerlIO_layer_hv;
+AV *PerlIO_layer_av;
+
+SV *
+PerlIO_find_layer(char *name, STRLEN len)
+{
+ dTHX;
+ SV **svp;
+ SV *sv;
+ if (len <= 0)
+ len = strlen(name);
+ svp = hv_fetch(PerlIO_layer_hv,name,len,0);
+ if (svp && (sv = *svp) && SvROK(sv))
+ return *svp;
+ return NULL;
+}
+
+void
+PerlIO_define_layer(PerlIO_funcs *tab)
+{
+ dTHX;
+ HV *stash = gv_stashpv("perlio::Layer", TRUE);
+ SV *sv = sv_bless(newRV_noinc(newSViv((IV) tab)),stash);
+ hv_store(PerlIO_layer_hv,tab->name,strlen(tab->name),sv,0);
+}
+
+PerlIO_funcs *
+PerlIO_default_layer(I32 n)
+{
+ dTHX;
+ SV **svp;
+ SV *layer;
+ PerlIO_funcs *tab = &PerlIO_stdio;
+ int len;
+ if (!PerlIO_layer_hv)
+ {
+ char *s = getenv("PERLIO");
+ newXS("perlio::import",XS_perlio_import,__FILE__);
+ newXS("perlio::unimport",XS_perlio_unimport,__FILE__);
+ PerlIO_layer_hv = get_hv("perlio::layers",GV_ADD|GV_ADDMULTI);
+ PerlIO_layer_av = get_av("perlio::layers",GV_ADD|GV_ADDMULTI);
+ PerlIO_define_layer(&PerlIO_unix);
+ PerlIO_define_layer(&PerlIO_unix);
+ PerlIO_define_layer(&PerlIO_perlio);
+ PerlIO_define_layer(&PerlIO_stdio);
+ av_push(PerlIO_layer_av,SvREFCNT_inc(PerlIO_find_layer(PerlIO_unix.name,0)));
+ if (s)
+ {
+ while (*s)
+ {
+ while (*s && isspace((unsigned char)*s))
+ s++;
+ if (*s)
+ {
+ char *e = s;
+ SV *layer;
+ while (*e && !isspace((unsigned char)*e))
+ e++;
+ layer = PerlIO_find_layer(s,e-s);
+ if (layer)
+ {
+ PerlIO_debug("Pushing %.*s\n",(e-s),s);
+ av_push(PerlIO_layer_av,SvREFCNT_inc(layer));
+ }
+ else
+ Perl_croak(aTHX_ "Unknown layer %.*s",(e-s),s);
+ s = e;
+ }
+ }
+ }
+ }
+ len = av_len(PerlIO_layer_av);
+ if (len < 1)
+ {
+ if (PerlIO_stdio.Set_ptrcnt)
+ {
+ av_push(PerlIO_layer_av,SvREFCNT_inc(PerlIO_find_layer(PerlIO_stdio.name,0)));
+ }
+ else
+ {
+ av_push(PerlIO_layer_av,SvREFCNT_inc(PerlIO_find_layer(PerlIO_perlio.name,0)));
+ }
+ len = av_len(PerlIO_layer_av);
+ }
+ if (n < 0)
+ n += len+1;
+ svp = av_fetch(PerlIO_layer_av,n,0);
+ if (svp && (layer = *svp) && SvROK(layer) && SvIOK((layer = SvRV(layer))))
+ {
+ tab = (PerlIO_funcs *) SvIV(layer);
+ }
+ /* PerlIO_debug("Layer %d is %s\n",n,tab->name); */
+ return tab;
+}
+
+#define PerlIO_default_top() PerlIO_default_layer(-1)
+#define PerlIO_default_btm() PerlIO_default_layer(0)
+
+void
+PerlIO_stdstreams()
+{
+ if (!_perlio)
+ {
+ PerlIO_allocate();
+ PerlIO_fdopen(0,"Ir");
+ PerlIO_fdopen(1,"Iw");
+ PerlIO_fdopen(2,"Iw");
+ }
+}
+
+#undef PerlIO_fdopen
PerlIO *
-PerlIO_stdin(void)
+PerlIO_fdopen(int fd, const char *mode)
{
- return (PerlIO *) stdin;
+ PerlIO_funcs *tab = PerlIO_default_top();
+ if (!_perlio)
+ PerlIO_stdstreams();
+ return (*tab->Fdopen)(fd,mode);
}
-#undef PerlIO_stdout
+#undef PerlIO_open
PerlIO *
-PerlIO_stdout(void)
+PerlIO_open(const char *path, const char *mode)
+{
+ PerlIO_funcs *tab = PerlIO_default_top();
+ if (!_perlio)
+ PerlIO_stdstreams();
+ return (*tab->Open)(path,mode);
+}
+
+IV
+PerlIOBase_init(PerlIO *f, const char *mode)
+{
+ PerlIOl *l = PerlIOBase(f);
+ l->flags &= ~(PERLIO_F_CANREAD|PERLIO_F_CANWRITE|
+ PERLIO_F_TRUNCATE|PERLIO_F_APPEND|PERLIO_F_BINARY);
+ if (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:
+ errno = EINVAL;
+ return -1;
+ }
+ while (*mode)
+ {
+ switch (*mode++)
+ {
+ case '+':
+ l->flags |= PERLIO_F_CANREAD|PERLIO_F_CANWRITE;
+ break;
+ case 'b':
+ l->flags |= PERLIO_F_BINARY;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ if (l->next)
+ {
+ l->flags |= l->next->flags &
+ (PERLIO_F_CANREAD|PERLIO_F_CANWRITE|
+ PERLIO_F_TRUNCATE|PERLIO_F_APPEND|PERLIO_F_BINARY);
+ }
+ }
+ return 0;
+}
+
+#undef PerlIO_reopen
+PerlIO *
+PerlIO_reopen(const char *path, const char *mode, PerlIO *f)
+{
+ if (f)
+ {
+ PerlIO_flush(f);
+ if ((*PerlIOBase(f)->tab->Reopen)(path,mode,f) == 0)
+ {
+ PerlIOBase_init(f,mode);
+ return f;
+ }
+ return NULL;
+ }
+ else
+ return PerlIO_open(path,mode);
+}
+
+#undef PerlIO_read
+SSize_t
+PerlIO_read(PerlIO *f, void *vbuf, Size_t count)
+{
+ return (*PerlIOBase(f)->tab->Read)(f,vbuf,count);
+}
+
+#undef PerlIO_ungetc
+int
+PerlIO_ungetc(PerlIO *f, int ch)
+{
+ STDCHAR buf = ch;
+ if ((*PerlIOBase(f)->tab->Unread)(f,&buf,1) == 1)
+ return ch;
+ return -1;
+}
+
+#undef PerlIO_write
+SSize_t
+PerlIO_write(PerlIO *f, const void *vbuf, Size_t count)
+{
+ return (*PerlIOBase(f)->tab->Write)(f,vbuf,count);
+}
+
+#undef PerlIO_seek
+int
+PerlIO_seek(PerlIO *f, Off_t offset, int whence)
+{
+ return (*PerlIOBase(f)->tab->Seek)(f,offset,whence);
+}
+
+#undef PerlIO_tell
+Off_t
+PerlIO_tell(PerlIO *f)
+{
+ return (*PerlIOBase(f)->tab->Tell)(f);
+}
+
+#undef PerlIO_flush
+int
+PerlIO_flush(PerlIO *f)
+{
+ if (f)
+ {
+ return (*PerlIOBase(f)->tab->Flush)(f);
+ }
+ else
+ {
+ PerlIO **table = &_perlio;
+ int code = 0;
+ while ((f = *table))
+ {
+ int i;
+ table = (PerlIO **)(f++);
+ for (i=1; i < PERLIO_TABLE_SIZE; i++)
+ {
+ if (*f && PerlIO_flush(f) != 0)
+ code = -1;
+ f++;
+ }
+ }
+ return code;
+ }
+}
+
+#undef PerlIO_isutf8
+int
+PerlIO_isutf8(PerlIO *f)
+{
+ return (PerlIOBase(f)->flags & PERLIO_F_UTF8) != 0;
+}
+
+#undef PerlIO_eof
+int
+PerlIO_eof(PerlIO *f)
+{
+ return (*PerlIOBase(f)->tab->Eof)(f);
+}
+
+#undef PerlIO_error
+int
+PerlIO_error(PerlIO *f)
{
- return (PerlIO *) stdout;
+ return (*PerlIOBase(f)->tab->Error)(f);
+}
+
+#undef PerlIO_clearerr
+void
+PerlIO_clearerr(PerlIO *f)
+{
+ (*PerlIOBase(f)->tab->Clearerr)(f);
+}
+
+#undef PerlIO_setlinebuf
+void
+PerlIO_setlinebuf(PerlIO *f)
+{
+ (*PerlIOBase(f)->tab->Setlinebuf)(f);
+}
+
+#undef PerlIO_has_base
+int
+PerlIO_has_base(PerlIO *f)
+{
+ if (f && *f)
+ {
+ return (PerlIOBase(f)->tab->Get_base != NULL);
+ }
+ return 0;
}
#undef PerlIO_fast_gets
-int
+int
PerlIO_fast_gets(PerlIO *f)
{
-#if defined(USE_STDIO_PTR) && defined(STDIO_PTR_LVALUE) && defined(STDIO_CNT_LVALUE)
- return 1;
-#else
+ if (f && *f)
+ {
+ PerlIOl *l = PerlIOBase(f);
+ return (l->tab->Set_ptrcnt != NULL);
+ }
return 0;
-#endif
}
#undef PerlIO_has_cntptr
-int
+int
PerlIO_has_cntptr(PerlIO *f)
{
-#if defined(USE_STDIO_PTR)
- return 1;
-#else
+ if (f && *f)
+ {
+ PerlIO_funcs *tab = PerlIOBase(f)->tab;
+ return (tab->Get_ptr != NULL && tab->Get_cnt != NULL);
+ }
return 0;
-#endif
}
#undef PerlIO_canset_cnt
-int
+int
PerlIO_canset_cnt(PerlIO *f)
{
-#if defined(USE_STDIO_PTR) && defined(STDIO_CNT_LVALUE)
- return 1;
-#else
+ if (f && *f)
+ {
+ PerlIOl *l = PerlIOBase(f);
+ return (l->tab->Set_ptrcnt != NULL);
+ }
return 0;
-#endif
+}
+
+#undef PerlIO_get_base
+STDCHAR *
+PerlIO_get_base(PerlIO *f)
+{
+ return (*PerlIOBase(f)->tab->Get_base)(f);
+}
+
+#undef PerlIO_get_bufsiz
+int
+PerlIO_get_bufsiz(PerlIO *f)
+{
+ return (*PerlIOBase(f)->tab->Get_bufsiz)(f);
+}
+
+#undef PerlIO_get_ptr
+STDCHAR *
+PerlIO_get_ptr(PerlIO *f)
+{
+ return (*PerlIOBase(f)->tab->Get_ptr)(f);
+}
+
+#undef PerlIO_get_cnt
+int
+PerlIO_get_cnt(PerlIO *f)
+{
+ return (*PerlIOBase(f)->tab->Get_cnt)(f);
}
#undef PerlIO_set_cnt
void
-PerlIO_set_cnt(PerlIO *f, int cnt)
+PerlIO_set_cnt(PerlIO *f,int cnt)
{
- dTHX;
- if (cnt < -1 && ckWARN_d(WARN_INTERNAL))
- Perl_warner(aTHX_ WARN_INTERNAL, "Setting cnt to %d\n",cnt);
-#if defined(USE_STDIO_PTR) && defined(STDIO_CNT_LVALUE)
- FILE_cnt(f) = cnt;
-#else
- Perl_croak(aTHX_ "Cannot set 'cnt' of FILE * on this system");
-#endif
+ (*PerlIOBase(f)->tab->Set_ptrcnt)(f,NULL,cnt);
}
#undef PerlIO_set_ptrcnt
void
PerlIO_set_ptrcnt(PerlIO *f, STDCHAR *ptr, int cnt)
{
- dTHX;
-#ifdef FILE_bufsiz
- STDCHAR *e = FILE_base(f) + FILE_bufsiz(f);
- int ec = e - ptr;
- if (ptr > e + 1 && ckWARN_d(WARN_INTERNAL))
- Perl_warner(aTHX_ WARN_INTERNAL, "Setting ptr %p > end+1 %p\n", ptr, e + 1);
- if (cnt != ec && ckWARN_d(WARN_INTERNAL))
- Perl_warner(aTHX_ WARN_INTERNAL, "Setting cnt to %d, ptr implies %d\n",cnt,ec);
-#endif
-#if defined(USE_STDIO_PTR) && defined(STDIO_PTR_LVALUE)
- FILE_ptr(f) = ptr;
-#else
- Perl_croak(aTHX_ "Cannot set 'ptr' of FILE * on this system");
-#endif
-#if defined(USE_STDIO_PTR) && defined(STDIO_CNT_LVALUE) && defined (STDIO_PTR_LVAL_NOCHANGE_CNT)
- FILE_cnt(f) = cnt;
-#else
-#if defined(STDIO_PTR_LVAL_SETS_CNT)
- assert (FILE_cnt(f) == cnt);
-#else
- Perl_croak(aTHX_ "Cannot set 'cnt' of FILE * on this system when setting 'ptr'");
-#endif
-#endif
+ (*PerlIOBase(f)->tab->Set_ptrcnt)(f,ptr,cnt);
}
-#undef PerlIO_get_cnt
-int
-PerlIO_get_cnt(PerlIO *f)
+/*--------------------------------------------------------------------------------------*/
+/* "Methods" of the "base class" */
+
+IV
+PerlIOBase_fileno(PerlIO *f)
{
-#ifdef FILE_cnt
- return FILE_cnt(f);
-#else
- dTHX;
- Perl_croak(aTHX_ "Cannot get 'cnt' of FILE * on this system");
- return -1;
-#endif
+ return PerlIO_fileno(PerlIONext(f));
}
-#undef PerlIO_get_bufsiz
-int
-PerlIO_get_bufsiz(PerlIO *f)
+PerlIO *
+PerlIO_push(PerlIO *f,PerlIO_funcs *tab,const char *mode)
{
-#ifdef FILE_bufsiz
- return FILE_bufsiz(f);
-#else
- dTHX;
- Perl_croak(aTHX_ "Cannot get 'bufsiz' of FILE * on this system");
+ PerlIOl *l = NULL;
+ Newc('L',l,tab->size,char,PerlIOl);
+ if (l)
+ {
+ Zero(l,tab->size,char);
+ l->next = *f;
+ l->tab = tab;
+ *f = l;
+ PerlIOBase_init(f,mode);
+ }
+ return f;
+}
+
+SSize_t
+PerlIOBase_unread(PerlIO *f, const void *vbuf, Size_t count)
+{
+ Off_t old = PerlIO_tell(f);
+ if (PerlIO_seek(f,-((Off_t)count),SEEK_CUR) == 0)
+ {
+ Off_t new = PerlIO_tell(f);
+ return old - new;
+ }
+ return 0;
+}
+
+IV
+PerlIOBase_sync(PerlIO *f)
+{
+ return 0;
+}
+
+IV
+PerlIOBase_close(PerlIO *f)
+{
+ IV code = 0;
+ if (PerlIO_flush(f) != 0)
+ code = -1;
+ if (PerlIO_close(PerlIONext(f)) != 0)
+ code = -1;
+ PerlIOBase(f)->flags &= ~(PERLIO_F_CANREAD|PERLIO_F_CANWRITE|PERLIO_F_OPEN);
+ return code;
+}
+
+IV
+PerlIOBase_eof(PerlIO *f)
+{
+ if (f && *f)
+ {
+ return (PerlIOBase(f)->flags & PERLIO_F_EOF) != 0;
+ }
+ return 1;
+}
+
+IV
+PerlIOBase_error(PerlIO *f)
+{
+ if (f && *f)
+ {
+ return (PerlIOBase(f)->flags & PERLIO_F_ERROR) != 0;
+ }
+ return 1;
+}
+
+void
+PerlIOBase_clearerr(PerlIO *f)
+{
+ if (f && *f)
+ {
+ PerlIOBase(f)->flags &= ~PERLIO_F_ERROR;
+ }
+}
+
+void
+PerlIOBase_setlinebuf(PerlIO *f)
+{
+
+}
+
+
+
+/*--------------------------------------------------------------------------------------*/
+/* Bottom-most level for UNIX-like case */
+
+typedef struct
+{
+ struct _PerlIO base; /* The generic part */
+ int fd; /* UNIX like file descriptor */
+ int oflags; /* open/fcntl flags */
+} PerlIOUnix;
+
+int
+PerlIOUnix_oflags(const char *mode)
+{
+ int oflags = -1;
+ 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;
+ }
+ if (*mode || oflags == -1)
+ {
+ errno = EINVAL;
+ oflags = -1;
+ }
+ return oflags;
+}
+
+IV
+PerlIOUnix_fileno(PerlIO *f)
+{
+ return PerlIOSelf(f,PerlIOUnix)->fd;
+}
+
+PerlIO *
+PerlIOUnix_fdopen(int fd,const char *mode)
+{
+ PerlIO *f = NULL;
+ if (*mode == 'I')
+ mode++;
+ if (fd >= 0)
+ {
+ int oflags = PerlIOUnix_oflags(mode);
+ if (oflags != -1)
+ {
+ PerlIOUnix *s = PerlIOSelf(PerlIO_push(f = PerlIO_allocate(),&PerlIO_unix,mode),PerlIOUnix);
+ s->fd = fd;
+ s->oflags = oflags;
+ PerlIOBase(f)->flags |= PERLIO_F_OPEN;
+ }
+ }
+ return f;
+}
+
+PerlIO *
+PerlIOUnix_open(const char *path,const char *mode)
+{
+ PerlIO *f = NULL;
+ int oflags = PerlIOUnix_oflags(mode);
+ if (oflags != -1)
+ {
+ int fd = open(path,oflags,0666);
+ if (fd >= 0)
+ {
+ PerlIOUnix *s = PerlIOSelf(PerlIO_push(f = PerlIO_allocate(),&PerlIO_unix,mode),PerlIOUnix);
+ s->fd = fd;
+ s->oflags = oflags;
+ PerlIOBase(f)->flags |= PERLIO_F_OPEN;
+ }
+ }
+ return f;
+}
+
+int
+PerlIOUnix_reopen(const char *path, const char *mode, PerlIO *f)
+{
+ PerlIOUnix *s = PerlIOSelf(f,PerlIOUnix);
+ int oflags = PerlIOUnix_oflags(mode);
+ if (PerlIOBase(f)->flags & PERLIO_F_OPEN)
+ (*PerlIOBase(f)->tab->Close)(f);
+ if (oflags != -1)
+ {
+ int fd = open(path,oflags,0666);
+ if (fd >= 0)
+ {
+ s->fd = fd;
+ s->oflags = oflags;
+ PerlIOBase(f)->flags |= PERLIO_F_OPEN;
+ return 0;
+ }
+ }
return -1;
-#endif
}
-#undef PerlIO_get_ptr
-STDCHAR *
-PerlIO_get_ptr(PerlIO *f)
+SSize_t
+PerlIOUnix_read(PerlIO *f, void *vbuf, Size_t count)
{
-#ifdef FILE_ptr
- return FILE_ptr(f);
+ int fd = PerlIOSelf(f,PerlIOUnix)->fd;
+ while (1)
+ {
+ SSize_t len = read(fd,vbuf,count);
+ if (len >= 0 || errno != EINTR)
+ return len;
+ }
+}
+
+SSize_t
+PerlIOUnix_write(PerlIO *f, const void *vbuf, Size_t count)
+{
+ int fd = PerlIOSelf(f,PerlIOUnix)->fd;
+ while (1)
+ {
+ SSize_t len = write(fd,vbuf,count);
+ if (len >= 0 || errno != EINTR)
+ return len;
+ }
+}
+
+IV
+PerlIOUnix_seek(PerlIO *f, Off_t offset, int whence)
+{
+ Off_t new = lseek(PerlIOSelf(f,PerlIOUnix)->fd,offset,whence);
+ return (new == (Off_t) -1) ? -1 : 0;
+}
+
+Off_t
+PerlIOUnix_tell(PerlIO *f)
+{
+ return lseek(PerlIOSelf(f,PerlIOUnix)->fd,0,SEEK_CUR);
+}
+
+IV
+PerlIOUnix_close(PerlIO *f)
+{
+ int fd = PerlIOSelf(f,PerlIOUnix)->fd;
+ int code = 0;
+ while (close(fd) != 0)
+ {
+ if (errno != EINTR)
+ {
+ code = -1;
+ break;
+ }
+ }
+ if (code == 0)
+ {
+ PerlIOBase(f)->flags &= ~PERLIO_F_OPEN;
+ }
+ return code;
+}
+
+PerlIO_funcs PerlIO_unix = {
+ "unix",
+ sizeof(PerlIOUnix),
+ 0,
+ PerlIOUnix_fileno,
+ PerlIOUnix_fdopen,
+ PerlIOUnix_open,
+ PerlIOUnix_reopen,
+ PerlIOUnix_read,
+ PerlIOBase_unread,
+ PerlIOUnix_write,
+ PerlIOUnix_seek,
+ PerlIOUnix_tell,
+ PerlIOUnix_close,
+ PerlIOBase_sync,
+ PerlIOBase_eof,
+ PerlIOBase_error,
+ PerlIOBase_clearerr,
+ PerlIOBase_setlinebuf,
+ NULL, /* get_base */
+ NULL, /* get_bufsiz */
+ NULL, /* get_ptr */
+ NULL, /* get_cnt */
+ NULL, /* set_ptrcnt */
+};
+
+/*--------------------------------------------------------------------------------------*/
+/* stdio as a layer */
+
+typedef struct
+{
+ struct _PerlIO base;
+ FILE * stdio; /* The stream */
+} PerlIOStdio;
+
+IV
+PerlIOStdio_fileno(PerlIO *f)
+{
+ return fileno(PerlIOSelf(f,PerlIOStdio)->stdio);
+}
+
+
+PerlIO *
+PerlIOStdio_fdopen(int fd,const char *mode)
+{
+ PerlIO *f = NULL;
+ int init = 0;
+ if (*mode == 'I')
+ {
+ init = 1;
+ mode++;
+ }
+ if (fd >= 0)
+ {
+ FILE *stdio = NULL;
+ if (init)
+ {
+ switch(fd)
+ {
+ case 0:
+ stdio = stdin;
+ break;
+ case 1:
+ stdio = stdout;
+ break;
+ case 2:
+ stdio = stderr;
+ break;
+ }
+ }
+ else
+ stdio = fdopen(fd,mode);
+ if (stdio)
+ {
+ PerlIOStdio *s = PerlIOSelf(PerlIO_push(f = PerlIO_allocate(),&PerlIO_stdio,mode),PerlIOStdio);
+ s->stdio = stdio;
+ }
+ }
+ return f;
+}
+
+#undef PerlIO_importFILE
+PerlIO *
+PerlIO_importFILE(FILE *stdio, int fl)
+{
+ PerlIO *f = NULL;
+ if (stdio)
+ {
+ PerlIOStdio *s = PerlIOSelf(PerlIO_push(f = PerlIO_allocate(),&PerlIO_stdio,"r+"),PerlIOStdio);
+ s->stdio = stdio;
+ }
+ return f;
+}
+
+PerlIO *
+PerlIOStdio_open(const char *path,const char *mode)
+{
+ PerlIO *f = NULL;
+ FILE *stdio = fopen(path,mode);
+ if (stdio)
+ {
+ PerlIOStdio *s = PerlIOSelf(PerlIO_push(f = PerlIO_allocate(),&PerlIO_stdio,mode),PerlIOStdio);
+ s->stdio = stdio;
+ }
+ return f;
+}
+
+int
+PerlIOStdio_reopen(const char *path, const char *mode, PerlIO *f)
+{
+ PerlIOStdio *s = PerlIOSelf(f,PerlIOStdio);
+ FILE *stdio = freopen(path,mode,s->stdio);
+ if (!s->stdio)
+ return -1;
+ s->stdio = stdio;
+ return 0;
+}
+
+SSize_t
+PerlIOStdio_read(PerlIO *f, void *vbuf, Size_t count)
+{
+ FILE *s = PerlIOSelf(f,PerlIOStdio)->stdio;
+ SSize_t got = 0;
+ if (count == 1)
+ {
+ STDCHAR *buf = (STDCHAR *) vbuf;
+ /* Perl is expecting PerlIO_getc() to fill the buffer
+ * Linux's stdio does not do that for fread()
+ */
+ int ch = fgetc(s);
+ if (ch != EOF)
+ {
+ *buf = ch;
+ got = 1;
+ }
+ }
+ else
+ got = fread(vbuf,1,count,s);
+ return got;
+}
+
+SSize_t
+PerlIOStdio_unread(PerlIO *f, const void *vbuf, Size_t count)
+{
+ FILE *s = PerlIOSelf(f,PerlIOStdio)->stdio;
+ STDCHAR *buf = ((STDCHAR *)vbuf)+count-1;
+ SSize_t unread = 0;
+ while (count > 0)
+ {
+ int ch = *buf-- & 0xff;
+ if (ungetc(ch,s) != ch)
+ break;
+ unread++;
+ count--;
+ }
+ return unread;
+}
+
+SSize_t
+PerlIOStdio_write(PerlIO *f, const void *vbuf, Size_t count)
+{
+ return fwrite(vbuf,1,count,PerlIOSelf(f,PerlIOStdio)->stdio);
+}
+
+IV
+PerlIOStdio_seek(PerlIO *f, Off_t offset, int whence)
+{
+ FILE *stdio = PerlIOSelf(f,PerlIOStdio)->stdio;
+ return fseek(stdio,offset,whence);
+}
+
+Off_t
+PerlIOStdio_tell(PerlIO *f)
+{
+ FILE *stdio = PerlIOSelf(f,PerlIOStdio)->stdio;
+ return ftell(stdio);
+}
+
+IV
+PerlIOStdio_close(PerlIO *f)
+{
+ return fclose(PerlIOSelf(f,PerlIOStdio)->stdio);
+}
+
+IV
+PerlIOStdio_flush(PerlIO *f)
+{
+ FILE *stdio = PerlIOSelf(f,PerlIOStdio)->stdio;
+ return fflush(stdio);
+}
+
+IV
+PerlIOStdio_eof(PerlIO *f)
+{
+ return feof(PerlIOSelf(f,PerlIOStdio)->stdio);
+}
+
+IV
+PerlIOStdio_error(PerlIO *f)
+{
+ return ferror(PerlIOSelf(f,PerlIOStdio)->stdio);
+}
+
+void
+PerlIOStdio_clearerr(PerlIO *f)
+{
+ clearerr(PerlIOSelf(f,PerlIOStdio)->stdio);
+}
+
+void
+PerlIOStdio_setlinebuf(PerlIO *f)
+{
+#ifdef HAS_SETLINEBUF
+ setlinebuf(PerlIOSelf(f,PerlIOStdio)->stdio);
#else
- dTHX;
- Perl_croak(aTHX_ "Cannot get 'ptr' of FILE * on this system");
- return NULL;
+ setvbuf(PerlIOSelf(f,PerlIOStdio)->stdio, Nullch, _IOLBF, 0);
#endif
}
-#undef PerlIO_get_base
+#ifdef FILE_base
STDCHAR *
-PerlIO_get_base(PerlIO *f)
+PerlIOStdio_get_base(PerlIO *f)
{
-#ifdef FILE_base
- return FILE_base(f);
-#else
- dTHX;
- Perl_croak(aTHX_ "Cannot get 'base' of FILE * on this system");
- return NULL;
+ FILE *stdio = PerlIOSelf(f,PerlIOStdio)->stdio;
+ return FILE_base(stdio);
+}
+
+Size_t
+PerlIOStdio_get_bufsiz(PerlIO *f)
+{
+ FILE *stdio = PerlIOSelf(f,PerlIOStdio)->stdio;
+ return FILE_bufsiz(stdio);
+}
#endif
+
+#ifdef USE_STDIO_PTR
+STDCHAR *
+PerlIOStdio_get_ptr(PerlIO *f)
+{
+ FILE *stdio = PerlIOSelf(f,PerlIOStdio)->stdio;
+ return FILE_ptr(stdio);
}
-#undef PerlIO_has_base
-int
-PerlIO_has_base(PerlIO *f)
+SSize_t
+PerlIOStdio_get_cnt(PerlIO *f)
+{
+ FILE *stdio = PerlIOSelf(f,PerlIOStdio)->stdio;
+ return FILE_cnt(stdio);
+}
+
+void
+PerlIOStdio_set_ptrcnt(PerlIO *f,STDCHAR *ptr,SSize_t cnt)
{
+ FILE *stdio = PerlIOSelf(f,PerlIOStdio)->stdio;
+ if (ptr != NULL)
+ {
+#ifdef STDIO_PTR_LVALUE
+ FILE_ptr(stdio) = ptr;
+#ifdef STDIO_PTR_LVAL_SETS_CNT
+ if (FILE_cnt(stdio) != (cnt))
+ {
+ dTHX;
+ assert(FILE_cnt(stdio) == (cnt));
+ }
+#endif
+#if (!defined(STDIO_PTR_LVAL_NOCHANGE_CNT))
+ /* Setting ptr _does_ change cnt - we are done */
+ return;
+#endif
+#else /* STDIO_PTR_LVALUE */
+ abort();
+#endif /* STDIO_PTR_LVALUE */
+ }
+/* Now (or only) set cnt */
+#ifdef STDIO_CNT_LVALUE
+ FILE_cnt(stdio) = cnt;
+#else /* STDIO_CNT_LVALUE */
+#if (defined(STDIO_PTR_LVALUE) && defined(STDIO_PTR_LVAL_SETS_CNT))
+ FILE_ptr(stdio) = FILE_ptr(stdio)+(FILE_cnt(stdio)-cnt);
+#else /* STDIO_PTR_LVAL_SETS_CNT */
+ abort();
+#endif /* STDIO_PTR_LVAL_SETS_CNT */
+#endif /* STDIO_CNT_LVALUE */
+}
+
+#endif
+
+PerlIO_funcs PerlIO_stdio = {
+ "stdio",
+ sizeof(PerlIOStdio),
+ 0,
+ PerlIOStdio_fileno,
+ PerlIOStdio_fdopen,
+ PerlIOStdio_open,
+ PerlIOStdio_reopen,
+ PerlIOStdio_read,
+ PerlIOStdio_unread,
+ PerlIOStdio_write,
+ PerlIOStdio_seek,
+ PerlIOStdio_tell,
+ PerlIOStdio_close,
+ PerlIOStdio_flush,
+ PerlIOStdio_eof,
+ PerlIOStdio_error,
+ PerlIOStdio_clearerr,
+ PerlIOStdio_setlinebuf,
#ifdef FILE_base
- return 1;
+ PerlIOStdio_get_base,
+ PerlIOStdio_get_bufsiz,
#else
- return 0;
+ NULL,
+ NULL,
#endif
+#ifdef USE_STDIO_PTR
+ PerlIOStdio_get_ptr,
+ PerlIOStdio_get_cnt,
+#if (defined(STDIO_PTR_LVALUE) && \
+ (defined(STDIO_CNT_LVALUE) || defined(STDIO_PTR_LVAL_SETS_CNT)))
+ PerlIOStdio_set_ptrcnt
+#else /* STDIO_PTR_LVALUE */
+ NULL
+#endif /* STDIO_PTR_LVALUE */
+#else /* USE_STDIO_PTR */
+ NULL,
+ NULL,
+ NULL
+#endif /* USE_STDIO_PTR */
+};
+
+#undef PerlIO_exportFILE
+FILE *
+PerlIO_exportFILE(PerlIO *f, int fl)
+{
+ PerlIO_flush(f);
+ /* Should really push stdio discipline when we have them */
+ return fdopen(PerlIO_fileno(f),"r+");
+}
+
+#undef PerlIO_findFILE
+FILE *
+PerlIO_findFILE(PerlIO *f)
+{
+ return PerlIO_exportFILE(f,0);
+}
+
+#undef PerlIO_releaseFILE
+void
+PerlIO_releaseFILE(PerlIO *p, FILE *f)
+{
+}
+
+/*--------------------------------------------------------------------------------------*/
+/* perlio buffer layer */
+
+typedef struct
+{
+ struct _PerlIO base;
+ Off_t posn; /* Offset of buf into the file */
+ STDCHAR * buf; /* Start of buffer */
+ STDCHAR * end; /* End of valid part of buffer */
+ STDCHAR * ptr; /* Current position in buffer */
+ Size_t bufsiz; /* Size of buffer */
+ IV oneword; /* Emergency buffer */
+} PerlIOBuf;
+
+
+PerlIO *
+PerlIOBuf_fdopen(int fd, const char *mode)
+{
+ PerlIO_funcs *tab = PerlIO_default_btm();
+ int init = 0;
+ PerlIO *f;
+ if (*mode == 'I')
+ {
+ init = 1;
+ mode++;
+ }
+ f = (*tab->Fdopen)(fd,mode);
+ if (f)
+ {
+ /* Initial stderr is unbuffered */
+ if (!init || fd != 2)
+ {
+ PerlIOBuf *b = PerlIOSelf(PerlIO_push(f,&PerlIO_perlio,NULL),PerlIOBuf);
+ b->posn = PerlIO_tell(PerlIONext(f));
+ }
+ }
+ return f;
+}
+
+PerlIO *
+PerlIOBuf_open(const char *path, const char *mode)
+{
+ PerlIO_funcs *tab = PerlIO_default_btm();
+ PerlIO *f = (*tab->Open)(path,mode);
+ if (f)
+ {
+ PerlIOBuf *b = PerlIOSelf(PerlIO_push(f,&PerlIO_perlio,NULL),PerlIOBuf);
+ b->posn = 0;
+ }
+ return f;
}
-#undef PerlIO_puts
int
-PerlIO_puts(PerlIO *f, const char *s)
+PerlIOBase_reopen(const char *path, const char *mode, PerlIO *f)
{
- return fputs(s,f);
+ return (*PerlIOBase(f)->tab->Reopen)(path,mode,PerlIONext(f));
}
-#undef PerlIO_open
-PerlIO *
-PerlIO_open(const char *path, const char *mode)
+void
+PerlIOBuf_alloc_buf(PerlIOBuf *b)
{
- return fopen(path,mode);
+ if (!b->bufsiz)
+ b->bufsiz = 4096;
+ New('B',b->buf,b->bufsiz,STDCHAR);
+ if (!b->buf)
+ {
+ b->buf = (STDCHAR *)&b->oneword;
+ b->bufsiz = sizeof(b->oneword);
+ }
+ b->ptr = b->buf;
+ b->end = b->ptr;
}
-#undef PerlIO_fdopen
-PerlIO *
-PerlIO_fdopen(int fd, const char *mode)
+/* This "flush" is akin to sfio's sync in that it handles files in either
+ read or write state
+*/
+IV
+PerlIOBuf_flush(PerlIO *f)
+{
+ PerlIOBuf *b = PerlIOSelf(f,PerlIOBuf);
+ int code = 0;
+ if (PerlIOBase(f)->flags & PERLIO_F_WRBUF)
+ {
+ /* write() the buffer */
+ STDCHAR *p = b->buf;
+ int count;
+ while (p < b->ptr)
+ {
+ count = PerlIO_write(PerlIONext(f),p,b->ptr - p);
+ if (count > 0)
+ {
+ p += count;
+ }
+ else if (count < 0)
+ {
+ PerlIOBase(f)->flags |= PERLIO_F_ERROR;
+ code = -1;
+ break;
+ }
+ }
+ b->posn += (p - b->buf);
+ }
+ else if (PerlIOBase(f)->flags & PERLIO_F_RDBUF)
+ {
+ /* Note position change */
+ b->posn += (b->ptr - b->buf);
+ if (b->ptr < b->end)
+ {
+ /* We did not consume all of it */
+ if (PerlIO_seek(PerlIONext(f),b->posn,SEEK_SET) == 0)
+ {
+ b->posn = PerlIO_tell(PerlIONext(f));
+ }
+ }
+ }
+ b->ptr = b->end = b->buf;
+ PerlIOBase(f)->flags &= ~(PERLIO_F_RDBUF|PERLIO_F_WRBUF);
+ if (PerlIO_flush(PerlIONext(f)) != 0)
+ code = -1;
+ return code;
+}
+
+SSize_t
+PerlIOBuf_read(PerlIO *f, void *vbuf, Size_t count)
{
- return fdopen(fd,mode);
+ PerlIOBuf *b = PerlIOSelf(f,PerlIOBuf);
+ STDCHAR *buf = (STDCHAR *) vbuf;
+ if (f)
+ {
+ Size_t got = 0;
+ if (!b->ptr)
+ PerlIOBuf_alloc_buf(b);
+ if (!(PerlIOBase(f)->flags & PERLIO_F_CANREAD))
+ return 0;
+ while (count > 0)
+ {
+ SSize_t avail = (b->end - b->ptr);
+ if ((SSize_t) count < avail)
+ avail = count;
+ if (avail > 0)
+ {
+ Copy(b->ptr,buf,avail,char);
+ got += avail;
+ b->ptr += avail;
+ count -= avail;
+ buf += avail;
+ }
+ if (count && (b->ptr >= b->end))
+ {
+ PerlIO_flush(f);
+ b->ptr = b->end = b->buf;
+ avail = PerlIO_read(PerlIONext(f),b->ptr,b->bufsiz);
+ if (avail <= 0)
+ {
+ if (avail == 0)
+ PerlIOBase(f)->flags |= PERLIO_F_EOF;
+ else
+ PerlIOBase(f)->flags |= PERLIO_F_ERROR;
+ break;
+ }
+ b->end = b->buf+avail;
+ PerlIOBase(f)->flags |= PERLIO_F_RDBUF;
+ }
+ }
+ return got;
+ }
+ return 0;
}
-#undef PerlIO_reopen
-PerlIO *
-PerlIO_reopen(const char *name, const char *mode, PerlIO *f)
+SSize_t
+PerlIOBuf_unread(PerlIO *f, const void *vbuf, Size_t count)
{
- return freopen(name,mode,f);
+ const STDCHAR *buf = (const STDCHAR *) vbuf+count;
+ PerlIOBuf *b = PerlIOSelf(f,PerlIOBuf);
+ SSize_t unread = 0;
+ SSize_t avail;
+ if (!b->buf)
+ PerlIOBuf_alloc_buf(b);
+ if (PerlIOBase(f)->flags & PERLIO_F_WRBUF)
+ PerlIO_flush(f);
+ if (b->buf)
+ {
+ if (PerlIOBase(f)->flags & PERLIO_F_RDBUF)
+ {
+ avail = (b->ptr - b->buf);
+ if (avail > (SSize_t) count)
+ avail = count;
+ b->ptr -= avail;
+ }
+ else
+ {
+ avail = b->bufsiz;
+ if (avail > (SSize_t) count)
+ avail = count;
+ b->end = b->ptr + avail;
+ }
+ if (avail > 0)
+ {
+ buf -= avail;
+ if (buf != b->ptr)
+ {
+ Copy(buf,b->ptr,avail,char);
+ }
+ count -= avail;
+ unread += avail;
+ PerlIOBase(f)->flags &= ~ PERLIO_F_EOF;
+ }
+ }
+ return unread;
}
-#undef PerlIO_close
-int
-PerlIO_close(PerlIO *f)
+SSize_t
+PerlIOBuf_write(PerlIO *f, const void *vbuf, Size_t count)
{
- return fclose(f);
+ PerlIOBuf *b = PerlIOSelf(f,PerlIOBuf);
+ const STDCHAR *buf = (const STDCHAR *) vbuf;
+ Size_t written = 0;
+ if (!b->buf)
+ PerlIOBuf_alloc_buf(b);
+ if (!(PerlIOBase(f)->flags & PERLIO_F_CANWRITE))
+ return 0;
+ while (count > 0)
+ {
+ SSize_t avail = b->bufsiz - (b->ptr - b->buf);
+ if ((SSize_t) count < avail)
+ avail = count;
+ PerlIOBase(f)->flags |= PERLIO_F_WRBUF;
+ if (PerlIOBase(f)->flags & PERLIO_F_LINEBUF)
+ {
+ while (avail > 0)
+ {
+ int ch = *buf++;
+ *(b->ptr)++ = ch;
+ count--;
+ avail--;
+ written++;
+ if (ch == '\n')
+ {
+ PerlIO_flush(f);
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (avail)
+ {
+ Copy(buf,b->ptr,avail,char);
+ count -= avail;
+ buf += avail;
+ written += avail;
+ b->ptr += avail;
+ }
+ }
+ if (b->ptr >= (b->buf + b->bufsiz))
+ PerlIO_flush(f);
+ }
+ return written;
}
-#undef PerlIO_eof
-int
-PerlIO_eof(PerlIO *f)
+IV
+PerlIOBuf_seek(PerlIO *f, Off_t offset, int whence)
{
- return feof(f);
+ PerlIOBuf *b = PerlIOSelf(f,PerlIOBuf);
+ int code;
+ code = PerlIO_flush(f);
+ if (code == 0)
+ {
+ PerlIOBase(f)->flags &= ~PERLIO_F_EOF;
+ code = PerlIO_seek(PerlIONext(f),offset,whence);
+ if (code == 0)
+ {
+ b->posn = PerlIO_tell(PerlIONext(f));
+ }
+ }
+ return code;
}
-#undef PerlIO_getname
-char *
-PerlIO_getname(PerlIO *f, char *buf)
+Off_t
+PerlIOBuf_tell(PerlIO *f)
{
-#ifdef VMS
- return fgetname(f,buf);
-#else
- dTHX;
- Perl_croak(aTHX_ "Don't know how to get file name");
- return NULL;
-#endif
+ PerlIOBuf *b = PerlIOSelf(f,PerlIOBuf);
+ Off_t posn = b->posn;
+ if (b->buf)
+ posn += (b->ptr - b->buf);
+ return posn;
}
-#undef PerlIO_getc
-int
-PerlIO_getc(PerlIO *f)
+IV
+PerlIOBuf_close(PerlIO *f)
{
- return fgetc(f);
+ IV code = PerlIOBase_close(f);
+ PerlIOBuf *b = PerlIOSelf(f,PerlIOBuf);
+ if (b->buf && b->buf != (STDCHAR *) &b->oneword)
+ {
+ Safefree(b->buf);
+ }
+ b->buf = NULL;
+ b->ptr = b->end = b->buf;
+ PerlIOBase(f)->flags &= ~(PERLIO_F_RDBUF|PERLIO_F_WRBUF);
+ return code;
}
-#undef PerlIO_error
-int
-PerlIO_error(PerlIO *f)
+void
+PerlIOBuf_setlinebuf(PerlIO *f)
{
- return ferror(f);
+ if (f)
+ {
+ PerlIOBase(f)->flags &= ~PERLIO_F_LINEBUF;
+ }
}
-#undef PerlIO_clearerr
void
-PerlIO_clearerr(PerlIO *f)
+PerlIOBuf_set_cnt(PerlIO *f, int cnt)
{
- clearerr(f);
+ PerlIOBuf *b = PerlIOSelf(f,PerlIOBuf);
+ dTHX;
+ if (!b->buf)
+ PerlIOBuf_alloc_buf(b);
+ b->ptr = b->end - cnt;
+ assert(b->ptr >= b->buf);
}
-#undef PerlIO_flush
-int
-PerlIO_flush(PerlIO *f)
+STDCHAR *
+PerlIOBuf_get_ptr(PerlIO *f)
{
- return Fflush(f);
+ PerlIOBuf *b = PerlIOSelf(f,PerlIOBuf);
+ if (!b->buf)
+ PerlIOBuf_alloc_buf(b);
+ return b->ptr;
}
-#undef PerlIO_fileno
-int
-PerlIO_fileno(PerlIO *f)
+SSize_t
+PerlIOBuf_get_cnt(PerlIO *f)
{
- return fileno(f);
+ PerlIOBuf *b = PerlIOSelf(f,PerlIOBuf);
+ if (!b->buf)
+ PerlIOBuf_alloc_buf(b);
+ if (PerlIOBase(f)->flags & PERLIO_F_RDBUF)
+ return (b->end - b->ptr);
+ return 0;
+}
+
+STDCHAR *
+PerlIOBuf_get_base(PerlIO *f)
+{
+ PerlIOBuf *b = PerlIOSelf(f,PerlIOBuf);
+ if (!b->buf)
+ PerlIOBuf_alloc_buf(b);
+ return b->buf;
+}
+
+Size_t
+PerlIOBuf_bufsiz(PerlIO *f)
+{
+ PerlIOBuf *b = PerlIOSelf(f,PerlIOBuf);
+ if (!b->buf)
+ PerlIOBuf_alloc_buf(b);
+ return (b->end - b->buf);
}
-#undef PerlIO_setlinebuf
void
-PerlIO_setlinebuf(PerlIO *f)
+PerlIOBuf_set_ptrcnt(PerlIO *f, STDCHAR *ptr, SSize_t cnt)
{
-#ifdef HAS_SETLINEBUF
- setlinebuf(f);
-#else
-# ifdef __BORLANDC__ /* Borland doesn't like NULL size for _IOLBF */
- setvbuf(f, Nullch, _IOLBF, BUFSIZ);
-# else
- setvbuf(f, Nullch, _IOLBF, 0);
-# endif
-#endif
+ PerlIOBuf *b = PerlIOSelf(f,PerlIOBuf);
+ if (!b->buf)
+ PerlIOBuf_alloc_buf(b);
+ b->ptr = ptr;
+ if (PerlIO_get_cnt(f) != cnt || b->ptr < b->buf)
+ {
+ dTHX;
+ assert(PerlIO_get_cnt(f) == cnt);
+ assert(b->ptr >= b->buf);
+ }
+ PerlIOBase(f)->flags |= PERLIO_F_RDBUF;
}
-#undef PerlIO_putc
-int
-PerlIO_putc(PerlIO *f, int ch)
+PerlIO_funcs PerlIO_perlio = {
+ "perlio",
+ sizeof(PerlIOBuf),
+ 0,
+ PerlIOBase_fileno,
+ PerlIOBuf_fdopen,
+ PerlIOBuf_open,
+ PerlIOBase_reopen,
+ PerlIOBuf_read,
+ PerlIOBuf_unread,
+ PerlIOBuf_write,
+ PerlIOBuf_seek,
+ PerlIOBuf_tell,
+ PerlIOBuf_close,
+ PerlIOBuf_flush,
+ PerlIOBase_eof,
+ PerlIOBase_error,
+ PerlIOBase_clearerr,
+ PerlIOBuf_setlinebuf,
+ PerlIOBuf_get_base,
+ PerlIOBuf_bufsiz,
+ PerlIOBuf_get_ptr,
+ PerlIOBuf_get_cnt,
+ PerlIOBuf_set_ptrcnt,
+};
+
+void
+PerlIO_init(void)
{
- return putc(ch,f);
+ if (!_perlio)
+ {
+ atexit(&PerlIO_cleanup);
+ }
}
-#undef PerlIO_ungetc
-int
-PerlIO_ungetc(PerlIO *f, int ch)
+#undef PerlIO_stdin
+PerlIO *
+PerlIO_stdin(void)
{
- return ungetc(ch,f);
+ if (!_perlio)
+ PerlIO_stdstreams();
+ return &_perlio[1];
}
-#undef PerlIO_read
-SSize_t
-PerlIO_read(PerlIO *f, void *buf, Size_t count)
+#undef PerlIO_stdout
+PerlIO *
+PerlIO_stdout(void)
{
- return fread(buf,1,count,f);
+ if (!_perlio)
+ PerlIO_stdstreams();
+ return &_perlio[2];
}
-#undef PerlIO_write
-SSize_t
-PerlIO_write(PerlIO *f, const void *buf, Size_t count)
+#undef PerlIO_stderr
+PerlIO *
+PerlIO_stderr(void)
{
- return fwrite1(buf,1,count,f);
+ if (!_perlio)
+ PerlIO_stdstreams();
+ return &_perlio[3];
}
-#undef PerlIO_vprintf
-int
-PerlIO_vprintf(PerlIO *f, const char *fmt, va_list ap)
+/*--------------------------------------------------------------------------------------*/
+
+#undef PerlIO_getname
+char *
+PerlIO_getname(PerlIO *f, char *buf)
{
- return vfprintf(f,fmt,ap);
+ dTHX;
+ Perl_croak(aTHX_ "Don't know how to get file name");
+ return NULL;
}
-#undef PerlIO_tell
-Off_t
-PerlIO_tell(PerlIO *f)
+
+/*--------------------------------------------------------------------------------------*/
+/* Functions which can be called on any kind of PerlIO implemented
+ in terms of above
+*/
+
+#undef PerlIO_getc
+int
+PerlIO_getc(PerlIO *f)
{
-#if defined(USE_64_BIT_STDIO) && defined(HAS_FTELLO) && !defined(USE_FTELL64)
- return ftello(f);
-#else
- return ftell(f);
-#endif
+ STDCHAR buf;
+ int count = PerlIO_read(f,&buf,1);
+ if (count == 1)
+ return (unsigned char) buf;
+ return -1;
}
-#undef PerlIO_seek
+#undef PerlIO_putc
int
-PerlIO_seek(PerlIO *f, Off_t offset, int whence)
+PerlIO_putc(PerlIO *f, int ch)
{
-#if defined(USE_64_BIT_STDIO) && defined(HAS_FSEEKO) && !defined(USE_FSEEK64)
- return fseeko(f,offset,whence);
-#else
- return fseek(f,offset,whence);
-#endif
+ STDCHAR buf = ch;
+ return PerlIO_write(f,&buf,1);
+}
+
+#undef PerlIO_puts
+int
+PerlIO_puts(PerlIO *f, const char *s)
+{
+ STRLEN len = strlen(s);
+ return PerlIO_write(f,s,len);
}
#undef PerlIO_rewind
void
PerlIO_rewind(PerlIO *f)
{
- rewind(f);
+ 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 = newSVpvn("",0);
+ char *s;
+ STRLEN len;
+ sv_vcatpvf(sv, fmt, &ap);
+ s = SvPV(sv,len);
+ return PerlIO_write(f,s,len);
}
#undef PerlIO_printf
-int
+int
PerlIO_printf(PerlIO *f,const char *fmt,...)
{
va_list ap;
int result;
va_start(ap,fmt);
- result = vfprintf(f,fmt,ap);
+ result = PerlIO_vprintf(f,fmt,ap);
va_end(ap);
return result;
}
#undef PerlIO_stdoutf
-int
+int
PerlIO_stdoutf(const char *fmt,...)
{
va_list ap;
@@ -447,55 +1848,41 @@ PerlIO_stdoutf(const char *fmt,...)
PerlIO *
PerlIO_tmpfile(void)
{
- return tmpfile();
-}
-
-#undef PerlIO_importFILE
-PerlIO *
-PerlIO_importFILE(FILE *f, int fl)
-{
- return f;
-}
-
-#undef PerlIO_exportFILE
-FILE *
-PerlIO_exportFILE(PerlIO *f, int fl)
-{
- return f;
-}
-
-#undef PerlIO_findFILE
-FILE *
-PerlIO_findFILE(PerlIO *f)
-{
+ dTHX;
+ /* I have no idea how portable mkstemp() is ... */
+ SV *sv = newSVpv("/tmp/PerlIO_XXXXXX",0);
+ int fd = mkstemp(SvPVX(sv));
+ PerlIO *f = NULL;
+ if (fd >= 0)
+ {
+ f = PerlIO_fdopen(fd,"w+");
+ if (f)
+ {
+ PerlIOBase(f)->flags |= PERLIO_F_TEMP;
+ }
+ unlink(SvPVX(sv));
+ SvREFCNT_dec(sv);
+ }
return f;
}
-#undef PerlIO_releaseFILE
-void
-PerlIO_releaseFILE(PerlIO *p, FILE *f)
-{
-}
-
-void
-PerlIO_init(void)
-{
- /* Does nothing (yet) except force this file to be included
- in perl binary. That allows this file to force inclusion
- of other functions that may be required by loadable
- extensions e.g. for FileHandle::tmpfile
- */
-}
+#undef HAS_FSETPOS
+#undef HAS_FGETPOS
#endif /* USE_SFIO */
#endif /* PERLIO_IS_STDIO */
+/*======================================================================================*/
+/* Now some functions in terms of above which may be needed even if
+ we are not in true PerlIO mode
+ */
+
#ifndef HAS_FSETPOS
#undef PerlIO_setpos
int
PerlIO_setpos(PerlIO *f, const Fpos_t *pos)
{
- return PerlIO_seek(f,*pos,0);
+ return PerlIO_seek(f,*pos,0);
}
#else
#ifndef PERLIO_IS_STDIO
@@ -554,7 +1941,7 @@ vfprintf(FILE *fd, char *pat, char *args)
#endif
#ifndef PerlIO_vsprintf
-int
+int
PerlIO_vsprintf(char *s, int n, const char *fmt, va_list ap)
{
int val = vsprintf(s, fmt, ap);
@@ -572,7 +1959,7 @@ PerlIO_vsprintf(char *s, int n, const char *fmt, va_list ap)
#endif
#ifndef PerlIO_sprintf
-int
+int
PerlIO_sprintf(char *s, int n, const char *fmt,...)
{
va_list ap;
diff --git a/pod/perlapi.pod b/pod/perlapi.pod
index 634180f7ef..061f403445 100644
--- a/pod/perlapi.pod
+++ b/pod/perlapi.pod
@@ -3223,10 +3223,10 @@ C<retlen> will be set to the length, in bytes, of that character,
and the pointer C<s> will be advanced to the end of the character.
If C<s> does not point to a well-formed UTF8 character, the behaviour
-is dependent on the value of C<checking>: if this is true, it is
-assumed that the caller will raise a warning, and this function will
-set C<retlen> to C<-1> and return. If C<checking> is not true, an optional UTF8
-warning is produced.
+is dependent on the value of C<flags>: if it contains UTF8_CHECK_ONLY,
+it is assumed that the caller will raise a warning, and this function
+will set C<retlen> to C<-1> and return. The C<flags> can also contain
+various flags to allow deviations from the strict UTF-8 encoding.
U8* s utf8_to_uv(STRLEN curlen, I32 *retlen, U32 flags)
diff --git a/t/lib/b.t b/t/lib/b.t
index 6303d624ed..fca7f4724f 100755
--- a/t/lib/b.t
+++ b/t/lib/b.t
@@ -126,6 +126,7 @@ ok;
chomp($a = `$^X "-I../lib" "-MB::Stash" "-Mwarnings" -e1`);
$a = join ',', sort split /,/, $a;
+$a =~ s/-uperlio(?:::\w+)?,//g if $Config{'useperlio'} eq 'define';
$a =~ s/-uWin32,// if $^O eq 'MSWin32';
$a =~ s/-u(Cwd|File|File::Copy|OS2),//g if $^O eq 'os2';
$a =~ s/-uCwd,// if $^O eq 'cygwin';