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 "config.h"
23#include "common.h"
24#include "NGStreamPipe.h"
25#include "NGFileStream.h"
26#include "NGBufferedStream.h"
27
28#if defined(WIN32)
29
30@implementation NGStreamPipe
31@end
32
33#else
34
35static const int NGInvalidUnixDescriptor = -1;
36
37@interface _NGConcretePipeFileHandle : NSFileHandle
38{
39@public
40  int *fd;
41}
42
43- (id)initWithDescriptor:(int *)_fd;
44
45@end
46
47@interface NGFileStream(PrivateMethods)
48- (id)__initWithDescriptor:(int)_fd mode:(NGStreamMode)_mode;
49@end
50
51@implementation NGStreamPipe
52
53+ (id)pipe {
54  return [[[self alloc] init] autorelease];
55}
56
57- (id)init {
58  if (pipe(self->fildes) == -1) {
59    NSLog (@"pipe() system call failed: %s", strerror (errno));
60    self = [self autorelease];
61    return nil;
62  }
63  return self;
64}
65
66- (void)gcFinalize {
67  [self close];
68}
69
70- (void)dealloc {
71  [self gcFinalize];
72  [self->fhIn  release];
73  [self->fhOut release];
74  [super dealloc];
75}
76
77- (NSFileHandle *)fileHandleForReading {
78  if (self->fhIn == nil) {
79    self->fhIn = [[_NGConcretePipeFileHandle alloc]
80                      initWithDescriptor:&(self->fildes[0])];
81  }
82  return self->fhIn;
83}
84- (NSFileHandle *)fileHandleForWriting {
85  if (self->fhOut == nil) {
86    self->fhOut = [[_NGConcretePipeFileHandle alloc]
87                       initWithDescriptor:&(self->fildes[1])];
88  }
89  return self->fhOut;
90}
91
92- (id<NGByteSequenceStream>)streamForReading {
93  return self;
94}
95- (id<NGOutputStream>)streamForWriting {
96  return self;
97}
98
99- (NSException *)lastException {
100  return nil;
101}
102
103/* NGInputStream */
104
105- (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
106  int readResult;
107
108  if (self->fildes[0] == NGInvalidUnixDescriptor) {
109    [NGStreamReadErrorException raiseWithStream:self
110                                reason:@"read end of pipe is closed"];
111  }
112
113  readResult = read(self->fildes[0], _buf, _len);
114
115  if (readResult == 0)
116    [NGEndOfStreamException raiseWithStream:self];
117  else if (readResult == -1)
118    [NGStreamReadErrorException raiseWithStream:self errorCode:errno];
119
120  return readResult;
121}
122- (BOOL)safeReadBytes:(void *)_buf count:(unsigned)_len {
123  return NGSafeReadBytesFromStream(self, _buf, _len);
124}
125
126/* marks */
127
128- (BOOL)mark {
129  NSLog(@"WARNING: called mark on a stream which doesn't support marking !");
130  return NO;
131}
132- (BOOL)rewind {
133  [NGStreamException raiseWithStream:self reason:@"marking not supported"];
134  return NO;
135}
136- (BOOL)markSupported {
137  return NO;
138}
139
140/* NGOutputStream */
141
142- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
143  int writeResult;
144
145  if (self->fildes[1] == NGInvalidUnixDescriptor) {
146    [NGStreamWriteErrorException raiseWithStream:self
147                                 reason:@"write end of pipe is closed"];
148  }
149
150  writeResult = write(self->fildes[1], _buf, _len);
151
152  if (writeResult == -1)
153    [NGStreamWriteErrorException raiseWithStream:self errorCode:errno];
154  return writeResult;
155}
156- (BOOL)safeWriteBytes:(const void *)_buf count:(unsigned)_len {
157  return NGSafeWriteBytesToStream(self, _buf, _len);
158}
159
160- (BOOL)flush {
161  return YES;
162}
163
164/* NGStream */
165
166- (BOOL)close {
167  if (self->fildes[0] != NGInvalidUnixDescriptor) close(self->fildes[0]);
168  if (self->fildes[1] != NGInvalidUnixDescriptor) close(self->fildes[1]);
169  return YES;
170}
171
172- (NGStreamMode)mode {
173  NGStreamMode mode = NGStreamMode_undefined;
174
175  if (self->fildes[0] != NGInvalidUnixDescriptor)
176    mode |= NGStreamMode_readOnly;
177  if (self->fildes[1] != NGInvalidUnixDescriptor)
178    mode |= NGStreamMode_writeOnly;
179
180  return mode;
181}
182
183// NGByteSequenceStream
184
185- (int)readByte {
186  return NGReadByteFromStream(self);
187}
188
189// Extensions
190
191- (BOOL)isOpen {
192  return (self->fildes[0] == NGInvalidUnixDescriptor) &&
193         (self->fildes[1] == NGInvalidUnixDescriptor) ? NO : YES;
194}
195
196/* description */
197
198- (NSString *)description {
199  return [NSString stringWithFormat:@"<0x%p[%@]: in=%i out=%i>",
200                     self, NSStringFromClass([self class]),
201                     self->fildes[0], self->fildes[1]];
202}
203
204@end /* NGStreamPipe */
205
206@implementation _NGConcretePipeFileHandle
207
208- (id)initWithDescriptor:(int *)_fd {
209  self->fd = _fd;
210  return self;
211}
212
213- (int)fileDescriptor {
214  return *(self->fd);
215}
216
217- (void)closeFile {
218  close(*(self->fd));
219  *(self->fd) = NGInvalidUnixDescriptor;
220}
221
222@end
223
224#endif /* WIN32 */
225