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

Last change on this file since 463 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
Line 
1/*
2 * stdio.c - User level <stdio> library implementation.
3 *
4 * Author     Alain Greiner (2016,2017,2018)
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>
25#include <stdarg.h>
26#include <almosmkh.h>
27#include <unistd.h>
28#include <fcntl.h>
29
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
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
47
48#define TO_STREAM(x) do { string[ps] = (x); ps++; if(ps==length) return -1; } while(0);
49
50xprintf_text:
51
52    while ( *format != 0 ) 
53    {
54
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    }
66
67    return ps;
68
69xprintf_arguments:
70
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++ );
80
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                {
101
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
174
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                }
197
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                }
222
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
251
252        format++;
253
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()
263
264//////////////////////////////////////
265int printf( const char * format, ... )
266{
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 );
274
275    if ( count == -1 ) 
276    {
277        display_string( "printf : xprintf failure" );
278        return -1;
279    }
280    else 
281    {
282        string[count] = 0;
283
284        return write( 1 , &string , count );
285    }
286}  // end printf()
287
288/////////////
289int getchar()
290{
291    char byte;
292
293    if ( read( 0 , &byte , 1 ) != 1 ) return 0;
294    else                              return (int)byte; 
295}
296
297////////////////////
298int putchar( int c )
299{
300    char byte = (char)c;
301
302    if( write( 1 , &byte , 1 ) != 1 ) return 0;
303    else                              return c; 
304}
305
306///////////////////////////////////////
307int snprintf( char           * string,
308              unsigned int     length,
309              const char     * format, ... )
310{
311    va_list   args;
312    int       count;
313
314    va_start( args, format );
315    count = xprintf( string , length , format , &args ); 
316    va_end( args );
317
318    if( count < length ) string[count] = 0;
319
320    return count;
321}  // end snprintf()
322
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    }
333
334    // get a file descriptor from kernel
335    int fd = open( pathname,
336                   O_CREAT | O_RDWR, 
337                   0 );
338
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    }
349
350    // register stream in open_file_array[]
351    open_file_array[fd].fd  = fd;
352    open_file_array[fd].key = VALID_OPEN_FILE;
353
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.