mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-26 10:11:03 +00:00
345 lines
8.3 KiB
Mathematica
345 lines
8.3 KiB
Mathematica
|
/* objc_streams - C-function interface to Objective-C streams
|
||
|
Copyright (C) 1993,1994, 1996 Free Software Foundation, Inc.
|
||
|
|
||
|
Written by: Adam Fedor <fedor@boulder.colorado.edu>
|
||
|
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 <stdio.h>
|
||
|
#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 <Streaming>)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 <SeekableStreaming>)s->stream_obj streamPosition];
|
||
|
[(id <SeekableStreaming>)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 <Streaming>)s->stream_obj writeByte: c];
|
||
|
else
|
||
|
return OSTREAM_EOF;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ostream_at_eos(ostream* s)
|
||
|
{
|
||
|
return [(id <Streaming>)s->stream_obj isAtEof];
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
ostream_flush(ostream *s)
|
||
|
{
|
||
|
int pos;
|
||
|
pos = [(id <Streaming>)s->stream_obj streamPosition];
|
||
|
[(id <Streaming>)s->stream_obj flushStream];
|
||
|
return [(id <Streaming>)s->stream_obj streamPosition] - pos;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ostream_seek(ostream *s, long offset, int mode)
|
||
|
{
|
||
|
if (!(s->flags & OSTREAM_CANSEEK))
|
||
|
return;
|
||
|
|
||
|
[(id <SeekableStreaming>)s->stream_obj setStreamPosition: offset
|
||
|
seekMode: (mode - OSTREAM_SEEK_FROM_START + STREAM_SEEK_FROM_START)];
|
||
|
}
|
||
|
|
||
|
long
|
||
|
ostream_tell(ostream *s)
|
||
|
{
|
||
|
return [(id <Streaming>)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 <Streaming>)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 <Streaming>)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 <Streaming>)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 <String> str = [String stringWithCString: format];
|
||
|
if (s->flags & OSTREAM_WRITEFLAG)
|
||
|
[(id <Streaming>)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 <String> str = [String stringWithCString: format];
|
||
|
if (s->flags & OSTREAM_READFLAG)
|
||
|
return [(id <Streaming>)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 <MemoryStreaming>)s->stream_obj streamBuffer]
|
||
|
length: [(id <MemoryStreaming>)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 <MemoryStreaming>)s->stream_obj streamBuffer];
|
||
|
if (len)
|
||
|
*len = [(id <MemoryStreaming>)s->stream_obj streamEofPosition];
|
||
|
if (maxlen)
|
||
|
*maxlen = [(id <MemoryStreaming>)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 <Streaming>)s->stream_obj close];
|
||
|
[(id)s->stream_obj release];
|
||
|
s->stream_obj = 0;
|
||
|
OBJC_FREE(s);
|
||
|
}
|
||
|
|
||
|
|