/* * stdio.c - User level library implementation. * * Author Alain Greiner (2016,2017,2018) * * Copyright (c) UPMC Sorbonne Universites * * This file is part of ALMOS-MKH. * * ALMOS-MKH is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2.0 of the License. * * ALMOS-MKH is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ALMOS-MKH; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include //////////////////////////////////////////////////////////////////////////////////////// // stdio library global variables //////////////////////////////////////////////////////////////////////////////////////// FILE open_file_array[MAX_OPEN_FILE_PER_PROCESS]; // array of open files structures //////////////////////////////////////////////////////////////////////////////////////// // stdio library functions //////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////// static unsigned int xprintf( char * string, unsigned int length, const char * format, va_list * args ) { unsigned int ps = 0; // write index to the string buffer #define TO_STREAM(x) do { string[ps] = (x); ps++; if(ps==length) return 0xFFFFFFFF; } while(0); xprintf_text: while ( *format != 0 ) { if (*format == '%') // copy argument to string { format++; goto xprintf_arguments; } else // copy one char to string { TO_STREAM( *format ); format++; } } return ps; xprintf_arguments: { char buf[30]; // buffer to display one number char * pbuf; // pointer on first char to display unsigned int len = 0; // number of char to display static const char HexaTab[] = "0123456789ABCDEF"; unsigned int i; // Ignore fields width and precision for ( ; (*format >= '0' && *format <= '9') || (*format == '.') ; format++ ); switch (*format) { case ('c'): // char conversion { int val = va_arg( *args, int ); buf[0] = val; pbuf = buf; len = 1; break; } case ('d'): // decimal signed integer { int val = va_arg( *args, int ); if (val < 0) { TO_STREAM( '-' ); val = -val; } for(i = 0; i < 10; i++) { buf[9 - i] = HexaTab[val % 10]; if (!(val /= 10)) break; } len = i + 1; pbuf = &buf[9 - i]; break; } case ('u'): // decimal unsigned integer { unsigned int val = va_arg( *args, unsigned int ); for(i = 0; i < 10; i++) { buf[9 - i] = HexaTab[val % 10]; if (!(val /= 10)) break; } len = i + 1; pbuf = &buf[9 - i]; break; } case ('x'): // 32 bits hexadecimal case ('l'): // 64 bits hexadecimal { unsigned int imax; unsigned long long val; if ( *format == 'l' ) // 64 bits { val = va_arg( *args, unsigned long long); imax = 16; } else // 32 bits { val = va_arg( *args, unsigned int); imax = 8; } TO_STREAM( '0' ); TO_STREAM( 'x' ); for(i = 0; i < imax; i++) { buf[(imax-1) - i] = HexaTab[val % 16]; if (!(val /= 16)) break; } len = i + 1; pbuf = &buf[(imax-1) - i]; break; } case ('s'): /* string */ { char* str = va_arg( *args, char* ); while (str[len]) { len++; } pbuf = str; break; } case ('f'): // IEEE754 64 bits // integer part : up to 10 decimal digits // decimal part : 9 decimal digits { union { double d; unsigned long long ull; } val; val.d = va_arg( *args, double ); unsigned long long mantisse; mantisse = val.ull & 0xFFFFFFFFFFFFFULL; // mantisse unsigned int exp; exp = (unsigned int)((val.ull & 0x7FF0000000000000ULL) >> 52); // exp if (exp == 0x7FF) // special values { if (mantisse & 0xFFFFFFFFFFFFFULL) // Not a Number { buf[0] = 'N'; buf[1] = 'a'; buf[2] = 'N'; len = 3; pbuf = buf; } else // infinite { // inf buf[0] = (val.ull & 0x8000000000000000ULL) ? '-' : '+'; buf[1] = 'i'; buf[2] = 'n'; buf[3] = 'f'; len = 4; pbuf = buf; } break; } // display sign & analyse overflow unsigned int overflow = 0; if (val.ull & 0x8000000000000000ULL) // negative { TO_STREAM( '-' ); val.d = val.d * -1; if( val.d < -9999999999.0) overflow = 1; } else // positive { TO_STREAM( '+' ); if( val.d > 9999999999.0) overflow = 1; } // check overflow caused by the 10.9 format if ( overflow ) { buf[0] = 'o'; buf[1] = 'v'; buf[2] = 'r'; len = 3; pbuf = buf; break; } // compute integer & decimal parts unsigned int intp; // integer part unsigned int decp; // decimal part intp = (unsigned int)val.d; val.d -= (double)intp; decp = (unsigned int)(val.d * 1000000000); // display decimal value in 10.9 format for(i = 0; i < 10; i++) { buf[9 - i] = HexaTab[intp % 10]; if (!(intp /= 10)) break; } pbuf = &buf[9 - i]; len = i+11; buf[10] = '.'; for(i = 0; i < 9; i++) { buf[19 - i] = HexaTab[decp % 10]; decp /= 10; } break; } default: // unsupported argument type { return 0xFFFFFFFF; } } // end switch on argument type format++; // copy argument to string for( i = 0 ; i < len ; i++ ) { TO_STREAM( pbuf[i] ); } goto xprintf_text; } } // end xprintf() ////////////////////////////////////// int printf( const char * format, ... ) { char string[4096]; va_list args; unsigned int count; va_start( args, format ); count = xprintf( string , 4095 , format , &args ); va_end( args ); if ( count == 0xFFFFFFFF ) { display_string( "printf : xprintf failure" ); return -1; } else { string[count] = 0; return write( 1 , &string , count ); } } // end printf() /////////////////// int getchar( void ) { char byte; if ( read( 0 , &byte , 1 ) != 1 ) return 0; else return (int)byte; } //////////////////// int putchar( int c ) { char byte = (char)c; if( write( 1 , &byte , 1 ) != 1 ) return 0; else return c; } /////////////////////////////////////// int snprintf( char * string, unsigned int length, const char * format, ... ) { va_list args; unsigned int count; va_start( args, format ); count = xprintf( string , length , format , &args ); va_end( args ); if( count < length ) string[count] = 0; return count; } // end snprintf() //////////////////////////////////// FILE * fopen( const char * pathname, const char * mode ) { //TODO handle the "mode" argument if( mode != NULL ) { printf("\n[ERROR] in %s : the mode argument must be NULL\n", __FUNCTION__ ); return NULL; } // get a file descriptor from kernel int fd = open( pathname, O_CREAT | O_RDWR, 0 ); if( fd < 0 ) { printf("\n[ERROR] in %s : file %s not found\n", __FUNCTION__ , pathname ); return NULL; } if( fd > MAX_OPEN_FILE_PER_PROCESS ) { printf("\n[ERROR] in %s : not enough space for file %s\n", __FUNCTION__ , pathname ); return NULL; } // register stream in open_file_array[] open_file_array[fd].fd = fd; open_file_array[fd].key = VALID_OPEN_FILE; return &open_file_array[fd]; } // end fopen() /////////////////////////// int fclose( FILE * stream ) { // check stream valid if( stream->key != VALID_OPEN_FILE ) return EOF; // get file descriptor from stream pointer int fd = stream->fd; // remove stream from open_file_array[] open_file_array[fd].key = 0; return close( fd ); } // end fclose() ///////////////////////////////// int fprintf( FILE * stream, const char * format, ... ) { char string[4096]; va_list args; unsigned int count; int fd; // check stream valid if( stream->key != VALID_OPEN_FILE ) return EOF; va_start( args, format ); count = xprintf( string , 4095 , format , &args ); va_end( args ); if ( count == 0xFFFFFFFF ) { display_string( "fprintf : xprintf failure" ); return -1; } else { // get file descriptor from file pointer fd = stream->fd; string[count] = 0; return write( fd , &string , count ); } } // end fprintf()