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

Last change on this file since 625 was 625, checked in by alain, 2 years ago

Fix a bug in the vmm_remove_vseg() function: the physical pages
associated to an user DATA vseg were released to the kernel when
the target process descriptor was in the reference cluster.
This physical pages release should be done only when the page
forks counter value is zero.
All other modifications are cosmetic.

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