Add Euro character.
[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       int thiswrite;
151
152       while (to_write > 0)
153         {
154           thiswrite = to_write;
155           if (thiswrite > IO_INBAND_MAX)
156             thiswrite = IO_INBAND_MAX;
157
158           if (err = device_write_inband ((device_t) f->__cookie, 0,
159                                          f->__target, p, thiswrite, &wrote))
160             {
161               errno = err;
162               f->__error = 1;
163               break;
164             }
165           p += wrote;
166           to_write -= wrote;
167           f->__target += wrote;
168         }
169     }
170   void write_crlf (void)
171     {
172       static const char crlf[] = "\r\n";
173       write_some (crlf, 2);
174     }
175
176   if (f->__buffer == NULL)
177     {
178       /* The stream is unbuffered.  */
179
180       if (c == '\n')
181         write_crlf ();
182       else if (c != EOF)
183         {
184           char cc = (unsigned char) c;
185           write_some (&cc, 1);
186         }
187
188       return;
189     }
190
191   if (f->__put_limit == f->__buffer)
192     {
193       /* Prime the stream for writing.  */
194       f->__put_limit = f->__buffer + f->__bufsize;
195       f->__bufp = f->__buffer;
196       if (c != EOF)
197         {
198           *f->__bufp++ = (unsigned char) c;
199           c = EOF;
200         }
201     }
202
203   {
204     /* Search for newlines (LFs) in the buffer.  */
205
206     char *start = f->__buffer, *p = start;
207
208     while (!ferror (f) && (p = memchr (p, '\n', f->__bufp - start)))
209       {
210         /* Found one.  Replace it with a CR and write out through that CR.  */
211
212         *p = '\r';
213         write_some (start, p + 1 - start);
214
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.  */
217
218         start = p;
219         *p++ = '\n';
220       }
221
222     /* Write the remainder of the buffer.  */
223
224     if (!ferror (f))
225       write_some (start, f->__bufp - start);
226   }
227
228   f->__bufp = f->__buffer;
229
230   if (c != EOF && !ferror (f))
231     {
232       if (f->__linebuf && (unsigned char) c == '\n')
233         write_crlf ();
234       else
235         *f->__bufp++ = (unsigned char) c;
236     }
237 }
238
239 static int
240 dealloc_ref (void *cookie)
241 {
242   if (mach_port_deallocate (mach_task_self (), (mach_port_t) cookie))
243     {
244       errno = EINVAL;
245       return -1;
246     }
247   return 0;
248 }
249
250
251 FILE *
252 mach_open_devstream (mach_port_t dev, const char *mode)
253 {
254   FILE *stream;
255
256   if (mach_port_mod_refs (mach_task_self (), dev, MACH_PORT_RIGHT_SEND, 1))
257     {
258       errno = EINVAL;
259       return NULL;
260     }
261
262   stream = fopencookie ((void *) dev, mode, __default_io_functions);
263   if (stream == NULL)
264     {
265       mach_port_deallocate (mach_task_self (), dev);
266       return NULL;
267     }
268
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;
275
276   return stream;
277 }