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

Last change on this file since 618 was 610, checked in by alain, 6 years ago

Fix several bugs in VFS to support the following
ksh commandis : cp, mv, rm, mkdir, cd, pwd

File size: 12.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
37FILE open_file_array[MAX_OPEN_FILE_PER_PROCESS];  // array of open files structures
38
39////////////////////////////////////////////////////////////////////////////////////////
40//          stdio library functions
41////////////////////////////////////////////////////////////////////////////////////////
42
43/////////////////////////////
44int rename( const char * old,
45            const char * new )
46{
47    return hal_user_syscall( SYS_RENAME,
48                             (reg_t)old,
49                             (reg_t)new, 0, 0 );   
50}
51
52///////////////////////////////////////////////////
53static unsigned int xprintf( char         * string,
54                             unsigned int   length,
55                             const char   * format, 
56                             va_list      * args ) 
57{
58    unsigned int ps = 0;    // write index to the string buffer
59
60#define TO_STREAM(x) do { string[ps] = (x); ps++; if(ps==length) return 0xFFFFFFFF; } while(0);
61
62xprintf_text:
63
64    while ( *format != 0 ) 
65    {
66
67        if (*format == '%')   // copy argument to string
68        {
69            format++;
70            goto xprintf_arguments;
71        }
72        else                  // copy one char to string
73        {
74            TO_STREAM( *format );
75            format++;
76        }
77    }
78
79    return ps;
80
81xprintf_arguments:
82
83    {
84        char              buf[30];    // buffer to display one number
85        char *            pbuf;       // pointer on first char to display
86        unsigned int      len = 0;    // number of char to display
87        static const char HexaTab[] = "0123456789ABCDEF";
88        unsigned int      i;
89       
90        // Ignore fields width and precision
91        for ( ; (*format >= '0' && *format <= '9') || (*format == '.') ; format++ );
92
93        switch (*format) 
94        {
95            case ('c'):             // char conversion
96            {
97                int val = va_arg( *args, int );
98                buf[0] = val;
99                pbuf   = buf;
100                len    = 1;
101                break;
102            }
103            case ('d'):             // decimal signed integer
104            {
105                int val = va_arg( *args, int );
106                if (val < 0) 
107                {
108                    TO_STREAM( '-' );
109                    val = -val;
110                }
111                for(i = 0; i < 10; i++) 
112                {
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 ('u'):             // decimal unsigned integer
122            {
123                unsigned int val = va_arg( *args, unsigned int );
124                for(i = 0; i < 10; i++) 
125                {
126                    buf[9 - i] = HexaTab[val % 10];
127                    if (!(val /= 10)) break;
128                }
129                len =  i + 1;
130                pbuf = &buf[9 - i];
131                break;
132            }
133            case ('x'):             // 32 bits hexadecimal
134            case ('l'):             // 64 bits hexadecimal
135            {
136                unsigned int       imax;
137                unsigned long long val;
138               
139                if ( *format == 'l' )   // 64 bits
140                {
141                    val = va_arg( *args, unsigned long long);
142                    imax = 16;
143                }
144                else                    // 32 bits
145                {
146                    val = va_arg( *args, unsigned int);
147                    imax = 8;
148                }
149               
150                TO_STREAM( '0' );
151                TO_STREAM( 'x' );
152               
153                for(i = 0; i < imax; i++) 
154                {
155                    buf[(imax-1) - i] = HexaTab[val % 16];
156                    if (!(val /= 16))  break;
157                }
158                len =  i + 1;
159                pbuf = &buf[(imax-1) - i];
160                break;
161            }
162            case ('s'):             /* string */
163            {
164                char* str = va_arg( *args, char* );
165                while (str[len]) { len++; }
166                pbuf = str;
167                break;
168            }
169            case ('f'):             // IEEE754 64 bits
170                                    // integer part : up to 10 decimal digits
171                                    // decimal part : 9 decimal digits
172            {
173                union
174                {
175                    double d;
176                    unsigned long long ull;
177                } val;
178               
179                val.d = va_arg( *args, double );
180               
181                unsigned long long mantisse;
182                mantisse = val.ull & 0xFFFFFFFFFFFFFULL;    // mantisse
183               
184                unsigned int exp;
185                exp = (unsigned int)((val.ull & 0x7FF0000000000000ULL) >> 52); // exp
186
187                if (exp == 0x7FF) // special values
188                {
189                    if (mantisse & 0xFFFFFFFFFFFFFULL)  // Not a Number
190                    {
191                        buf[0] = 'N';
192                        buf[1] = 'a';
193                        buf[2] = 'N';
194                        len = 3;
195                        pbuf = buf;
196                    }
197                    else                              // infinite
198                    {
199                        // inf
200                        buf[0] = (val.ull & 0x8000000000000000ULL) ? '-' : '+';
201                        buf[1] = 'i';
202                        buf[2] = 'n';
203                        buf[3] = 'f';
204                        len = 4;
205                        pbuf = buf;
206                    }
207                    break;
208                }
209
210                // display sign & analyse overflow
211                unsigned int overflow = 0;
212                if (val.ull & 0x8000000000000000ULL)  // negative
213                {
214                    TO_STREAM( '-' );
215                    val.d = val.d * -1;
216                    if( val.d < -9999999999.0) overflow = 1;
217                }
218                else                                  // positive
219                {
220                    TO_STREAM( '+' );
221                    if( val.d > 9999999999.0) overflow = 1;
222                }
223               
224                // check overflow caused by the 10.9 format
225                if ( overflow )   
226                {
227                    buf[0] = 'o';
228                    buf[1] = 'v';
229                    buf[2] = 'r';
230                    len = 3;
231                    pbuf = buf;
232                    break;
233                }
234
235                // compute integer & decimal parts
236                unsigned int intp;                  // integer part
237                unsigned int decp;                  // decimal part
238                intp = (unsigned int)val.d;     
239                val.d -= (double)intp;
240                decp = (unsigned int)(val.d * 1000000000);
241               
242                // display decimal value in 10.9 format
243                for(i = 0; i < 10; i++) 
244                {
245                    buf[9 - i] = HexaTab[intp % 10];
246                    if (!(intp /= 10)) break;
247                }
248                pbuf = &buf[9 - i];
249                len = i+11;
250                buf[10] = '.';
251                for(i = 0; i < 9; i++)
252                {
253                    buf[19 - i] = HexaTab[decp % 10];
254                    decp /= 10;
255                }
256                break;
257            }
258            default:       // unsupported argument type
259            {
260                return 0xFFFFFFFF;
261            }
262        }  // end switch on  argument type
263
264        format++;
265
266        // copy argument to string
267        for( i = 0 ; i < len ; i++ )
268        {
269            TO_STREAM( pbuf[i] );
270        }
271       
272        goto xprintf_text;
273    }
274} // end xprintf()
275
276//////////////////////////////////////
277int printf( const char * format, ... )
278{
279    char               string[4096];
280    va_list            args;
281    unsigned int       count;
282   
283    va_start( args, format );
284    count = xprintf( string , 4095 , format , &args ); 
285    va_end( args );
286
287    if ( count == 0xFFFFFFFF ) 
288    {
289        display_string( "printf : xprintf failure" );
290        return -1;
291    }
292    else 
293    {
294        string[count] = 0;
295
296        return write( 1 , &string , count );
297    }
298}  // end printf()
299
300///////////////////
301int getchar( void )
302{
303    char byte;
304
305    if ( read( 0 , &byte , 1 ) != 1 ) return 0;
306    else                              return (int)byte; 
307}
308
309////////////////////
310int putchar( int c )
311{
312    char byte = (char)c;
313
314    if( write( 1 , &byte , 1 ) != 1 ) return 0;
315    else                              return c; 
316}
317
318///////////////////////////////////////
319int snprintf( char           * string,
320              unsigned int     length,
321              const char     * format, ... )
322{
323    va_list            args;
324    unsigned int       count;
325
326    va_start( args, format );
327    count = xprintf( string , length , format , &args ); 
328    va_end( args );
329
330    if( count < length ) string[count] = 0;
331
332    return count;
333}  // end snprintf()
334
335////////////////////////////////////
336FILE * fopen( const char * pathname,
337              const char * mode )
338{
339    //TODO handle the "mode" argument
340    if( mode != NULL )
341    {
342        printf("\n[ERROR] in %s : the mode argument must be NULL\n", __FUNCTION__ );
343        return NULL;
344    }
345
346    // get a file descriptor from kernel
347    int fd = open( pathname,
348                   O_CREAT | O_RDWR, 
349                   0 );
350
351    if( fd < 0 )
352    {
353        printf("\n[ERROR] in %s : file %s not found\n", __FUNCTION__ , pathname );
354        return NULL;
355    }
356    if( fd > MAX_OPEN_FILE_PER_PROCESS )
357    {
358        printf("\n[ERROR] in %s : not enough space for file %s\n", __FUNCTION__ , pathname );
359        return NULL;
360    }
361
362    // register stream in open_file_array[]
363    open_file_array[fd].fd  = fd;
364    open_file_array[fd].key = VALID_OPEN_FILE;
365
366    return &open_file_array[fd];
367}  // end fopen()
368
369///////////////////////////
370int fclose( FILE * stream )
371{
372    // check stream valid
373    if( stream->key != VALID_OPEN_FILE ) return EOF;
374
375    // get file descriptor from stream pointer
376    int fd = stream->fd;
377
378    // remove stream from open_file_array[]
379    open_file_array[fd].key = 0;
380   
381    return close( fd );
382}  // end fclose()
383
384/////////////////////////////////
385int fprintf( FILE       * stream,
386             const char * format, ... )
387{
388    char               string[4096];
389    va_list            args;
390    unsigned int       count;
391    int                fd;
392   
393    // check stream valid
394    if( stream->key != VALID_OPEN_FILE ) return EOF;
395
396    va_start( args, format );
397    count = xprintf( string , 4095 , format , &args ); 
398    va_end( args );
399
400    if ( count == 0xFFFFFFFF ) 
401    {
402        display_string( "fprintf : xprintf failure" );
403        return -1;
404    }
405    else 
406    {
407        // get file descriptor from file pointer
408        fd = stream->fd;
409       
410        string[count] = 0;
411
412        return write( fd , &string , count );
413    }
414}  // end fprintf()
415
416
417
418
419
Note: See TracBrowser for help on using the repository browser.