Changeset 11395


Ignore:
Timestamp:
11/23/08 11:29:10 (12 years ago)
Author:
ehuelsmann
Message:

Commit in-progress implementation.

Note: This commit still fails ansi test FILE-POSITION.5: it just locks up.

Location:
branches/open-external-format
Files:
2 added
3 edited

Legend:

Unmodified
Added
Removed
  • branches/open-external-format/build.xml

    r11386 r11395  
    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"/>
  • branches/open-external-format/src/org/armedbear/lisp/FileStream.java

    r11392 r11395  
    3838import java.io.IOException;
    3939import java.io.RandomAccessFile;
     40import org.armedbear.lisp.util.RandomAccessCharacterFile;
    4041
    4142public final class FileStream extends Stream
    4243{
    43     private static final int BUFSIZE = 4096;
    44 
    45     private final RandomAccessFile raf;
    46     private final RandomAccessFile in;
    47     private final RandomAccessFile out;
     44    private final RandomAccessCharacterFile racf;
     45    private final RandomAccessCharacterFile in;
     46    private final RandomAccessCharacterFile out;
    4847    private final Pathname pathname;
    4948    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;
    57 
     49
     50    public enum EolStyle {
     51        CR,
     52        CRLF,
     53        LF
     54    }
     55   
     56    static final private Symbol keywordCodePage = Packages.internKeyword("CODE-PAGE");
     57   
     58    private final static EolStyle platformEolStyle = Utilities.isPlatformWindows ? EolStyle.CRLF : EolStyle.LF;
     59   
     60    private EolStyle eolStyle = platformEolStyle;
     61    private char eolChar = 0;
     62   
    5863    public FileStream(Pathname pathname, String namestring,
    5964                      LispObject elementType, LispObject direction,
    60                       LispObject ifExists)
     65                      LispObject ifExists, String encoding, EolStyle eol)
    6166        throws IOException
    6267    {
     68        /* externalFormat is a LispObject of which the first char is a
     69         * name of a character encoding (such as :UTF-8 or :ISO-8859-1), used
     70         * by ABCL as a string designator, unless the name is :CODE-PAGE.
     71         * A real string is (thus) also allowed.
     72         *
     73         * Then, a property list follows with 3 possible keys:
     74         *   :ID (values: code page numbers supported by MS-DOS/IBM-DOS/MS-Windows
     75         *   :EOL-STYLE (values: :CR / :LF / :CRLF [none means native])
     76         *   :LITTLE-ENDIAN (values: NIL / T)
     77         *
     78         * These definitions have been taken from FLEXI-STREAMS:
     79         *    http://www.weitz.de/flexi-streams/#make-external-format
     80         */
    6381        final File file = new File(namestring);
    6482        String mode = null;
     
    7492            isOutputStream = true;
    7593        }
     94       
    7695        Debug.assertTrue(mode != null);
    77         raf = new RandomAccessFile(file, mode);
    78         in = isInputStream ? raf : null;
    79         out = isOutputStream ? raf : null;
     96        RandomAccessFile raf = new RandomAccessFile(file, mode);
     97        racf = new RandomAccessCharacterFile(raf, encoding);
     98        in = isInputStream ? racf : null;
     99        out = isOutputStream ? racf : null;
    80100        // ifExists is ignored unless we have an output stream.
    81101        if (isOutputStream) {
     
    106126            bytesPerUnit = width / 8;
    107127        }
    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;
     128        eolChar = (eol == EolStyle.CR) ? '\r' : '\n';
    120129    }
    121130
     
    151160    {
    152161        try {
    153             return in.getFilePointer() < in.length() ? T : NIL;
     162            return in.dataIsAvailableForRead() ? T : NIL;
    154163        }
    155164        catch (NullPointerException e) {
     
    169178        if (isOpen()) {
    170179            try {
    171                 length = raf.length();
     180                length = racf.length();
    172181            }
    173182            catch (IOException e) {
     
    191200    }
    192201
    193     @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 
    221202    // Returns -1 at end of file.
    222203    @Override
     
    224205    {
    225206        try {
    226             int c = _readByte();
    227             if (Utilities.isPlatformWindows) {
     207            int c = in.getReader().read();
     208            if (eolStyle == EolStyle.CRLF) {
    228209                if (c == '\r') {
    229                     int c2 = _readByte();
     210                    long mark = in.position();
     211                    int c2 = in.getReader().read();
    230212                    if (c2 == '\n') {
    231213                        ++lineNumber;
     
    233215                    }
    234216                    // '\r' was not followed by '\n'
    235                     if (inputBuffer != null && inputBufferOffset > 0) {
    236                         --inputBufferOffset;
     217                    // we cannot depend on characters to contain 1 byte only
     218                    // so we need to revert to the last known position.
     219                    in.position(mark);
     220                }
     221                return c;
     222            }
     223            if (c == eolChar) {
     224                ++lineNumber;
     225                return c;
     226            }
     227            return c;
     228        }
     229        catch (NullPointerException e) {
     230            streamNotInputStream();
     231        }
     232        catch (IOException e) {
     233            error(new StreamError(this, e));
     234        }
     235        // Not reached.
     236        return -1;
     237    }
     238
     239    @Override
     240    protected void _unreadChar(int n) throws ConditionThrowable
     241    {
     242        try {
     243            in.unreadChar((char)n);
     244        }
     245        catch (IOException e) {
     246            error(new StreamError(this, e));
     247        }
     248    }
     249
     250    @Override
     251    protected boolean _charReady() throws ConditionThrowable
     252    {
     253        return true;
     254    }
     255
     256    @Override
     257    public void _writeChar(char c) throws ConditionThrowable
     258    {
     259        try {
     260            if (c == '\n') {
     261                if (eolStyle == EolStyle.CRLF)
     262                    out.getWriter().write((byte)'\r');
     263                out.getWriter().write((byte)eolChar);
     264                charPos = 0;
     265            } else {
     266                out.getWriter().write((byte)c);
     267                ++charPos;
     268            }
     269        }
     270        catch (IOException e) {
     271            error(new StreamError(this, e));
     272        }
     273    }
     274
     275    @Override
     276    public void _writeChars(char[] chars, int start, int end)
     277        throws ConditionThrowable
     278    {
     279        try {
     280            if (eolStyle == EolStyle.CRLF) {
     281                for (int i = start; i < end; i++) {
     282                    char c = chars[i];
     283                    if (c == '\n') {
     284                        out.getWriter().write((byte)'\r');
     285                        out.getWriter().write((byte)'\n');
     286                        charPos = 0;
    237287                    } else {
    238                         clearInputBuffer();
    239                         long pos = in.getFilePointer();
    240                         if (pos > 0)
    241                             in.seek(pos - 1);
     288                        out.getWriter().write((byte)c);
     289                        ++charPos;
    242290                    }
    243291                }
    244                 return c;
    245             }
    246             if (c == '\n') {
    247                 ++lineNumber;
    248                 return c;
    249             }
    250             return c;
     292            } else {
     293                for (int i = start; i < end; i++) {
     294                    char c = chars[i];
     295                    out.getWriter().write((byte)c);
     296                    if (c == '\n') {
     297                        out.getWriter().write((byte)eolChar);
     298                        charPos = 0;
     299                    } else {
     300                        out.getWriter().write((byte)c);
     301                        ++charPos;
     302                    }
     303                }
     304            }
     305        }
     306        catch (IOException e) {
     307            error(new StreamError(this, e));
     308        }
     309    }
     310
     311    @Override
     312    public void _writeString(String s) throws ConditionThrowable
     313    {
     314        _writeChars(s.toCharArray(), 0, s.length());
     315    }
     316
     317    @Override
     318    public void _writeLine(String s) throws ConditionThrowable
     319    {
     320        _writeString(s);
     321        if (eolStyle == EolStyle.CRLF)
     322            _writeChar('\r');
     323        _writeChar(eolChar);
     324        charPos = 0;
     325    }
     326
     327    // Reads an 8-bit byte.
     328    @Override
     329    public int _readByte() throws ConditionThrowable
     330    {
     331        try {
     332            return in.getInputStream().read(); // Reads an 8-bit byte.
    251333        }
    252334        catch (NullPointerException e) {
     
    260342    }
    261343
    262     @Override
    263     protected void _unreadChar(int n) throws ConditionThrowable
    264     {
    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             }
     344    // Writes an 8-bit byte.
     345    @Override
     346    public void _writeByte(int n) throws ConditionThrowable
     347    {
     348        try {
     349            out.getOutputStream().write(n); // Writes an 8-bit byte.
     350        }
     351        catch (NullPointerException e) {
     352            streamNotOutputStream();
     353        }
     354        catch (IOException e) {
     355            error(new StreamError(this, e));
     356        }
     357    }
     358
     359    @Override
     360    public void _clearInput() throws ConditionThrowable
     361    {
     362        try {
     363            in.position(in.length());
    301364        }
    302365        catch (NullPointerException e) {
     
    309372
    310373    @Override
    311     protected boolean _charReady() throws ConditionThrowable
    312     {
    313         return true;
    314     }
    315 
    316     @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
    444     public void _clearInput() throws ConditionThrowable
    445     {
    446         try {
    447             in.seek(in.length());
    448             clearInputBuffer();
    449         }
    450         catch (NullPointerException e) {
    451             streamNotInputStream();
    452         }
    453         catch (IOException e) {
    454             error(new StreamError(this, e));
    455         }
    456     }
    457 
    458     @Override
    459374    protected long _getFilePosition() throws ConditionThrowable
    460375    {
    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();
     376        try {
     377            long pos = racf.position();
    469378            return pos / bytesPerUnit;
    470379        }
     
    479388    protected boolean _setFilePosition(LispObject arg) throws ConditionThrowable
    480389    {
    481         if (outputBuffer != null)
    482             flushOutputBuffer();
    483         if (inputBuffer != null)
    484             clearInputBuffer();
    485390        try {
    486391            long pos;
     
    488393                pos = 0;
    489394            else if (arg == Keyword.END)
    490                 pos = raf.length();
     395                pos = racf.length();
    491396            else {
    492397                long n = Fixnum.getValue(arg); // FIXME arg might be a bignum
    493398                pos = n * bytesPerUnit;
    494399            }
    495             raf.seek(pos);
     400            racf.position(pos);
    496401        }
    497402        catch (IOException e) {
     
    504409    public void _close() throws ConditionThrowable
    505410    {
    506         if (outputBuffer != null)
    507             flushOutputBuffer();
    508         try {
    509             raf.close();
     411        try {
     412            racf.close();
    510413            setOpen(false);
    511414        }
    512415        catch (IOException e) {
    513416            error(new StreamError(this, e));
    514         }
    515     }
    516 
    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             }
    569417        }
    570418    }
     
    579427    private static final Primitive MAKE_FILE_STREAM =
    580428        new Primitive("make-file-stream", PACKAGE_SYS, true,
    581                       "pathname namestring element-type direction if-exists")
     429                      "pathname namestring element-type direction if-exists external-format")
    582430    {
    583431        @Override
    584432        public LispObject execute(LispObject first, LispObject second,
    585433                                  LispObject third, LispObject fourth,
    586                                   LispObject fifth)
     434                                  LispObject fifth, LispObject sixth)
    587435            throws ConditionThrowable
    588436        {
     
    604452            LispObject direction = fourth;
    605453            LispObject ifExists = fifth;
     454            LispObject externalFormat = sixth;
     455           
     456            String encoding = "ISO-8859-1";
     457            if (externalFormat != NIL) {
     458                Symbol enc = (Symbol)externalFormat.car(); //FIXME: class cast exception to be caught
     459                if (enc != NIL) {
     460                    if (enc != keywordCodePage) {
     461                        encoding = enc.getName();
     462                    }
     463                    //FIXME: the else for the keywordCodePage to be filled in
     464                }
     465                //FIXME: the else for the == NIL to be filled in: raise an error...
     466            }
     467       
     468           
     469           
    606470            if (direction != Keyword.INPUT && direction != Keyword.OUTPUT &&
    607471                direction != Keyword.IO)
     
    609473            try {
    610474                return new FileStream(pathname, namestring.getStringValue(),
    611                                       elementType, direction, ifExists);
     475                                      elementType, direction, ifExists,
     476                                      encoding, platformEolStyle);
    612477            }
    613478            catch (FileNotFoundException e) {
  • branches/open-external-format/src/org/armedbear/lisp/open.lisp

    r11391 r11395  
    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 nil))
    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 nil)))
    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 nil)))
    208210         (unless stream
    209211           (error 'file-error
Note: See TracChangeset for help on using the changeset viewer.