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

Last change on this file since 647 was 647, checked in by alain, 4 years ago

...miscelaneous...

File size: 14.9 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 <hal_shared_types.h>
26#include <hal_user.h>
27#include <syscalls_numbers.h>
28#include <stdarg.h>
29#include <almosmkh.h>
30#include <unistd.h>
31#include <fcntl.h>
32
33////////////////////////////////////////////////////////////////////////////////////////
34//          stdio library global variables
35////////////////////////////////////////////////////////////////////////////////////////
36
37// This user space array registers all FILE descriptors open by a given process
38FILE open_file_array[MAX_OPEN_FILE_PER_PROCESS];  // array of open files structures
39
40////////////////////////////////////////////////////////////////////////////////////////
41//          stdio library functions
42////////////////////////////////////////////////////////////////////////////////////////
43
44/////////////////////////////
45int rename( const char * old,
46            const char * new )
47{
48    return hal_user_syscall( SYS_RENAME,
49                             (reg_t)old,
50                             (reg_t)new, 0, 0 );   
51}
52
53////////////////////////////////////////////////////////////////////////////////////////
54// This static function analyses the <format> and the <args> to build a formated
55// string in the buffer defined by <string> and <length>.
56// It does NOT add a terminating NUL character in the <string buffer>.
57// If success, it returns the number of bytes actually copied in the string buffer.
58// It returns -1 in case of illegal format, or if the formated string exceeds the
59// the length argument.
60////////////////////////////////////////////////////////////////////////////////////////
61static int xprintf( char         * string,
62                    int            length,
63                    const char   * format, 
64                    va_list      * args ) 
65{
66    int ps = 0;    // index in the string buffer
67
68#define TO_STREAM(x) do { string[ps] = (x); ps++; if(ps==length) return -1; } while(0);
69
70xprintf_text:
71
72    while ( *format != 0 ) 
73    {
74
75        if (*format == '%')   // copy argument to string
76        {
77            format++;
78            goto xprintf_arguments;
79        }
80        else                  // copy one char to string
81        {
82            TO_STREAM( *format );
83            format++;
84        }
85    }
86
87    return ps;
88
89xprintf_arguments:
90
91    {
92        char              buf[30];    // buffer to store the string for one number
93        char *            pbuf;       // pointer on first char to display
94        unsigned int      len = 0;    // number of char to display
95        static const char HexaTab[] = "0123456789ABCDEF";
96        unsigned int      i;
97       
98        // Ignore fields width and precision
99        for ( ; (*format >= '0' && *format <= '9') || (*format == '.') ; format++ );
100
101        switch (*format) 
102        {
103            case ('c'):             // char conversion
104            {
105                int val = va_arg( *args, int );
106                buf[0] = val;
107                pbuf   = buf;
108                len    = 1;
109                break;
110            }
111            case ('d'):             // decimal signed integer
112            {
113                int val = va_arg( *args, int );
114                if (val < 0) 
115                {
116                    TO_STREAM( '-' );
117                    val = -val;
118                }
119                for(i = 0; i < 10; i++) 
120                {
121
122                    buf[9 - i] = HexaTab[val % 10];
123                    if (!(val /= 10)) break;
124                }
125                len =  i + 1;
126                pbuf = &buf[9 - i];
127                break;
128            }
129            case ('u'):             // decimal unsigned integer
130            {
131                unsigned int val = va_arg( *args, unsigned int );
132                for(i = 0; i < 10; i++) 
133                {
134                    buf[9 - i] = HexaTab[val % 10];
135                    if (!(val /= 10)) break;
136                }
137                len =  i + 1;
138                pbuf = &buf[9 - i];
139                break;
140            }
141            case ('x'):             // 32 bits hexadecimal
142            case ('l'):             // 64 bits hexadecimal
143            {
144                unsigned int       imax;
145                unsigned long long val;
146               
147                if ( *format == 'l' )   // 64 bits
148                {
149                    val = va_arg( *args, unsigned long long);
150                    imax = 16;
151                }
152                else                    // 32 bits
153                {
154                    val = va_arg( *args, unsigned int);
155                    imax = 8;
156                }
157               
158                TO_STREAM( '0' );
159                TO_STREAM( 'x' );
160               
161                for(i = 0; i < imax; i++) 
162                {
163                    buf[(imax-1) - i] = HexaTab[val % 16];
164                    if (!(val /= 16))  break;
165                }
166                len =  i + 1;
167                pbuf = &buf[(imax-1) - i];
168                break;
169            }
170            case ('s'):             /* string */
171            {
172                char* str = va_arg( *args, char* );
173                while (str[len]) { len++; }
174                pbuf = str;
175                break;
176            }
177            case ('f'):             // IEEE754 64 bits
178                                    // integer part : up to 10 decimal digits
179                                    // decimal part : 9 decimal digits
180            {
181                union
182                {
183                    double d;
184                    unsigned long long ull;
185                } val;
186               
187                val.d = va_arg( *args, double );
188               
189                unsigned long long mantisse;
190                mantisse = val.ull & 0xFFFFFFFFFFFFFULL;    // mantisse
191               
192                unsigned int exp;
193                exp = (unsigned int)((val.ull & 0x7FF0000000000000ULL) >> 52); // exp
194
195                if (exp == 0x7FF) // special values
196                {
197                    if (mantisse & 0xFFFFFFFFFFFFFULL)  // Not a Number
198                    {
199                        buf[0] = 'N';
200                        buf[1] = 'a';
201                        buf[2] = 'N';
202                        len = 3;
203                        pbuf = buf;
204                    }
205                    else                              // infinite
206                    {
207                        // inf
208                        buf[0] = (val.ull & 0x8000000000000000ULL) ? '-' : '+';
209                        buf[1] = 'i';
210                        buf[2] = 'n';
211                        buf[3] = 'f';
212                        len = 4;
213                        pbuf = buf;
214                    }
215                    break;
216                }
217
218                // display sign & analyse overflow
219                unsigned int overflow = 0;
220                if (val.ull & 0x8000000000000000ULL)  // negative
221                {
222                    TO_STREAM( '-' );
223                    val.d = val.d * -1;
224                    if( val.d < -9999999999.0) overflow = 1;
225                }
226                else                                  // positive
227                {
228                    TO_STREAM( '+' );
229                    if( val.d > 9999999999.0) overflow = 1;
230                }
231               
232                // check overflow caused by the 10.9 format
233                if ( overflow )   
234                {
235                    buf[0] = 'o';
236                    buf[1] = 'v';
237                    buf[2] = 'r';
238                    len = 3;
239                    pbuf = buf;
240                    break;
241                }
242
243                // compute integer & decimal parts
244                unsigned int intp;                  // integer part
245                unsigned int decp;                  // decimal part
246                intp = (unsigned int)val.d;     
247                val.d -= (double)intp;
248                decp = (unsigned int)(val.d * 1000000000);
249               
250                // display decimal value in 10.9 format
251                for(i = 0; i < 10; i++) 
252                {
253                    buf[9 - i] = HexaTab[intp % 10];
254                    if (!(intp /= 10)) break;
255                }
256                pbuf = &buf[9 - i];
257                len = i+11;
258                buf[10] = '.';
259                for(i = 0; i < 9; i++)
260                {
261                    buf[19 - i] = HexaTab[decp % 10];
262                    decp /= 10;
263                }
264                break;
265            }
266            default:       // unsupported argument type
267            {
268                return -1;
269            }
270        }  // end switch on  argument type
271
272        format++;
273
274        // copy argument to string
275        for( i = 0 ; i < len ; i++ )
276        {
277            TO_STREAM( pbuf[i] );
278        }
279       
280        goto xprintf_text;
281    }
282} // end xprintf()
283
284//////////////////////////////////////
285int printf( const char * format, ... )
286{
287    char               string[4096];
288    va_list            args;
289    unsigned int       count;
290   
291    va_start( args, format );
292    count = xprintf( string , 4095 , format , &args ); 
293    va_end( args );
294
295    if ( count == 0xFFFFFFFF ) 
296    {
297        display_string( "printf : xprintf failure" );
298        return -1;
299    }
300    else 
301    {
302        string[count] = 0;
303
304        return write( 1 , &string , count );
305    }
306}  // end printf()
307
308///////////////////
309int getchar( void )
310{
311    char byte;
312
313    if ( read( 0 , &byte , 1 ) != 1 ) return 0;
314    else                              return (int)byte; 
315}
316
317////////////////////
318int putchar( int c )
319{
320    char byte = (char)c;
321
322    if( write( 1 , &byte , 1 ) != 1 ) return 0;
323    else                              return c; 
324}
325
326///////////////////////////////////////
327int snprintf( char           * string,
328              unsigned int     length,
329              const char     * format, ... )
330{
331    va_list            args;
332    unsigned int       count;
333
334    va_start( args, format );
335    count = xprintf( string , (int)length , format , &args ); 
336    va_end( args );
337
338    if( count < length ) string[count] = 0;
339
340    return count;
341}  // end snprintf()
342
343////////////////////////////////////
344FILE * fopen( const char * pathname,
345              const char * mode )
346{
347    //TODO handle the "mode" argument
348    if( mode != NULL )
349    {
350        printf("\n[%s] error : the mode argument must be NULL\n", __FUNCTION__ );
351        return NULL;
352    }
353
354    // get a file descriptor from kernel
355    int fd = open( pathname,
356                   O_CREAT | O_RDWR, 
357                   0 );
358
359    if( fd < 0 )
360    {
361        printf("\n[%s] error : file <%s> not found\n", __FUNCTION__ , pathname );
362        return NULL;
363    }
364    if( fd > MAX_OPEN_FILE_PER_PROCESS )
365    {
366        printf("\n[%s] error : not enough space for file <%s>\n", __FUNCTION__ , pathname );
367        return NULL;
368    }
369
370    // register stream in open_file_array[]
371    open_file_array[fd].fd  = fd;
372    open_file_array[fd].key = VALID_OPEN_FILE;
373
374    return &open_file_array[fd];
375
376}  // end fopen()
377
378///////////////////////////
379int fclose( FILE * stream )
380{
381    // check stream valid
382    if( stream->key != VALID_OPEN_FILE ) return EOF;
383
384    // get file descriptor from stream pointer
385    int fd = stream->fd;
386
387    // remove stream from user open_file_array[]
388    open_file_array[fd].key = 0;
389   
390    // close the kernel file descriptor
391    if( close( fd ) )
392    {
393        printf("\n[%s] error : cannot close file %d\n", __FUNCTION__ , fd );
394        return -1;
395    }
396
397    return 0;
398
399}  // end fclose()
400
401//////////////////////////////////////////
402unsigned int fread( void         * buffer,
403                    unsigned int   size,
404                    unsigned int   nitems,
405                    FILE         * stream )
406{
407    // check stream valid
408    if( stream->key != VALID_OPEN_FILE ) return EOF;
409
410    // get file descriptor from stream pointer
411    int fd = stream->fd;
412
413    // compute nbytes
414    int nbytes = size * nitems;
415
416    if( hal_user_syscall( SYS_READ,
417                          (reg_t)fd,
418                          (reg_t)buffer,
419                          (reg_t)nbytes, 0 ) == nbytes ) return nitems;
420    else return 0;
421
422}  // end fread()
423
424//////////////////////////////////////////
425unsigned int fwrite( void         * buffer,
426                     unsigned int   size,
427                     unsigned int   nitems,
428                     FILE         * stream )
429{
430    // check stream valid
431    if( stream->key != VALID_OPEN_FILE ) return EOF;
432
433    // get file descriptor from stream pointer
434    int fd = stream->fd;
435
436    // compute nbytes
437    int nbytes = size * nitems;
438
439    if( hal_user_syscall( SYS_WRITE,
440                          (reg_t)fd,
441                          (reg_t)buffer,
442                          (reg_t)nbytes, 0 ) == nbytes ) return nitems;
443    else return 0;
444
445}  // end fwrite()
446
447//////////////////////////////////////////
448unsigned int fseek( FILE         * stream,
449                    unsigned int   offset,
450                    int            whence )
451{
452    // check stream valid
453    if( stream->key != VALID_OPEN_FILE ) return -1;
454
455    // get file descriptor from stream pointer
456    int fd = stream->fd;
457
458    return( hal_user_syscall( SYS_LSEEK,
459                              (reg_t)fd,
460                              (reg_t)offset,
461                              (reg_t)whence, 0 ) );
462}  // end fseek()
463
464/////////////////////////////////
465int fprintf( FILE       * stream,
466             const char * format, ... )
467{
468    char               string[4096];
469    va_list            args;
470    int                count;
471    int                writen;
472    int                fd;
473   
474    // check stream valid
475    if( stream->key != VALID_OPEN_FILE )
476    {
477        printf("\n[error in %s] stream %x non registered\n", __FUNCTION__, stream );
478        return -1;
479    }
480
481    va_start( args, format );
482    count = xprintf( string , 4095 , format , &args ); 
483    va_end( args );
484
485    // check format
486    if ( count < 0 ) 
487    {
488        printf("\n[error in %s] unsupported format %s\n", __FUNCTION__, format );
489        return -1;
490    }
491
492    // get file descriptor from file pointer
493    fd = stream->fd;
494
495    // set terminating NUL
496    string[count] = 0;
497
498    // copy string to file
499    writen = write( fd , &string , count );
500
501    // check write
502    if(writen != count )
503    {
504        printf("\n[error in %s] cannot write to stream %s\n", __FUNCTION__, stream );
505        return -1;
506    }
507
508    return writen;
509
510}  // end fprintf()
511
512
513
514
515
Note: See TracBrowser for help on using the repository browser.