From: Nick Ing-Simmons Date: Thu, 23 Nov 2000 19:46:23 +0000 (+0000) Subject: Implement PerlIO_binmode() X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=60382766f71ec2a2d8e34a951c5c77b494bd86bb;p=p5sagit%2Fp5-mst-13.2.git Implement PerlIO_binmode() Fix PerlIOCrlf_unread() (*--ptr rather than *ptr-- ...) Test on UNIX with PERLIO="perlio crlf" to mimic Win32, make binmode in t/lib/io_tell.t unconditional so that works. Checkin just so Win32 machine can see these changes. p4raw-id: //depot/perlio@7842 --- diff --git a/doio.c b/doio.c index 3c0bcf1..914f91c 100644 --- a/doio.c +++ b/doio.c @@ -1066,7 +1066,11 @@ fail_discipline: end = strchr(s+1, ':'); if (!end) end = s+len; +#ifndef PERLIO_LAYERS Perl_croak(aTHX_ "Unknown discipline '%.*s'", end-s, s); +#else + s = end; +#endif } } } @@ -1076,46 +1080,11 @@ fail_discipline: int Perl_do_binmode(pTHX_ PerlIO *fp, int iotype, int mode) { -#ifdef DOSISH -# if defined(atarist) || defined(__MINT__) - if (!PerlIO_flush(fp)) { - if (mode & O_BINARY) - ((FILE*)fp)->_flag |= _IOBIN; - else - ((FILE*)fp)->_flag &= ~ _IOBIN; - return 1; - } - return 0; -# else - if (PerlLIO_setmode(PerlIO_fileno(fp), mode) != -1) { -# if defined(WIN32) && defined(__BORLANDC__) - /* The translation mode of the stream is maintained independent - * of the translation mode of the fd in the Borland RTL (heavy - * digging through their runtime sources reveal). User has to - * set the mode explicitly for the stream (though they don't - * document this anywhere). GSAR 97-5-24 - */ - PerlIO_seek(fp,0L,0); - if (mode & O_BINARY) - ((FILE*)fp)->flags |= _F_BIN; - else - ((FILE*)fp)->flags &= ~ _F_BIN; -# endif - return 1; - } - else - return 0; -# endif -#else -# if defined(USEMYBINMODE) - if (my_binmode(fp, iotype, mode) != FALSE) - return 1; - else - return 0; -# else - return 1; -# endif -#endif + /* The old body of this is now in non-LAYER part of perlio.c + * This is a stub for any XS code which might have been calling it. + */ + char *name = (O_BINARY != O_TEXT && !(mode & O_BINARY)) ? ":crlf" : ":raw"; + return PerlIO_binmode(aTHX_ fp, iotype, mode, name); } #if !defined(HAS_TRUNCATE) && !defined(HAS_CHSIZE) && defined(F_FREESP) @@ -2151,7 +2120,7 @@ static int S_s64_malloc( S64_IOB *ptr) { return( 0); ptr->size += _S64_BUFFER_SIZE; - + return( 1); } @@ -2162,7 +2131,7 @@ static int S_s64_malloc( S64_IOB *ptr) { int Perl_do_s64_getc( PerlIO *f) { S64_IOB *ptr = _s64_get_buffer(f); if( ptr) { - if( ptr->cnt) + if( ptr->cnt) return( ptr->buffer[--ptr->cnt]); } return( getc(f)); @@ -2174,7 +2143,7 @@ int Perl_do_s64_ungetc( int ch, PerlIO *f) { if( !ptr) ptr=_s64_create_buffer(f); if( !ptr) return( EOF); - if( !ptr->buffer || (ptr->buffer && ptr->cnt >= ptr->size)) + if( !ptr->buffer || (ptr->buffer && ptr->cnt >= ptr->size)) if( !_s64_malloc( ptr)) return( EOF); ptr->buffer[ptr->cnt++] = ch; diff --git a/perlio.c b/perlio.c index 8856166..697fc86 100644 --- a/perlio.c +++ b/perlio.c @@ -40,6 +40,56 @@ PerlIO_apply_layers(pTHX_ PerlIO *f, const char *mode, const char *names) /* NOTREACHED */ return -1; } + +int +PerlIO_binmode(pTHX_ PerlIO *fp, int iotype, int mode, const char *names) +{ +/* This used to be contents of do_binmode in doio.c */ +#ifdef DOSISH +# if defined(atarist) || defined(__MINT__) + if (!PerlIO_flush(fp)) { + if (mode & O_BINARY) + ((FILE*)fp)->_flag |= _IOBIN; + else + ((FILE*)fp)->_flag &= ~ _IOBIN; + return 1; + } + return 0; +# else + if (PerlLIO_setmode(PerlIO_fileno(fp), mode) != -1) { +# if defined(WIN32) && defined(__BORLANDC__) + /* The translation mode of the stream is maintained independent + * of the translation mode of the fd in the Borland RTL (heavy + * digging through their runtime sources reveal). User has to + * set the mode explicitly for the stream (though they don't + * document this anywhere). GSAR 97-5-24 + */ + PerlIO_seek(fp,0L,0); + if (mode & O_BINARY) + ((FILE*)fp)->flags |= _F_BIN; + else + ((FILE*)fp)->flags &= ~ _F_BIN; +# endif + return 1; + } + else + return 0; +# endif +#else +# if defined(USEMYBINMODE) + if (my_binmode(fp, iotype, mode) != FALSE) + return 1; + else + return 0; +# else + return 1; +# endif +#endif +} + + + + #endif #if !defined(PERL_IMPLICIT_SYS) @@ -193,7 +243,7 @@ PerlIO_cleantable(PerlIO **tablep) for (i=PERLIO_TABLE_SIZE-1; i > 0; i--) { PerlIO *f = table+i; - if (*f) + if (*f) { PerlIO_close(f); } @@ -431,6 +481,41 @@ PerlIO_default_layer(I32 n) 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"); + } +} + +PerlIO * +PerlIO_push(PerlIO *f,PerlIO_funcs *tab,const char *mode) +{ + 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; + if ((*l->tab->Pushed)(f,mode) != 0) + { + PerlIO_pop(f); + return NULL; + } + } + return f; +} + int PerlIO_apply_layers(pTHX_ PerlIO *f, const char *mode, const char *names) { @@ -450,19 +535,34 @@ PerlIO_apply_layers(pTHX_ PerlIO *f, const char *mode, const char *names) e++; if (e > s) { - SV *layer = PerlIO_find_layer(s,e-s); - if (layer) + if ((e - s) == 3 && strncmp(s,"raw",3) == 0) { - PerlIO_funcs *tab = INT2PTR(PerlIO_funcs *, SvIV(SvRV(layer))); - if (tab) + /* Pop back to bottom layer */ + if (PerlIONext(f)) { - PerlIO *new = PerlIO_push(f,tab,mode); - if (!new) - return -1; + PerlIO_flush(f); + while (PerlIONext(f)) + { + PerlIO_pop(f); + } } } else - Perl_warn(aTHX_ "perlio: unknown layer \"%.*s\"",(e-s),s); + { + SV *layer = PerlIO_find_layer(s,e-s); + if (layer) + { + PerlIO_funcs *tab = INT2PTR(PerlIO_funcs *, SvIV(SvRV(layer))); + if (tab) + { + PerlIO *new = PerlIO_push(f,tab,mode); + if (!new) + return -1; + } + } + else + Perl_warn(aTHX_ "perlio: unknown layer \"%.*s\"",(int)(e-s),s); + } } s = e; } @@ -471,44 +571,32 @@ PerlIO_apply_layers(pTHX_ PerlIO *f, const char *mode, const char *names) return 0; } -#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"); - } -} -PerlIO * -PerlIO_push(PerlIO *f,PerlIO_funcs *tab,const char *mode) +/*--------------------------------------------------------------------------------------*/ +/* Given the abstraction above the public API functions */ + +int +PerlIO_binmode(pTHX_ PerlIO *fp, int iotype, int mode, const char *names) { - PerlIOl *l = NULL; - Newc('L',l,tab->size,char,PerlIOl); - if (l) + if (!names || (O_TEXT != O_BINARY && mode & O_BINARY)) { - Zero(l,tab->size,char); - l->next = *f; - l->tab = tab; - *f = l; - if ((*l->tab->Pushed)(f,mode) != 0) + PerlIO *top = fp; + PerlIOl *l; + while (l = *top) { - PerlIO_pop(f); - return NULL; + if (PerlIOBase(top)->tab == &PerlIO_crlf) + { + PerlIO_flush(top); + PerlIO_pop(top); + break; + } + top = PerlIONext(top); } } - return f; + return PerlIO_apply_layers(aTHX_ fp, NULL, names) == 0 ? TRUE : FALSE; } -/*--------------------------------------------------------------------------------------*/ -/* Given the abstraction above the public API functions */ - #undef PerlIO_close int PerlIO_close(PerlIO *f) @@ -948,8 +1036,8 @@ PerlIOUnix_oflags(const char *mode) if (*mode == 'b') { oflags |= O_BINARY; - mode++; - } + mode++; + } /* Always open in binary mode */ oflags |= O_BINARY; if (*mode || oflags == -1) @@ -1672,7 +1760,7 @@ PerlIOBuf_read(PerlIO *f, void *vbuf, Size_t count) while (count > 0) { SSize_t avail = PerlIO_get_cnt(f); - SSize_t take = (count < avail) ? count : avail; + SSize_t take = (count < avail) ? count : avail; if (take > 0) { STDCHAR *ptr = PerlIO_get_ptr(f); @@ -1931,14 +2019,14 @@ PerlIO_funcs PerlIO_perlio = { /*--------------------------------------------------------------------------------------*/ /* crlf - translation On read translate CR,LF to "\n" we do this by overriding ptr/cnt entries - to hand back a line at a time and keeping a record of which nl we "lied" about. + to hand back a line at a time and keeping a record of which nl we "lied" about. On write translate "\n" to CR,LF */ typedef struct { PerlIOBuf base; /* PerlIOBuf stuff */ - STDCHAR *nl; /* Position of crlf we "lied" about in the buffer */ + STDCHAR *nl; /* Position of crlf we "lied" about in the buffer */ } PerlIOCrlf; SSize_t @@ -1946,9 +2034,15 @@ PerlIOCrlf_unread(PerlIO *f, const void *vbuf, Size_t count) { const STDCHAR *buf = (const STDCHAR *) vbuf+count; PerlIOBuf *b = PerlIOSelf(f,PerlIOBuf); + PerlIOCrlf *c = PerlIOSelf(f,PerlIOCrlf); SSize_t unread = 0; if (PerlIOBase(f)->flags & PERLIO_F_WRBUF) PerlIO_flush(f); + if (c->nl) + { + *(c->nl) = 0xd; + c->nl = NULL; + } if (!b->buf) PerlIO_get_base(f); if (b->buf) @@ -1965,8 +2059,8 @@ PerlIOCrlf_unread(PerlIO *f, const void *vbuf, Size_t count) { if (b->ptr - 2 >= b->buf) { - *(b->ptr)-- = 0xa; - *(b->ptr)-- = 0xd; + *--(b->ptr) = 0xa; + *--(b->ptr) = 0xd; unread++; count--; } @@ -1978,10 +2072,10 @@ PerlIOCrlf_unread(PerlIO *f, const void *vbuf, Size_t count) } else { - *(b->ptr)-- = ch; + *--(b->ptr) = ch; unread++; count--; - } + } } } return unread; @@ -1999,33 +2093,33 @@ PerlIOCrlf_get_cnt(PerlIO *f) if (!c->nl) { STDCHAR *nl = b->ptr; - scan: + scan: while (nl < b->end && *nl != 0xd) nl++; if (nl < b->end && *nl == 0xd) { - test: + test: if (nl+1 < b->end) { if (nl[1] == 0xa) { *nl = '\n'; - c->nl = nl; + c->nl = nl; } - else + else { /* Not CR,LF but just CR */ nl++; - goto scan; + goto scan; } } else { - /* Blast - found CR as last char in buffer */ + /* Blast - found CR as last char in buffer */ if (b->ptr < nl) { /* They may not care, defer work as long as possible */ - return (nl - b->ptr); + return (nl - b->ptr); } else { @@ -2041,13 +2135,13 @@ PerlIOCrlf_get_cnt(PerlIO *f) b->ptr = nl = b->buf; /* Which is what we hand off */ b->posn--; /* Buffer starts here */ *nl = 0xd; /* Fill in the CR */ - if (code == 0) + if (code == 0) goto test; /* fill() call worked */ /* CR at EOF - just fall through */ } } - } - } + } + } return (((c->nl) ? (c->nl+1) : b->end) - b->ptr); } return 0; @@ -2061,7 +2155,14 @@ PerlIOCrlf_set_ptrcnt(PerlIO *f, STDCHAR *ptr, SSize_t cnt) if (!b->buf) PerlIO_get_base(f); if (!ptr) - ptr = ((c->nl) ? (c->nl+1) : b->end) - cnt; + { + ptr = ((c->nl) ? (c->nl+1) : b->end) - cnt; + } + else + { + if (ptr != (((c->nl) ? (c->nl+1) : b->end) - cnt)) + abort(); + } if (c->nl) { if (ptr > c->nl) @@ -2070,7 +2171,7 @@ PerlIOCrlf_set_ptrcnt(PerlIO *f, STDCHAR *ptr, SSize_t cnt) *(c->nl) = 0xd; c->nl = NULL; ptr++; - } + } } b->ptr = ptr; PerlIOBase(f)->flags |= PERLIO_F_RDBUF; @@ -2094,19 +2195,22 @@ PerlIOCrlf_write(PerlIO *f, const void *vbuf, Size_t count) { if (*buf == '\n') { - if (b->ptr + 2 >= eptr) + if ((b->ptr + 2) > eptr) { /* Not room for both */ PerlIO_flush(f); break; } - *(b->ptr)++ = 0xd; /* CR */ - *(b->ptr)++ = 0xa; /* LF */ - buf++; - if (PerlIOBase(f)->flags & PERLIO_F_LINEBUF) - { - PerlIO_flush(f); - break; + else + { + *(b->ptr)++ = 0xd; /* CR */ + *(b->ptr)++ = 0xa; /* LF */ + buf++; + if (PerlIOBase(f)->flags & PERLIO_F_LINEBUF) + { + PerlIO_flush(f); + break; + } } } else @@ -2130,10 +2234,8 @@ PerlIOCrlf_flush(PerlIO *f) PerlIOCrlf *c = PerlIOSelf(f,PerlIOCrlf); if (c->nl) { - dTHX; - Perl_warn(aTHX_ __FUNCTION__ " f=%p flush with nl@%p",f,c->nl); *(c->nl) = 0xd; - c->nl = NULL; + c->nl = NULL; } return PerlIOBuf_flush(f); } diff --git a/perlio.h b/perlio.h index 8cb4f7e..75f00a2 100644 --- a/perlio.h +++ b/perlio.h @@ -309,7 +309,10 @@ extern PerlIO * PerlIO_fdupopen (PerlIO *); extern int PerlIO_isutf8 (PerlIO *); #endif #ifndef PerlIO_apply_layers -extern int PerlIO_apply_layers (pTHX_ PerlIO *f,const char *mode, const char *names); +extern int PerlIO_apply_layers (pTHX_ PerlIO *f, const char *mode, const char *names); +#endif +#ifndef PerlIO_binmode +extern int PerlIO_binmode (pTHX_ PerlIO *f, int iotype, int omode, const char *names); #endif extern void PerlIO_debug(const char *fmt,...); diff --git a/pp_sys.c b/pp_sys.c index 2194653..88ce86c 100644 --- a/pp_sys.c +++ b/pp_sys.c @@ -687,11 +687,14 @@ PP(pp_binmode) PerlIO *fp; MAGIC *mg; SV *discp = Nullsv; + STRLEN len = 0; + char *names = NULL; if (MAXARG < 1) RETPUSHUNDEF; - if (MAXARG > 1) + if (MAXARG > 1) { discp = POPs; + } gv = (GV*)POPs; @@ -712,7 +715,12 @@ PP(pp_binmode) if (!(io = GvIO(gv)) || !(fp = IoIFP(io))) RETPUSHUNDEF; - if (do_binmode(fp,IoTYPE(io),mode_from_discipline(discp))) + if (discp) { + names = SvPV(discp,len); + } + + if (PerlIO_binmode(aTHX_ fp,IoTYPE(io),mode_from_discipline(discp), + (discp) ? SvPV_nolen(discp) : Nullch)) RETPUSHYES; else RETPUSHUNDEF; @@ -3137,7 +3145,7 @@ PP(pp_fttext) (void)PerlIO_close(fp); RETPUSHUNDEF; } - do_binmode(fp, '<', O_BINARY); + PerlIO_binmode(aTHX_ fp, '<', O_BINARY, Nullch); len = PerlIO_read(fp, tbuf, sizeof(tbuf)); (void)PerlIO_close(fp); if (len <= 0) { diff --git a/t/lib/io_tell.t b/t/lib/io_tell.t index 3aa4b03..65c63bd 100755 --- a/t/lib/io_tell.t +++ b/t/lib/io_tell.t @@ -27,7 +27,7 @@ print "1..13\n"; use IO::File; $tst = IO::File->new("$tell_file","r") || die("Can't open $tell_file"); -binmode $tst if ($^O eq 'MSWin32' or $^O eq 'dos'); +binmode $tst; # its a nop unless it matters. Was only if ($^O eq 'MSWin32' or $^O eq 'dos'); if ($tst->eof) { print "not ok 1\n"; } else { print "ok 1\n"; } $firstline = <$tst>;