Mercurial > hg > xemacs-beta
diff src/lstream.h @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 131b0175ea99 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lstream.h Mon Aug 13 08:45:50 2007 +0200 @@ -0,0 +1,313 @@ +/* Generic stream implementation -- header file. + Copyright (C) 1995 Free Software Foundation, Inc. + Copyright (C) 1996 Ben Wing. + +This file is part of XEmacs. + +XEmacs 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, or (at your option) any +later version. + +XEmacs 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. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Not in FSF. */ + +/* Written by Ben Wing. */ + +#ifndef _XEMACS_LSTREAM_H_ +#define _XEMACS_LSTREAM_H_ + +/************************************************************************/ +/* definition of Lstream object */ +/************************************************************************/ + +DECLARE_LRECORD (lstream, struct lstream); +#define XLSTREAM(x) XRECORD (x, lstream, struct lstream) +#define XSETLSTREAM(x, p) XSETRECORD (x, p, lstream) +#define LSTREAMP(x) RECORDP (x, lstream) +/* #define CHECK_LSTREAM(x) CHECK_RECORD (x, lstream) + Lstream pointers should never escape to the Lisp level, so + functions should not be doing this. */ + +#ifndef EOF +#define EOF (-1) +#endif + +typedef enum lstream_buffering +{ + /* No buffering. */ + LSTREAM_UNBUFFERED, + /* Buffer until a '\n' character is reached. */ + LSTREAM_LINE_BUFFERED, + /* Buffer in standard-size (i.e. 512-byte) blocks. */ + LSTREAM_BLOCK_BUFFERED, + /* Buffer in blocks of a specified size. */ + LSTREAM_BLOCKN_BUFFERED, + /* Buffer until the stream is closed (only applies to write-only + streams). Only one call to the stream writer will be made, + and that is when the stream is closed. */ + LSTREAM_UNLIMITED +} Lstream_buffering; + +/* Methods defining how this stream works. Some may be undefined. */ + +/* We do not implement the seek/tell paradigm. I tried to do that, + but getting the semantics right in the presence of buffering is + extremely tricky and very error-prone and basically not worth it. + This is especially the case with complicated streams like + decoding streams -- the seek pointer in this case can't be a single + integer but has to be a whole complicated structure that records + all of the stream's state at the time. + + Rewind semantics are generally easy to implement, so we do provide + a rewind method. Even rewind() may not be available on a stream, + however -- e.g. on process output. */ + +typedef struct lstream_implementation +{ + CONST char *name; + int size; /* Number of additional bytes to be allocated with this + stream. Access this data using Lstream_data(). */ + /* Read some data from the stream's end and store it into DATA, which + can hold SIZE bytes. Return the number of bytes read. A return + value of 0 means no bytes can be read at this time. This may + be because of an EOF, or because there is a granularity greater + than one byte that the stream imposes on the returned data, and + SIZE is less than this granularity. (This will happen frequently + for streams that need to return whole characters, because + Lstream_read() calls the reader function repeatedly until it + has the number of bytes it wants or until 0 is returned.) + The lstream functions do not treat a 0 return as EOF or do + anything special; however, the calling function will interpret + any 0 it gets back as EOF. This will normally not happen unless + the caller calls Lstream_read() with a very small size. + + This function can be NULL if the stream is output-only. */ + /* The omniscient mly, blinded by the irresistable thrall of Common + Lisp, thinks that it is bogus that the types and implementations + of input and output streams are the same. */ + int (*reader) (Lstream *stream, unsigned char *data, int size); + /* Send some data to the stream's end. Data to be sent is in DATA + and is SIZE bytes. Return the number of bytes sent. This + function can send and return fewer bytes than is passed in; in + that case, the function will just be called again until there is + no data left or 0 is returned. A return value of 0 means that no + more data can be currently stored, but there is no error; the + data will be squirrelled away until the writer can accept + data. (This is useful, e.g., of you're dealing with a + non-blocking file descriptor and are getting EWOULDBLOCK errors.) + This function can be NULL if the stream is input-only. */ + int (*writer) (Lstream *stream, CONST unsigned char *data, int size); + /* Rewind the stream. If this is NULL, the stream is not seekable. */ + int (*rewinder) (Lstream *stream); + /* Indicate whether this stream is seekable -- i.e. it can be rewound. + This method is ignored if the stream does not have a rewind + method. If this method is not present, the result is determined + by whether a rewind method is present. */ + int (*seekable_p) (Lstream *stream); + /* Perform any additional operations necessary to flush the + data in this stream. */ + int (*flusher) (Lstream *stream); + /* Perform any additional operations necessary to close this + stream down. May be NULL. This function is called when + Lstream_close() is called or when the stream is garbage- + collected. When this function is called, all pending data + in the stream will already have been written out. */ + int (*closer) (Lstream *stream); + /* Mark this object for garbage collection. Same semantics as + a standard Lisp_Object marker. This function can be NULL. */ + Lisp_Object (*marker) (Lisp_Object lstream, void (*markfun) (Lisp_Object)); +} Lstream_implementation; + +#define DEFINE_LSTREAM_IMPLEMENTATION(name,c_name,size) \ + Lstream_implementation c_name[1] = \ + { { (name), (size) } } + +#define LSTREAM_FL_IS_OPEN 1 +#define LSTREAM_FL_READ 2 +#define LSTREAM_FL_WRITE 4 +#define LSTREAM_FL_NO_PARTIAL_CHARS 8 + +struct lstream +{ + struct lcrecord_header header; + CONST Lstream_implementation *imp; /* methods for this stream */ + Lstream_buffering buffering; /* type of buffering in use */ + int buffering_size; /* number of bytes buffered */ + + unsigned char *in_buffer; /* holds characters read from stream end */ + int in_buffer_size; /* allocated size of buffer */ + int in_buffer_current; /* number of characters in buffer */ + int in_buffer_ind; /* pointer to next character to take from buffer */ + + unsigned char *out_buffer; /* holds characters to write to stream end */ + int out_buffer_size; /* allocated size of buffer */ + int out_buffer_ind; /* pointer to next buffer spot to write a character */ + + /* The unget buffer is more or less a stack -- things get pushed + onto the end and read back from the end. Lstream_read() + basically reads backwards from the end to get stuff; Lstream_unread() + similarly has to push the data on backwards. */ + unsigned char *unget_buffer; /* holds characters pushed back onto input */ + int unget_buffer_size; /* allocated size of buffer */ + int unget_buffer_ind; /* pointer to next buffer spot to write a character */ + + int byte_count; + long flags; /* Align pointer for 64 bit machines (kny) */ + char data[1]; +}; + +#define LSTREAM_TYPE_P(lstr, type) \ + ((lstr)->imp == lstream_##type) + +#ifdef ERROR_CHECK_TYPECHECK +MAC_DECLARE_EXTERN (struct lstream *, MTlstream_data) +# define LSTREAM_TYPE_DATA(lstr, type) \ +MAC_BEGIN \ + MAC_DECLARE (struct lstream *, MTlstream_data, lstr) \ + assert (LSTREAM_TYPE_P (MTlstream_data, type)) \ + MAC_SEP \ + (struct type##_stream *) Lstream_data (MTlstream_data) \ +MAC_END +#else +# define LSTREAM_TYPE_DATA(lstr, type) \ + ((struct type##_stream *) Lstream_data (lstr)) +#endif + +/* Declare that lstream-type TYPE has method M; used in + initialization routines */ +#define LSTREAM_HAS_METHOD(type, m) \ + (lstream_##type->m = type##_##m) + + +Lstream *Lstream_new (CONST Lstream_implementation *imp, + CONST char *mode); +void Lstream_reopen (Lstream *lstr); +void Lstream_set_buffering (Lstream *lstr, Lstream_buffering buffering, + int buffering_size); +int Lstream_flush (Lstream *lstr); +int Lstream_flush_out (Lstream *lstr); +int Lstream_fputc (Lstream *lstr, int c); +int Lstream_fgetc (Lstream *lstr); +void Lstream_fungetc (Lstream *lstr, int c); +int Lstream_read (Lstream *lstr, void *data, int size); +int Lstream_write (Lstream *lstr, CONST void *data, int size); +void Lstream_unread (Lstream *lstr, CONST void *data, int size); +int Lstream_rewind (Lstream *lstr); +int Lstream_seekable_p (Lstream *lstr); +int Lstream_close (Lstream *lstr); +void Lstream_delete (Lstream *lstr); +void Lstream_set_character_mode (Lstream *str); + +/* Call the function equivalent if the out buffer is full. Otherwise, + add to the end of the out buffer and, if line buffering is called for + and the character marks the end of a line, write out the buffer. */ + +#define Lstream_putc(stream, c) \ + ((stream)->out_buffer_ind >= (stream)->out_buffer_size ? \ + Lstream_fputc (stream, c) : \ + ((stream)->out_buffer[(stream)->out_buffer_ind++] = \ + (unsigned char) (c), \ + (stream)->byte_count++, \ + (stream)->buffering == LSTREAM_LINE_BUFFERED && \ + (stream)->out_buffer[(stream)->out_buffer_ind - 1] == '\n' ? \ + Lstream_flush_out (stream) : 0)) + +/* Retrieve from unget buffer if there are any characters there; + else retrieve from in buffer if there's anything there; + else call the function equivalent */ +#define Lstream_getc(stream) \ + ((stream)->unget_buffer_ind > 0 ? \ + ((stream)->byte_count++, \ + (stream)->unget_buffer[--(stream)->unget_buffer_ind]) : \ + (stream)->in_buffer_ind < (stream)->in_buffer_current ? \ + ((stream)->byte_count++, \ + (stream)->in_buffer[(stream)->in_buffer_ind++]) : \ + Lstream_fgetc (stream)) + +/* Add to the end if it won't overflow buffer; otherwise call the + function equivalent */ +#define Lstream_ungetc(stream, c) \ + ((stream)->unget_buffer_ind >= (stream)->unget_buffer_size ? \ + Lstream_fungetc (stream, c) : \ + (void) ((stream)->byte_count--, \ + ((stream)->unget_buffer[(stream)->unget_buffer_ind++] = \ + (unsigned char) (c)))) + +#define Lstream_data(stream) ((void *) ((stream)->data)) +#define Lstream_byte_count(stream) ((stream)->byte_count) + + + +/************************************************************************/ +/* working with an Lstream as a stream of Emchars */ +/************************************************************************/ + +# define Lstream_get_emchar(stream) Lstream_getc (stream) +# define Lstream_put_emchar(stream, ch) Lstream_putc (stream, ch) +# define Lstream_unget_emchar(stream, ch) Lstream_ungetc (stream, ch) + + + +/************************************************************************/ +/* Lstream implementations */ +/************************************************************************/ + +/* Flags we can pass to the filedesc and stdio streams. */ + +/* If set, close the descriptor or FILE * when the stream is closed. */ +#define LSTR_CLOSING 1 + +/* If set, allow quitting out of the actual I/O. */ +#define LSTR_ALLOW_QUIT 2 + +/* If set and filedesc_stream_set_pty_flushing() has been called + on the stream, do not send more than pty_max_bytes on a single + line without flushing the data out using the eof_char. */ +#define LSTR_PTY_FLUSHING 4 + +/* If set, an EWOULDBLOCK error is not treated as an error but + simply causes the write function to return 0 as the number + of bytes written out. */ +#define LSTR_BLOCKED_OK 8 + +Lisp_Object make_stdio_input_stream (FILE *stream, int flags); +Lisp_Object make_stdio_output_stream (FILE *stream, int flags); +Lisp_Object make_filedesc_input_stream (int filedesc, int offset, int count, + int flags); +Lisp_Object make_filedesc_output_stream (int filedesc, int offset, int count, + int flags); +void filedesc_stream_set_pty_flushing (Lstream *stream, + int pty_max_bytes, + Bufbyte eof_char); +int filedesc_stream_was_blocked (Lstream *stream); +Lisp_Object make_lisp_string_input_stream (Lisp_Object string, + Bytecount offset, + Bytecount len); +Lisp_Object make_fixed_buffer_input_stream (CONST unsigned char *buf, + int size); +Lisp_Object make_fixed_buffer_output_stream (unsigned char *buf, + int size); +CONST unsigned char *fixed_buffer_input_stream_ptr (Lstream *stream); +unsigned char *fixed_buffer_output_stream_ptr (Lstream *stream); +Lisp_Object make_resizing_buffer_output_stream (void); +unsigned char *resizing_buffer_stream_ptr (Lstream *stream); +Lisp_Object make_dynarr_output_stream (unsigned_char_dynarr *dyn); +#define LSTR_SELECTIVE 1 +#define LSTR_IGNORE_ACCESSIBLE 2 +Lisp_Object make_lisp_buffer_input_stream (struct buffer *buf, Bufpos start, + Bufpos end, int flags); +Lisp_Object make_lisp_buffer_output_stream (struct buffer *buf, Bufpos pos, + int flags); +Bufpos lisp_buffer_stream_startpos (Lstream *stream); + +#endif /* _XEMACS_LSTREAM_H_ */