Changeset 11434


Ignore:
Timestamp:
12/07/08 23:24:31 (12 years ago)
Author:
ehuelsmann
Message:

Merge open-external-format branch back to trunk.

Location:
trunk/j
Files:
8 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/j/build.xml

    r11386 r11434  
    101101    <patternset id="abcl.source.java">
    102102      <include name="org/armedbear/lisp/*.java"/>
     103      <include name="org/armedbear/lisp/util/*.java"/>
    103104      <include name="org/armedbear/Main.java"/>
    104105    </patternset>
     
    118119    <patternset id="abcl.objects">
    119120      <include name="org/armedbear/lisp/*.class"/>
     121      <include name="org/armedbear/lisp/util/*.class"/>
    120122      <include name="org/armedbear/lisp/*.cls"/>
    121123      <include name="org/armedbear/lisp/*.abcl"/>
  • trunk/j/src/org/armedbear/lisp/FileStream.java

    r11392 r11434  
    33 *
    44 * Copyright (C) 2004-2006 Peter Graves
     5 * Copyright (C) 2008 Hideo at Yokohama
    56 * $Id$
    67 *
     
    3536
    3637import java.io.File;
     38import java.io.InputStream;
     39import java.io.OutputStream;
     40import java.io.Reader;
     41import java.io.Writer;
    3742import java.io.FileNotFoundException;
    3843import java.io.IOException;
    3944import java.io.RandomAccessFile;
     45import org.armedbear.lisp.util.RandomAccessCharacterFile;
    4046
    4147public final class FileStream extends Stream
    4248{
    43     private static final int BUFSIZE = 4096;
    44 
    45     private final RandomAccessFile raf;
    46     private final RandomAccessFile in;
    47     private final RandomAccessFile out;
     49    private final RandomAccessCharacterFile racf;
    4850    private final Pathname pathname;
    4951    private final int bytesPerUnit;
    50     private final byte[] inputBuffer;
    51     private final byte[] outputBuffer;
    52 
    53     private long inputBufferFilePosition;
    54     private int inputBufferOffset;
    55     private int inputBufferCount;
    56     private int outputBufferOffset;
    5752
    5853    public FileStream(Pathname pathname, String namestring,
    5954                      LispObject elementType, LispObject direction,
    60                       LispObject ifExists)
     55                      LispObject ifExists, LispObject format)
    6156        throws IOException
    6257    {
     58        /* externalFormat is a LispObject of which the first char is a
     59         * name of a character encoding (such as :UTF-8 or :ISO-8859-1), used
     60         * by ABCL as a string designator, unless the name is :CODE-PAGE.
     61         * A real string is (thus) also allowed.
     62         *
     63         * Then, a property list follows with 3 possible keys:
     64         *   :ID (values: code page numbers supported by MS-DOS/IBM-DOS/MS-Windows
     65         *   :EOL-STYLE (values: :CR / :LF / :CRLF [none means native])
     66         *   :LITTLE-ENDIAN (values: NIL / T)
     67         *
     68         * These definitions have been taken from FLEXI-STREAMS:
     69         *    http://www.weitz.de/flexi-streams/#make-external-format
     70         */
    6371        final File file = new File(namestring);
    6472        String mode = null;
     
    7482            isOutputStream = true;
    7583        }
     84       
    7685        Debug.assertTrue(mode != null);
    77         raf = new RandomAccessFile(file, mode);
    78         in = isInputStream ? raf : null;
    79         out = isOutputStream ? raf : null;
     86        RandomAccessFile raf = new RandomAccessFile(file, mode);
     87 
    8088        // ifExists is ignored unless we have an output stream.
    8189        if (isOutputStream) {
     
    9098            }
    9199        }
     100        setExternalFormat(format);
     101       
     102  // don't touch raf directly after passing it to racf.
     103  // the state will become inconsistent if you do that.
     104        racf = new RandomAccessCharacterFile(raf, encoding);
     105
    92106        this.pathname = pathname;
    93107        this.elementType = elementType;
     
    95109            isCharacterStream = true;
    96110            bytesPerUnit = 1;
     111      if (isInputStream) {
     112    initAsCharacterInputStream(racf.getReader());
     113      }
     114      if (isOutputStream) {
     115    initAsCharacterOutputStream(racf.getWriter());
     116      }
    97117        } else {
    98118            isBinaryStream = true;
     
    105125            }
    106126            bytesPerUnit = width / 8;
    107         }
    108         if (isBinaryStream && isInputStream && !isOutputStream && bytesPerUnit == 1)
    109             inputBuffer = new byte[BUFSIZE];
    110         else if (isCharacterStream && isInputStream && !isOutputStream)
    111             inputBuffer = new byte[BUFSIZE];
    112         else
    113             inputBuffer = null;
    114         if (isBinaryStream && isOutputStream && !isInputStream && bytesPerUnit == 1)
    115             outputBuffer = new byte[BUFSIZE];
    116         else if (isCharacterStream && isOutputStream && !isInputStream)
    117             outputBuffer = new byte[BUFSIZE];
    118         else
    119             outputBuffer = null;
     127      if (isInputStream) {
     128    initAsBinaryInputStream(racf.getInputStream());
     129      }
     130      if (isOutputStream) {
     131    initAsBinaryOutputStream(racf.getOutputStream());
     132      }
     133        }
    120134    }
    121135
     
    148162
    149163    @Override
    150     public LispObject listen() throws ConditionThrowable
    151     {
    152         try {
    153             return in.getFilePointer() < in.length() ? T : NIL;
    154         }
    155         catch (NullPointerException e) {
    156             streamNotInputStream();
    157         }
    158         catch (IOException e) {
    159             error(new StreamError(this, e));
    160         }
    161         // Not reached.
    162         return NIL;
    163     }
    164 
    165     @Override
    166164    public LispObject fileLength() throws ConditionThrowable
    167165    {
     
    169167        if (isOpen()) {
    170168            try {
    171                 length = raf.length();
     169                length = racf.length();
    172170            }
    173171            catch (IOException e) {
     
    192190
    193191    @Override
    194     public LispObject readLine(boolean eofError, LispObject eofValue)
    195         throws ConditionThrowable
    196     {
    197         if (inputBuffer != null) {
    198             final LispThread thread = LispThread.currentThread();
    199             final FastStringBuffer sb = new FastStringBuffer();
    200             while (true) {
    201                 int n = _readChar();
    202                 if (n < 0) {
    203                     // End of file.
    204                     if (sb.length() == 0) {
    205                         if (eofError)
    206                             return error(new EndOfFile(this));
    207                         return thread.setValues(eofValue, T);
    208                     }
    209                     return thread.setValues(new SimpleString(sb), T);
    210                 }
    211                 char c = (char) n;
    212                 if (c == '\n')
    213                     return thread.setValues(new SimpleString(sb), NIL);
    214                 else
    215                     sb.append(c);
    216             }
    217         } else
    218             return super.readLine(eofError, eofValue);
    219     }
    220 
    221     // Returns -1 at end of file.
    222     @Override
    223     protected int _readChar() throws ConditionThrowable
    224     {
    225         try {
    226             int c = _readByte();
    227             if (Utilities.isPlatformWindows) {
    228                 if (c == '\r') {
    229                     int c2 = _readByte();
    230                     if (c2 == '\n') {
    231                         ++lineNumber;
    232                         return c2;
    233                     }
    234                     // '\r' was not followed by '\n'
    235                     if (inputBuffer != null && inputBufferOffset > 0) {
    236                         --inputBufferOffset;
    237                     } else {
    238                         clearInputBuffer();
    239                         long pos = in.getFilePointer();
    240                         if (pos > 0)
    241                             in.seek(pos - 1);
    242                     }
    243                 }
    244                 return c;
    245             }
    246             if (c == '\n') {
    247                 ++lineNumber;
    248                 return c;
    249             }
    250             return c;
    251         }
    252         catch (NullPointerException e) {
    253             streamNotInputStream();
    254         }
    255         catch (IOException e) {
    256             error(new StreamError(this, e));
    257         }
    258         // Not reached.
    259         return -1;
    260     }
    261 
    262     @Override
    263192    protected void _unreadChar(int n) throws ConditionThrowable
    264193    {
    265         if (inputBuffer != null && inputBufferOffset > 0) {
    266             --inputBufferOffset;
    267             if (n != '\n')
    268                 return;
    269             --lineNumber;
    270             if (!Utilities.isPlatformWindows)
    271                 return;
    272             // Check for preceding '\r'.
    273             if (inputBufferOffset > 0) {
    274                 if (inputBuffer[--inputBufferOffset] != '\r')
    275                     ++inputBufferOffset;
    276                 return;
    277             }
    278             // We can't go back far enough in the buffered input. Reset and
    279             // fall through...
    280             ++inputBufferOffset;
    281         }
    282         try {
    283             long pos;
    284             if (inputBuffer != null && inputBufferFilePosition >= 0)
    285                 pos = inputBufferFilePosition + inputBufferOffset;
    286             else
    287                 pos = in.getFilePointer();
    288             clearInputBuffer();
    289             if (pos > 0)
    290                 in.seek(pos - 1);
    291             if (Utilities.isPlatformWindows && n == '\n') {
    292                 // Check for preceding '\r'.
    293                 pos = in.getFilePointer();
    294                 if (pos > 0) {
    295                     in.seek(pos - 1);
    296                     n = in.read();
    297                     if (n == '\r')
    298                         in.seek(pos - 1);
    299                 }
    300             }
    301         }
    302         catch (NullPointerException e) {
    303             streamNotInputStream();
     194        try {
     195            racf.unreadChar((char)n);
    304196        }
    305197        catch (IOException e) {
     
    315207
    316208    @Override
    317     public void _writeChar(char c) throws ConditionThrowable
    318     {
    319         if (c == '\n') {
    320             if (Utilities.isPlatformWindows)
    321                 _writeByte((byte)'\r');
    322             _writeByte((byte)c);
    323             charPos = 0;
    324         } else {
    325             _writeByte((byte)c);
    326             ++charPos;
    327         }
    328     }
    329 
    330     @Override
    331     public void _writeChars(char[] chars, int start, int end)
    332         throws ConditionThrowable
    333     {
    334         if (Utilities.isPlatformWindows) {
    335             for (int i = start; i < end; i++) {
    336                 char c = chars[i];
    337                 if (c == '\n') {
    338                     _writeByte((byte)'\r');
    339                     _writeByte((byte)c);
    340                     charPos = 0;
    341                 } else {
    342                     _writeByte((byte)c);
    343                     ++charPos;
    344                 }
    345             }
    346         } else {
    347             // We're not on Windows, so no newline conversion is necessary.
    348             for (int i = start; i < end; i++) {
    349                 char c = chars[i];
    350                 _writeByte((byte)c);
    351                 if (c == '\n')
    352                     charPos = 0;
    353                 else
    354                     ++charPos;
    355             }
    356         }
    357     }
    358 
    359     @Override
    360     public void _writeString(String s) throws ConditionThrowable
    361     {
    362         final int length = s.length();
    363         if (Utilities.isPlatformWindows) {
    364             for (int i = 0; i < length; i++) {
    365                 char c = s.charAt(i);
    366                 if (c == '\n') {
    367                     _writeByte((byte)'\r');
    368                     _writeByte((byte)c);
    369                     charPos = 0;
    370                 } else {
    371                     _writeByte((byte)c);
    372                     ++charPos;
    373                 }
    374             }
    375         } else {
    376             // We're not on Windows, so no newline conversion is necessary.
    377             for (int i = 0; i < length; i++) {
    378                 char c = s.charAt(i);
    379                 _writeByte((byte)c);
    380                 if (c == '\n')
    381                     charPos = 0;
    382                 else
    383                     ++charPos;
    384             }
    385         }
    386     }
    387 
    388     @Override
    389     public void _writeLine(String s) throws ConditionThrowable
    390     {
    391         _writeString(s);
    392         if (Utilities.isPlatformWindows)
    393             _writeByte((byte)'\r');
    394         _writeByte((byte)'\n');
    395         charPos = 0;
    396     }
    397 
    398     // Reads an 8-bit byte.
    399     @Override
    400     public int _readByte() throws ConditionThrowable
    401     {
    402         if (inputBuffer != null)
    403             return readByteFromBuffer();
    404         try {
    405             return in.read(); // Reads an 8-bit byte.
    406         }
    407         catch (NullPointerException e) {
    408             streamNotInputStream();
    409         }
    410         catch (IOException e) {
    411             error(new StreamError(this, e));
    412         }
    413         // Not reached.
    414         return -1;
    415     }
    416 
    417     // Writes an 8-bit byte.
    418     @Override
    419     public void _writeByte(int n) throws ConditionThrowable
    420     {
    421         if (outputBuffer != null) {
    422             writeByteToBuffer((byte)n);
    423         } else {
    424             try {
    425                 out.write((byte)n); // Writes an 8-bit byte.
    426             }
    427             catch (NullPointerException e) {
    428                 streamNotOutputStream();
    429             }
    430             catch (IOException e) {
    431                 error(new StreamError(this, e));
    432             }
    433         }
    434     }
    435 
    436     @Override
    437     public void _finishOutput() throws ConditionThrowable
    438     {
    439         if (outputBuffer != null)
    440             flushOutputBuffer();
    441     }
    442 
    443     @Override
    444209    public void _clearInput() throws ConditionThrowable
    445210    {
    446211        try {
    447             in.seek(in.length());
    448             clearInputBuffer();
    449         }
    450         catch (NullPointerException e) {
    451             streamNotInputStream();
     212      if (isInputStream) {
     213    racf.position(racf.length());
     214      } else {
     215    streamNotInputStream();
     216      }
    452217        }
    453218        catch (IOException e) {
     
    459224    protected long _getFilePosition() throws ConditionThrowable
    460225    {
    461         if (inputBuffer != null) {
    462             if (inputBufferFilePosition >= 0)
    463                 return inputBufferFilePosition + inputBufferOffset;
    464         }
    465         if (outputBuffer != null)
    466             flushOutputBuffer();
    467         try {
    468             long pos = raf.getFilePointer();
     226        try {
     227            long pos = racf.position();
    469228            return pos / bytesPerUnit;
    470229        }
     
    479238    protected boolean _setFilePosition(LispObject arg) throws ConditionThrowable
    480239    {
    481         if (outputBuffer != null)
    482             flushOutputBuffer();
    483         if (inputBuffer != null)
    484             clearInputBuffer();
    485240        try {
    486241            long pos;
     
    488243                pos = 0;
    489244            else if (arg == Keyword.END)
    490                 pos = raf.length();
     245                pos = racf.length();
    491246            else {
    492247                long n = Fixnum.getValue(arg); // FIXME arg might be a bignum
    493248                pos = n * bytesPerUnit;
    494249            }
    495             raf.seek(pos);
     250            racf.position(pos);
    496251        }
    497252        catch (IOException e) {
     
    504259    public void _close() throws ConditionThrowable
    505260    {
    506         if (outputBuffer != null)
    507             flushOutputBuffer();
    508         try {
    509             raf.close();
     261        try {
     262            racf.close();
    510263            setOpen(false);
    511264        }
     
    515268    }
    516269
    517     private int readByteFromBuffer() throws ConditionThrowable
    518     {
    519         if (inputBufferOffset >= inputBufferCount) {
    520             fillInputBuffer();
    521             if (inputBufferCount < 0)
    522                 return -1;
    523         }
    524         return inputBuffer[inputBufferOffset++] & 0xff;
    525     }
    526 
    527     private void fillInputBuffer() throws ConditionThrowable
    528     {
    529         try {
    530             inputBufferFilePosition = in.getFilePointer();
    531             inputBufferOffset = 0;
    532             inputBufferCount = in.read(inputBuffer, 0, BUFSIZE);
    533         }
    534         catch (NullPointerException e) {
    535             streamNotInputStream();
    536         }
    537         catch (IOException e) {
    538             error(new StreamError(this, e));
    539         }
    540     }
    541 
    542     private void clearInputBuffer()
    543     {
    544         inputBufferFilePosition = -1;
    545         inputBufferOffset = 0;
    546         inputBufferCount = 0;
    547     }
    548 
    549     private void writeByteToBuffer(byte b) throws ConditionThrowable
    550     {
    551         if (outputBufferOffset == BUFSIZE)
    552             flushOutputBuffer();
    553         outputBuffer[outputBufferOffset++] = b;
    554     }
    555 
    556     private void flushOutputBuffer() throws ConditionThrowable
    557     {
    558         if (outputBufferOffset > 0) {
    559             try {
    560                 out.write(outputBuffer, 0, outputBufferOffset);
    561                 outputBufferOffset = 0;
    562             }
    563             catch (NullPointerException e) {
    564                 streamNotOutputStream();
    565             }
    566             catch (IOException e) {
    567                 error(new StreamError(this, e));
    568             }
    569         }
    570     }
    571 
    572270    @Override
    573271    public String writeToString() throws ConditionThrowable
     
    576274    }
    577275
    578     // ### make-file-stream pathname namestring element-type direction if-exists => stream
     276    // ### make-file-stream pathname namestring element-type direction if-exists external-format => stream
    579277    private static final Primitive MAKE_FILE_STREAM =
    580278        new Primitive("make-file-stream", PACKAGE_SYS, true,
    581                       "pathname namestring element-type direction if-exists")
     279                      "pathname namestring element-type direction if-exists external-format")
    582280    {
    583281        @Override
    584282        public LispObject execute(LispObject first, LispObject second,
    585283                                  LispObject third, LispObject fourth,
    586                                   LispObject fifth)
     284                                  LispObject fifth, LispObject sixth)
    587285            throws ConditionThrowable
    588286        {
     
    604302            LispObject direction = fourth;
    605303            LispObject ifExists = fifth;
     304            LispObject externalFormat = sixth;
     305           
    606306            if (direction != Keyword.INPUT && direction != Keyword.OUTPUT &&
    607307                direction != Keyword.IO)
     
    609309            try {
    610310                return new FileStream(pathname, namestring.getStringValue(),
    611                                       elementType, direction, ifExists);
     311                                      elementType, direction, ifExists,
     312                                      externalFormat);
    612313            }
    613314            catch (FileNotFoundException e) {
  • trunk/j/src/org/armedbear/lisp/Stream.java

    r11391 r11434  
    4444import java.io.PrintWriter;
    4545import java.io.PushbackReader;
     46import java.io.Reader;
    4647import java.io.StringWriter;
    4748import java.io.Writer;
     
    6364  protected boolean isBinaryStream;
    6465
     66  private boolean pastEnd = false;
    6567  private boolean interactive;
    6668  private boolean open = true;
    67 
     69 
    6870  // Character input.
    69   private PushbackReader reader;
     71  protected PushbackReader reader;
    7072  protected int offset;
    7173  protected int lineNumber;
     
    8082   */
    8183  protected int charPos;
    82 
     84 
     85  public enum EolStyle {
     86    RAW,
     87    CR,
     88    CRLF,
     89    LF
     90  }
     91
     92  static final protected Symbol keywordDefault = Packages.internKeyword("DEFAULT");
     93 
     94  static final private Symbol keywordCodePage = Packages.internKeyword("CODE-PAGE");
     95  static final private Symbol keywordID = Packages.internKeyword("ID");
     96
     97  static final private Symbol keywordEolStyle = Packages.internKeyword("EOL-STYLE");
     98  static final private Symbol keywordCR = Packages.internKeyword("CR");
     99  static final private Symbol keywordLF = Packages.internKeyword("LF");
     100  static final private Symbol keywordCRLF = Packages.internKeyword("CRLF");
     101  static final private Symbol keywordRAW = Packages.internKeyword("RAW");
     102   
     103  public final static EolStyle platformEolStyle = Utilities.isPlatformWindows ? EolStyle.CRLF : EolStyle.LF;
     104   
     105  protected EolStyle eolStyle = platformEolStyle;
     106  protected char eolChar = (eolStyle == EolStyle.CR) ? '\r' : '\n';
     107  protected LispObject externalFormat = LispObject.NIL;
     108  protected String encoding = null;
     109  protected char lastChar = 0;
     110 
    83111  // Binary input.
    84   private BufferedInputStream in;
     112  private InputStream in;
    85113
    86114  // Binary output.
    87   private BufferedOutputStream out;
     115  private OutputStream out;
    88116
    89117  protected Stream()
     
    91119  }
    92120
     121  public Stream(InputStream inputStream, LispObject elementType)
     122    {
     123      this(inputStream, elementType, keywordDefault);
     124    }
     125
     126
    93127  // Input stream constructors.
    94   public Stream(InputStream inputStream, LispObject elementType)
     128    public Stream(InputStream inputStream, LispObject elementType, LispObject format)
    95129  {
    96130    this.elementType = elementType;
     131    setExternalFormat(format);
    97132    if (elementType == Symbol.CHARACTER || elementType == Symbol.BASE_CHAR)
    98133      {
    99         isCharacterStream = true;
    100134        InputStreamReader inputStreamReader;
    101135        try
    102136          {
    103137            inputStreamReader =
    104               new InputStreamReader(inputStream, "ISO-8859-1");
     138                    (encoding == null) ?
     139                        new InputStreamReader(inputStream)
     140                        : new InputStreamReader(inputStream, encoding);
    105141          }
    106142        catch (java.io.UnsupportedEncodingException e)
     
    110146              new InputStreamReader(inputStream);
    111147          }
    112         reader = new PushbackReader(new BufferedReader(inputStreamReader),
    113                                     2);
     148        initAsCharacterInputStream(new BufferedReader(inputStreamReader));
    114149      }
    115150    else
    116151      {
    117152        isBinaryStream = true;
    118         in = new BufferedInputStream(inputStream);
    119       }
    120     isInputStream = true;
    121     isOutputStream = false;
     153        InputStream stream = new BufferedInputStream(inputStream);
     154  initAsBinaryInputStream(stream);
     155      }
    122156  }
    123157
     
    128162  }
    129163
     164  public Stream(OutputStream outputStream, LispObject elementType)
     165    {
     166      this(outputStream, elementType, keywordDefault);
     167    }
     168   
    130169  // Output stream constructors.
    131   public Stream(OutputStream outputStream, LispObject elementType)
     170  public Stream(OutputStream outputStream, LispObject elementType, LispObject format)
    132171  {
    133172    this.elementType = elementType;
     173    setExternalFormat(format);
    134174    if (elementType == Symbol.CHARACTER || elementType == Symbol.BASE_CHAR)
    135175      {
    136         isCharacterStream = true;
     176  Writer w;
    137177        try
    138178          {
    139             writer = new OutputStreamWriter(outputStream, "ISO-8859-1");
     179            w = (encoding == null) ?
     180                new OutputStreamWriter(outputStream)
     181                : new OutputStreamWriter(outputStream, encoding);
    140182          }
    141183        catch (java.io.UnsupportedEncodingException e)
    142184          {
    143185            Debug.trace(e);
    144             writer = new OutputStreamWriter(outputStream);
    145           }
     186            w = new OutputStreamWriter(outputStream);
     187          }
     188  initAsCharacterOutputStream(w);
    146189      }
    147190    else
    148191      {
    149         isBinaryStream = true;
    150         out = new BufferedOutputStream(outputStream);
    151       }
    152     isInputStream = false;
    153     isOutputStream = true;
     192        OutputStream stream = new BufferedOutputStream(outputStream);
     193  initAsBinaryOutputStream(stream);
     194      }
    154195  }
    155196
     
    161202  }
    162203
     204  protected void initAsCharacterInputStream(Reader reader)
     205  {
     206    if (! (reader instanceof PushbackReader))
     207        this.reader = new PushbackReader(reader, 5);
     208    else
     209        this.reader = (PushbackReader)reader;
     210   
     211    isInputStream = true;
     212    isCharacterStream = true;
     213  }
     214
     215  protected void initAsBinaryInputStream(InputStream in) {
     216    this.in = in;
     217    isInputStream = true;
     218    isBinaryStream = true;
     219  }
     220
     221  protected void initAsCharacterOutputStream(Writer writer) {
     222    this.writer = writer;
     223    isOutputStream = true;
     224    isCharacterStream = true;
     225  }
     226
     227  protected void initAsBinaryOutputStream(OutputStream out) {
     228    this.out = out;
     229    isOutputStream = true;
     230    isBinaryStream = true;
     231  }
     232
    163233  public boolean isInputStream() throws ConditionThrowable
    164234  {
     
    201271  }
    202272
     273  public LispObject getExternalFormat() {
     274      return externalFormat;
     275  }
     276 
     277  public String getEncoding() {
     278      return encoding;
     279  }
     280 
     281  public void setExternalFormat(LispObject format) {
     282    if (format == keywordDefault) {
     283      encoding = null;
     284      eolStyle = platformEolStyle;
     285      eolChar = (eolStyle == EolStyle.CR) ? '\r' : '\n';
     286      externalFormat = format;
     287      return;
     288    }
     289     
     290    try {
     291      LispObject enc;
     292      boolean encIsCp = false;
     293     
     294      if (format instanceof Cons) {
     295          // meaning a non-empty list
     296          enc = format.car();
     297
     298          if (enc == keywordCodePage) {
     299              encIsCp = true;
     300
     301              enc = LispObject.getf(format.cdr(), keywordID, null);
     302          }
     303         
     304          LispObject eol = LispObject.getf(format.cdr(), keywordEolStyle, keywordRAW);
     305          if (eol == keywordCR)
     306              eolStyle = EolStyle.CR;
     307          else if (eol == keywordLF)
     308              eolStyle = EolStyle.LF;
     309          else if (eol == keywordCRLF)
     310              eolStyle = EolStyle.CRLF;
     311          else if (eol != keywordRAW)
     312              //###FIXME: raise an error
     313              ;
     314         
     315      } else
     316        enc = format;
     317     
     318      if (enc.numberp())
     319          encoding = enc.toString();
     320      else if (enc instanceof AbstractString)
     321          encoding = enc.getStringValue();
     322      else if (enc == keywordDefault)
     323          // This allows the user to use the encoding determined by
     324          // Java to be the default for the current environment
     325          // while still being able to set other stream options
     326          // (e.g. :EOL-STYLE)
     327          encoding = null;
     328      else if (enc instanceof Symbol)
     329          encoding = ((Symbol)enc).getName();
     330      else
     331          //###FIXME: raise an error!
     332          ;
     333     
     334      if (encIsCp)
     335          encoding = "Cp" + encoding;
     336    }
     337    catch (ConditionThrowable ct) { }
     338   
     339    eolChar = (eolStyle == EolStyle.CR) ? '\r' : '\n';
     340    externalFormat = format;
     341  }
     342 
    203343  public boolean isOpen()
    204344  {
     
    16041744  public LispObject listen() throws ConditionThrowable
    16051745  {
    1606     return _charReady() ? T : NIL;
     1746    if (pastEnd)
     1747      return NIL;
     1748   
     1749    if (! _charReady())
     1750      return NIL;
     1751   
     1752    int n = _readChar();
     1753    if (n < 0)
     1754      return NIL;
     1755
     1756    _unreadChar(n);
     1757   
     1758    return T;
    16071759  }
    16081760
     
    16521804  protected int _readChar() throws ConditionThrowable
    16531805  {
     1806    if (pastEnd)
     1807      return -1;
     1808   
    16541809    try
    16551810      {
    16561811        int n = reader.read();
     1812       
     1813        if (n < 0) {
     1814            pastEnd = true;
     1815            return -1;
     1816        }
     1817       
    16571818        ++offset;
    1658         if (n == '\r')
    1659           {
    1660             if (interactive && Utilities.isPlatformWindows)
    1661               return _readChar();
    1662           }
    1663         if (n == '\n')
     1819        if (eolStyle == EolStyle.CRLF && n == '\r') {
     1820            n = _readChar();
     1821            if (n != '\n') {
     1822                _unreadChar(n);
     1823                return '\r';
     1824            }
     1825        }
     1826
     1827        if (n == eolChar) {
    16641828          ++lineNumber;
     1829          return '\n';
     1830        }
     1831
    16651832        return n;
    16661833      }
     
    16891856        reader.unread(n);
    16901857        --offset;
    1691         if (n == '\n')
     1858        pastEnd = false;
     1859        if (n == eolChar)
    16921860          --lineNumber;
    16931861      }
     
    17371905    try
    17381906      {
    1739         writer.write(c);
    1740         if (c == '\n')
    1741           {
    1742             writer.flush();
    1743             charPos = 0;
    1744           }
    1745         else
     1907        if (c == '\n') {
     1908    if (eolStyle == EolStyle.CRLF && lastChar != '\r')
     1909              writer.write('\r');
     1910
     1911          writer.write(eolChar);
     1912          lastChar = eolChar;
     1913          writer.flush();
     1914          charPos = 0;
     1915        } else {
     1916          writer.write(c);
     1917          lastChar = c;
    17461918          ++charPos;
     1919        }
    17471920      }
    17481921    catch (NullPointerException e)
     
    17701943    try
    17711944      {
     1945        if (eolStyle != EolStyle.RAW) {
     1946          for (int i = start; i < end; i++)
     1947            //###FIXME: the number of writes can be greatly reduced by
     1948            // writing the space between newlines as chunks.
     1949            _writeChar(chars[i]);
     1950          return;
     1951        }
     1952       
    17721953        writer.write(chars, start, end - start);
     1954        if (start < end)
     1955          lastChar = chars[end-1];
     1956       
    17731957        int index = -1;
    17741958        for (int i = end; i-- > start;)
     
    17781962                index = i;
    17791963                break;
    1780               }
    1781           }
     1964    }
     1965  }
    17821966        if (index < 0)
    17831967          {
    17841968            // No newline.
    17851969            charPos += (end - start);
    1786           }
     1970        }
    17871971        else
    17881972          {
    17891973            charPos = end - (index + 1);
    1790             writer.flush();
    1791           }
    1792       }
     1974              writer.flush();
     1975      }
     1976    }
    17931977    catch (NullPointerException e)
    17941978      {
     
    18141998    try
    18151999      {
    1816         writer.write(s);
    1817         int index = s.lastIndexOf('\n');
    1818         if (index < 0)
    1819           charPos += s.length();
    1820         else
    1821           {
    1822             charPos = s.length() - (index + 1);
    1823             writer.flush();
    1824           }
     2000  _writeChars(s.toCharArray(), 0, s.length());
    18252001      }
    18262002    catch (NullPointerException e)
     
    18302006        else
    18312007          throw e;
    1832       }
    1833     catch (IOException e)
    1834       {
    1835         error(new StreamError(this, e));
    18362008      }
    18372009  }
     
    18472019    try
    18482020      {
    1849         writer.write(s);
    1850         writer.write('\n');
    1851         writer.flush();
    1852         charPos = 0;
     2021        _writeString(s);
     2022        _writeChar('\n');
    18532023      }
    18542024    catch (NullPointerException e)
     
    18562026        // writer is null
    18572027        streamNotCharacterOutputStream();
    1858       }
    1859     catch (IOException e)
    1860       {
    1861         error(new StreamError(this, e));
    18622028      }
    18632029  }
     
    18732039    try
    18742040      {
    1875         return in.read(); // Reads an 8-bit byte.
     2041        int n = in.read();
     2042        if (n < 0)
     2043          pastEnd = true;
     2044       
     2045        return n; // Reads an 8-bit byte.
    18762046      }
    18772047    catch (IOException e)
     
    19342104    if (reader != null)
    19352105      {
    1936         while (_charReady())
    1937           _readChar();
     2106        int c = 0;
     2107        while (_charReady() && (c >= 0))
     2108          c = _readChar();
    19382109      }
    19392110    else if (in != null)
     
    19412112        try
    19422113          {
     2114            int n = 0;
    19432115            while (in.available() > 0)
    1944               in.read();
     2116              n = in.read();
     2117           
     2118            if (n < 0)
     2119              pastEnd = true;
    19452120          }
    19462121        catch (IOException e)
     
    20072182        writer.write(sw.toString());
    20082183        writer.write('\n');
     2184        lastChar = '\n';
    20092185        writer.flush();
    20102186        charPos = 0;
  • trunk/j/src/org/armedbear/lisp/StringInputStream.java

    r11391 r11434  
    3434package org.armedbear.lisp;
    3535
     36import java.io.StringReader;
     37
    3638public final class StringInputStream extends Stream
    3739{
    38     final String s;
    39     final int start;
    40     final int end;
    41 
     40    private final StringReader stringReader;
     41    private final int start;
     42   
    4243    public StringInputStream(String s)
    4344    {
     
    5354    {
    5455        elementType = Symbol.CHARACTER;
    55         isInputStream = true;
    56         isOutputStream = false;
    57         isCharacterStream = true;
    58         isBinaryStream = false;
    59         this.s = s;
     56        setExternalFormat(keywordDefault);
     57        eolStyle = EolStyle.RAW;
     58
    6059        this.start = start;
    61         this.end = end;
    62         offset = start;
     60       
     61        stringReader = new StringReader(s.substring(start, end));
     62        initAsCharacterInputStream(stringReader);
    6363    }
    6464
     65    @Override
    6566    public LispObject typeOf()
    6667    {
     
    6869    }
    6970
     71    @Override
    7072    public LispObject classOf()
    7173    {
     
    7375    }
    7476
     77    @Override
    7578    public LispObject typep(LispObject type) throws ConditionThrowable
    7679    {
     
    8689    }
    8790
    88     public LispObject close(LispObject abort) throws ConditionThrowable
    89     {
    90         setOpen(false);
    91         return T;
    92     }
    93 
    94     public LispObject listen()
    95     {
    96         return offset < end ? T : NIL;
    97     }
    98 
    99     protected int _readChar()
    100     {
    101         if (offset >= end)
    102             return -1;
    103         int n = s.charAt(offset);
    104         ++offset;
    105         if (n == '\n')
    106             ++lineNumber;
    107         return n;
    108     }
    109 
    110     protected void _unreadChar(int n)
    111     {
    112         if (offset > start) {
    113             --offset;
    114             if (n == '\n')
    115                 --lineNumber;
    116         }
    117     }
    118 
    119     protected boolean _charReady()
    120     {
    121         return true;
    122     }
    123 
     91    @Override
    12492    public String toString()
    12593    {
     
    12795    }
    12896
     97    @Override
     98    public int getOffset() {
     99        return start + super.getOffset();
     100    }
     101   
    129102    // ### make-string-input-stream
    130103    // make-string-input-stream string &optional start end => string-stream
     
    132105        new Primitive("make-string-input-stream", "string &optional start end")
    133106    {
     107        @Override
    134108        public LispObject execute(LispObject arg) throws ConditionThrowable
    135109        {
     
    137111        }
    138112
     113        @Override
    139114        public LispObject execute(LispObject first, LispObject second)
    140115            throws ConditionThrowable
     
    145120        }
    146121
     122        @Override
    147123        public LispObject execute(LispObject first, LispObject second,
    148124                                  LispObject third)
     
    162138        new Primitive("string-input-stream-current", PACKAGE_EXT, true, "stream")
    163139    {
     140        @Override
    164141        public LispObject execute(LispObject arg) throws ConditionThrowable
    165142        {
  • trunk/j/src/org/armedbear/lisp/StringOutputStream.java

    r11391 r11434  
    4848    {
    4949        this.elementType = elementType;
    50         isInputStream = false;
    51         isOutputStream = true;
    52         isCharacterStream = true;
    53         isBinaryStream = false;
    54         setWriter(stringWriter = new StringWriter());
     50        this.eolStyle = EolStyle.RAW;
     51        initAsCharacterOutputStream(stringWriter = new StringWriter());
    5552    }
    5653
     54    @Override
    5755    public LispObject typeOf()
    5856    {
     
    6058    }
    6159
     60    @Override
    6261    public LispObject classOf()
    6362    {
     
    6564    }
    6665
     66    @Override
    6767    public LispObject typep(LispObject type) throws ConditionThrowable
    6868    {
     
    7878    }
    7979
    80     public void _writeChar(char c) throws ConditionThrowable
    81     {
    82         if (elementType == NIL)
    83             writeError();
    84         super._writeChar(c);
    85     }
    86 
    87     public void _writeChars(char[] chars, int start, int end)
    88         throws ConditionThrowable
    89     {
    90         if (elementType == NIL)
    91             writeError();
    92         super._writeChars(chars, start, end);
    93     }
    94 
    95     public void _writeString(String s) throws ConditionThrowable
    96     {
    97         if (elementType == NIL)
    98             writeError();
    99         super._writeString(s);
    100     }
    101 
    102     public void _writeLine(String s) throws ConditionThrowable
    103     {
    104         if (elementType == NIL)
    105             writeError();
    106         super._writeLine(s);
    107     }
    108 
    109     private void writeError() throws ConditionThrowable
    110     {
    111         error(new TypeError("Attempt to write to a string output stream of element type NIL."));
    112     }
    113 
     80    @Override
    11481    protected long _getFilePosition() throws ConditionThrowable
    11582    {
    11683        if (elementType == NIL)
    11784            return 0;
    118         return stringWriter.toString().length();
     85        return stringWriter.getBuffer().length();
    11986    }
    12087
     
    12996    }
    13097
     98    @Override
    13199    public String toString()
    132100    {
     
    140108                       "element-type")
    141109    {
     110        @Override
    142111        public LispObject execute(LispObject arg) throws ConditionThrowable
    143112        {
     
    151120        new Primitive("get-output-stream-string", "string-output-stream")
    152121    {
     122        @Override
    153123        public LispObject execute(LispObject arg) throws ConditionThrowable
    154124        {
  • trunk/j/src/org/armedbear/lisp/open.lisp

    r11391 r11434  
    107107       (if-does-not-exist nil if-does-not-exist-given)
    108108       (external-format :default))
    109   (declare (ignore external-format)) ; FIXME
     109;  (declare (ignore external-format)) ; FIXME
    110110  (setf element-type (case element-type
    111111                       ((character base-char)
     
    144144                   :format-control "The file ~S does not exist."
    145145                   :format-arguments (list namestring)))))
    146        (make-file-stream pathname namestring element-type :input nil))
     146       (make-file-stream pathname namestring element-type :input nil external-format))
    147147      (:probe
    148148       (case if-does-not-exist
     
    158158          ;; not yet exist." See java.io.File.createNewFile().
    159159          (create-new-file namestring)))
    160        (let ((stream (make-file-stream pathname namestring element-type :input nil)))
     160       (let ((stream (make-file-stream pathname namestring element-type
     161                                       :input nil external-format)))
    161162         (when stream
    162163           (close stream))
     
    205206                 :format-control "Option not supported: ~S."
    206207                 :format-arguments (list if-exists))))
    207        (let ((stream (make-file-stream pathname namestring element-type direction if-exists)))
     208       (let ((stream (make-file-stream pathname namestring element-type
     209                                       direction if-exists external-format)))
    208210         (unless stream
    209211           (error 'file-error
  • trunk/j/src/org/armedbear/lisp/socket.lisp

    r11391 r11434  
    3232(in-package "SYSTEM")
    3333
    34 (defun get-socket-stream (socket &key (element-type 'character))
    35   ":ELEMENT-TYPE must be CHARACTER or (UNSIGNED-BYTE 8); the default is CHARACTER."
     34(defun get-socket-stream (socket &key (element-type 'character) (external-format :default))
     35  ":ELEMENT-TYPE must be CHARACTER or (UNSIGNED-BYTE 8); the default is CHARACTER.
     36EXTERNAL-FORMAT must be of the same format as specified for OPEN."
    3637  (cond ((eq element-type 'character))
    3738        ((equal element-type '(unsigned-byte 8)))
     
    4041                :format-control
    4142                ":ELEMENT-TYPE must be CHARACTER or (UNSIGNED-BYTE 8).")))
    42   (%socket-stream socket element-type))
     43  (%socket-stream socket element-type external-format))
    4344
    4445(defun make-socket (host port)
  • trunk/j/src/org/armedbear/lisp/socket_stream.java

    r11391 r11434  
    4141    private socket_stream()
    4242    {
    43         super("%socket-stream", PACKAGE_SYS, false, "socket element-type");
     43        super("%socket-stream", PACKAGE_SYS, false, "socket element-type external-format");
    4444    }
    4545
    46     public LispObject execute(LispObject first, LispObject second)
     46    public LispObject execute(LispObject first, LispObject second, LispObject third)
    4747        throws ConditionThrowable
    4848    {
     
    5151        try {
    5252             Stream in =
    53                  new Stream(socket.getInputStream(), elementType);
     53                 new Stream(socket.getInputStream(), elementType, third);
    5454             Stream out =
    55                  new Stream(socket.getOutputStream(), elementType);
     55                 new Stream(socket.getOutputStream(), elementType, third);
    5656             return new SocketStream(socket, in, out);
    5757        }
Note: See TracChangeset for help on using the changeset viewer.