1/*
2  Copyright (C) 2000-2005 SKYRIX Software AG
3
4  This file is part of SOPE.
5
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
9  later version.
10
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.
15
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
19  02111-1307, USA.
20*/
21
22#include "NGTextStream.h"
23#include "common.h"
24
25@implementation NGTextStream
26
27- (void)dealloc {
28  [self->lastException release];
29  [super dealloc];
30}
31
32/* NGTextInputStream */
33
34- (NSException *)lastException {
35  return nil;
36}
37- (void)setLastException:(NSException *)_exception {
38  ASSIGN(self->lastException, _exception);
39}
40- (void)resetLastException {
41  [self->lastException release];
42  self->lastException = nil;
43}
44
45- (unichar)readCharacter {
46  [self subclassResponsibility:_cmd];
47  return 0;
48}
49
50- (BOOL)isOpen {
51  return YES;
52}
53
54/* NGExtendedTextInputStream */
55
56- (NSString *)readLineAsString {
57  NSMutableString *str;
58  unichar c;
59
60  *(&str) = (id)[NSMutableString string];
61
62  NS_DURING {
63    while ((c = [self readCharacter]) != '\n')
64      [str appendString:[NSString stringWithCharacters:&c length:1]];
65  }
66  NS_HANDLER {
67    if ([localException isKindOfClass:[NGEndOfStreamException class]]) {
68      if ([str length] == 0) str = nil;
69    }
70    else
71      [localException raise];
72  }
73  NS_ENDHANDLER;
74
75  return str;
76}
77
78- (unsigned)readCharacters:(unichar *)_chars count:(unsigned)_count {
79  /*
80    Read up to _count characters, but one at the minimum.
81  */
82  volatile unsigned pos;
83
84  NS_DURING {
85    for (pos = 0; pos < _count; pos++)
86      _chars[pos] = [self readCharacter];
87  }
88  NS_HANDLER {
89    if ([localException isKindOfClass:[NGEndOfStreamException class]]) {
90      if (pos == 0)
91        [localException raise];
92    }
93    else
94      [localException raise];
95  }
96  NS_ENDHANDLER;
97
98  NSAssert1(pos > 0, @"invalid character count to be returned: %i", pos);
99  return pos;
100}
101
102- (BOOL)safeReadCharacters:(unichar *)_chars count:(unsigned)_count {
103  volatile unsigned pos;
104
105  for (pos = 0; pos < _count; pos++)
106    _chars[pos] = [self readCharacter];
107
108  return YES;
109}
110
111/* NGTextOutputStream */
112
113- (BOOL)writeCharacter:(unichar)_character {
114  [self subclassResponsibility:_cmd];
115  return NO;
116}
117
118- (BOOL)writeString:(NSString *)_string {
119  unsigned length = [_string length], cnt = 0;
120  unichar  buffer[length];
121  void     (*writeChar)(id, SEL, unichar);
122
123  writeChar = (void (*)(id,SEL,unichar))
124    [self methodForSelector:@selector(writeCharacter:)];
125
126  [_string getCharacters:buffer];
127  for (cnt = 0; cnt < length; cnt++)
128    writeChar(self, @selector(writeCharacter:), buffer[cnt]);
129
130  return YES;
131}
132
133- (BOOL)flush {
134  return YES;
135}
136
137/* NGExtendedTextOutputStream */
138
139- (BOOL)writeFormat:(NSString *)_format arguments:(va_list)_ap {
140  NSString *tmp;
141
142  tmp = [[[NSString alloc] initWithFormat:_format arguments:_ap] autorelease];
143  [self writeString:tmp];
144  return YES;
145}
146- (BOOL)writeFormat:(NSString *)_format, ... {
147  va_list ap;
148  BOOL res = NO;
149
150  va_start(ap, _format);
151
152#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
153  /* As soon as we add an exception handler on Leopard compilation
154   * breaks. Probably some GCC bug.
155   */
156  res = [self writeFormat:_format arguments:ap];
157#else
158  NS_DURING {
159    res = [self writeFormat:_format arguments:ap];
160  }
161  NS_HANDLER {
162    va_end(ap);
163    [localException raise];
164  }
165  NS_ENDHANDLER;
166#endif
167
168  va_end(ap);
169
170  return res;
171}
172
173- (BOOL)writeNewline {
174  if (![self writeString:@"\n"]) return NO;
175  return [self flush];
176}
177
178- (unsigned)writeCharacters:(const unichar *)_chars count:(unsigned)_count {
179  /*
180    Write up to _count characters, but one at the minimum.
181  */
182  volatile unsigned pos;
183
184  NS_DURING {
185    for (pos = 0; pos < _count; pos++)
186      [self writeCharacter:_chars[pos]];
187  }
188  NS_HANDLER {
189    if ([localException isKindOfClass:[NGEndOfStreamException class]]) {
190      if (pos == 0)
191        [localException raise];
192    }
193    else
194      [localException raise];
195  }
196  NS_ENDHANDLER;
197
198  NSAssert1(pos > 0, @"invalid character count to be returned: %i", pos);
199  return pos;
200}
201
202- (BOOL)safeWriteCharacters:(const unichar *)_chars count:(unsigned)_count {
203  unsigned pos;
204
205  for (pos = 0; pos < _count; pos++) {
206    if (![self writeCharacter:_chars[pos]])
207      return NO;
208  }
209
210  return YES;
211}
212
213@end /* NGTextStream */
214