]> git.ipfire.org Git - thirdparty/glibc.git/blob - mach/devstream.c
Update to 2.1.x development version
[thirdparty/glibc.git] / mach / devstream.c
1 /* stdio on a Mach device port.
2 Translates \n to \r\n on output, echos and translates \r to \n on input.
3 Copyright (C) 1992, 1993, 1994, 1996, 1997 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 #include <stdio.h>
22 #include <mach.h>
23 #include <device/device.h>
24 #include <errno.h>
25 #include <string.h>
26
27 static int
28 input (FILE *f)
29 {
30 kern_return_t err;
31 char *buffer;
32 size_t to_read;
33 mach_msg_type_number_t nread;
34 char c;
35
36 if (f->__buffer == NULL)
37 {
38 buffer = &c;
39 to_read = 1;
40 }
41 else
42 {
43 buffer = f->__buffer;
44 to_read = f->__bufsize;
45 }
46
47 f->__eof = 0;
48
49 nread = to_read;
50 err = device_read_inband ((device_t) f->__cookie, 0, f->__target,
51 to_read, buffer, &nread);
52
53 if (err)
54 {
55 f->__error = 1;
56 f->__bufp = f->__get_limit = f->__put_limit = f->__buffer;
57 errno = err;
58 return EOF;
59 }
60
61 /* Echo it back. */
62 err = device_write_inband ((device_t) f->__cookie, 0, f->__target,
63 buffer, nread, (int *) &to_read);
64
65 /* Translate LF to CR. */
66 {
67 char *p;
68 for (p = memchr (buffer, '\r', nread); p;
69 p = memchr (p + 1, '\r', (buffer + nread) - (p + 1)))
70 *p = '\n';
71 }
72
73 if (f->__buffer == NULL)
74 return (unsigned char) c;
75
76 f->__get_limit = f->__buffer + nread;
77 f->__bufp = f->__buffer;
78 f->__put_limit = f->__buffer + (f->__mode.__write ? f->__bufsize : 0);
79 return (unsigned char) *f->__bufp++;
80 }
81
82
83 #if 0
84 static void
85 output (FILE *f, int c)
86 {
87 inline void write_some (const char *p, size_t to_write)
88 {
89 kern_return_t err;
90 int wrote;
91 while (to_write > 0)
92 {
93 if (err = device_write ((device_t) f->__cookie, 0,
94 f->__target, (char *)p,
95 to_write, &wrote))
96 {
97 errno = err;
98 f->__error = 1;
99 break;
100 }
101 p += wrote;
102 to_write -= wrote;
103 f->__target += wrote;
104 }
105 }
106
107 if (f->__buffer != NULL)
108 {
109 if (f->__put_limit == f->__buffer)
110 {
111 /* Prime the stream for writing. */
112 f->__put_limit = f->__buffer + f->__bufsize;
113 f->__bufp = f->__buffer;
114 if (c != EOF)
115 {
116 *f->__bufp++ = (unsigned char) c;
117 c = EOF;
118 }
119 }
120
121
122 /* Write out the buffer. */
123
124 write_some (f->__buffer, f->__bufp - f->__buffer);
125
126 f->__bufp = f->__buffer;
127 }
128
129 if (c != EOF && !ferror (f))
130 {
131 if (f->__linebuf && (unsigned char) c == '\n')
132 {
133 static const char nl = '\n';
134 write_some (&nl, 1);
135 }
136 else
137 *f->__bufp++ = (unsigned char) c;
138 }
139 }
140 #endif
141
142
143 static void
144 output (FILE *f, int c)
145 {
146 void write_some (const char *p, size_t to_write)
147 {
148 kern_return_t err;
149 int wrote;
150 while (to_write > 0)
151 {
152 if (err = device_write_inband ((device_t) f->__cookie, 0,
153 f->__target, p, to_write, &wrote))
154 {
155 errno = err;
156 f->__error = 1;
157 break;
158 }
159 p += wrote;
160 to_write -= wrote;
161 f->__target += wrote;
162 }
163 }
164 void write_crlf (void)
165 {
166 static const char crlf[] = "\r\n";
167 write_some (crlf, 2);
168 }
169
170 if (f->__buffer == NULL)
171 {
172 /* The stream is unbuffered. */
173
174 if (c == '\n')
175 write_crlf ();
176 else if (c != EOF)
177 {
178 char cc = (unsigned char) c;
179 write_some (&cc, 1);
180 }
181
182 return;
183 }
184
185 if (f->__put_limit == f->__buffer)
186 {
187 /* Prime the stream for writing. */
188 f->__put_limit = f->__buffer + f->__bufsize;
189 f->__bufp = f->__buffer;
190 if (c != EOF)
191 {
192 *f->__bufp++ = (unsigned char) c;
193 c = EOF;
194 }
195 }
196
197 {
198 /* Search for newlines (LFs) in the buffer. */
199
200 char *start = f->__buffer, *p = start;
201
202 while (!ferror (f) && (p = memchr (p, '\n', f->__bufp - start)))
203 {
204 /* Found one. Replace it with a CR and write out through that CR. */
205
206 *p = '\r';
207 write_some (start, p + 1 - start);
208
209 /* Change it back to an LF; the next iteration will write it out
210 first thing. Start the next searching iteration one char later. */
211
212 start = p;
213 *p++ = '\n';
214 }
215
216 /* Write the remainder of the buffer. */
217
218 if (!ferror (f))
219 write_some (start, f->__bufp - start);
220 }
221
222 f->__bufp = f->__buffer;
223
224 if (c != EOF && !ferror (f))
225 {
226 if (f->__linebuf && (unsigned char) c == '\n')
227 write_crlf ();
228 else
229 *f->__bufp++ = (unsigned char) c;
230 }
231 }
232
233 static int
234 dealloc_ref (void *cookie)
235 {
236 if (mach_port_deallocate (mach_task_self (), (mach_port_t) cookie))
237 {
238 errno = EINVAL;
239 return -1;
240 }
241 return 0;
242 }
243
244
245 FILE *
246 mach_open_devstream (mach_port_t dev, const char *mode)
247 {
248 FILE *stream;
249
250 if (mach_port_mod_refs (mach_task_self (), dev, MACH_PORT_RIGHT_SEND, 1))
251 {
252 errno = EINVAL;
253 return NULL;
254 }
255
256 stream = fopencookie ((void *) dev, mode, __default_io_functions);
257 if (stream == NULL)
258 {
259 mach_port_deallocate (mach_task_self (), dev);
260 return NULL;
261 }
262
263 stream->__room_funcs.__input = input;
264 stream->__room_funcs.__output = output;
265 stream->__io_funcs.__close = dealloc_ref;
266 stream->__io_funcs.__seek = NULL; /* Cannot seek. */
267 stream->__io_funcs.__fileno = NULL; /* No corresponding POSIX.1 fd. */
268 stream->__seen = 1;
269
270 return stream;
271 }