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

Last change on this file was 684, checked in by alain, 3 years ago

Introduce the socket.c & socket.h files.

File size: 17.1 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            {
145                unsigned int val = va_arg( *args , unsigned int );
146                TO_STREAM( '0' );
147                TO_STREAM( 'x' );
148                for(i = 0 ; i < 8 ; i++) 
149                {
150                    buf[7 - i] = HexaTab[val & 0xF];
151                    val = val >> 4;
152                    if( val == 0)  break;
153                }
154                len =  i + 1;
155                pbuf = &buf[7 - i];
156                break;
157            }
158            case ('X'):             // exactly 8 digits hexa after "0x"
159            {
160                unsigned int val = va_arg( *args , unsigned int );
161                TO_STREAM( '0' );
162                TO_STREAM( 'x' );
163                for(i = 0 ; i < 8 ; i++) 
164                {
165                    buf[7 - i] = (val != 0) ? HexaTab[val & 0xF] : '0';
166                    val = val >> 4;
167                }
168                len = 8;
169                pbuf = &buf[0];
170                break;
171            }
172            case ('l'):             // up to 16 digits hexa after "0x"
173            {
174                unsigned long long val = ((unsigned long long)va_arg( *args, unsigned int)) |
175                                         ((unsigned long long)va_arg( *args, unsigned int) << 32);
176                TO_STREAM( '0' );
177                TO_STREAM( 'x' );
178                for(i = 0 ; i < 16 ; i++) 
179                {
180                    buf[15 - i] = HexaTab[val & 0xF];
181                    val = val >> 4;
182                    if( val == 0)  break;
183                }
184                len =  i + 1;
185                pbuf = &buf[15 - i];
186                break;
187            }
188            case ('L'):             // exactly 16 digits hexa after "0x"
189            {
190                unsigned long long val = ((unsigned long long)va_arg( *args, unsigned int)) |
191                                         ((unsigned long long)va_arg( *args, unsigned int) << 32);
192                TO_STREAM( '0' );
193                TO_STREAM( 'x' );
194                for(i = 0 ; i < 16 ; i++) 
195                {
196                    buf[15 - i] = (val != 0) ? HexaTab[val & 0xF] : '0';
197                    val = val >> 4;
198                }
199                len =  16;
200                pbuf = &buf[0];
201                break;
202            }
203            case ('s'):             /* string */
204            {
205                char * str = va_arg( *args , char* );
206                while (str[len]) { len++; }
207                pbuf = str;
208                break;
209            }
210            case ('f'):             // IEEE754 64 bits
211                                    // integer part : up to 10 decimal digits
212                                    // decimal part : 9 decimal digits
213            {
214                union
215                {
216                    double d;
217                    unsigned long long ull;
218                } val;
219               
220                val.d = va_arg( *args, double );
221               
222                unsigned long long mantisse;
223                mantisse = val.ull & 0xFFFFFFFFFFFFFULL;    // mantisse
224               
225                unsigned int exp;
226                exp = (unsigned int)((val.ull & 0x7FF0000000000000ULL) >> 52); // exp
227
228                if (exp == 0x7FF) // special values
229                {
230                    if (mantisse & 0xFFFFFFFFFFFFFULL)  // Not a Number
231                    {
232                        buf[0] = 'N';
233                        buf[1] = 'a';
234                        buf[2] = 'N';
235                        len = 3;
236                        pbuf = buf;
237                    }
238                    else                              // infinite
239                    {
240                        // inf
241                        buf[0] = (val.ull & 0x8000000000000000ULL) ? '-' : '+';
242                        buf[1] = 'i';
243                        buf[2] = 'n';
244                        buf[3] = 'f';
245                        len = 4;
246                        pbuf = buf;
247                    }
248                    break;
249                }
250
251                // display sign & analyse overflow
252                unsigned int overflow = 0;
253                if (val.ull & 0x8000000000000000ULL)  // negative
254                {
255                    TO_STREAM( '-' );
256                    val.d = val.d * -1;
257                    if( val.d < -9999999999.0) overflow = 1;
258                }
259                else                                  // positive
260                {
261                    TO_STREAM( '+' );
262                    if( val.d > 9999999999.0) overflow = 1;
263                }
264               
265                // check overflow caused by the 10.9 format
266                if ( overflow )   
267                {
268                    buf[0] = 'o';
269                    buf[1] = 'v';
270                    buf[2] = 'r';
271                    len = 3;
272                    pbuf = buf;
273                    break;
274                }
275
276                // compute integer & decimal parts
277                unsigned int intp;                  // integer part
278                unsigned int decp;                  // decimal part
279                intp = (unsigned int)val.d;     
280                val.d -= (double)intp;
281                decp = (unsigned int)(val.d * 1000000000);
282               
283                // display decimal value in 10.9 format
284                for(i = 0; i < 10; i++) 
285                {
286                    buf[9 - i] = HexaTab[intp % 10];
287                    if (!(intp /= 10)) break;
288                }
289                pbuf = &buf[9 - i];
290                len = i+11;
291                buf[10] = '.';
292                for(i = 0; i < 9; i++)
293                {
294                    buf[19 - i] = HexaTab[decp % 10];
295                    decp /= 10;
296                }
297                break;
298            }
299            default:       // unsupported argument type
300            {
301                return -1;
302            }
303        }  // end switch on  argument type
304
305        format++;
306
307        // copy argument sub-string to the string buffer
308        for( i = 0 ; i < len ; i++ )
309        {
310            TO_STREAM( pbuf[i] );
311        }
312       
313        goto xprintf_text;
314    }
315} // end xprintf()
316
317//////////////////////////////////////
318int printf( const char * format, ... )
319{
320    char      string[4096];
321    va_list   args;
322    int       count;
323   
324    va_start( args, format );
325    count = xprintf( string , 4095 , format , &args ); 
326    va_end( args );
327
328    if ( count < 0 ) 
329    {
330        display_string( "printf : xprintf failure" );
331        return -1;
332    }
333    else 
334    {
335        string[count] = 0;
336
337        return write( 1 , &string , count );
338    }
339}  // end printf()
340
341///////////////////
342int getchar( void )
343{
344    char byte;
345
346    if ( read( 0 , &byte , 1 ) != 1 ) return 0;
347    else                              return (int)byte; 
348}
349
350////////////////////
351int putchar( int c )
352{
353    char byte = (char)c;
354
355    if( write( 1 , &byte , 1 ) != 1 ) return 0;
356    else                              return c; 
357}
358
359///////////////////////////////////////
360int snprintf( char           * string,
361              unsigned int     length,
362              const char     * format, ... )
363{
364    va_list   args;
365    int       count;
366
367    va_start( args, format );
368    count = xprintf( string , (int)length , format , &args ); 
369    va_end( args );
370
371    if( (count < 0) || (count == (int)length) )  // failure
372    {
373        return -1;
374    }
375    else                                        // success
376    {
377        // add NUL character
378        string[count] = 0;
379
380        return count;
381    }
382}  // end snprintf()
383
384
385
386
387
388////////////////////////////////////
389FILE * fopen( const char * pathname,
390              const char * mode )
391{
392    //TODO handle the "mode" argument
393    if( mode != NULL )
394    {
395        printf("\n[%s] error : the mode argument must be NULL\n", __FUNCTION__ );
396        return NULL;
397    }
398
399    // get a file descriptor from kernel
400    int fd = open( pathname,
401                   O_CREAT | O_RDWR, 
402                   0 );
403
404    if( fd < 0 )
405    {
406        printf("\n[%s] error : file <%s> not found\n", __FUNCTION__ , pathname );
407        return NULL;
408    }
409    if( fd > MAX_OPEN_FILE_PER_PROCESS )
410    {
411        printf("\n[%s] error : not enough space for file <%s>\n", __FUNCTION__ , pathname );
412        return NULL;
413    }
414
415    // register stream in open_file_array[]
416    open_file_array[fd].fd  = fd;
417    open_file_array[fd].key = VALID_OPEN_FILE;
418
419    return &open_file_array[fd];
420
421}  // end fopen()
422
423///////////////////////////
424int fclose( FILE * stream )
425{
426    // check stream valid
427    if( stream->key != VALID_OPEN_FILE ) return EOF;
428
429    // get file descriptor from stream pointer
430    int fd = stream->fd;
431
432    // remove stream from user open_file_array[]
433    open_file_array[fd].key = 0;
434   
435    // close the kernel file descriptor
436    if( close( fd ) )
437    {
438        printf("\n[%s] error : cannot close file %d\n", __FUNCTION__ , fd );
439        return -1;
440    }
441
442    return 0;
443
444}  // end fclose()
445
446//////////////////////////
447int fgetc( FILE * stream )
448{
449    // check stream valid
450    if( stream->key != VALID_OPEN_FILE ) return EOF;
451
452    // get file descriptor from stream pointer
453    int fd = stream->fd;
454
455    char byte;
456
457    if ( read( fd , &byte , 1 ) != 1 ) return 0;
458    else                               return (int)byte; 
459
460}
461
462/////////////////
463int fputc( int c, 
464           FILE * stream)
465{
466    // check stream valid
467    if( stream->key != VALID_OPEN_FILE ) return EOF;
468
469    // get file descriptor from stream pointer
470    int fd = stream->fd;
471
472    char byte = (char)c;
473
474    if( write( fd , &byte , 1 ) != 1 ) return 0;
475    else                               return c; 
476
477}
478
479//////////////////////////////////////////
480unsigned int fread( void         * buffer,
481                    unsigned int   size,
482                    unsigned int   nitems,
483                    FILE         * stream )
484{
485    // check stream valid
486    if( stream->key != VALID_OPEN_FILE ) return EOF;
487
488    // get file descriptor from stream pointer
489    int fd = stream->fd;
490
491    // compute nbytes
492    int nbytes = size * nitems;
493
494    if( hal_user_syscall( SYS_READ,
495                          (reg_t)fd,
496                          (reg_t)buffer,
497                          (reg_t)nbytes, 0 ) == nbytes ) return nitems;
498    else return 0;
499
500}  // end fread()
501
502//////////////////////////////////////////
503unsigned int fwrite( void         * buffer,
504                     unsigned int   size,
505                     unsigned int   nitems,
506                     FILE         * stream )
507{
508    // check stream valid
509    if( stream->key != VALID_OPEN_FILE ) return EOF;
510
511    // get file descriptor from stream pointer
512    int fd = stream->fd;
513
514    // compute nbytes
515    int nbytes = size * nitems;
516
517    if( hal_user_syscall( SYS_WRITE,
518                          (reg_t)fd,
519                          (reg_t)buffer,
520                          (reg_t)nbytes, 0 ) == nbytes ) return nitems;
521    else return 0;
522
523}  // end fwrite()
524
525//////////////////////////////////////////
526unsigned int fseek( FILE         * stream,
527                    unsigned int   offset,
528                    int            whence )
529{
530    // check stream valid
531    if( stream->key != VALID_OPEN_FILE ) return -1;
532
533    // get file descriptor from stream pointer
534    int fd = stream->fd;
535
536    return( hal_user_syscall( SYS_LSEEK,
537                              (reg_t)fd,
538                              (reg_t)offset,
539                              (reg_t)whence, 0 ) );
540}  // end fseek()
541
542/////////////////////////////////
543int fprintf( FILE       * stream,
544             const char * format, ... )
545{
546    char               string[4096];
547    va_list            args;
548    int                count;
549    int                writen;
550    int                fd;
551   
552    // check stream valid
553    if( stream->key != VALID_OPEN_FILE )
554    {
555        printf("\n[error in %s] stream %x non registered\n", __FUNCTION__, stream );
556        return -1;
557    }
558
559    va_start( args, format );
560    count = xprintf( string , 4095 , format , &args ); 
561    va_end( args );
562
563    // check format
564    if ( count < 0 ) 
565    {
566        printf("\n[error in %s] unsupported format %s\n", __FUNCTION__, format );
567        return -1;
568    }
569
570    // get file descriptor from file pointer
571    fd = stream->fd;
572
573    // set terminating NUL
574    string[count] = 0;
575
576    // copy string to file
577    writen = write( fd , &string , count );
578
579    // check write
580    if(writen != count )
581    {
582        printf("\n[error in %s] cannot write to stream %s\n", __FUNCTION__, stream );
583        return -1;
584    }
585
586    return writen;
587
588}  // end fprintf()
589
590
591
592
593
Note: See TracBrowser for help on using the repository browser.