source: trunk/System/Sources/libc/src/stdio.c @ 366

Last change on this file since 366 was 366, checked in by khorben, 12 years ago

Merge from upstream

File size: 20.4 KB
Line 
1/* $Id: stdio.c,v 1.80 2009/02/24 14:20:57 khorben Exp $ */
2/* Copyright (c) 2009 Pierre Pronchery <khorben@defora.org> */
3/* This file is part of DeforaOS System libc */
4/* This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, version 3 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program.  If not, see <http://www.gnu.org/licenses/>. */
15
16
17
18#include "errno.h"
19#include "fcntl.h"
20#include "unistd.h"
21#include "stdarg.h"
22#include "stdlib.h"
23#include "string.h"
24#include "limits.h"
25#include "syscalls.h"
26#include "stdio.h"
27
28#define min(a, b) ((a) > (b) ? (b) : (a))
29
30
31/* private */
32/* types */
33typedef enum _FILEDirection { FD_READ = 0, FD_WRITE = 1 } FILEDirection;
34
35struct _FILE
36{
37        int fd;
38        int flags;
39        unsigned char buf[BUFSIZ];
40        unsigned int len;
41        unsigned int pos;
42        char eof;
43        char error;
44        int fbuf;
45        FILEDirection dir;
46};
47
48
49/* variables */
50static FILE _stdin =
51{
52        STDIN_FILENO, O_RDONLY, { 0 }, 0, 0, 0, 0, _IOFBF, FD_READ
53};
54FILE * stdin = &_stdin;
55
56static FILE _stdout =
57{
58        STDOUT_FILENO, O_WRONLY, { 0 }, 0, 0, 0, 0, _IOLBF, FD_WRITE
59};
60FILE * stdout = &_stdout;
61
62static FILE _stderr =
63{
64        STDERR_FILENO, O_WRONLY, { 0 }, 0, 0, 0, 0, _IONBF, FD_WRITE
65};
66FILE * stderr = &_stderr;
67
68
69/* prototypes */
70static int _fopen_mode(char const * mode);
71static FILE * _fopen_new(int fd, int flags, int fbuf);
72
73
74/* public */
75/* clearerr */
76void clearerr(FILE * file)
77{
78        file->eof = 0;
79        file->error = 0;
80}
81
82
83/* fclose */
84int fclose(FILE * file)
85{
86        int ret;
87       
88        ret = fflush(file);
89        close(file->fd);
90        return ret;
91}
92
93
94/* fdopen */
95FILE * fdopen(int fd, char const * mode)
96{
97        return _fopen_new(fd, _fopen_mode(mode), isatty(fd) ? _IONBF : _IOFBF);
98}
99
100
101/* feof */
102int feof(FILE * file)
103{
104        return file->eof;
105}
106
107
108/* ferror */
109int ferror(FILE * file)
110{
111        return file->error;
112}
113
114
115/* fflush */
116int fflush(FILE * file)
117{
118        ssize_t w;
119
120        if(file == NULL)
121        {
122                errno = ENOSYS; /* FIXME implement */
123                return -1;
124        }
125        if(file->dir == FD_READ)
126        {
127                file->len = 0;
128                file->pos = 0;
129                return 0;
130        }
131        else if(file->dir != FD_WRITE)
132                return EOF;
133        for(; file->pos < file->len; file->pos += w)
134                if((w = write(file->fd, &file->buf[file->pos],
135                                                file->len - file->pos)) < 0)
136                {
137                        file->error = 1;
138                        return EOF;
139                }
140        file->pos = 0;
141        file->len = 0;
142        return 0;
143}
144
145
146/* fgetc */
147int fgetc(FILE * file)
148{
149        char c;
150
151        if(fread(&c, sizeof(char), 1, file) != 1)
152                return EOF;
153        return c;
154}
155
156
157/* fgets */
158char * fgets(char * str, int size, FILE * fp)
159{
160        int i;
161        int c;
162
163        if(size < 0)
164        {
165                errno = EINVAL;
166                return NULL;
167        }
168        for(i = 0; i + 1 < size; i++)
169        {
170                if((c = fgetc(fp)) == EOF)
171                {
172                        if(i == 0 || !feof(fp))
173                                return NULL;
174                        break;
175                }
176                str[i] = c;
177                if(c == '\n')
178                        break;
179        }
180        if(++i >= size)
181                return NULL;
182        str[i] = '\0';
183        return str;
184}
185
186
187/* fileno */
188int fileno(FILE * file)
189{
190        if(file == NULL)
191        {
192                errno = EBADF;
193                return -1;
194        }
195        return file->fd;
196}
197
198
199/* fopen */
200FILE * fopen(char const * path, char const * mode)
201{
202        FILE * file;
203        int flags;
204        int fd;
205
206        if((flags = _fopen_mode(mode)) == -1
207                        || (fd = open(path, file->flags, 0777)) < 0)
208                return NULL;
209        if((file = _fopen_new(fd, flags, isatty(fd) ? _IONBF : _IOFBF)) == NULL)
210        {
211                close(fd);
212                return NULL;
213        }
214        return file;
215}
216
217
218/* fprintf */
219int fprintf(FILE * file, char const * format, ...)
220{
221        int ret;
222        va_list arg;
223
224        va_start(arg, format);
225        ret = vfprintf(file, format, arg);
226        va_end(arg);
227        return ret;
228}
229
230
231/* fputc */
232int fputc(int c, FILE * file)
233{
234        unsigned char p = c;
235
236        if(fwrite(&p, sizeof(char), 1, file) != 1)
237                return EOF;
238        return p;
239}
240
241
242/* fputs */
243int fputs(char const * str, FILE * file)
244{
245        size_t len;
246
247        if((len = strlen(str)) == 0)
248                return 0;
249        return fwrite(str, sizeof(char), len, file) == len ? 0 : EOF;
250}
251
252
253/* fread */
254size_t fread(void * ptr, size_t size, size_t nb, FILE * file)
255{
256        char * p = (char*)ptr;
257        size_t i;
258        size_t j;
259        size_t len;
260        ssize_t r;
261
262        if(file->dir != FD_READ)
263        {
264                if(fflush(file) != 0)
265                        return 0;
266                else
267                        file->dir = FD_READ;
268        }
269        for(i = 0; i < nb; i++)
270                for(j = 0; j < size; j += len)
271                {
272                        if(file->pos == file->len)
273                        {
274                                if((r = read(file->fd, file->buf, BUFSIZ)) < 0)
275                                {
276                                        file->error = 1;
277                                        return i;
278                                }
279                                else if(r == 0)
280                                {
281                                        file->eof = 1;
282                                        return i;
283                                }
284                                file->pos = 0;
285                                file->len = r;
286                        }
287                        len = min(file->len - file->pos, size - j);
288                        memcpy(p, &file->buf[file->pos], len);
289                        file->pos += len;
290                        p += len;
291                }
292        return i;
293}
294
295
296/* freopen */
297FILE * freopen(char const * path, char const * mode, FILE * file)
298{
299        int flags;
300
301        fflush(file);
302        if(path == NULL)
303        {
304                if((flags = _fopen_mode(mode)) == -1)
305                {
306                        if(fcntl(file->fd, F_SETFL, flags) == -1)
307                                return NULL;
308                        file->flags = flags;
309                        file->dir = flags & O_WRONLY ? FD_WRITE : FD_READ;
310                        return file;
311                }
312        }
313        close(file->fd);
314        clearerr(file);
315        if((flags = _fopen_mode(mode)) == -1
316                        || (file->fd = open(path, file->flags, 0777)) < 0)
317                return NULL;
318        file->flags = flags;
319        file->dir = flags & O_WRONLY ? FD_WRITE : FD_READ;
320        file->fbuf = isatty(file->fd) ? _IONBF : _IOFBF;
321        return file;
322}
323
324
325/* fscanf */
326int fscanf(FILE * fp, char const * format, ...)
327{
328        int ret;
329        va_list arg;
330
331        va_start(arg, format);
332        ret = vfscanf(fp, format, arg);
333        va_end(arg);
334        return ret;
335}
336
337
338/* fseek */
339int fseek(FILE * file, long offset, int whence)
340{
341        if(fflush(file) != 0)
342                return 1;
343        return lseek(file->fd, offset, whence) != -1 ? 0 : -1;
344}
345
346
347/* ftell */
348long ftell(FILE * file)
349{
350        /* FIXME implement */
351        errno = ENOSYS;
352        return -1;
353}
354
355
356/* fwrite */
357size_t fwrite(void const * ptr, size_t size, size_t nb, FILE * file)
358{
359        char const * p = (char const *)ptr;
360        size_t i;
361        size_t j;
362        size_t len;
363        ssize_t w;
364
365        if(file->dir != FD_WRITE)
366        {
367                if(fflush(file) != 0)
368                        return 0;
369                file->dir = FD_WRITE;
370        }
371        for(i = 0; i < nb; i++)
372                for(j = 0; j < size; j+=len)
373                {
374                        len = min(BUFSIZ - file->len, size - j);
375                        memcpy(&file->buf[file->len], p, len);
376                        p += len;
377                        file->len += len;
378                        if(file->len != BUFSIZ) /* buffer is not full */
379                                continue;
380                        if((w = write(file->fd, &file->buf[file->pos], BUFSIZ
381                                                        - file->pos)) < 0)
382                        {
383                                file->error = 1;
384                                return i;
385                        }
386                        if(w != BUFSIZ - (ssize_t)file->pos) /* XXX cast */
387                                file->pos = w; /* buffer is not empty */
388                        else /* buffer is empty */
389                        {
390                                file->pos = 0;
391                                file->len = 0;
392                        }
393                }
394        if(file->fbuf == _IOFBF)
395                return nb;
396        if(file->fbuf == _IOLBF)
397        {
398                j = file->pos;
399                for(i = j; i < file->len; i++)
400                        if(file->buf[i] == '\n')
401                                j = i;
402        }
403        else /* file is unbuffered */
404                j = file->len;
405        for(; file->pos < j; file->pos += w) /* empty buffer if necessary */
406                if((w = write(file->fd, &file->buf[file->pos], j - file->pos))
407                                < 0)
408                {
409                        file->error = 1;
410                        break; /* XXX should we otherwise report the error? */
411                }
412        return nb;
413}
414
415
416/* getc */
417int getc(FILE * file)
418{
419        return fgetc(file);
420}
421
422
423/* getchar */
424int getchar(void)
425{
426        return fgetc(stdin);
427}
428
429
430/* pclose */
431int pclose(FILE * stream)
432{
433        /* FIXME should be specific? */
434        return fclose(stream);
435}
436
437
438/* perror */
439void perror(char const * s)
440{
441        if(s != NULL && *s != '\0')
442                fprintf(stderr, "%s%s", s, ": ");
443        /* strerror() never returns NULL */
444        fputs(strerror(errno), stderr);
445        fputc('\n', stderr);
446}
447
448
449/* popen */
450static void _popen_child(char const * command, int flags, int * fd);
451
452FILE * popen(char const * command, char const * mode)
453{
454        int flags;
455        pid_t pid;
456        int fd[2];
457        int res;
458
459        if((flags = _fopen_mode(mode)) == -1)
460                return NULL;
461        if((res = pipe(fd)) != 0)
462                return NULL;
463        if((pid = fork()) == -1)
464        {
465                close(fd[0]);
466                close(fd[1]);
467                return NULL;
468        }
469        if(pid == 0) /* child */
470                _popen_child(command, flags, fd);
471        if(flags & O_WRONLY)
472                close(fd[0]);
473        else
474                close(fd[1]);
475        return _fopen_new(flags & O_WRONLY ? fd[1] : fd[0], flags, _IONBF);
476}
477
478static void _popen_child(char const * command, int flags, int * fd)
479{
480        if(flags & O_WRONLY)
481        {
482                close(fd[1]);
483                if(dup2(fd[0], 0) == -1)
484                        exit(127);
485        }
486        else
487        {
488                close(fd[0]);
489                if(dup2(fd[1], 1) == -1)
490                        exit(127);
491        }
492        execlp("/bin/sh", "sh", "-c", command, NULL);
493        exit(127);
494}
495
496
497/* printf */
498int printf(char const * format, ...)
499{
500        int ret;
501        va_list arg;
502
503        va_start(arg, format);
504        ret = vfprintf(stdout, format, arg);
505        va_end(arg);
506        return ret;
507}
508
509
510/* putc */
511int putc(int c, FILE * fp)
512{
513        return fputc(c, fp);
514}
515
516
517/* putchar */
518int putchar(int c)
519{
520        return fputc(c, stdout);
521}
522
523
524/* puts */
525int puts(char const * string)
526{
527        size_t i;
528       
529        i = strlen(string);
530        if(fwrite(string, sizeof(char), i, stdout) != i)
531                return EOF;
532        fputc('\n', stdout);
533        return i <= INT_MAX ? i : INT_MAX;
534}
535
536
537/* remove */
538int remove(char const * path)
539{
540        if(unlink(path) == 0)
541                return 0;
542        if(errno == EISDIR && rmdir(path) == 0)
543                return 0;
544        return -1;
545}
546
547
548/* rename */
549#ifndef SYS_rename
550# warning Unsupported platform: rename() is missing
551int rename(char const * from, char const * to)
552{
553        errno = ENOSYS;
554        return -1;
555}
556#endif
557
558
559/* rewind */
560void rewind(FILE * file)
561{
562        /* FIXME implement */
563}
564
565
566/* scanf */
567int scanf(char const * format, ...)
568{
569        int ret;
570        va_list arg;
571
572        va_start(arg, format);
573        ret = vfscanf(stdin, format, arg);
574        va_end(arg);
575        return ret;
576}
577
578
579/* setbuf */
580void setbuf(FILE * file, char * buf)
581{
582        setvbuf(file, buf, (buf != NULL) ? _IOFBF : _IONBF, BUFSIZ);
583}
584
585
586/* setvbuf */
587void setvbuf(FILE * file, char * buf, int type, size_t size)
588{
589        /* FIXME implement */
590}
591
592
593/* snprintf */
594int snprintf(char * str, size_t size, char const * format, ...)
595{
596        va_list arg;
597        int ret;
598
599        va_start(arg, format);
600        ret = vsnprintf(str, size, format, arg);
601        va_end(arg);
602        return ret;
603}
604
605
606/* sprintf */
607int sprintf(char * str, char const * format, ...)
608{
609        va_list arg;
610        int ret;
611
612        va_start(arg, format);
613        ret = vsprintf(str, format, arg);
614        va_end(arg);
615        return ret;
616}
617
618
619/* sscanf */
620int sscanf(char const * string, char const * format, ...)
621{
622        /* FIXME implement */
623        errno = ENOSYS;
624        return -1;
625}
626
627
628/* tmpfile */
629FILE * tmpfile(void)
630{
631        char * path;
632        int fd;
633        FILE * fp;
634
635        if((path = mktemp("/tmp/tmp.XXXXXX")) == NULL)
636                return NULL;
637        if((fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0)
638                return NULL;
639        if(unlink(path) != 0
640                        || (fp = fdopen(fd, "w+")) == NULL)
641        {
642                close(fd);
643                return NULL;
644        }
645        return fp;
646}
647
648
649/* ungetc */
650int ungetc(int c, FILE * file)
651{
652        if(c == EOF || c < 0)
653        {
654                errno = EINVAL;
655                return EOF;
656        }
657        if(file->len == sizeof(file->buf))
658        {
659                errno = ENOBUFS;
660                return EOF;
661        }
662        memmove(&file->buf[file->pos + 1], &file->buf[file->pos], file->len
663                        - file->pos);
664        file->buf[file->pos] = c; /* XXX c may be silently truncated */
665        file->len++;
666        return file->buf[file->pos];
667}
668
669
670/* vfprintf */
671typedef int (*print_func)(void * dest, size_t size, const char * buf);
672static int _fprint(void * dest, size_t size, const char * buf);
673static int _vprintf(print_func func, void * dest, size_t size,
674                char const * format, va_list arg);
675
676int vfprintf(FILE * file, char const * format, va_list arg)
677{
678        return _vprintf(_fprint, file, ~0, format, arg);
679}
680
681static int _fprint(void * dest, size_t size, char const buf[])
682{
683        FILE * fp = dest;
684
685        return fwrite(buf, sizeof(char), size, fp);
686}
687
688/* _vprintf */
689#define FLAGS_HASH      0x01
690#define FLAGS_MINUS     0x02
691#define FLAGS_PLUS      0x04
692#define FLAGS_SPACE     0x08
693#define FLAGS_ZERO      0x10
694static char _vprintf_flags(char const * p, size_t * i);
695static size_t _vprintf_width(char const * p, size_t * i);
696static size_t _vprintf_precision(char const * p, size_t * i);
697static void _format_lutoa(char * dest, unsigned long n, size_t base);
698static int _format_c(print_func func, void * dest, size_t size, size_t * len,
699                char * chrp);
700static int _format_d(print_func func, void * dest, size_t size, size_t * len,
701                long long * ptr);
702static int _format_o(print_func func, void * dest, size_t size, size_t * len,
703                unsigned long long * ptr);
704static int _format_s(print_func func, void * dest, size_t size, size_t * len,
705                char * str);
706static int _format_p(print_func func, void * dest, size_t size, size_t * len,
707                void * ptr);
708static int _format_u(print_func func, void * dest, size_t size, size_t * len,
709                unsigned long long * ptr);
710static int _format_x(print_func func, void * dest, size_t size, size_t * len,
711                unsigned long long * ptr);
712
713static int _vprintf(print_func func, void * dest, size_t size,
714                char const * format, va_list arg)
715{
716        int ret = 0;
717        char const * p;         /* pointer to current format character */
718        size_t i;
719        size_t len;             /* length to output at current iteration */
720        char flags;
721        size_t width;
722        size_t precision;
723        int lng;
724        char c;
725        char * str;
726        long long int d;
727        unsigned long long int u;
728        void * ptr;
729
730        for(p = format; *p != '\0'; p += i)
731        {
732                for(i = 0; p[i] != '\0' && p[i] != '%'; i++);
733                if(i > 0)
734                {
735                        len = min(i, size);
736                        if(func(dest, len, p) != len)
737                                return -1;
738                }
739                else if(*(p++) == '%')
740                {
741                        len = 0;
742                        flags = _vprintf_flags(p, &i);
743                        width = _vprintf_width(p, &i);
744                        precision = _vprintf_precision(p, &i);
745                        for(lng = 0; p[i] != '\0'; i++)
746                        {
747                                if(p[i] == 'l')
748                                {
749                                        if(++lng > 2)
750                                        {
751                                                errno = EINVAL;
752                                                return -1;
753                                        }
754                                }
755                                else if(p[i] == 'c')
756                                {
757                                        c = va_arg(arg, int);
758                                        if(_format_c(func, dest, size, &len, &c)
759                                                        == -1)
760                                                return -1;
761                                        break;
762                                }
763                                else if(p[i] == 'd')
764                                {
765                                        if(lng > 1)
766                                                d = va_arg(arg, long long int);
767                                        else if (lng == 1)
768                                                d = va_arg(arg, long int);
769                                        else
770                                                d = va_arg(arg, int);
771                                        if(_format_d(func, dest, size, &len, &d)
772                                                        == -1)
773                                                return -1;
774                                        break;
775                                }
776                                else if(p[i] == 'o')
777                                {
778                                        if(lng > 1)
779                                                u = va_arg(arg, unsigned long
780                                                                long int);
781                                        else if(lng == 1)
782                                                u = va_arg(arg, unsigned long
783                                                                        int);
784                                        else
785                                                u = va_arg(arg, unsigned int);
786                                        if(_format_o(func, dest, size, &len, &u)
787                                                        == -1)
788                                                return -1;
789                                        break;
790                                }
791                                else if(p[i] == 'p')
792                                {
793                                        ptr = va_arg(arg, void*);
794                                        if(_format_p(func, dest, size, &len,
795                                                                ptr) == -1)
796                                                return -1;
797                                        break;
798                                }
799                                else if(p[i] == 's')
800                                {
801                                        str = va_arg(arg, char*);
802                                        if(_format_s(func, dest, size, &len,
803                                                                str) == -1)
804                                                return -1;
805                                        break;
806                                }
807                                else if(p[i] == 'u')
808                                {
809                                        if(lng > 1)
810                                                u = va_arg(arg, unsigned long
811                                                                long int);
812                                        else if(lng == 1)
813                                                u = va_arg(arg, unsigned long
814                                                                        int);
815                                        else
816                                                u = va_arg(arg, unsigned int);
817                                        if(_format_u(func, dest, size, &len, &u)
818                                                        == -1)
819                                                return -1;
820                                        break;
821                                }
822                                else if(p[i] == 'x')
823                                {
824                                        if(lng > 1)
825                                                u = va_arg(arg, unsigned long
826                                                                long int);
827                                        else if(lng == 1)
828                                                u = va_arg(arg, unsigned long
829                                                                int);
830                                        else
831                                                u = va_arg(arg, unsigned int);
832                                        if(_format_x(func, dest, size, &len, &u)
833                                                        == -1)
834                                                return -1;
835                                        break;
836                                }
837                                else if(p[i] == 'z')
838                                {
839                                        if(lng != 0)
840                                        {
841                                                errno = EINVAL;
842                                                return -1;
843                                        }
844                                        lng = 1;
845                                }
846                                else
847                                {
848                                        errno = EINVAL;
849                                        return -1;
850                                }
851                        }
852                        i++;
853                }
854                if(INT_MAX - len < ret)
855                {
856                        errno = ERANGE;
857                        return -1;
858                }
859                size -= len;
860                ret += len;
861        }
862        return ret;
863}
864
865static char _vprintf_flags(char const * p, size_t * i)
866{
867        char flags = 0;
868
869        for(; p[*i] != '\0'; (*i)++)
870        {
871                if(p[*i] == '#')
872                        flags |= FLAGS_HASH;
873                else if(p[*i] == '-')
874                        flags |= FLAGS_MINUS;
875                else if(p[*i] == '+')
876                        flags |= FLAGS_PLUS;
877                else if(p[*i] == ' ')
878                        flags |= FLAGS_SPACE;
879                else if(p[*i] == '0')
880                        flags |= FLAGS_ZERO;
881                else
882                        break;
883        }
884        return flags;
885}
886
887static size_t _vprintf_width(char const * p, size_t * i)
888{
889        size_t width = 0;
890
891        for(; p[*i] != '\0'; (*i)++)
892        {
893                if(p[*i] < '0' || p[*i] > '9')
894                        break;
895                width *= 10;
896                width += p[*i] - '0';
897        }
898        return width;
899}
900
901static size_t _vprintf_precision(char const * p, size_t * i)
902{
903        if(p[*i] != '.')
904                return 0;
905        (*i)++;
906        return _vprintf_width(p, i);
907}
908
909static int _format_c(print_func func, void * dest, size_t size, size_t * len,
910                char * chrp)
911{
912        if(size == 0)
913        {
914                *len = 0;
915                return 0;
916        }
917        if(func(dest, 1, chrp) != 1)
918                return -1;
919        *len = 1;
920        return 0;
921}
922
923static int _format_d(print_func func, void * dest, size_t size, size_t * len,
924                long long * ptr)
925{
926        unsigned long long uval;
927
928        if(*ptr >= 0)
929        {
930                uval = *ptr;
931                return _format_u(func, dest, size - 1, len, &uval);
932        }
933        uval = -(*ptr);
934        if(func(dest, 1, "-") != 1
935                        || _format_u(func, dest, size - 1, len, &uval) == -1)
936                return -1;
937        (*len)++;
938        return 0;
939}
940
941static int _format_o(print_func func, void * dest, size_t size, size_t * len,
942                unsigned long long * ptr)
943{
944        char tmp[22] = "";
945        int l;
946
947        _format_lutoa(tmp, *ptr, 8); /* XXX assumes tmp is large enough */
948        *len = strlen(tmp);
949        l = min(*len, size);
950        if(func(dest, l, tmp) != l)
951                return -1;
952        return 0;
953}
954
955static int _format_s(print_func func, void * dest, size_t size, size_t * len,
956                char * str)
957{
958        int l;
959
960        *len = strlen(str);
961        l = min(*len, size);
962        if(func(dest, l, str) != l)
963                return -1;
964        return 0;
965}
966
967static int _format_p(print_func func, void * dest, size_t size, size_t * len,
968                void * ptr)
969{
970        char tmp[3 + sizeof(void*) + sizeof(void*)] = "0x";
971        int l;
972
973        *len = sizeof(tmp);
974        l = min(sizeof(tmp), size);
975        _format_lutoa(&tmp[2], (long)ptr, 16); /* XXX cast */
976        if(func(dest, l, tmp) != l)
977                return -1;
978        return 0;
979}
980
981static int _format_u(print_func func, void * dest, size_t size, size_t * len,
982                unsigned long long * ptr)
983{
984        char tmp[19] = "";
985        int l;
986
987        _format_lutoa(tmp, *ptr, 10); /* XXX assumes tmp is large enough */
988        *len = strlen(tmp);
989        l = min(*len, size);
990        if(func(dest, l, tmp) != l)
991                return -1;
992        return 0;
993}
994
995static int _format_x(print_func func, void * dest, size_t size, size_t * len,
996                unsigned long long * ptr)
997{
998        char tmp[sizeof(long) + sizeof(long) + 1] = "";
999        int l;
1000
1001        _format_lutoa(tmp, *ptr, 16); /* XXX assumes tmp is large enough */
1002        *len = strlen(tmp);
1003        l = min(*len, size);
1004        if(func(dest, l, tmp) != l)
1005                return -1;
1006        return 0;
1007}
1008
1009/* PRE  dest is long enough
1010 * POST 2 <= base <= 36         dest is the ascii representation of n
1011 *      else                    dest is an empty string */
1012static void _format_lutoa(char * dest, unsigned long n, size_t base)
1013{
1014        static char const conv[] = "0123456789abcdefghijklmnopqrstuvwxyz";
1015        size_t len = 0;
1016        unsigned long p;
1017        size_t i;
1018
1019        if(base < 2 || base >= sizeof(conv))
1020        {
1021                dest[0] = '\0';
1022                return;
1023        }
1024        if(n == 0)
1025        {
1026                strcpy(dest, "0");
1027                return;
1028        }
1029        /* XXX performing twice the divisions is not optimal */
1030        for(p = n; p > 0; p /= base)
1031                len++;
1032        for(i = len; n > 0; n /= base)
1033        {
1034                p = n % base;
1035                dest[--i] = conv[p];
1036                n -= p;
1037        }
1038        dest[len] = '\0';
1039}
1040
1041
1042/* vfscanf */
1043int vfscanf(FILE * file, char const * format, va_list arg)
1044{
1045        /* FIXME implement */
1046        errno = ENOSYS;
1047        return -1;
1048}
1049
1050
1051/* vprintf */
1052int vprintf(char const * format, va_list arg)
1053{
1054        return _vprintf(_fprint, stdout, ~0, format, arg);
1055}
1056
1057
1058/* vsnprintf */
1059static int _sprint(void * dest, size_t size, const char * buf);
1060
1061int vsnprintf(char * str, size_t size, char const * format, va_list arg)
1062{
1063        int ret;
1064        char * p = str;
1065        size_t i;
1066
1067        if((ret = _vprintf(_sprint, &p, size, format, arg)) < 0)
1068                return ret;
1069        i = ret;
1070        if(i < size)
1071                str[ret] = '\0';
1072        else if(size > 0)
1073                str[size - 1] = '\0';
1074        return ret;
1075}
1076
1077static int _sprint(void * dest, size_t size, char const buf[])
1078{
1079        char ** str = dest;
1080
1081        strncpy(*str, buf, size);
1082        *str += size;
1083        return size;
1084}
1085
1086
1087/* vsprintf */
1088int vsprintf(char * str, char const * format, va_list arg)
1089{
1090        int ret;
1091        char * p = str;
1092        size_t size = -1;
1093
1094        if((ret = _vprintf(_sprint, &p, size, format, arg)) < 0)
1095                return ret;
1096        str[ret] = '\0';
1097        return ret;
1098}
1099
1100
1101/* private */
1102/* functions */
1103/* fopen_mode */
1104/* PRE
1105 * POST
1106 *      -1      error
1107 *      else    corresponding mode */
1108static int _fopen_mode(char const * mode)
1109{
1110        int flags;
1111
1112        if(*mode == 'r')
1113        {
1114                flags = O_RDONLY;
1115                if(*++mode == 'b')
1116                        ++mode;
1117                if(*mode == '\0')
1118                        return flags;
1119                if(*mode == '+' && ++mode)
1120                        flags = O_RDWR;
1121        }
1122        else if(*mode == 'w')
1123        {
1124                flags = O_WRONLY | O_CREAT;
1125                if(*++mode == 'b')
1126                        ++mode;
1127                if(*mode == '\0')
1128                        return flags;
1129                if(*mode == '+' && ++mode)
1130                        flags = O_RDWR | O_CREAT;
1131        }
1132        else if(*mode == 'a')
1133        {
1134                flags = O_APPEND;
1135                if(*++mode == 'b')
1136                        ++mode;
1137                if(*mode == '\0')
1138                        return flags;
1139                if(*mode == '+' && ++mode)
1140                        flags |= O_CREAT;
1141        }
1142        else
1143        {
1144                errno = EINVAL;
1145                return -1;
1146        }
1147        if(*mode == 'b')
1148                ++mode;
1149        if(*mode != '\0')
1150        {
1151                errno = EINVAL;
1152                return -1;
1153        }
1154        return flags;
1155}
1156
1157
1158/* fopen_new */
1159static FILE * _fopen_new(int fd, int flags, int fbuf)
1160{
1161        FILE * file;
1162
1163        if(flags == -1)
1164                return NULL;
1165        if((file = malloc(sizeof(*file))) == NULL)
1166                return NULL;
1167        file->flags = flags;
1168        file->fd = fd;
1169        file->len = 0;
1170        file->pos = 0;
1171        file->eof = 0;
1172        file->error = 0;
1173        file->dir = file->flags & O_WRONLY ? FD_WRITE : FD_READ;
1174        file->fbuf = fbuf;
1175        return file;
1176}
Note: See TracBrowser for help on using the repository browser.