source: trunk/libs/mini-libc/stdio.c @ 459

Last change on this file since 459 was 459, checked in by alain, 6 years ago

Introduce the math library, to support the floating point
data used by the multi-thread fft application.
Fix several bugs regarding the FPU context save/restore.
Introduce support for the %f format in printf.

File size: 11.6 KB
RevLine 
[439]1/*
[445]2 * stdio.c - User level <stdio> library implementation.
[439]3 *
[445]4 * Author     Alain Greiner (2016,2017,2018)
[439]5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <stdio.h>
[444]25#include <stdarg.h>
[445]26#include <almosmkh.h>
[444]27#include <unistd.h>
[459]28#include <fcntl.h>
[445]29
[459]30////////////////////////////////////////////////////////////////////////////////////////
31//          stdio library global variables
32////////////////////////////////////////////////////////////////////////////////////////
33
34FILE open_file_array[MAX_OPEN_FILE_PER_PROCESS];  // array of open files structures
35
36////////////////////////////////////////////////////////////////////////////////////////
37//          stdio library functions
38////////////////////////////////////////////////////////////////////////////////////////
39
[444]40//////////////////////////////////////////
41static int xprintf( char         * string,
42                    unsigned int   length,
43                    const char   * format, 
44                    va_list      * args ) 
45{
46    unsigned int ps = 0;    // write index to the string buffer
[439]47
[444]48#define TO_STREAM(x) do { string[ps] = (x); ps++; if(ps==length) return -1; } while(0);
[439]49
[444]50xprintf_text:
[439]51
[444]52    while ( *format != 0 ) 
53    {
[439]54
[444]55        if (*format == '%')   // copy argument to string
56        {
57            format++;
58            goto xprintf_arguments;
59        }
60        else                  // copy one char to string
61        {
62            TO_STREAM( *format );
63            format++;
64        }
65    }
[439]66
[444]67    return ps;
[439]68
[444]69xprintf_arguments:
[439]70
[444]71    {
72        char              buf[30];    // buffer to display one number
73        char *            pbuf;       // pointer on first char to display
74        unsigned int      len = 0;    // number of char to display
75        static const char HexaTab[] = "0123456789ABCDEF";
76        unsigned int      i;
77       
78        // Ignore fields width and precision
79        for ( ; (*format >= '0' && *format <= '9') || (*format == '.') ; format++ );
[439]80
[444]81        switch (*format) 
82        {
83            case ('c'):             // char conversion
84            {
85                int val = va_arg( *args, int );
86                buf[0] = val;
87                pbuf   = buf;
88                len    = 1;
89                break;
90            }
91            case ('d'):             // decimal signed integer
92            {
93                int val = va_arg( *args, int );
94                if (val < 0) 
95                {
96                    TO_STREAM( '-' );
97                    val = -val;
98                }
99                for(i = 0; i < 10; i++) 
100                {
[439]101
[444]102                    buf[9 - i] = HexaTab[val % 10];
103                    if (!(val /= 10)) break;
104                }
105                len =  i + 1;
106                pbuf = &buf[9 - i];
107                break;
108            }
109            case ('u'):             // decimal unsigned integer
110            {
111                unsigned int val = va_arg( *args, unsigned int );
112                for(i = 0; i < 10; i++) 
113                {
114                    buf[9 - i] = HexaTab[val % 10];
115                    if (!(val /= 10)) break;
116                }
117                len =  i + 1;
118                pbuf = &buf[9 - i];
119                break;
120            }
121            case ('x'):             // 32 bits hexadecimal
122            case ('l'):             // 64 bits hexadecimal
123            {
124                unsigned int       imax;
125                unsigned long long val;
126               
127                if ( *format == 'l' )   // 64 bits
128                {
129                    val = va_arg( *args, unsigned long long);
130                    imax = 16;
131                }
132                else                    // 32 bits
133                {
134                    val = va_arg( *args, unsigned int);
135                    imax = 8;
136                }
137               
138                TO_STREAM( '0' );
139                TO_STREAM( 'x' );
140               
141                for(i = 0; i < imax; i++) 
142                {
143                    buf[(imax-1) - i] = HexaTab[val % 16];
144                    if (!(val /= 16))  break;
145                }
146                len =  i + 1;
147                pbuf = &buf[(imax-1) - i];
148                break;
149            }
150            case ('s'):             /* string */
151            {
152                char* str = va_arg( *args, char* );
153                while (str[len]) { len++; }
154                pbuf = str;
155                break;
156            }
157            case ('f'):             // IEEE754 64 bits
158                                    // integer part : up to 10 decimal digits
159                                    // decimal part : 9 decimal digits
160            {
161                union
162                {
163                    double d;
164                    unsigned long long ull;
165                } val;
166               
167                val.d = va_arg( *args, double );
168               
169                unsigned long long mantisse;
170                mantisse = val.ull & 0xFFFFFFFFFFFFFULL;    // mantisse
171               
172                unsigned int exp;
173                exp = (unsigned int)((val.ull & 0x7FF0000000000000ULL) >> 52); // exp
[439]174
[444]175                if (exp == 0x7FF) // special values
176                {
177                    if (mantisse & 0xFFFFFFFFFFFFFULL)  // Not a Number
178                    {
179                        buf[0] = 'N';
180                        buf[1] = 'a';
181                        buf[2] = 'N';
182                        len = 3;
183                        pbuf = buf;
184                    }
185                    else                              // infinite
186                    {
187                        // inf
188                        buf[0] = (val.ull & 0x8000000000000000ULL) ? '-' : '+';
189                        buf[1] = 'i';
190                        buf[2] = 'n';
191                        buf[3] = 'f';
192                        len = 4;
193                        pbuf = buf;
194                    }
195                    break;
196                }
[439]197
[444]198                // display sign & analyse overflow
199                unsigned int overflow = 0;
200                if (val.ull & 0x8000000000000000ULL)  // negative
201                {
202                    TO_STREAM( '-' );
203                    val.d = val.d * -1;
204                    if( val.d < -9999999999.0) overflow = 1;
205                }
206                else                                  // positive
207                {
208                    TO_STREAM( '+' );
209                    if( val.d > 9999999999.0) overflow = 1;
210                }
211               
212                // check overflow caused by the 10.9 format
213                if ( overflow )   
214                {
215                    buf[0] = 'o';
216                    buf[1] = 'v';
217                    buf[2] = 'r';
218                    len = 3;
219                    pbuf = buf;
220                    break;
221                }
[439]222
[444]223                // compute integer & decimal parts
224                unsigned int intp;                  // integer part
225                unsigned int decp;                  // decimal part
226                intp = (unsigned int)val.d;     
227                val.d -= (double)intp;
228                decp = (unsigned int)(val.d * 1000000000);
229               
230                // display decimal value in 10.9 format
231                for(i = 0; i < 10; i++) 
232                {
233                    buf[9 - i] = HexaTab[intp % 10];
234                    if (!(intp /= 10)) break;
235                }
236                pbuf = &buf[9 - i];
237                len = i+11;
238                buf[10] = '.';
239                for(i = 0; i < 9; i++)
240                {
241                    buf[19 - i] = HexaTab[decp % 10];
242                    decp /= 10;
243                }
244                break;
245            }
246            default:       // unsupported argument type
247            {
248                return -1;
249            }
250        }  // end switch on  argument type
[439]251
[444]252        format++;
[439]253
[444]254        // copy argument to string
255        for( i = 0 ; i < len ; i++ )
256        {
257            TO_STREAM( pbuf[i] );
258        }
259       
260        goto xprintf_text;
261    }
262} // end xprintf()
[439]263
264//////////////////////////////////////
[444]265int printf( const char * format, ... )
[439]266{
[444]267    char      string[4096];
268    va_list   args;
269    int       count;
270   
271    va_start( args, format );
272    count = xprintf( string , 4095 , format , &args ); 
273    va_end( args );
[439]274
[444]275    if ( count == -1 ) 
276    {
[457]277        display_string( "printf : xprintf failure" );
[444]278        return -1;
279    }
280    else 
281    {
282        string[count] = 0;
[459]283
[457]284        return write( 1 , &string , count );
[444]285    }
[459]286}  // end printf()
[439]287
[444]288/////////////
289int getchar()
[439]290{
[444]291    char byte;
[439]292
[444]293    if ( read( 0 , &byte , 1 ) != 1 ) return 0;
294    else                              return (int)byte; 
[439]295}
296
[444]297////////////////////
298int putchar( int c )
[439]299{
[444]300    char byte = (char)c;
[439]301
[444]302    if( write( 1 , &byte , 1 ) != 1 ) return 0;
303    else                              return c; 
[439]304}
305
306///////////////////////////////////////
[444]307int snprintf( char           * string,
308              unsigned int     length,
309              const char     * format, ... )
[439]310{
[444]311    va_list   args;
312    int       count;
[439]313
[444]314    va_start( args, format );
315    count = xprintf( string , length , format , &args ); 
316    va_end( args );
[439]317
[444]318    if( count < length ) string[count] = 0;
[439]319
[444]320    return count;
[459]321}  // end snprintf()
[439]322
[459]323////////////////////////////////////
324FILE * fopen( const char * pathname,
325              const char * mode )
326{
327    //TODO handle the "mode" argument
328    if( mode != NULL )
329    {
330        printf("\n[ERROR] in %s : the mode argument must be NULL\n", __FUNCTION__ );
331        return NULL;
332    }
[439]333
[459]334    // get a file descriptor from kernel
335    int fd = open( pathname,
336                   O_CREAT | O_RDWR, 
337                   0 );
[439]338
[459]339    if( fd < 0 )
340    {
341        printf("\n[ERROR] in %s : file %s not found\n", __FUNCTION__ , pathname );
342        return NULL;
343    }
344    if( fd > MAX_OPEN_FILE_PER_PROCESS )
345    {
346        printf("\n[ERROR] in %s : not enough space for file %s\n", __FUNCTION__ , pathname );
347        return NULL;
348    }
[439]349
[459]350    // register stream in open_file_array[]
351    open_file_array[fd].fd  = fd;
352    open_file_array[fd].key = VALID_OPEN_FILE;
[439]353
[459]354    return &open_file_array[fd];
355}  // end fopen()
356
357///////////////////////////
358int fclose( FILE * stream )
359{
360    // check stream valid
361    if( stream->key != VALID_OPEN_FILE ) return EOF;
362
363    // get file descriptor from stream pointer
364    int fd = stream->fd;
365
366    // remove stream from open_file_array[]
367    open_file_array[fd].key = 0;
368   
369    return close( fd );
370}  // end fclose()
371
372/////////////////////////////////
373int fprintf( FILE       * stream,
374             const char * format, ... )
375{
376    char      string[4096];
377    va_list   args;
378    int       count;
379    int       fd;
380   
381    // check stream valid
382    if( stream->key != VALID_OPEN_FILE ) return EOF;
383
384    va_start( args, format );
385    count = xprintf( string , 4095 , format , &args ); 
386    va_end( args );
387
388    if ( count == -1 ) 
389    {
390        display_string( "fprintf : xprintf failure" );
391        return -1;
392    }
393    else 
394    {
395        // get file descriptor from file pointer
396        fd = stream->fd;
397       
398        string[count] = 0;
399
400        return write( fd , &string , count );
401    }
402}  // end fprintf()
403
404
405
406
407
Note: See TracBrowser for help on using the repository browser.