gt:       StringValue line = file.readLine(length);
context: /*
   * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
   *
   * This file is part of Resin(R) Open Source
   *
   * Each copy or derived work must preserve the copyright notice and this
   * notice unmodified.
   *
   * Resin Open Source is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * Resin Open Source is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
   * of NON-INFRINGEMENT.  See the GNU General Public License for more
   * details.
   *
   * You should have received a copy of the GNU General Public License
   * along with Resin Open Source; if not, write to the
   *
   *   Free Software Foundation, Inc.
   *   59 Temple Place, Suite 330
   *   Boston, MA 02111-1307  USA
   *
   * @author Scott Ferguson
   */
  
  package com.caucho.quercus.lib.file;
  
  import com.caucho.quercus.QuercusModuleException;
  import com.caucho.quercus.annotation.NotNull;
  import com.caucho.quercus.annotation.Optional;
  import com.caucho.quercus.annotation.Reference;
  import com.caucho.quercus.annotation.ReturnNullAsFalse;
  import com.caucho.quercus.env.*;
  import com.caucho.quercus.lib.file.SocketInputOutput.Domain;
  import com.caucho.quercus.module.AbstractQuercusModule;
  import com.caucho.quercus.resources.StreamContextResource;
  import com.caucho.util.L10N;
  import com.caucho.vfs.TempBuffer;
  
  import java.io.IOException;
  import java.net.UnknownHostException;
  import java.util.HashMap;
  import java.util.Map;
  
  /**
   * Handling the PHP Stream API
   */
  public class StreamModule extends AbstractQuercusModule {
    private static final L10N L = new L10N(StreamModule.class);
   
    public static final int STREAM_FILTER_READ = 1;
    public static final int STREAM_FILTER_WRITE = 2;
    public static final int STREAM_FILTER_ALL = 3;
  
    public static final int PSFS_PASS_ON = 2;
    public static final int PSFS_FEED_ME = 1;
    public static final int PSFS_ERR_FATAL = 0;
  
    public static final int STREAM_USE_PATH = 1;
    public static final int STREAM_REPORT_ERRORS = 8;
  
    public static final int STREAM_CLIENT_ASYNC_CONNECT = 2;
    public static final int STREAM_CLIENT_CONNECT = 4;
    public static final int STREAM_CLIENT_PERSISTENT = 1;
  
    public static final int STREAM_SERVER_BIND = 4;
    public static final int STREAM_SERVER_LISTEN = 8;
  
    public static final int STREAM_URL_STAT_LINK = 1;
    public static final int STREAM_URL_STAT_QUIET = 2;
  
    private static final HashMap<String,Value> _constMap 
      = new HashMap<String,Value>();
  
    private static final HashMap<String,ProtocolWrapper> _wrapperMap 
      = new HashMap<String,ProtocolWrapper>();
  
    private static final HashMap<String,ProtocolWrapper> _unregisteredWrapperMap 
      = new HashMap<String,ProtocolWrapper>();
  
    private static final ArrayValue _wrapperArray = new ArrayValueImpl();
  
    /**
     * Adds the constant to the PHP engine's constant map.
     *
     * @return the new constant chain
     */
    public Map<String,Value> getConstMap()
    {
      return _constMap;
    }
  
    /*
    public static void stream_bucket_append(Env env, 
                                            @NotNull StreamBucketBrigade brigade,
                                            @NotNull StreamBucket bucket)
    {
      brigade.append(bucket);
    }
  
    @ReturnNullAsFalse
    public static Value stream_bucket_make_writable(Env env, 
        @NotNull StreamBucketBrigade brigade)
    {
      return brigade.popTop();
    }
    */                                       
  
    /**
     * Creates a stream context.
     */
    public static Value stream_context_create(Env env, 
                                              @Optional ArrayValue options)
    {
      return new StreamContextResource(options);
    }
  
    /**
     * Returns the options from a stream context.
     */
    public static Value stream_context_get_options(Env env, Value resource)
    {
      if (resource instanceof StreamContextResource) {
        return ((StreamContextResource) resource).getOptions();
      }
      else {
        env.warning(L.l("expected resource at '{0}'", resource));
  
        return BooleanValue.FALSE;
      }
    }
  
    /**
     * Returns the default stream context.
     */
    public static Value stream_context_get_default(Env env,
                                                   @Optional ArrayValue options)
    {
      StreamContextResource context = env.getDefaultStreamContext();
  
      if (options != null)
        context.setOptions(options);
  
      return context;
    }
  
    /**
     * Set an options for a stream context.
     */
    public static boolean stream_context_set_option(Env env,
                                                    Value resource,
                                                    StringValue wrapper,
                                                    StringValue option,
                                                    Value value)
    {
      if (resource instanceof StreamContextResource) {
        StreamContextResource context = (StreamContextResource) resource;
  
        context.setOption(env, wrapper, option, value);
  
        return true;
      }
      else {
        env.warning(L.l("expected resource at '{0}'", resource));
  
        return false;
      }
    }
  
    /**
     * Sets parameters for the context
     */
    public static boolean stream_context_set_params(Env env,
                                                    Value resource,
                                                    ArrayValue value)
    {
      if (resource instanceof StreamContextResource) {
        StreamContextResource context = (StreamContextResource) resource;
  
        context.setParameters(value);
  
        return true;
      }
      else {
        env.warning(L.l("expected resource at '{0}'", resource));
  
        return false;
      }
    }
  
    /**
     * Copies from an input stream to an output stream
     */
    public static long stream_copy_to_stream(Env env,
                                             @NotNull BinaryInput in,
                                             @NotNull BinaryOutput out,
                                             @Optional("-1") int length,
                                             @Optional int offset)
    {
      try {
        if (in == null)
          return -1;
  
        if (out == null)
          return -1;
  
        TempBuffer temp = TempBuffer.allocate();
        byte []buffer = temp.getBuffer();
  
        while (offset-- > 0)
          in.read();
  
        if (length < 0)
          length = Integer.MAX_VALUE;
  
        long bytesWritten = 0;
  
        while (length > 0) {
          int sublen = buffer.length;
  
          if (length < sublen)
            sublen = (int) length;
  
          sublen = in.read(buffer, 0, sublen);
          if (sublen < 0)
            return bytesWritten;
  
          out.write(buffer, 0, sublen);
  
          bytesWritten += sublen;
          length -= sublen;
        }
  
        TempBuffer.free(temp);
  
        return bytesWritten;
      } catch (IOException e) {
        throw new QuercusModuleException(e);
      }
    }
  
    /**
     * Returns the rest of the file as a string
     *
     * @param filename the file's name
     * @param useIncludePath if true, use the include path
     * @param context the resource context
     */
    public static Value stream_get_contents(Env env,
                                            @NotNull BinaryInput in,
                                            @Optional("-1") long maxLen,
                                            @Optional long offset)
    {
      try {
        if (in == null)
          return BooleanValue.FALSE;
  
        StringBuilder sb = new StringBuilder();
  
        int ch;
  
        if (maxLen < 0)
          maxLen = Integer.MAX_VALUE;
  
        while (offset-- > 0)
          in.read();
  
        while (maxLen-- > 0 && (ch = in.read()) >= 0) {
          sb.append((char) ch);
        }
  
        // XXX: handle offset and maxlen
  
        return env.createStringOld(sb.toString());
      } catch (IOException e) {
        throw new QuercusModuleException(e);
      }
    }
  
    /**
     * Returns the next line
     */
    public static Value stream_get_line(Env env,
                                        @NotNull BinaryInput file,
                                        @Optional("-1") long length)
    {
      try {
        if (file == null)
          return BooleanValue.FALSE;
  
        if (length < 0)
          length = Integer.MAX_VALUE;
  
  