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

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

Merge from upstream

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