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

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

Introduce the fgetc() and fputc() functions.

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