diff --git a/Source/ostream.h b/Source/ostream.h new file mode 100644 index 000000000..49f3117ee --- /dev/null +++ b/Source/ostream.h @@ -0,0 +1,82 @@ +/* objc_streams - C-function interface to Objective-C streams + Copyright (C) 1993,1994, 1996 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Jun 1996 + + This file is part of the GNUstep Base Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __objc_stream_h_GNUSTEP_BASE_INCLUDE +#define __objc_stream_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +typedef struct _ostream { + void* stream_obj; + int flags; +} ostream; + +/* Access modes */ +#define OSTREAM_READONLY 1 /* read on stream only */ +#define OSTREAM_WRITEONLY 2 /* write on stream only */ +#define OSTREAM_READWRITE 4 /* do read & write */ +#define OSTREAM_APPEND 8 /* append (write at end of file) */ + +/* Seek modes */ +#define OSTREAM_SEEK_FROM_START 0 +#define OSTREAM_SEEK_FROM_CURRENT 1 +#define OSTREAM_SEEK_FROM_END 2 + +/* Private flags */ +#define OSTREAM_READFLAG 1 /* stream is for reading */ +#define OSTREAM_WRITEFLAG (1 << 1) /* stream is for writing */ +#define OSTREAM_ISBUFFER (1 << 2) +#define OSTREAM_USER_OWNS_BUF (1 << 3) +#define OSTREAM_CANSEEK (1 << 4) + +extern int ostream_getc(ostream* s); +extern void ostream_ungetc(ostream* s); +extern int ostream_putc(ostream* s, int c); +extern BOOL ostream_at_eos(ostream* s); +extern char* ostream_gets(ostream* s, char* buf, int count); + +extern int ostream_flush(ostream *s); +extern void ostream_seek(ostream *s, long offset, int mode); +extern long ostream_tell(ostream *s); +extern int ostream_read(ostream* s, void* buf, int count); +extern int ostream_write(ostream* s, const void* buf, int count); +extern void ostream_printf(ostream *s, const char *format, ...); +extern void ostream_vprintf(ostream *s, const char *format, va_list argList); +extern int ostream_scanf(ostream *s, const char *format, ...); +extern int ostream_vscanf(ostream *s, const char *format, va_list argList); + +extern ostream *ostream_open_descriptor(int fd, int mode); +extern ostream *ostream_open_memory(const char *addr, int size, int mode); +extern ostream *ostream_map_file(const char *name, int mode); +extern int ostream_save_to_file(ostream *s, const char *name); +extern void ostream_get_memory_buffer(ostream *s, char **addr, + int *len, int *maxlen); +extern void ostream_close_memory(ostream *s, int option); +extern void ostream_close(ostream *s); + +#define OSTREAM_FREEBUFFER 0 +#define OSTREAM_TRUNCATEBUFFER 1 +#define OSTREAM_SAVEBUFFER 2 + +#endif /* __objc_stream_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Source/ostream.m b/Source/ostream.m new file mode 100644 index 000000000..5a94c2c92 --- /dev/null +++ b/Source/ostream.m @@ -0,0 +1,344 @@ +/* objc_streams - C-function interface to Objective-C streams + Copyright (C) 1993,1994, 1996 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Aug 1996 + + This file is part of the GNUstep Base Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include +#include "gnustep/base/objc_streams.h" +#include "gnustep/base/MemoryStream.h" +#include "gnustep/base/StdioStream.h" +#include "gnustep/base/String.h" + +#define OSTREAM_EOF EOF + +/* Handle a stream error - FIXME: not sure if this should throw an exception + or what... */ +static void +_ostream_error(const char* message) +{ + fprintf(stderr, "ostream error: %s\n", message); +} + +int +ostream_getc(ostream* s) +{ + char c = 0; + if (s->flags & OSTREAM_READFLAG) + [(id )s->stream_obj readByte: &c]; + else + c = OSTREAM_EOF; + return c; +} + +void +ostream_ungetc(ostream* s) +{ + if ((s->flags & OSTREAM_READFLAG) && (s->flags & OSTREAM_CANSEEK)) + { + long pos = [(id )s->stream_obj streamPosition]; + [(id )s->stream_obj setStreamPosition: pos-1]; + } + else + _ostream_error("Tried to unget on non-readable/non-seekable stream"); +} + +int +ostream_putc(ostream* s, int c) +{ + if (s->flags & OSTREAM_WRITEFLAG) + return [(id )s->stream_obj writeByte: c]; + else + return OSTREAM_EOF; +} + +BOOL +ostream_at_eos(ostream* s) +{ + return [(id )s->stream_obj isAtEof]; +} + + +int +ostream_flush(ostream *s) +{ + int pos; + pos = [(id )s->stream_obj streamPosition]; + [(id )s->stream_obj flushStream]; + return [(id )s->stream_obj streamPosition] - pos; +} + +void +ostream_seek(ostream *s, long offset, int mode) +{ + if (!(s->flags & OSTREAM_CANSEEK)) + return; + + [(id )s->stream_obj setStreamPosition: offset + seekMode: (mode - OSTREAM_SEEK_FROM_START + STREAM_SEEK_FROM_START)]; +} + +long +ostream_tell(ostream *s) +{ + return [(id )s->stream_obj streamPosition]; +} + +int +ostream_read(ostream* s, void* buf, int count) +{ + assert(buf); /* xxxFIXME: should be an exception ? */ + if (s->flags & OSTREAM_READFLAG) + return [(id )s->stream_obj readBytes: buf length: count]; + return OSTREAM_EOF; +} + +char* ostream_gets(ostream* s, char* buf, int count) +{ + char c; + int i = 0; + + assert(buf); /* xxxFIXME: should be an exception ? */ + if (!(s->flags & OSTREAM_READFLAG)) + return NULL; + while (i < count-1) { + [(id )s->stream_obj readByte: &c]; + if (c == -1) + break; + buf[i++] = c; + if (c == '\n') + break; + } + buf[i++] = 0; + + return i > 1 ? buf : NULL; +} + +int +ostream_write(ostream* s, const void* buf, int count) +{ + assert(buf); /* xxxFIXME: should be an exception ? */ + if (s->flags & OSTREAM_WRITEFLAG) + return [(id )s->stream_obj writeBytes: buf length: count]; + return OSTREAM_EOF; +} + +void +ostream_printf(ostream *s, const char *format, ...) +{ + va_list args; + va_start(args, format); + ostream_vprintf(s, format, args); + va_end(args); +} + +void +ostream_vprintf(ostream *s, const char *format, va_list argList) +{ + id str = [String stringWithCString: format]; + if (s->flags & OSTREAM_WRITEFLAG) + [(id )s->stream_obj writeFormat: str arguments: argList]; + else + _ostream_error("Tried to write to non-writable stream"); +} + +int +ostream_scanf(ostream *s, const char *format, ...) +{ + int ret; + va_list args; + va_start(args, format); + ret = ostream_vscanf(s, format, args); + va_end(args); + return ret; +} + +int +ostream_vscanf(ostream *s, const char *format, va_list argList) +{ + id str = [String stringWithCString: format]; + if (s->flags & OSTREAM_READFLAG) + return [(id )s->stream_obj readFormat: str + arguments: argList]; + _ostream_error("Tried to read from non-readable stream"); + return OSTREAM_EOF; +} + +static ostream * +_ostream_new_stream_struct(int mode, char** cmode) +{ + char* fmode; + ostream* stream; + OBJC_MALLOC(stream, ostream, 1); + stream->flags = 0; + switch (mode) + { + case OSTREAM_READONLY: + fmode = "r"; + stream->flags |= OSTREAM_READFLAG; + break; + case OSTREAM_WRITEONLY: + fmode = "w"; + stream->flags |= OSTREAM_WRITEFLAG; + break; + case OSTREAM_READWRITE: + fmode = "w+"; + stream->flags |= OSTREAM_READFLAG; + stream->flags |= OSTREAM_WRITEFLAG; + break; + case OSTREAM_APPEND: + fmode = "w"; + stream->flags |= OSTREAM_WRITEFLAG; + break; + default: + fmode = "r"; + break; + } + if (cmode) + *cmode = fmode; + return stream; +} + +ostream * +ostream_open_descriptor(int fd, int mode) +{ + char* fmode; + ostream* stream = _ostream_new_stream_struct(mode, &fmode); + stream->stream_obj = [[StdioStream alloc] initWithFileDescriptor: fd + fmode: fmode]; + /* FIXME: Just assuming we can seek FILE streams */ + stream->flags |= OSTREAM_CANSEEK; + return stream; +} + +ostream * +ostream_open_memory(const char *addr, int size, int mode) +{ + char* fmode; + ostream* stream = _ostream_new_stream_struct(mode, &fmode); + if (addr) + { + stream->stream_obj = [[MemoryStream alloc] _initOnMallocBuffer: addr + size: size + eofPosition: size + prefix: 0 + position: 0]; + if (!stream->stream_obj) + return NULL; + + /* xxxFIXME: Now way of telling MemoryStream that we own this buffer + so just ad an extra retain so we never free the stream */ + [(id)stream->stream_obj retain]; + } + else + { + stream->stream_obj = [[MemoryStream alloc] initWithCapacity: size + prefix: 0]; + } + if (mode == OSTREAM_APPEND) + ostream_seek(stream, 0, OSTREAM_SEEK_FROM_END); + stream->flags |= OSTREAM_CANSEEK; + stream->flags |= OSTREAM_ISBUFFER; + return stream; +} + +ostream * +ostream_map_file(const char *name, int mode) +{ + char* fmode; + String* str = [String stringWithCString: name]; + ostream* stream = _ostream_new_stream_struct(mode, &fmode); + stream->stream_obj = [[StdioStream alloc] initWithFilename: str + fmode: fmode]; + if (!stream->stream_obj) + return NULL; + + /* xxxFIXME: Just assuming that we can seek: */ + stream->flags |= OSTREAM_CANSEEK; + if (mode == OSTREAM_APPEND) + ostream_seek(stream, 0, OSTREAM_SEEK_FROM_END); + return stream; +} + +/* Would like to use NSData for this, but it's to hard to pass the buffer + and tell NSData not to free it */ +int +ostream_save_to_file(ostream *s, const char *name) +{ + StdioStream* output; + if (!(s->flags & OSTREAM_ISBUFFER)) + { + _ostream_error("Tried to save non-memory stream"); + return -1; + } + + output = [[StdioStream alloc] initWithFilename: + [NSString stringWithCString: name] fmode: "w"]; + if (!output) + { + _ostream_error("Unable to open save file"); + return -1; + } + + [output writeBytes: [(id )s->stream_obj streamBuffer] + length: [(id )s->stream_obj streamEofPosition]]; + [output release]; + return 0; +} + +void +ostream_get_memory_buffer(ostream *s, char **addr, int *len, int *maxlen) +{ + if (!(s->flags & OSTREAM_ISBUFFER)) + { + if (addr) + *addr = 0; + return; + } + + if (addr) + *addr = [(id )s->stream_obj streamBuffer]; + if (len) + *len = [(id )s->stream_obj streamEofPosition]; + if (maxlen) + *maxlen = [(id )s->stream_obj streamBufferCapacity]; +} + +void +ostream_close_memory(ostream *s, int option) +{ + if (s->flags & OSTREAM_ISBUFFER) + { + /* Here's the extra release that allows MemoryStream to dealloc itself */ + if (option == OSTREAM_FREEBUFFER) + [(id)s->stream_obj release]; + } + ostream_close(s); +} + +void +ostream_close(ostream *s) +{ + [(id )s->stream_obj close]; + [(id)s->stream_obj release]; + s->stream_obj = 0; + OBJC_FREE(s); +} + +