Update.
[glibc.git] / mach / devstream.c
blobb54dcff60d1f879e791bcc8060b4d8d018b20233
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.
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.
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.
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. */
21 #include <stdio.h>
22 #include <mach.h>
23 #include <device/device.h>
24 #include <errno.h>
25 #include <string.h>
27 static int
28 input (FILE *f)
30 kern_return_t err;
31 char *buffer;
32 size_t to_read;
33 mach_msg_type_number_t nread;
34 char c;
36 if (f->__buffer == NULL)
38 buffer = &c;
39 to_read = 1;
41 else
43 buffer = f->__buffer;
44 to_read = f->__bufsize;
47 f->__eof = 0;
49 nread = to_read;
50 err = device_read_inband ((device_t) f->__cookie, 0, f->__target,
51 to_read, buffer, &nread);
53 if (err)
55 f->__error = 1;
56 f->__bufp = f->__get_limit = f->__put_limit = f->__buffer;
57 errno = err;
58 return EOF;
61 /* Echo it back. */
62 err = device_write_inband ((device_t) f->__cookie, 0, f->__target,
63 buffer, nread, (int *) &to_read);
65 /* Translate LF to CR. */
67 char *p;
68 for (p = memchr (buffer, '\r', nread); p;
69 p = memchr (p + 1, '\r', (buffer + nread) - (p + 1)))
70 *p = '\n';
73 if (f->__buffer == NULL)
74 return (unsigned char) c;
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++;
83 #if 0
84 static void
85 output (FILE *f, int c)
87 inline void write_some (const char *p, size_t to_write)
89 kern_return_t err;
90 int wrote;
91 while (to_write > 0)
93 if (err = device_write ((device_t) f->__cookie, 0,
94 f->__target, (char *)p,
95 to_write, &wrote))
97 errno = err;
98 f->__error = 1;
99 break;
101 p += wrote;
102 to_write -= wrote;
103 f->__target += wrote;
107 if (f->__buffer != NULL)
109 if (f->__put_limit == f->__buffer)
111 /* Prime the stream for writing. */
112 f->__put_limit = f->__buffer + f->__bufsize;
113 f->__bufp = f->__buffer;
114 if (c != EOF)
116 *f->__bufp++ = (unsigned char) c;
117 c = EOF;
122 /* Write out the buffer. */
124 write_some (f->__buffer, f->__bufp - f->__buffer);
126 f->__bufp = f->__buffer;
129 if (c != EOF && !ferror (f))
131 if (f->__linebuf && (unsigned char) c == '\n')
133 static const char nl = '\n';
134 write_some (&nl, 1);
136 else
137 *f->__bufp++ = (unsigned char) c;
140 #endif
143 static void
144 output (FILE *f, int c)
146 void write_some (const char *p, size_t to_write)
148 kern_return_t err;
149 int wrote;
150 int thiswrite;
152 while (to_write > 0)
154 thiswrite = to_write;
155 if (thiswrite > IO_INBAND_MAX)
156 thiswrite = IO_INBAND_MAX;
158 if (err = device_write_inband ((device_t) f->__cookie, 0,
159 f->__target, p, thiswrite, &wrote))
161 errno = err;
162 f->__error = 1;
163 break;
165 p += wrote;
166 to_write -= wrote;
167 f->__target += wrote;
170 void write_crlf (void)
172 static const char crlf[] = "\r\n";
173 write_some (crlf, 2);
176 if (f->__buffer == NULL)
178 /* The stream is unbuffered. */
180 if (c == '\n')
181 write_crlf ();
182 else if (c != EOF)
184 char cc = (unsigned char) c;
185 write_some (&cc, 1);
188 return;
191 if (f->__put_limit == f->__buffer)
193 /* Prime the stream for writing. */
194 f->__put_limit = f->__buffer + f->__bufsize;
195 f->__bufp = f->__buffer;
196 if (c != EOF)
198 *f->__bufp++ = (unsigned char) c;
199 c = EOF;
204 /* Search for newlines (LFs) in the buffer. */
206 char *start = f->__buffer, *p = start;
208 while (!ferror (f) && (p = memchr (p, '\n', f->__bufp - start)))
210 /* Found one. Replace it with a CR and write out through that CR. */
212 *p = '\r';
213 write_some (start, p + 1 - start);
215 /* Change it back to an LF; the next iteration will write it out
216 first thing. Start the next searching iteration one char later. */
218 start = p;
219 *p++ = '\n';
222 /* Write the remainder of the buffer. */
224 if (!ferror (f))
225 write_some (start, f->__bufp - start);
228 f->__bufp = f->__buffer;
230 if (c != EOF && !ferror (f))
232 if (f->__linebuf && (unsigned char) c == '\n')
233 write_crlf ();
234 else
235 *f->__bufp++ = (unsigned char) c;
239 static int
240 dealloc_ref (void *cookie)
242 if (mach_port_deallocate (mach_task_self (), (mach_port_t) cookie))
244 errno = EINVAL;
245 return -1;
247 return 0;
251 FILE *
252 mach_open_devstream (mach_port_t dev, const char *mode)
254 FILE *stream;
256 if (mach_port_mod_refs (mach_task_self (), dev, MACH_PORT_RIGHT_SEND, 1))
258 errno = EINVAL;
259 return NULL;
262 stream = fopencookie ((void *) dev, mode, __default_io_functions);
263 if (stream == NULL)
265 mach_port_deallocate (mach_task_self (), dev);
266 return NULL;
269 stream->__room_funcs.__input = input;
270 stream->__room_funcs.__output = output;
271 stream->__io_funcs.__close = dealloc_ref;
272 stream->__io_funcs.__seek = NULL; /* Cannot seek. */
273 stream->__io_funcs.__fileno = NULL; /* No corresponding POSIX.1 fd. */
274 stream->__seen = 1;
276 return stream;