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

Last change on this file since 677 was 677, checked in by alain, 6 months ago

Introduce the fgetc() and fputc() functions.

File size: 16.2 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 that can be simultaneously
38// open by a given process. The structure FILE is defined in the <stdio.h> file.
39
40FILE open_file_array[MAX_OPEN_FILE_PER_PROCESS]; 
41
42////////////////////////////////////////////////////////////////////////////////////////
43//          stdio library functions
44////////////////////////////////////////////////////////////////////////////////////////
45
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
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////////////////////////////////////////////////////////////////////////////////////////
63static int xprintf( char         * string,
64                    int            length,
65                    const char   * format, 
66                    va_list      * args ) 
67{
68    int ps = 0;    // index in the string buffer
69
70#define TO_STREAM(x) do { string[ps] = (x); ps++; if(ps==length) return -1; } while(0);
71
72xprintf_text:
73
74    while ( *format != 0 ) 
75    {
76
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    }
88
89    return ps;
90
91xprintf_arguments:
92
93    {
94        char              buf[30];    // buffer to store the string for one number
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++ );
102
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                {
123
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            }
143            case ('x'):             // up to 8 digits hexa after "0x"
144            case ('X'):             // exactly 8 digits hexa after "0x"
145            {
146                unsigned int val = va_arg( *args , unsigned int );
147                TO_STREAM( '0' );
148                TO_STREAM( 'x' );
149                for(i = 0 ; i < 8 ; i++) 
150                {
151                    buf[7 - i] = HexaTab[val & 0xF];
152                    if( (*format == 'x') && ((val >> 4) == 0) )  break;
153                    val = val >> 4;
154                }
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);
164                TO_STREAM( '0' );
165                TO_STREAM( 'x' );
166                for(i = 0 ; i < 16 ; i++) 
167                {
168                    buf[15 - i] = HexaTab[val & 0xF];
169                    if( (*format == 'l') && ((val >> 4) == 0) )  break;
170                    val = val >> 4;
171                }
172                len =  i + 1;
173                pbuf = &buf[15 - i];
174                break;
175            }
176            case ('s'):             /* string */
177            {
178                char * str = va_arg( *args , char* );
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
200
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                }
223
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                }
248
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            {
274                return -1;
275            }
276        }  // end switch on  argument type
277
278        format++;
279
280        // copy argument sub-string to the string buffer
281        for( i = 0 ; i < len ; i++ )
282        {
283            TO_STREAM( pbuf[i] );
284        }
285       
286        goto xprintf_text;
287    }
288} // end xprintf()
289
290//////////////////////////////////////
291int printf( const char * format, ... )
292{
293    char      string[4096];
294    va_list   args;
295    int       count;
296   
297    va_start( args, format );
298    count = xprintf( string , 4095 , format , &args ); 
299    va_end( args );
300
301    if ( count < 0 ) 
302    {
303        display_string( "printf : xprintf failure" );
304        return -1;
305    }
306    else 
307    {
308        string[count] = 0;
309
310        return write( 1 , &string , count );
311    }
312}  // end printf()
313
314///////////////////
315int getchar( void )
316{
317    char byte;
318
319    if ( read( 0 , &byte , 1 ) != 1 ) return 0;
320    else                              return (int)byte; 
321}
322
323////////////////////
324int putchar( int c )
325{
326    char byte = (char)c;
327
328    if( write( 1 , &byte , 1 ) != 1 ) return 0;
329    else                              return c; 
330}
331
332///////////////////////////////////////
333int snprintf( char           * string,
334              unsigned int     length,
335              const char     * format, ... )
336{
337    va_list   args;
338    int       count;
339
340    va_start( args, format );
341    count = xprintf( string , (int)length , format , &args ); 
342    va_end( args );
343
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;
352
353        return count;
354    }
355}  // end snprintf()
356
357
358
359
360
361////////////////////////////////////
362FILE * fopen( const char * pathname,
363              const char * mode )
364{
365    //TODO handle the "mode" argument
366    if( mode != NULL )
367    {
368        printf("\n[%s] error : the mode argument must be NULL\n", __FUNCTION__ );
369        return NULL;
370    }
371
372    // get a file descriptor from kernel
373    int fd = open( pathname,
374                   O_CREAT | O_RDWR, 
375                   0 );
376
377    if( fd < 0 )
378    {
379        printf("\n[%s] error : file <%s> not found\n", __FUNCTION__ , pathname );
380        return NULL;
381    }
382    if( fd > MAX_OPEN_FILE_PER_PROCESS )
383    {
384        printf("\n[%s] error : not enough space for file <%s>\n", __FUNCTION__ , pathname );
385        return NULL;
386    }
387
388    // register stream in open_file_array[]
389    open_file_array[fd].fd  = fd;
390    open_file_array[fd].key = VALID_OPEN_FILE;
391
392    return &open_file_array[fd];
393
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
405    // remove stream from user open_file_array[]
406    open_file_array[fd].key = 0;
407   
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
417}  // end fclose()
418
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
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
465    int nbytes = size * nitems;
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
488    int nbytes = size * nitems;
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
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
515/////////////////////////////////
516int fprintf( FILE       * stream,
517             const char * format, ... )
518{
519    char               string[4096];
520    va_list            args;
521    int                count;
522    int                writen;
523    int                fd;
524   
525    // check stream valid
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    }
531
532    va_start( args, format );
533    count = xprintf( string , 4095 , format , &args ); 
534    va_end( args );
535
536    // check format
537    if ( count < 0 ) 
538    {
539        printf("\n[error in %s] unsupported format %s\n", __FUNCTION__, format );
540        return -1;
541    }
542
543    // get file descriptor from file pointer
544    fd = stream->fd;
545
546    // set terminating NUL
547    string[count] = 0;
548
549    // copy string to file
550    writen = write( fd , &string , count );
551
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    }
558
559    return writen;
560
561}  // end fprintf()
562
563
564
565
566
Note: See TracBrowser for help on using the repository browser.