stdio.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008, The EROS Group, LLC.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or
00006  * without modification, are permitted provided that the following
00007  * conditions are met:
00008  *
00009  *   - Redistributions of source code must contain the above 
00010  *     copyright notice, this list of conditions, and the following
00011  *     disclaimer. 
00012  *
00013  *   - Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions, and the following
00015  *     disclaimer in the documentation and/or other materials 
00016  *     provided with the distribution.
00017  *
00018  *   - Neither the names of the copyright holders nor the names of any
00019  *     of any contributors may be used to endorse or promote products
00020  *     derived from this software without specific prior written
00021  *     permission. 
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00026  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00027  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00028  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00029  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00030  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00031  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00033  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034  */
00035 
00036 #include <unistd.h>
00037 #include <fcntl.h>
00038 
00039 #include "BUILD/bitc-runtime.h"
00040 
00045 struct ty_bitc_stdioStream {
00059   bool isInit;
00060   FILE *f;
00061 } ;
00062 
00063 // Okay -- this is nasty. We would LIKE to write these declarations
00064 // as:
00065 //
00066 //   static stdiostream our_stdin = { stdin };
00067 //   static stdiostream our_stdout = { stdout };
00068 //   static stdiostream our_stderr = { stderr };
00069 //
00070 // but unfortunately stdin, stdout, stderr are not constants that can
00071 // be reused in this way. We can either resolve this with an init
00072 // section procedure to hand-initialize them or with an accessor
00073 // function. Shap prefers the init section approach, but that is ELF
00074 // dependent and not everyone uses ELF (which is silly, but what can
00075 // you do).
00076 
00077 static ty_bitc_stdioStream our_stdin = { false, 0 };
00078 static ty_bitc_stdioStream our_stdout = { false, 0 };
00079 static ty_bitc_stdioStream our_stderr = { false, 0 };
00080  
00081 static inline void
00082 fix_stdio_stream(ty_bitc_stdioStream *ios)
00083 {
00084   if (ios->isInit)
00085     return;
00086 
00087   if (ios == &our_stdin)
00088     ios->f = stdin;
00089   else if (ios == &our_stdout)
00090     ios->f = stdout;
00091   else if (ios == &our_stderr)
00092     ios->f = stderr;
00093 }
00094 
00095 ty_bitc_stdioStream *bitc_stdio_stdin  = &our_stdin;
00096 ty_bitc_stdioStream *bitc_stdio_stdout = &our_stdout;
00097 ty_bitc_stdioStream *bitc_stdio_stderr = &our_stderr;
00098 
00099 ty_bitc_stdioStream *
00100 DEFUN(bitc_stdio_open, bitc_string_t *nm, bitc_string_t *mode)
00101 {
00102   ty_bitc_stdioStream *ios = GC_MALLOC_ATOMIC(sizeof(ty_bitc_stdioStream));
00103   ios->f = fopen(nm->s, mode->s);
00104   if (ios->f == NULL)
00105     BITC_THROW(&val_ExNoPermission);
00106 
00107   ios->isInit = true;
00108 
00109   return ios;
00110 }
00111 DEFCLOSURE(bitc_stdio_open);
00112 
00113 void
00114 DEFUN(bitc_stdio_close, ty_bitc_stdioStream *ios)
00115 {
00116   fix_stdio_stream(ios);
00117 
00118   if (ios->f) {
00119     fclose(ios->f);
00120     ios->f = NULL;
00121   }
00122 }
00123 DEFCLOSURE(bitc_stdio_close);
00124   
00125 // The encoding and decoding procedures below are taken from
00126 //
00127 //  http://www1.tip.nl/~t876506/utf8tbl.html#algo
00128 //
00129 
00130 // A BitC char is a 32-bit UNICODE UCS-4 code point. The BitC external
00131 // representation is UTF-8, so we need to transcode it here. 
00132 // Note: This is deficient, because it is not doing proper unicode
00133 // code point decoding.
00134 bitc_char_t
00135 DEFUN(bitc_stdio_read_char, ty_bitc_stdioStream *ios)
00136 {
00137   bitc_uns8_t encoded[6];
00138   bitc_char_t ucs4;
00139   ssize_t result;
00140 
00141   fix_stdio_stream(ios);
00142 
00143   if (ios->f == NULL)
00144     BITC_THROW(&val_ExFileIsClosed);
00145 
00146   // Read the first char:
00147   result = fread(&encoded[0], 1, 1, ios->f);
00148   if (result != 1)
00149     BITC_THROW(&val_ExAtEOF);
00150 
00151   if (encoded[0] <= 127) {
00152     ucs4 = encoded[0];
00153   }
00154   else if (encoded[0] <= 223) {
00155     result = fread(&encoded[1], 1, 1, ios->f);
00156     if (result != 1)
00157       BITC_THROW(&val_ExAtEOF);
00158     ucs4 = 
00159       (encoded[0] - 192)*64 
00160       + (encoded[1]-128);
00161   }
00162   else if (encoded[0] <= 239) {
00163     result = fread(&encoded[1], 2, 1, ios->f);
00164     if (result != 1)
00165       BITC_THROW(&val_ExAtEOF);
00166     ucs4 = 
00167       (encoded[0] - 224)*4096 
00168       + (encoded[1]-128)*64
00169       + (encoded[2]-128);
00170   }
00171   else if (encoded[0] <= 247) {
00172     result = fread(&encoded[1], 3, 1, ios->f);
00173     if (result != 1)
00174       BITC_THROW(&val_ExAtEOF);
00175     ucs4 = 
00176       (encoded[0] - 240)*262144
00177       + (encoded[1]-128)*4096
00178       + (encoded[2]-128)*64
00179       + (encoded[3]-128);
00180   }
00181   else if (encoded[0] <= 251) {
00182     result = fread(&encoded[1], 4, 1, ios->f);
00183     if (result != 1)
00184       BITC_THROW(&val_ExAtEOF);
00185     ucs4 = 
00186       (encoded[0] - 248)*16777216 
00187       + (encoded[1]-128)*262144
00188       + (encoded[2]-128)*4096
00189       + (encoded[3]-128)*64
00190       + (encoded[4]-128);
00191   }
00192   else if (encoded[0] <= 253) {
00193     result = fread(&encoded[1], 5, 1, ios->f);
00194     if (result != 1)
00195       BITC_THROW(&val_ExAtEOF);
00196     ucs4 = 
00197       (encoded[0] - 252)*1073741824
00198       + (encoded[1]-128)*16777216 
00199       + (encoded[2]-128)*262144
00200       + (encoded[3]-128)*4096
00201       + (encoded[4]-128)*64
00202       + (encoded[5]-128);
00203   }
00204   else
00205     BITC_THROW(&val_ExNotUTF8);
00206 
00207   return ucs4;
00208 }
00209 DEFCLOSURE(bitc_stdio_read_char);
00210 
00211 // A BitC char is a 32-bit UNICODE UCS-4 code point. The BitC external
00212 // representation is UTF-8, so we need to transcode it here. 
00213 void
00214 DEFUN(bitc_stdio_write_char, ty_bitc_stdioStream *ios, bitc_char_t ucs4)
00215 {
00216   ssize_t result;
00217   fix_stdio_stream(ios);
00218 
00219   if (ios->f == NULL)
00220     BITC_THROW(&val_ExFileIsClosed);
00221 
00222   bitc_uns8_t encoded[6];
00223   bitc_uns8_t *utf8 = encoded;
00224 
00225   if (ucs4 <= 0x7f) {
00226     *utf8++ = ucs4;
00227   }
00228   else if (ucs4 <= 0x7ff) {
00229     *utf8++ = 192u + (ucs4 / 64);
00230     *utf8++ = 128u + (ucs4 % 64);
00231   }
00232   else if (ucs4 <= 0xffff) {
00233     *utf8++ = 224u + (ucs4 / 4096);
00234     *utf8++ = 128u + ((ucs4 / 64) % 64);
00235     *utf8++ = 128u + (ucs4 % 64);
00236   }
00237   else if (ucs4 <= 0x1fffff) {
00238     *utf8++ = 240 + (ucs4 / 262144);
00239     *utf8++ = 128u + ((ucs4 / 4096) % 64);
00240     *utf8++ = 128u + ((ucs4 / 64) % 64);
00241     *utf8++ = 128u + (ucs4 % 64);
00242   }
00243   else if (ucs4 <= 0x3ffffff) {
00244     *utf8++ = 248u + (ucs4 / 16777216);
00245     *utf8++ = 128u + ((ucs4 / 262144) % 64);
00246     *utf8++ = 128u + ((ucs4 / 4096) % 64);
00247     *utf8++ = 128u + ((ucs4 / 64) % 64);
00248     *utf8++ = 128u + (ucs4 % 64);
00249   }
00250   else if (ucs4 <= 0x7fffffff) {
00251     *utf8++ = 252u + (ucs4 / 1073741824);
00252     *utf8++ = 128u + ((ucs4 / 16777216) % 64);
00253     *utf8++ = 128u + ((ucs4 / 262144) % 64);
00254     *utf8++ = 128u + ((ucs4 / 4096) % 64);
00255     *utf8++ = 128u + ((ucs4 / 64) % 64);
00256     *utf8++ = 128u + (ucs4 % 64);
00257   }
00258 
00259   result = fwrite(encoded, utf8-encoded, 1, ios->f);
00260 
00261   if (result == 0)
00262     BITC_THROW(&val_ExAtEOF);
00263   else if (result < 0)
00264     BITC_THROW(&val_ExNoPermission);
00265 }
00266 DEFCLOSURE(bitc_stdio_write_char);
00267 
00268 // Note: This is deficient, because it is not doing proper unicode
00269 // code point deco ding.
00270 bitc_uns8_t
00271 DEFUN(bitc_stdio_read_byte, ty_bitc_stdioStream *ios)
00272 {
00273   unsigned char c;
00274 
00275   fix_stdio_stream(ios);
00276 
00277   if (ios->f == NULL)
00278     BITC_THROW(&val_ExFileIsClosed);
00279 
00280   if ( fread(&c, 1, 1, ios->f) != 1 )
00281     BITC_THROW(&val_ExNoPermission);
00282 
00283   return c;
00284 }
00285 DEFCLOSURE(bitc_stdio_read_byte);
00286 
00287 // Note: This is deficient, because it is not doing proper unicode
00288 // code point encoding.
00289 void
00290 DEFUN(bitc_stdio_write_byte, ty_bitc_stdioStream *ios, bitc_uns8_t c)
00291 {
00292   fix_stdio_stream(ios);
00293 
00294   if (ios->f == NULL)
00295     BITC_THROW(&val_ExFileIsClosed);
00296 
00297   if ( fwrite(&c, 1, 1, ios->f) != 1 )
00298     BITC_THROW(&val_ExNoPermission);
00299 }
00300 DEFCLOSURE(bitc_stdio_write_byte);
00301 
00302 bitc_bool_t
00303 DEFUN(bitc_stdio_eofp, ty_bitc_stdioStream *ios)
00304 {
00305   fix_stdio_stream(ios);
00306 
00307   if (ios->f == NULL)
00308     BITC_THROW(&val_ExFileIsClosed);
00309 
00310   return (feof(ios->f) ? true : false);
00311 }
00312 DEFCLOSURE(bitc_stdio_eofp);
00313 

Generated on Sat Feb 4 23:59:30 2012 for BitC Runtime Library by  doxygen 1.4.7