2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE 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 SOPE 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 SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include <NGStreams/NGCTextStream.h>
23 #include <NGStreams/NGStreamExceptions.h>
24 #include <NGStreams/NGFileStream.h>
25 #include <NGExtensions/NGCharBuffers.h>
28 static NSString *NGNewLineString = @"\n";
30 @interface _NGCTextStreamLineEnumerator : NSEnumerator
32 NGCTextStream *stream;
34 - (id)initWithTextStream:(NGCTextStream *)_stream;
38 NGStreams_DECLARE id<NGExtendedTextInputStream> NGTextIn = nil;
39 NGStreams_DECLARE id<NGExtendedTextOutputStream> NGTextOut = nil;
40 NGStreams_DECLARE id<NGExtendedTextOutputStream> NGTextErr = nil;
42 @implementation NGCTextStream
45 return [super version] + 0 /* v2 */;
50 NGStreams_DECLARE void NGInitTextStdio(void) {
51 static BOOL isInitialized = NO;
57 NGTextIn = [(NGCTextStream *)[NGCTextStream alloc]
58 initWithSource:(id<NGStream>)NGIn];
59 NGTextOut = [(NGCTextStream *)[NGCTextStream alloc]
60 initWithSource:(id<NGStream>)NGOut];
61 NGTextErr = [(NGCTextStream *)[NGCTextStream alloc]
62 initWithSource:(id<NGStream>)NGErr];
66 + (void)_flushForExit:(NSNotification *)_notification {
68 [NGTextIn release]; NGTextIn = nil;
69 [NGTextOut flush]; [NGTextOut release]; NGTextOut = nil;
70 [NGTextErr flush]; [NGTextErr release]; NGTextErr = nil;
73 static void _flushAtExit(void) {
75 [NGTextIn release]; NGTextIn = nil;
76 [NGTextOut flush]; [NGTextOut release]; NGTextOut = nil;
77 [NGTextErr flush]; [NGTextErr release]; NGTextErr = nil;
81 BOOL isInitialized = NO;
83 NSAssert2([super version] == 2,
84 @"invalid superclass (%@) version %i !",
85 NSStringFromClass([self superclass]), [super version]);
94 + (id)textStreamWithInputSource:(id<NGInputStream>)_s {
95 if (_s == nil) return nil;
96 return [[(NGCTextStream *)[self alloc] initWithInputSource:_s] autorelease];
98 + (id)textStreamWithOutputSource:(id<NGOutputStream>)_s {
99 if (_s == nil) return nil;
100 return [[(NGCTextStream *)[self alloc] initWithOutputSource:_s] autorelease];
102 + (id)textStreamWithSource:(id<NGStream>)_stream {
103 if (_stream == nil) return nil;
104 return [[(NGCTextStream *)[self alloc] initWithSource:_stream] autorelease];
107 - (id)initWithSource:(id<NGStream>)_stream {
108 if (_stream == nil) {
112 if ((self = [super init])) {
113 self->source = [_stream retain];
116 //# warning no selector caching on MacOSX ...
118 /* check whether we are dealing with a proxy .. */
119 if ([source isKindOfClass:[NSObject class]]) {
120 self->readBytes = (NGIOReadMethodType)
121 [(NSObject *)source methodForSelector:@selector(readBytes:count:)];
122 self->writeBytes = (NGIOWriteMethodType)
123 [(NSObject *)source methodForSelector:@selector(writeBytes:count:)];
124 self->flushBuffer = (BOOL (*)(id,SEL))
125 [(NSObject *)source methodForSelector:@selector(flush)];
131 - (id)initWithInputSource:(id<NGInputStream>)_source {
132 return [self initWithSource:(id)_source];
134 - (id)initWithOutputSource:(id<NGOutputStream>)_source {
135 return [self initWithSource:(id)_source];
139 [self->source release];
140 self->readBytes = NULL;
141 self->writeBytes = NULL;
142 self->flushBuffer = NULL;
148 - (id<NGStream>)source {
151 - (int)fileDescriptor {
152 return [(id)[self source] fileDescriptor];
156 return [(id)[self source] isOpen];
162 return [self->source close];
165 /* NGTextInputStream */
167 - (unichar)readCharacter {
168 return [self readChar];
171 - (unsigned char)readChar {
176 res = readBytes(self->source, @selector(readBytes:count:),
177 &c, sizeof(unsigned char));
180 res = [self->source readBytes:&c count:sizeof(unsigned char)];
182 if (res == NGStreamError) {
183 [self setLastException:[self->source lastException]];
190 /* TODO: fix exception handling */
192 - (NSString *)readLineAsString {
193 NGCharBuffer8 buffer = NULL;
196 *(&buffer) = NGCharBuffer8_new(128);
203 res = self->readBytes(source, @selector(readBytes:count:),
204 &c, sizeof(unsigned char));
205 if (res != 1) [[self->source lastException] raise];
208 res = readBytes(source, @selector(readBytes:count:),
209 &c, sizeof(unsigned char));
210 if (res != 1) [[self->source lastException] raise];
213 if ((c != '\n') && (c != 0)) {
214 NSAssert1(c != 0, @"tried to add '0' character to buffer '%s' ..",
216 NGCharBuffer8_addChar(buffer, c);
219 while ((c != '\n') && (c != 0));
223 res = [self->source readBytes:&c count:sizeof(unsigned char)];
224 /* TODO: raises exception */
225 if (res != 1) [[self->source lastException] raise];
227 res = [self->source readBytes:&c count:sizeof(unsigned char)];
228 if (res != 1) [[self->source lastException] raise];
231 if ((c != '\n') && (c != 0))
232 NGCharBuffer8_addChar(buffer, c);
234 while ((c != '\n') && (c != 0));
238 if ([localException isKindOfClass:[NGEndOfStreamException class]]) {
239 if (buffer->length == 0) {
240 NGCharBuffer8_dealloc(buffer);
245 [localException raise];
249 return buffer ? NGCharBuffer8_makeStringAndDealloc(buffer) : nil;
252 - (NSEnumerator *)lineEnumerator {
253 return [[[_NGCTextStreamLineEnumerator alloc]
254 initWithTextStream:self]
258 // NGTextOutputStream
260 - (BOOL)writeCharacter:(unichar)_character {
264 if (_character > ((sizeof(unsigned char) * 256) - 1)) {
265 // character is not in range of maximum system encoding
266 [NSException raise:@"NGCTextStreamEncodingException"
268 @"called writeCharacter: with character code (0x%X) exceeding"
269 @" the maximum system character code (0x%X)",
270 _character, ((sizeof(unsigned char) * 256) - 1)];
276 res = writeBytes(self->source, @selector(writeBytes:count:),
277 &c, sizeof(unsigned char));
280 res = [self->source writeBytes:&c count:sizeof(unsigned char)];
282 if (res == NGStreamError) {
283 [self setLastException:[self->source lastException]];
290 - (BOOL)writeString:(NSString *)_string {
291 unsigned char *str, *buf;
294 if ((toGo = [_string cStringLength]) == 0)
297 buf = str = calloc(toGo + 1, sizeof(unsigned char));
298 [_string getCString:(char *)str]; str[toGo] = '\0';
304 writeCount = writeBytes
305 ? writeBytes(source, @selector(writeBytes:count:), str, toGo)
306 : [source writeBytes:str count:toGo];
308 if (writeCount == NGStreamError)
309 [[self->source lastException] raise];
316 if (buf) { free(buf); buf = NULL; };
317 [localException raise];
321 if (buf) { free(buf); buf = NULL; }
327 return flushBuffer(self->source, @selector(flush));
329 return [self->source flush];
332 - (BOOL)writeNewline {
333 if (![self writeString:NGNewLineString]) return NO;
334 if (![self flush]) return NO;
338 @end /* NGCTextStream */
340 @implementation _NGCTextStreamLineEnumerator
342 - (id)initWithTextStream:(NGCTextStream *)_stream {
343 self->stream = [_stream retain];
348 [self->stream release];
358 result = [self->stream readLineAsString];
361 if ([localException isKindOfClass:[NGEndOfStreamException class]])
364 [localException raise];
371 @end /* _NGCTextStreamLineEnumerator */