2 Copyright (C) 2000-2003 SKYRIX Software AG
4 This file is part of OGo
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #import <NGExtensions/NGCharBuffers.h>
25 #include "NGCTextStream.h"
26 #include "NGStreamExceptions.h"
27 #include "NGFileStream.h"
29 static NSString *NGNewLineString = @"\n";
31 @interface _NGCTextStreamLineEnumerator : NSEnumerator
33 NGCTextStream *stream;
35 - (id)initWithTextStream:(NGCTextStream *)_stream;
39 NGStreams_DECLARE id<NGExtendedTextInputStream> NGTextIn = nil;
40 NGStreams_DECLARE id<NGExtendedTextOutputStream> NGTextOut = nil;
41 NGStreams_DECLARE id<NGExtendedTextOutputStream> NGTextErr = nil;
43 @implementation NGCTextStream
46 return [super version] + 0 /* v2 */;
51 NGStreams_DECLARE void NGInitTextStdio(void) {
52 static BOOL isInitialized = NO;
58 NGTextIn = [(NGCTextStream *)[NGCTextStream alloc]
59 initWithSource:(id<NGStream>)NGIn];
60 NGTextOut = [(NGCTextStream *)[NGCTextStream alloc]
61 initWithSource:(id<NGStream>)NGOut];
62 NGTextErr = [(NGCTextStream *)[NGCTextStream alloc]
63 initWithSource:(id<NGStream>)NGErr];
67 + (void)_flushForExit:(NSNotification *)_notification {
68 [NGTextIn flush]; [NGTextIn release]; NGTextIn = nil;
69 [NGTextOut flush]; [NGTextOut release]; NGTextOut = nil;
70 [NGTextErr flush]; [NGTextErr release]; NGTextErr = nil;
73 static void _flushAtExit(void) {
74 [NGTextIn flush]; [NGTextIn release]; NGTextIn = nil;
75 [NGTextOut flush]; [NGTextOut release]; NGTextOut = nil;
76 [NGTextErr flush]; [NGTextErr release]; NGTextErr = nil;
80 BOOL isInitialized = NO;
82 NSAssert2([super version] == 2,
83 @"invalid superclass (%@) version %i !",
84 NSStringFromClass([self superclass]), [super version]);
93 + (id)textStreamWithInputSource:(id<NGInputStream>)_s {
94 if (_s == nil) return nil;
95 return [[(NGCTextStream *)[self alloc] initWithInputSource:_s] autorelease];
97 + (id)textStreamWithOutputSource:(id<NGOutputStream>)_s {
98 if (_s == nil) return nil;
99 return [[(NGCTextStream *)[self alloc] initWithOutputSource:_s] autorelease];
101 + (id)textStreamWithSource:(id<NGStream>)_stream {
102 if (_stream == nil) return nil;
103 return [[(NGCTextStream *)[self alloc] initWithSource:_stream] autorelease];
106 - (id)initWithSource:(id<NGStream>)_stream {
107 if (_stream == nil) {
111 if ((self = [super init])) {
112 self->source = [_stream retain];
115 //# warning no selector caching on MacOSX ...
117 /* check whether we are dealing with a proxy .. */
118 if ([source isKindOfClass:[NSObject class]]) {
119 self->readBytes = (NGIOReadMethodType)
120 [(NSObject *)source methodForSelector:@selector(readBytes:count:)];
121 self->writeBytes = (NGIOWriteMethodType)
122 [(NSObject *)source methodForSelector:@selector(writeBytes:count:)];
123 self->flushBuffer = (BOOL (*)(id,SEL))
124 [(NSObject *)source methodForSelector:@selector(flush)];
130 - (id)initWithInputSource:(id<NGInputStream>)_source {
131 return [self initWithSource:(id)_source];
133 - (id)initWithOutputSource:(id<NGOutputStream>)_source {
134 return [self initWithSource:(id)_source];
138 [self->source release];
139 self->readBytes = NULL;
140 self->writeBytes = NULL;
141 self->flushBuffer = NULL;
147 - (id<NGStream>)source {
150 - (int)fileDescriptor {
151 return [(id)[self source] fileDescriptor];
155 return [(id)[self source] isOpen];
161 return [self->source close];
164 /* NGTextInputStream */
166 - (unichar)readCharacter {
167 return [self readChar];
170 - (unsigned char)readChar {
175 res = readBytes(self->source, @selector(readBytes:count:),
176 &c, sizeof(unsigned char));
179 res = [self->source readBytes:&c count:sizeof(unsigned char)];
181 if (res == NGStreamError) {
182 [self setLastException:[self->source lastException]];
189 /* TODO: fix exception handling */
191 - (NSString *)readLineAsString {
192 NGCharBuffer8 buffer = NULL;
195 *(&buffer) = NGCharBuffer8_new(128);
202 res = self->readBytes(source, @selector(readBytes:count:),
203 &c, sizeof(unsigned char));
204 if (res != 1) [[self->source lastException] raise];
207 res = readBytes(source, @selector(readBytes:count:),
208 &c, sizeof(unsigned char));
209 if (res != 1) [[self->source lastException] raise];
212 if ((c != '\n') && (c != 0)) {
213 NSAssert1(c != 0, @"tried to add '0' character to buffer '%s' ..",
215 NGCharBuffer8_addChar(buffer, c);
218 while ((c != '\n') && (c != 0));
222 res = [self->source readBytes:&c count:sizeof(unsigned char)];
223 /* TODO: raises exception */
224 if (res != 1) [[self->source lastException] raise];
226 res = [self->source readBytes:&c count:sizeof(unsigned char)];
227 if (res != 1) [[self->source lastException] raise];
230 if ((c != '\n') && (c != 0))
231 NGCharBuffer8_addChar(buffer, c);
233 while ((c != '\n') && (c != 0));
237 if ([localException isKindOfClass:[NGEndOfStreamException class]]) {
238 if (buffer->length == 0) {
239 NGCharBuffer8_dealloc(buffer);
244 [localException raise];
248 return buffer ? NGCharBuffer8_makeStringAndDealloc(buffer) : nil;
251 - (NSEnumerator *)lineEnumerator {
252 return [[[_NGCTextStreamLineEnumerator alloc]
253 initWithTextStream:self]
257 // NGTextOutputStream
259 - (BOOL)writeCharacter:(unichar)_character {
263 if (_character > ((sizeof(unsigned char) * 256) - 1)) {
264 // character is not in range of maximum system encoding
265 [NSException raise:@"NGCTextStreamEncodingException"
267 @"called writeCharacter: with character code (0x%X) exceeding"
268 @" the maximum system character code (0x%X)",
269 _character, ((sizeof(unsigned char) * 256) - 1)];
275 res = writeBytes(self->source, @selector(writeBytes:count:),
276 &c, sizeof(unsigned char));
279 res = [self->source writeBytes:&c count:sizeof(unsigned char)];
281 if (res == NGStreamError) {
282 [self setLastException:[self->source lastException]];
289 - (BOOL)writeString:(NSString *)_string {
290 unsigned char *str, *buf;
293 if ((toGo = [_string cStringLength]) == 0)
296 buf = str = calloc(toGo + 1, sizeof(unsigned char));
297 [_string getCString:str]; str[toGo] = '\0';
303 writeCount = writeBytes
304 ? writeBytes(source, @selector(writeBytes:count:), str, toGo)
305 : [source writeBytes:str count:toGo];
307 if (writeCount == NGStreamError)
308 [[self->source lastException] raise];
315 if (buf) { free(buf); buf = NULL; };
316 [localException raise];
320 if (buf) { free(buf); buf = NULL; }
326 return flushBuffer(self->source, @selector(flush));
328 return [self->source flush];
331 - (BOOL)writeNewline {
332 if (![self writeString:NGNewLineString]) return NO;
333 if (![self flush]) return NO;
337 @end /* NGCTextStream */
339 @implementation _NGCTextStreamLineEnumerator
341 - (id)initWithTextStream:(NGCTextStream *)_stream {
342 self->stream = [_stream retain];
347 [self->stream release];
357 result = [self->stream readLineAsString];
360 if ([localException isKindOfClass:[NGEndOfStreamException class]])
363 [localException raise];
370 @end /* _NGCTextStreamLineEnumerator */