Update to 2.1.x development version
[kopensolaris-gnu/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 }