Back to index

glibc  2.9
devstream.c
Go to the documentation of this file.
00001 /* stdio on a Mach device port.
00002    Translates \n to \r\n on output, echos and translates \r to \n on input.
00003    Copyright (C) 1992,93,94,96,97,2000 Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <stdio.h>
00022 #include <mach.h>
00023 #include <device/device.h>
00024 #include <errno.h>
00025 #include <string.h>
00026 
00027 
00028 static ssize_t
00029 devstream_write (void *cookie, const char *buffer, size_t n)
00030 {
00031   const device_t dev = (device_t) cookie;
00032 
00033   int write_some (const char *p, size_t to_write)
00034     {
00035       kern_return_t err;
00036       int wrote;
00037       int thiswrite;
00038 
00039       while (to_write > 0)
00040        {
00041          thiswrite = to_write;
00042          if (thiswrite > IO_INBAND_MAX)
00043            thiswrite = IO_INBAND_MAX;
00044 
00045          if (err = device_write_inband (dev, 0, 0, p, thiswrite, &wrote))
00046            {
00047              errno = err;
00048              return 0;
00049            }
00050          p += wrote;
00051          to_write -= wrote;
00052        }
00053       return 1;
00054     }
00055   int write_crlf (void)
00056     {
00057       static const char crlf[] = "\r\n";
00058       return write_some (crlf, 2);
00059     }
00060 
00061   /* Search for newlines (LFs) in the buffer.  */
00062 
00063   const char *start = buffer, *p;
00064   while ((p = memchr (start, '\n', n)) != NULL)
00065     {
00066       /* Found one.  Write out through the preceding character,
00067         and then write a CR/LF pair.  */
00068 
00069       if ((p > start && !write_some (start, p - start))
00070          || !write_crlf ())
00071        return (start - buffer) ?: -1;
00072 
00073       n -= p + 1 - start;
00074       start = p + 1;
00075     }
00076 
00077   /* Write the remainder of the buffer.  */
00078   if (write_some (start, n))
00079     start += n;
00080   return (start - buffer) ?: -1;
00081 }
00082 
00083 static ssize_t
00084 devstream_read (void *cookie, char *buffer, size_t to_read)
00085 {
00086   const device_t dev = (device_t) cookie;
00087 
00088   kern_return_t err;
00089   mach_msg_type_number_t nread = to_read;
00090 
00091   err = device_read_inband (dev, 0, 0, to_read, buffer, &nread);
00092   if (err)
00093     {
00094       errno = err;
00095       return -1;
00096     }
00097 
00098   /* Translate CR to LF.  */
00099   {
00100     char *p;
00101     for (p = memchr (buffer, '\r', nread); p;
00102         p = memchr (p + 1, '\r', (buffer + nread) - (p + 1)))
00103       *p = '\n';
00104   }
00105 
00106   /* Echo back what we read.  */
00107   (void) devstream_write (cookie, buffer, nread);
00108 
00109   return nread;
00110 }
00111 
00112 static int
00113 dealloc_ref (void *cookie)
00114 {
00115   if (mach_port_deallocate (mach_task_self (), (mach_port_t) cookie))
00116     {
00117       errno = EINVAL;
00118       return -1;
00119     }
00120   return 0;
00121 }
00122 
00123 #ifndef USE_IN_LIBIO
00124 #define cookie_io_functions_t __io_functions
00125 #define write __write
00126 #define read __read
00127 #define close __close
00128 #endif
00129 
00130 FILE *
00131 mach_open_devstream (mach_port_t dev, const char *mode)
00132 {
00133   FILE *stream;
00134 
00135   if (mach_port_mod_refs (mach_task_self (), dev, MACH_PORT_RIGHT_SEND, 1))
00136     {
00137       errno = EINVAL;
00138       return NULL;
00139     }
00140 
00141   stream = fopencookie ((void *) dev, mode,
00142                      (cookie_io_functions_t) { write: devstream_write,
00143                                             read: devstream_read,
00144                                             close: dealloc_ref });
00145   if (stream == NULL)
00146     {
00147       mach_port_deallocate (mach_task_self (), dev);
00148       return NULL;
00149     }
00150 
00151   return stream;
00152 }