diff --git a/src/Peachpie.Library/Spl/SplFileInfo.cs b/src/Peachpie.Library/Spl/SplFileInfo.cs index d98453e144..5060b4b448 100644 --- a/src/Peachpie.Library/Spl/SplFileInfo.cs +++ b/src/Peachpie.Library/Spl/SplFileInfo.cs @@ -193,6 +193,12 @@ public class SplFileObject : SplFileInfo, SeekableIterator, RecursiveIterator private protected PhpStream _stream; + private protected char _delimiter = ','; + private protected char _enclosure = '\"'; + private protected char _escape = '\\'; + private protected int _flags = 0; + private protected long _maxLineLength = 0; + public SplFileObject(Context ctx, string file_name, string open_mode = "r", bool use_include_path = false, PhpResource context = null) : this(ctx) { @@ -230,45 +236,116 @@ protected SplFileObject(Context ctx) : base() #region SeekableIterator, RecursiveIterator - public virtual PhpValue/*string|array*/ current() - { - throw new NotImplementedException(); - } + private protected long _line = -1; + private protected PhpValue _value = PhpValue.False; - public virtual RecursiveIterator getChildren() - { - throw new NotImplementedException(); - } + public virtual PhpValue /*string|array*/ current() => _value; - public virtual bool hasChildren() - { - throw new NotImplementedException(); - } + /// Get line number. + /// This number may not reflect the actual line number in the file if is used to read fixed lengths of the file. + public virtual PhpValue key() => _line < 0 ? 0 : _line; + + public virtual void next() => movenextimpl(); - public virtual PhpValue key() + private protected void resetimpl() { - throw new NotImplementedException(); + _line = -1; + _stream.Seek(0, SeekOrigin.Begin); } - - public virtual void next() + + private protected bool movenextimpl() { - throw new NotImplementedException(); + // read next line + if ((_flags & READ_CSV) == 0) + { + for (;;) + { + if (_stream.Eof) + { + _value = PhpValue.False; + return false; + } + + var text = _stream.ReadLine( + (int)(_maxLineLength <= 0 ? -1 : _maxLineLength), + null + ); + + _line++; + + if ((_flags & SKIP_EMPTY) != 0 && string.IsNullOrWhiteSpace(text)) + { + continue; + } + + _value = (_flags & DROP_NEW_LINE) != 0 && text.Length > 0 && text.LastChar() == '\n' + ? text.Substring(0, text.Length - 1) + : text; + + return true; + } + } + else + { + if (_stream.Eof) + { + _value = PhpValue.False; + return false; + } + + _value = PhpPath.ReadLineCsv( + () => _stream.ReadLine(-1, null), _delimiter, _enclosure, _escape + ); + _line++; + return true; + } } public virtual void rewind() { - throw new NotImplementedException(); + resetimpl(); + movenextimpl(); } + /// + /// Seek to specified line. + /// + /// Zero-based line number. public virtual void seek(long line_pos) { - throw new NotImplementedException(); + if (line_pos == _line) + { + // do nothing + return; + } + + if (line_pos < 0) + { + throw new ValueError( + string.Format(Resources.Resources.arg_negative, nameof(line_pos)) + ); + } + + resetimpl(); + + // read N lines + while (_line < line_pos && movenextimpl()) + { + // + } } public virtual bool valid() { - throw new NotImplementedException(); + if (_line < 0) + movenextimpl(); + + return !_value.IsFalse; } + + public virtual RecursiveIterator getChildren() => null; // no purpose + + public virtual bool hasChildren() => false; // never true #endregion @@ -316,17 +393,31 @@ public virtual bool valid() [return: CastToFalse] public virtual int fwrite(PhpString data, int length = -1) => PhpPath.fwrite(_ctx, _stream, data, length); - public virtual PhpArray getCsvControl() { throw new NotImplementedException(); } - public virtual int getFlags() { throw new NotImplementedException(); } - public virtual int getMaxLineLen() { throw new NotImplementedException(); } - public virtual void setCsvControl(string delimiter = ",", string enclosure = "\"", string escape = "\\") { throw new NotImplementedException(); } - public virtual void setFlags(int flags) { throw new NotImplementedException(); } - public virtual void setMaxLineLen(int max_len) { throw new NotImplementedException(); } + public virtual PhpArray getCsvControl() => new PhpArray(3) { _delimiter.ToString(), _enclosure.ToString(), _escape.ToString() }; + + public virtual int getFlags() => _flags; + + public virtual long getMaxLineLen() => _maxLineLength; + + public virtual void setCsvControl(char delimiter = ',', char enclosure = '\"', char escape = '\\') + { + _delimiter = delimiter; + _enclosure = enclosure; + _escape = escape; + } + + public virtual void setFlags(int flags) + { + _flags = flags; + } + + public virtual void setMaxLineLen(long max_len) { _maxLineLength = max_len; } + public virtual PhpString getCurrentLine() => fgets(); } /// - /// The SplTempFileObject class offers an object oriented interface for a temporary file. + /// The SplTempFileObject class offers an object-oriented interface for a temporary file. /// [PhpType(PhpTypeAttribute.InheritName), PhpExtension(SplExtension.Name)] public class SplTempFileObject : SplFileObject